First pass at dotnet-pack

- Ported nuget package building code over from dnu. Moved that code to use NuGet v3 primitives.
- Simplified the package builder API
- Left out resources and schema detection for now
- This folder should remain self contained as the code will be copied into NuGet v3.
- Missing features include symbols packages
This commit is contained in:
David Fowler 2015-11-12 03:50:38 -08:00
parent ba3f0745e3
commit df3a5fba7a
23 changed files with 1870 additions and 18 deletions

View file

@ -220,7 +220,7 @@ namespace Microsoft.Extensions.ProjectModel.Compilation
{
foreach (var assemblyPath in section)
{
if (PathUtility.IsPlaceholderFile(assemblyPath))
if (IsPlaceholderFile(assemblyPath))
{
continue;
}
@ -232,6 +232,11 @@ namespace Microsoft.Extensions.ProjectModel.Compilation
}
}
private static bool IsPlaceholderFile(string path)
{
return string.Equals(Path.GetFileName(path), "_._", StringComparison.Ordinal);
}
private static bool LibraryIsOfType(LibraryType type, LibraryDescription library)
{
return type.Equals(LibraryType.Unspecified) || // No type filter was requested

View file

@ -9,7 +9,7 @@ namespace Microsoft.Extensions.ProjectModel.Graph
{
private readonly LibraryDependencyTypeFlag _flags;
public static LibraryDependencyType Default = new LibraryDependencyType();
public static LibraryDependencyType Default = LibraryDependencyType.Parse("default");
private LibraryDependencyType(LibraryDependencyTypeFlag flags)
{

View file

@ -1,4 +1,5 @@
using System.Linq;
using System.Runtime.Versioning;
namespace NuGet.Frameworks
{
@ -8,13 +9,45 @@ namespace NuGet.Frameworks
public static string GetTwoDigitShortFolderName(this NuGetFramework self)
{
var original = self.GetShortFolderName();
var digits = original.SkipWhile(c => !char.IsDigit(c)).ToArray();
if(digits.Length == 1)
var index = 0;
for (; index < original.Length; index++)
{
return original + "0";
if (char.IsDigit(original[index]))
{
break;
}
}
return original;
var versionPart = original.Substring(index);
// Assume if the version part was preserved then leave it alone
if (versionPart.IndexOf('.') != -1)
{
return original;
}
var name = original.Substring(0, index);
var version = self.Version.ToString(2);
if (self.Framework.Equals(FrameworkConstants.FrameworkIdentifiers.NetPlatform))
{
return name + version;
}
return name + version.Replace(".", string.Empty);
}
// NuGet.Frameworks doesn't have the equivalent of the old VersionUtility.GetFrameworkString
// which is relevant for building packages
public static string GetFrameworkString(this NuGetFramework self)
{
var frameworkName = new FrameworkName(self.DotNetFrameworkName);
string name = frameworkName.Identifier + frameworkName.Version;
if (string.IsNullOrEmpty(frameworkName.Profile))
{
return name;
}
return name + "-" + frameworkName.Profile;
}
}
}

View file

@ -9,11 +9,6 @@ namespace Microsoft.Extensions.ProjectModel.Utilities
{
internal static class PathUtility
{
public static bool IsPlaceholderFile(string path)
{
return string.Equals(Path.GetFileName(path), "_._", StringComparison.Ordinal);
}
public static bool IsChildOfDirectory(string dir, string candidate)
{
if (dir == null)

View file

@ -5,9 +5,9 @@ using NuGet.Versioning;
namespace Microsoft.Extensions.ProjectModel.Utilities
{
internal static class VersionUtility
public static class VersionUtility
{
public static NuGetVersion GetAssemblyVersion(string path)
internal static NuGetVersion GetAssemblyVersion(string path)
{
return new NuGetVersion(AssemblyLoadContext.GetAssemblyName(path).Version);
}

View file

@ -268,9 +268,7 @@ namespace Microsoft.DotNet.Tools.Compiler
runtimeContext.CreateExporter(configuration));
}
PrintSummary(diagnostics, sw, success);
return success;
return PrintSummary(diagnostics, sw, success);
}
private static string GetProjectOutput(Project project, NuGetFramework framework, string configuration, string outputPath)
@ -433,7 +431,7 @@ namespace Microsoft.DotNet.Tools.Compiler
return "\"" + input.Replace("\\", "\\\\").Replace("\"", "\\\"") + "\"";
}
private static void PrintSummary(List<DiagnosticMessage> diagnostics, Stopwatch sw, bool success = true)
private static bool PrintSummary(List<DiagnosticMessage> diagnostics, Stopwatch sw, bool success = true)
{
PrintDiagnostics(diagnostics);
@ -445,6 +443,7 @@ namespace Microsoft.DotNet.Tools.Compiler
if (errorCount > 0 || !success)
{
Reporter.Output.WriteLine("Compilation failed.".Red());
success = false;
}
else
{
@ -458,6 +457,8 @@ namespace Microsoft.DotNet.Tools.Compiler
Reporter.Output.WriteLine($"Time elapsed {sw.Elapsed}");
Reporter.Output.WriteLine();
return success;
}
private static bool AddResources(Project project, List<string> compilerArgs, string intermediateOutputPath)

View file

@ -0,0 +1,64 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
namespace NuGet
{
public static class Constants
{
/// <summary>
/// Represents the ".nupkg" extension.
/// </summary>
public static readonly string PackageExtension = ".nupkg";
/// <summary>
/// Represents the ".nuspec" extension.
/// </summary>
public static readonly string ManifestExtension = ".nuspec";
/// <summary>
/// Represents the ".nupkg.sha512" extension.
/// </summary>
public static readonly string HashFileExtension = ".nupkg.sha512";
/// <summary>
/// Represents the content directory in the package.
/// </summary>
public static readonly string ContentDirectory = "content";
/// <summary>
/// Represents the lib directory in the package.
/// </summary>
public static readonly string LibDirectory = "lib";
/// <summary>
/// Represents the tools directory in the package.
/// </summary>
public static readonly string ToolsDirectory = "tools";
/// <summary>
/// Represents the build directory in the package.
/// </summary>
public static readonly string BuildDirectory = "build";
public static readonly string BinDirectory = "bin";
public static readonly string PackageReferenceFile = "packages.config";
public static readonly string BeginIgnoreMarker = "NUGET: BEGIN LICENSE TEXT";
public static readonly string EndIgnoreMarker = "NUGET: END LICENSE TEXT";
internal const string PackageRelationshipNamespace = "http://schemas.microsoft.com/packaging/2010/07/";
// Starting from nuget 2.0, we use a file with the special name '_._' to represent an empty folder.
public const string PackageEmptyFileName = "_._";
// This is temporary until we fix the gallery to have proper first class support for this.
// The magic unpublished date is 1900-01-01T00:00:00
public static readonly DateTimeOffset Unpublished = new DateTimeOffset(1900, 1, 1, 0, 0, 0, TimeSpan.FromHours(-8));
public static readonly IReadOnlyList<string> AssemblyReferencesExtensions
= new string[] { ".dll", ".exe", ".winmd" };
}
}

View file

@ -0,0 +1,29 @@
using System;
using System.Collections.Generic;
using NuGet.Frameworks;
namespace NuGet
{
public class FrameworkAssemblyReference
{
public FrameworkAssemblyReference(string assemblyName, IEnumerable<NuGetFramework> supportedFrameworks)
{
if (string.IsNullOrEmpty(assemblyName))
{
throw new ArgumentException(nameof(assemblyName));
}
if (supportedFrameworks == null)
{
throw new ArgumentNullException(nameof(supportedFrameworks));
}
AssemblyName = assemblyName;
SupportedFrameworks = supportedFrameworks;
}
public string AssemblyName { get; private set; }
public IEnumerable<NuGetFramework> SupportedFrameworks { get; private set; }
}
}

View file

@ -0,0 +1,20 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.IO;
namespace NuGet
{
public interface IPackageFile
{
/// <summary>
/// Gets the full path of the file inside the package.
/// </summary>
string Path
{
get;
}
Stream GetStream();
}
}

View file

@ -0,0 +1,87 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.IO;
using System.Linq;
using System.Xml.Linq;
namespace NuGet
{
public class Manifest
{
private const string SchemaVersionAttributeName = "schemaVersion";
public Manifest(ManifestMetadata metadata)
{
if (metadata == null)
{
throw new ArgumentNullException(nameof(metadata));
}
Metadata = metadata;
}
public ManifestMetadata Metadata { get; }
/// <summary>
/// Saves the current manifest to the specified stream.
/// </summary>
/// <param name="stream">The target stream.</param>
public void Save(Stream stream)
{
Save(stream, validate: true, minimumManifestVersion: 1);
}
/// <summary>
/// Saves the current manifest to the specified stream.
/// </summary>
/// <param name="stream">The target stream.</param>
/// <param name="minimumManifestVersion">The minimum manifest version that this class must use when saving.</param>
public void Save(Stream stream, int minimumManifestVersion)
{
Save(stream, validate: true, minimumManifestVersion: minimumManifestVersion);
}
public void Save(Stream stream, bool validate)
{
Save(stream, validate, minimumManifestVersion: 1);
}
public void Save(Stream stream, bool validate, int minimumManifestVersion)
{
int version = Math.Max(minimumManifestVersion, ManifestVersionUtility.GetManifestVersion(Metadata));
var schemaNamespace = (XNamespace)ManifestSchemaUtility.GetSchemaNamespace(version);
new XDocument(
new XElement(schemaNamespace + "package",
Metadata.ToXElement(schemaNamespace))).Save(stream);
}
public static Manifest Create(PackageBuilder copy)
{
var metadata = new ManifestMetadata();
metadata.Id = copy.Id?.Trim();
metadata.Version = copy.Version;
metadata.Title = copy.Title?.Trim();
metadata.Authors = copy.Authors.Distinct();
metadata.Owners = copy.Owners.Distinct();
metadata.Tags = string.Join(",", copy.Tags).Trim();
metadata.LicenseUrl = copy.LicenseUrl;
metadata.ProjectUrl = copy.ProjectUrl;
metadata.IconUrl = copy.IconUrl;
metadata.RequireLicenseAcceptance = copy.RequireLicenseAcceptance;
metadata.Description = copy.Description?.Trim();
metadata.Copyright = copy.Copyright?.Trim();
metadata.Summary = copy.Summary?.Trim();
metadata.ReleaseNotes = copy.ReleaseNotes?.Trim();
metadata.Language = copy.Language?.Trim();
metadata.DependencySets = copy.DependencySets;
metadata.FrameworkAssemblies = copy.FrameworkAssemblies;
metadata.PackageAssemblyReferences = copy.PackageAssemblyReferences;
metadata.MinClientVersionString = copy.MinClientVersion?.ToString();
return new Manifest(metadata);
}
}
}

View file

@ -0,0 +1,84 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using NuGet.Versioning;
namespace NuGet
{
public class ManifestMetadata
{
private string _minClientVersionString;
private IEnumerable<string> _authors = Enumerable.Empty<string>();
private IEnumerable<string> _owners = Enumerable.Empty<string>();
[ManifestVersion(5)]
public string MinClientVersionString
{
get { return _minClientVersionString; }
set
{
Version version = null;
if (!string.IsNullOrEmpty(value) && !System.Version.TryParse(value, out version))
{
// TODO: Resources
throw new InvalidDataException("NuGetResources.Manifest_InvalidMinClientVersion");
}
_minClientVersionString = value;
MinClientVersion = version;
}
}
public Version MinClientVersion { get; private set; }
public string Id { get; set; }
public NuGetVersion Version { get; set; }
public string Title { get; set; }
public IEnumerable<string> Authors
{
get { return _authors; }
set { _authors = value ?? Enumerable.Empty<string>(); }
}
public IEnumerable<string> Owners
{
get { return (_owners == null || !_owners.Any()) ? _authors : _owners; }
set { _owners = value ?? Enumerable.Empty<string>(); }
}
public Uri IconUrl { get; set; }
public Uri LicenseUrl { get; set; }
public Uri ProjectUrl { get; set; }
public bool RequireLicenseAcceptance { get; set; }
public string Description { get; set; }
public string Summary { get; set; }
[ManifestVersion(2)]
public string ReleaseNotes { get; set; }
[ManifestVersion(2)]
public string Copyright { get; set; }
public string Language { get; set; }
public string Tags { get; set; }
public IEnumerable<PackageDependencySet> DependencySets { get; set; } = new List<PackageDependencySet>();
public ICollection<PackageReferenceSet> PackageAssemblyReferences { get; set; } = new List<PackageReferenceSet>();
public IEnumerable<FrameworkAssemblyReference> FrameworkAssemblies { get; set; } = new List<FrameworkAssemblyReference>();
}
}

View file

@ -0,0 +1,77 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Globalization;
using System.Linq;
namespace NuGet
{
internal static class ManifestSchemaUtility
{
/// <summary>
/// Baseline schema
/// </summary>
internal const string SchemaVersionV1 = "http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd";
/// <summary>
/// Added copyrights, references and release notes
/// </summary>
internal const string SchemaVersionV2 = "http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd";
/// <summary>
/// Used if the version is a semantic version.
/// </summary>
internal const string SchemaVersionV3 = "http://schemas.microsoft.com/packaging/2011/10/nuspec.xsd";
/// <summary>
/// Added 'targetFramework' attribute for 'dependency' elements.
/// Allow framework folders under 'content' and 'tools' folders.
/// </summary>
internal const string SchemaVersionV4 = "http://schemas.microsoft.com/packaging/2012/06/nuspec.xsd";
/// <summary>
/// Added 'targetFramework' attribute for 'references' elements.
/// Added 'minClientVersion' attribute
/// </summary>
internal const string SchemaVersionV5 = "http://schemas.microsoft.com/packaging/2013/01/nuspec.xsd";
/// <summary>
/// Allows XDT transformation
/// </summary>
internal const string SchemaVersionV6 = "http://schemas.microsoft.com/packaging/2013/05/nuspec.xsd";
private static readonly string[] VersionToSchemaMappings = new[] {
SchemaVersionV1,
SchemaVersionV2,
SchemaVersionV3,
SchemaVersionV4,
SchemaVersionV5,
SchemaVersionV6
};
public static int GetVersionFromNamespace(string @namespace)
{
int index = Math.Max(0, Array.IndexOf(VersionToSchemaMappings, @namespace));
// we count version from 1 instead of 0
return index + 1;
}
public static string GetSchemaNamespace(int version)
{
// Versions are internally 0-indexed but stored with a 1 index so decrement it by 1
if (version <= 0 || version > VersionToSchemaMappings.Length)
{
// TODO: Resources
throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture, "NuGetResources.UnknownSchemaVersion", version));
}
return VersionToSchemaMappings[version - 1];
}
public static bool IsKnownSchema(string schemaNamespace)
{
return VersionToSchemaMappings.Contains(schemaNamespace, StringComparer.OrdinalIgnoreCase);
}
}
}

View file

@ -0,0 +1,18 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
namespace NuGet
{
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
internal sealed class ManifestVersionAttribute : Attribute
{
public ManifestVersionAttribute(int version)
{
Version = version;
}
public int Version { get; private set; }
}
}

View file

@ -0,0 +1,111 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections;
using System.Linq;
using System.Reflection;
namespace NuGet
{
internal static class ManifestVersionUtility
{
public const int DefaultVersion = 1;
public const int SemverVersion = 3;
public const int TargetFrameworkSupportForDependencyContentsAndToolsVersion = 4;
public const int TargetFrameworkSupportForReferencesVersion = 5;
public const int XdtTransformationVersion = 6;
public static int GetManifestVersion(ManifestMetadata metadata)
{
return Math.Max(GetVersionFromObject(metadata), GetMaxVersionFromMetadata(metadata));
}
private static int GetMaxVersionFromMetadata(ManifestMetadata metadata)
{
// Important: check for version 5 before version 4
bool referencesHasTargetFramework =
metadata.PackageAssemblyReferences != null &&
metadata.PackageAssemblyReferences.Any(r => r.TargetFramework != null);
if (referencesHasTargetFramework)
{
return TargetFrameworkSupportForReferencesVersion;
}
bool dependencyHasTargetFramework =
metadata.DependencySets != null &&
metadata.DependencySets.Any(d => d.TargetFramework != null);
if (dependencyHasTargetFramework)
{
return TargetFrameworkSupportForDependencyContentsAndToolsVersion;
}
if (metadata.Version.IsPrerelease)
{
return SemverVersion;
}
return DefaultVersion;
}
private static int GetVersionFromObject(object obj)
{
// all public, gettable, non-static properties
return obj?.GetType()
.GetRuntimeProperties()
.Where(prop => prop.GetMethod != null && prop.GetMethod.IsPublic && !prop.GetMethod.IsStatic)
.Select(prop => GetVersionFromPropertyInfo(obj, prop))
.Max()
?? DefaultVersion;
}
private static int GetVersionFromPropertyInfo(object obj, PropertyInfo property)
{
var value = property.GetValue(obj, index: null);
if (value == null)
{
return DefaultVersion;
}
int? version = GetPropertyVersion(property);
if (!version.HasValue)
{
return DefaultVersion;
}
var stringValue = value as string;
if (stringValue != null)
{
if (!string.IsNullOrEmpty(stringValue))
{
return version.Value;
}
return DefaultVersion;
}
// For all other object types a null check would suffice.
return version.Value;
}
private static int VisitList(IEnumerable list)
{
int version = DefaultVersion;
foreach (var item in list)
{
version = Math.Max(version, GetVersionFromObject(item));
}
return version;
}
private static int? GetPropertyVersion(PropertyInfo property)
{
var attribute = property.GetCustomAttribute<ManifestVersionAttribute>();
return attribute?.Version;
}
}
}

View file

@ -0,0 +1,382 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using NuGet.Packaging;
using NuGet.Packaging.Core;
using NuGet.Versioning;
namespace NuGet
{
public class PackageBuilder
{
private const string DefaultContentType = "application/octet";
internal const string ManifestRelationType = "manifest";
public PackageBuilder()
{
Files = new List<IPackageFile>();
DependencySets = new List<PackageDependencySet>();
FrameworkAssemblies = new List<FrameworkAssemblyReference>();
PackageAssemblyReferences = new List<PackageReferenceSet>();
Authors = new List<string>();
Owners = new List<string>();
Tags = new List<string>();
}
public string Id
{
get;
set;
}
public NuGetVersion Version
{
get;
set;
}
public string Title
{
get;
set;
}
public List<string> Authors
{
get;
private set;
}
public List<string> Owners
{
get;
private set;
}
public Uri IconUrl
{
get;
set;
}
public Uri LicenseUrl
{
get;
set;
}
public Uri ProjectUrl
{
get;
set;
}
public bool RequireLicenseAcceptance
{
get;
set;
}
public bool DevelopmentDependency
{
get;
set;
}
public string Description
{
get;
set;
}
public string Summary
{
get;
set;
}
public string ReleaseNotes
{
get;
set;
}
public string Language
{
get;
set;
}
public List<string> Tags
{
get;
private set;
}
public string Copyright
{
get;
set;
}
public List<PackageDependencySet> DependencySets
{
get;
private set;
}
public List<IPackageFile> Files
{
get;
private set;
}
public List<FrameworkAssemblyReference> FrameworkAssemblies
{
get;
private set;
}
public List<PackageReferenceSet> PackageAssemblyReferences
{
get;
private set;
}
public Version MinClientVersion
{
get;
set;
}
public void Save(Stream stream)
{
// Make sure we're saving a valid package id
PackageIdValidator.ValidatePackageId(Id);
// Throw if the package doesn't contain any dependencies nor content
if (!Files.Any() && !DependencySets.SelectMany(d => d.Dependencies).Any() && !FrameworkAssemblies.Any())
{
// TODO: Resources
throw new InvalidOperationException("NuGetResources.CannotCreateEmptyPackage");
}
if (!ValidateSpecialVersionLength(Version))
{
// TODO: Resources
throw new InvalidOperationException("NuGetResources.SemVerSpecialVersionTooLong");
}
ValidateDependencySets(Version, DependencySets);
ValidateReferenceAssemblies(Files, PackageAssemblyReferences);
using (var package = new ZipArchive(stream, ZipArchiveMode.Create))
{
// Validate and write the manifest
WriteManifest(package, ManifestVersionUtility.DefaultVersion);
// Write the files to the package
var extensions = WriteFiles(package);
extensions.Add("nuspec");
WriteOpcContentTypes(package, extensions);
}
}
private static string CreatorInfo()
{
var creatorInfo = new List<string>();
var assembly = typeof(PackageBuilder).GetTypeInfo().Assembly;
creatorInfo.Add(assembly.FullName);
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
{
creatorInfo.Add("Linux");
}
else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
{
creatorInfo.Add("OSX");
}
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
creatorInfo.Add("Windows");
}
var attribute = assembly.GetCustomAttributes<System.Runtime.Versioning.TargetFrameworkAttribute>().FirstOrDefault();
if (attribute != null)
{
creatorInfo.Add(attribute.FrameworkDisplayName);
}
return String.Join(";", creatorInfo);
}
internal static void ValidateDependencySets(SemanticVersion version, IEnumerable<PackageDependencySet> dependencies)
{
if (version == null)
{
// We have independent validation for null-versions.
return;
}
foreach (var dep in dependencies.SelectMany(s => s.Dependencies))
{
PackageIdValidator.ValidatePackageId(dep.Id);
}
// REVIEW: Do we want to keep enfocing this?
/*if (version.IsPrerelease)
{
// If we are creating a production package, do not allow any of the dependencies to be a prerelease version.
var prereleaseDependency = dependencies.SelectMany(set => set.Dependencies).FirstOrDefault(IsPrereleaseDependency);
if (prereleaseDependency != null)
{
throw new InvalidDataException(String.Format(CultureInfo.CurrentCulture, "NuGetResources.Manifest_InvalidPrereleaseDependency", prereleaseDependency.ToString()));
}
}*/
}
internal static void ValidateReferenceAssemblies(IEnumerable<IPackageFile> files, IEnumerable<PackageReferenceSet> packageAssemblyReferences)
{
var libFiles = new HashSet<string>(from file in files
where !string.IsNullOrEmpty(file.Path) && file.Path.StartsWith("lib", StringComparison.OrdinalIgnoreCase)
select Path.GetFileName(file.Path), StringComparer.OrdinalIgnoreCase);
foreach (var reference in packageAssemblyReferences.SelectMany(p => p.References))
{
if (!libFiles.Contains(reference) &&
!libFiles.Contains(reference + ".dll") &&
!libFiles.Contains(reference + ".exe") &&
!libFiles.Contains(reference + ".winmd"))
{
// TODO: Resources
throw new InvalidDataException(String.Format(CultureInfo.CurrentCulture, "NuGetResources.Manifest_InvalidReference", reference));
}
}
}
private void WriteManifest(ZipArchive package, int minimumManifestVersion)
{
string path = Id + Constants.ManifestExtension;
WriteOpcManifestRelationship(package, path);
ZipArchiveEntry entry = package.CreateEntry(path, CompressionLevel.Optimal);
using (Stream stream = entry.Open())
{
Manifest manifest = Manifest.Create(this);
manifest.Save(stream, minimumManifestVersion);
}
}
private HashSet<string> WriteFiles(ZipArchive package)
{
var extensions = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
// Add files that might not come from expanding files on disk
foreach (var file in Files.Distinct())
{
using (Stream stream = file.GetStream())
{
try
{
CreatePart(package, file.Path, stream);
var fileExtension = Path.GetExtension(file.Path);
// We have files without extension (e.g. the executables for Nix)
if (!string.IsNullOrEmpty(fileExtension))
{
extensions.Add(fileExtension.Substring(1));
}
}
catch
{
throw;
}
}
}
return extensions;
}
private static void CreatePart(ZipArchive package, string path, Stream sourceStream)
{
if (PackageHelper.IsManifest(path))
{
return;
}
var entry = package.CreateEntry(PathUtility.GetPathWithForwardSlashes(path), CompressionLevel.Optimal);
using (var stream = entry.Open())
{
sourceStream.CopyTo(stream);
}
}
private static bool IsPrereleaseDependency(PackageDependency dependency)
{
return dependency.VersionRange.MinVersion?.IsPrerelease == true ||
dependency.VersionRange.MaxVersion?.IsPrerelease == true;
}
private static bool ValidateSpecialVersionLength(SemanticVersion version)
{
if (!version.IsPrerelease)
{
return true;
}
return version == null || version.Release.Length <= 20;
}
private void WriteOpcManifestRelationship(ZipArchive package, string path)
{
ZipArchiveEntry relsEntry = package.CreateEntry("_rels/.rels", CompressionLevel.Optimal);
using (var writer = new StreamWriter(relsEntry.Open()))
{
writer.Write(String.Format(@"<?xml version=""1.0"" encoding=""utf-8""?>
<Relationships xmlns=""http://schemas.openxmlformats.org/package/2006/relationships"">
<Relationship Type=""http://schemas.microsoft.com/packaging/2010/07/manifest"" Target=""/{0}"" Id=""{1}"" />
</Relationships>", path, GenerateRelationshipId()));
writer.Flush();
}
}
private static void WriteOpcContentTypes(ZipArchive package, HashSet<string> extensions)
{
// OPC backwards compatibility
ZipArchiveEntry relsEntry = package.CreateEntry("[Content_Types].xml", CompressionLevel.Optimal);
using (var writer = new StreamWriter(relsEntry.Open()))
{
writer.Write(@"<?xml version=""1.0"" encoding=""utf-8""?>
<Types xmlns=""http://schemas.openxmlformats.org/package/2006/content-types"">
<Default Extension=""rels"" ContentType=""application/vnd.openxmlformats-package.relationships+xml"" />");
foreach (var extension in extensions)
{
writer.Write(@"<Default Extension=""" + extension + @""" ContentType=""application/octet"" />");
}
writer.Write("</Types>");
writer.Flush();
}
}
// Generate a relationship id for compatibility
private string GenerateRelationshipId()
{
return "R" + Guid.NewGuid().ToString("N").Substring(0, 16);
}
}
}

View file

@ -0,0 +1,39 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Linq;
using NuGet.Frameworks;
using NuGet.Packaging.Core;
namespace NuGet
{
public class PackageDependencySet
{
public PackageDependencySet(IEnumerable<PackageDependency> dependencies)
: this((NuGetFramework)null, dependencies)
{
}
public PackageDependencySet(string targetFramework, IEnumerable<PackageDependency> dependencies)
: this(targetFramework != null ? NuGetFramework.Parse(targetFramework) : null, dependencies)
{
}
public PackageDependencySet(NuGetFramework targetFramework, IEnumerable<PackageDependency> dependencies)
{
if (dependencies == null)
{
throw new ArgumentNullException(nameof(dependencies));
}
TargetFramework = targetFramework;
Dependencies = dependencies.ToArray();
}
public NuGetFramework TargetFramework { get; }
public IReadOnlyList<PackageDependency> Dependencies { get; }
}
}

View file

@ -0,0 +1,72 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Globalization;
namespace NuGet
{
public static class PackageIdValidator
{
internal const int MaxPackageIdLength = 100;
public static bool IsValidPackageId(string packageId)
{
if (string.IsNullOrWhiteSpace(packageId))
{
throw new ArgumentException(nameof(packageId));
}
// Rules:
// Should start with a character
// Can be followed by '.' or '-'. Cannot have 2 of these special characters consecutively.
// Cannot end with '-' or '.'
var firstChar = packageId[0];
if (!char.IsLetterOrDigit(firstChar) && firstChar != '_')
{
// Should start with a char/digit/_.
return false;
}
var lastChar = packageId[packageId.Length - 1];
if (lastChar == '-' || lastChar == '.')
{
// Should not end with a '-' or '.'.
return false;
}
for (int index = 1; index < packageId.Length - 1; index++)
{
var ch = packageId[index];
if (!char.IsLetterOrDigit(ch) && ch != '-' && ch != '.')
{
return false;
}
if ((ch == '-' || ch == '.') && ch == packageId[index - 1])
{
// Cannot have two successive '-' or '.' in the name.
return false;
}
}
return true;
}
public static void ValidatePackageId(string packageId)
{
if (packageId.Length > MaxPackageIdLength)
{
// TODO: Resources
throw new ArgumentException("NuGetResources.Manifest_IdMaxLengthExceeded");
}
if (!IsValidPackageId(packageId))
{
// TODO: Resources
throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, "NuGetResources.InvalidPackageId", packageId));
}
}
}
}

View file

@ -0,0 +1,182 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
using NuGet.Frameworks;
using NuGet.Packaging.Core;
namespace NuGet
{
internal static class PackageMetadataXmlExtensions
{
private const string References = "references";
private const string Reference = "reference";
private const string Group = "group";
private const string File = "file";
private const string TargetFramework = "targetFramework";
private const string FrameworkAssemblies = "frameworkAssemblies";
private const string FrameworkAssembly = "frameworkAssembly";
private const string AssemblyName = "assemblyName";
private const string Dependencies = "dependencies";
public static XElement ToXElement(this ManifestMetadata metadata, XNamespace ns)
{
var elem = new XElement(ns + "metadata");
if (metadata.MinClientVersionString != null)
{
elem.SetAttributeValue("minClientVersion", metadata.MinClientVersionString);
}
elem.Add(new XElement(ns + "id", metadata.Id));
elem.Add(new XElement(ns + "version", metadata.Version.ToString()));
AddElementIfNotNull(elem, ns, "title", metadata.Title);
elem.Add(new XElement(ns + "requireLicenseAcceptance", metadata.RequireLicenseAcceptance));
AddElementIfNotNull(elem, ns, "authors", metadata.Authors, authors => string.Join(",", authors));
AddElementIfNotNull(elem, ns, "owners", metadata.Owners, owners => string.Join(",", owners));
AddElementIfNotNull(elem, ns, "licenseUrl", metadata.LicenseUrl);
AddElementIfNotNull(elem, ns, "projectUrl", metadata.ProjectUrl);
AddElementIfNotNull(elem, ns, "iconUrl", metadata.IconUrl);
AddElementIfNotNull(elem, ns, "description", metadata.Description);
AddElementIfNotNull(elem, ns, "summary", metadata.Summary);
AddElementIfNotNull(elem, ns, "releaseNotes", metadata.ReleaseNotes);
AddElementIfNotNull(elem, ns, "copyright", metadata.Copyright);
AddElementIfNotNull(elem, ns, "language", metadata.Language);
AddElementIfNotNull(elem, ns, "tags", metadata.Tags);
elem.Add(GetXElementFromGroupableItemSets(
ns,
metadata.DependencySets,
set => set.TargetFramework != null,
set => set.TargetFramework.GetFrameworkString(),
set => set.Dependencies,
GetXElementFromPackageDependency,
Dependencies,
TargetFramework));
elem.Add(GetXElementFromGroupableItemSets(
ns,
metadata.PackageAssemblyReferences,
set => set.TargetFramework != null,
set => set.TargetFramework.GetFrameworkString(),
set => set.References,
GetXElementFromPackageReference,
References,
TargetFramework));
elem.Add(GetXElementFromFrameworkAssemblies(ns, metadata.FrameworkAssemblies));
return elem;
}
private static XElement GetXElementFromGroupableItemSets<TSet, TItem>(
XNamespace ns,
IEnumerable<TSet> objectSets,
Func<TSet, bool> isGroupable,
Func<TSet, string> getGroupIdentifer,
Func<TSet, IEnumerable<TItem>> getItems,
Func<XNamespace, TItem, XElement> getXElementFromItem,
string parentName,
string identiferAttributeName)
{
if (objectSets == null || !objectSets.Any())
{
return null;
}
var groupableSets = new List<TSet>();
var ungroupableSets = new List<TSet>();
foreach (var set in objectSets)
{
if (isGroupable(set))
{
groupableSets.Add(set);
}
else
{
ungroupableSets.Add(set);
}
}
var childElements = new List<XElement>();
if (!groupableSets.Any())
{
// none of the item sets are groupable, then flatten the items
childElements.AddRange(objectSets.SelectMany(getItems).Select(item => getXElementFromItem(ns, item)));
}
else
{
// move the group with null target framework (if any) to the front just for nicer display in UI
foreach (var set in ungroupableSets.Concat(groupableSets))
{
var groupElem = new XElement(
ns + Group,
getItems(set).Select(item => getXElementFromItem(ns, item)).ToArray());
if (isGroupable(set))
{
groupElem.SetAttributeValue(identiferAttributeName, getGroupIdentifer(set));
}
childElements.Add(groupElem);
}
}
return new XElement(ns + parentName, childElements.ToArray());
}
private static XElement GetXElementFromPackageReference(XNamespace ns, string reference)
{
return new XElement(ns + Reference, new XAttribute(File, reference));
}
private static XElement GetXElementFromPackageDependency(XNamespace ns, PackageDependency dependency)
{
return new XElement(ns + "dependency",
new XAttribute("id", dependency.Id),
dependency.VersionRange != null ? new XAttribute("version", dependency.VersionRange.ToString()) : null);
}
private static XElement GetXElementFromFrameworkAssemblies(XNamespace ns, IEnumerable<FrameworkAssemblyReference> references)
{
if (references == null || !references.Any())
{
return null;
}
return new XElement(
ns + FrameworkAssemblies,
references.Select(reference =>
new XElement(ns + FrameworkAssembly,
new XAttribute(AssemblyName, reference.AssemblyName),
reference.SupportedFrameworks != null && reference.SupportedFrameworks.Any() ?
new XAttribute("targetFramework", string.Join(", ", reference.SupportedFrameworks.Select(f => f.GetFrameworkString()))) :
null)));
}
private static void AddElementIfNotNull<T>(XElement parent, XNamespace ns, string name, T value)
where T : class
{
if (value != null)
{
parent.Add(new XElement(ns + name, value));
}
}
private static void AddElementIfNotNull<T>(XElement parent, XNamespace ns, string name, T value, Func<T, object> process)
where T : class
{
if (value != null)
{
var processed = process(value);
if (processed != null)
{
parent.Add(new XElement(ns + name, processed));
}
}
}
}
}

View file

@ -0,0 +1,34 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Linq;
using NuGet.Frameworks;
namespace NuGet
{
public class PackageReferenceSet
{
public PackageReferenceSet(IEnumerable<string> references)
: this(null, references)
{
}
public PackageReferenceSet(NuGetFramework targetFramework, IEnumerable<string> references)
{
if (references == null)
{
throw new ArgumentNullException(nameof(references));
}
TargetFramework = targetFramework;
References = references.ToArray();
}
public IReadOnlyCollection<string> References { get; }
public NuGetFramework TargetFramework { get; }
}
}

View file

@ -0,0 +1,33 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.IO;
namespace NuGet
{
internal static class PathUtility
{
public static string GetPathWithForwardSlashes(string path)
{
return path.Replace('\\', '/');
}
public static string GetPathWithBackSlashes(string path)
{
return path.Replace('/', '\\');
}
public static string GetPathWithDirectorySeparator(string path)
{
if (Path.DirectorySeparatorChar == '/')
{
return GetPathWithForwardSlashes(path);
}
else
{
return GetPathWithBackSlashes(path);
}
}
}
}

View file

@ -0,0 +1,80 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.IO;
namespace NuGet
{
public class PhysicalPackageFile : IPackageFile
{
private readonly Func<Stream> _streamFactory;
public PhysicalPackageFile()
{
}
public PhysicalPackageFile(PhysicalPackageFile file)
{
SourcePath = file.SourcePath;
TargetPath = file.TargetPath;
}
internal PhysicalPackageFile(Func<Stream> streamFactory)
{
_streamFactory = streamFactory;
}
/// <summary>
/// Path on disk
/// </summary>
public string SourcePath { get; set; }
/// <summary>
/// Path in package
/// </summary>
public string TargetPath { get; set; }
public string Path
{
get
{
return TargetPath;
}
}
public Stream GetStream()
{
return _streamFactory != null ? _streamFactory() : File.OpenRead(SourcePath);
}
public override string ToString()
{
return TargetPath;
}
public override bool Equals(object obj)
{
var file = obj as PhysicalPackageFile;
return file != null && string.Equals(SourcePath, file.SourcePath, StringComparison.OrdinalIgnoreCase) &&
string.Equals(TargetPath, file.TargetPath, StringComparison.OrdinalIgnoreCase);
}
public override int GetHashCode()
{
int hash = 0;
if (SourcePath != null)
{
hash = SourcePath.GetHashCode();
}
if (TargetPath != null)
{
hash = hash * 4567 + TargetPath.GetHashCode();
}
return hash;
}
}
}

View file

@ -0,0 +1,475 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using Microsoft.Extensions.ProjectModel;
using NuGet;
using Microsoft.Dnx.Runtime.Common.CommandLine;
using Microsoft.DotNet.Cli.Utils;
using NuGet.Packaging.Core;
using Microsoft.Extensions.ProjectModel.Graph;
using NuGet.Versioning;
using NuGet.Frameworks;
using Microsoft.Extensions.ProjectModel.Files;
using Microsoft.Extensions.FileSystemGlobbing;
using Microsoft.Extensions.FileSystemGlobbing.Abstractions;
using Microsoft.Extensions.ProjectModel.Utilities;
namespace Microsoft.DotNet.Tools.Compiler
{
public class Program
{
public static int Main(string[] args)
{
DebugHelper.HandleDebugSwitch(ref args);
var app = new CommandLineApplication();
app.Name = "dotnet compile";
app.FullName = ".NET Compiler";
app.Description = "Compiler for the .NET Platform";
app.HelpOption("-h|--help");
var output = app.Option("-o|--output <OUTPUT_DIR>", "Directory in which to place outputs", CommandOptionType.SingleValue);
var intermediateOutput = app.Option("-t|--temp-output <OUTPUT_DIR>", "Directory in which to place temporary outputs", CommandOptionType.SingleValue);
var configuration = app.Option("-c|--configuration <CONFIGURATION>", "Configuration under which to build", CommandOptionType.SingleValue);
var project = app.Argument("<PROJECT>", "The project to compile, defaults to the current directory. Can be a path to a project.json or a project directory");
app.OnExecute(() =>
{
// Locate the project and get the name and full path
var path = project.Value;
if (string.IsNullOrEmpty(path))
{
path = Directory.GetCurrentDirectory();
}
var configValue = configuration.Value() ?? Cli.Utils.Constants.DefaultConfiguration;
var outputValue = output.Value();
return BuildPackage(path, configValue, outputValue, intermediateOutput.Value()) ? 1 : 0;
});
try
{
return app.Execute(args);
}
catch (Exception ex)
{
#if DEBUG
Console.Error.WriteLine(ex);
#else
Console.Error.WriteLine(ex.Message);
#endif
return 1;
}
}
private static bool BuildPackage(string path, string configuration, string outputValue, string intermediateOutputValue)
{
var contexts = ProjectContext.CreateContextForEachFramework(path);
var project = contexts.First().ProjectFile;
if (project.Files.SourceFiles.Any())
{
var argsBuilder = new StringBuilder();
argsBuilder.Append($"--configuration {configuration}");
if (!string.IsNullOrEmpty(outputValue))
{
argsBuilder.Append($" --output \"{outputValue}\"");
}
if (!string.IsNullOrEmpty(intermediateOutputValue))
{
argsBuilder.Append($" --temp-output \"{intermediateOutputValue}\"");
}
argsBuilder.Append($" \"{path}\"");
var result = Command.Create("dotnet-compile", argsBuilder.ToString())
.ForwardStdOut()
.ForwardStdErr()
.Execute();
if (result.ExitCode != 0)
{
return false;
}
}
Reporter.Output.WriteLine($"Producing nuget package for {project.Name}");
var packDiagnostics = new List<DiagnosticMessage>();
// Things compiled now build the package
var packageBuilder = CreatePackageBuilder(project);
// TODO: Report errors for required fields
// id
// author
// description
foreach (var context in contexts)
{
Reporter.Verbose.WriteLine($"Processing {context.TargetFramework.ToString().Yellow()}");
PopulateDependencies(context, packageBuilder);
var outputPath = GetOutputPath(context, configuration, outputValue);
var outputName = GetProjectOutputName(context.ProjectFile, context.TargetFramework, configuration);
TryAddOutputFile(packageBuilder, context, outputPath, outputName);
// REVIEW: Do we keep making symbols packages?
TryAddOutputFile(packageBuilder, context, outputPath, $"{project.Name}.pdb");
TryAddOutputFile(packageBuilder, context, outputPath, $"{project.Name}.mdb");
TryAddOutputFile(packageBuilder, context, outputPath, $"{project.Name}.xml");
Reporter.Verbose.WriteLine("");
}
var rootOutputPath = GetOutputPath(project, configuration, outputValue);
var packageOutputPath = GetPackagePath(project, rootOutputPath);
if (GeneratePackage(project, packageBuilder, packageOutputPath, packDiagnostics))
{
return true;
}
return false;
}
private static bool GeneratePackage(Project project, PackageBuilder packageBuilder, string nupkg, List<DiagnosticMessage> packDiagnostics)
{
foreach (var sharedFile in project.Files.SharedFiles)
{
var file = new PhysicalPackageFile();
file.SourcePath = sharedFile;
file.TargetPath = Path.Combine("shared", Path.GetFileName(sharedFile));
packageBuilder.Files.Add(file);
}
var root = project.ProjectDirectory;
if (project.Files.PackInclude != null && project.Files.PackInclude.Any())
{
AddPackageFiles(project, project.Files.PackInclude, packageBuilder, packDiagnostics);
}
// Write the packages as long as we're still in a success state.
if (!packDiagnostics.Any(d => d.Severity == DiagnosticMessageSeverity.Error))
{
Reporter.Verbose.WriteLine($"Adding package files");
foreach (var file in packageBuilder.Files.OfType<PhysicalPackageFile>())
{
if (file.SourcePath != null && File.Exists(file.SourcePath))
{
Reporter.Verbose.WriteLine($"Adding {file.Path.Yellow()}");
}
}
Directory.CreateDirectory(Path.GetDirectoryName(nupkg));
using (var fs = File.Create(nupkg))
{
packageBuilder.Save(fs);
Reporter.Output.WriteLine($"{project.Name} -> {Path.GetFullPath(nupkg)}");
}
return true;
}
return false;
}
private static void AddPackageFiles(Project project, IEnumerable<PackIncludeEntry> packageFiles, PackageBuilder packageBuilder, IList<DiagnosticMessage> diagnostics)
{
var rootDirectory = new DirectoryInfoWrapper(new DirectoryInfo(project.ProjectDirectory));
foreach (var match in CollectAdditionalFiles(rootDirectory, packageFiles, project.ProjectFilePath, diagnostics))
{
packageBuilder.Files.Add(match);
}
}
internal static IEnumerable<PhysicalPackageFile> CollectAdditionalFiles(DirectoryInfoBase rootDirectory, IEnumerable<PackIncludeEntry> projectFileGlobs, string projectFilePath, IList<DiagnosticMessage> diagnostics)
{
foreach (var entry in projectFileGlobs)
{
// Evaluate the globs on the right
var matcher = new Matcher();
matcher.AddIncludePatterns(entry.SourceGlobs);
var results = matcher.Execute(rootDirectory);
var files = results.Files.ToList();
// Check for illegal characters
if (string.IsNullOrEmpty(entry.Target))
{
diagnostics.Add(new DiagnosticMessage(
ErrorCodes.NU1003,
$"Invalid '{ProjectFilesCollection.PackIncludePropertyName}' section. The target '{entry.Target}' is invalid, " +
"targets must either be a file name or a directory suffixed with '/'. " +
"The root directory of the package can be specified by using a single '/' character.",
projectFilePath,
DiagnosticMessageSeverity.Error,
entry.Line,
entry.Column));
continue;
}
if (entry.Target.Split('/').Any(s => s.Equals(".") || s.Equals("..")))
{
diagnostics.Add(new DiagnosticMessage(
ErrorCodes.NU1004,
$"Invalid '{ProjectFilesCollection.PackIncludePropertyName}' section. " +
$"The target '{entry.Target}' contains path-traversal characters ('.' or '..'). " +
"These characters are not permitted in target paths.",
projectFilePath,
DiagnosticMessageSeverity.Error,
entry.Line,
entry.Column));
continue;
}
// Check the arity of the left
if (entry.Target.EndsWith("/"))
{
var dir = entry.Target.Substring(0, entry.Target.Length - 1).Replace('/', Path.DirectorySeparatorChar);
foreach (var file in files)
{
yield return new PhysicalPackageFile()
{
SourcePath = Path.Combine(rootDirectory.FullName, PathUtility.GetPathWithDirectorySeparator(file.Path)),
TargetPath = Path.Combine(dir, PathUtility.GetPathWithDirectorySeparator(file.Stem))
};
}
}
else
{
// It's a file. If the glob matched multiple things, we're sad :(
if (files.Count > 1)
{
// Arity mismatch!
string sourceValue = entry.SourceGlobs.Length == 1 ?
$"\"{entry.SourceGlobs[0]}\"" :
("[" + string.Join(",", entry.SourceGlobs.Select(v => $"\"{v}\"")) + "]");
diagnostics.Add(new DiagnosticMessage(
ErrorCodes.NU1005,
$"Invalid '{ProjectFilesCollection.PackIncludePropertyName}' section. " +
$"The target '{entry.Target}' refers to a single file, but the pattern {sourceValue} " +
"produces multiple files. To mark the target as a directory, suffix it with '/'.",
projectFilePath,
DiagnosticMessageSeverity.Error,
entry.Line,
entry.Column));
}
else
{
yield return new PhysicalPackageFile()
{
SourcePath = Path.Combine(rootDirectory.FullName, files[0].Path),
TargetPath = PathUtility.GetPathWithDirectorySeparator(entry.Target)
};
}
}
}
}
private static void TryAddOutputFile(PackageBuilder packageBuilder,
ProjectContext context,
string outputPath,
string filePath)
{
var targetPath = Path.Combine("lib", context.TargetFramework.GetTwoDigitShortFolderName(), Path.GetFileName(filePath));
var sourcePath = Path.Combine(outputPath, filePath);
if (!File.Exists(sourcePath))
{
return;
}
packageBuilder.Files.Add(new PhysicalPackageFile
{
SourcePath = sourcePath,
TargetPath = targetPath
});
}
public static void PopulateDependencies(ProjectContext context, PackageBuilder packageBuilder)
{
var dependencies = new List<PackageDependency>();
var project = context.RootProject;
foreach (var dependency in project.Dependencies)
{
if (!dependency.HasFlag(LibraryDependencyTypeFlag.BecomesNupkgDependency))
{
continue;
}
// TODO: Efficiency
var dependencyDescription = context.LibraryManager.GetLibraries().First(l => l.RequestedRanges.Contains(dependency));
// REVIEW: Can we get this far with unresolved dependencies
if (dependencyDescription == null || !dependencyDescription.Resolved)
{
continue;
}
if (dependencyDescription.Identity.Type == LibraryType.Project &&
((ProjectDescription)dependencyDescription).Project.EmbedInteropTypes)
{
continue;
}
if (dependency.Target == LibraryType.ReferenceAssembly)
{
packageBuilder.FrameworkAssemblies.Add(new FrameworkAssemblyReference(dependency.Name, new[] { context.TargetFramework }));
Reporter.Verbose.WriteLine($"Adding framework assembly {dependency.Name.Yellow()}");
}
else
{
VersionRange dependencyVersion = null;
if (dependency.VersionRange == null ||
dependency.VersionRange.IsFloating)
{
dependencyVersion = new VersionRange(dependencyDescription.Identity.Version);
}
else
{
dependencyVersion = dependency.VersionRange;
}
Reporter.Verbose.WriteLine($"Adding dependency {dependency.Name.Yellow()} {VersionUtility.RenderVersion(dependencyVersion).Yellow()}");
dependencies.Add(new PackageDependency(dependency.Name, dependencyVersion));
}
}
packageBuilder.DependencySets.Add(new PackageDependencySet(context.TargetFramework, dependencies));
}
private static string GetPackagePath(Project project, string outputPath, bool symbols = false)
{
string fileName = $"{project.Name}.{project.Version}{(symbols ? ".symbols" : string.Empty)}{NuGet.Constants.PackageExtension}";
return Path.Combine(outputPath, fileName);
}
private static PackageBuilder CreatePackageBuilder(Project project)
{
var builder = new PackageBuilder();
builder.Authors.AddRange(project.Authors);
builder.Owners.AddRange(project.Owners);
if (builder.Authors.Count == 0)
{
var defaultAuthor = Environment.GetEnvironmentVariable("NUGET_AUTHOR");
if (string.IsNullOrEmpty(defaultAuthor))
{
builder.Authors.Add(project.Name);
}
else
{
builder.Authors.Add(defaultAuthor);
}
}
builder.Description = project.Description ?? project.Name;
builder.Id = project.Name;
builder.Version = project.Version;
builder.Title = project.Title;
builder.Summary = project.Summary;
builder.Copyright = project.Copyright;
builder.RequireLicenseAcceptance = project.RequireLicenseAcceptance;
builder.ReleaseNotes = project.ReleaseNotes;
builder.Language = project.Language;
builder.Tags.AddRange(project.Tags);
if (!string.IsNullOrEmpty(project.IconUrl))
{
builder.IconUrl = new Uri(project.IconUrl);
}
if (!string.IsNullOrEmpty(project.ProjectUrl))
{
builder.ProjectUrl = new Uri(project.ProjectUrl);
}
if (!string.IsNullOrEmpty(project.LicenseUrl))
{
builder.LicenseUrl = new Uri(project.LicenseUrl);
}
return builder;
}
// REVIEW: This code copying kinda sucks
private static string GetProjectOutputName(Project project, NuGetFramework framework, string configuration)
{
var compilationOptions = project.GetCompilerOptions(framework, configuration);
var outputExtension = ".dll";
if (framework.IsDesktop() && compilationOptions.EmitEntryPoint.GetValueOrDefault())
{
outputExtension = ".exe";
}
return project.Name + outputExtension;
}
private static string GetOutputPath(Project project, string configuration, string outputOptionValue)
{
var outputPath = string.Empty;
if (string.IsNullOrEmpty(outputOptionValue))
{
outputPath = Path.Combine(
GetDefaultRootOutputPath(project, outputOptionValue),
Cli.Utils.Constants.BinDirectoryName,
configuration);
}
else
{
outputPath = outputOptionValue;
}
return outputPath;
}
private static string GetOutputPath(ProjectContext context, string configuration, string outputOptionValue)
{
var outputPath = string.Empty;
if (string.IsNullOrEmpty(outputOptionValue))
{
outputPath = Path.Combine(
GetDefaultRootOutputPath(context.ProjectFile, outputOptionValue),
Cli.Utils.Constants.BinDirectoryName,
configuration,
context.TargetFramework.GetTwoDigitShortFolderName());
}
else
{
outputPath = outputOptionValue;
}
return outputPath;
}
private static string GetDefaultRootOutputPath(Project project, string outputOptionValue)
{
string rootOutputPath = string.Empty;
if (string.IsNullOrEmpty(outputOptionValue))
{
rootOutputPath = project.ProjectDirectory;
}
return rootOutputPath;
}
}
}

View file

@ -0,0 +1,31 @@
{
"name": "dotnet-pack",
"version": "1.0.0-*",
"compilationOptions": {
"emitEntryPoint": true
},
"dependencies": {
"Microsoft.NETCore.Runtime": "1.0.1-beta-23504",
"System.IO.Compression.ZipFile": "4.0.1-beta-23504",
"Microsoft.NETCore.Targets.DNXCore": "5.0.0-beta-23511",
"System.Console": "4.0.0-beta-23504",
"System.Collections": "4.0.11-beta-23504",
"System.Linq": "4.0.1-beta-23504",
"System.Diagnostics.Process": "4.1.0-beta-23504",
"System.IO.FileSystem": "4.0.1-beta-23504",
"Microsoft.DotNet.ProjectModel": "1.0.0-*",
"Microsoft.DotNet.Cli.Utils": {
"type": "build",
"version": "1.0.0-*"
},
"Microsoft.Extensions.CommandLineUtils.Sources": {
"type": "build",
"version": "1.0.0-*"
}
},
"frameworks": {
"dnxcore50": { }
}
}