private IEnumerable <CsprojInfo> EnumerateDebugifiableProjects(DebugCommand cmd) { var path = cmd.Path; var isCsprojFile = File.Exists(path) && string.Equals(Path.GetExtension(path), ".csproj", StringComparison.InvariantCultureIgnoreCase); if (isCsprojFile) { var csproj = path; if (TryGetVersion(csproj, out string version) || !string.IsNullOrWhiteSpace(cmd.Version)) { // to be sure that the csproj is nuget-compatible, ensure it is the new csproj format if (!File.ReadLines(csproj).First().Trim().StartsWith("<Project Sdk=")) { _logger.Warning($"Project file {Path.GetFileName(csproj)} is not supported: Only latest csproj format is supported"); } else { var packageId = GetPackageId(csproj); yield return(new CsprojInfo(packageId, version ?? cmd.Version, csproj)); } } else { _logger.Warning($"Project file {Path.GetFileName(csproj)} does not contain a <Version> element. Please specify a version using the -v commandline argument."); } } else { // ensure path is a directory path = Directory.Exists(path) ? path : Path.GetDirectoryName(path); foreach (var csproj in Directory.EnumerateFiles(path, "*.csproj", SearchOption.AllDirectories)) { if (TryGetVersion(csproj, out string version) || !string.IsNullOrWhiteSpace(cmd.Version)) { // to be sure that the csproj is nuget-compatible, ensure it is the new csproj format if (!File.ReadLines(csproj).First().Trim().StartsWith("<Project Sdk=")) { _logger.Warning($"Project file {Path.GetFileName(csproj)} is not supported: Only latest csproj format is supported"); } else { var packageId = GetPackageId(csproj); yield return(new CsprojInfo(packageId, version ?? cmd.Version, csproj)); } } else { _logger.Warning($"Project file {Path.GetFileName(csproj)} does not contain a <Version> element. Please specify a version using the -v commandline argument."); } } } }
private bool DotnetPack(CsprojInfo projectFile, DebugCommand cmd) { bool verbose = cmd.Verbose; var csprojPath = projectFile.Path; if (!Path.IsPathRooted(csprojPath)) { throw new ArgumentException($"{nameof(csprojPath)} must be rooted"); } // dotnet pack --include-symbols --include-source -c Debug // see: https://docs.microsoft.com/en-us/dotnet/core/tools/dotnet-pack var name = "dotnet"; //var args = $"pack '{csprojPath}' --include-symbols --include-source -c Debug"; var args = $"pack --include-symbols --include-source -c Debug {cmd.PackArguments}"; _logger.Info($"creating {projectFile.NugetPackageName}"); var output = ExecuteProcess(name, args, csprojPath, verbose); const string fallbackTraceMessage = "error : If you are building projects that require targets from full MSBuild or MSBuildFrameworkToolsPath, you need to use desktop msbuild ('msbuild.exe') instead of 'dotnet build' or 'dotnet msbuild'"; var fallbackToMsBuildRequired = output.Output.Any(l => l.Contains(fallbackTraceMessage)); if (verbose) { foreach (var line in output.Output) { _logger.Debug(line); } _logger.Debug($"dotnet pack returned {output.ExitCode}"); } if (fallbackToMsBuildRequired) { if (verbose) { _logger.Debug("falling back to full MSBuild as advanced targets are required..."); } return(MsBuildPack(projectFile, verbose)); } // only iif dotnet pack returns 0, everything is fine return(output.ExitCode == 0); }
private void ExtractNupkg(DebugCommand cmd, string extractPath, string packagePath) { // add pseudo file to know when do delete such a folder if (cmd.Verbose) { _logger.Debug($"Writing .debugified.txt to {extractPath}"); } File.WriteAllText(Path.Combine(extractPath, ".debugified.txt"), "this package was debugified"); using var archive = new ZipArchive(File.OpenRead(packagePath)); foreach (var entry in archive.Entries) { if (entry.FullName.StartsWith("lib") || entry.FullName.StartsWith("src")) { if (cmd.Verbose) { _logger.Debug($"Extracting {entry.FullName}"); } // Gets the full path to ensure that relative segments are removed. string destinationPath = Path.GetFullPath(Path.Combine(extractPath, entry.FullName)); // Ordinal match is safest, case-sensitive volumes can be mounted within volumes that // are case-insensitive. if (destinationPath.StartsWith(extractPath, StringComparison.Ordinal)) { // ensure the subdirectories exist Directory.CreateDirectory(Path.GetDirectoryName(destinationPath)); entry.ExtractToFile(destinationPath, true); } } else { if (cmd.Verbose) { _logger.Debug($"Skipping {entry.FullName} as it does not start with 'src' or 'lib'"); } } } }
public void Debugify(DebugCommand cmd) { if (!string.IsNullOrWhiteSpace(cmd.Version)) { var versionValidator = new Regex(@"\d+\.\d+\.\d+(\.\d+)?[\d\w_-]*?"); if (!versionValidator.IsMatch(cmd.Version)) { _logger.Error($"Error: '{cmd.Version}' is not a valid nuget package version"); return; } } if (string.IsNullOrEmpty(cmd.Path)) { if (cmd.Verbose) { _logger.Debug($"No path provided. Will run in current directory: {Environment.CurrentDirectory}"); } cmd.Path = Environment.CurrentDirectory; } else { if (!Path.IsPathRooted(cmd.Path)) { cmd.Path = Path.GetFullPath(cmd.Path); } if (cmd.Verbose) { _logger.Debug($"Path: {cmd.Path}"); } } // find it within the current solution var solutionDir = File.Exists(cmd.Path) && string.Equals(Path.GetExtension(cmd.Path), ".sln", StringComparison.InvariantCultureIgnoreCase) ? Path.GetDirectoryName(cmd.Path) : RecursivelyFindSolutionDir(cmd.Path, cmd.Verbose); if (solutionDir is null) { _logger.Warning($"Could not find any solution in '{(File.Exists(cmd.Path) ? Path.GetDirectoryName(cmd.Path) : cmd.Path)}'"); return; } if (cmd.Verbose) { _logger.Debug($"Found sln directory: {solutionDir}"); } // find all compatible project files var projectFiles = EnumerateDebugifiableProjects(cmd).ToList(); if (!projectFiles.Any()) { _logger.Warning($"Could not find any debugifiable *.csproj files in '{(File.Exists(cmd.Path) ? Path.GetDirectoryName(cmd.Path) : cmd.Path)}'"); return; } // make sur the version files are restored afterwards using (var cd = new CompositeDisposable(_logger)) { // pack the thing up var packFailedCount = 0; var erroredCsprojInfos = new List <CsprojInfo>(); // replace version in csproj files if (!string.IsNullOrWhiteSpace(cmd.Version)) { foreach (var projectFile in projectFiles) { try { if (cmd.Verbose) { _logger.Debug($"changing package version of {Path.GetFileName(projectFile.Path)}"); } cd.Add(projectFile.ReplaceVersion(cmd.Version)); } catch (Exception x) { erroredCsprojInfos.Add(projectFile); packFailedCount++; _logger.Error(x.Message); } } } foreach (var projectFile in projectFiles.Except(erroredCsprojInfos)) { if (!DotnetPack(projectFile, cmd)) { _logger.Error($"dotnet pack failed for {Path.GetFileName(projectFile.Path)}"); packFailedCount++; } } if (packFailedCount != 0) { _logger.Warning( $"WARNING: Failed to create {packFailedCount} of {projectFiles.Count} *.nupkg files"); } } // resolve nuget package cache var pathWithEnv = $@"%USERPROFILE%\.nuget\packages\"; var packageCachePath = Environment.ExpandEnvironmentVariables(pathWithEnv); if (cmd.Verbose) { _logger.Info($"nuget package cache fount at '{packageCachePath}'"); } // find each nupkg and extract it to cache foreach (var projectFile in projectFiles) { var packageName = projectFile.NugetPackageName; var packagePath = Directory.EnumerateFiles(solutionDir, "*.nupkg", SearchOption.AllDirectories) .FirstOrDefault(p => string.Equals(packageName, Path.GetFileName(p), StringComparison.InvariantCultureIgnoreCase)); if (packagePath is null) { _logger.Error($"Could not find package {packageName}"); continue; } // verify, that there is a nuget package with the same id and version in the cache var extractPath = Path.Combine(packageCachePath, projectFile.PackageId, projectFile.ActualVersion); if (!Directory.Exists(extractPath)) { _logger.Warning($"Cannot debugify {packageName} as the package cannot be found in the cache: {extractPath}"); continue; } // extract nupkg contents into package cache ExtractNupkg(cmd, extractPath, packagePath); _logger.Success($"Successfully debugified {projectFile.PackageId} version {projectFile.ActualVersion}"); } }