mirror of
https://github.com/aphrody-labs/NuGet.Client.git
synced 2026-10-15 05:49:05 +00:00
322 lines
12 KiB
C#
322 lines
12 KiB
C#
#nullable disable
|
|
|
|
using System;
|
|
using System.CodeDom.Compiler;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Xml.Linq;
|
|
using Microsoft.CSharp;
|
|
using NuGet;
|
|
|
|
namespace GenerateTestPackages
|
|
{
|
|
class Program
|
|
{
|
|
const string KeyFileName = "TestPackageKey.snk";
|
|
|
|
static Dictionary<string, PackageInfo> Packages = new Dictionary<string, PackageInfo>();
|
|
|
|
static void Main(string[] args)
|
|
{
|
|
string path = args[0];
|
|
var extension = Path.GetExtension(path);
|
|
|
|
if (extension.Equals(".nuspec", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
BuildPackage(path);
|
|
}
|
|
else
|
|
{
|
|
BuildDependency(path);
|
|
}
|
|
}
|
|
|
|
private static void BuildPackage(string nuspecPath)
|
|
{
|
|
var repositoryPath = Path.GetDirectoryName(nuspecPath);
|
|
var basePath = Path.Combine(repositoryPath, "files", Path.GetFileNameWithoutExtension(nuspecPath));
|
|
Directory.CreateDirectory(basePath);
|
|
|
|
var createdFiles = new List<string>();
|
|
bool deleteDir = true;
|
|
using (var fileStream = File.OpenRead(nuspecPath))
|
|
{
|
|
var manifest = Manifest.ReadFrom(fileStream, validateSchema: true);
|
|
var packageBuilder = new PackageBuilder();
|
|
packageBuilder.Populate(manifest.Metadata);
|
|
if (!manifest.Files.IsEmpty())
|
|
{
|
|
foreach (var file in manifest.Files)
|
|
{
|
|
string outputPath = Path.Combine(basePath, file.Source);
|
|
if (File.Exists(outputPath))
|
|
{
|
|
deleteDir = false;
|
|
// A user created file exists. Continue to next file.
|
|
continue;
|
|
}
|
|
|
|
createdFiles.Add(outputPath);
|
|
string outputDir = Path.GetDirectoryName(outputPath);
|
|
if (!Directory.Exists(outputDir))
|
|
{
|
|
Directory.CreateDirectory(outputDir);
|
|
}
|
|
|
|
if (file.Source.StartsWith(@"lib" + Path.DirectorySeparatorChar) &&
|
|
(file.Source.EndsWith(".dll") && !file.Source.EndsWith("resources.dll")))
|
|
{
|
|
var name = Path.GetFileNameWithoutExtension(file.Source);
|
|
CreateAssembly(new PackageInfo(manifest.Metadata.Id + ":" + manifest.Metadata.Version),
|
|
outputPath: outputPath);
|
|
}
|
|
else
|
|
{
|
|
File.WriteAllBytes(outputPath, new byte[0]);
|
|
}
|
|
}
|
|
|
|
packageBuilder.PopulateFiles(basePath, manifest.Files);
|
|
}
|
|
|
|
string nupkgDirectory = Path.GetFullPath("packages");
|
|
Directory.CreateDirectory(nupkgDirectory);
|
|
string nupkgPath = Path.Combine(nupkgDirectory, Path.GetFileNameWithoutExtension(nuspecPath)) + ".nupkg";
|
|
using (var nupkgStream = File.Create(nupkgPath))
|
|
{
|
|
packageBuilder.Save(nupkgStream);
|
|
}
|
|
}
|
|
try
|
|
{
|
|
if (deleteDir)
|
|
{
|
|
Directory.Delete(basePath, recursive: true);
|
|
}
|
|
else
|
|
{
|
|
// Delete files that we created.
|
|
createdFiles.ForEach(File.Delete);
|
|
}
|
|
}
|
|
catch { }
|
|
}
|
|
|
|
private static void BuildDependency(string path)
|
|
{
|
|
var document = XDocument.Load(path);
|
|
|
|
XNamespace ns = "http://schemas.microsoft.com/vs/2009/dgml";
|
|
|
|
// Parse through the dgml file and group things by Source
|
|
Packages = document.Descendants(ns + "Link")
|
|
.ToLookup(l => l.Attribute("Source").Value)
|
|
.Select(group => new PackageInfo(group.Key, group.Select(GetDependencyInfoFromLinkTag)))
|
|
.ToDictionary(p => p.FullName.ToString());
|
|
|
|
// Add all the packages that only exist as targets to the dictionary
|
|
var allPackageNames = Packages.Values.SelectMany(p => p.Dependencies).Select(dep => dep.FullName.ToString()).Distinct().ToList();
|
|
foreach (var dependency in allPackageNames)
|
|
{
|
|
if (!Packages.ContainsKey(dependency))
|
|
{
|
|
Packages.Add(dependency, new PackageInfo(dependency));
|
|
}
|
|
}
|
|
|
|
// Process all the packages
|
|
foreach (var p in Packages.Values)
|
|
{
|
|
EnsurePackageProcessed(p);
|
|
}
|
|
|
|
// Add all packages that are simply listed as Nodes.
|
|
var remainders = document.Root.Elements(ns + "Nodes")
|
|
.Elements()
|
|
.Select(s => new PackageInfo(s.Attribute("Id").Value));
|
|
|
|
foreach (var package in remainders)
|
|
{
|
|
if (!Packages.ContainsKey(package.FullName.ToString()))
|
|
{
|
|
EnsurePackageProcessed(package);
|
|
}
|
|
}
|
|
}
|
|
|
|
static DependencyInfo GetDependencyInfoFromLinkTag(XElement linkTag)
|
|
{
|
|
var label = linkTag.Attribute("Label");
|
|
|
|
return new DependencyInfo(
|
|
new FullPackageName(linkTag.Attribute("Target").Value),
|
|
label != null ? VersionUtility.ParseVersionSpec(label.Value) : null);
|
|
}
|
|
|
|
static void EnsurePackageProcessed(string fullName)
|
|
{
|
|
EnsurePackageProcessed(Packages[fullName]);
|
|
}
|
|
|
|
static void EnsurePackageProcessed(PackageInfo package)
|
|
{
|
|
if (!package.Processed)
|
|
{
|
|
ProcessPackage(package);
|
|
package.Processed = true;
|
|
}
|
|
}
|
|
|
|
static void ProcessPackage(PackageInfo package)
|
|
{
|
|
// Make sure all its dependencies are processed first
|
|
foreach (var dependency in package.Dependencies)
|
|
{
|
|
EnsurePackageProcessed(dependency.FullName.ToString());
|
|
}
|
|
|
|
Console.WriteLine("Creating package {0}", package.FullName);
|
|
CreateAssembly(package);
|
|
CreatePackage(package);
|
|
}
|
|
|
|
static void CreateAssembly(PackageInfo package, string outputPath = null)
|
|
{
|
|
|
|
// Save the snk file from the embedded resource to the disk so we can use it when we compile
|
|
using (var resStream = typeof(Program).Assembly.GetManifestResourceStream("GenerateTestPackages." + KeyFileName))
|
|
{
|
|
using (var snkStream = File.Create(KeyFileName))
|
|
{
|
|
resStream.CopyTo(snkStream);
|
|
}
|
|
}
|
|
|
|
|
|
var codeProvider = new CSharpCodeProvider();
|
|
var compilerParams = new CompilerParameters()
|
|
{
|
|
OutputAssembly = outputPath ?? Path.GetFullPath(GetAssemblyFullPath(package.FullName)),
|
|
CompilerOptions = "/keyfile:" + KeyFileName
|
|
};
|
|
|
|
// Add all the dependencies as referenced assemblies
|
|
foreach (DependencyInfo dependency in package.Dependencies)
|
|
{
|
|
compilerParams.ReferencedAssemblies.Add(GetAssemblyFullPath(dependency.FullName));
|
|
}
|
|
|
|
// Create the source code and compile it using CodeDom
|
|
var generator = new AssemblySourceFileGenerator() { Package = package };
|
|
CompilerResults results = codeProvider.CompileAssemblyFromSource(compilerParams, generator.TransformText());
|
|
|
|
if (results.Errors.HasErrors)
|
|
{
|
|
Console.WriteLine(results.Errors[0]);
|
|
}
|
|
|
|
File.Delete(KeyFileName);
|
|
}
|
|
|
|
static void CreatePackage(PackageInfo package)
|
|
{
|
|
var packageBuilder = new PackageBuilder()
|
|
{
|
|
Id = package.Id,
|
|
Version = package.Version,
|
|
Description = "Some test package"
|
|
};
|
|
|
|
packageBuilder.Authors.Add(".NET Foundation");
|
|
|
|
string assemblySourcePath = GetAssemblyFullPath(package.FullName);
|
|
packageBuilder.Files.Add(new PhysicalPackageFile()
|
|
{
|
|
SourcePath = assemblySourcePath,
|
|
TargetPath = @"lib\" + Path.GetFileName(assemblySourcePath)
|
|
});
|
|
|
|
var set = new PackageDependencySet(VersionUtility.DefaultTargetFramework,
|
|
package.Dependencies.Select(dependency => new PackageDependency(dependency.Id, dependency.VersionSpec)));
|
|
packageBuilder.DependencySets.Add(set);
|
|
|
|
using (var stream = File.Create(GetPackageFileFullPath(package)))
|
|
{
|
|
packageBuilder.Save(stream);
|
|
}
|
|
}
|
|
|
|
static string GetAssemblyFullPath(FullPackageName fullName)
|
|
{
|
|
string relativeDir = string.Format(@"Assemblies\{0}\{1}", fullName.Id, fullName.Version);
|
|
string fullDir = Path.GetFullPath(relativeDir);
|
|
Directory.CreateDirectory(fullDir);
|
|
return Path.Combine(fullDir, fullName.Id + ".dll");
|
|
}
|
|
|
|
static string GetPackageFileFullPath(PackageInfo package)
|
|
{
|
|
string packagesFolder = Path.GetFullPath("Packages");
|
|
Directory.CreateDirectory(packagesFolder);
|
|
string packageFileName = String.Format("{0}.{1}.nupkg", package.Id, package.Version);
|
|
return Path.Combine(packagesFolder, packageFileName);
|
|
}
|
|
}
|
|
|
|
class PackageInfo
|
|
{
|
|
public PackageInfo(string nameAndVersion, IEnumerable<DependencyInfo> dependencies = null)
|
|
{
|
|
FullName = new FullPackageName(nameAndVersion);
|
|
|
|
Dependencies = dependencies != null ? dependencies : Enumerable.Empty<DependencyInfo>();
|
|
}
|
|
|
|
public FullPackageName FullName { get; private set; }
|
|
public string Id { get { return FullName.Id; } }
|
|
public SemanticVersion Version { get { return FullName.Version; } }
|
|
public IEnumerable<DependencyInfo> Dependencies { get; private set; }
|
|
public bool Processed { get; set; }
|
|
|
|
public override string ToString()
|
|
{
|
|
return FullName.ToString();
|
|
}
|
|
}
|
|
|
|
// Contains at least an exact id:version, and optionally a fuller version spec
|
|
class DependencyInfo
|
|
{
|
|
public DependencyInfo(FullPackageName fullName, IVersionSpec versionSpec)
|
|
{
|
|
FullName = fullName;
|
|
|
|
// Default to the simple version (which means min-version)
|
|
VersionSpec = versionSpec ?? VersionUtility.ParseVersionSpec(FullName.Version.ToString());
|
|
}
|
|
|
|
public FullPackageName FullName { get; private set; }
|
|
public IVersionSpec VersionSpec { get; private set; }
|
|
public string Id { get { return FullName.Id; } }
|
|
}
|
|
|
|
class FullPackageName
|
|
{
|
|
public FullPackageName(string nameAndVersion)
|
|
{
|
|
var parts = nameAndVersion.Split(':');
|
|
Id = parts[0];
|
|
Version = new SemanticVersion(parts[1]);
|
|
}
|
|
|
|
public string Id { get; private set; }
|
|
public SemanticVersion Version { get; private set; }
|
|
|
|
public override string ToString()
|
|
{
|
|
return Id + ":" + Version;
|
|
}
|
|
}
|
|
}
|