Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion docs/content/bootstrapper.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@ paket.bootstrapper.exe [prerelease|<version>] [--prefer-nuget] [--self] [-s] [-f
* `--run`: Once downloaded run `paket.exe`. All arguments following this one are
ignored and passed directly to `paket.exe`.

* `--config-file=<config-file-path>`: Forces the bootstrapper to use another
config file instead of the default `paket.bootstrapper.exe.config` file.

* `--help`: Show help detailing all possible options.

### In application settings
Expand All @@ -76,14 +79,16 @@ Example:
<add key="ForceNuget" value="True"/>
<add key="Prerelease" value="True"/>
<add key="PaketVersion" value="1.5"/>
<add key="BoostrapperOutputDir" value="_workDir" />
</appSettings>
</configuration>
```

* `PreferNuget`: Same as `--prefer-nuget` option.
* `ForceNuget`: Same as `--force-nuget` option.
* `PaketVersion`: Same as `<version>` option.
* `Prerelease`: Same as `prerelease` option.
* `PaketVersion`: Same as `<version>` option.
* `BootstrapperOutputDir`: Same as `--output-dir=` option.

### With environment variables

Expand Down Expand Up @@ -168,3 +173,10 @@ A few default settings are applied:
* The bootstrapper is silenced and only errors are displayed. `-v` can be used
once to restore normal output or twice to show more details.
* If no version is specified a default `--max-file-age` of `12` hours is used.

**Note about anti virus and magic mode:**

If your anti virus is too aggressive, and must have paket excluded, it will not
be fully excluded unless you change the `BoostrapperOutputDir` to a folder that
is excluded from the anti virus scanner, e.g. a sub folder inside the repository
of the project utilizing magic mode.
109 changes: 62 additions & 47 deletions src/Paket.Bootstrapper/ArgumentParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ public static class CommandArgs
public const string IgnoreCache = "-f";
public const string MaxFileAge = "--max-file-age=";
public const string Run = "--run";
public const string OutputDir = "--output-dir=";
public const string AsTool = "--as-tool";
public const string OutputDir = "--output-dir=";
public const string ConfigFile = "--config-file=";
}
public static class AppSettingKeys
Expand All @@ -38,6 +38,7 @@ public static class AppSettingKeys
public const string PaketVersion = "PaketVersion";
public const string Prerelease = "Prerelease";
public const string IgnoreCache = "IgnoreCache";
public const string BootstrapperOutputDir = "BootstrapperOutputDir";
}
public static class EnvArgs
{
Expand All @@ -47,57 +48,17 @@ public static class EnvArgs
public const string PaketVersionEnvPosix = "PAKET_VERSION";
}

private static void FillTarget(DownloadArguments downloadArguments, bool magicMode, IFileSystemProxy fileSystem)
{
var folder = Path.GetDirectoryName(fileSystem.GetExecutingAssemblyPath()) ?? "";
var ? GetMagicModeTarget(fileSystem) : Path.Combine(folder, "paket.exe");

downloadArguments.Target = target;
downloadArguments.Folder = Path.GetDirectoryName(target);
}

private static void FillTargetToRelativeDir(DownloadArguments downloadArguments, IFileSystemProxy fileSystem)
{
var folder = fileSystem.GetCurrentDirectory();
var "paket.exe");

downloadArguments.Target = target;
downloadArguments.Folder = Path.GetDirectoryName(target);
}

public static BootstrapperOptions ParseArgumentsAndConfigurations(IEnumerable<string> arguments, NameValueCollection appSettings, IDictionary envVariables, IFileSystemProxy fileSystem, IEnumerable<string> argumentsInDependenciesFile)
{
var options = new BootstrapperOptions();
var commandArgs = arguments.ToList();
var magicMode = GetIsMagicMode(fileSystem);
var transparentMagicMode = magicMode && commandArgs.IndexOf(CommandArgs.Run) == -1;

var outputDirArg = commandArgs.SingleOrDefault(x => x.StartsWith(CommandArgs.OutputDir));
if (outputDirArg != null)
{
commandArgs.Remove(outputDirArg);
var folder = outputDirArg.Substring(CommandArgs.OutputDir.Length);
var "paket.exe");

options.DownloadArguments.Target = target;
options.DownloadArguments.Folder = Path.GetDirectoryName(target);
}
else
{
FillTarget(options.DownloadArguments, magicMode, fileSystem);
}
NameValueCollection settings = ParseBootstrapperOnlyCommandArgs(commandArgs, appSettings, options.DownloadArguments, fileSystem, magicMode);

var configFileArg = commandArgs.SingleOrDefault(x => x.StartsWith(CommandArgs.ConfigFile));
if (configFileArg != null)
{
commandArgs.Remove(configFileArg);
var configFilePath = configFileArg.Substring(CommandArgs.ConfigFile.Length);
var newSettings = ReadSettings(configFilePath);
appSettings = newSettings;
}

// 1 - AppSettings
FillOptionsFromAppSettings(options, appSettings);
// 1 - AppSettings or settings from target settings file
FillOptionsFromAppSettings(options, settings);

// 2 - paket.dependencies
FillNonRunOptionsFromArguments(options, argumentsInDependenciesFile.ToList());
Expand Down Expand Up @@ -166,6 +127,62 @@ public static BootstrapperOptions ParseArgumentsAndConfigurations(IEnumerable<st
return options;
}

private static NameValueCollection ParseBootstrapperOnlyCommandArgs(List<string> commandArgs, NameValueCollection appSettings, DownloadArguments downloadArguments, IFileSystemProxy fileSystem, bool magicMode)
{
var configFileArg = commandArgs.SingleOrDefault(x => x.StartsWith(CommandArgs.ConfigFile));
NameValueCollection newSettings = appSettings;
if (configFileArg != null)
{
commandArgs.Remove(configFileArg);
var configFilePath = configFileArg.Substring(CommandArgs.ConfigFile.Length);
newSettings = ReadSettings(configFilePath);
}

// Check if output dir has been provided - commandline takes priority
var outputDirArg = commandArgs.SingleOrDefault(x => x.StartsWith(CommandArgs.OutputDir));
var bootstrapperOutputDir = newSettings.GetKey(AppSettingKeys.BootstrapperOutputDir);
string targetFolder = null;
if (outputDirArg != null)
{
commandArgs.Remove(outputDirArg);
targetFolder = outputDirArg.Substring(CommandArgs.OutputDir.Length);
}
else if(bootstrapperOutputDir != null)
{
targetFolder = bootstrapperOutputDir;
}

// Fill target - if none has been found, the default (temp folder with unique exe name) is used
FillTarget(downloadArguments, magicMode, targetFolder, fileSystem);

return newSettings;
}

private static void FillTarget(DownloadArguments downloadArguments, bool magicMode, string targetFolder, IFileSystemProxy fileSystem)
{
if (targetFolder == null && !magicMode)
{
targetFolder = Path.GetDirectoryName(fileSystem.GetExecutingAssemblyPath()) ?? "";
}

string targetPath;
if (targetFolder != null)
{
targetPath = Path.Combine(targetFolder, "paket.exe");
}
else
{
targetPath = GetMagicModeTarget(fileSystem);
targetFolder = Path.GetDirectoryName(targetPath);
}

// Make sure folder exists - creates it, and parents, if it does not exist.
fileSystem.CreateDirectory(targetFolder);

downloadArguments.Target = targetPath;
downloadArguments.Folder = targetFolder;
}

private static NameValueCollection ReadSettings(string configFilePath)
{
var doc = XDocument.Load(configFilePath);
Expand Down Expand Up @@ -231,7 +248,6 @@ private static void FillOptionsFromAppSettings(BootstrapperOptions options, Name
{
options.DownloadArguments.IgnoreCache = true;
}

}

private static void FillOptionsFromEnvVariables(BootstrapperOptions options, IDictionary envVariables)
Expand Down Expand Up @@ -367,8 +383,7 @@ private static string GetMagicModeTarget(IFileSystemProxy fileSystemProxy)
// accessing the same file as their path depends on the bootstrapper path.
var assemblyLocation = fileSystemProxy.GetExecutingAssemblyPath();
var targetName = String.Format("paket_{0}.exe",GetHash(assemblyLocation));
var targetFolder = Path.Combine(fileSystemProxy.GetTempPath(), "paket");
fileSystemProxy.CreateDirectory(targetFolder);
var targetFolder = Path.Combine(fileSystemProxy.GetTempPath(), "paket");
return Path.Combine(targetFolder, targetName);
}

Expand Down
58 changes: 54 additions & 4 deletions tests/Paket.Bootstrapper.Tests/ArgumentParserTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,11 @@ public class ArgumentParserTests

class DummyFileSystemProxy : IFileSystemProxy
{
private readonly string assembly;
private readonly string _assembly;

public DummyFileSystemProxy(string assembly)
{
this.assembly = assembly;
_assembly = assembly;
}

public bool FileExists(string filename)
Expand Down Expand Up @@ -98,7 +98,7 @@ public void DeleteDirectory(string path, bool recursive)

public string GetExecutingAssemblyPath()
{
return assembly;
return _assembly;
}

public string GetTempPath()
Expand Down Expand Up @@ -557,7 +557,7 @@ public void Magic_prerelease()
Assert.That(result.RunArgs, Is.Not.Empty.And.EqualTo(new[] {"-s", "--help", "foo"}));
Assert.That(result.DownloadArguments.IgnorePrerelease, Is.False);
Assert.That(result.DownloadArguments.MaxFileAgeInMinutes, Is.Null);
Assert.That(result.DownloadArguments.Target, Does.StartWith(MagicModeFileSystemSystem.GetTempPath()).And.EndsWith(".exe"));
Assert.That(result.DownloadArguments.Target, Does.StartWith(Path.Combine(MagicModeFileSystemSystem.GetTempPath(), "paket", "paket_")).And.EndsWith(".exe"));
}

[Test]
Expand Down Expand Up @@ -687,6 +687,56 @@ public void Magic_MaxFileAgeInMinutes()
Assert.That(result.UnprocessedCommandArgs, Is.Empty);
}

[Test]
public void Magic_WithOutputDirInCommandLine()
{
//arrange

//act
var result = ParseMagic(new[] {"--output-dir=_workDir"}, null, null);

//assert
Assert.That(result, Is.Not.Null);
Assert.That(result.UnprocessedCommandArgs, Is.Empty);
Assert.That(result.Run, Is.True);
Assert.AreEqual(Path.Combine("_workDir", "paket.exe"), result.DownloadArguments.Target);
}

[Test]
public void Magic_WithOutputDirInAppSettings()
{
//arrange
var appSettings = new NameValueCollection();
appSettings.Add(ArgumentParser.AppSettingKeys.BootstrapperOutputDir, "_appSettingWorkDir");

//act
var result = ParseMagic(new string[0], appSettings, null);

//assert
Assert.That(result, Is.Not.Null);
Assert.That(result.UnprocessedCommandArgs, Is.Empty);
Assert.That(result.Run, Is.True);
Assert.AreEqual(Path.Combine("_appSettingWorkDir", "paket.exe"), result.DownloadArguments.Target);
}

[Test]
public void Magic_WithOutputDirInCommandLineAndAppSettings()
{
//arrange
var appSettings = new NameValueCollection();
appSettings.Add(ArgumentParser.AppSettingKeys.BootstrapperOutputDir, "_appSettingWorkDir");

//act
var result = ParseMagic(new[] {"--output-dir=_workDir"}, appSettings, null);

//assert
Assert.That(result, Is.Not.Null);
Assert.That(result.UnprocessedCommandArgs, Is.Empty);
Assert.That(result.Run, Is.True);
// CommandLine must take precedence
Assert.AreEqual(Path.Combine("_workDir", "paket.exe"), result.DownloadArguments.Target);
}


[Test]
public void Dependencies_FindDependenciesFile()
Expand Down