/// <summary> /// Create a <see cref="RuntimeHostBuilder"/> for the project in the specified /// <paramref name="projectDirectory"/>, using the default configuration. /// </summary> /// <remarks> /// This method will throw if the project.json file cannot be found in the /// specified folder. If a project.lock.json file is present in the directory /// it will be loaded. /// </remarks> /// <param name="projectDirectory">The directory of the project to host</param> public static RuntimeHostBuilder ForProjectDirectory(string projectDirectory, NuGetFramework runtimeFramework, IServiceProvider services) { if (string.IsNullOrEmpty(projectDirectory)) { throw new ArgumentNullException(nameof(projectDirectory)); } if (runtimeFramework == null) { throw new ArgumentNullException(nameof(runtimeFramework)); } var log = RuntimeLogging.Logger <RuntimeHostBuilder>(); var hostBuilder = new RuntimeHostBuilder(); // Load the Project var projectResolver = new PackageSpecResolver(projectDirectory); PackageSpec packageSpec; if (projectResolver.TryResolvePackageSpec(GetProjectName(projectDirectory), out packageSpec)) { log.LogVerbose($"Loaded project {packageSpec.Name}"); hostBuilder.Project = new Project(packageSpec); } hostBuilder.GlobalSettings = projectResolver.GlobalSettings; // Load the Lock File if present LockFile lockFile; if (TryReadLockFile(projectDirectory, out lockFile)) { log.LogVerbose($"Loaded lock file"); hostBuilder.LockFile = lockFile; } // Set the framework and other components hostBuilder.TargetFramework = runtimeFramework; hostBuilder.Services = services; hostBuilder.PackagePathResolver = new PackagePathResolver( ResolveRepositoryPath(hostBuilder.GlobalSettings), GetCachePaths()); log.LogVerbose("Registering PackageSpecReferenceDependencyProvider"); hostBuilder.DependencyProviders.Add(new PackageSpecReferenceDependencyProvider(projectResolver)); if (hostBuilder.LockFile != null) { log.LogVerbose("Registering LockFileDependencyProvider"); hostBuilder.DependencyProviders.Add(new LockFileDependencyProvider(hostBuilder.LockFile)); } log.LogVerbose("Registering ReferenceAssemblyDependencyProvider"); var referenceResolver = new FrameworkReferenceResolver(); hostBuilder.DependencyProviders.Add(new ReferenceAssemblyDependencyProvider(referenceResolver)); // GAC resolver goes here! :) return(hostBuilder); }
private async Task <IEnumerable <RestoreTargetGraph> > ExecuteRestoreAsync(NuGetv3LocalRepository localRepository, RemoteWalkContext context, CancellationToken token) { if (_request.Project.TargetFrameworks.Count == 0) { _logger.LogError(string.Format(CultureInfo.CurrentCulture, Strings.Log_ProjectDoesNotSpecifyTargetFrameworks, _request.Project.Name, _request.Project.FilePath)); _success = false; return(Enumerable.Empty <RestoreTargetGraph>()); } _logger.LogMinimal(string.Format(CultureInfo.CurrentCulture, Strings.Log_RestoringPackages, _request.Project.FilePath)); // External references var updatedExternalProjects = new List <ExternalProjectReference>(_request.ExternalProjects); if (_request.ExternalProjects.Count > 0) { // There should be at most one match in the external projects. var rootProjectMatches = _request.ExternalProjects.Where(proj => string.Equals( _request.Project.Name, proj.PackageSpecProjectName, StringComparison.OrdinalIgnoreCase)) .ToList(); if (rootProjectMatches.Count > 1) { throw new InvalidOperationException($"Ambiguous project name '{_request.Project.Name}'."); } var rootProject = rootProjectMatches.SingleOrDefault(); if (rootProject != null) { // Replace the project spec with the passed in package spec, // for installs which are done in memory first this will be // different from the one on disk updatedExternalProjects.RemoveAll(project => project.UniqueName.Equals(rootProject.UniqueName, StringComparison.Ordinal)); var updatedReference = new ExternalProjectReference( rootProject.UniqueName, _request.Project, rootProject.MSBuildProjectPath, rootProject.ExternalProjectReferences); updatedExternalProjects.Add(updatedReference); // Determine if the targets and props files should be written out. context.IsMsBuildBased = XProjUtility.IsMSBuildBasedProject(rootProject.MSBuildProjectPath); } else { Debug.Fail("RestoreRequest.ExternaProjects contains references, but does not contain the top level references. Add the project we are restoring for."); throw new InvalidOperationException($"Missing external reference metadata for {_request.Project.Name}"); } } // Load repositories // the external project provider is specific to the current restore project var projectResolver = new PackageSpecResolver(_request.Project); context.ProjectLibraryProviders.Add( new PackageSpecReferenceDependencyProvider(projectResolver, updatedExternalProjects, _logger)); var remoteWalker = new RemoteDependencyWalker(context); var projectRange = new LibraryRange() { Name = _request.Project.Name, VersionRange = new VersionRange(_request.Project.Version), TypeConstraint = LibraryDependencyTarget.Project | LibraryDependencyTarget.ExternalProject }; // Resolve dependency graphs var allInstalledPackages = new HashSet <LibraryIdentity>(); var allGraphs = new List <RestoreTargetGraph>(); var runtimeIds = RequestRuntimeUtility.GetRestoreRuntimes(_request); var projectFrameworkRuntimePairs = CreateFrameworkRuntimePairs(_request.Project, runtimeIds); var projectRestoreRequest = new ProjectRestoreRequest( _request, _request.Project, _request.ExistingLockFile, _runtimeGraphCache, _runtimeGraphCacheByPackage); var projectRestoreCommand = new ProjectRestoreCommand(_logger, projectRestoreRequest); var result = await projectRestoreCommand.TryRestore( projectRange, projectFrameworkRuntimePairs, allInstalledPackages, localRepository, remoteWalker, context, writeToLockFile : true, token : token); var success = result.Item1; var runtimes = result.Item3; allGraphs.AddRange(result.Item2); _success = success; // Calculate compatibility profiles to check by merging those defined in the project with any from the command line foreach (var profile in _request.Project.RuntimeGraph.Supports) { CompatibilityProfile compatProfile; if (profile.Value.RestoreContexts.Any()) { // Just use the contexts from the project definition compatProfile = profile.Value; } else if (!runtimes.Supports.TryGetValue(profile.Value.Name, out compatProfile)) { // No definition of this profile found, so just continue to the next one _logger.LogWarning(string.Format(CultureInfo.CurrentCulture, Strings.Log_UnknownCompatibilityProfile, profile.Key)); continue; } foreach (var pair in compatProfile.RestoreContexts) { _logger.LogDebug($" {profile.Value.Name} -> +{pair}"); _request.CompatibilityProfiles.Add(pair); } } // Walk additional runtime graphs for supports checks if (_success && _request.CompatibilityProfiles.Any()) { var compatibilityResult = await projectRestoreCommand.TryRestore(projectRange, _request.CompatibilityProfiles, allInstalledPackages, localRepository, remoteWalker, context, writeToLockFile : false, token : token); _success = compatibilityResult.Item1; // TryRestore may contain graphs that are already in allGraphs if the // supports section contains the same TxM as the project framework. var currentGraphs = new HashSet <KeyValuePair <NuGetFramework, string> >( allGraphs.Select(graph => new KeyValuePair <NuGetFramework, string>( graph.Framework, graph.RuntimeIdentifier)) ); foreach (var graph in compatibilityResult.Item2) { var key = new KeyValuePair <NuGetFramework, string>( graph.Framework, graph.RuntimeIdentifier); if (currentGraphs.Add(key)) { allGraphs.Add(graph); } } } return(allGraphs); }
public int Main(string[] args) { #if DEBUG if (args.Contains("--debug")) { args = args.Skip(1).ToArray(); System.Diagnostics.Debugger.Launch(); } #endif // Set up logging _log = new CommandOutputLogger(); var app = new CommandLineApplication(); app.Name = "nuget3"; app.FullName = ".NET Package Manager"; app.HelpOption("-h|--help"); app.VersionOption("--version", GetType().GetTypeInfo().Assembly.GetName().Version.ToString()); app.Command("restore", restore => { restore.Description = "Restores packages for a project and writes a lock file"; var sources = restore.Option("-s|--source <source>", "Specifies a NuGet package source to use during the restore", CommandOptionType.MultipleValue); var packagesDirectory = restore.Option("--packages <packagesDirectory>", "Directory to install packages in", CommandOptionType.SingleValue); var parallel = restore.Option("-p|--parallel <noneOrNumberOfParallelTasks>", $"The number of concurrent tasks to use when restoring. Defaults to {RestoreRequest.DefaultDegreeOfConcurrency}; pass 'none' to run without concurrency.", CommandOptionType.SingleValue); var projectFile = restore.Argument("[project file]", "The path to the project to restore for, either a project.json or the directory containing it. Defaults to the current directory"); restore.OnExecute(async() => { // Figure out the project directory IEnumerable <string> externalProjects = null; PackageSpec project; var projectPath = Path.GetFullPath(projectFile.Value ?? "."); if (string.Equals(PackageSpec.PackageSpecFileName, Path.GetFileName(projectPath), StringComparison.OrdinalIgnoreCase)) { _log.LogVerbose($"Reading project file {projectFile.Value}"); projectPath = Path.GetDirectoryName(projectPath); project = JsonPackageSpecReader.GetPackageSpec(File.ReadAllText(projectFile.Value), Path.GetFileName(projectPath), projectFile.Value); } else if (MsBuildUtility.IsMsBuildBasedProject(projectPath)) { #if DNXCORE50 throw new NotSupportedException(); #else externalProjects = MsBuildUtility.GetProjectReferences(projectPath); projectPath = Path.GetDirectoryName(Path.GetFullPath(projectPath)); var packageSpecFile = Path.Combine(projectPath, PackageSpec.PackageSpecFileName); project = JsonPackageSpecReader.GetPackageSpec(File.ReadAllText(packageSpecFile), Path.GetFileName(projectPath), projectFile.Value); _log.LogVerbose($"Reading project file {projectFile.Value}"); #endif } else { var file = Path.Combine(projectPath, PackageSpec.PackageSpecFileName); _log.LogVerbose($"Reading project file {file}"); project = JsonPackageSpecReader.GetPackageSpec(File.ReadAllText(file), Path.GetFileName(projectPath), file); } _log.LogVerbose($"Loaded project {project.Name} from {project.FilePath}"); // Resolve the root directory var rootDirectory = PackageSpecResolver.ResolveRootDirectory(projectPath); _log.LogVerbose($"Found project root directory: {rootDirectory}"); // Resolve the packages directory var packagesDir = packagesDirectory.HasValue() ? packagesDirectory.Value() : Path.Combine(Environment.GetEnvironmentVariable("USERPROFILE"), ".nuget", "packages"); _log.LogVerbose($"Using packages directory: {packagesDir}"); var packageSources = sources.Values.Select(s => new PackageSource(s)); if (!packageSources.Any()) { var settings = Settings.LoadDefaultSettings(projectPath, configFileName: null, machineWideSettings: null); var packageSourceProvider = new PackageSourceProvider(settings); packageSources = packageSourceProvider.LoadPackageSources(); } var request = new RestoreRequest( project, packageSources, packagesDir); if (externalProjects != null) { foreach (var externalReference in externalProjects) { request.ExternalProjects.Add( new ExternalProjectReference( externalReference, Path.Combine(Path.GetDirectoryName(externalReference), PackageSpec.PackageSpecFileName), projectReferences: Enumerable.Empty <string>())); } } // Run the restore if (parallel.HasValue()) { int parallelDegree; if (string.Equals(parallel.Value(), "none", StringComparison.OrdinalIgnoreCase)) { request.MaxDegreeOfConcurrency = 1; } else if (int.TryParse(parallel.Value(), out parallelDegree)) { request.MaxDegreeOfConcurrency = parallelDegree; } } if (request.MaxDegreeOfConcurrency <= 1) { _log.LogInformation("Running non-parallel restore"); } else { _log.LogInformation($"Running restore with {request.MaxDegreeOfConcurrency} concurrent jobs"); } var command = new RestoreCommand(_log); var sw = Stopwatch.StartNew(); var result = await command.ExecuteAsync(request); sw.Stop(); _log.LogInformation($"Restore completed in {sw.ElapsedMilliseconds:0.00}ms!"); return(0); }); }); app.Command("diag", diag => { diag.Description = "Diagnostic commands for debugging package dependency graphs"; diag.Command("lockfile", lockfile => { lockfile.Description = "Dumps data from the project lock file"; var project = lockfile.Option("--project <project>", "Path containing the project lockfile, or the patht to the lockfile itself", CommandOptionType.SingleValue); var target = lockfile.Option("--target <target>", "View information about a specific project target", CommandOptionType.SingleValue); var library = lockfile.Argument("<library>", "Optionally, get detailed information about a specific library"); lockfile.OnExecute(() => { var diagnostics = new DiagnosticCommands(_log); var projectFile = project.HasValue() ? project.Value() : Path.GetFullPath("."); return(diagnostics.Lockfile(projectFile, target.Value(), library.Value)); }); }); diag.OnExecute(() => { diag.ShowHelp(); return(0); }); }); app.OnExecute(() => { app.ShowHelp(); return(0); }); return(app.Execute(args)); }
public async Task <RestoreResult> ExecuteAsync(RestoreRequest request) { if (request.Project.TargetFrameworks.Count == 0) { _log.LogError("The project does not specify any target frameworks!"); return(new RestoreResult(success: false, restoreGraphs: Enumerable.Empty <RestoreTargetGraph>())); } var projectLockFilePath = string.IsNullOrEmpty(request.LockFilePath) ? Path.Combine(request.Project.BaseDirectory, LockFileFormat.LockFileName) : request.LockFilePath; _log.LogInformation($"Restoring packages for '{request.Project.FilePath}'"); _log.LogWarning("TODO: Read and use lock file"); // Load repositories var projectResolver = new PackageSpecResolver(request.Project.BaseDirectory); var nugetRepository = Repository.Factory.GetCoreV3(request.PackagesDirectory); var context = new RemoteWalkContext(); context.ProjectLibraryProviders.Add( new LocalDependencyProvider( new PackageSpecReferenceDependencyProvider(projectResolver))); if (request.ExternalProjects != null) { context.ProjectLibraryProviders.Add( new LocalDependencyProvider( new ExternalProjectReferenceDependencyProvider(request.ExternalProjects))); } context.LocalLibraryProviders.Add( new SourceRepositoryDependencyProvider(nugetRepository, _log)); foreach (var provider in request.Sources.Select(s => CreateProviderFromSource(s, request.NoCache))) { context.RemoteLibraryProviders.Add(provider); } var remoteWalker = new RemoteDependencyWalker(context); var projectRange = new LibraryRange() { Name = request.Project.Name, VersionRange = new VersionRange(request.Project.Version), TypeConstraint = LibraryTypes.Project }; // Resolve dependency graphs var frameworks = request.Project.TargetFrameworks.Select(f => f.FrameworkName).ToList(); var graphs = new List <RestoreTargetGraph>(); foreach (var framework in frameworks) { graphs.Add(await WalkDependencies(projectRange, framework, remoteWalker, context)); } if (graphs.Any(g => g.InConflict)) { _log.LogError("Failed to resolve conflicts"); return(new RestoreResult(success: false, restoreGraphs: graphs)); } // Install the runtime-agnostic packages var allInstalledPackages = new HashSet <LibraryIdentity>(); var localRepository = new NuGetv3LocalRepository(request.PackagesDirectory, checkPackageIdCase: false); await InstallPackages(graphs, request.PackagesDirectory, allInstalledPackages, request.MaxDegreeOfConcurrency); // Resolve runtime dependencies var runtimeGraphs = new List <RestoreTargetGraph>(); if (request.Project.RuntimeGraph.Runtimes.Count > 0) { foreach (var graph in graphs) { var runtimeSpecificGraphs = await WalkRuntimeDependencies(projectRange, graph, request.Project.RuntimeGraph, remoteWalker, context, localRepository); runtimeGraphs.AddRange(runtimeSpecificGraphs); } graphs.AddRange(runtimeGraphs); if (runtimeGraphs.Any(g => g.InConflict)) { _log.LogError("Failed to resolve conflicts"); return(new RestoreResult(success: false, restoreGraphs: graphs)); } // Install runtime-specific packages await InstallPackages(runtimeGraphs, request.PackagesDirectory, allInstalledPackages, request.MaxDegreeOfConcurrency); } else { _log.LogVerbose("Skipping runtime dependency walk, no runtimes defined in project.json"); } // Build the lock file var repository = new NuGetv3LocalRepository(request.PackagesDirectory, checkPackageIdCase: false); var lockFile = CreateLockFile(request.Project, graphs, repository); var lockFileFormat = new LockFileFormat(); lockFileFormat.Write(projectLockFilePath, lockFile); return(new RestoreResult(true, graphs, lockFile)); }
public int Main(string[] args) { #if DEBUG if (args.Contains("--debug")) { args = args.Skip(1).ToArray(); System.Diagnostics.Debugger.Launch(); } #endif // Set up logging var loggerFactory = new LoggerFactory(); loggerFactory.AddProvider(new CommandOutputLoggerProvider() { LogLevel = LogLevel.Debug }); _log = loggerFactory.CreateLogger <Program>(); var app = new CommandLineApplication(); app.Name = "nuget3"; app.FullName = ".NET Package Manager"; app.HelpOption("-h|--help"); app.VersionOption("--version", _applicationEnvironment.Version); app.Command("restore", restore => { restore.Description = "Restores packages for a project and writes a lock file"; var sources = restore.Option("-s|--source <source>", "Specifies a NuGet package source to use during the restore", CommandOptionType.MultipleValue); var packagesDirectory = restore.Option("--packages <packagesDirectory>", "Directory to install packages in", CommandOptionType.SingleValue); var parallel = restore.Option("-p|--parallel <noneOrNumberOfParallelTasks>", $"The number of concurrent tasks to use when restoring. Defaults to {RestoreRequest.DefaultDegreeOfConcurrency}; pass 'none' to run without concurrency.", CommandOptionType.SingleValue); var projectFile = restore.Argument("[project file]", "The path to the project to restore for, either a project.json or the directory containing it. Defaults to the current directory"); restore.OnExecute(async() => { // Figure out the project directory PackageSpec project; string projectDirectory = projectFile.Value ?? Path.GetFullPath("."); if (string.Equals(PackageSpec.PackageSpecFileName, Path.GetFileName(projectDirectory), StringComparison.OrdinalIgnoreCase)) { _log.LogVerbose($"Reading project file {projectFile.Value}"); projectDirectory = Path.GetDirectoryName(Path.GetFullPath(projectDirectory)); project = JsonPackageSpecReader.GetPackageSpec(File.ReadAllText(projectFile.Value), Path.GetFileName(projectDirectory), projectFile.Value); } else { string file = Path.Combine(projectDirectory, PackageSpec.PackageSpecFileName); _log.LogVerbose($"Reading project file {file}"); project = JsonPackageSpecReader.GetPackageSpec(File.ReadAllText(file), Path.GetFileName(projectDirectory), file); } _log.LogVerbose($"Loaded project {project.Name} from {project.FilePath}"); // Resolve the root directory var rootDirectory = PackageSpecResolver.ResolveRootDirectory(projectDirectory); _log.LogVerbose($"Found project root directory: {rootDirectory}"); // Resolve the packages directory // TODO: Do this for real :) var packagesDir = packagesDirectory.HasValue() ? packagesDirectory.Value() : Path.Combine(Environment.GetEnvironmentVariable("USERPROFILE"), ".dnx", "packages"); _log.LogVerbose($"Using packages directory: {packagesDirectory}"); // Run the restore var request = new RestoreRequest( project, sources.Values.Select(s => new PackageSource(s)), packagesDir); if (parallel.HasValue()) { int parallelDegree; if (string.Equals(parallel.Value(), "none", StringComparison.OrdinalIgnoreCase)) { request.MaxDegreeOfConcurrency = 1; } else if (int.TryParse(parallel.Value(), out parallelDegree)) { request.MaxDegreeOfConcurrency = parallelDegree; } } if (request.MaxDegreeOfConcurrency <= 1) { _log.LogInformation("Running non-parallel restore"); } else { _log.LogInformation($"Running restore with {request.MaxDegreeOfConcurrency} concurrent jobs"); } var command = new RestoreCommand(loggerFactory); var sw = Stopwatch.StartNew(); var result = await command.ExecuteAsync(request); sw.Stop(); _log.LogInformation($"Restore completed in {sw.ElapsedMilliseconds:0.00}ms!"); return(0); }); }); app.Command("diag", diag => { diag.Description = "Diagnostic commands for debugging package dependency graphs"; diag.Command("lockfile", lockfile => { lockfile.Description = "Dumps data from the project lock file"; var project = lockfile.Option("--project <project>", "Path containing the project lockfile, or the patht to the lockfile itself", CommandOptionType.SingleValue); var target = lockfile.Option("--target <target>", "View information about a specific project target", CommandOptionType.SingleValue); var library = lockfile.Argument("<library>", "Optionally, get detailed information about a specific library"); lockfile.OnExecute(() => { var diagnostics = new DiagnosticCommands(loggerFactory); var projectFile = project.HasValue() ? project.Value() : Path.GetFullPath("."); return(diagnostics.Lockfile(projectFile, target.Value(), library.Value)); }); }); diag.OnExecute(() => { diag.ShowHelp(); return(0); }); }); app.OnExecute(() => { app.ShowHelp(); return(0); }); return(app.Execute(args)); }