/// <summary> /// This is a helper method for looking up directories that directly contains assemblies that would be loaded /// given the published runtime framework. We should run crossgen on these folders /// </summary> private IEnumerable <string> ResolveOutputAssemblies(PublishRoot root) { var resolver = new DefaultPackagePathResolver(root.TargetPackagesPath); if (root.LockFile == null) { return(Enumerable.Empty <string>()); } var directories = new HashSet <string>(); foreach (var target in root.LockFile.Targets) { foreach (var library in target.Libraries) { var packagesDir = resolver.GetInstallPath(library.Name, library.Version); foreach (var path in library.RuntimeAssemblies) { var assemblyPath = CombinePath(packagesDir, path); directories.Add(Path.GetDirectoryName(assemblyPath)); } } } return(directories); }
public bool BuildNativeImages(PublishRoot root) { var success = true; // REVIEW: Does does doing this for multiple runtimes make sense? foreach (var runtime in root.Runtimes) { var runtimeBin = Path.Combine(runtime.TargetPath, "bin"); var options = new CrossgenOptions() { CrossgenPath = Path.Combine(runtimeBin, "crossgen.exe"), InputPaths = ResolveOutputAssemblies(root), RuntimePath = runtimeBin, Symbols = false }; var crossgenManager = new CrossgenManager(options); success &= crossgenManager.GenerateNativeImages(); if (!success) { return(false); } } return(success); }
private async Task <bool> Restore(PublishRoot root, PublishProject publishProject, string restoreDirectory) { var appEnv = (IApplicationEnvironment)root.HostServices.GetService(typeof(IApplicationEnvironment)); var feedOptions = new FeedOptions(); feedOptions.IgnoreFailedSources = true; feedOptions.Sources.Add(root.TargetPackagesPath); feedOptions.TargetPackagesFolder = root.TargetPackagesPath; var restoreCommand = new RestoreCommand(appEnv); foreach (var runtime in root.Runtimes) { restoreCommand.TargetFrameworks.Add(publishProject.SelectFrameworkForRuntime(runtime)); } restoreCommand.SkipRestoreEvents = true; restoreCommand.SkipInstall = true; // This is a workaround for #1322. Since we use restore to generate the lock file // after publish, it's possible to fail restore after copying the closure // if framework assemblies and packages have the same name. This is more likely now // since dependencies may exist in the top level restoreCommand.IgnoreMissingDependencies = true; restoreCommand.CheckHashFile = false; restoreCommand.RestoreDirectories.Add(restoreDirectory); restoreCommand.FeedOptions = feedOptions; // Mute "dnu restore" subcommand restoreCommand.Reports = Reports.Constants.NullReports; var success = await restoreCommand.Execute(); return(success); }
public bool BuildNativeImages(PublishRoot root) { var success = true; foreach (var runtime in root.Runtimes) { NuGetDependencyResolver resolver; if (!_resolverLookup.TryGetValue(runtime.Framework, out resolver)) { throw new InvalidOperationException("No matching framework is found for " + runtime.Framework); } var runtimeBin = Path.Combine(runtime.TargetPath, "bin"); var options = new CrossgenOptions() { CrossgenPath = Path.Combine(runtimeBin, "crossgen.exe"), InputPaths = ResolveOutputAssemblies(root, resolver), RuntimePath = runtimeBin, Symbols = false }; var crossgenManager = new CrossgenManager(options); success &= crossgenManager.GenerateNativeImages(); if (!success) { return(false); } } return(success); }
/// <summary> /// This is a helper method for looking up directories that directly contains assemblies that would be loaded /// given the published runtime framework. We should run crossgen on these folders /// </summary> private IEnumerable<string> ResolveOutputAssemblies(PublishRoot root) { var resolver = new DefaultPackagePathResolver(root.TargetPackagesPath); if (root.PublishedLockFile == null) { return Enumerable.Empty<string>(); } var directories = new HashSet<string>(); foreach (var target in root.PublishedLockFile.Targets) { foreach (var library in target.Libraries) { var packagesDir = resolver.GetInstallPath(library.Name, library.Version); foreach (var path in library.RuntimeAssemblies) { var assemblyPath = CombinePath(packagesDir, path); directories.Add(Path.GetDirectoryName(assemblyPath)); } } } return directories; }
private void CopyProject(PublishRoot root, Runtime.Project project, string targetPath, bool includeSource) { var additionalExcluding = new List <string>(); // If a public folder is specified with 'webroot' or '--wwwroot', we ignore it when copying project files var wwwRootPath = string.Empty; if (!string.IsNullOrEmpty(WwwRoot)) { wwwRootPath = Path.GetFullPath(Path.Combine(project.ProjectDirectory, WwwRoot)); wwwRootPath = PathUtility.EnsureTrailingSlash(wwwRootPath); } // If project root is used as value of '--wwwroot', we shouldn't exclude it when copying if (string.Equals(wwwRootPath, PathUtility.EnsureTrailingSlash(project.ProjectDirectory))) { wwwRootPath = string.Empty; } if (!string.IsNullOrEmpty(wwwRootPath)) { additionalExcluding.Add(wwwRootPath.Substring(PathUtility.EnsureTrailingSlash(project.ProjectDirectory).Length)); } var sourceFiles = project.Files.GetFilesForBundling(includeSource, additionalExcluding); root.Operations.Copy(sourceFiles, project.ProjectDirectory, targetPath); }
public bool BuildNativeImages(PublishRoot root) { var success = true; foreach (var runtime in root.Runtimes) { NuGetDependencyResolver resolver; if (!_resolverLookup.TryGetValue(runtime.Framework, out resolver)) { throw new InvalidOperationException("No matching framework is found for " + runtime.Framework); } var runtimeBin = Path.Combine(runtime.TargetPath, "bin"); var options = new CrossgenOptions() { CrossgenPath = Path.Combine(runtimeBin, "crossgen.exe"), InputPaths = ResolveOutputAssemblies(root, resolver), RuntimePath = runtimeBin, Symbols = false }; var crossgenManager = new CrossgenManager(options); success &= crossgenManager.GenerateNativeImages(); if (!success) { return false; } } return success; }
private void EmitSource(PublishRoot root) { root.Reports.Quiet.WriteLine(" Copying source code from {0} dependency {1}", _projectDescription.Type, _projectDescription.Identity.Name); var project = GetCurrentProject(); var targetName = project.Name; TargetPath = Path.Combine( root.OutputPath, PublishRoot.AppRootName, PublishRoot.SourceFolderName, targetName); // If root.OutputPath is specified by --out option, it might not be a full path TargetPath = Path.GetFullPath(TargetPath); root.Reports.Quiet.WriteLine(" Source {0}", _projectDescription.Path.Bold()); root.Reports.Quiet.WriteLine(" Target {0}", TargetPath); root.Operations.Delete(TargetPath); CopyProject(root, project, TargetPath, includeSource: true); CopyRelativeSources(project); UpdateWebRoot(root, TargetPath); var appBase = Path.Combine(PublishRoot.AppRootName, "src", project.Name); _relativeAppBase = Path.Combine("..", appBase); ApplicationBasePath = Path.Combine(root.OutputPath, appBase); }
private async Task <bool> Restore(PublishRoot root, PublishProject publishProject, string restoreDirectory, IEnumerable <FrameworkName> targetFrameworks) { var appEnv = PlatformServices.Default.Application; var feedOptions = new FeedOptions(); feedOptions.IgnoreFailedSources = true; feedOptions.Sources.Add(root.TargetPackagesPath); feedOptions.TargetPackagesFolder = root.TargetPackagesPath; var restoreCommand = new RestoreCommand(appEnv); restoreCommand.TargetFrameworks.AddRange(targetFrameworks); restoreCommand.RequestedRuntimes = root.RuntimeIdentifiers; restoreCommand.SkipRestoreEvents = true; restoreCommand.SkipInstall = true; // This is a workaround for #1322. Since we use restore to generate the lock file // after publish, it's possible to fail restore after copying the closure // if framework assemblies and packages have the same name. This is more likely now // since dependencies may exist in the top level restoreCommand.IgnoreMissingDependencies = true; restoreCommand.CheckHashFile = false; restoreCommand.RestoreDirectories.Add(restoreDirectory); restoreCommand.FeedOptions = feedOptions; // Mute "dnu restore" subcommand restoreCommand.Reports = Reports.Constants.NullReports; var success = await restoreCommand.Execute(); return(success); }
public bool Emit(PublishRoot root) { root.Reports.Quiet.WriteLine("Bundling runtime {0}", Name); if (Directory.Exists(TargetPath)) { root.Reports.Quiet.WriteLine(" {0} already exists.", TargetPath); // REVIEW: IS this correct? return(true); } if (!Directory.Exists(TargetPath)) { Directory.CreateDirectory(TargetPath); } new PublishOperations().Copy(_runtimePath, TargetPath); if (!RuntimeEnvironmentHelper.IsWindows) { // Executable permissions on dnx lost on copy. var dnxPath = Path.Combine(TargetPath, "bin", "dnx"); if (!FileOperationUtils.MarkExecutable(dnxPath)) { root.Reports.Information.WriteLine("Failed to mark {0} as executable".Yellow(), dnxPath); } } return(true); }
public bool PostProcess(PublishRoot root) { // At this point, all nupkgs generated from dependency projects are available in packages folder // So we can add them to lockfile now if (!UpdateLockFile(root)) { return(false); } // Prune the packages folder only leaving things that are required PrunePackages(root); // If --wwwroot-out doesn't have a non-empty value, we don't need a public app folder in output if (string.IsNullOrEmpty(WwwRootOut)) { return(true); } var project = GetCurrentProject(); // Construct path to public app folder, which contains content files and tool dlls // The name of public app folder is specified with "--appfolder" option // Default name of public app folder is the same as main project var wwwRootOutPath = Path.Combine(root.OutputPath, WwwRootOut); // Delete old public app folder because we don't want leftovers from previous operations root.Operations.Delete(wwwRootOutPath); Directory.CreateDirectory(wwwRootOutPath); // Copy content files (e.g. html, js and images) of main project into public app folder CopyContentFiles(root, project, wwwRootOutPath); return(GenerateWebConfigFileForWwwRootOut(root, project, wwwRootOutPath)); }
public PublishRuntime(PublishRoot root, FrameworkName frameworkName, string runtimePath) { _frameworkName = frameworkName; _runtimePath = runtimePath; Name = new DirectoryInfo(_runtimePath).Name; TargetPath = Path.Combine(root.TargetRuntimesPath, Name); }
public bool Emit(PublishRoot root) { root.Reports.Quiet.WriteLine("Bundling runtime {0}", Name); if (Directory.Exists(TargetPath)) { root.Reports.Quiet.WriteLine(" {0} already exists.", TargetPath); // REVIEW: IS this correct? return true; } if (!Directory.Exists(TargetPath)) { Directory.CreateDirectory(TargetPath); } new PublishOperations().Copy(_runtimePath, TargetPath); if (!RuntimeEnvironmentHelper.IsWindows) { // Executable permissions on dnx lost on copy. var dnxPath = Path.Combine(TargetPath, "bin", "dnx"); if (!FileOperationUtils.MarkExecutable(dnxPath)) { root.Reports.Information.WriteLine("Failed to mark {0} as executable".Yellow(), dnxPath); } } return true; }
public bool BuildNativeImages(PublishRoot root) { var success = true; // REVIEW: Does does doing this for multiple runtimes make sense? foreach (var runtime in root.Runtimes) { var runtimeBin = Path.Combine(runtime.TargetPath, "bin"); var options = new CrossgenOptions() { CrossgenPath = Path.Combine(runtimeBin, "crossgen.exe"), InputPaths = ResolveOutputAssemblies(root), RuntimePath = runtimeBin, Symbols = false }; var crossgenManager = new CrossgenManager(options); success &= crossgenManager.GenerateNativeImages(); if (!success) { return false; } } return success; }
private static string GetBootstrapperVersion(PublishRoot root) { // Use version of Microsoft.AspNet.Loader.IIS.Interop as version of bootstrapper var package = root.Packages.SingleOrDefault( x => string.Equals(x.Library.Name, "Microsoft.AspNet.Loader.IIS.Interop")); return(package == null ? string.Empty : package.Library.Version.ToString()); }
bool TryAddRuntime(PublishRoot root, FrameworkName frameworkName, string runtimePath) { if (!Directory.Exists(runtimePath)) { return(false); } root.Runtimes.Add(new PublishRuntime(root, frameworkName, runtimePath)); return(true); }
private void UpdateWebRoot(PublishRoot root, string targetPath) { // Update the 'webroot' property, which was specified with '--wwwroot-out' option if (!string.IsNullOrEmpty(WwwRootOut)) { var targetProjectJson = Path.Combine(targetPath, Runtime.Project.ProjectFileName); UpdateJson(targetProjectJson, jsonObj => { var targetWebRootPath = Path.Combine(root.OutputPath, WwwRootOut); jsonObj["webroot"] = PathUtility.GetRelativePath(targetProjectJson, targetWebRootPath, separator: '/'); }); } }
private bool UpdateLockFile(PublishRoot root) { var tasks = new Task <bool> [root.Projects.Count]; for (int i = 0; i < root.Projects.Count; i++) { var project = root.Projects[i]; var restoreDirectory = project.IsPackage ? Path.Combine(project.TargetPath, "root") : project.TargetPath; tasks[i] = Restore(root, project, restoreDirectory); } Task.WaitAll(tasks); return(tasks.All(t => t.Result)); }
private void CopyContentFiles(PublishRoot root, Runtime.Project project, string targetFolderPath) { root.Reports.Quiet.WriteLine("Copying contents of {0} dependency {1} to {2}", _projectDescription.Type, _projectDescription.Identity.Name, targetFolderPath); var contentSourcePath = GetWwwRootSourcePath(project.ProjectDirectory, WwwRoot); root.Reports.Quiet.WriteLine(" Source {0}", contentSourcePath); root.Reports.Quiet.WriteLine(" Target {0}", targetFolderPath); if (Directory.Exists(contentSourcePath)) { root.Operations.Copy(contentSourcePath, targetFolderPath); } }
/// <summary> /// This is a helper method for looking up directories that directly contains assemblies that would be loaded /// given the published runtime framework. We should run crossgen on these folders /// </summary> private IEnumerable <string> ResolveOutputAssemblies(PublishRoot root, NuGetDependencyResolver resolver) { var outputPathsMap = root.Packages .ToDictionary( pkg => pkg.Library, pkg => pkg.TargetPath ); var result = new HashSet <string>(); var libraryNotInOutput = new List <LibraryIdentity>(); var missingOutputFolder = new List <string>(); foreach (var dependency in resolver.PackageAssemblyLookup.Values) { var libId = dependency.Library.Identity; var libPath = dependency.Library.Path; var assemblyDir = Path.GetDirectoryName(dependency.Path); var assemblySelection = assemblyDir.Substring(libPath.Length); string outputLibLocation; if (!outputPathsMap.TryGetValue(libId, out outputLibLocation)) { libraryNotInOutput.Add(libId); continue; } var output = outputLibLocation + assemblySelection; if (!Directory.Exists(output)) { missingOutputFolder.Add(output); } else { result.Add(output); } } if (libraryNotInOutput.Any()) { throw new InvalidOperationException(string.Format("Library {0} cannot be found in the published output.", string.Join(", ", libraryNotInOutput))); } if (missingOutputFolder.Any()) { throw new InvalidOperationException("Published output does not contain directory:\n" + string.Join("\n", missingOutputFolder)); } return(result); }
private IEnumerable <FrameworkName> SelectCompatibleFrameworks(PublishRoot root, Runtime.Project project, IEnumerable <FrameworkName> requestedFrameworks) { var selectedFrameworks = new List <FrameworkName>(); foreach (var framework in requestedFrameworks) { var selectedFramework = project.GetCompatibleTargetFramework(framework); if (selectedFramework == null) { root.Reports.WriteError($"Unable to build {project.Name}. It is not compatible with the requested target framework: {framework}"); return(null); } selectedFrameworks.Add(selectedFramework.FrameworkName); } return(selectedFrameworks); }
public void Emit(PublishRoot root) { root.Reports.Quiet.WriteLine("Using {0} dependency {1}", _package.Type, Library); var srcPackagePathResolver = new DefaultPackagePathResolver(root.SourcePackagesPath); var targetPackagePathResolver = new DefaultPackagePathResolver(root.TargetPackagesPath); var srcPackageDir = srcPackagePathResolver.GetInstallPath( _package.Identity.Name, _package.Identity.Version); var targetPackageDir = targetPackagePathResolver.GetInstallPath( _package.Identity.Name, _package.Identity.Version); root.Reports.Quiet.WriteLine(" Source {0}", srcPackageDir.Bold()); root.Reports.Quiet.WriteLine(" Target {0}", targetPackageDir); root.Operations.Copy(srcPackageDir, targetPackageDir); }
private bool UpdateLockFile(PublishRoot root) { var appEnv = (IApplicationEnvironment)root.HostServices.GetService(typeof(IApplicationEnvironment)); var feedOptions = new FeedOptions(); feedOptions.IgnoreFailedSources = true; feedOptions.Sources.Add(root.TargetPackagesPath); feedOptions.TargetPackagesFolder = root.TargetPackagesPath; var tasks = new Task <bool> [root.Projects.Count]; for (int i = 0; i < root.Projects.Count; i++) { var project = root.Projects[i]; var restoreCommand = new RestoreCommand(appEnv); foreach (var runtime in root.Runtimes) { restoreCommand.TargetFrameworks.Add(project.SelectFrameworkForRuntime(runtime)); } var restoreDirectory = project.IsPackage ? Path.Combine(project.TargetPath, "root") : project.TargetPath; restoreCommand.SkipRestoreEvents = true; restoreCommand.SkipInstall = true; // This is a workaround for #1322. Since we use restore to generate the lock file // after publish, it's possible to fail restore after copying the closure // if framework assemblies and packages have the same name. This is more likely now // since dependencies may exist in the top level restoreCommand.IgnoreMissingDependencies = true; restoreCommand.CheckHashFile = false; restoreCommand.RestoreDirectories.Add(restoreDirectory); restoreCommand.FeedOptions = feedOptions; // Mute "dnu restore" subcommand restoreCommand.Reports = Reports.Constants.NullReports; tasks[i] = restoreCommand.Execute(); } Task.WaitAll(tasks); return(tasks.All(t => t.Result)); }
private static void CopyAspNetLoaderDll(PublishRoot root, string wwwRootOutPath) { // Tool dlls including AspNet.Loader.dll go to bin folder under public app folder var wwwRootOutBinPath = Path.Combine(wwwRootOutPath, "bin"); // Check for an environment variable which can be used (generally in tests) // to override where AspNet.Loader.dll is located. var loaderPath = Environment.GetEnvironmentVariable(EnvironmentNames.AspNetLoaderPath); if (string.IsNullOrEmpty(loaderPath)) { // Copy Microsoft.AspNet.Loader.IIS.Interop/tools/*.dll into bin to support AspNet.Loader.dll var package = root.Packages.SingleOrDefault( x => string.Equals(x.Library.Name, "Microsoft.AspNet.Loader.IIS.Interop")); if (package == null) { return; } var resolver = new DefaultPackagePathResolver(root.SourcePackagesPath); var packagePath = resolver.GetInstallPath(package.Library.Name, package.Library.Version); loaderPath = Path.Combine(packagePath, "tools"); } if (!string.IsNullOrEmpty(loaderPath) && Directory.Exists(loaderPath)) { foreach (var packageToolFile in Directory.EnumerateFiles(loaderPath, "*.dll").Select(Path.GetFileName)) { // Create the bin folder only when we need to put something inside it if (!Directory.Exists(wwwRootOutBinPath)) { Directory.CreateDirectory(wwwRootOutBinPath); } // Copy to bin folder under public app folder File.Copy( Path.Combine(loaderPath, packageToolFile), Path.Combine(wwwRootOutBinPath, packageToolFile), overwrite: true); } } }
public async Task Emit(PublishRoot root) { root.Reports.Quiet.WriteLine("Using {0} dependency {1}", _libraryDescription.Type, Library); var packagePathResolver = new DefaultPackagePathResolver(root.SourcePackagesPath); var srcNupkgPath = packagePathResolver.GetPackageFilePath(_libraryDescription.Identity.Name, _libraryDescription.Identity.Version); var options = new Packages.AddOptions { NuGetPackage = srcNupkgPath, PackageHashFilePath = Path.ChangeExtension(srcNupkgPath, NuGet.Constants.HashFileExtension), SourcePackages = root.TargetPackagesPath, }; // Mute "packages add" subcommand options.Reports = Reports.Constants.NullReports; var packagesAddCommand = new Packages.AddCommand(options); await packagesAddCommand.Execute(); }
public bool Emit(PublishRoot root) { root.Reports.Quiet.WriteLine("Using {0} dependency {1} for {2}", _projectDescription.Type, _projectDescription.Identity, _projectDescription.Framework.ToString().Yellow().Bold()); var success = true; if (root.NoSource || IsWrappingAssembly()) { success = EmitNupkg(root); } else { success = EmitSource(root); } root.Reports.Quiet.WriteLine(); return success; }
public bool Emit(PublishRoot root) { root.Reports.Quiet.WriteLine("Using {0} dependency {1} for {2}", _projectDescription.Type, _projectDescription.Identity, _projectDescription.Framework.ToString().Yellow().Bold()); var success = true; if (root.NoSource || IsWrappingAssembly()) { success = EmitNupkg(root); } else { EmitSource(root); } root.Reports.Quiet.WriteLine(); return(success); }
/// <summary> /// This is the factory method to instantiate a PackNativeManager, if parameters are in invalid state and native /// generation cannot be performed, it would return null /// </summary> public static NativeImageGenerator Create(PublishOptions options, PublishRoot root, IEnumerable<DependencyContext> contexts) { if (options.Runtimes.Count() == 0) { options.Reports.Information.WriteLine( "Please provide target CoreCLR runtimes using --runtime flags".Yellow()); return null; } foreach (var runtime in root.Runtimes) { var frameworkName = runtime.Framework; // NOTE: !IsDesktop == IsCore and only Core packages can be crossgened at least for now if (VersionUtility.IsDesktop(frameworkName)) { options.Reports.Information.WriteLine( "Native image generation is only supported for .NET Core flavors.".Yellow()); return null; } } var duplicates = options.Runtimes .GroupBy(r => CrossgenManager.ResolveProcessorArchitecture(r)) .Where(g => g.Count() > 1); if (duplicates.Any()) { var message = "The following runtimes will result in output conflicts. Please provide distinct runtime flavor for each processor architecture:\n" + string.Join("\n", duplicates.Select( g => string.Format("Architecture: {0}\nRuntimes: {1}", g.Key, string.Join(", ", g)))); options.Reports.Information.WriteLine(message.Yellow()); return null; } var contextMap = contexts.ToDictionary( context => context.FrameworkName, context => context.NuGetDependencyResolver ); return new NativeImageGenerator(contextMap); }
/// <summary> /// This is the factory method to instantiate a PackNativeManager, if parameters are in invalid state and native /// generation cannot be performed, it would return null /// </summary> public static NativeImageGenerator Create(PublishOptions options, PublishRoot root, IEnumerable <DependencyContext> contexts) { if (options.Runtimes.Count() == 0) { options.Reports.Information.WriteLine( "Please provide target CoreCLR runtimes using --runtime flags".Yellow()); return(null); } foreach (var runtime in root.Runtimes) { var frameworkName = runtime.Framework; // NOTE: !IsDesktop == IsCore and only Core packages can be crossgened at least for now if (VersionUtility.IsDesktop(frameworkName)) { options.Reports.Information.WriteLine( "Native image generation is only supported for .NET Core flavors.".Yellow()); return(null); } } var duplicates = options.Runtimes .GroupBy(r => CrossgenManager.ResolveProcessorArchitecture(r)) .Where(g => g.Count() > 1); if (duplicates.Any()) { var message = "The following runtimes will result in output conflicts. Please provide distinct runtime flavor for each processor architecture:\n" + string.Join("\n", duplicates.Select( g => string.Format("Architecture: {0}\nRuntimes: {1}", g.Key, string.Join(", ", g)))); options.Reports.Information.WriteLine(message.Yellow()); return(null); } var contextMap = contexts.ToDictionary( context => context.FrameworkName, context => context.NuGetDependencyResolver ); return(new NativeImageGenerator(contextMap)); }
private void UpdateWebRoot(PublishRoot root, string targetPath) { // Update the 'webroot' property, which was specified with '--wwwroot-out' option if (!string.IsNullOrEmpty(WwwRootOut)) { var hostingConfig = Path.Combine(targetPath, "hosting.json"); if (!File.Exists(hostingConfig)) { File.AppendAllText(hostingConfig, $@"{{ ""webroot"": ""{PathUtility.GetRelativePath(hostingConfig, Path.Combine(root.OutputPath, WwwRootOut), separator: '/')}"" }}"); } else { UpdateJson(hostingConfig, jsonObj => { var targetWebRootPath = Path.Combine(root.OutputPath, WwwRootOut); PublishOperations.SetWebRootJson(jsonObj, PathUtility.GetRelativePath(hostingConfig, targetWebRootPath, separator: '/')); }); } } }
private bool EmitNupkg(PublishRoot root) { root.Reports.Quiet.WriteLine(" Packing nupkg from {0} dependency {1}", _projectDescription.Type, _projectDescription.Identity.Name); IsPackage = true; var project = GetCurrentProject(); if (project == null) { return false; } var resolver = new DefaultPackagePathResolver(root.TargetPackagesPath); var targetNupkg = resolver.GetPackageFileName(project.Name, project.Version); TargetPath = resolver.GetInstallPath(project.Name, project.Version); root.Reports.Quiet.WriteLine(" Source {0}", _projectDescription.Path.Bold()); root.Reports.Quiet.WriteLine(" Target {0}", TargetPath); if (Directory.Exists(TargetPath)) { root.Operations.Delete(TargetPath); } // If this is a wrapper project, we need to generate a lock file before building it if (IsWrappingAssembly()) { var success = Restore(root, publishProject: this, restoreDirectory: project.ProjectDirectory) .GetAwaiter().GetResult(); if (!success) { return false; } } // Generate nupkg from this project dependency var buildOptions = new BuildOptions(); buildOptions.ProjectPatterns.Add(project.ProjectDirectory); buildOptions.OutputDir = Path.Combine(project.ProjectDirectory, "bin"); buildOptions.Configurations.Add(root.Configuration); buildOptions.GeneratePackages = true; buildOptions.Reports = root.Reports.ShallowCopy(); if (root.Frameworks.Any()) { // Make sure we only emit the nupkgs for the specified frameworks // We need to pick actual project frameworks relevant to the publish // but the project may not target exactly the right framework so we need // to use a compatibility check. foreach (var framework in root.Frameworks) { var selectedFramework = project.GetCompatibleTargetFramework(framework.Key); if (selectedFramework == null) { root.Reports.WriteError($"Unable to build {project.Name}. It is not compatible with the requested target framework: {framework.Key}"); return false; } buildOptions.TargetFrameworks.Add(selectedFramework.FrameworkName, VersionUtility.GetShortFrameworkName(selectedFramework.FrameworkName)); } } // Mute "dnu pack" completely if it is invoked by "dnu publish --quiet" buildOptions.Reports.Information = root.Reports.Quiet; var buildManager = new BuildManager(root.HostServices, buildOptions); if (!buildManager.Build()) { return false; } // Extract the generated nupkg to target path var srcNupkgPath = Path.Combine(buildOptions.OutputDir, root.Configuration, targetNupkg); var srcSymbolsNupkgPath = Path.ChangeExtension(srcNupkgPath, "symbols.nupkg"); var options = new Packages.AddOptions { NuGetPackage = root.IncludeSymbols ? srcSymbolsNupkgPath : srcNupkgPath, SourcePackages = root.TargetPackagesPath, Reports = root.Reports }; var packagesAddCommand = new Packages.AddCommand(options); packagesAddCommand.Execute().GetAwaiter().GetResult(); // Copy content files (e.g. html, js and images) of main project into "root" folder of the exported package var rootFolderPath = Path.Combine(TargetPath, "root"); var rootProjectJson = Path.Combine(rootFolderPath, Runtime.Project.ProjectFileName); root.Operations.Delete(rootFolderPath); CopyProject(root, project, rootFolderPath, includeSource: false); UpdateWebRoot(root, rootFolderPath); UpdateJson(rootProjectJson, jsonObj => { // Update the project entrypoint jsonObj["entryPoint"] = _projectDescription.Identity.Name; // Set mark this as non loadable jsonObj["loadable"] = false; // Update the dependencies node to reference the main project var deps = new JObject(); jsonObj["dependencies"] = deps; deps[_projectDescription.Identity.Name] = _projectDescription.Identity.Version.ToString(); }); var appBase = Path.Combine(PublishRoot.AppRootName, "packages", resolver.GetPackageDirectory(_projectDescription.Identity.Name, _projectDescription.Identity.Version), "root"); _relativeAppBase = Path.Combine("..", appBase); ApplicationBasePath = Path.Combine(root.OutputPath, appBase); root.Reports.Quiet.WriteLine("Removing {0}", srcNupkgPath); File.Delete(srcNupkgPath); root.Reports.Quiet.WriteLine("Removing {0}", srcSymbolsNupkgPath); File.Delete(srcSymbolsNupkgPath); return true; }
private void PrunePackages(PublishRoot root) { if (root.MainProjectLockFile == null) { return; } var resolver = new DefaultPackagePathResolver(root.TargetPackagesPath); var lockFilePath = Path.GetFullPath(Path.Combine(ApplicationBasePath, LockFileFormat.LockFileName)); root.PublishedLockFile = new LockFileFormat().Read(lockFilePath); var filesToKeep = new HashSet <string>(); var filesToRemove = new HashSet <string>(); foreach (var target in root.PublishedLockFile.Targets) { foreach (var library in target.Libraries) { var packageDir = resolver.GetInstallPath(library.Name, library.Version); if (library.Name != root.MainProjectName && string.Equals(library.Type, Runtime.LibraryTypes.Package, StringComparison.OrdinalIgnoreCase)) { filesToRemove.Add(resolver.GetHashPath(library.Name, library.Version)); filesToRemove.Add(resolver.GetPackageFilePath(library.Name, library.Version)); filesToRemove.AddRange(Directory.EnumerateFiles(packageDir, $"{library.Name}.xml", SearchOption.AllDirectories)); } foreach (var path in library.RuntimeAssemblies) { filesToKeep.Add(Path.Combine(packageDir, path)); } foreach (var path in library.CompileTimeAssemblies) { filesToKeep.Add(Path.Combine(packageDir, path)); } foreach (var path in library.NativeLibraries) { filesToKeep.Add(Path.Combine(packageDir, path)); } foreach (var path in library.ResourceAssemblies) { filesToKeep.Add(Path.Combine(packageDir, path)); } } } foreach (var target in root.MainProjectLockFile.Targets.Where(projectTarget => string.IsNullOrEmpty(projectTarget.RuntimeIdentifier) && !root.PublishedLockFile.Targets.Any(publishTarget => projectTarget.TargetFramework == publishTarget.TargetFramework))) { foreach (var library in target.Libraries) { var packageDir = resolver.GetInstallPath(library.Name, library.Version); if (Directory.Exists(packageDir)) { foreach (var path in library.RuntimeAssemblies) { filesToRemove.Add(Path.Combine(packageDir, path)); } foreach (var path in library.CompileTimeAssemblies) { filesToRemove.Add(Path.Combine(packageDir, path)); } foreach (var path in library.NativeLibraries) { filesToRemove.Add(Path.Combine(packageDir, path)); } foreach (var path in library.ResourceAssemblies) { filesToRemove.Add(Path.Combine(packageDir, path)); } } } } foreach (var file in filesToRemove.Except(filesToKeep)) { File.Delete(file); } if (Directory.Exists(root.TargetPackagesPath)) { root.Operations.DeleteEmptyFolders(root.TargetPackagesPath); } return; }
private bool EmitNupkg(PublishRoot root) { root.Reports.Quiet.WriteLine(" Packing nupkg from {0} dependency {1}", _libraryDescription.Type, _libraryDescription.Identity.Name); IsPackage = true; var project = GetCurrentProject(); var resolver = new DefaultPackagePathResolver(root.TargetPackagesPath); var targetNupkg = resolver.GetPackageFileName(project.Name, project.Version); TargetPath = resolver.GetInstallPath(project.Name, project.Version); root.Reports.Quiet.WriteLine(" Source {0}", _libraryDescription.Path.Bold()); root.Reports.Quiet.WriteLine(" Target {0}", TargetPath); if (Directory.Exists(TargetPath)) { root.Operations.Delete(TargetPath); } // Generate nupkg from this project dependency var buildOptions = new BuildOptions(); buildOptions.ProjectPatterns.Add(project.ProjectDirectory); buildOptions.OutputDir = Path.Combine(project.ProjectDirectory, "bin"); buildOptions.Configurations.Add(root.Configuration); buildOptions.GeneratePackages = true; buildOptions.Reports = root.Reports.ShallowCopy(); // Mute "dnu pack" completely if it is invoked by "dnu publish --quiet" buildOptions.Reports.Information = root.Reports.Quiet; var buildManager = new BuildManager(root.HostServices, buildOptions); if (!buildManager.Build()) { return false; } // Extract the generated nupkg to target path var srcNupkgPath = Path.Combine(buildOptions.OutputDir, root.Configuration, targetNupkg); var srcSymbolsNupkgPath = Path.ChangeExtension(srcNupkgPath, "symbols.nupkg"); var options = new Packages.AddOptions { NuGetPackage = root.IncludeSymbols ? srcSymbolsNupkgPath : srcNupkgPath, SourcePackages = root.TargetPackagesPath, Reports = root.Reports }; var packagesAddCommand = new Packages.AddCommand(options); packagesAddCommand.Execute().GetAwaiter().GetResult(); // Copy content files (e.g. html, js and images) of main project into "root" folder of the exported package var rootFolderPath = Path.Combine(TargetPath, "root"); var rootProjectJson = Path.Combine(rootFolderPath, Runtime.Project.ProjectFileName); root.Operations.Delete(rootFolderPath); CopyProject(root, project, rootFolderPath, includeSource: false); UpdateWebRoot(root, rootFolderPath); UpdateJson(rootProjectJson, jsonObj => { // Update the project entrypoint jsonObj["entryPoint"] = _libraryDescription.Identity.Name; // Set mark this as non loadable jsonObj["loadable"] = false; // Update the dependencies node to reference the main project var deps = new JObject(); jsonObj["dependencies"] = deps; deps[_libraryDescription.Identity.Name] = _libraryDescription.Identity.Version.ToString(); }); var appBase = Path.Combine(PublishRoot.AppRootName, "packages", resolver.GetPackageDirectory(_libraryDescription.Identity.Name, _libraryDescription.Identity.Version), "root"); _relativeAppBase = Path.Combine("..", appBase); ApplicationBasePath = Path.Combine(root.OutputPath, appBase); root.Reports.Quiet.WriteLine("Removing {0}", srcNupkgPath); File.Delete(srcNupkgPath); root.Reports.Quiet.WriteLine("Removing {0}", srcSymbolsNupkgPath); File.Delete(srcSymbolsNupkgPath); return true; }
private void GenerateWebConfigFileForWwwRootOut(PublishRoot root, Runtime.Project project, string wwwRootOutPath) { // Generate web.config for public app folder var wwwRootOutWebConfigFilePath = Path.Combine(wwwRootOutPath, "web.config"); var wwwRootSourcePath = GetWwwRootSourcePath(project.ProjectDirectory, WwwRoot); var webConfigFilePath = Path.Combine(wwwRootSourcePath, "web.config"); XDocument xDoc; if (File.Exists(webConfigFilePath)) { xDoc = XDocument.Parse(File.ReadAllText(webConfigFilePath)); } else { xDoc = new XDocument(); } if (xDoc.Root == null) { xDoc.Add(new XElement("configuration")); } if (xDoc.Root.Name != "configuration") { throw new InvalidDataException("'configuration' is the only valid name for root element of web.config file"); } var appSettingsElement = GetOrAddElement(parent: xDoc.Root, name: "appSettings"); // Always generate \ since web.config is a IIS thing only var relativeRuntimesPath = PathUtility.GetRelativePath(wwwRootOutWebConfigFilePath, root.TargetRuntimesPath) .Replace(Path.DirectorySeparatorChar, '\\'); var defaultRuntime = root.Runtimes.FirstOrDefault(); var appBase = _relativeAppBase.Replace(Path.DirectorySeparatorChar, '\\'); var keyValuePairs = new Dictionary <string, string>() { { Runtime.Constants.WebConfigBootstrapperVersion, GetBootstrapperVersion(root) }, { Runtime.Constants.WebConfigRuntimePath, relativeRuntimesPath }, { Runtime.Constants.WebConfigRuntimeVersion, GetRuntimeVersion(defaultRuntime) }, { Runtime.Constants.WebConfigRuntimeFlavor, GetRuntimeFlavor(defaultRuntime) }, { Runtime.Constants.WebConfigRuntimeAppBase, appBase }, }; foreach (var pair in keyValuePairs) { var addElement = appSettingsElement.Elements() .Where(x => x.Name == "add" && x.Attribute("key").Value == pair.Key) .SingleOrDefault(); if (addElement == null) { addElement = new XElement("add"); addElement.SetAttributeValue("key", pair.Key); appSettingsElement.Add(addElement); } addElement.SetAttributeValue("value", pair.Value); } // Generate target framework information ApplyTargetFramework(xDoc, project); var xmlWriterSettings = new XmlWriterSettings { Indent = true, ConformanceLevel = ConformanceLevel.Auto }; using (var xmlWriter = XmlWriter.Create(File.Create(wwwRootOutWebConfigFilePath), xmlWriterSettings)) { xDoc.WriteTo(xmlWriter); } }
private void GenerateWebConfigFileForWwwRootOut(PublishRoot root, Runtime.Project project, string wwwRootOutPath) { // Generate web.config for public app folder var wwwRootOutWebConfigFilePath = Path.Combine(wwwRootOutPath, "web.config"); var wwwRootSourcePath = GetWwwRootSourcePath(project.ProjectDirectory, WwwRoot); var webConfigFilePath = Path.Combine(wwwRootSourcePath, "web.config"); XDocument xDoc; if (File.Exists(webConfigFilePath)) { xDoc = XDocument.Parse(File.ReadAllText(webConfigFilePath)); } else { xDoc = new XDocument(); } if (xDoc.Root == null) { xDoc.Add(new XElement("configuration")); } if (xDoc.Root.Name != "configuration") { throw new InvalidDataException("'configuration' is the only valid name for root element of web.config file"); } var appSettingsElement = GetOrAddElement(parent: xDoc.Root, name: "appSettings"); // Always generate \ since web.config is a IIS thing only var relativeRuntimesPath = PathUtility.GetRelativePath(wwwRootOutWebConfigFilePath, root.TargetRuntimesPath) .Replace(Path.DirectorySeparatorChar, '\\'); var defaultRuntime = root.Runtimes.FirstOrDefault(); var appBase = _relativeAppBase.Replace(Path.DirectorySeparatorChar, '\\'); var keyValuePairs = new Dictionary<string, string>() { { Runtime.Constants.WebConfigBootstrapperVersion, GetBootstrapperVersion(root) }, { Runtime.Constants.WebConfigRuntimePath, relativeRuntimesPath }, { Runtime.Constants.WebConfigRuntimeVersion, GetRuntimeVersion(defaultRuntime) }, { Runtime.Constants.WebConfigRuntimeFlavor, GetRuntimeFlavor(defaultRuntime) }, { Runtime.Constants.WebConfigRuntimeAppBase, appBase }, }; foreach (var pair in keyValuePairs) { var addElement = appSettingsElement.Elements() .Where(x => x.Name == "add" && x.Attribute("key").Value == pair.Key) .SingleOrDefault(); if (addElement == null) { addElement = new XElement("add"); addElement.SetAttributeValue("key", pair.Key); appSettingsElement.Add(addElement); } addElement.SetAttributeValue("value", pair.Value); } // Generate target framework information ApplyTargetFramework(xDoc, project); var xmlWriterSettings = new XmlWriterSettings { Indent = true, ConformanceLevel = ConformanceLevel.Auto }; using (var xmlWriter = XmlWriter.Create(File.Create(wwwRootOutWebConfigFilePath), xmlWriterSettings)) { xDoc.WriteTo(xmlWriter); } }
private bool PrunePackages(PublishRoot root) { var resolver = new DefaultPackagePathResolver(root.TargetPackagesPath); // Special cases (for backwards compat) var specialFolders = new List<string> { "native", "InteropAssemblies", "redist", "runtimes" }; if (!root.NoSource) { // 'shared' folder is build time dependency, so we only copy it when deploying with source specialFolders.Add("shared"); } var lockFilePath = Path.GetFullPath(Path.Combine(ApplicationBasePath, LockFileFormat.LockFileName)); var format = new LockFileFormat(); root.LockFile = format.Read(lockFilePath); var keep = new HashSet<string>(); foreach (var target in root.LockFile.Targets) { foreach (var library in target.Libraries) { var packagesDir = resolver.GetInstallPath(library.Name, library.Version); var manifest = resolver.GetManifestFilePath(library.Name, library.Version); keep.Add(manifest); foreach (var path in library.RuntimeAssemblies) { keep.Add(CombinePath(packagesDir, path)); } foreach (var path in library.CompileTimeAssemblies) { keep.Add(CombinePath(packagesDir, path)); } foreach (var path in library.NativeLibraries) { keep.Add(CombinePath(packagesDir, path)); } foreach (var path in library.ResourceAssemblies) { keep.Add(CombinePath(packagesDir, path)); } foreach (var specialFolder in specialFolders) { var specialFolderPath = CombinePath(packagesDir, specialFolder); if (!Directory.Exists(specialFolderPath)) { continue; } keep.AddRange(Directory.EnumerateFiles(specialFolderPath, "*.*", SearchOption.AllDirectories)); } } } foreach (var package in root.Packages) { var packageDir = resolver.GetInstallPath(package.Library.Name, package.Library.Version); var packageFiles = Directory.EnumerateFiles(packageDir, "*.*", SearchOption.AllDirectories); foreach (var file in packageFiles) { if (!keep.Contains(file)) { File.Delete(file); } } root.Operations.DeleteEmptyFolders(packageDir); } return true; }
private async Task<bool> Restore(PublishRoot root, PublishProject publishProject, string restoreDirectory) { var appEnv = (IApplicationEnvironment)root.HostServices.GetService(typeof(IApplicationEnvironment)); var feedOptions = new FeedOptions(); feedOptions.IgnoreFailedSources = true; feedOptions.Sources.Add(root.TargetPackagesPath); feedOptions.TargetPackagesFolder = root.TargetPackagesPath; var restoreCommand = new RestoreCommand(appEnv); foreach (var framework in root.Frameworks) { restoreCommand.TargetFrameworks.Add(framework.Key); } restoreCommand.SkipRestoreEvents = true; restoreCommand.SkipInstall = true; // This is a workaround for #1322. Since we use restore to generate the lock file // after publish, it's possible to fail restore after copying the closure // if framework assemblies and packages have the same name. This is more likely now // since dependencies may exist in the top level restoreCommand.IgnoreMissingDependencies = true; restoreCommand.CheckHashFile = false; restoreCommand.RestoreDirectories.Add(restoreDirectory); restoreCommand.FeedOptions = feedOptions; // Mute "dnu restore" subcommand restoreCommand.Reports = Reports.Constants.NullReports; var success = await restoreCommand.Execute(); return success; }
private bool GenerateWebConfigFileForWwwRootOut(PublishRoot root, Runtime.Project project, string wwwRootOutPath) { // Generate web.config for public app folder var wwwRootOutWebConfigFilePath = Path.Combine(wwwRootOutPath, "web.config"); var wwwRootSourcePath = GetWwwRootSourcePath(project.ProjectDirectory, WwwRoot); var webConfigFilePath = Path.Combine(wwwRootSourcePath, "web.config"); XDocument xDoc; if (File.Exists(webConfigFilePath)) { xDoc = XDocument.Parse(File.ReadAllText(webConfigFilePath)); } else { xDoc = new XDocument(); } if (xDoc.Root == null) { xDoc.Add(new XElement("configuration")); } if (xDoc.Root.Name != "configuration") { throw new InvalidDataException("'configuration' is the only valid name for root element of web.config file"); } // <system.webServer> // <handlers> // <add name="httpplatformhandler" path="*" verb="*" modules="httpPlatformHandler" resourceType="Unspecified" /> // </handlers> // <httpPlatform processPath="..\command.cmd" // arguments="" // stdoutLogEnabled="true" // stdoutLogFile="..\logs\stdout.log"> // </httpPlatform> // </system.webServer> // Look for specified command var command = root.IISCommand; if (!string.IsNullOrEmpty(command) && !project.Commands.ContainsKey(command)) { root.Reports.WriteError($"Specified command {command} cannot be found."); return(false); } else if (project.Commands.Count == 1) { command = project.Commands.First().Key; } else if (project.Commands.Count == 0) { root.Reports.WriteWarning("No commands defined. Defaulting to web."); } else { root.Reports.WriteWarning("Multiple commands defined. Defaulting to web."); } command = command ?? "web"; root.Reports.Information.WriteLine($"Using command '{command}' as the entry point for web.config."); var azurePublishValue = Environment.GetEnvironmentVariable("DNU_PUBLISH_AZURE"); var publishingToAzure = string.Equals(azurePublishValue, "true", StringComparison.Ordinal) || string.Equals(azurePublishValue, "1", StringComparison.Ordinal) || !string.IsNullOrEmpty(Environment.GetEnvironmentVariable("WEBSITE_SITE_NAME")); var basePath = publishingToAzure ? @"%home%\site" : ".."; var baseLogPath = publishingToAzure ? @"\\?\%home%\LogFiles" : @"..\logs"; var targetDocument = XDocument.Parse($@"<configuration><system.webServer> <handlers> <add name=""httpplatformhandler"" path=""*"" verb=""*"" modules=""httpPlatformHandler"" resourceType=""Unspecified"" /> </handlers> <httpPlatform processPath=""{basePath}\approot\{command}.cmd"" arguments="""" stdoutLogEnabled=""true"" stdoutLogFile=""{baseLogPath}\stdout.log""> </httpPlatform> </system.webServer></configuration>"); var attributesToOverwrite = new[] { "processPath", "arguments" }; var result = xDoc.Root.MergeWith(targetDocument.Root, (name, sourceChild, targetChild) => { if (sourceChild != null) { // We're only going to merge the httpPlatform element attributes we don't care about if (string.Equals(name.LocalName, "httpPlatform")) { foreach (var attr in sourceChild.Attributes()) { if (!attributesToOverwrite.Contains(attr.Name.LocalName)) { targetChild.SetAttributeValue(attr.Name, attr.Value); } } } targetChild.Remove(); sourceChild.Parent.Add(targetChild); sourceChild.Remove(); return(true); } return(false); }); var xmlWriterSettings = new XmlWriterSettings { Indent = true, ConformanceLevel = ConformanceLevel.Auto }; using (var xmlWriter = XmlWriter.Create(File.Create(wwwRootOutWebConfigFilePath), xmlWriterSettings)) { result.WriteTo(xmlWriter); } // Create the logs directory so the httpPlatformHandler can write there Directory.CreateDirectory(Path.Combine(root.OutputPath, "logs")); return(true); }
public bool Publish() { var warnings = new List <DiagnosticMessage>(); Runtime.Project project; if (!Runtime.Project.TryGetProject(_options.ProjectDir, out project, warnings)) { _options.Reports.Error.WriteLine("Unable to locate {0}.".Red(), Runtime.Project.ProjectFileName); return(false); } foreach (var warning in warnings) { _options.Reports.Information.WriteLine(warning.FormattedMessage.Yellow()); } // '--wwwroot' option can override 'webroot' property in project.json _options.WwwRoot = _options.WwwRoot ?? project.WebRoot; _options.WwwRootOut = _options.WwwRootOut ?? _options.WwwRoot; if (string.IsNullOrEmpty(_options.WwwRoot) && !string.IsNullOrEmpty(_options.WwwRootOut)) { _options.Reports.Error.WriteLine( "'--wwwroot-out' option can be used only when the '--wwwroot' option or 'webroot' in project.json is specified.".Red()); return(false); } if (string.Equals(_options.WwwRootOut, PublishRoot.AppRootName, StringComparison.OrdinalIgnoreCase)) { _options.Reports.Error.WriteLine( "'{0}' is a reserved folder name. Please choose another name for the wwwroot-out folder.".Red(), PublishRoot.AppRootName); return(false); } var sw = Stopwatch.StartNew(); string outputPath = _options.OutputDir; var projectDir = project.ProjectDirectory; var frameworkContexts = new Dictionary <FrameworkName, DependencyContext>(); var root = new PublishRoot(project, outputPath, _hostServices, _options.Reports) { Configuration = _options.Configuration, NoSource = _options.NoSource, IncludeSymbols = _options.IncludeSymbols }; Func <string, string> getVariable = key => { return(null); }; if (!ScriptExecutor.Execute(project, "prepare", getVariable)) { _options.Reports.Error.WriteLine(ScriptExecutor.ErrorMessage); return(false); } if (!ScriptExecutor.Execute(project, "prepublish", getVariable)) { _options.Reports.Error.WriteLine(ScriptExecutor.ErrorMessage); return(false); } if (!ResolveActualRuntimeNames(_options.Runtimes)) { return(false); } foreach (var runtime in _options.Runtimes) { // Calculate the runtime name by taking the last path segment (since it could be a path), // but first strip off any trailing '\' or '/' in case the path provided was something like // "C:\Foo\Bar\dnx-clr-win-x64...\" var runtimeName = new DirectoryInfo(runtime).Name; var frameworkName = DependencyContext.SelectFrameworkNameForRuntime( project.GetTargetFrameworks().Select(x => x.FrameworkName), runtimeName); if (frameworkName == null) { _options.Reports.Error.WriteLine( "The project being published does not support the runtime '{0}'", runtime.ToString().Red().Bold()); return(false); } var runtimeLocated = TryAddRuntime(root, frameworkName, runtime); List <string> runtimeProbePaths = null; if (!runtimeLocated) { runtimeProbePaths = new List <string>(); runtimeProbePaths.Add(runtime); var runtimeHome = Environment.GetEnvironmentVariable(EnvironmentNames.Home); if (string.IsNullOrEmpty(runtimeHome)) { var runtimeGlobalPath = DnuEnvironment.GetFolderPath(DnuFolderPath.DnxGlobalPath); var defaultRuntimeHome = DnuEnvironment.GetFolderPath(DnuFolderPath.DefaultDnxHome); runtimeHome = $"{defaultRuntimeHome};{runtimeGlobalPath}"; } foreach (var portion in runtimeHome.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries)) { var packagesPath = Path.Combine( Environment.ExpandEnvironmentVariables(portion), "runtimes", runtime); if (TryAddRuntime(root, frameworkName, packagesPath)) { runtimeLocated = true; break; } runtimeProbePaths.Add(packagesPath); } } if (!runtimeLocated) { _options.Reports.Error.WriteLine(string.Format("Unable to locate runtime '{0}'", runtime.Red().Bold())); if (runtimeProbePaths != null) { _options.Reports.Error.WriteLine(string.Format("Locations probed:{0}{1}", Environment.NewLine, string.Join(Environment.NewLine, runtimeProbePaths))); } return(false); } if (!frameworkContexts.ContainsKey(frameworkName)) { frameworkContexts[frameworkName] = CreateDependencyContext(project, frameworkName); } } // If there is no target framework filter specified with '--runtime', // the published output targets all frameworks specified in project.json if (!_options.Runtimes.Any()) { foreach (var frameworkInfo in project.GetTargetFrameworks()) { if (!frameworkContexts.ContainsKey(frameworkInfo.FrameworkName)) { frameworkContexts[frameworkInfo.FrameworkName] = CreateDependencyContext(project, frameworkInfo.FrameworkName); } } } if (!frameworkContexts.Any()) { // We can only get here if the project has no frameworks section, which we don't actually support any more _options.Reports.Error.WriteLine("The project being published has no frameworks listed in the 'frameworks' section."); return(false); } root.SourcePackagesPath = frameworkContexts.First().Value.PackagesDirectory; bool anyUnresolvedDependency = false; foreach (var dependencyContext in frameworkContexts.Values) { foreach (var library in dependencyContext.LibraryManager.GetLibraryDescriptions()) { if (!library.Resolved) { // If there's any unresolved dependencies then complain and keep working _options.Reports.Quiet.WriteLine(" Unable to resolve dependency {0}", library.Identity.ToString().Red().Bold()); anyUnresolvedDependency = true; } else { if (library.Type == LibraryTypes.Project) { if (!root.Projects.Any(p => p.Library.Name == library.Identity.Name)) { var publishProject = new PublishProject((ProjectDescription)library); if (publishProject.Library.Name == project.Name) { publishProject.WwwRoot = _options.WwwRoot; publishProject.WwwRootOut = _options.WwwRootOut; } root.Projects.Add(publishProject); } } else if (library.Type == LibraryTypes.Package) { if (!root.Packages.Any(p => p.Library.Name == library.Identity.Name)) { root.Packages.Add(new PublishPackage((PackageDescription)library)); } } } } } NativeImageGenerator nativeImageGenerator = null; if (_options.Native) { nativeImageGenerator = NativeImageGenerator.Create(_options, root, frameworkContexts.Values); if (nativeImageGenerator == null) { _options.Reports.Error.WriteLine("Fail to initiate native image generation process.".Red()); return(false); } } var success = root.Emit(); if (!ScriptExecutor.Execute(project, "postpublish", getVariable)) { _options.Reports.Error.WriteLine(ScriptExecutor.ErrorMessage); return(false); } if (_options.Native && !nativeImageGenerator.BuildNativeImages(root)) { _options.Reports.Error.WriteLine("Native image generation failed."); return(false); } sw.Stop(); _options.Reports.Information.WriteLine("Time elapsed {0}", sw.Elapsed); return(!anyUnresolvedDependency && success); }
private bool UpdateLockFile(PublishRoot root) { var tasks = new Task<bool>[root.Projects.Count]; for (int i = 0; i < root.Projects.Count; i++) { var project = root.Projects[i]; var restoreDirectory = project.IsPackage ? Path.Combine(project.TargetPath, "root") : project.TargetPath; tasks[i] = Restore(root, project, restoreDirectory); } Task.WaitAll(tasks); return tasks.All(t => t.Result); }
private bool GenerateWebConfigFileForWwwRootOut(PublishRoot root, Runtime.Project project, string wwwRootOutPath) { // Generate web.config for public app folder var wwwRootOutWebConfigFilePath = Path.Combine(wwwRootOutPath, "web.config"); var wwwRootSourcePath = GetWwwRootSourcePath(project.ProjectDirectory, WwwRoot); var webConfigFilePath = Path.Combine(wwwRootSourcePath, "web.config"); XDocument xDoc; if (File.Exists(webConfigFilePath)) { xDoc = XDocument.Parse(File.ReadAllText(webConfigFilePath)); } else { xDoc = new XDocument(); } if (xDoc.Root == null) { xDoc.Add(new XElement("configuration")); } if (xDoc.Root.Name != "configuration") { throw new InvalidDataException("'configuration' is the only valid name for root element of web.config file"); } // <system.webServer> // <handlers> // <add name="httpplatformhandler" path="*" verb="*" modules="httpPlatformHandler" resourceType="Unspecified" /> // </handlers> // <httpPlatform processPath="..\command.cmd" // arguments="" // stdoutLogEnabled="true" // stdoutLogFile="..\logs\stdout.log"> // </httpPlatform> // </system.webServer> // Look for specified command var command = root.IISCommand; if (!string.IsNullOrEmpty(command) && !project.Commands.ContainsKey(command)) { root.Reports.WriteError($"Specified command {command} cannot be found."); return false; } else if (project.Commands.Count == 1) { command = project.Commands.First().Key; } else if (project.Commands.Count == 0) { root.Reports.WriteWarning("No commands defined. Defaulting to web."); } else { root.Reports.WriteWarning("Multiple commands defined. Defaulting to web."); } command = command ?? "web"; root.Reports.Information.WriteLine($"Using command '{command}' as the entry point for web.config."); var azurePublishValue = Environment.GetEnvironmentVariable("DNU_PUBLISH_AZURE"); var publishingToAzure = string.Equals(azurePublishValue, "true", StringComparison.Ordinal) || string.Equals(azurePublishValue, "1", StringComparison.Ordinal) || !string.IsNullOrEmpty(Environment.GetEnvironmentVariable("WEBSITE_SITE_NAME")); var basePath = publishingToAzure ? @"%home%\site" : ".."; var baseLogPath = publishingToAzure ? @"\\?\%home%\LogFiles" : @"..\logs"; var targetDocument = XDocument.Parse($@"<configuration><system.webServer> <handlers> <add name=""httpplatformhandler"" path=""*"" verb=""*"" modules=""httpPlatformHandler"" resourceType=""Unspecified"" /> </handlers> <httpPlatform processPath=""{basePath}\approot\{command}.cmd"" arguments="""" stdoutLogEnabled=""true"" stdoutLogFile=""{baseLogPath}\stdout.log""> </httpPlatform> </system.webServer></configuration>"); var attributesToOverwrite = new[] { "processPath", "arguments" }; var result = xDoc.Root.MergeWith(targetDocument.Root, (name, sourceChild, targetChild) => { if (sourceChild != null) { // We're only going to merge the httpPlatform element attributes we don't care about if (string.Equals(name.LocalName, "httpPlatform")) { foreach (var attr in sourceChild.Attributes()) { if (!attributesToOverwrite.Contains(attr.Name.LocalName)) { targetChild.SetAttributeValue(attr.Name, attr.Value); } } } targetChild.Remove(); sourceChild.Parent.Add(targetChild); sourceChild.Remove(); return true; } return false; }); var xmlWriterSettings = new XmlWriterSettings { Indent = true, ConformanceLevel = ConformanceLevel.Auto }; using (var xmlWriter = XmlWriter.Create(File.Create(wwwRootOutWebConfigFilePath), xmlWriterSettings)) { result.WriteTo(xmlWriter); } // Create the logs directory so the httpPlatformHandler can write there Directory.CreateDirectory(Path.Combine(root.OutputPath, "logs")); return true; }
private bool PrunePackages(PublishRoot root) { var resolver = new DefaultPackagePathResolver(root.TargetPackagesPath); // Special cases (for backwards compat) var specialFolders = new List <string> { "native", "InteropAssemblies", "redist" }; if (!root.NoSource) { // 'shared' folder is build time dependency, so we only copy it when deploying with source specialFolders.Add("shared"); } var lockFilePath = Path.GetFullPath(Path.Combine(ApplicationBasePath, LockFileFormat.LockFileName)); var format = new LockFileFormat(); root.LockFile = format.Read(lockFilePath); var keep = new HashSet <string>(); foreach (var target in root.LockFile.Targets) { foreach (var library in target.Libraries) { var packagesDir = resolver.GetInstallPath(library.Name, library.Version); var manifest = resolver.GetManifestFilePath(library.Name, library.Version); keep.Add(manifest); foreach (var path in library.RuntimeAssemblies) { keep.Add(CombinePath(packagesDir, path)); } foreach (var path in library.CompileTimeAssemblies) { keep.Add(CombinePath(packagesDir, path)); } foreach (var path in library.NativeLibraries) { keep.Add(CombinePath(packagesDir, path)); } foreach (var specialFolder in specialFolders) { var specialFolderPath = CombinePath(packagesDir, specialFolder); if (!Directory.Exists(specialFolderPath)) { continue; } keep.AddRange(Directory.EnumerateFiles(specialFolderPath, "*.*", SearchOption.AllDirectories)); } } } foreach (var package in root.Packages) { var packageDir = resolver.GetInstallPath(package.Library.Name, package.Library.Version); var packageFiles = Directory.EnumerateFiles(packageDir, "*.*", SearchOption.AllDirectories); foreach (var file in packageFiles) { if (!keep.Contains(file)) { File.Delete(file); } } root.Operations.DeleteEmptyFolders(packageDir); } return(true); }
private static string GetBootstrapperVersion(PublishRoot root) { // Use version of Microsoft.AspNet.Loader.IIS.Interop as version of bootstrapper var package = root.Packages.SingleOrDefault( x => string.Equals(x.Library.Name, "Microsoft.AspNet.Loader.IIS.Interop")); return package == null ? string.Empty : package.Library.Version.ToString(); }
public bool PostProcess(PublishRoot root) { // At this point, all nupkgs generated from dependency projects are available in packages folder // So we can add them to lockfile now if (!UpdateLockFile(root)) { return false; } // Prune the packages folder only leaving things that are required if (!PrunePackages(root)) { return false; } // If --wwwroot-out doesn't have a non-empty value, we don't need a public app folder in output if (string.IsNullOrEmpty(WwwRootOut)) { return true; } var project = GetCurrentProject(); // Construct path to public app folder, which contains content files and tool dlls // The name of public app folder is specified with "--appfolder" option // Default name of public app folder is the same as main project var wwwRootOutPath = Path.Combine(root.OutputPath, WwwRootOut); // Delete old public app folder because we don't want leftovers from previous operations root.Operations.Delete(wwwRootOutPath); Directory.CreateDirectory(wwwRootOutPath); // Copy content files (e.g. html, js and images) of main project into public app folder CopyContentFiles(root, project, wwwRootOutPath); return GenerateWebConfigFileForWwwRootOut(root, project, wwwRootOutPath); }
/// <summary> /// This is a helper method for looking up directories that directly contains assemblies that would be loaded /// given the published runtime framework. We should run crossgen on these folders /// </summary> private IEnumerable<string> ResolveOutputAssemblies(PublishRoot root, NuGetDependencyResolver resolver) { var outputPathsMap = root.Packages .ToDictionary( pkg => pkg.Library, pkg => pkg.TargetPath ); var result = new HashSet<string>(); var libraryNotInOutput = new List<LibraryIdentity>(); var missingOutputFolder = new List<string>(); foreach (var dependency in resolver.PackageAssemblyLookup.Values) { var libId = dependency.Library.Identity; var libPath = dependency.Library.Path; var assemblyDir = Path.GetDirectoryName(dependency.Path); var assemblySelection = assemblyDir.Substring(libPath.Length); string outputLibLocation; if (!outputPathsMap.TryGetValue(libId, out outputLibLocation)) { libraryNotInOutput.Add(libId); continue; } var output = outputLibLocation + assemblySelection; if (!Directory.Exists(output)) { missingOutputFolder.Add(output); } else { result.Add(output); } } if (libraryNotInOutput.Any()) { throw new InvalidOperationException(string.Format("Library {0} cannot be found in the published output.", string.Join(", ", libraryNotInOutput))); } if (missingOutputFolder.Any()) { throw new InvalidOperationException("Published output does not contain directory:\n" + string.Join("\n", missingOutputFolder)); } return result; }
private void PrunePackages(PublishRoot root) { if (root.MainProjectLockFile == null) { return; } var resolver = new DefaultPackagePathResolver(root.TargetPackagesPath); var lockFilePath = Path.GetFullPath(Path.Combine(ApplicationBasePath, LockFileFormat.LockFileName)); root.PublishedLockFile = new LockFileFormat().Read(lockFilePath); var filesToKeep = new HashSet<string>(); var filesToRemove = new HashSet<string>(); foreach (var target in root.PublishedLockFile.Targets) { foreach (var library in target.Libraries) { var packageDir = resolver.GetInstallPath(library.Name, library.Version); if (library.Name != root.MainProjectName && string.Equals(library.Type, Runtime.LibraryTypes.Package, StringComparison.OrdinalIgnoreCase)) { filesToRemove.Add(resolver.GetHashPath(library.Name, library.Version)); filesToRemove.Add(resolver.GetPackageFilePath(library.Name, library.Version)); filesToRemove.AddRange(Directory.EnumerateFiles(packageDir, $"{library.Name}.xml", SearchOption.AllDirectories)); } foreach (var path in library.RuntimeAssemblies) { filesToKeep.Add(Path.Combine(packageDir, path)); } foreach (var path in library.CompileTimeAssemblies) { filesToKeep.Add(Path.Combine(packageDir, path)); } foreach (var path in library.NativeLibraries) { filesToKeep.Add(Path.Combine(packageDir, path)); } foreach (var path in library.ResourceAssemblies) { filesToKeep.Add(Path.Combine(packageDir, path)); } } } foreach (var target in root.MainProjectLockFile.Targets.Where(projectTarget => string.IsNullOrEmpty(projectTarget.RuntimeIdentifier) && !root.PublishedLockFile.Targets.Any(publishTarget => projectTarget.TargetFramework == publishTarget.TargetFramework))) { foreach (var library in target.Libraries) { var packageDir = resolver.GetInstallPath(library.Name, library.Version); if (Directory.Exists(packageDir)) { foreach (var path in library.RuntimeAssemblies) { filesToRemove.Add(Path.Combine(packageDir, path)); } foreach (var path in library.CompileTimeAssemblies) { filesToRemove.Add(Path.Combine(packageDir, path)); } foreach (var path in library.NativeLibraries) { filesToRemove.Add(Path.Combine(packageDir, path)); } foreach (var path in library.ResourceAssemblies) { filesToRemove.Add(Path.Combine(packageDir, path)); } } } } foreach (var file in filesToRemove.Except(filesToKeep)) { File.Delete(file); } if (Directory.Exists(root.TargetPackagesPath)) { root.Operations.DeleteEmptyFolders(root.TargetPackagesPath); } return; }
private bool UpdateLockFile(PublishRoot root) { var appEnv = (IApplicationEnvironment)root.HostServices.GetService(typeof(IApplicationEnvironment)); var feedOptions = new FeedOptions(); feedOptions.IgnoreFailedSources = true; feedOptions.Sources.Add(root.TargetPackagesPath); feedOptions.TargetPackagesFolder = root.TargetPackagesPath; var tasks = new Task<bool>[root.Projects.Count]; for (int i = 0; i < root.Projects.Count; i++) { var project = root.Projects[i]; var restoreCommand = new RestoreCommand(appEnv); foreach (var runtime in root.Runtimes) { restoreCommand.TargetFrameworks.Add(project.SelectFrameworkForRuntime(runtime)); } var restoreDirectory = project.IsPackage ? Path.Combine(project.TargetPath, "root") : project.TargetPath; restoreCommand.SkipRestoreEvents = true; restoreCommand.SkipInstall = true; // This is a workaround for #1322. Since we use restore to generate the lock file // after publish, it's possible to fail restore after copying the closure // if framework assemblies and packages have the same name. This is more likely now // since dependencies may exist in the top level restoreCommand.IgnoreMissingDependencies = true; restoreCommand.CheckHashFile = false; restoreCommand.RestoreDirectories.Add(restoreDirectory); restoreCommand.FeedOptions = feedOptions; // Mute "dnu restore" subcommand restoreCommand.Reports = Reports.Constants.NullReports; tasks[i] = restoreCommand.Execute(); } Task.WaitAll(tasks); return tasks.All(t => t.Result); }
private bool TryAddRuntime(PublishRoot root, FrameworkName frameworkName, string runtimePath) { if (!Directory.Exists(runtimePath)) { return false; } root.Runtimes.Add(new PublishRuntime(root, frameworkName, runtimePath)); root.Frameworks.Add(frameworkName, null); return true; }
private async Task<bool> Restore(PublishRoot root, PublishProject publishProject, string restoreDirectory, IEnumerable<FrameworkName> targetFrameworks) { var appEnv = PlatformServices.Default.Application; var feedOptions = new FeedOptions(); feedOptions.IgnoreFailedSources = true; feedOptions.Sources.Add(root.TargetPackagesPath); feedOptions.TargetPackagesFolder = root.TargetPackagesPath; var restoreCommand = new RestoreCommand(appEnv); restoreCommand.TargetFrameworks.AddRange(targetFrameworks); restoreCommand.RequestedRuntimes = root.RuntimeIdentifiers; restoreCommand.SkipRestoreEvents = true; restoreCommand.SkipInstall = true; // This is a workaround for #1322. Since we use restore to generate the lock file // after publish, it's possible to fail restore after copying the closure // if framework assemblies and packages have the same name. This is more likely now // since dependencies may exist in the top level restoreCommand.IgnoreMissingDependencies = true; restoreCommand.CheckHashFile = false; restoreCommand.RestoreDirectories.Add(restoreDirectory); restoreCommand.FeedOptions = feedOptions; // Mute "dnu restore" subcommand restoreCommand.Reports = Reports.Constants.NullReports; var success = await restoreCommand.Execute(); return success; }
public bool Publish() { var warnings = new List<DiagnosticMessage>(); Runtime.Project project; if (!Runtime.Project.TryGetProject(_options.ProjectDir, out project, warnings)) { _options.Reports.Error.WriteLine("Unable to locate {0}.".Red(), Runtime.Project.ProjectFileName); return false; } foreach (var warning in warnings) { _options.Reports.Information.WriteLine(warning.FormattedMessage.Yellow()); } // '--wwwroot' option can override 'webroot' property in project.json _options.WwwRoot = _options.WwwRoot ?? project.WebRoot; _options.WwwRootOut = _options.WwwRootOut ?? _options.WwwRoot; if (string.IsNullOrEmpty(_options.WwwRoot) && !string.IsNullOrEmpty(_options.WwwRootOut)) { _options.Reports.Error.WriteLine( "'--wwwroot-out' option can be used only when the '--wwwroot' option or 'webroot' in project.json is specified.".Red()); return false; } if (string.Equals(_options.WwwRootOut, PublishRoot.AppRootName, StringComparison.OrdinalIgnoreCase)) { _options.Reports.Error.WriteLine( "'{0}' is a reserved folder name. Please choose another name for the wwwroot-out folder.".Red(), PublishRoot.AppRootName); return false; } var sw = Stopwatch.StartNew(); string outputPath = _options.OutputDir; var projectDir = project.ProjectDirectory; var frameworkContexts = new Dictionary<FrameworkName, DependencyContext>(); var root = new PublishRoot(project, outputPath, _hostServices, _options.Reports) { Configuration = _options.Configuration, NoSource = _options.NoSource, IncludeSymbols = _options.IncludeSymbols }; Func<string, string> getVariable = key => { return null; }; if (!ScriptExecutor.Execute(project, "prepare", getVariable)) { _options.Reports.Error.WriteLine(ScriptExecutor.ErrorMessage); return false; } if (!ScriptExecutor.Execute(project, "prepublish", getVariable)) { _options.Reports.Error.WriteLine(ScriptExecutor.ErrorMessage); return false; } if (!ResolveActualRuntimeNames(_options.Runtimes)) { return false; } foreach (var runtime in _options.Runtimes) { // Calculate the runtime name by taking the last path segment (since it could be a path), // but first strip off any trailing '\' or '/' in case the path provided was something like // "C:\Foo\Bar\dnx-clr-win-x64...\" var runtimeName = new DirectoryInfo(runtime).Name; var frameworkName = DependencyContext.SelectFrameworkNameForRuntime( project.GetTargetFrameworks().Select(x => x.FrameworkName), runtimeName); if (frameworkName == null) { _options.Reports.Error.WriteLine( "The project being published does not support the runtime '{0}'", runtime.ToString().Red().Bold()); return false; } var runtimeLocated = TryAddRuntime(root, frameworkName, runtime); List<string> runtimeProbePaths = null; if (!runtimeLocated) { runtimeProbePaths = new List<string>(); runtimeProbePaths.Add(runtime); var runtimeHome = Environment.GetEnvironmentVariable(EnvironmentNames.Home); if (string.IsNullOrEmpty(runtimeHome)) { var runtimeGlobalPath = DnuEnvironment.GetFolderPath(DnuFolderPath.DnxGlobalPath); var defaultRuntimeHome = DnuEnvironment.GetFolderPath(DnuFolderPath.DefaultDnxHome); runtimeHome = $"{defaultRuntimeHome};{runtimeGlobalPath}"; } foreach (var portion in runtimeHome.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries)) { var packagesPath = Path.Combine( Environment.ExpandEnvironmentVariables(portion), "runtimes", runtime); if (TryAddRuntime(root, frameworkName, packagesPath)) { runtimeLocated = true; break; } runtimeProbePaths.Add(packagesPath); } } if (!runtimeLocated) { _options.Reports.Error.WriteLine(string.Format("Unable to locate runtime '{0}'", runtime.Red().Bold())); if (runtimeProbePaths != null) { _options.Reports.Error.WriteLine(string.Format("Locations probed:{0}{1}", Environment.NewLine, string.Join(Environment.NewLine, runtimeProbePaths))); } return false; } if (!frameworkContexts.ContainsKey(frameworkName)) { frameworkContexts[frameworkName] = CreateDependencyContext(project, frameworkName); } } // If there is no target framework filter specified with '--runtime', // the published output targets all frameworks specified in project.json if (!_options.Runtimes.Any()) { foreach (var frameworkInfo in project.GetTargetFrameworks()) { if (!frameworkContexts.ContainsKey(frameworkInfo.FrameworkName)) { frameworkContexts[frameworkInfo.FrameworkName] = CreateDependencyContext(project, frameworkInfo.FrameworkName); } } } if (!frameworkContexts.Any()) { // We can only get here if the project has no frameworks section, which we don't actually support any more _options.Reports.Error.WriteLine("The project being published has no frameworks listed in the 'frameworks' section."); return false; } root.SourcePackagesPath = frameworkContexts.First().Value.PackagesDirectory; bool anyUnresolvedDependency = false; foreach (var dependencyContext in frameworkContexts.Values) { // If there's any unresolved dependencies then complain and keep working if (dependencyContext.DependencyWalker.Libraries.Any(l => !l.Resolved)) { anyUnresolvedDependency = true; var message = "Warning: " + dependencyContext.DependencyWalker.GetMissingDependenciesWarning( dependencyContext.FrameworkName); _options.Reports.Quiet.WriteLine(message.Yellow()); } foreach (var libraryDescription in dependencyContext.NuGetDependencyResolver.Dependencies) { IList<DependencyContext> contexts; if (!root.LibraryDependencyContexts.TryGetValue(libraryDescription.Identity, out contexts)) { root.Packages.Add(new PublishPackage(libraryDescription)); contexts = new List<DependencyContext>(); root.LibraryDependencyContexts[libraryDescription.Identity] = contexts; } contexts.Add(dependencyContext); } foreach (var libraryDescription in dependencyContext.ProjectReferenceDependencyProvider.Dependencies) { if (!root.Projects.Any(p => p.Name == libraryDescription.Identity.Name)) { var publishProject = new PublishProject( dependencyContext.ProjectReferenceDependencyProvider, dependencyContext.ProjectResolver, libraryDescription); if (publishProject.Name == project.Name) { publishProject.WwwRoot = _options.WwwRoot; publishProject.WwwRootOut = _options.WwwRootOut; } root.Projects.Add(publishProject); } } } NativeImageGenerator nativeImageGenerator = null; if (_options.Native) { nativeImageGenerator = NativeImageGenerator.Create(_options, root, frameworkContexts.Values); if (nativeImageGenerator == null) { _options.Reports.Error.WriteLine("Fail to initiate native image generation process.".Red()); return false; } } var success = root.Emit(); if (!ScriptExecutor.Execute(project, "postpublish", getVariable)) { _options.Reports.Error.WriteLine(ScriptExecutor.ErrorMessage); return false; } if (_options.Native && !nativeImageGenerator.BuildNativeImages(root)) { _options.Reports.Error.WriteLine("Native image generation failed."); return false; } sw.Stop(); _options.Reports.Information.WriteLine("Time elapsed {0}", sw.Elapsed); return !anyUnresolvedDependency && success; }
private void CopyProject(PublishRoot root, Runtime.Project project, string targetPath, bool includeSource) { var additionalExcluding = new List<string>(); // If a public folder is specified with 'webroot' or '--wwwroot', we ignore it when copying project files var wwwRootPath = string.Empty; if (!string.IsNullOrEmpty(WwwRoot)) { wwwRootPath = Path.GetFullPath(Path.Combine(project.ProjectDirectory, WwwRoot)); wwwRootPath = PathUtility.EnsureTrailingSlash(wwwRootPath); } // If project root is used as value of '--wwwroot', we shouldn't exclude it when copying if (string.Equals(wwwRootPath, PathUtility.EnsureTrailingSlash(project.ProjectDirectory))) { wwwRootPath = string.Empty; } if (!string.IsNullOrEmpty(wwwRootPath)) { additionalExcluding.Add(wwwRootPath.Substring(PathUtility.EnsureTrailingSlash(project.ProjectDirectory).Length)); } var sourceFiles = project.Files.GetFilesForBundling(includeSource, additionalExcluding); root.Operations.Copy(sourceFiles, project.ProjectDirectory, targetPath); }
public bool Publish() { var warnings = new List<DiagnosticMessage>(); Runtime.Project project; if (!Runtime.Project.TryGetProject(_options.ProjectDir, out project, warnings)) { _options.Reports.Error.WriteLine("Unable to locate {0}.".Red(), Runtime.Project.ProjectFileName); return false; } foreach (var warning in warnings) { _options.Reports.Information.WriteLine(warning.FormattedMessage.Yellow()); } if (string.IsNullOrEmpty(_options.WwwRoot) && File.Exists(Path.Combine(project.ProjectDirectory, "hosting.json"))) { var jsonObj = JObject.Parse(File.ReadAllText(Path.Combine(project.ProjectDirectory, "hosting.json"))); _options.WwwRoot = PublishOperations.GetWebRootJson(jsonObj)?.ToString(); } if (string.IsNullOrEmpty(_options.WwwRoot) && Directory.Exists(Path.Combine(project.ProjectDirectory, "wwwroot"))) { _options.WwwRoot = "wwwroot"; } _options.WwwRoot = _options.WwwRoot ?? ""; _options.WwwRootOut = _options.WwwRootOut ?? _options.WwwRoot; if (string.IsNullOrEmpty(_options.WwwRoot) && !string.IsNullOrEmpty(_options.WwwRootOut)) { _options.Reports.Error.WriteLine( "'--wwwroot-out' option can be used only when the '--wwwroot' option or 'webroot' in project.json is specified.".Red()); return false; } if (string.Equals(_options.WwwRootOut, PublishRoot.AppRootName, StringComparison.OrdinalIgnoreCase)) { _options.Reports.Error.WriteLine( "'{0}' is a reserved folder name. Please choose another name for the wwwroot-out folder.".Red(), PublishRoot.AppRootName); return false; } var sw = Stopwatch.StartNew(); string outputPath = _options.OutputDir; var projectDir = project.ProjectDirectory; var frameworkContexts = new Dictionary<Tuple<FrameworkName, string>, DependencyContext>(); var root = new PublishRoot(project, outputPath, _options.Reports) { Configuration = _options.Configuration, NoSource = _options.NoSource, IncludeSymbols = _options.IncludeSymbols, IISCommand = _options.IISCommand }; Func<string, string> getVariable = key => { return null; }; if (!ScriptExecutor.Execute(project, "prepare", getVariable)) { _options.Reports.Error.WriteLine(ScriptExecutor.ErrorMessage); return false; } if (!ScriptExecutor.Execute(project, "prepublish", getVariable)) { _options.Reports.Error.WriteLine(ScriptExecutor.ErrorMessage); return false; } if (!ResolveActualRuntimeNames(_options.Runtimes)) { return false; } foreach (var runtime in _options.Runtimes) { // Calculate the runtime name by taking the last path segment (since it could be a path), // but first strip off any trailing '\' or '/' in case the path provided was something like // "C:\Foo\Bar\dnx-clr-win-x64...\" var runtimeName = new DirectoryInfo(runtime).Name; var frameworkName = DependencyContext.SelectFrameworkNameForRuntime( project.GetTargetFrameworks().Select(x => x.FrameworkName), runtimeName); if (frameworkName == null) { _options.Reports.Error.WriteLine( "The project being published does not support the runtime '{0}'", runtime.ToString().Red().Bold()); return false; } var runtimeLocated = TryAddRuntime(root, frameworkName, runtime); List<string> runtimeProbePaths = null; if (!runtimeLocated) { runtimeProbePaths = new List<string>(); runtimeProbePaths.Add(runtime); var runtimeHome = Environment.GetEnvironmentVariable(EnvironmentNames.Home); var pathSeparator = Path.PathSeparator; if (string.IsNullOrEmpty(runtimeHome)) { var runtimeGlobalPath = DnuEnvironment.GetFolderPath(DnuFolderPath.DnxGlobalPath); var defaultRuntimeHome = DnuEnvironment.GetFolderPath(DnuFolderPath.DefaultDnxHome); runtimeHome = $"{defaultRuntimeHome}{pathSeparator}{runtimeGlobalPath}"; } foreach (var portion in runtimeHome.Split(new[] { pathSeparator }, StringSplitOptions.RemoveEmptyEntries)) { var packagesPath = Path.Combine( Environment.ExpandEnvironmentVariables(portion), "runtimes", runtime); if (TryAddRuntime(root, frameworkName, packagesPath)) { runtimeLocated = true; break; } runtimeProbePaths.Add(packagesPath); } } if (!runtimeLocated) { _options.Reports.Error.WriteLine(string.Format("Unable to locate runtime '{0}'", runtime.Red().Bold())); if (runtimeProbePaths != null) { _options.Reports.Error.WriteLine(string.Format("Locations probed:{0}{1}", Environment.NewLine, string.Join(Environment.NewLine, runtimeProbePaths))); } return false; } if (!frameworkContexts.ContainsKey(Tuple.Create(frameworkName, string.Empty))) { frameworkContexts[Tuple.Create(frameworkName, string.Empty)] = CreateDependencyContext(project, frameworkName, Enumerable.Empty<string>()); } foreach (var rid in DependencyContext.GetRuntimeIdentifiers(runtimeName)) { root.RuntimeIdentifiers.Add(rid); if (!frameworkContexts.ContainsKey(Tuple.Create(frameworkName, rid))) { frameworkContexts[Tuple.Create(frameworkName, rid)] = CreateDependencyContext(project, frameworkName, new[] { rid }); } } } // If there is no target framework filter specified with '--runtime', // the published output targets all frameworks specified in project.json if (!_options.Runtimes.Any()) { IEnumerable<FrameworkName> frameworksToPublish; if (!_options.TargetFrameworks.Any()) { frameworksToPublish = project .GetTargetFrameworks() .Select(fx => fx.FrameworkName); } else { string frameworkSelectionError; frameworksToPublish = FrameworkSelectionHelper.SelectFrameworks(project, _options.TargetFrameworks, _applicationEnvironment.RuntimeFramework, out frameworkSelectionError)?.ToList(); if (frameworksToPublish == null) { _options.Reports.WriteError(frameworkSelectionError); return false; } foreach (var framework in frameworksToPublish) { root.Frameworks.Add(framework, null); } } // Add runtime IDs for the currently running platform foreach (var runtime in PlatformServices.Default.Runtime.GetDefaultRestoreRuntimes()) { root.RuntimeIdentifiers.Add(runtime); } foreach (var framework in frameworksToPublish) { if (!frameworkContexts.ContainsKey(Tuple.Create(framework, string.Empty))) { frameworkContexts[Tuple.Create(framework, string.Empty)] = CreateDependencyContext(project, framework, Enumerable.Empty<string>()); } foreach (var rid in RuntimeEnvironmentHelper.RuntimeEnvironment.GetDefaultRestoreRuntimes()) { root.RuntimeIdentifiers.Add(rid); if (!frameworkContexts.ContainsKey(Tuple.Create(framework, rid))) { frameworkContexts[Tuple.Create(framework, rid)] = CreateDependencyContext(project, framework, new[] { rid }); } } } } if (!frameworkContexts.Any()) { // We can only get here if the project has no frameworks section, which we don't actually support any more _options.Reports.Error.WriteLine("The project being published has no frameworks listed in the 'frameworks' section."); return false; } root.SourcePackagesPath = frameworkContexts.First().Value.PackagesDirectory; bool anyUnresolvedDependency = false; foreach (var dependencyContext in frameworkContexts.Values) { foreach (var library in dependencyContext.LibraryManager.GetLibraryDescriptions()) { if (!library.Resolved) { // If there's any unresolved dependencies then complain and keep working _options.Reports.Quiet.WriteLine(" Unable to resolve dependency {0}", library.Identity.ToString().Red().Bold()); anyUnresolvedDependency = true; } else { if (library.Type == Runtime.LibraryTypes.Project) { if (!root.Projects.Any(p => p.Library.Name == library.Identity.Name)) { var publishProject = new PublishProject((ProjectDescription)library); if (publishProject.Library.Name == project.Name) { publishProject.WwwRoot = _options.WwwRoot; publishProject.WwwRootOut = _options.WwwRootOut; } root.Projects.Add(publishProject); } } else if (library.Type == Runtime.LibraryTypes.Package) { if (!root.Packages.Any(p => p.Library.Name == library.Identity.Name && p.Library.Version == library.Identity.Version)) { root.Packages.Add(new PublishPackage((PackageDescription)library)); } } } } } NativeImageGenerator nativeImageGenerator = null; if (_options.Native) { nativeImageGenerator = NativeImageGenerator.Create(_options, root, frameworkContexts.Values); if (nativeImageGenerator == null) { _options.Reports.Error.WriteLine("Fail to initiate native image generation process.".Red()); return false; } } var success = root.Emit(); if (!ScriptExecutor.Execute(project, "postpublish", getVariable)) { _options.Reports.Error.WriteLine(ScriptExecutor.ErrorMessage); return false; } if (_options.Native && !nativeImageGenerator.BuildNativeImages(root)) { _options.Reports.Error.WriteLine("Native image generation failed."); return false; } sw.Stop(); _options.Reports.Information.WriteLine("Time elapsed {0}", sw.Elapsed); return !anyUnresolvedDependency && success; }
private bool EmitNupkg(PublishRoot root) { root.Reports.Quiet.WriteLine(" Packing nupkg from {0} dependency {1}", _projectDescription.Type, _projectDescription.Identity.Name); IsPackage = true; var project = GetCurrentProject(); var resolver = new DefaultPackagePathResolver(root.TargetPackagesPath); var targetNupkg = resolver.GetPackageFileName(project.Name, project.Version); TargetPath = resolver.GetInstallPath(project.Name, project.Version); root.Reports.Quiet.WriteLine(" Source {0}", _projectDescription.Path.Bold()); root.Reports.Quiet.WriteLine(" Target {0}", TargetPath); if (Directory.Exists(TargetPath)) { root.Operations.Delete(TargetPath); } // If this is a wrapper project, we need to generate a lock file before building it if (IsWrappingAssembly()) { var success = Restore(root, publishProject: this, restoreDirectory: project.ProjectDirectory) .GetAwaiter().GetResult(); if (!success) { return(false); } } // Generate nupkg from this project dependency var buildOptions = new BuildOptions(); buildOptions.ProjectPatterns.Add(project.ProjectDirectory); buildOptions.OutputDir = Path.Combine(project.ProjectDirectory, "bin"); buildOptions.Configurations.Add(root.Configuration); buildOptions.GeneratePackages = true; buildOptions.Reports = root.Reports.ShallowCopy(); // Mute "dnu pack" completely if it is invoked by "dnu publish --quiet" buildOptions.Reports.Information = root.Reports.Quiet; var buildManager = new BuildManager(root.HostServices, buildOptions); if (!buildManager.Build()) { return(false); } // Extract the generated nupkg to target path var srcNupkgPath = Path.Combine(buildOptions.OutputDir, root.Configuration, targetNupkg); var srcSymbolsNupkgPath = Path.ChangeExtension(srcNupkgPath, "symbols.nupkg"); var options = new Packages.AddOptions { NuGetPackage = root.IncludeSymbols ? srcSymbolsNupkgPath : srcNupkgPath, SourcePackages = root.TargetPackagesPath, Reports = root.Reports }; var packagesAddCommand = new Packages.AddCommand(options); packagesAddCommand.Execute().GetAwaiter().GetResult(); // Copy content files (e.g. html, js and images) of main project into "root" folder of the exported package var rootFolderPath = Path.Combine(TargetPath, "root"); var rootProjectJson = Path.Combine(rootFolderPath, Runtime.Project.ProjectFileName); root.Operations.Delete(rootFolderPath); CopyProject(root, project, rootFolderPath, includeSource: false); UpdateWebRoot(root, rootFolderPath); UpdateJson(rootProjectJson, jsonObj => { // Update the project entrypoint jsonObj["entryPoint"] = _projectDescription.Identity.Name; // Set mark this as non loadable jsonObj["loadable"] = false; // Update the dependencies node to reference the main project var deps = new JObject(); jsonObj["dependencies"] = deps; deps[_projectDescription.Identity.Name] = _projectDescription.Identity.Version.ToString(); }); var appBase = Path.Combine(PublishRoot.AppRootName, "packages", resolver.GetPackageDirectory(_projectDescription.Identity.Name, _projectDescription.Identity.Version), "root"); _relativeAppBase = Path.Combine("..", appBase); ApplicationBasePath = Path.Combine(root.OutputPath, appBase); root.Reports.Quiet.WriteLine("Removing {0}", srcNupkgPath); File.Delete(srcNupkgPath); root.Reports.Quiet.WriteLine("Removing {0}", srcSymbolsNupkgPath); File.Delete(srcSymbolsNupkgPath); return(true); }