2016-01-04 12:36:46 -08:00
|
|
|
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
|
|
|
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
|
|
|
|
|
|
using System;
|
|
|
|
using System.Collections.Generic;
|
|
|
|
using System.IO;
|
|
|
|
using System.Linq;
|
|
|
|
using System.Text;
|
|
|
|
using Microsoft.DotNet.Cli.Utils;
|
|
|
|
using Microsoft.Dnx.Runtime.Common.CommandLine;
|
2016-01-29 18:21:37 -08:00
|
|
|
using Microsoft.Dotnet.Cli.Compiler.Common;
|
2016-01-04 12:36:46 -08:00
|
|
|
using Microsoft.DotNet.ProjectModel;
|
|
|
|
using Microsoft.DotNet.ProjectModel.Graph;
|
|
|
|
using NuGet.Frameworks;
|
2015-12-18 16:39:43 -08:00
|
|
|
using Microsoft.Extensions.PlatformAbstractions;
|
2016-01-04 12:36:46 -08:00
|
|
|
|
|
|
|
namespace Microsoft.DotNet.Tools.Restore
|
|
|
|
{
|
2016-01-30 21:47:50 -08:00
|
|
|
public partial class RestoreCommand
|
2016-01-04 12:36:46 -08:00
|
|
|
{
|
2015-12-18 16:39:43 -08:00
|
|
|
private static readonly string DefaultRid = PlatformServices.Default.Runtime.GetLegacyRestoreRuntimeIdentifier();
|
|
|
|
|
2016-01-30 21:47:50 -08:00
|
|
|
public static int Run(string[] args)
|
2016-01-04 12:36:46 -08:00
|
|
|
{
|
|
|
|
DebugHelper.HandleDebugSwitch(ref args);
|
|
|
|
|
|
|
|
var app = new CommandLineApplication(false)
|
|
|
|
{
|
|
|
|
Name = "dotnet restore",
|
|
|
|
FullName = ".NET project dependency restorer",
|
|
|
|
Description = "Restores dependencies listed in project.json"
|
|
|
|
};
|
2016-01-12 16:36:31 -08:00
|
|
|
|
|
|
|
// Parse --quiet, because we have to handle that specially since NuGet3 has a different
|
|
|
|
// "--verbosity" switch that goes BEFORE the command
|
|
|
|
var quiet = args.Any(s => s.Equals("--quiet", StringComparison.OrdinalIgnoreCase));
|
|
|
|
args = args.Where(s => !s.Equals("--quiet", StringComparison.OrdinalIgnoreCase)).ToArray();
|
|
|
|
|
2016-01-04 12:36:46 -08:00
|
|
|
app.OnExecute(() =>
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
2016-01-12 16:36:31 -08:00
|
|
|
var projectRestoreResult = NuGet3.Restore(args, quiet);
|
2016-01-04 12:36:46 -08:00
|
|
|
|
|
|
|
var restoreTasks = GetRestoreTasks(args);
|
|
|
|
|
|
|
|
foreach (var restoreTask in restoreTasks)
|
|
|
|
{
|
|
|
|
var project = ProjectReader.GetProject(restoreTask.ProjectPath);
|
|
|
|
|
2016-01-12 16:36:31 -08:00
|
|
|
RestoreTools(project, restoreTask, quiet);
|
2016-01-04 12:36:46 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
return projectRestoreResult;
|
|
|
|
}
|
|
|
|
catch (InvalidOperationException e)
|
|
|
|
{
|
|
|
|
Console.WriteLine(e.Message);
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
catch (Exception e)
|
|
|
|
{
|
|
|
|
Console.WriteLine(e.Message);
|
|
|
|
|
|
|
|
return -2;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
return app.Execute(args);
|
|
|
|
}
|
|
|
|
|
|
|
|
private static IEnumerable<RestoreTask> GetRestoreTasks(IEnumerable<string> args)
|
|
|
|
{
|
|
|
|
var directory = Directory.GetCurrentDirectory();
|
|
|
|
|
|
|
|
if (args.Any())
|
|
|
|
{
|
|
|
|
var firstArg = args.First();
|
|
|
|
|
|
|
|
if (IsProjectFile(firstArg))
|
|
|
|
{
|
|
|
|
return new [] {new RestoreTask { ProjectPath = firstArg, Arguments = args.Skip(1)} };
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Directory.Exists(firstArg))
|
|
|
|
{
|
|
|
|
directory = firstArg;
|
|
|
|
|
|
|
|
args = args.Skip(1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return GetAllProjectFiles(directory)
|
|
|
|
.Select(p => new RestoreTask {ProjectPath = p, Arguments = args});
|
|
|
|
}
|
|
|
|
|
|
|
|
private static string[] GetAllProjectFiles(string directory)
|
|
|
|
{
|
|
|
|
return Directory.GetFiles(directory, Project.FileName, SearchOption.AllDirectories);
|
|
|
|
}
|
|
|
|
|
|
|
|
private static bool IsProjectFile(string firstArg)
|
|
|
|
{
|
|
|
|
return firstArg.EndsWith(Project.FileName) && File.Exists(firstArg);
|
|
|
|
}
|
|
|
|
|
2016-01-12 16:36:31 -08:00
|
|
|
private static void RestoreTools(Project project, RestoreTask restoreTask, bool quiet)
|
2016-01-04 12:36:46 -08:00
|
|
|
{
|
|
|
|
foreach (var tooldep in project.Tools)
|
|
|
|
{
|
2016-01-12 16:36:31 -08:00
|
|
|
RestoreTool(tooldep, restoreTask, quiet);
|
2016-01-04 12:36:46 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-01-12 16:36:31 -08:00
|
|
|
private static void RestoreTool(LibraryRange tooldep, RestoreTask restoreTask, bool quiet)
|
2016-01-04 12:36:46 -08:00
|
|
|
{
|
2016-01-20 17:20:38 -08:00
|
|
|
var tempRoot = Path.Combine(restoreTask.ProjectDirectory, "obj");
|
2016-01-15 13:34:05 -08:00
|
|
|
try
|
|
|
|
{
|
2016-01-20 17:20:38 -08:00
|
|
|
var tempPath = Path.Combine(tempRoot, Guid.NewGuid().ToString(), "bin");
|
2016-01-04 12:36:46 -08:00
|
|
|
|
2016-02-01 17:30:41 -08:00
|
|
|
var restoreSucceded = RestoreToolToPath(tooldep, restoreTask.Arguments, tempPath, quiet);
|
|
|
|
if (restoreSucceded)
|
|
|
|
{
|
|
|
|
CreateDepsInPackageCache(tooldep, tempPath);
|
|
|
|
PersistLockFile(tooldep, tempPath, restoreTask.ProjectDirectory);
|
|
|
|
}
|
2016-01-15 13:34:05 -08:00
|
|
|
}
|
|
|
|
finally
|
|
|
|
{
|
|
|
|
Directory.Delete(tempRoot, true);
|
|
|
|
}
|
2016-01-04 12:36:46 -08:00
|
|
|
}
|
|
|
|
|
2016-01-06 02:27:16 -08:00
|
|
|
private static void PersistLockFile(LibraryRange tooldep, string tempPath, string projectPath)
|
2016-01-04 12:36:46 -08:00
|
|
|
{
|
2016-01-06 02:27:16 -08:00
|
|
|
var sourcePath = Path.Combine(tempPath, "project.lock.json");
|
|
|
|
var targetDir = Path.Combine(projectPath, "artifacts", "Tools", tooldep.Name);
|
|
|
|
var targetPath = Path.Combine(targetDir, "project.lock.json");
|
|
|
|
|
|
|
|
if (Directory.Exists(targetDir)) Directory.Delete(targetDir, true);
|
|
|
|
Directory.CreateDirectory(targetDir);
|
|
|
|
|
|
|
|
Console.WriteLine($"Writing '{sourcePath}' to '{targetPath}'");
|
|
|
|
|
|
|
|
File.Move(sourcePath, targetPath);
|
2016-01-04 12:36:46 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
private static void CreateDepsInPackageCache(LibraryRange toolLibrary, string projectPath)
|
|
|
|
{
|
|
|
|
var context = ProjectContext.Create(projectPath,
|
2016-03-01 17:35:32 -06:00
|
|
|
FrameworkConstants.CommonFrameworks.NetStandardApp15, new[] { DefaultRid });
|
2016-01-04 12:36:46 -08:00
|
|
|
|
|
|
|
var toolDescription = context.LibraryManager.GetLibraries()
|
|
|
|
.Select(l => l as PackageDescription)
|
|
|
|
.Where(l => l != null)
|
|
|
|
.FirstOrDefault(l => l.Identity.Name == toolLibrary.Name);
|
|
|
|
|
|
|
|
var depsPath = Path.Combine(
|
|
|
|
toolDescription.Path,
|
2016-02-23 02:34:27 -08:00
|
|
|
Path.GetDirectoryName(toolDescription.RuntimeAssemblies.First().Path),
|
2016-01-04 12:36:46 -08:00
|
|
|
toolDescription.Identity.Name + FileNameSuffixes.Deps);
|
2016-01-29 18:21:37 -08:00
|
|
|
|
2016-03-14 18:41:08 -07:00
|
|
|
var depsJsonPath = Path.Combine(
|
|
|
|
toolDescription.Path,
|
|
|
|
Path.GetDirectoryName(toolDescription.RuntimeAssemblies.First().Path),
|
|
|
|
toolDescription.Identity.Name + FileNameSuffixes.DepsJson);
|
|
|
|
|
2016-02-03 10:57:25 -08:00
|
|
|
var calculator = context.GetOutputPaths(Constants.DefaultConfiguration, buidBasePath: null, outputPath: context.ProjectDirectory);
|
2016-03-08 16:46:50 -08:00
|
|
|
var executable = new Executable(context, calculator, context.CreateExporter(Constants.DefaultConfiguration), null);
|
2016-01-29 18:21:37 -08:00
|
|
|
|
2016-02-03 10:57:25 -08:00
|
|
|
executable.MakeCompilationOutputRunnable();
|
2016-01-04 12:36:46 -08:00
|
|
|
|
|
|
|
if (File.Exists(depsPath)) File.Delete(depsPath);
|
2016-03-14 18:41:08 -07:00
|
|
|
if (File.Exists(depsJsonPath)) File.Delete(depsJsonPath);
|
2016-01-04 12:36:46 -08:00
|
|
|
|
2016-02-03 10:57:25 -08:00
|
|
|
File.Move(Path.Combine(calculator.RuntimeOutputPath, "bin" + FileNameSuffixes.Deps), depsPath);
|
2016-03-14 18:41:08 -07:00
|
|
|
File.Move(Path.Combine(calculator.RuntimeOutputPath, "bin" + FileNameSuffixes.DepsJson), depsJsonPath);
|
2016-01-04 12:36:46 -08:00
|
|
|
}
|
|
|
|
|
2016-02-01 17:30:41 -08:00
|
|
|
private static bool RestoreToolToPath(LibraryRange tooldep, IEnumerable<string> args, string tempPath, bool quiet)
|
2016-01-04 12:36:46 -08:00
|
|
|
{
|
|
|
|
Directory.CreateDirectory(tempPath);
|
|
|
|
var projectPath = Path.Combine(tempPath, Project.FileName);
|
2016-01-06 02:27:16 -08:00
|
|
|
|
|
|
|
Console.WriteLine($"Restoring Tool '{tooldep.Name}' for '{projectPath}' in '{tempPath}'");
|
|
|
|
|
2016-03-01 17:35:32 -06:00
|
|
|
File.WriteAllText(projectPath, GenerateProjectJsonContents(new[] {"netstandardapp1.5"}, tooldep));
|
2016-03-07 09:34:18 -08:00
|
|
|
return NuGet3.Restore(new[] { $"{projectPath}" }.Concat(args), quiet) == 0;
|
2016-01-04 12:36:46 -08:00
|
|
|
}
|
|
|
|
|
2016-01-12 16:36:31 -08:00
|
|
|
private static string GenerateProjectJsonContents(IEnumerable<string> frameworks, LibraryRange tooldep)
|
2016-01-04 12:36:46 -08:00
|
|
|
{
|
|
|
|
var sb = new StringBuilder();
|
|
|
|
sb.AppendLine("{");
|
2016-01-12 16:36:31 -08:00
|
|
|
sb.AppendLine(" \"dependencies\": {");
|
|
|
|
sb.AppendLine($" \"{tooldep.Name}\": \"{tooldep.VersionRange.OriginalString}\"");
|
|
|
|
sb.AppendLine(" },");
|
|
|
|
sb.AppendLine(" \"frameworks\": {");
|
|
|
|
foreach (var framework in frameworks)
|
2016-01-04 12:36:46 -08:00
|
|
|
{
|
2016-03-01 17:35:32 -06:00
|
|
|
var importsStatement = "\"imports\": [ \"dnxcore50\", \"portable-net452+win81\" ]";
|
2016-02-09 12:59:01 -08:00
|
|
|
sb.AppendLine($" \"{framework}\": {{ {importsStatement} }}");
|
2016-01-04 12:36:46 -08:00
|
|
|
}
|
2016-03-07 09:34:18 -08:00
|
|
|
sb.AppendLine(" },");
|
|
|
|
sb.AppendLine(" \"runtimes\": { ");
|
|
|
|
sb.AppendLine($" \"{DefaultRid}\": {{}}");
|
2016-01-12 16:36:31 -08:00
|
|
|
sb.AppendLine(" }");
|
2016-01-04 12:36:46 -08:00
|
|
|
sb.AppendLine("}");
|
|
|
|
var pjContents = sb.ToString();
|
|
|
|
return pjContents;
|
|
|
|
}
|
|
|
|
}
|
2016-01-12 16:36:31 -08:00
|
|
|
}
|