├── nue.png
├── Nue
├── Nue.Core
│ ├── IResolver.cs
│ ├── TfmAtom.cs
│ ├── IPackageResolver.cs
│ ├── Nue.Core.csproj
│ ├── RunSettings.cs
│ ├── PackageInformation.cs
│ ├── PackageAtom.cs
│ └── Helpers.cs
├── Nue.StandardResolver
│ ├── packages.config
│ ├── app.config
│ ├── custom.nuget.config
│ ├── Properties
│ │ └── AssemblyInfo.cs
│ ├── PackageDownloder.cs
│ ├── Nue.StandardResolver.csproj
│ └── Resolver.cs
├── Nue
│ ├── Core
│ │ ├── DualOutput.cs
│ │ └── Extractor.cs
│ ├── Models
│ │ └── CommandLineOptions.cs
│ ├── packages.config
│ ├── Properties
│ │ └── AssemblyInfo.cs
│ ├── Program.cs
│ ├── App.config
│ └── Nue.csproj
└── Nue.sln
├── packagedefs
├── devices.csv
└── azuresdkfornet.csv
├── LICENSE
├── README.md
└── .gitignore
/nue.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/docascode/nue/HEAD/nue.png
--------------------------------------------------------------------------------
/Nue/Nue.Core/IResolver.cs:
--------------------------------------------------------------------------------
1 | namespace Nue.Core
2 | {
3 | public interface IResolver
4 | {
5 | }
6 | }
--------------------------------------------------------------------------------
/packagedefs/devices.csv:
--------------------------------------------------------------------------------
1 | xboxlive,[resolver=xbl;target=x64;ide=v140;build=release]Microsoft.Xbox.Live.SDK.WinRT.UWP,2017.5.20170517.1
--------------------------------------------------------------------------------
/Nue/Nue.Core/TfmAtom.cs:
--------------------------------------------------------------------------------
1 | namespace Nue.Core
2 | {
3 | public class TfmAtom
4 | {
5 | public string Moniker { get; set; }
6 | public string Target { get; set; }
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/Nue/Nue.StandardResolver/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/Nue/Nue.Core/IPackageResolver.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Threading.Tasks;
3 |
4 | namespace Nue.Core
5 | {
6 | public interface IPackageResolver
7 | {
8 | // will merge the current package information mapping into pkgInfoMap
9 | bool CopyBinarySet(PackageAtom package, RunSettings runSettings, PackageInfomarionMapping pkgInfoMap, AssemblyMappingPackageInformation pkgInfoMapofdepAssembly, string outputPrefix = "");
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/Nue/Nue.StandardResolver/app.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/Nue/Nue.StandardResolver/custom.nuget.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/Nue/Nue.Core/Nue.Core.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard1.6
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/packagedefs/azuresdkfornet.csv:
--------------------------------------------------------------------------------
1 | uwp-aspnetcore-app-ref,[excludedDlls=Microsoft.Win32.Registry.dll|System.Diagnostics.EventLog*|System.IO.Pipelines*|System.Security*|System.Windows.Extensions.dll]Microsoft.AspNetCore.App.Ref,3.0.0
2 | uwp-toolkit,[altDep=netstandard1.4|netstandard1.6]Microsoft.Toolkit.Uwp,2.0.0
3 | uwp-toolkit-notif,Microsoft.Toolkit.Uwp.Notifications
4 | uwp-toolkit-ui,Microsoft.Toolkit.Uwp.UI,2.0.0
5 | uwp-toolkit-ui-animations,Microsoft.Toolkit.Uwp.UI.Animations,2.0.0
6 | uwp-toolkit-ui-controls,Microsoft.Toolkit.Uwp.UI.Controls,2.0.0
7 | uwp-toolkit-notif-js,Microsoft.Toolkit.Uwp.Notifications.JavaScript,2.0.0
8 | uwp-toolkit-devtools,Microsoft.Toolkit.Uwp.DeveloperTools,2.0.0
--------------------------------------------------------------------------------
/Nue/Nue.Core/RunSettings.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace Nue.Core
6 | {
7 | public class RunSettings
8 | {
9 | public const string NUGET_DEFAULT_FEED = "https://api.nuget.org/v3/index.json";
10 |
11 | public readonly string TFM;
12 |
13 | public readonly string Feed;
14 |
15 | public readonly string NugetPath;
16 |
17 | public readonly string OutputPath;
18 |
19 | public RunSettings(string tfm, string feed, string nugetPath, string outputPath)
20 | {
21 | feed = feed?.Trim('\"');
22 | Feed = string.IsNullOrEmpty(feed) ? NUGET_DEFAULT_FEED : feed;
23 |
24 | TFM = tfm;
25 | NugetPath = nugetPath;
26 | OutputPath = outputPath;
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/Nue/Nue/Core/DualOutput.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 | using System.Text;
4 |
5 | namespace Nue.Core
6 | {
7 | public static class DualOutput
8 | {
9 | private static TextWriter _current;
10 |
11 | private class OutputWriter : TextWriter
12 | {
13 | static object locker = new object();
14 | public override Encoding Encoding
15 | {
16 | get
17 | {
18 | return _current.Encoding;
19 | }
20 | }
21 |
22 | public override void WriteLine(string value)
23 | {
24 | _current.WriteLine(value);
25 |
26 | lock (locker)
27 | {
28 | File.AppendAllText("nue-execution-log.txt", value);
29 | }
30 | }
31 | }
32 |
33 | public static void Initialize()
34 | {
35 | _current = Console.Out;
36 | Console.SetOut(new OutputWriter());
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 Den Delimarsky
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/Nue/Nue.Core/PackageInformation.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 |
6 | namespace Nue.Core
7 | {
8 | public class PackageInfomarion
9 | {
10 | public string Name { get; set; }
11 |
12 | public string Version { get; set; }
13 |
14 | public string Feed { get; set; }
15 | }
16 |
17 | // moniker1
18 | // |__ assembly1 => package1
19 | // |__ assembly2 => package2
20 | public class PackageInfomarionMapping : Dictionary>
21 | {
22 | public PackageInfomarionMapping ToFlatten(string newMoniker)
23 | {
24 | var result = new PackageInfomarionMapping();
25 | result[newMoniker] = new Dictionary();
26 |
27 | foreach (var moniker in this.Keys)
28 | {
29 | foreach (var mapping in this[moniker])
30 | {
31 | result[newMoniker][mapping.Key] = mapping.Value;
32 | }
33 | }
34 |
35 | return result;
36 | }
37 | }
38 |
39 | public class AssemblyMappingPackageInformation : Dictionary>
40 | {
41 |
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/Nue/Nue/Models/CommandLineOptions.cs:
--------------------------------------------------------------------------------
1 | using CommandLine;
2 |
3 | namespace Nue.Models
4 | {
5 | internal class CommandLineOptions
6 | {
7 | [Option('p', "packages", Required = false, HelpText = "Path to CSV with packages.")]
8 | public string PackagePath { get; set; }
9 |
10 | [Option('o', "output", Required = false, HelpText = "Determines where to output the binaries and their dependencies.")]
11 | public string OutputPath { get; set; }
12 |
13 | [Option('f', "framework", Required = false, HelpText = "Determines the framework for which to get the binaries.", Default = "net471")]
14 | public string Framework { get; set; }
15 |
16 | [Option('n', "nugetpath", Required = false, HelpText = "Path to folder containing NuGet.exe.")]
17 | public string NuGetPath { get; set; }
18 |
19 | [Option('P', "password", Required = false, HelpText = "Password for the feed to be used.")]
20 | public string Password { get; set; }
21 |
22 | [Option('U', "username", Required = false, HelpText = "Username for the feed to be used.")]
23 | public string Username { get; set; }
24 |
25 | [Option('F', "feed", Required = false, HelpText = "Custom feed to use with to download NuGet packages.")]
26 | public string Feed { get; set; }
27 |
28 | [Option('m', "moniker", Required = false, HelpText = "Record all package information in a single moniker")]
29 | public string Moniker { get; set; }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/Nue/Nue/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/Nue/Nue/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("Nue")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("Nue")]
13 | [assembly: AssemblyCopyright("Copyright © 2017")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("68cc99c6-1dbe-4459-ba94-742e9ff7bc86")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/Nue/Nue.StandardResolver/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("Nue.StandardResolver")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("Nue.StandardResolver")]
13 | [assembly: AssemblyCopyright("Copyright © 2017")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("c8046141-6e78-44b8-bad8-d83a19e8e77b")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/Nue/Nue/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Diagnostics;
3 | using System.IO;
4 | using CommandLine;
5 | using Newtonsoft.Json;
6 | using Nue.Core;
7 | using Nue.Models;
8 |
9 | namespace Nue
10 | {
11 | internal class Program
12 | {
13 | private static void Main(string[] args)
14 | {
15 | Stopwatch stopwatch = new Stopwatch();
16 | stopwatch.Start();
17 |
18 | DualOutput.Initialize();
19 |
20 | Console.WriteLine("[info] nue 2.0.0-9272018.1817");
21 |
22 | Parser.Default.ParseArguments(args).WithParsed(options =>
23 | {
24 | Console.WriteLine("[info] Declared NuGet path: " + options.NuGetPath);
25 |
26 | RunSettings runSettings = new RunSettings(options.Framework, options.Feed, options.NuGetPath, options.OutputPath);
27 | var completed = Extractor.DownloadPackages(options.PackagePath, runSettings, out var pkgInfoMap);
28 |
29 | // Write package information
30 | var moniker = Path.GetFileNameWithoutExtension(options.PackagePath);
31 | if (!string.IsNullOrEmpty(options.Moniker))
32 | {
33 | pkgInfoMap = pkgInfoMap.ToFlatten(options.Moniker);
34 | moniker = options.Moniker;
35 | }
36 | var jsonString = JsonConvert.SerializeObject(pkgInfoMap);
37 | Directory.CreateDirectory(Path.Combine(options.OutputPath, "PackageInformation"));
38 | File.WriteAllText(Path.Combine(options.OutputPath, "PackageInformation", $"{moniker}.json"), jsonString);
39 |
40 | Console.WriteLine("[info] Completed successfully: " + completed);
41 | });
42 |
43 | stopwatch.Stop();
44 | Console.WriteLine($"[info] Completed extraction in {stopwatch.Elapsed.TotalMinutes} minutes");
45 | Debug.WriteLine($"[info] Completed extraction in {stopwatch.Elapsed.TotalMinutes} minutes");
46 | }
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/Nue/Nue.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 15
4 | VisualStudioVersion = 15.0.26730.3
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nue", "Nue\Nue.csproj", "{68CC99C6-1DBE-4459-BA94-742E9FF7BC86}"
7 | EndProject
8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Nue.Core", "Nue.Core\Nue.Core.csproj", "{6D7568AE-C944-4C70-8DA6-54F983689972}"
9 | EndProject
10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nue.StandardResolver", "Nue.StandardResolver\Nue.StandardResolver.csproj", "{C8046141-6E78-44B8-BAD8-D83A19E8E77B}"
11 | EndProject
12 | Global
13 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
14 | Debug|Any CPU = Debug|Any CPU
15 | Release|Any CPU = Release|Any CPU
16 | EndGlobalSection
17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
18 | {68CC99C6-1DBE-4459-BA94-742E9FF7BC86}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
19 | {68CC99C6-1DBE-4459-BA94-742E9FF7BC86}.Debug|Any CPU.Build.0 = Debug|Any CPU
20 | {68CC99C6-1DBE-4459-BA94-742E9FF7BC86}.Release|Any CPU.ActiveCfg = Release|Any CPU
21 | {68CC99C6-1DBE-4459-BA94-742E9FF7BC86}.Release|Any CPU.Build.0 = Release|Any CPU
22 | {6D7568AE-C944-4C70-8DA6-54F983689972}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
23 | {6D7568AE-C944-4C70-8DA6-54F983689972}.Debug|Any CPU.Build.0 = Debug|Any CPU
24 | {6D7568AE-C944-4C70-8DA6-54F983689972}.Release|Any CPU.ActiveCfg = Release|Any CPU
25 | {6D7568AE-C944-4C70-8DA6-54F983689972}.Release|Any CPU.Build.0 = Release|Any CPU
26 | {C8046141-6E78-44B8-BAD8-D83A19E8E77B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
27 | {C8046141-6E78-44B8-BAD8-D83A19E8E77B}.Debug|Any CPU.Build.0 = Debug|Any CPU
28 | {C8046141-6E78-44B8-BAD8-D83A19E8E77B}.Release|Any CPU.ActiveCfg = Release|Any CPU
29 | {C8046141-6E78-44B8-BAD8-D83A19E8E77B}.Release|Any CPU.Build.0 = Release|Any CPU
30 | EndGlobalSection
31 | GlobalSection(SolutionProperties) = preSolution
32 | HideSolutionNode = FALSE
33 | EndGlobalSection
34 | GlobalSection(ExtensibilityGlobals) = postSolution
35 | SolutionGuid = {7DE47469-1C7B-4BA2-8AB6-36AC275727CB}
36 | EndGlobalSection
37 | EndGlobal
38 |
--------------------------------------------------------------------------------
/Nue/Nue.Core/PackageAtom.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Text.RegularExpressions;
5 |
6 | namespace Nue.Core
7 | {
8 | public class PackageAtom
9 | {
10 | [JsonProperty("moniker")]
11 | public string Moniker { get; set; }
12 |
13 | [JsonProperty("id")]
14 | public string Name { get; set; }
15 |
16 | [JsonProperty("versionOption")]
17 | public VersionOption VersionOption { get; set; }
18 |
19 | [JsonProperty("customVersion")]
20 | public string CustomVersion { get; set; }
21 |
22 | [JsonIgnore]
23 | public bool CustomVersionDefined { get => VersionOption == VersionOption.Custom && !string.IsNullOrEmpty(CustomVersion); }
24 |
25 | [JsonProperty("isPrerelease")]
26 | public bool IsPrerelease { get; set; }
27 |
28 | public bool IsPowerShellPackage { get; set; }
29 |
30 | public bool IsDotnetPlatform { get; set; }
31 |
32 | [JsonProperty("customProperties")]
33 | public PackageAdditionalProperties CustomProperties { get; set; }
34 |
35 | public Dictionary CustomPropertyBag { get; set; }
36 |
37 | public string GetFullName()
38 | {
39 | var versionStr = VersionOption == VersionOption.Custom ? CustomVersion : VersionOption.ToString();
40 | if (IsPrerelease)
41 | {
42 | versionStr += " -Prerelease";
43 | }
44 | return $"{Name} [Version {versionStr}]";
45 | }
46 | }
47 |
48 | public class PackageAdditionalProperties
49 | {
50 | [JsonProperty("feed")]
51 | public string CustomFeed { get; set; }
52 |
53 | [JsonProperty("libFolder")]
54 | public string CustomLibraryFolder { get; set; }
55 |
56 | [JsonProperty("depFolder")]
57 | public string CustomDependencyFolder { get; set; }
58 |
59 | [JsonProperty("tfm")]
60 | public string TFM { get; set; }
61 |
62 | [JsonProperty("excludedDlls")]
63 | public List ExcludedDlls { get; set; }
64 | }
65 |
66 | public enum VersionOption
67 | {
68 | Latest,
69 | Custom
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/Nue/Nue/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # 📦 nue - the NuGet Package Extractor
2 |
3 | 
4 |
5 | `nue` is a tool developed to extract NuGet packages into a folder structure that is compatible with the [docs.microsoft.com](https://docs.microsoft.com) .NET API documentation infrastructure.
6 |
7 | It accepts a `*.csv` file as a source, and then relies on `nuget.exe` to install individual packages and collect their dependencies.
8 |
9 | 
10 |
11 | ## To run
12 |
13 | The core executable is `nue.exe`. It accepts the following parameters:
14 |
15 | * `-p` or `--packages` - Path to package listing CSV file. See the structure for the file below.
16 | * `-o` or `--output` - Output path. It's acceptable if the folder does not yet exist, as _nue_ will create one for you.
17 | * `-f` or `--frameworks` - Framework for which to extract the packages. Use the [TFMs](https://docs.microsoft.com/en-us/nuget/schema/target-frameworks) reference to target folders in the `lib` folder of the main package.
18 | * `-n` or `--nugetpath` - Path to `nuget.exe` when working in `le` (local extraction) mode. This can be downloaded on the [official NuGet page](https://www.nuget.org/downloads).
19 |
20 | ### Input CSV structure
21 |
22 | When working with a list of packages, generally you need to follow the structure:
23 |
24 | ```text
25 | {package_moniker_base},{package_ID},{version}
26 | {package_moniker_base},{package_ID}
27 | {package_moniker_base},{package_ID},{version}
28 | ```
29 |
30 | The moniker will be assembled by combining the `{package_moniker_base}` and `{version}`, in this form: `{package_moniker}-{version}`, where `{version}` is available. When the `{version}` value is not specified, the `{package_moniker_base}` will become the moniker.
31 |
32 | ### Behavior
33 |
34 | * When in the CSV, a version is specified after a package ID, that specific version will be installed and subsequently - processed.
35 | * If no version is specified after the package ID, the latest available version for the package will be installed (_can be either stable or pre-release, depending on configuration_).
36 |
37 | ### Custom package configuration
38 |
39 | In some cases, you might need to create custom package onboarding scenarios. To handle those, we are enabling custom parameters, that can be included before the package ID, in square brackets, as such:
40 |
41 | ```text
42 | {package_moniker},[custom_parameter=value]{package_ID}
43 | ```
44 |
45 | The following custom parameters are supported:
46 |
47 | | Parameter | Description |
48 | |:----------|:------------|
49 | | `customSource` | URL to a custom feed for the package. |
50 | | `tfm` | Overrides the global TFM for the specific package. |
51 | | `altDep` | Alternative dependency TFM - helpful when you have a specific TFM for the core library, but a different TFM for dependency libraries. |
52 | | `isPrerelease` | Required to install a pre-release package. |
53 | | `customDependencyFolder` | A custom folder from which we need to pull dependencies. Relative to the package root. |
--------------------------------------------------------------------------------
/Nue/Nue.StandardResolver/PackageDownloder.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 | using System.IO.Compression;
4 | using System.Net;
5 |
6 | namespace Nue.StandardResolver
7 | {
8 | public class PackageDownloder
9 | {
10 | private string rootUrl = "http://nuget.org/api/v2/package/";
11 | private string outPutPath;
12 | private string fileName;
13 | private string packageId;
14 | private string version;
15 | private bool overwrite;
16 | public string Url
17 | {
18 | get
19 | {
20 | var url = CombineUriToString(rootUrl, packageId);
21 | if (!string.IsNullOrEmpty(version))
22 | {
23 | url = $"{url}/{version}";
24 | }
25 |
26 | return url;
27 | }
28 | }
29 |
30 | public PackageDownloder(string outPutPath, string packageId, string version, bool overwrite = false)
31 | {
32 | this.outPutPath = outPutPath;
33 | this.packageId = packageId;
34 | this.overwrite = overwrite;
35 | this.version = version;
36 | }
37 |
38 | public void DownloadPackage()
39 | {
40 | if (string.IsNullOrEmpty(outPutPath))
41 | {
42 | Console.WriteLine($"[error] outPutPath cannot be empty"); return;
43 | }
44 |
45 | if (string.IsNullOrEmpty(packageId))
46 | {
47 | Console.WriteLine($"[error] packageId cannot be empty"); return;
48 | }
49 |
50 | if (!Directory.Exists(outPutPath))
51 | {
52 | Directory.CreateDirectory(outPutPath);
53 | }
54 |
55 | var request = WebRequest.Create(Url) as HttpWebRequest;
56 | var response = request.GetResponse() as HttpWebResponse;
57 | fileName = response.Headers["Content-Disposition"];
58 | if (string.IsNullOrEmpty(fileName))
59 | {
60 | fileName = response.ResponseUri.Segments[response.ResponseUri.Segments.Length - 1];
61 | }
62 | else
63 | {
64 | fileName = fileName.Remove(0, fileName.IndexOf("filename=") + 9);
65 | }
66 |
67 | using (var responseStream = response.GetResponseStream())
68 | {
69 | long totalLength = response.ContentLength;
70 | using (var stream = new FileStream(Path.Combine(outPutPath, fileName), overwrite ? FileMode.Create : FileMode.CreateNew))
71 | {
72 | byte[] bArr = new byte[1024];
73 | int size;
74 | while ((size = responseStream.Read(bArr, 0, bArr.Length)) > 0)
75 | {
76 | stream.Write(bArr, 0, size);
77 | }
78 | }
79 | }
80 | }
81 |
82 | public void Unzip()
83 | {
84 | ModifyFileNameExtension();
85 | var sourceFileName = Path.Combine(outPutPath, fileName);
86 | var zipPath = Path.Combine(outPutPath, $"{Path.GetFileNameWithoutExtension(sourceFileName)}");
87 | if (!Directory.Exists(zipPath))
88 | {
89 | Directory.CreateDirectory(zipPath);
90 | }
91 |
92 | ZipFile.ExtractToDirectory(fileName, zipPath);
93 | }
94 |
95 | private void ModifyFileNameExtension()
96 | {
97 | var sourceFileName = Path.Combine(outPutPath, fileName);
98 | var destFileName = Path.Combine(outPutPath, $"{Path.GetFileNameWithoutExtension(sourceFileName)}.zip");
99 | File.Move(sourceFileName, destFileName);
100 | fileName = destFileName;
101 | }
102 |
103 | private string CombineUriToString(string baseUri, string relativeOrAbsoluteUri)
104 | {
105 | return new Uri(new Uri(baseUri), relativeOrAbsoluteUri).ToString();
106 | }
107 | }
108 | }
109 |
--------------------------------------------------------------------------------
/Nue/Nue.StandardResolver/Nue.StandardResolver.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {C8046141-6E78-44B8-BAD8-D83A19E8E77B}
8 | Library
9 | Properties
10 | Nue.StandardResolver
11 | Nue.StandardResolver
12 | v4.6.1
13 | 512
14 |
15 |
16 |
17 | true
18 | full
19 | false
20 | bin\Debug\
21 | DEBUG;TRACE
22 | prompt
23 | 4
24 |
25 |
26 | pdbonly
27 | true
28 | bin\Release\
29 | TRACE
30 | prompt
31 | 4
32 |
33 |
34 |
35 |
36 | ..\packages\Newtonsoft.Json.11.0.2\lib\net45\Newtonsoft.Json.dll
37 |
38 |
39 |
40 |
41 | True
42 |
43 |
44 |
45 |
46 |
47 |
48 | ..\packages\System.IO.Compression.ZipFile.4.3.0\lib\net46\System.IO.Compression.ZipFile.dll
49 | True
50 | True
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 | {6d7568ae-c944-4c70-8da6-54f983689972}
70 | Nue.Core
71 |
72 |
73 |
74 |
75 |
76 | Always
77 |
78 |
79 | Designer
80 |
81 |
82 |
83 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 |
4 | # User-specific files
5 | *.suo
6 | *.user
7 | *.userosscache
8 | *.sln.docstates
9 |
10 | # User-specific files (MonoDevelop/Xamarin Studio)
11 | *.userprefs
12 |
13 | # Build results
14 | [Dd]ebug/
15 | [Dd]ebugPublic/
16 | [Rr]elease/
17 | [Rr]eleases/
18 | x64/
19 | x86/
20 | bld/
21 | [Bb]in/
22 | [Oo]bj/
23 | [Ll]og/
24 |
25 | # Visual Studio 2015 cache/options directory
26 | .vs/
27 | # Uncomment if you have tasks that create the project's static files in wwwroot
28 | #wwwroot/
29 |
30 | # MSTest test Results
31 | [Tt]est[Rr]esult*/
32 | [Bb]uild[Ll]og.*
33 |
34 | # NUNIT
35 | *.VisualState.xml
36 | TestResult.xml
37 |
38 | # Build Results of an ATL Project
39 | [Dd]ebugPS/
40 | [Rr]eleasePS/
41 | dlldata.c
42 |
43 | # DNX
44 | project.lock.json
45 | artifacts/
46 |
47 | *_i.c
48 | *_p.c
49 | *_i.h
50 | *.ilk
51 | *.meta
52 | *.obj
53 | *.pch
54 | *.pdb
55 | *.pgc
56 | *.pgd
57 | *.rsp
58 | *.sbr
59 | *.tlb
60 | *.tli
61 | *.tlh
62 | *.tmp
63 | *.tmp_proj
64 | *.log
65 | *.vspscc
66 | *.vssscc
67 | .builds
68 | *.pidb
69 | *.svclog
70 | *.scc
71 |
72 | # Chutzpah Test files
73 | _Chutzpah*
74 |
75 | # Visual C++ cache files
76 | ipch/
77 | *.aps
78 | *.ncb
79 | *.opendb
80 | *.opensdf
81 | *.sdf
82 | *.cachefile
83 | *.VC.db
84 | *.VC.VC.opendb
85 |
86 | # Visual Studio profiler
87 | *.psess
88 | *.vsp
89 | *.vspx
90 | *.sap
91 |
92 | # TFS 2012 Local Workspace
93 | $tf/
94 |
95 | # Guidance Automation Toolkit
96 | *.gpState
97 |
98 | # ReSharper is a .NET coding add-in
99 | _ReSharper*/
100 | *.[Rr]e[Ss]harper
101 | *.DotSettings.user
102 |
103 | # JustCode is a .NET coding add-in
104 | .JustCode
105 |
106 | # TeamCity is a build add-in
107 | _TeamCity*
108 |
109 | # DotCover is a Code Coverage Tool
110 | *.dotCover
111 |
112 | # NCrunch
113 | _NCrunch_*
114 | .*crunch*.local.xml
115 | nCrunchTemp_*
116 |
117 | # MightyMoose
118 | *.mm.*
119 | AutoTest.Net/
120 |
121 | # Web workbench (sass)
122 | .sass-cache/
123 |
124 | # Installshield output folder
125 | [Ee]xpress/
126 |
127 | # DocProject is a documentation generator add-in
128 | DocProject/buildhelp/
129 | DocProject/Help/*.HxT
130 | DocProject/Help/*.HxC
131 | DocProject/Help/*.hhc
132 | DocProject/Help/*.hhk
133 | DocProject/Help/*.hhp
134 | DocProject/Help/Html2
135 | DocProject/Help/html
136 |
137 | # Click-Once directory
138 | publish/
139 |
140 | # Publish Web Output
141 | *.[Pp]ublish.xml
142 | *.azurePubxml
143 | # TODO: Comment the next line if you want to checkin your web deploy settings
144 | # but database connection strings (with potential passwords) will be unencrypted
145 | *.pubxml
146 | *.publishproj
147 |
148 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
149 | # checkin your Azure Web App publish settings, but sensitive information contained
150 | # in these scripts will be unencrypted
151 | PublishScripts/
152 |
153 | # NuGet Packages
154 | *.nupkg
155 | # The packages folder can be ignored because of Package Restore
156 | **/packages/*
157 | # except build/, which is used as an MSBuild target.
158 | !**/packages/build/
159 | # Uncomment if necessary however generally it will be regenerated when needed
160 | #!**/packages/repositories.config
161 | # NuGet v3's project.json files produces more ignoreable files
162 | *.nuget.props
163 | *.nuget.targets
164 |
165 | # Microsoft Azure Build Output
166 | csx/
167 | *.build.csdef
168 |
169 | # Microsoft Azure Emulator
170 | ecf/
171 | rcf/
172 |
173 | # Windows Store app package directories and files
174 | AppPackages/
175 | BundleArtifacts/
176 | Package.StoreAssociation.xml
177 | _pkginfo.txt
178 |
179 | # Visual Studio cache files
180 | # files ending in .cache can be ignored
181 | *.[Cc]ache
182 | # but keep track of directories ending in .cache
183 | !*.[Cc]ache/
184 |
185 | # Others
186 | ClientBin/
187 | ~$*
188 | *~
189 | *.dbmdl
190 | *.dbproj.schemaview
191 | *.pfx
192 | *.publishsettings
193 | node_modules/
194 | orleans.codegen.cs
195 |
196 | # Since there are multiple workflows, uncomment next line to ignore bower_components
197 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
198 | #bower_components/
199 |
200 | # RIA/Silverlight projects
201 | Generated_Code/
202 |
203 | # Backup & report files from converting an old project file
204 | # to a newer Visual Studio version. Backup files are not needed,
205 | # because we have git ;-)
206 | _UpgradeReport_Files/
207 | Backup*/
208 | UpgradeLog*.XML
209 | UpgradeLog*.htm
210 |
211 | # SQL Server files
212 | *.mdf
213 | *.ldf
214 |
215 | # Business Intelligence projects
216 | *.rdl.data
217 | *.bim.layout
218 | *.bim_*.settings
219 |
220 | # Microsoft Fakes
221 | FakesAssemblies/
222 |
223 | # GhostDoc plugin setting file
224 | *.GhostDoc.xml
225 |
226 | # Node.js Tools for Visual Studio
227 | .ntvs_analysis.dat
228 |
229 | # Visual Studio 6 build log
230 | *.plg
231 |
232 | # Visual Studio 6 workspace options file
233 | *.opt
234 |
235 | # Visual Studio LightSwitch build output
236 | **/*.HTMLClient/GeneratedArtifacts
237 | **/*.DesktopClient/GeneratedArtifacts
238 | **/*.DesktopClient/ModelManifest.xml
239 | **/*.Server/GeneratedArtifacts
240 | **/*.Server/ModelManifest.xml
241 | _Pvt_Extensions
242 |
243 | # Paket dependency manager
244 | .paket/paket.exe
245 | paket-files/
246 |
247 | # FAKE - F# Make
248 | .fake/
249 |
250 | # JetBrains Rider
251 | .idea/
252 | *.sln.iml
253 |
--------------------------------------------------------------------------------
/Nue/Nue/Nue.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {68CC99C6-1DBE-4459-BA94-742E9FF7BC86}
8 | Exe
9 | Properties
10 | Nue
11 | Nue
12 | v4.6.1
13 | 512
14 | true
15 |
16 |
17 |
18 |
19 |
20 | AnyCPU
21 | true
22 | full
23 | false
24 | bin\Debug\
25 | DEBUG;TRACE
26 | prompt
27 | 4
28 |
29 |
30 | AnyCPU
31 | pdbonly
32 | true
33 | bin\Release\
34 | TRACE
35 | prompt
36 | 4
37 |
38 |
39 |
40 | ..\packages\CommandLineParser.2.2.1\lib\net45\CommandLine.dll
41 |
42 |
43 |
44 | ..\packages\Newtonsoft.Json.11.0.2\lib\net45\Newtonsoft.Json.dll
45 |
46 |
47 |
48 |
49 |
50 | ..\packages\System.Console.4.3.1\lib\net46\System.Console.dll
51 | True
52 |
53 |
54 |
55 |
56 |
57 | ..\packages\System.Reflection.TypeExtensions.4.4.0\lib\net461\System.Reflection.TypeExtensions.dll
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 | {6d7568ae-c944-4c70-8da6-54f983689972}
82 | Nue.Core
83 |
84 |
85 | {c8046141-6e78-44b8-bad8-d83a19e8e77b}
86 | Nue.StandardResolver
87 |
88 |
89 |
90 |
91 |
92 |
93 | This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.
94 |
95 |
96 |
97 |
104 |
--------------------------------------------------------------------------------
/Nue/Nue/Core/Extractor.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.VisualBasic.FileIO;
2 | using Nue.StandardResolver;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.IO;
6 | using System.Linq;
7 | using System.Text.RegularExpressions;
8 | using System.Threading;
9 | using System.Threading.Tasks;
10 |
11 | namespace Nue.Core
12 | {
13 | public class Extractor
14 | {
15 | public static void PreparePropertyBag(IEnumerable packages)
16 | {
17 | foreach (var package in packages)
18 | {
19 | if (package.CustomPropertyBag ==null)
20 | {
21 | package.CustomPropertyBag = new Dictionary();
22 | }
23 | if (package.CustomProperties == null)
24 | {
25 | package.CustomProperties = new PackageAdditionalProperties();
26 | }
27 |
28 | // Inject the TFM into the resolver if none was specified for the package.
29 | if (package.CustomPropertyBag.TryGetValue("tfm", out string tfmVal))
30 | {
31 | package.CustomProperties.TFM = tfmVal;
32 | }
33 |
34 | // Determines whether a package is a PowerShell package - there is some custom logic that we need
35 | // to apply to determine what the assemblies are there.
36 | if (package.CustomPropertyBag.TryGetValue("ps", out string psVal))
37 | {
38 | package.IsPowerShellPackage = Convert.ToBoolean(psVal);
39 | }
40 |
41 | if (package.CustomPropertyBag.TryGetValue("isPrerelease", out string preReleaseVal))
42 | {
43 | package.IsPrerelease = Convert.ToBoolean(preReleaseVal);
44 | }
45 |
46 | if (package.CustomPropertyBag.TryGetValue("libpath", out string libpathVal))
47 | {
48 | package.CustomProperties.CustomLibraryFolder = libpathVal;
49 | }
50 |
51 | if (package.CustomPropertyBag.TryGetValue("customDependencyFolder", out string depPathVal))
52 | {
53 | package.CustomProperties.CustomDependencyFolder = depPathVal;
54 | }
55 |
56 | if (package.CustomPropertyBag.TryGetValue("customSource", out string feedVal))
57 | {
58 | package.CustomProperties.CustomFeed = feedVal;
59 | }
60 |
61 | if (package.CustomPropertyBag.TryGetValue("excludedDlls", out string excludedDllVal))
62 | {
63 | if (!string.IsNullOrEmpty(excludedDllVal))
64 | {
65 | var excludedDlls = excludedDllVal.Split('|');
66 | package.CustomProperties.ExcludedDlls = excludedDlls.Select(e=>Helpers.WildCardToRegex(e)).ToList();
67 | }
68 | }
69 | }
70 | }
71 |
72 | public static bool DownloadPackages(string packagePath, RunSettings runSettings, out PackageInfomarionMapping pkgInfoMap)
73 | {
74 | pkgInfoMap = new PackageInfomarionMapping();
75 |
76 | if (string.IsNullOrWhiteSpace(packagePath) || string.IsNullOrWhiteSpace(runSettings.OutputPath)) return false;
77 |
78 | var packages = GetPackagesFromFile(packagePath);
79 |
80 | PreparePropertyBag(packages);
81 |
82 | var assemblyPkgInfoMap = new AssemblyMappingPackageInformation();
83 |
84 | foreach (var package in packages)
85 | {
86 | // Package resolver that will be used to get the full path to binaries.
87 | IPackageResolver resolver = new Resolver();
88 |
89 | var currentOutputPrefix = Guid.NewGuid().ToString().Substring(0,5);
90 | var isSuccess = resolver.CopyBinarySet(package, runSettings, pkgInfoMap, assemblyPkgInfoMap, currentOutputPrefix);
91 |
92 | try
93 | {
94 | Console.WriteLine($"[info] Deleting {Path.Combine(runSettings.OutputPath, "_pacman" + currentOutputPrefix)}");
95 | Helpers.DeleteDirectory(Path.Combine(runSettings.OutputPath, "_pacman" + currentOutputPrefix));
96 | }
97 | catch
98 | {
99 | Console.WriteLine("[error] Errored out the first time we tried to delete the folder. Retrying...");
100 |
101 | Thread.Sleep(2000);
102 | Helpers.DeleteDirectory(Path.Combine(runSettings.OutputPath, "_pacman" + currentOutputPrefix));
103 | }
104 | }
105 |
106 | return true;
107 | }
108 |
109 | private static List GetPackagesFromFile(string packagePath)
110 | {
111 | if (packagePath.EndsWith(".csv"))
112 | {
113 | return GetPackagesFromCSVFile(packagePath);
114 | }
115 | else if (packagePath.EndsWith(".json"))
116 | {
117 | return Newtonsoft.Json.JsonConvert.DeserializeObject>(File.ReadAllText(packagePath));
118 | }
119 | Console.WriteLine($"[error] Cannot recognize {packagePath}.");
120 |
121 | return null;
122 | }
123 |
124 | private static List GetPackagesFromCSVFile(string packagePath)
125 | {
126 | var packages = new List();
127 |
128 | using (var parser = new TextFieldParser(packagePath))
129 | {
130 | parser.TextFieldType = FieldType.Delimited;
131 | parser.SetDelimiters(",");
132 |
133 | while (!parser.EndOfData)
134 | {
135 | var fields = parser.ReadFields();
136 |
137 | if (fields == null) continue;
138 |
139 | // Given the conventions, let's find out how many versions are requested to be downloaded.
140 | var pAtom = new PackageAtom();
141 |
142 | if (fields.Length == 2)
143 | {
144 | // There is no version specified.
145 | pAtom.Moniker = fields[0];
146 | pAtom.Name = fields[1];
147 | pAtom.VersionOption = VersionOption.Latest;
148 | }
149 | else if (fields.Length > 2)
150 | {
151 | // There is a version specified.
152 | pAtom.Moniker = fields[0] + "-" + fields[2];
153 | pAtom.Name = fields[1];
154 | pAtom.VersionOption = VersionOption.Custom;
155 | pAtom.CustomVersion = fields[2];
156 | }
157 | else
158 | {
159 | Console.WriteLine("[error] Could not read in package information for " + fields.ToString());
160 | break;
161 | }
162 |
163 | // Property bag will be formatted like:
164 | // [property1=value1;property2=value2]PackageId
165 | var propertyBagRegex = @"(\[.+\])";
166 | Regex formalizedRegEx = new Regex(propertyBagRegex);
167 | var match = formalizedRegEx.Match(pAtom.Name);
168 |
169 | if (match.Success)
170 | {
171 | // There seems to be a property bag attached to the name.
172 | var rawPropertyBag = match.Value.Replace("[", "").Replace("]", "").Trim();
173 | if (!string.IsNullOrWhiteSpace(rawPropertyBag))
174 | {
175 | // Normalize the package name without the property bag.
176 | pAtom.Name = pAtom.Name.Replace(match.Value, "");
177 | pAtom.CustomPropertyBag = new Dictionary();
178 |
179 | // Avoiding the case of empty property bag, looks like in this case we are good.
180 | var properties = rawPropertyBag.Split(new char[] { ';' });
181 | foreach (var property in properties)
182 | {
183 | var splitProperty = property.Split(new char[] { '=' });
184 | pAtom.CustomPropertyBag.Add(splitProperty[0], splitProperty[1]);
185 | }
186 | }
187 | }
188 |
189 | packages.Add(pAtom);
190 | }
191 | }
192 |
193 | return packages;
194 | }
195 | }
196 | }
197 |
--------------------------------------------------------------------------------
/Nue/Nue.Core/Helpers.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Diagnostics;
4 | using System.IO;
5 | using System.Linq;
6 | using System.Text.RegularExpressions;
7 |
8 | namespace Nue.Core
9 | {
10 | public static class Helpers
11 | {
12 | // From: http://stackoverflow.com/a/329502
13 | public static void DeleteDirectory(string target_dir)
14 | {
15 | if (Directory.Exists(target_dir))
16 | {
17 | string[] files = Directory.GetFiles(target_dir);
18 | string[] dirs = Directory.GetDirectories(target_dir);
19 |
20 | foreach (string file in files)
21 | {
22 | File.SetAttributes(file, FileAttributes.Normal);
23 | File.Delete(file);
24 | }
25 |
26 | foreach (string dir in dirs)
27 | {
28 | DeleteDirectory(dir);
29 | }
30 |
31 | Directory.Delete(target_dir, true);
32 | }
33 | }
34 |
35 | // Determines the best folder match for a libary based on the specified target moniker.
36 | public static string GetBestLibMatch(string tfm, string[] folderPaths)
37 | {
38 | var tfmRegex = new Regex(@"(?[a-zA-Z]*)(?[0-9\.0-9]*)");
39 | var match = tfmRegex.Match(tfm);
40 |
41 | var tfmBase = match.Groups["Base"].Value;
42 | var tfmVersion = match.Groups["Version"].Value;
43 | string folder = string.Empty;
44 |
45 | // Look for a folder that matches exactly the TFM.
46 | var exactMatch = (from c in folderPaths
47 | where Path.GetFileName(c).Equals(tfm, StringComparison.CurrentCultureIgnoreCase)
48 | select c).FirstOrDefault();
49 |
50 | // If we found one, we should just return it.
51 | if (exactMatch != null)
52 | return exactMatch;
53 |
54 | // As an example, if the TFM is net45, this should cover everything like:
55 | // net45, net451, net452
56 | var lenientMatch = new Regex($@"^(?(?{tfm})(?[0-9\.0-9]*))$", RegexOptions.IgnoreCase);
57 | folder = GetWinningFolder(folderPaths, lenientMatch);
58 |
59 | if (!string.IsNullOrWhiteSpace(folder)) return folder;
60 | // As an example, if the TFM is netcoreapp3.0 or net5.0, this should cover everything like:
61 | // netstandard2.0, netstandard1.0
62 | var tfmBaseOfNetCore = "netstandard";
63 | var netCoreRegex = new Regex($@"^(?(?{tfmBaseOfNetCore})(?[0-9\.0-9]*))$", RegexOptions.IgnoreCase);
64 | folder = GetWinningFolder(folderPaths, netCoreRegex);
65 |
66 | if (!string.IsNullOrWhiteSpace(folder)) return folder;
67 | // Now we just match the base, e.g. for net we should get:
68 | // net45, net46, net461
69 | var baseMatch = new Regex($@"^(?(?{tfmBase}[a-z]*)(?[0-9\.0-9]*))$", RegexOptions.IgnoreCase);
70 | folder = GetWinningFolder(folderPaths, baseMatch);
71 |
72 | if (!string.IsNullOrWhiteSpace(folder)) return folder;
73 | // Now do an even more lenient match within
74 | var preciseTfmRegex = new Regex($@"(?(?{tfmBase})(?[0-9\.0-9]+))", RegexOptions.IgnoreCase);
75 | folder = GetWinningFolder(folderPaths, preciseTfmRegex);
76 |
77 |
78 | if (!string.IsNullOrWhiteSpace(folder)) return folder;
79 | // Given that we have found nothing, is there anything that matches the first 3 characters?
80 | var broadAssumptionRegex = new Regex($@"(?(?{tfmBase.Substring(0, 3)})(?[0-9\.0-9]+))", RegexOptions.IgnoreCase);
81 | folder = GetWinningFolder(folderPaths, broadAssumptionRegex);
82 |
83 |
84 |
85 | return folder;
86 | }
87 |
88 | public static Regex WildCardToRegex(string pattern)
89 | {
90 | return new Regex("^" + Regex.Escape(pattern).Replace("\\?", ".").Replace("\\*", ".*") + "$", RegexOptions.Compiled);
91 | }
92 |
93 | public static bool CopyLibraryContent(string source, string destination, PackageAtom package, out List binaries)
94 | {
95 | binaries = new List();
96 | var docFiles = new List();
97 |
98 | try
99 | {
100 | binaries = Directory.GetFiles(source, "*.*", SearchOption.TopDirectoryOnly)
101 | .Where(s => s.EndsWith(".dll") || s.EndsWith(".winmd")).ToList();
102 | if (package.CustomProperties.ExcludedDlls != null && package.CustomProperties.ExcludedDlls.Count != 0)
103 | {
104 | binaries = binaries.Where(b => !package.CustomProperties.ExcludedDlls.Any(d => d.IsMatch(Path.GetFileName(b)))).ToList();
105 | }
106 | }
107 | catch
108 | {
109 | Console.WriteLine($"[error] Could not get binaries for {package.Name} from {source}.");
110 | return false;
111 | }
112 |
113 |
114 | foreach (var binary in binaries)
115 | File.Copy(binary, Path.Combine(destination, Path.GetFileName(binary)), true);
116 |
117 | try
118 | {
119 | docFiles = Directory.GetFiles(source, "*.xml", SearchOption.TopDirectoryOnly).ToList();
120 |
121 | if (package.CustomProperties.ExcludedDlls != null && package.CustomProperties.ExcludedDlls.Count != 0)
122 | {
123 | docFiles = docFiles.Where(b => !package.CustomProperties.ExcludedDlls.Any(d => d.IsMatch(Path.GetFileName(b)))).ToList();
124 | }
125 |
126 | foreach (var docFile in docFiles)
127 | File.Copy(docFile, Path.Combine(destination, Path.GetFileName(docFile)), true);
128 | }
129 | catch
130 | {
131 | Console.WriteLine($"[warning] Could not get documentation files for {package.Name} from {source}.");
132 | }
133 |
134 | return true;
135 | }
136 |
137 | public static string BuildCommandString(PackageAtom package, string rootPath, string configPath, RunSettings runSettings)
138 | {
139 | var baseline = $@"install {package.Name} -OutputDirectory ""{rootPath.Trim('"')}"" -Verbosity Quiet -FallbackSource https://api.nuget.org/v3/index.json -ConfigFile ""{configPath.Trim('"')}""";
140 |
141 | if (!string.IsNullOrWhiteSpace(package.CustomProperties.TFM))
142 | {
143 | baseline += $" -Framework {package.CustomProperties.TFM}";
144 | }
145 | else if (!string.IsNullOrEmpty(runSettings.TFM))
146 | {
147 | baseline += $" -Framework {runSettings.TFM}";
148 | }
149 |
150 | if (!string.IsNullOrWhiteSpace(package.CustomProperties.CustomFeed))
151 | {
152 | baseline += $" -Source {package.CustomProperties.CustomFeed}";
153 | }
154 | else if (!string.IsNullOrEmpty(runSettings.Feed))
155 | {
156 | baseline += $" -Source {runSettings.Feed}";
157 | }
158 |
159 | if (package.CustomVersionDefined)
160 | {
161 | baseline += $" -Version {package.CustomVersion}";
162 | }
163 | if (package.IsPrerelease)
164 | {
165 | baseline += " -PreRelease";
166 | }
167 |
168 | return baseline;
169 | }
170 |
171 | private static string GetWinningFolder(string[] folders, Regex regex)
172 | {
173 | var folderAssociations = new Dictionary();
174 | foreach (var folder in folders)
175 | {
176 | var exactFolderName = Path.GetFileName(folder);
177 | var token = regex.Match(exactFolderName);
178 | if (!token.Success) continue;
179 | var folderVersion = token.Groups["version"].Value;
180 |
181 | if (!string.IsNullOrEmpty(folderVersion))
182 | {
183 | folderAssociations.Add(folder, folderVersion);
184 | }
185 | else
186 | {
187 | folderAssociations.Add(folder, "0");
188 | }
189 | }
190 |
191 | if (folderAssociations.Count <= 0) return string.Empty;
192 | var topItem = (from c in folderAssociations orderby c.Value descending select c).First();
193 | return topItem.Key;
194 | }
195 | }
196 | }
197 |
--------------------------------------------------------------------------------
/Nue/Nue.StandardResolver/Resolver.cs:
--------------------------------------------------------------------------------
1 | using Nue.Core;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Diagnostics;
5 | using System.IO;
6 | using System.Linq;
7 | using System.Reflection;
8 | using System.Text;
9 | namespace Nue.StandardResolver
10 | {
11 | public class Resolver : IPackageResolver
12 | {
13 | public bool CopyBinarySet(
14 | PackageAtom package,
15 | RunSettings runSettings,
16 | PackageInfomarionMapping pkgInfoMap,
17 | AssemblyMappingPackageInformation assemblyPkgInfoMap,
18 | string outputPrefix = "")
19 | {
20 | var tfm = package.CustomProperties.TFM ?? runSettings.TFM;
21 | var rootPath = runSettings.OutputPath + "\\_pacman" + outputPrefix;
22 |
23 | Console.WriteLine($"[info] Attempting to install: {package.GetFullName()}...");
24 |
25 | string command = $"{runSettings.NugetPath}\\nuget.exe";
26 |
27 | ProcessStartInfo cmdsi = new ProcessStartInfo(command)
28 | {
29 | UseShellExecute = false,
30 | RedirectStandardOutput = true,
31 | RedirectStandardError = true,
32 | };
33 |
34 | var configPath = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "custom.nuget.config");
35 |
36 | string commandString = Helpers.BuildCommandString(package, rootPath, configPath, runSettings);
37 | cmdsi.Arguments = commandString;
38 | Console.WriteLine($"[info] {command} {commandString}");
39 | StringBuilder sb = new StringBuilder();
40 | Process cmd = Process.Start(cmdsi);
41 |
42 | cmd.OutputDataReceived += (object sender, DataReceivedEventArgs e) =>
43 | {
44 | if (!string.IsNullOrWhiteSpace(e.Data))
45 | {
46 | sb.AppendLine(e.Data);
47 | }
48 | };
49 | cmd.ErrorDataReceived += (object sender, DataReceivedEventArgs e) =>
50 | {
51 | if (!string.IsNullOrWhiteSpace(e.Data))
52 | {
53 | sb.AppendLine(e.Data);
54 | }
55 | };
56 |
57 | cmd.BeginOutputReadLine();
58 | cmd.BeginErrorReadLine();
59 |
60 | cmd.WaitForExit();
61 | var isContinue = true;
62 | if (cmd.ExitCode != 0)
63 | {
64 | // The package ( https://www.nuget.org/packages/Microsoft.AspNetCore.App.Ref/3.0.0) is marked as DotnetPlatform and therefore cannot be installed directly by nuget.exe. One possible solution is to directly download the .nupkg file and extra dlls from it.
65 | // Task377921:https://ceapex.visualstudio.com/Engineering/_workitems/edit/377921
66 | var msg = sb.ToString();
67 | if (msg.Contains("package type 'DotnetPlatform'"))
68 | {
69 | package.IsDotnetPlatform = true;
70 | Console.WriteLine("[info] The package is marked as DotnetPlatform and therefore cannot be installed directly by nuget.exe. Package attempted: " + package.Name);
71 | var packageEngine = new PackageDownloder(rootPath, package.Name, package.CustomVersion, true);
72 | packageEngine.DownloadPackage();
73 | packageEngine.Unzip();
74 | }
75 | else
76 | {
77 | Console.WriteLine("[error] There was an error in NuGet installation. Package attempted: " + package.Name);
78 | isContinue = false;
79 | }
80 | }
81 |
82 | if (!isContinue)
83 | {
84 | return false;
85 | }
86 | else
87 | {
88 | var packageFqn = package.Name;
89 | if (package.CustomVersionDefined)
90 | {
91 | packageFqn += "." + package.CustomVersion;
92 | }
93 |
94 | var pacManPackagePath = Path.Combine(rootPath, packageFqn);
95 |
96 | string pacManPackageLibPath = "";
97 |
98 | pacManPackagePath = (from c in Directory.GetDirectories(rootPath) where c.StartsWith(pacManPackagePath, StringComparison.InvariantCultureIgnoreCase) select c).FirstOrDefault();
99 |
100 | var packageVersion = pacManPackagePath.Replace(Path.Combine(rootPath, package.Name + "."), "");
101 | if (package.IsDotnetPlatform)
102 | {
103 | packageVersion = pacManPackagePath.Replace(Path.Combine(rootPath, package.Name.ToLowerInvariant() + "."), "");
104 | }
105 |
106 | // In some cases, the lookup might be happening inside a custom path.
107 | // For PowerShell, this should be done inside the root directory.
108 | if (package.IsPowerShellPackage)
109 | {
110 | pacManPackageLibPath = pacManPackagePath;
111 | }
112 | else if (!string.IsNullOrWhiteSpace(package.CustomProperties?.CustomLibraryFolder))
113 | {
114 | pacManPackageLibPath = Path.Combine(pacManPackagePath, package.CustomProperties.CustomLibraryFolder);
115 | }
116 | else
117 | {
118 | pacManPackageLibPath = pacManPackagePath + "\\lib";
119 | }
120 |
121 | var packageFolderId = string.IsNullOrEmpty(package.Moniker) ? package.Name : package.Moniker;
122 | var packageContainerPath = Path.Combine(runSettings.OutputPath, packageFolderId);
123 | var packageDependencyContainerPath = Path.Combine(runSettings.OutputPath, "dependencies", packageFolderId);
124 |
125 | // Among other things, we need to make sure that the package was not already extracted for
126 | // another team.
127 | if (Directory.Exists(pacManPackageLibPath) && !Directory.Exists(packageContainerPath))
128 | {
129 | Directory.CreateDirectory(packageContainerPath);
130 |
131 | // If we are dealing with a different PowerShell package, we might need to operate slightly
132 | // differently givent that the structure is not at all reflective of what other NuGet packages encompass.
133 | if (package.IsPowerShellPackage)
134 | {
135 | Console.WriteLine($"[info] Treating {package.Name} as a PowerShell package.");
136 |
137 | var helpXmlFiles = from c in Directory.GetFiles(pacManPackageLibPath)
138 | where Path.GetFileName(c).ToLower().EndsWith("-help.xml")
139 | select c;
140 |
141 | var dllFiles = new List();
142 |
143 | foreach (var helpXmlFile in helpXmlFiles)
144 | {
145 | var workingDll = Path.GetFileName(helpXmlFile).ToLower().Replace("-help.xml", "");
146 | if (File.Exists(Path.Combine(pacManPackageLibPath, workingDll)))
147 | {
148 | dllFiles.Add(workingDll);
149 | }
150 | }
151 |
152 | if (dllFiles.Any())
153 | {
154 | foreach (var dll in dllFiles)
155 | {
156 | File.Copy(Path.Combine(pacManPackageLibPath, dll), Path.Combine(packageContainerPath, dll), true);
157 | //File.Copy(Path.Combine(pacManPackageLibPath, dll + "-help.xml"), Path.Combine(packageContainerPath, Path.GetFileNameWithoutExtension(dll) + ".xml"), true);
158 | }
159 |
160 | var dependencies = (from c in Directory.GetFiles(pacManPackageLibPath)
161 | where !dllFiles.Contains(Path.GetFileName(c).ToLower()) && Path.GetFileName(c).EndsWith(".dll")
162 | select c).ToList();
163 | if ((tfm.StartsWith("net46") || tfm.StartsWith("net47") || tfm.StartsWith("net48"))
164 | && Directory.Exists(Path.Combine(pacManPackageLibPath, "PreloadAssemblies")))
165 | {
166 | dependencies.AddRange(Directory.GetFiles(Path.Combine(pacManPackageLibPath, "PreloadAssemblies")));
167 | }
168 | if (tfm.StartsWith("netcoreapp")
169 | && Directory.Exists(Path.Combine(pacManPackageLibPath, "NetCoreAssemblies")))
170 | {
171 | dependencies.AddRange(Directory.GetFiles(Path.Combine(pacManPackageLibPath, "NetCoreAssemblies")));
172 | }
173 | if (dependencies.Count > 0)
174 | {
175 | Directory.CreateDirectory(packageDependencyContainerPath);
176 |
177 | foreach (var dependency in dependencies)
178 | {
179 |
180 | File.Copy(dependency, Path.Combine(packageDependencyContainerPath, Path.GetFileName(dependency)), true);
181 | }
182 | }
183 | }
184 | }
185 | else
186 | {
187 | var dependencyFolders = new List();
188 |
189 | // Directory exists, so we should proceed to package extraction.
190 | var directories = Directory.GetDirectories(pacManPackageLibPath);
191 | var closestDirectory = Helpers.GetBestLibMatch(tfm, directories);
192 |
193 | try
194 | {
195 | dependencyFolders = (from c in Directory.GetDirectories(rootPath)
196 | where Path.GetFileName(c).ToLower() != packageFqn.ToLower()
197 | select c).ToList();
198 | }
199 | catch
200 | {
201 | Console.WriteLine($"[warning] Could not create list of dependencies for {package.Name}");
202 | }
203 |
204 | // It might be possible that the author specified an additional dependency folder.
205 | // If that is the case, we are just going to add it to the existing set of folders.
206 | if (!string.IsNullOrEmpty(package.CustomProperties.CustomDependencyFolder))
207 | {
208 | dependencyFolders.Add(Path.Combine(pacManPackagePath, package.CustomProperties.CustomDependencyFolder));
209 | }
210 |
211 | string informationalPackageString = $"[info] Currently available library sets for {package.Name}\n";
212 |
213 | foreach (var folder in directories)
214 | {
215 | var tfmFolder = Path.GetFileName(folder);
216 | informationalPackageString += " |___" + tfmFolder + "\n";
217 | }
218 |
219 | Console.WriteLine(informationalPackageString);
220 |
221 | if (dependencyFolders.Any())
222 | {
223 | informationalPackageString = $"[info] Package dependencies for {package.Name}\n";
224 |
225 | foreach (var dependency in dependencyFolders)
226 | {
227 | informationalPackageString += " |___" + Path.GetFileNameWithoutExtension(dependency) + "\n";
228 | }
229 |
230 | Console.WriteLine(informationalPackageString);
231 | }
232 |
233 | var frameworkIsAvailable = !string.IsNullOrWhiteSpace(closestDirectory);
234 |
235 | bool capturedContent = false;
236 | List binaries = null;
237 | if (frameworkIsAvailable)
238 | {
239 | capturedContent = Helpers.CopyLibraryContent(closestDirectory, packageContainerPath, package, out binaries);
240 | }
241 | else
242 | {
243 | capturedContent = Helpers.CopyLibraryContent(pacManPackageLibPath, packageContainerPath, package, out binaries);
244 | }
245 |
246 | // record the assembly => package mapping
247 | var packageInfo = new PackageInfomarion()
248 | {
249 | Name = package.Name,
250 | Version = packageVersion,
251 | Feed = runSettings.Feed
252 | };
253 | if (!pkgInfoMap.ContainsKey(packageFolderId))
254 | {
255 | pkgInfoMap[packageFolderId] = new Dictionary();
256 | }
257 | foreach (var binary in binaries)
258 | {
259 | AssemblyPackageInformationMap(binary, assemblyPkgInfoMap, packageInfo);
260 | var assemblyName = Path.GetFileNameWithoutExtension(binary);
261 | pkgInfoMap[packageFolderId][assemblyName] = packageInfo;
262 | }
263 |
264 | // Only process dependencies if we actually captured binary content.
265 | if (capturedContent)
266 | {
267 | if (package.CustomProperties.ExcludedDlls != null && package.CustomProperties.ExcludedDlls.Count != 0)
268 | {
269 | var excludedDllDirectory = pacManPackageLibPath;
270 | if (frameworkIsAvailable)
271 | {
272 | excludedDllDirectory = closestDirectory;
273 | }
274 |
275 | if (!Directory.Exists(packageDependencyContainerPath))
276 | {
277 | Directory.CreateDirectory(packageDependencyContainerPath);
278 | }
279 |
280 | var dlls = Directory.EnumerateFiles(excludedDllDirectory, "*.*", SearchOption.TopDirectoryOnly)
281 | .Where(s => s.EndsWith(".dll"));
282 |
283 | foreach (var dll in dlls)
284 | {
285 | if (package.CustomProperties.ExcludedDlls.Any(d => d.IsMatch(Path.GetFileName(dll))))
286 | {
287 | File.Copy(dll,
288 | Path.Combine(packageDependencyContainerPath, Path.GetFileName(dll)),
289 | true);
290 | }
291 | }
292 | }
293 |
294 | if (dependencyFolders.Any())
295 | {
296 | foreach (var dependency in dependencyFolders)
297 | {
298 | var availableDependencyMonikers = new List();
299 |
300 | var targetPath = Path.Combine(dependency, "lib");
301 | if (Directory.Exists(targetPath) && Directory.GetFiles(targetPath, "*.*", SearchOption.AllDirectories)
302 | .Where(s => s.EndsWith(".dll") || s.EndsWith(".winmd")).Count() > 0)
303 | {
304 | List alternateDependencies = new List();
305 |
306 | // In some cases, we might want to have alterhative dependency monikers.
307 | if (package.CustomPropertyBag.ContainsKey("altDep"))
308 | {
309 | alternateDependencies = new List(package.CustomPropertyBag["altDep"].Split('|'));
310 | }
311 |
312 | var dependencyLibFolders = Directory.GetDirectories(Path.Combine(dependency, "lib"));
313 | var closestDepLibFolder = Helpers.GetBestLibMatch(tfm, dependencyLibFolders);
314 |
315 | if (string.IsNullOrWhiteSpace(closestDepLibFolder))
316 | {
317 | // We could not find a regular TFM dependency, let's try again for alternates.
318 | if (alternateDependencies.Count > 0)
319 | {
320 | foreach (var altDependency in alternateDependencies)
321 | {
322 | closestDepLibFolder = Helpers.GetBestLibMatch(altDependency, dependencyLibFolders);
323 | if (!string.IsNullOrWhiteSpace(closestDepLibFolder))
324 | break;
325 | }
326 | }
327 | }
328 |
329 | var dFrameworkIsAvailable = !string.IsNullOrWhiteSpace(closestDepLibFolder);
330 |
331 | if (dFrameworkIsAvailable)
332 | {
333 | if (!Directory.Exists(packageDependencyContainerPath))
334 | {
335 | Directory.CreateDirectory(packageDependencyContainerPath);
336 | }
337 |
338 | var dependencyBinaries = Directory.EnumerateFiles(closestDepLibFolder, "*.*", SearchOption.TopDirectoryOnly)
339 | .Where(s => s.EndsWith(".dll") || s.EndsWith(".winmd"));
340 |
341 | foreach (var binary in dependencyBinaries)
342 | File.Copy(binary,
343 | Path.Combine(packageDependencyContainerPath, Path.GetFileName(binary)),
344 | true);
345 | }
346 | }
347 | else
348 | {
349 | // The "lib" folder does not exist, so let's just look in the root.
350 | var dependencyBinaries = Directory.EnumerateFiles(dependency, "*.*", SearchOption.TopDirectoryOnly)
351 | .Where(s => s.EndsWith(".dll") || s.EndsWith(".winmd"));
352 |
353 | foreach (var binary in dependencyBinaries)
354 | File.Copy(binary,
355 | Path.Combine(packageDependencyContainerPath, Path.GetFileName(binary)),
356 | true);
357 | }
358 | }
359 | }
360 | else if(package.CustomProperties.ExcludedDlls == null || package.CustomProperties.ExcludedDlls.Count == 0)
361 | {
362 | Console.WriteLine($"[warning] No dependencies captured for {package.Name}");
363 | }
364 | }
365 | else
366 | {
367 | Console.WriteLine($"[error] No binaries captured for {package.Name}");
368 | return false;
369 | }
370 | }
371 | }
372 | return true;
373 | }
374 | }
375 |
376 | private void AssemblyPackageInformationMap(string binary, AssemblyMappingPackageInformation assemblyPkgInfoMap, PackageInfomarion packageInfo)
377 | {
378 | var assemblyName = Path.GetFileName(binary);
379 | if (!assemblyPkgInfoMap.ContainsKey(assemblyName))
380 | {
381 | assemblyPkgInfoMap[assemblyName] = new List();
382 | }
383 |
384 | var dependencyPackages = assemblyPkgInfoMap[assemblyName];
385 | dependencyPackages.Add(packageInfo);
386 |
387 | if (dependencyPackages.Count > 1)
388 | {
389 | string informationalPackageStringOfDependency = $"[warning] {assemblyName} already exists in the following packages\n";
390 | foreach (var item in dependencyPackages)
391 | {
392 | informationalPackageStringOfDependency += " |___" + item.Name + " " + item.Version + "\n";
393 | }
394 |
395 | Console.WriteLine(informationalPackageStringOfDependency);
396 | }
397 |
398 | }
399 | }
400 | }
401 |
--------------------------------------------------------------------------------