TryParse() public static method

public static TryParse ( string versionString, SemanticVersion, &semanticVersion ) : bool
versionString string
semanticVersion SemanticVersion,
return bool
Ejemplo n.º 1
0
        private bool IsNpmInstalled()
        {
            var output = CmdHelper.RunCmdAndGetOutput("npm -v").Trim();

            return(SemanticVersion.TryParse(output, out _));
        }
Ejemplo n.º 2
0
 void CantParse(string s)
 {
     Assert.IsFalse(SemanticVersion.TryParse(s, out _));
 }
Ejemplo n.º 3
0
        private static void LoadPackages(IEnumerable <string> packagePaths, Dictionary <string, PackageInfo> packages, string tempDirectoryOpt, bool release)
        {
            bool readOnly = tempDirectoryOpt == null;

            foreach (var packagePath in packagePaths)
            {
                Package package;
                string  tempPathOpt;
                if (readOnly)
                {
                    tempPathOpt = null;
                    package     = Package.Open(packagePath, FileMode.Open, FileAccess.Read);
                }
                else
                {
                    tempPathOpt = Path.Combine(tempDirectoryOpt, Guid.NewGuid().ToString());
                    File.Copy(packagePath, tempPathOpt);
                    package = Package.Open(tempPathOpt, FileMode.Open, FileAccess.ReadWrite);
                }

                string    packageId    = null;
                Stream    nuspecStream = null;
                XDocument nuspecXml    = null;

                PackageInfo packageInfo = null;
                try
                {
                    SemanticVersion packageVersion    = null;
                    SemanticVersion newPackageVersion = null;

                    foreach (var part in package.GetParts())
                    {
                        string relativePath = part.Uri.OriginalString;
                        ParsePartName(relativePath, out var fileName, out var dirName);

                        if (dirName == "/" && fileName.EndsWith(".nuspec", StringComparison.OrdinalIgnoreCase))
                        {
                            nuspecStream = part.GetStream(FileMode.Open, readOnly ? FileAccess.Read : FileAccess.ReadWrite);
                            nuspecXml    = XDocument.Load(nuspecStream);

                            var metadata = nuspecXml.Element(XName.Get("package", NuspecXmlns))?.Element(XName.Get("metadata", NuspecXmlns));
                            if (metadata == null)
                            {
                                throw new InvalidDataException($"'{packagePath}' has invalid nuspec: missing 'metadata' element");
                            }

                            packageId = metadata.Element(XName.Get("id", NuspecXmlns))?.Value;
                            if (packageId == null)
                            {
                                throw new InvalidDataException($"'{packagePath}' has invalid nuspec: missing 'id' element");
                            }

                            var    versionElement    = metadata.Element(XName.Get("version", NuspecXmlns));
                            string packageVersionStr = versionElement?.Value;
                            if (packageVersionStr == null)
                            {
                                throw new InvalidDataException($"'{packagePath}' has invalid nuspec: missing 'version' element");
                            }

                            if (!SemanticVersion.TryParse(packageVersionStr, out packageVersion))
                            {
                                throw new InvalidDataException($"'{packagePath}' has invalid nuspec: invalid 'version' value '{packageVersionStr}'");
                            }

                            if (!packageVersion.IsPrerelease)
                            {
                                throw new InvalidOperationException($"Can only update pre-release packages: '{packagePath}' has release version");
                            }

                            // To strip build number take the first part of the pre-release label (e.g. "beta1-62030-10")
                            string releaseLabel = release ? null : packageVersion.Release.Split('-').First();

                            newPackageVersion = new SemanticVersion(packageVersion.Major, packageVersion.Minor, packageVersion.Patch, releaseLabel);

                            if (!readOnly)
                            {
                                versionElement.SetValue(newPackageVersion.ToNormalizedString());
                            }

                            break;
                        }
                    }

                    if (nuspecStream == null)
                    {
                        throw new InvalidDataException($"'{packagePath}' is missing .nuspec file");
                    }

                    if (packages.ContainsKey(packageId))
                    {
                        throw new InvalidDataException($"Multiple packages of name '{packageId}' specified");
                    }

                    if (!readOnly)
                    {
                        package.PackageProperties.Version = newPackageVersion.ToNormalizedString();
                    }

                    packageInfo = new PackageInfo(package, packageId, packageVersion, newPackageVersion, tempPathOpt, nuspecStream, nuspecXml);
                }
                finally
                {
                    if (packageInfo == null)
                    {
                        nuspecStream.Dispose();
                        package.Close();

                        if (tempPathOpt != null)
                        {
                            File.Delete(tempPathOpt);
                        }
                    }
                }

                packages.Add(packageId, packageInfo);
            }
        }
Ejemplo n.º 4
0
        private static void LoadPackages(IEnumerable <string> packagePaths, Dictionary <string, PackageInfo> packages, string tempDirectoryOpt, VersionTranslation translation)
        {
            bool readOnly = tempDirectoryOpt == null;

            foreach (var packagePath in packagePaths)
            {
                Package package;
                string  tempPathOpt;
                bool    isDotnetTool = false;
                if (readOnly)
                {
                    tempPathOpt = null;
                    package     = Package.Open(packagePath, FileMode.Open, FileAccess.Read);
                }
                else
                {
                    tempPathOpt = Path.Combine(tempDirectoryOpt, Guid.NewGuid().ToString());
                    File.Copy(packagePath, tempPathOpt);
                    package = Package.Open(tempPathOpt, FileMode.Open, FileAccess.ReadWrite);
                }

                string    packageId    = null;
                Stream    nuspecStream = null;
                XDocument nuspecXml    = null;

                PackageInfo packageInfo = null;
                try
                {
                    SemanticVersion packageVersion    = null;
                    SemanticVersion newPackageVersion = null;
                    string          nuspecXmlns       = NuGetUtils.DefaultNuspecXmlns;

                    foreach (var part in package.GetParts())
                    {
                        string relativePath = part.Uri.OriginalString;
                        if (NuGetUtils.IsNuSpec(relativePath))
                        {
                            nuspecStream = part.GetStream(FileMode.Open, readOnly ? FileAccess.Read : FileAccess.ReadWrite);
                            nuspecXml    = XDocument.Load(nuspecStream);

                            if (nuspecXml.Root.HasAttributes)
                            {
                                var xmlNsAttribute = nuspecXml.Root.Attributes("xmlns").SingleOrDefault();
                                if (xmlNsAttribute != null)
                                {
                                    nuspecXmlns = xmlNsAttribute.Value;
                                }
                            }

                            var metadata = nuspecXml.Element(XName.Get("package", nuspecXmlns))?.Element(XName.Get("metadata", nuspecXmlns));
                            if (metadata == null)
                            {
                                throw new InvalidDataException($"'{packagePath}' has invalid nuspec: missing 'metadata' element");
                            }

                            packageId = metadata.Element(XName.Get("id", nuspecXmlns))?.Value;
                            if (packageId == null)
                            {
                                throw new InvalidDataException($"'{packagePath}' has invalid nuspec: missing 'id' element");
                            }

                            var    versionElement    = metadata.Element(XName.Get("version", nuspecXmlns));
                            string packageVersionStr = versionElement?.Value;
                            if (packageVersionStr == null)
                            {
                                throw new InvalidDataException($"'{packagePath}' has invalid nuspec: missing 'version' element");
                            }

                            if (!SemanticVersion.TryParse(packageVersionStr, out packageVersion))
                            {
                                throw new InvalidDataException($"'{packagePath}' has invalid nuspec: invalid 'version' value '{packageVersionStr}'");
                            }

                            if (!packageVersion.IsPrerelease)
                            {
                                throw new InvalidOperationException($"Can only update pre-release packages: '{packagePath}' has release version");
                            }

                            isDotnetTool = IsDotnetTool(nuspecXmlns, metadata);

                            switch (translation)
                            {
                            case VersionTranslation.Release:
                                // "1.2.3-beta-12345-01-abcdef" -> "1.2.3"
                                // "1.2.3-beta.12345.1+abcdef" -> "1.2.3"
                                newPackageVersion = new SemanticVersion(packageVersion.Major, packageVersion.Minor, packageVersion.Patch);
                                break;

                            case VersionTranslation.PreRelease:
                                // To strip build number take the first pre-release label.
                                // "1.2.3-beta-12345-01-abcdef" -> "1.2.3-beta-final-abcdef"
                                // "1.2.3-beta.12345.1+abcdef" -> "1.2.3-beta.final+abcdef"

                                // SemVer1 version has a single label "beta-12345-01-abcdef" and no metadata.
                                // SemVer2 version has multiple labels { "beta", "12345", "1" } and metadata "abcdef".
                                const string finalLabel = "final";
                                bool         isSemVer1  = packageVersion.Release.Contains('-');
                                var          label      = packageVersion.ReleaseLabels.First().Split('-')[0];

                                newPackageVersion = new SemanticVersion(
                                    packageVersion.Major,
                                    packageVersion.Minor,
                                    packageVersion.Patch,
                                    isSemVer1 ? new[] { label + "-" + finalLabel } : new[] { label, finalLabel },
                                    packageVersion.Metadata);
                                break;

                            case VersionTranslation.None:
                                newPackageVersion = packageVersion;
                                break;
                            }

                            if (!readOnly)
                            {
                                // Note: ToFullString = ToNormalizedString + metadata
                                versionElement.SetValue(newPackageVersion.ToFullString());
                            }

                            break;
                        }
                    }

                    if (isDotnetTool)
                    {
                        // skip repack DotnetTool since it has version embedded in executable
                        // and repack does not support it
                        continue;
                    }

                    if (nuspecStream == null)
                    {
                        throw new InvalidDataException($"'{packagePath}' is missing .nuspec file");
                    }

                    if (packages.ContainsKey(packageId))
                    {
                        throw new InvalidDataException($"Multiple packages of name '{packageId}' specified");
                    }

                    if (!readOnly)
                    {
                        package.PackageProperties.Version = newPackageVersion.ToFullString();
                    }

                    packageInfo = new PackageInfo(package, packageId, packageVersion, newPackageVersion, tempPathOpt, nuspecStream, nuspecXml, nuspecXmlns);
                }
                finally
                {
                    if (packageInfo == null)
                    {
                        nuspecStream.Dispose();
                        package.Close();

                        if (tempPathOpt != null)
                        {
                            File.Delete(tempPathOpt);
                        }
                    }
                }

                packages.Add(packageId, packageInfo);
            }
        }
        public AdvancedInstallViewModel(
            IChocolateyService chocolateyService,
            IPersistenceService persistenceService,
            SemanticVersion packageVersion)
        {
            _chocolateyService  = chocolateyService;
            _persistenceService = persistenceService;

            _cts = new CancellationTokenSource();

            _packageVersion = packageVersion.ToString();
            SelectedVersion = _packageVersion;

            FetchAvailableVersions();

            AvailableChecksumTypes = new List <string> {
                "md5", "sha1", "sha256", "sha512"
            };
            InstallCommand = new RelayCommand(
                o => { Close?.Invoke(this); },
                o => string.IsNullOrEmpty(SelectedVersion) || SelectedVersion == Resources.AdvancedChocolateyDialog_LatestVersion || SemanticVersion.TryParse(SelectedVersion, out _));
            CancelCommand = new RelayCommand(
                o =>
            {
                _cts.Cancel();
                Close?.Invoke(null);
            },
                o => true);

            BrowseLogFileCommand       = new RelayCommand(BrowseLogFile);
            BrowseCacheLocationCommand = new RelayCommand(BrowseCacheLocation);

            SetDefaults();
        }
        protected override async Task Execute(DeleteReleasesByRangeParams options)
        {
            if (!SemanticVersion.TryParse(options.FromVersion, out var from))
            {
                Console.Error.WriteLine($"Invalid 'from' version: {options.FromVersion}");
                return;
            }

            if (!SemanticVersion.TryParse(options.ToVersion, out var to))
            {
                Console.Error.WriteLine($"Invalid 'to' version: {options.ToVersion}");
                return;
            }

            using (var client = await OctopusClientProvider.GetOctopusClient(options))
            {
                foreach (var projectStr in await options.GetEffectiveProjects(client))
                {
                    var project = await client.Repository.Projects.FindByName(projectStr);

                    if (project == null)
                    {
                        Console.WriteLine($"Skipped {projectStr} as cannot find this project");
                        continue;
                    }

                    var releases =
                        await client.Repository.Projects.GetAllReleases(project);

                    if (releases == null || !releases.Any())
                    {
                        Console.WriteLine($"Skipped {projectStr} as cannot find the release for this project");
                        continue;
                    }

                    foreach (var release in releases)
                    {
                        if (!SemanticVersion.TryParse(release.Version, out var current))
                        {
                            Console.WriteLine(
                                $"Skipped deleteing a version for project {projectStr} as unable to interpret version: {release.Version}");
                            continue;
                        }

                        if (current < from || current > to)
                        {
                            continue;
                        }

                        Console.WriteLine($"Deleting {release.Version} for project {projectStr}");
                        try
                        {
                            await client.Repository.Releases.Delete(release);
                        }
                        catch (OctopusResourceNotFoundException)
                        {
                            Console.WriteLine($"Skipped {projectStr} as cannot find the release for this project");
                        }
                    }
                }
            }
        }
Ejemplo n.º 7
0
        bool IsValidVersionNumber()
        {
            SemanticVersion version = null;

            return(SemanticVersion.TryParse(Version, out version));
        }
 public void ValidateInvalidVersionParsing(string versionString, string tagPrefixRegex = null)
 {
     Assert.IsFalse(SemanticVersion.TryParse(versionString, tagPrefixRegex, out _), "TryParse Result");
 }
Ejemplo n.º 9
0
        public IQueryable <V2FeedPackage> GetUpdates(
            string packageIds,
            string versions,
            bool includePrerelease,
            bool includeAllVersions,
            string targetFrameworks,
            string versionConstraints)
        {
            if (String.IsNullOrEmpty(packageIds) || String.IsNullOrEmpty(versions))
            {
                return(Enumerable.Empty <V2FeedPackage>().AsQueryable());
            }

            // Workaround https://github.com/NuGet/NuGetGallery/issues/674 for NuGet 2.1 client. Can probably eventually be retired (when nobody uses 2.1 anymore...)
            // Note - it was URI un-escaping converting + to ' ', undoing that is actually a pretty conservative substitution because
            // space characters are never acepted as valid by VersionUtility.ParseFrameworkName.
            if (!string.IsNullOrEmpty(targetFrameworks))
            {
                targetFrameworks = targetFrameworks.Replace(' ', '+');
            }

            var idValues              = packageIds.Trim().ToLowerInvariant().Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
            var versionValues         = versions.Trim().Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
            var targetFrameworkValues = String.IsNullOrEmpty(targetFrameworks)
                                            ? null
                                            : targetFrameworks.Split('|').Select(VersionUtility.ParseFrameworkName).ToList();
            var versionConstraintValues = String.IsNullOrEmpty(versionConstraints)
                                            ? new string[idValues.Length]
                                            : versionConstraints.Split('|');

            if (idValues.Length == 0 || idValues.Length != versionValues.Length || idValues.Length != versionConstraintValues.Length)
            {
                // Exit early if the request looks invalid
                return(Enumerable.Empty <V2FeedPackage>().AsQueryable());
            }

            var versionLookup = idValues.Select((id, i) =>
            {
                SemanticVersion currentVersion;
                if (SemanticVersion.TryParse(versionValues[i], out currentVersion))
                {
                    IVersionSpec versionConstraint = null;
                    if (versionConstraintValues[i] != null)
                    {
                        if (!VersionUtility.TryParseVersionSpec(versionConstraintValues[i], out versionConstraint))
                        {
                            versionConstraint = null;
                        }
                    }
                    return(Tuple.Create(id, Tuple.Create(currentVersion, versionConstraint)));
                }
                return(null);
            })
                                .Where(t => t != null)
                                .ToLookup(t => t.Item1, t => t.Item2, StringComparer.OrdinalIgnoreCase);

            var packages = PackageRepository.GetAll()
                           .Include(p => p.PackageRegistration)
                           .Include(p => p.SupportedFrameworks)
                           .Where(p =>
                                  p.Listed && (includePrerelease || !p.IsPrerelease) &&
                                  idValues.Contains(p.PackageRegistration.Id.ToLower()))
                           .OrderBy(p => p.PackageRegistration.Id);

            return(GetUpdates(packages, versionLookup, targetFrameworkValues, includeAllVersions).AsQueryable()
                   .ToV2FeedPackageQuery(GetSiteRoot(), Configuration.Features.FriendlyLicenses));
        }
Ejemplo n.º 10
0
        /// <summary>Get a semantic local version for update checks.</summary>
        /// <param name="version">The version to map.</param>
        /// <param name="map">A map of version replacements.</param>
        /// <param name="allowNonStandard">Whether to allow non-standard versions.</param>
        private string GetRawMappedVersion(string version, IDictionary <string, string> map, bool allowNonStandard)
        {
            if (version == null || map == null || !map.Any())
            {
                return(version);
            }

            // match exact raw version
            if (map.ContainsKey(version))
            {
                return(map[version]);
            }

            // match parsed version
            if (SemanticVersion.TryParse(version, allowNonStandard, out ISemanticVersion parsed))
            {
                if (map.ContainsKey(parsed.ToString()))
                {
                    return(map[parsed.ToString()]);
                }

                foreach ((string fromRaw, string toRaw) in map)
                {
                    if (SemanticVersion.TryParse(fromRaw, allowNonStandard, out ISemanticVersion target) && parsed.Equals(target) && SemanticVersion.TryParse(toRaw, allowNonStandard, out ISemanticVersion newVersion))
                    {
                        return(newVersion.ToString());
                    }
                }
            }

            return(version);
        }
Ejemplo n.º 11
0
        /*********
        ** Private methods
        *********/
        /// <summary>Get metadata about a mod by scraping the Nexus website.</summary>
        /// <param name="id">The Nexus mod ID.</param>
        /// <returns>Returns the mod info if found, else <c>null</c>.</returns>
        private async Task <NexusMod> GetModFromWebsiteAsync(uint id)
        {
            // fetch HTML
            string html;

            try
            {
                html = await this.WebClient
                       .GetAsync(string.Format(this.WebModScrapeUrlFormat, id))
                       .AsString();
            }
            catch (ApiException ex) when(ex.Status == HttpStatusCode.NotFound)
            {
                return(null);
            }

            // parse HTML
            var doc = new HtmlDocument();

            doc.LoadHtml(html);

            // handle Nexus error message
            HtmlNode node = doc.DocumentNode.SelectSingleNode("//div[contains(@class, 'site-notice')][contains(@class, 'warning')]");

            if (node != null)
            {
                string[] errorParts = node.InnerText.Trim().Split(new[] { '\n' }, 2, System.StringSplitOptions.RemoveEmptyEntries);
                string   errorCode  = errorParts[0];
                string   errorText  = errorParts.Length > 1 ? errorParts[1] : null;
                switch (errorCode.Trim().ToLower())
                {
                case "not found":
                    return(null);

                default:
                    return(new NexusMod {
                        Error = $"Nexus error: {errorCode} ({errorText}).", Status = this.GetWebStatus(errorCode)
                    });
                }
            }

            // extract mod info
            string url     = this.GetModUrl(id);
            string name    = doc.DocumentNode.SelectSingleNode("//div[@id='pagetitle']//h1")?.InnerText.Trim();
            string version = doc.DocumentNode.SelectSingleNode("//ul[contains(@class, 'stats')]//li[@class='stat-version']//div[@class='stat']")?.InnerText.Trim();

            SemanticVersion.TryParse(version, out ISemanticVersion parsedVersion);

            // extract files
            var downloads = new List <IModDownload>();

            foreach (var fileSection in doc.DocumentNode.SelectNodes("//div[contains(@class, 'files-tabs')]"))
            {
                string sectionName = fileSection.Descendants("h2").First().InnerText;
                if (sectionName != "Main files" && sectionName != "Optional files")
                {
                    continue;
                }

                foreach (var container in fileSection.Descendants("dt"))
                {
                    string fileName    = container.GetDataAttribute("name").Value;
                    string fileVersion = container.GetDataAttribute("version").Value;
                    string description = container.SelectSingleNode("following-sibling::*[1][self::dd]//div").InnerText?.Trim(); // get text of next <dd> tag; derived from https://stackoverflow.com/a/25535623/262123

                    downloads.Add(
                        new GenericModDownload(fileName, description, fileVersion)
                        );
                }
            }

            // yield info
            return(new NexusMod
            {
                Name = name,
                Version = parsedVersion?.ToString() ?? version,
                Url = url,
                Downloads = downloads.ToArray()
            });
        }
Ejemplo n.º 12
0
        public KestrelDiagDialog(IServiceProvider provider, Application application)
            : base(provider)
        {
            InitializeComponent();

            using (var client = new WebClient())
            {
                string latest       = null;
                var    hasException = false;
                try
                {
                    var entry = "https://dotnetcli.blob.core.windows.net/dotnet/release-metadata/releases-index.json";
                    if (fileCaches.ContainsKey(entry))
                    {
                        latest = fileCaches[entry];
                    }
                    else
                    {
                        latest = client.DownloadString(entry);
                        fileCaches.Add(entry, latest);
                    }
                }
                catch (Exception)
                {
                    hasException = true;
                }

                JObject content;
                if (string.IsNullOrWhiteSpace(latest) || hasException)
                {
                    // fallback to resources.
                    using var bytes  = new MemoryStream(Resources.releases_index);
                    using var stream = new StreamReader(bytes);
                    using var json   = new JsonTextReader(stream);
                    content          = (JObject)JToken.ReadFrom(json);
                }
                else
                {
                    content = JObject.Parse(latest);
                }

                var releases = content["releases-index"];
                foreach (var release in releases)
                {
                    var    link = release["releases.json"].Value <string>();
                    string info = null;
                    hasException = false;
                    try
                    {
                        if (fileCaches.ContainsKey(link))
                        {
                            info = fileCaches[link];
                        }
                        else
                        {
                            info = client.DownloadString(link);
                            fileCaches.Add(link, info);
                        }
                    }
                    catch (Exception)
                    {
                        hasException = true;
                    }

                    JObject details;
                    if (string.IsNullOrWhiteSpace(info) || hasException)
                    {
                        // fallback to resources.
                        var number = new Version(release.Value <string>("channel-version"));
                        var name   = $"{number.Major}.{number.Minor}-release";
                        var stored = Resources.ResourceManager.GetObject(name);
                        if (stored == null)
                        {
                            // IMPORTANT: didn't have this version in resource.
                            continue;
                        }

                        using var bytes  = new MemoryStream((byte[])stored);
                        using var stream = new StreamReader(bytes);
                        using var json   = new JsonTextReader(stream);
                        details          = (JObject)JToken.ReadFrom(json);
                    }
                    else
                    {
                        details = JObject.Parse(info);
                    }

                    foreach (var actual in details["releases"])
                    {
                        var runtimeObject = actual["runtime"];
                        if (runtimeObject == null)
                        {
                            // skip no runtime release.
                            continue;
                        }

                        try
                        {
                            if (!runtimeObject.HasValues)
                            {
                                continue;
                            }

                            var longVersion = runtimeObject.Value <string>("version");
                            if (longVersion == null)
                            {
                                continue;
                            }

                            var aspNetRuntime = actual["aspnetcore-runtime"];
                            if (aspNetRuntime == null || !aspNetRuntime.HasValues)
                            {
                                continue;
                            }

                            var aspNetCoreModuleObject = aspNetRuntime["version-aspnetcoremodule"];
                            if (aspNetCoreModuleObject == null || !aspNetCoreModuleObject.HasValues)
                            {
                                // skip no ASP.NET Core module release.
                                continue;
                            }

                            var aspNetCoreModule = aspNetCoreModuleObject.Values <string>().First();
                            var phase            = release.Value <string>("support-phase");
                            var expired          = phase == "eol";
                            var runtime          = SemanticVersion.Parse(longVersion);
                            if (mappings.ContainsKey(runtime))
                            {
                                Console.WriteLine($"{runtime}: new {aspNetCoreModule}: old {mappings[runtime].Item1}");
                            }
                            else
                            {
                                mappings.Add(runtime,
                                             new Tuple <Version, bool>(Version.Parse(aspNetCoreModule), expired));
                            }
                        }
                        catch (Exception ex)
                        {
                            Console.WriteLine($"JSON parsing failed. {ex}");
                        }
                    }
                }
            }

            var container = new CompositeDisposable();

            FormClosed += (sender, args) => container.Dispose();

            container.Add(
                Observable.FromEventPattern <EventArgs>(btnGenerate, "Click")
                .ObserveOn(System.Threading.SynchronizationContext.Current)
                .Subscribe(evt =>
            {
                txtResult.Clear();
                try
                {
                    Warn("IMPORTANT: This report might contain confidential information. Mask such before sharing with others.");
                    Warn("-----");
                    Debug($"System Time: {DateTime.Now}");
                    Debug($"Processor Architecture: {Environment.GetEnvironmentVariable("PROCESSOR_ARCHITECTURE")}");
                    Debug($"OS: {Environment.OSVersion}");
                    Debug($"Server Type: {application.Server.Mode.AsString(EnumFormat.Description)}");
                    Debug(string.Empty);

                    var root = application.VirtualDirectories[0].PhysicalPath.ExpandIisExpressEnvironmentVariables(application.GetActualExecutable());
                    if (string.IsNullOrWhiteSpace(root))
                    {
                        Error("Invalid site root directory is detected.");
                        return;
                    }

                    // check ANCM.
                    var appHost     = application.Server.GetApplicationHostConfiguration();
                    var definitions = new List <SectionDefinition>();
                    appHost.RootSectionGroup.GetAllDefinitions(definitions);
                    if (!definitions.Any(item => item.Path == "system.webServer/aspNetCore"))
                    {
                        Error($"ASP.NET Core module is not installed as part of IIS. Please refer to https://docs.microsoft.com/en-us/aspnet/core/host-and-deploy/iis/index#install-the-net-core-hosting-bundle for more details.");
                        return;
                    }

                    var modules = new ModulesFeature((Module)provider);
                    modules.Load();
                    Debug($"Scan {modules.Items.Count} installed module(s).");
                    var hasV1 = modules.Items.FirstOrDefault(item => item.Name == "AspNetCoreModule");
                    var hasV2 = modules.Items.FirstOrDefault(item => item.Name == "AspNetCoreModuleV2");

                    if (hasV1 == null && hasV2 == null)
                    {
                        Error($"ASP.NET Core module is not installed as part of IIS. Please refer to https://docs.microsoft.com/en-us/aspnet/core/host-and-deploy/iis/index#install-the-net-core-hosting-bundle for more details.");
                        return;
                    }

                    Version ancmVersion = null;
                    if (hasV2 != null)
                    {
                        var file = hasV2.GlobalModule.Image.ExpandIisExpressEnvironmentVariables(application.GetActualExecutable());
                        if (File.Exists(file))
                        {
                            var info    = FileVersionInfo.GetVersionInfo(file);
                            ancmVersion = new Version(info.FileMajorPart, info.FileMinorPart, info.FileBuildPart, info.FilePrivatePart);
                            Info($"ASP.NET Core module version 2 is installed for .NET Core 3.1 and above: {file} ({info.FileVersion}).");
                        }
                        else
                        {
                            Error("ASP.NET Core module version 2 is not installed properly.");
                        }
                    }
                    else
                    {
                        var file = hasV1.GlobalModule.Image.ExpandIisExpressEnvironmentVariables(application.GetActualExecutable());
                        if (File.Exists(hasV1.GlobalModule.Image.ExpandIisExpressEnvironmentVariables(application.GetActualExecutable())))
                        {
                            var info    = FileVersionInfo.GetVersionInfo(file);
                            ancmVersion = new Version(info.FileMajorPart, info.FileMinorPart, info.FileBuildPart, info.FilePrivatePart);
                            Info($"ASP.NET Core module version 1 is installed for .NET Core 1.0-2.1: {file} ({info.FileVersion})");
                        }
                        else
                        {
                            Error("ASP.NET Core module version 2 is not installed properly.");
                        }
                    }

                    // check handler.
                    Debug(string.Empty);
                    var handlers = new HandlersFeature((Module)provider);
                    handlers.Load();
                    var foundHandlers = new List <HandlersItem>();
                    Debug($"Scan {handlers.Items.Count} registered handler(s).");
                    foreach (var item in handlers.Items)
                    {
                        if (item.Modules == "AspNetCoreModule")
                        {
                            if (hasV1 != null)
                            {
                                Info($"* Found a valid ASP.NET Core handler as {{ Name: {item.Name}, Path: {item.Path}, State: {item.GetState(handlers.AccessPolicy)}, Module: {item.TypeString}, Entry Type: {item.Flag} }}.");
                                foundHandlers.Add(item);
                            }
                            else
                            {
                                Error($"* Found an invalid ASP.NET Core handler as {{ Name: {item.Name}, Path: {item.Path}, State: {item.GetState(handlers.AccessPolicy)}, Module: {item.TypeString}, Entry Type: {item.Flag} }} because ASP.NET Core module version 1 is missing.");
                            }
                        }
                        else if (item.Modules == "AspNetCoreModuleV2")
                        {
                            if (hasV2 != null)
                            {
                                Info($"* Found a valid ASP.NET Core handler as {{ Name: {item.Name}, Path: {item.Path}, State: {item.GetState(handlers.AccessPolicy)}, Module: {item.TypeString}, Entry Type: {item.Flag} }}.");
                                foundHandlers.Add(item);
                            }
                            else
                            {
                                Error($"* Found an invalid ASP.NET Core handler as {{ Name: {item.Name}, Path: {item.Path}, State: {item.GetState(handlers.AccessPolicy)}, Module: {item.TypeString}, Entry Type: {item.Flag} }} because ASP.NET Core module version 2 is missing.");
                            }
                        }
                    }

                    if (foundHandlers.Count == 0)
                    {
                        Error($"No valid ASP.NET Core handler is registered for this web site.");
                        Error($"To run ASP.NET Core on IIS, please refer to https://docs.microsoft.com/en-us/aspnet/core/host-and-deploy/iis/index for more details.");
                        return;
                    }

                    var name = application.ApplicationPoolName;
                    var pool = application.Server.ApplicationPools.FirstOrDefault(item => item.Name == name);
                    if (pool == null)
                    {
                        Error($"The application pool '{name}' cannot be found.");
                        return;
                    }

                    var x86 = pool.Enable32BitAppOnWin64;

                    // check VC++ 2015.
                    var cppFile = Path.Combine(
                        Environment.GetFolderPath(x86 ? Environment.SpecialFolder.SystemX86 : Environment.SpecialFolder.System),
                        $"msvcp140.dll");
                    if (File.Exists(cppFile))
                    {
                        var cpp = FileVersionInfo.GetVersionInfo(cppFile);
                        if (cpp.FileMinorPart >= 0)
                        {
                            Info($"  Visual C++ runtime is detected (expected: 14.0, detected: {cpp.FileVersion}): {cppFile}.");
                        }
                        else
                        {
                            Error($"  Visual C++ runtime 14.0 is not detected. Please install it following the tips on https://docs.microsoft.com/en-us/aspnet/core/host-and-deploy/iis/index#install-the-net-core-hosting-bundle.");
                        }
                    }
                    else
                    {
                        Error($"  Visual C++ 14.0 runtime is not detected. Please install it following the tips on https://docs.microsoft.com/en-us/aspnet/core/host-and-deploy/iis/index#install-the-net-core-hosting-bundle.");
                    }

                    Info($"The application pool '{name}' is used.");
                    // check ASP.NET version.
                    if (pool.ManagedRuntimeVersion != ApplicationPool.ManagedRuntimeVersionNone)
                    {
                        Error($"The application pool '{name}' is using .NET CLR {pool.ManagedRuntimeVersion}. Please set it to 'No Managed Code'.");
                    }

                    Info($"Pool identity is {pool.ProcessModel}");
                    var user = application.Server.Mode == WorkingMode.IisExpress ? $"{Environment.UserDomainName}\\{Environment.UserName}" : pool.ProcessModel.ToString();
                    Warn($"Please ensure pool identity has read access to the content folder {application.PhysicalPath}.");

                    var poolBitness = x86 ? "32" : "64";
                    Info($"Pool bitness is {poolBitness} bit");

                    var config       = application.GetWebConfiguration();
                    var section      = config.GetSection("system.webServer/aspNetCore");
                    var processPath  = (string)section["processPath"];
                    var arguments    = (string)section["arguments"];
                    var hostingModel = (string)section["hostingModel"];

                    Debug($"Scan aspNetCore section.");
                    Debug($"    \"processPath\": {processPath}.");
                    Debug($"    \"arguments\": {arguments}.");
                    Debug($"    \"hostingModel\": {hostingModel}.");

                    if (string.Equals("InProcess", hostingModel, StringComparison.OrdinalIgnoreCase))
                    {
                        Warn("In-process hosting model is detected. To avoid 500.xx errors, make sure that the bitness of published artifacts matches the application pool bitness");

                        if (string.Equals("dotnet", processPath, StringComparison.OrdinalIgnoreCase))
                        {
                            Info("Framework dependent deployment is detected. Skip bitness check.");
                        }
                        else
                        {
                            Info("Self-contained deployment is detected. Check bitness.");
                            var path = processPath;
                            if (!File.Exists(path))
                            {
                                path = Path.Combine(application.PhysicalPath, path);
                            }

                            if (!File.Exists(path))
                            {
                                Error($"Cannot locate executable: {path}");
                            }
                            else
                            {
                                var bit32 = DialogHelper.GetImageArchitecture(path);
                                if (bit32 == x86)
                                {
                                    Info($"Published artifacts bitness matches.");
                                }
                                else
                                {
                                    var artifactBitness = bit32 ? "32" : "64";
                                    Error($"Published artifacts bitness is {artifactBitness} bit. Mismatch detected.");
                                }
                            }
                        }
                    }

                    if (string.IsNullOrWhiteSpace(processPath) && string.IsNullOrWhiteSpace(arguments))
                    {
                        Warn("There is no ASP.NET Core web app to analyze.");
                    }
                    else if (string.Equals(processPath, "%LAUNCHER_PATH%", StringComparison.OrdinalIgnoreCase) ||
                             string.Equals(arguments, "%LAUNCHER_ARGS%", StringComparison.OrdinalIgnoreCase))
                    {
                        Warn("Value of processPath or arguments is placeholder used by Visual Studio. This site can only be run from within Visual Studio.");
                    }
                    else
                    {
                        try
                        {
                            var fileName = Path.GetFileName(processPath);
                            string executable;
                            if (string.Equals(fileName, "dotnet.exe", StringComparison.OrdinalIgnoreCase) || string.Equals(fileName, "dotnet", StringComparison.OrdinalIgnoreCase))
                            {
                                if (arguments.StartsWith("exec ", StringComparison.OrdinalIgnoreCase))
                                {
                                    arguments = arguments.Substring("exec ".Length).Replace("\"", null);
                                }

                                executable = Path.GetFileNameWithoutExtension(arguments);
                            }
                            else
                            {
                                executable = Path.GetFileNameWithoutExtension(processPath);
                            }

                            var runtime = Path.Combine(root, executable + ".runtimeconfig.json");
                            if (File.Exists(runtime))
                            {
                                Debug($"Found runtime config file {runtime}.");
                                var reader    = JObject.Parse(File.ReadAllText(runtime));
                                string actual = null;
                                var framework = reader["runtimeOptions"]["framework"];
                                if (framework != null)
                                {
                                    actual = framework["version"].Value <string>();
                                    Info($"Runtime is {actual}");
                                }
                                else
                                {
                                    var frameworks = reader["runtimeOptions"]["includedFrameworks"];
                                    if (frameworks == null)
                                    {
                                        frameworks = reader["runtimeOptions"]["frameworks"];     // .NET 6
                                    }

                                    if (frameworks != null)
                                    {
                                        foreach (var item in frameworks.Children())
                                        {
                                            if (item["name"].Value <string>() == "Microsoft.AspNetCore.App")
                                            {
                                                actual = item["version"].Value <string>();
                                                Info($"Runtime is {actual}.");
                                            }
                                        }
                                    }
                                }
                                if (actual != null && SemanticVersion.TryParse(actual, out SemanticVersion aspNetCoreVersion) && aspNetCoreVersion >= SemanticVersion.Parse("3.1.0"))
                                {
                                    if (aspNetCoreVersion.IsPrerelease)
                                    {
                                        Warn("This is a prerelease runtime version.");
                                    }

                                    if (mappings.ContainsKey(aspNetCoreVersion))
                                    {
                                        var expired = mappings[aspNetCoreVersion].Item2;
                                        if (expired)
                                        {
                                            Error($".NET Core version {aspNetCoreVersion} is end-of-life. Please upgrade to a supported version.");
                                        }

                                        var minimal = mappings[aspNetCoreVersion].Item1;
                                        if (ancmVersion == null || ancmVersion < minimal)
                                        {
                                            Error($"Runtime {aspNetCoreVersion} does not work with ASP.NET Core module version {ancmVersion}. Minimal version is {minimal}.");
                                        }

                                        if (ancmVersion > minimal && (ancmVersion.Major != minimal.Major || ancmVersion.Minor != minimal.Minor))
                                        {
                                            Warn($"Runtime {aspNetCoreVersion} requires ASP.NET Core module version {minimal}. Installed version {ancmVersion} might not be compatible.");
                                        }
                                    }
                                }
                                else
                                {
                                    Warn($"Couldn't detect runtime version {actual}. Please refer to pages such as https://dotnet.microsoft.com/download/dotnet-core/3.1 to verify that ASP.NET Core version {ancmVersion} matches the runtime of the web app.");
                                }
                            }
                            else
                            {
                                Error($"Cannot locate runtime config file {runtime}.");
                            }
                        }
                        catch (Exception ex)
                        {
                            Error("Cannot analyze ASP.NET Core web app successfully.");
                            Rollbar.RollbarLocator.RollbarInstance.Error(ex, new Dictionary <string, object> {
                                { "source", "web app" }
                            });
                        }
                    }
                }
                catch (COMException ex)
                {
                    Error("A generic exception occurred.");
                    Error($"To run ASP.NET Core on IIS, please refer to https://docs.microsoft.com/en-us/aspnet/core/host-and-deploy/iis/index for more details.");
                    Debug(ex.ToString());
                    Rollbar.RollbarLocator.RollbarInstance.Error(ex);
                }
                catch (Exception ex)
                {
                    Debug(ex.ToString());
                    Rollbar.RollbarLocator.RollbarInstance.Error(ex);
                }
            }));

            container.Add(
                Observable.FromEventPattern <EventArgs>(btnSave, "Click")
                .ObserveOn(System.Threading.SynchronizationContext.Current)
                .Subscribe(evt =>
            {
                var fileName = DialogHelper.ShowSaveFileDialog(null, "Text Files|*.txt|All Files|*.*", application.GetActualExecutable());
                if (string.IsNullOrEmpty(fileName))
                {
                    return;
                }

                File.WriteAllText(fileName, txtResult.Text);
            }));

            container.Add(
                Observable.FromEventPattern <EventArgs>(btnVerify, "Click")
                .ObserveOn(System.Threading.SynchronizationContext.Current)
                .Subscribe(evt =>
            {
                txtResult.Clear();
            }));
        }
Ejemplo n.º 13
0
        public async Task <IReadOnlyCollection <PackageVersion> > GetPackageVersionsAsync(
            [NotNull] string packageId,
            bool useCache                       = true,
            ILogger logger                      = null,
            bool includePreReleased             = false,
            string nugetPackageSource           = null,
            string nugetConfigFile              = null,
            CancellationToken cancellationToken = default)
        {
            if (string.IsNullOrWhiteSpace(packageId))
            {
                throw new ArgumentException("Value cannot be null or whitespace.", nameof(packageId));
            }

            if (packageId.Equals(Constants.NotAvailable))
            {
                return(ImmutableArray <PackageVersion> .Empty);
            }

            string NormalizeKey(string key)
            {
                return(key.Replace(":", "_")
                       .Replace("/", "")
                       .Replace(".", "")
                       .Replace(Path.DirectorySeparatorChar.ToString(), "_"));
            }

            string cacheKey = AllPackagesCacheKey;

            if (!string.IsNullOrWhiteSpace(nugetConfigFile))
            {
                string configCachePart = $"{PackagesCacheKeyBaseUrn}:{NormalizeKey(nugetConfigFile)}";

                cacheKey = !string.IsNullOrWhiteSpace(nugetPackageSource) ? $"{configCachePart}:{NormalizeKey(nugetPackageSource)}" : configCachePart;
            }
            else if (!string.IsNullOrWhiteSpace(nugetPackageSource))
            {
                cacheKey = $"{PackagesCacheKeyBaseUrn}:{NormalizeKey(nugetPackageSource)}";
            }

            cacheKey += $":{packageId}";

            _logger.Verbose("Using package cache key {Key}", cacheKey);

            if (useCache)
            {
                if (_memoryCache.TryGetValue(cacheKey, out IReadOnlyCollection <PackageVersion> packages))
                {
                    if (packages.Count > 0)
                    {
                        _logger.Debug("Returning packages from cache with key {Key} for package id {PackageId}",
                                      cacheKey,
                                      packageId);
                        return(packages);
                    }
                }
            }

            var                 nuGetDownloadClient = new NuGetDownloadClient();
            HttpClient          httpClient          = _httpClientFactory.CreateClient("nuget");
            NuGetDownloadResult nuGetDownloadResult;

            using (var cts = new CancellationTokenSource(TimeSpan.FromSeconds(30)))
            {
                nuGetDownloadResult = await nuGetDownloadClient.DownloadNuGetAsync(NuGetDownloadSettings.Default,
                                                                                   _logger,
                                                                                   httpClient,
                                                                                   cts.Token);
            }

            if (!nuGetDownloadResult.Succeeded)
            {
                if (nuGetDownloadResult.Exception != null)
                {
                    _logger.Error(nuGetDownloadResult.Exception,
                                  "Could not download NuGet.exe: {Result}",
                                  nuGetDownloadResult.Result);
                }
                else
                {
                    _logger.Error("Could not download NuGet.exe: {Result}", nuGetDownloadResult.Result);
                }
            }

            string nugetExe = nuGetDownloadResult.NuGetExePath;

            if (string.IsNullOrWhiteSpace(nugetExe))
            {
                throw new DeployerAppException("The nuget.exe path is not set");
            }

            if (!File.Exists(nugetExe))
            {
                throw new DeployerAppException($"The nuget.exe path '{nugetExe}' does not exist");
            }

            string packageSourceAppSettingsKey = ConfigurationConstants.NuGetPackageSourceName;

            string packageSource = nugetPackageSource.WithDefault(_keyValueConfiguration[packageSourceAppSettingsKey]);

            var args = new List <string> {
                "list", packageId
            };

            if (includePreReleased)
            {
                args.Add("-PreRelease");
            }

            if (!string.IsNullOrWhiteSpace(packageSource))
            {
                logger?.Debug("Using package source '{PackageSource}' for package {Package}", packageSource, packageId);
                args.Add("-source");
                args.Add(packageSource);
            }
            else
            {
                logger?.Debug(
                    "There is no package source defined i app settings, key '{PackageSourceAppSettingsKey}', using all sources",
                    packageSourceAppSettingsKey);
            }

            args.Add("-AllVersions");
            args.Add("-NonInteractive");
            args.Add("-Verbosity");
            args.Add("normal");

            string configFile =
                nugetConfigFile.WithDefault(_keyValueConfiguration[ConfigurationConstants.NugetConfigFile]);

            if (configFile.HasValue() && File.Exists(configFile))
            {
                _logger.Debug("Using NuGet config file {NuGetConfigFile} for package {Package}", configFile, packageId);
                args.Add("-ConfigFile");
                args.Add(configFile);
            }

            var builder    = new List <string>();
            var errorBuild = new List <string>();

            logger?.Debug("Running NuGet from package service to find packages with timeout {Seconds} seconds",
                          _deploymentConfiguration.ListTimeOutInSeconds);

            ExitCode exitCode;

            using (var cancellationTokenSource =
                       new CancellationTokenSource(TimeSpan.FromSeconds(_deploymentConfiguration.ListTimeOutInSeconds)))
            {
                using (CancellationTokenSource linked =
                           CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, cancellationTokenSource.Token))
                {
                    exitCode = await ProcessRunner.ExecuteProcessAsync(nugetExe,
                                                                       args,
                                                                       (message, category) =>
                    {
                        builder.Add(message);
                        _logger.Debug("{Category} {Message}", category, message);
                    },
                                                                       (message, category) =>
                    {
                        errorBuild.Add(message);
                        _logger.Error("{Category} {Message}", category, message);
                    },
                                                                       (message, category) => _logger.Debug("{Category} {ProcessToolMessage}", category, message),
                                                                       (message, category) => _logger.Verbose("{Category} {ProcessToolMessage}", category, message),
                                                                       cancellationToken : linked.Token);
                }
            }

            string standardOut      = string.Join(Environment.NewLine, builder);
            string standardErrorOut = string.Join(Environment.NewLine, errorBuild);

            if (!exitCode.IsSuccess)
            {
                var sources      = new List <string>();
                var sourcesError = new List <string>();

                var sourcesArgs = new List <string> {
                    "sources"
                };

                if (configFile.HasValue() && File.Exists(configFile))
                {
                    sourcesArgs.Add("-ConfigFile");
                    sourcesArgs.Add(configFile);
                }

                sourcesArgs.Add("-NonInteractive");

                if (_logger.IsEnabled(LogEventLevel.Debug) || _logger.IsEnabled(LogEventLevel.Verbose))
                {
                    sourcesArgs.Add("-Verbosity");
                    sourcesArgs.Add("detailed");
                }

                await ProcessRunner.ExecuteProcessAsync(nugetExe,
                                                        sourcesArgs,
                                                        (message, _) => sources.Add(message),
                                                        (message, _) => sourcesError.Add(message),
                                                        (message, category) => _logger.Information("{Category} {ProcessToolMessage}", category, message),
                                                        (message, category) => _logger.Verbose("{Category} {ProcessToolMessage}", category, message),
                                                        cancellationToken : cancellationToken);

                string sourcesOut      = string.Join(Environment.NewLine, sources);
                string sourcesErrorOut = string.Join(Environment.NewLine, sourcesError);

                _logger.Error(
                    "Exit code {Code} when running NuGet list packages; standard out '{StandardOut}', standard error '{StandardErrorOut}', exe path '{NugetExe}', arguments '{Arguments}', nuget sources '{SourcesOut}', sources error '{SourcesErrorOut}'",
                    exitCode.Code,
                    standardOut,
                    standardErrorOut,
                    nugetExe,
                    string.Join(" ", args),
                    sourcesOut,
                    sourcesErrorOut);

                return(Array.Empty <PackageVersion>());
            }

            var ignoredOutputStatements = new List <string> {
                "Using credentials", "No packages found"
            };

            List <string> included =
                builder.Where(line => !ignoredOutputStatements.Any(ignored =>
                                                                   line.IndexOf(ignored, StringComparison.InvariantCultureIgnoreCase) >= 0))
                .ToList();

            List <PackageVersion> items = included.Select(
                package =>
            {
                string[] parts = package.Split(' ');

                string currentPackageId = parts[0];

                try
                {
                    string version = parts.Last();

                    if (!SemanticVersion.TryParse(version, out SemanticVersion semanticVersion))
                    {
                        _logger.Debug(
                            "Found package version {Version} for package {Package}, skipping because it could not be parsed as semantic version",
                            version,
                            currentPackageId);
                        return(null);
                    }

                    if (!packageId.Equals(currentPackageId, StringComparison.OrdinalIgnoreCase))
                    {
                        _logger.Debug(
                            "Found package {Package}, skipping because it does match requested package {RequestedPackage}",
                            currentPackageId,
                            packageId);

                        return(null);
                    }

                    return(new PackageVersion(packageId, semanticVersion));
                }
                catch (Exception ex) when(!ex.IsFatal())
                {
                    _logger.Warning(ex, "Error parsing package '{Package}'", package);
                    return(null);
                }
            })
                                          .Where(packageVersion => packageVersion != null)
                                          .OrderBy(packageVersion => packageVersion.PackageId)
                                          .ThenByDescending(packageVersion => packageVersion.Version)
                                          .ToList();

            var addedPackages = new List <string>();

            foreach (PackageVersion packageVersion in items)
            {
                addedPackages.Add(packageVersion.ToString());
            }

            if (_logger.IsEnabled(LogEventLevel.Verbose))
            {
                _logger.Verbose("Added {Count} packages to in-memory cache with cache key {CacheKey} {PackageVersions}",
                                addedPackages.Count,
                                cacheKey,
                                addedPackages);
            }
            else if (addedPackages.Count > 0 && addedPackages.Count < 20)
            {
                _logger.Information(
                    "Added {Count} packages to in-memory cache with cache key {CacheKey} {PackageVersions}",
                    addedPackages.Count,
                    cacheKey,
                    addedPackages);
            }
            else if (addedPackages.Any())
            {
                _logger.Information("Added {Count} packages to in-memory cache with cache key {CacheKey}",
                                    addedPackages.Count,
                                    cacheKey);
            }

            if (addedPackages.Any())
            {
                _memoryCache.Set(cacheKey, items);
            }
            else
            {
                _logger.Debug("Added no packages to in-memory cache for cache key {CacheKey}", cacheKey);
            }

            return(items);
        }
Ejemplo n.º 14
0
        private static ExitCodes OnInstallCommand(string versionJsonRoot, string version, IReadOnlyList <string> sources)
        {
            if (!SemanticVersion.TryParse(string.IsNullOrEmpty(version) ? DefaultVersionSpec : version, out var semver))
            {
                Console.Error.WriteLine($"\"{version}\" is not a semver-compliant version spec.");
                return(ExitCodes.InvalidVersionSpec);
            }

            var options = new VersionOptions
            {
                Version = semver,
                PublicReleaseRefSpec = new string[]
                {
                    @"^refs/heads/master$",
                    @"^refs/heads/v\d+(?:\.\d+)?$",
                },
                CloudBuild = new VersionOptions.CloudBuildOptions
                {
                    BuildNumber = new VersionOptions.CloudBuildNumberOptions
                    {
                        Enabled = true,
                    },
                },
            };
            string searchPath = GetSpecifiedOrCurrentDirectoryPath(versionJsonRoot);

            if (!Directory.Exists(searchPath))
            {
                Console.Error.WriteLine("\"{0}\" is not an existing directory.", searchPath);
                return(ExitCodes.NoGitRepo);
            }

            var repository = GitExtensions.OpenGitRepo(searchPath);

            if (repository == null)
            {
                Console.Error.WriteLine("No git repo found at or above: \"{0}\"", searchPath);
                return(ExitCodes.NoGitRepo);
            }

            if (string.IsNullOrEmpty(versionJsonRoot))
            {
                versionJsonRoot = repository.Info.WorkingDirectory;
            }

            var existingOptions = VersionFile.GetVersion(versionJsonRoot);

            if (existingOptions != null)
            {
                if (!string.IsNullOrEmpty(version))
                {
                    var setVersionExitCode = OnSetVersionCommand(versionJsonRoot, version);
                    if (setVersionExitCode != ExitCodes.OK)
                    {
                        return(setVersionExitCode);
                    }
                }
            }
            else
            {
                string versionJsonPath = VersionFile.SetVersion(versionJsonRoot, options);
                LibGit2Sharp.Commands.Stage(repository, versionJsonPath);
            }

            // Create/update the Directory.Build.props file in the directory of the version.json file to add the NB.GV package.
            string directoryBuildPropsPath = Path.Combine(versionJsonRoot, "Directory.Build.props");

            MSBuild.Project propsFile;
            if (File.Exists(directoryBuildPropsPath))
            {
                propsFile = new MSBuild.Project(directoryBuildPropsPath);
            }
            else
            {
                propsFile = new MSBuild.Project();
            }

            const string PackageReferenceItemType = "PackageReference";

            if (!propsFile.GetItemsByEvaluatedInclude(PackageId).Any(i => i.ItemType == "PackageReference"))
            {
                // Validate given sources
                foreach (var source in sources)
                {
                    if (!Uri.TryCreate(source, UriKind.Absolute, out var _))
                    {
                        Console.Error.WriteLine($"\"{source}\" is not a valid NuGet package source.");
                        return(ExitCodes.InvalidNuGetPackageSource);
                    }
                }

                string packageVersion = GetLatestPackageVersionAsync(PackageId, versionJsonRoot, sources).GetAwaiter().GetResult();
                if (string.IsNullOrEmpty(packageVersion))
                {
                    string verifyPhrase = sources.Any()
                        ? "Please verify the given 'source' option(s)."
                        : "Please verify the package sources in the NuGet.Config files.";
                    Console.Error.WriteLine($"Latest stable version of the {PackageId} package could not be determined. " + verifyPhrase);
                    return(ExitCodes.PackageIdNotFound);
                }

                propsFile.AddItem(
                    PackageReferenceItemType,
                    PackageId,
                    new Dictionary <string, string>
                {
                    { "Version", packageVersion },
                    { "PrivateAssets", "all" },
                });

                propsFile.Save(directoryBuildPropsPath);
            }

            LibGit2Sharp.Commands.Stage(repository, directoryBuildPropsPath);

            return(ExitCodes.OK);
        }
Ejemplo n.º 15
0
        // TODO: refresh the file when it gets old
        public override async Task <Tuple <bool, INuGetResource> > TryCreate(SourceRepository source, CancellationToken token)
        {
            ServiceIndexResourceV3 index = null;

            var url = source.PackageSource.Source;

            // the file type can easily rule out if we need to request the url
            if (source.PackageSource.ProtocolVersion == 3 ||
                (source.PackageSource.IsHttp &&
                 url.EndsWith(".json", StringComparison.OrdinalIgnoreCase)))
            {
                ServiceIndexCacheInfo cacheInfo;
                // check the cache before downloading the file
                if (!_cache.TryGetValue(url, out cacheInfo) ||
                    UtcNow - cacheInfo.CachedTime > MaxCacheDuration)
                {
                    var messageHandlerResource = await source.GetResourceAsync <HttpHandlerResource>(token);

                    var client = new DataClient(messageHandlerResource.MessageHandler);

                    JObject json;

                    try
                    {
                        json = await client.GetJObjectAsync(new Uri(url), token);
                    }
                    catch (JsonReaderException)
                    {
                        _cache.TryAdd(url, new ServiceIndexCacheInfo {
                            CachedTime = UtcNow
                        });
                        return(new Tuple <bool, INuGetResource>(false, null));
                    }
                    catch (HttpRequestException)
                    {
                        _cache.TryAdd(url, new ServiceIndexCacheInfo {
                            CachedTime = UtcNow
                        });
                        return(new Tuple <bool, INuGetResource>(false, null));
                    }

                    if (json != null)
                    {
                        // Use SemVer instead of NuGetVersion, the service index should always be
                        // in strict SemVer format
                        SemanticVersion version;
                        JToken          versionToken;
                        if (json.TryGetValue("version", out versionToken) &&
                            versionToken.Type == JTokenType.String &&
                            SemanticVersion.TryParse((string)versionToken, out version) &&
                            version.Major == 3)
                        {
                            index = new ServiceIndexResourceV3(json, UtcNow);
                        }
                    }
                }
                else
                {
                    index = cacheInfo.Index;
                }

                // cache the value even if it is null to avoid checking it again later
                _cache.TryAdd(url, new ServiceIndexCacheInfo {
                    CachedTime = UtcNow, Index = index
                });
            }

            return(new Tuple <bool, INuGetResource>(index != null, index));
        }
Ejemplo n.º 16
0
        /// <summary>
        /// Task execution override
        /// </summary>
        /// <returns>
        /// True if successful
        /// False otherwise
        /// </returns>
        public override Boolean Execute()
        {
            try
            {
                Debug.WriteLine("\n=== NuPackage on {0} ===", (object)Path.GetFileName(ProjectPath));

                // we must check the tool version that used to edit the NuBuild project,
                // if that is higher than the current, than there is a good chance that a new feature is used
                // in that case we can't build the packages with an older NuBuild framework
                // this is usefull with multiple developers and/or CI/TFS server
                string          assemblyInformationalVersion = FileVersionInfo.GetVersionInfo(Assembly.GetExecutingAssembly().Location).ProductVersion;
                SemanticVersion semanticToolVersionInProject;
                if (SemanticVersion.TryParse(ToolVersion, out semanticToolVersionInProject) &&
                    semanticToolVersionInProject > SemanticVersion.Parse(assemblyInformationalVersion))
                {
                    Log.LogError("The project properties are edited with a higher version NuBuild ({0}). Update the NuBuild project system from {1} to the latest version!",
                                 semanticToolVersionInProject, assemblyInformationalVersion);
                    return(false);
                }

                // prepare the task for execution
                if (this.ReferenceProjects == null)
                {
                    this.ReferenceProjects = new ITaskItem[0];
                }
                if (this.ReferenceLibraries == null)
                {
                    this.ReferenceLibraries = new ITaskItem[0];
                }
                if (!Path.IsPathRooted(this.OutputPath))
                {
                    this.OutputPath = Path.GetFullPath(this.OutputPath);
                }
                if (!Directory.Exists(this.OutputPath))
                {
                    Directory.CreateDirectory(this.OutputPath);
                }
                propertyProvider = new PropertyProvider(ProjectPath, this.ReferenceLibraries
                                                        .ValidReferenceLibraryForBinaryNuSource()
                                                        .ValidReferenceLibraryForPropertyProvider()
                                                        .ToArray());

                // remove previous outputs (.nupkg and .nupkgs files)
                var nupkgsFullPath = ProjectHelper.GetNupkgsFullPath(ProjectPath, OutputPath);
                if (File.Exists(nupkgsFullPath))
                {
                    foreach (var pkgPath in System.IO.File.ReadAllLines(nupkgsFullPath))
                    {
                        if (File.Exists(pkgPath))
                        {
                            File.Delete(pkgPath);
                        }
                    }
                    File.Delete(nupkgsFullPath);
                }
                // write out the new .nupkgs intermediate file
                System.IO.File.WriteAllLines(nupkgsFullPath, this.NuSpec.Select(ti => ti.GetMetadata("NuPackagePath")), System.Text.Encoding.UTF8);
                // compile the nuget packages
                foreach (var specItem in this.NuSpec)
                {
                    BuildPackage(specItem);
                }
            }
            catch (Exception e)
            {
                Log.LogError("{0} ({1})", e.ToString(), e.GetType().Name);
                return(false);
            }
            return(true);
        }
Ejemplo n.º 17
0
        PackageVersion DeserializePackageVersion(XElement node)
        {
            var version    = new PackageVersion();
            var elements   = node.Elements().ToList();
            var attributes = node.Attributes().ToList();

            foreach (var element in elements)
            {
                if (element.IsEmpty)
                {
                    continue;
                }
                setProp(element.Name.LocalName, element.Value);
            }
            foreach (var attribute in attributes)
            {
                setProp(attribute.Name.LocalName, attribute.Value);
            }

            return(version);

            void setProp(string propertyName, string value)
            {
                if (propertyName == "CPU") // CPU was removed in OpenTAP 9.0. This is to support packages created by TAP 8x
                {
                    propertyName = "Architecture";
                }

                var prop = typeof(PackageVersion).GetProperty(propertyName);

                if (prop == null)
                {
                    return;
                }
                if (prop.PropertyType.IsEnum)
                {
                    prop.SetValue(version, Enum.Parse(prop.PropertyType, value));
                }
                else if (prop.PropertyType.HasInterface <IList <string> >())
                {
                    var list = new List <string>();
                    list.Add(value);
                    prop.SetValue(version, list);
                }
                else if (prop.PropertyType == typeof(SemanticVersion))
                {
                    if (SemanticVersion.TryParse(value, out var semver))
                    {
                        prop.SetValue(version, semver);
                    }
                    else
                    {
                        Log.Warning($"Cannot parse version '{value}' of package '{version.Name ?? "Unknown"}'.");
                    }
                }
                else if (prop.PropertyType == typeof(DateTime))
                {
                    if (DateTime.TryParse(value, out var date))
                    {
                        prop.SetValue(version, date);
                    }
                }
                else
                {
                    prop.SetValue(version, value);
                }
            }
        }
Ejemplo n.º 18
0
        private static ExitCodes OnPrepareReleaseCommand(string projectPath, string prereleaseTag, string nextVersion)
        {
            // validate project path property
            string searchPath = GetSpecifiedOrCurrentDirectoryPath(projectPath);

            if (!Directory.Exists(searchPath))
            {
                Console.Error.WriteLine($"\"{searchPath}\" is not an existing directory.");
                return(ExitCodes.NoGitRepo);
            }

            // parse nextVersion if parameter was specified
            SemanticVersion nextVersionParsed = default;

            if (!string.IsNullOrEmpty(nextVersion))
            {
                if (!SemanticVersion.TryParse(nextVersion, out nextVersionParsed))
                {
                    Console.Error.WriteLine($"\"{nextVersion}\" is not a semver-compliant version spec.");
                    return(ExitCodes.InvalidVersionSpec);
                }
            }

            // run prepare-release
            try
            {
                var releaseManager = new ReleaseManager(Console.Out, Console.Error);
                releaseManager.PrepareRelease(searchPath, prereleaseTag, nextVersionParsed);
                return(ExitCodes.OK);
            }
            catch (ReleaseManager.ReleasePreparationException ex)
            {
                // map error codes
                switch (ex.Error)
                {
                case ReleaseManager.ReleasePreparationError.NoGitRepo:
                    return(ExitCodes.NoGitRepo);

                case ReleaseManager.ReleasePreparationError.UncommittedChanges:
                    return(ExitCodes.UncommittedChanges);

                case ReleaseManager.ReleasePreparationError.InvalidBranchNameSetting:
                    return(ExitCodes.InvalidBranchNameSetting);

                case ReleaseManager.ReleasePreparationError.NoVersionFile:
                    return(ExitCodes.NoVersionJsonFound);

                case ReleaseManager.ReleasePreparationError.VersionDecrement:
                    return(ExitCodes.InvalidVersionSpec);

                case ReleaseManager.ReleasePreparationError.BranchAlreadyExists:
                    return(ExitCodes.BranchAlreadyExists);

                case ReleaseManager.ReleasePreparationError.UserNotConfigured:
                    return(ExitCodes.UserNotConfigured);

                case ReleaseManager.ReleasePreparationError.DetachedHead:
                    return(ExitCodes.DetachedHead);

                default:
                    Report.Fail($"{nameof(ReleaseManager.ReleasePreparationError)}: {ex.Error}");
                    return((ExitCodes)(-1));
                }
            }
        }
Ejemplo n.º 19
0
        static async Task <int> CommandDemoteAsync([NotNull] DemoteOptions options, [NotNull] ISnapFilesystem filesystem,
                                                   [NotNull] ISnapAppReader snapAppReader, [NotNull] ISnapAppWriter snapAppWriter, [NotNull] INuGetPackageSources nuGetPackageSources,
                                                   [NotNull] INugetService nugetService, [NotNull] IDistributedMutexClient distributedMutexClient,
                                                   [NotNull] ISnapPackageManager snapPackageManager, [NotNull] ISnapPack snapPack,
                                                   [NotNull] ISnapNetworkTimeProvider snapNetworkTimeProvider, [NotNull] ISnapExtractor snapExtractor, [NotNull] ISnapOs snapOs,
                                                   [NotNull] ISnapxEmbeddedResources snapxEmbeddedResources, [NotNull] ICoreRunLib coreRunLib,
                                                   [NotNull] ILog logger, [NotNull] string workingDirectory, CancellationToken cancellationToken)
        {
            if (options == null)
            {
                throw new ArgumentNullException(nameof(options));
            }
            if (filesystem == null)
            {
                throw new ArgumentNullException(nameof(filesystem));
            }
            if (snapAppReader == null)
            {
                throw new ArgumentNullException(nameof(snapAppReader));
            }
            if (snapAppWriter == null)
            {
                throw new ArgumentNullException(nameof(snapAppWriter));
            }
            if (nuGetPackageSources == null)
            {
                throw new ArgumentNullException(nameof(nuGetPackageSources));
            }
            if (nugetService == null)
            {
                throw new ArgumentNullException(nameof(nugetService));
            }
            if (distributedMutexClient == null)
            {
                throw new ArgumentNullException(nameof(distributedMutexClient));
            }
            if (snapPackageManager == null)
            {
                throw new ArgumentNullException(nameof(snapPackageManager));
            }
            if (snapPack == null)
            {
                throw new ArgumentNullException(nameof(snapPack));
            }
            if (snapNetworkTimeProvider == null)
            {
                throw new ArgumentNullException(nameof(snapNetworkTimeProvider));
            }
            if (snapExtractor == null)
            {
                throw new ArgumentNullException(nameof(snapExtractor));
            }
            if (snapOs == null)
            {
                throw new ArgumentNullException(nameof(snapOs));
            }
            if (snapxEmbeddedResources == null)
            {
                throw new ArgumentNullException(nameof(snapxEmbeddedResources));
            }
            if (coreRunLib == null)
            {
                throw new ArgumentNullException(nameof(coreRunLib));
            }
            if (logger == null)
            {
                throw new ArgumentNullException(nameof(logger));
            }
            if (workingDirectory == null)
            {
                throw new ArgumentNullException(nameof(workingDirectory));
            }
            if (options == null)
            {
                throw new ArgumentNullException(nameof(options));
            }
            if (nugetService == null)
            {
                throw new ArgumentNullException(nameof(nugetService));
            }

            var stopwatch = new Stopwatch();

            stopwatch.Restart();

            var             anyRid             = options.Rid == null;
            var             anyVersion         = options.FromVersion == null;
            SnapApp         anyRidSnapApp      = null;
            SemanticVersion fromVersion        = null;
            var             runtimeIdentifiers = new List <string>();

            if (!anyVersion)
            {
                if (!SemanticVersion.TryParse(options.FromVersion, out fromVersion))
                {
                    Console.WriteLine($"Unable to parse from version: {options.FromVersion}");
                    return(1);
                }

                if (!options.RemoveAll)
                {
                    Console.WriteLine("You must specify --remove-all if you want to demote releases newer than --from-version.");
                    return(1);
                }
            }

            var snapApps = BuildSnapAppsFromDirectory(filesystem, snapAppReader, workingDirectory);

            if (!snapApps.Apps.Any())
            {
                return(1);
            }

            foreach (var snapsApp in snapApps.Apps)
            {
                foreach (var target in snapsApp.Targets.Where(target =>
                                                              anyRid || string.Equals(options.Rid, target.Rid, StringComparison.OrdinalIgnoreCase)))
                {
                    anyRidSnapApp = snapApps.BuildSnapApp(snapsApp.Id, target.Rid, nuGetPackageSources, filesystem);
                    runtimeIdentifiers.AddRange(snapApps.GetRids(anyRidSnapApp));
                    break;
                }
            }

            if (anyRidSnapApp == null)
            {
                if (anyRid)
                {
                    logger.Error($"Unable to find application with id: {options.Id}.");
                    return(1);
                }

                logger.Error($"Unable to find application with id: {options.Id}. Rid: {options.Rid}");
                return(1);
            }

            logger.Info('-'.Repeat(TerminalBufferWidth));

            Console.WriteLine($"Demoting application with id: {anyRidSnapApp.Id}.");
            Console.WriteLine($"Runtime identifiers (RID): {string.Join(", ", runtimeIdentifiers)}");

            if (anyRid)
            {
                if (!logger.Prompt("y|yes", "You have not specified a rid, all releases in listed runtime identifiers will be removed. " +
                                   "Do you want to continue? [y|n]")
                    )
                {
                    return(1);
                }
            }

            MaybeOverrideLockToken(snapApps, logger, options.Id, options.LockToken);

            if (string.IsNullOrWhiteSpace(snapApps.Generic.Token))
            {
                logger.Error("Please specify a token in your snapx.yml file. A random UUID is sufficient.");
                return(1);
            }

            logger.Info('-'.Repeat(TerminalBufferWidth));

            var packagesDirectory = BuildPackagesDirectory(filesystem, workingDirectory);

            filesystem.DirectoryCreateIfNotExists(packagesDirectory);

            await using var distributedMutex = WithDistributedMutex(distributedMutexClient, logger,
                                                                    snapApps.BuildLockKey(anyRidSnapApp), cancellationToken);

            var tryAcquireRetries = options.LockRetries == -1 ? int.MaxValue : options.LockRetries;

            if (!await distributedMutex.TryAquireAsync(TimeSpan.FromSeconds(15), tryAcquireRetries))
            {
                logger.Info('-'.Repeat(TerminalBufferWidth));
                return(1);
            }

            logger.Info('-'.Repeat(TerminalBufferWidth));

            logger.Info("Downloading releases nupkg.");

            var(snapAppsReleases, _, currentReleasesMemoryStream) = await snapPackageManager
                                                                    .GetSnapsReleasesAsync(anyRidSnapApp, logger, cancellationToken);

            if (currentReleasesMemoryStream != null)
            {
                await currentReleasesMemoryStream.DisposeAsync();
            }

            if (snapAppsReleases == null)
            {
                return(1);
            }

            if (!snapAppsReleases.Any())
            {
                logger.Error($"Releases nupkg does not contain application id: {anyRidSnapApp.Id}");
                return(1);
            }


            logger.Info($"Downloaded releases nupkg. Current version: {snapAppsReleases.Version}.");

            var snapAppReleases = options.RemoveAll ?
                                  snapAppsReleases.GetReleases(anyRidSnapApp, x =>
            {
                bool VersionFilter()
                {
                    return(anyVersion || x.Version > fromVersion);
                }

                bool RidFilter()
                {
                    return(anyRid || x.Target.Rid == anyRidSnapApp.Target.Rid);
                }

                return(RidFilter() && VersionFilter());
            }) :
                                  snapAppsReleases.GetMostRecentReleases(anyRidSnapApp, x => anyRid || x.Target.Rid == anyRidSnapApp.Target.Rid);

            if (!snapAppReleases.Any())
            {
                logger.Error("Unable to find any releases that matches demotion criterias.");
                return(1);
            }

            logger.Info('-'.Repeat(TerminalBufferWidth));

            var consoleTable = new ConsoleTable("Rid", "Channels", "Version", "Count")
            {
                Header = $"Demote summary overview. Total releases: {snapAppReleases.Count()}."
            };

            foreach (var(rid, releases) in snapAppReleases.ToDictionaryByKey(x => x.Target.Rid))
            {
                var channels       = releases.SelectMany(x => x.Channels).Distinct().ToList();
                var releaseVersion = options.RemoveAll ? "All versions" : releases.First().Version.ToString();
                consoleTable.AddRow(new object[]
                {
                    rid,
                    string.Join(", ", channels),
                    releaseVersion,
                    releases.Count.ToString()
                });
            }

            consoleTable.Write(logger);

            if (!logger.Prompt("y|yes", "Ready to demote releases. Do you want to continue? [y|n]"))
            {
                return(1);
            }

            logger.Info('-'.Repeat(TerminalBufferWidth));
            logger.Info($"Retrieving network time from: {snapNetworkTimeProvider}.");

            var nowUtc = await SnapUtility.RetryAsync(async() => await snapNetworkTimeProvider.NowUtcAsync(), 3);

            if (!nowUtc.HasValue)
            {
                logger.Error($"Unknown error retrieving network time from: {snapNetworkTimeProvider}");
                return(1);
            }

            var localTimeStr = TimeZoneInfo
                               .ConvertTimeFromUtc(nowUtc.Value, TimeZoneInfo.Local)
                               .ToString("F", CultureInfo.CurrentCulture);

            logger.Info($"Successfully retrieved network time. Time is now: {localTimeStr}");
            logger.Info('-'.Repeat(TerminalBufferWidth));

            var snapAppsReleasesDemotedCount = snapAppsReleases.Demote(snapAppReleases);

            if (snapAppsReleasesDemotedCount != snapAppReleases.Count())
            {
                logger.Error("Unknown error when removing demoted releases. " +
                             $"Expected to remove {snapAppReleases.Count()} but only {snapAppsReleasesDemotedCount} was removed.");
                return(1);
            }

            logger.Info("Building releases nupkg. " +
                        $"Current database version: {snapAppsReleases.Version}. " +
                        $"Releases count: {snapAppsReleases.Count()}.");

            var releasesMemoryStream = !snapAppsReleases.Any() ?
                                       snapPack.BuildEmptyReleasesPackage(anyRidSnapApp, snapAppsReleases) :
                                       snapPack.BuildReleasesPackage(anyRidSnapApp, snapAppsReleases);

            var releasesNupkgAbsolutePath = snapOs.Filesystem.PathCombine(packagesDirectory, anyRidSnapApp.BuildNugetReleasesFilename());
            var releasesNupkgFilename     = filesystem.PathGetFileName(releasesNupkgAbsolutePath);
            await snapOs.Filesystem.FileWriteAsync(releasesMemoryStream, releasesNupkgAbsolutePath, cancellationToken);

            logger.Info("Finished building releases nupkg.\n" +
                        $"Filename: {releasesNupkgFilename}.\n" +
                        $"Size: {releasesMemoryStream.Length.BytesAsHumanReadable()}.\n" +
                        $"New database version: {snapAppsReleases.Version}.\n" +
                        $"Pack id: {snapAppsReleases.PackId:N}.");

            logger.Info('-'.Repeat(TerminalBufferWidth));

            var anySnapTargetDefaultChannel = anyRidSnapApp.Channels.First();
            var nugetSources  = anyRidSnapApp.BuildNugetSources(filesystem.PathGetTempPath());
            var packageSource = nugetSources.Items.Single(x => x.Name == anySnapTargetDefaultChannel.PushFeed.Name);

            await PushPackageAsync(nugetService, filesystem, distributedMutex, nuGetPackageSources, packageSource,
                                   anySnapTargetDefaultChannel, releasesNupkgAbsolutePath, cancellationToken, logger);

            await BlockUntilSnapUpdatedReleasesNupkgAsync(logger, snapPackageManager, snapAppsReleases, anyRidSnapApp,
                                                          anySnapTargetDefaultChannel, TimeSpan.FromSeconds(15), cancellationToken);

            logger.Info('-'.Repeat(TerminalBufferWidth));

            await CommandRestoreAsync(new RestoreOptions
            {
                Id              = anyRidSnapApp.Id,
                Rid             = anyRid ? null : anyRidSnapApp.Target.Rid,
                BuildInstallers = true
            }, filesystem, snapAppReader, snapAppWriter,
                                      nuGetPackageSources, snapPackageManager, snapOs, snapxEmbeddedResources,
                                      coreRunLib, snapPack, logger, workingDirectory, cancellationToken);

            logger.Info('-'.Repeat(TerminalBufferWidth));

            logger.Info($"Fetching releases overview from feed: {anySnapTargetDefaultChannel.PushFeed.Name}");

            await CommandListAsync(new ListOptions { Id = anyRidSnapApp.Id }, filesystem, snapAppReader,
                                   nuGetPackageSources, nugetService, snapExtractor, logger, workingDirectory, cancellationToken);

            logger.Info('-'.Repeat(TerminalBufferWidth));
            logger.Info($"Demote completed in {stopwatch.Elapsed.TotalSeconds:F1}s.");

            return(0);
        }
Ejemplo n.º 20
0
        /// <summary>Loads content packs and vanilla doors.</summary>
        /// <returns>The loaded doors.</returns>
        public IList <ContentPackDoor> LoadContentPacks()
        {
            IList <ContentPackDoor> data = new List <ContentPackDoor>();

            // Validate each pack and load the tile sheets referenced in the process.
            foreach (IContentPack contentPack in this.helper.ContentPacks.GetOwned())
            {
                if (contentPack.Manifest.UniqueID.Equals("vanilla", StringComparison.InvariantCultureIgnoreCase))
                {
                    this.errorQueue.AddError($"{contentPack.Manifest.Name} ({contentPack.Manifest.UniqueID}) - A content pack's unique id can't be {contentPack.Manifest.UniqueID}. This pack won't be loaded.");
                    continue;
                }

                ContentPack loadedPack = contentPack.ReadJsonFile <ContentPack>("content.json");

                if (!SemanticVersion.TryParse(loadedPack.Version, out ISemanticVersion version))
                {
                    this.errorQueue.AddError($"{contentPack.Manifest.Name} ({contentPack.Manifest.UniqueID}) - The version ({loadedPack.Version}) is invalid. This pack won't be loaded.");
                    continue;
                }

                if (version.IsNewerThan(this.helper.ModRegistry.Get(this.helper.ModRegistry.ModID).Manifest.Version))
                {
                    this.errorQueue.AddError($"{contentPack.Manifest.Name} ({contentPack.Manifest.UniqueID}) - ({loadedPack.Version}) is too new to be loaded. Please update Better Doors!");
                    continue;
                }

                if (!version.Equals(new SemanticVersion("1.0.0")))
                {
                    this.errorQueue.AddError($"{contentPack.Manifest.Name} ({contentPack.Manifest.UniqueID}) - Unrecognized content pack version: {loadedPack.Version}. This pack won't be loaded.");
                    continue;
                }

                ISet <string> doorNames = new HashSet <string>(StringComparer.InvariantCultureIgnoreCase);

                foreach (KeyValuePair <string, IList <string> > entry in loadedPack.Doors)
                {
                    if (!File.Exists(Path.Combine(contentPack.DirectoryPath, entry.Key)))
                    {
                        this.QueueError(contentPack, entry.Key, $"{entry.Key} doesn't exist", false);
                        continue;
                    }

                    string    imageError  = null;
                    Texture2D spriteSheet = null;

                    try
                    {
                        spriteSheet = contentPack.LoadAsset <Texture2D>(entry.Key);

                        if (spriteSheet.Width % 64 != 0 || spriteSheet.Height % 48 != 0)
                        {
                            imageError = $"The dimensions of the sprite sheet are invalid. Must be a multiple of 64 x 48. Instead, they are {spriteSheet.Width} x {spriteSheet.Height}";
                        }
                    }
                    catch (ContentLoadException)
                    {
                        imageError = $"{entry.Key} isn't a valid image";
                    }

                    if (imageError != null)
                    {
                        this.QueueError(contentPack, entry.Key, imageError, false);
                        continue;
                    }

                    int count = 0;
                    foreach (string doorName in entry.Value)
                    {
                        string nameError = null;

                        if (!doorNames.Add(doorName))
                        {
                            nameError = $"{doorName} is repeated more than once";
                        }
                        else if (doorName.Contains(" "))
                        {
                            nameError = $"{doorName} can't have spaces in it";
                        }

                        if (nameError != null)
                        {
                            this.QueueError(contentPack, entry.Key, nameError, true);
                            continue;
                        }

                        if (!Utils.IsValidTile(spriteSheet.Width, spriteSheet.Height, 16, count * 4, out string tileError))
                        {
                            this.QueueError(contentPack, entry.Key, tileError, true);
                            continue;
                        }

                        data.Add(new ContentPackDoor(contentPack.Manifest.UniqueID, spriteSheet, doorName, Utils.ConvertTileIndexToPosition(spriteSheet.Width, Utils.TileSize, count * 4)));

                        count++;
                    }
                }
            }

            this.monitor.Log($"Loaded {data.Count} door sprites from content packs.", LogLevel.Trace);

            this.errorQueue.PrintErrors("Found some errors when loading door sprites from content packs:");

            // Also load the vanilla door textures.
            const string vanillaPath    = "LooseSprites/Cursors";
            Texture2D    vanillaTexture = this.helper.Content.Load <Texture2D>(vanillaPath, ContentSource.GameContent);

            data.Add(new ContentPackDoor("vanilla", vanillaTexture, "light", new Point(512, 144)));
            data.Add(new ContentPackDoor("vanilla", vanillaTexture, "window", new Point(576, 144)));
            data.Add(new ContentPackDoor("vanilla", vanillaTexture, "saloon", new Point(640, 144)));

            return(data);
        }
Ejemplo n.º 21
0
        public virtual async Task <ActionResult> GetPackage(string id, string version)
        {
            // some security paranoia about URL hacking somehow creating e.g. open redirects
            // validate user input: explicit calls to the same validators used during Package Registrations
            // Ideally shouldn't be necessary?
            if (!PackageIdValidator.IsValidPackageId(id ?? ""))
            {
                return(new HttpStatusCodeWithBodyResult(HttpStatusCode.BadRequest, "The format of the package id is invalid"));
            }

            if (!String.IsNullOrEmpty(version))
            {
                SemanticVersion dummy;
                if (!SemanticVersion.TryParse(version, out dummy))
                {
                    return(new HttpStatusCodeWithBodyResult(HttpStatusCode.BadRequest, "The package version is not a valid semantic version"));
                }
            }

            // if the version is null, the user is asking for the latest version. Presumably they don't want includePrerelease release versions.
            // The allow prerelease flag is ignored if both partialId and version are specified.
            // In general we want to try to add download statistics for any package regardless of whether a version was specified.
            try
            {
                Package package = PackageService.FindPackageByIdAndVersion(id, version, allowPrerelease: false);
                if (package == null)
                {
                    return(new HttpStatusCodeWithBodyResult(
                               HttpStatusCode.NotFound, String.Format(CultureInfo.CurrentCulture, Strings.PackageWithIdAndVersionNotFound, id, version)));
                }

                try
                {
                    var stats = new PackageStatistics
                    {
                        // IMPORTANT: Timestamp is managed by the database.
                        IPAddress        = Request.UserHostAddress,
                        UserAgent        = Request.UserAgent,
                        Package          = package,
                        Operation        = Request.Headers["NuGet-Operation"],
                        DependentPackage = Request.Headers["NuGet-DependentPackage"],
                        ProjectGuids     = Request.Headers["NuGet-ProjectGuids"],
                    };

                    PackageService.AddDownloadStatistics(stats);
                }
                catch (ReadOnlyModeException)
                {
                    // *gulp* Swallowed. It's OK not to add statistics and ok to not log errors in read only mode.
                }
                catch (SqlException e)
                {
                    // Log the error and continue
                    QuietlyLogException(e);
                }
                catch (DataException e)
                {
                    // Log the error and continue
                    QuietlyLogException(e);
                }

                return(await PackageFileService.CreateDownloadPackageActionResultAsync(HttpContext.Request.Url, package));
            }
            catch (SqlException e)
            {
                QuietlyLogException(e);
            }
            catch (DataException e)
            {
                QuietlyLogException(e);
            }

            // Fall back to constructing the URL based on the package version and ID.

            return(await PackageFileService.CreateDownloadPackageActionResultAsync(HttpContext.Request.Url, id, version));
        }
Ejemplo n.º 22
0
        public virtual async Task <ActionResult> GetPackage(string id, string version)
        {
            // some security paranoia about URL hacking somehow creating e.g. open redirects
            // validate user input: explicit calls to the same validators used during Package Registrations
            // Ideally shouldn't be necessary?
            if (!PackageIdValidator.IsValidPackageId(id ?? ""))
            {
                return(new HttpStatusCodeWithBodyResult(HttpStatusCode.BadRequest, "The format of the package id is invalid"));
            }

            if (!String.IsNullOrEmpty(version))
            {
                SemanticVersion dummy;
                if (!SemanticVersion.TryParse(version, out dummy))
                {
                    return(new HttpStatusCodeWithBodyResult(HttpStatusCode.BadRequest, "The package version is not a valid semantic version"));
                }
            }

            // Normalize the version
            version = SemanticVersionExtensions.Normalize(version);

            // if the version is null, the user is asking for the latest version. Presumably they don't want includePrerelease release versions.
            // The allow prerelease flag is ignored if both partialId and version are specified.
            // In general we want to try to add download statistics for any package regardless of whether a version was specified.

            // Only allow database requests to take up to 5 seconds.  Any longer and we just lose the data; oh well.
            EntitiesContext.SetCommandTimeout(5);

            Package package = null;

            try
            {
                package = PackageService.FindPackageByIdAndVersion(id, version, allowPrerelease: false);
                if (package == null)
                {
                    return(new HttpStatusCodeWithBodyResult(
                               HttpStatusCode.NotFound, String.Format(CultureInfo.CurrentCulture, Strings.PackageWithIdAndVersionNotFound, id, version)));
                }

                try
                {
                    var stats = new PackageStatistics
                    {
                        IPAddress        = Request.UserHostAddress,
                        UserAgent        = Request.UserAgent,
                        Package          = package,
                        Operation        = Request.Headers["NuGet-Operation"],
                        DependentPackage = Request.Headers["NuGet-DependentPackage"],
                        ProjectGuids     = Request.Headers["NuGet-ProjectGuids"],
                    };

                    if (_config == null || _config.MetricsServiceUri == null)
                    {
                        PackageService.AddDownloadStatistics(stats);
                    }
                    else
                    {
                        // Disable warning about not awaiting async calls because we are _intentionally_ not awaiting this.
#pragma warning disable 4014
                        Task.Run(() => PostDownloadStatistics(id, package.NormalizedVersion, stats.IPAddress, stats.UserAgent, stats.Operation, stats.DependentPackage, stats.ProjectGuids));
#pragma warning restore 4014
                    }
                }
                catch (ReadOnlyModeException)
                {
                    // *gulp* Swallowed. It's OK not to add statistics and ok to not log errors in read only mode.
                }
                catch (SqlException e)
                {
                    // Log the error and continue
                    QuietLog.LogHandledException(e);
                }
                catch (DataException e)
                {
                    // Log the error and continue
                    QuietLog.LogHandledException(e);
                }
            }
            catch (SqlException e)
            {
                QuietLog.LogHandledException(e);
            }
            catch (DataException e)
            {
                QuietLog.LogHandledException(e);
            }

            // Fall back to constructing the URL based on the package version and ID.
            if (String.IsNullOrEmpty(version) && package == null)
            {
                // Database was unavailable and we don't have a version, return a 503
                return(new HttpStatusCodeWithBodyResult(HttpStatusCode.ServiceUnavailable, Strings.DatabaseUnavailable_TrySpecificVersion));
            }
            return(await PackageFileService.CreateDownloadPackageActionResultAsync(
                       HttpContext.Request.Url,
                       id,
                       String.IsNullOrEmpty(version)?package.NormalizedVersion : version));
        }
Ejemplo n.º 23
0
        private static ExitCodes OnInstallCommand(string versionJsonRoot, string version)
        {
            if (!SemanticVersion.TryParse(string.IsNullOrEmpty(version) ? DefaultVersionSpec : version, out var semver))
            {
                Console.Error.WriteLine($"\"{version}\" is not a semver-compliant version spec.");
                return(ExitCodes.InvalidVersionSpec);
            }

            var options = new VersionOptions
            {
                Version = semver,
                PublicReleaseRefSpec = new string[]
                {
                    @"^refs/heads/master$",
                    @"^refs/heads/v\d+(?:\.\d+)?$",
                },
                CloudBuild = new VersionOptions.CloudBuildOptions
                {
                    BuildNumber = new VersionOptions.CloudBuildNumberOptions
                    {
                        Enabled = true,
                    },
                },
            };
            string searchPath = GetSpecifiedOrCurrentDirectoryPath(versionJsonRoot);

            if (!Directory.Exists(searchPath))
            {
                Console.Error.WriteLine("\"{0}\" is not an existing directory.", searchPath);
                return(ExitCodes.NoGitRepo);
            }

            var repository = GitExtensions.OpenGitRepo(searchPath);

            if (repository == null)
            {
                Console.Error.WriteLine("No git repo found at or above: \"{0}\"", searchPath);
                return(ExitCodes.NoGitRepo);
            }

            if (string.IsNullOrEmpty(versionJsonRoot))
            {
                versionJsonRoot = repository.Info.WorkingDirectory;
            }

            var existingOptions = VersionFile.GetVersion(versionJsonRoot);

            if (existingOptions != null)
            {
                if (!string.IsNullOrEmpty(version))
                {
                    var setVersionExitCode = OnSetVersionCommand(versionJsonRoot, version);
                    if (setVersionExitCode != ExitCodes.OK)
                    {
                        return(setVersionExitCode);
                    }
                }
            }
            else
            {
                string versionJsonPath = VersionFile.SetVersion(versionJsonRoot, options, includeSchemaProperty: true);
                LibGit2Sharp.Commands.Stage(repository, versionJsonPath);
            }

            // Create/update the Directory.Build.props file in the directory of the version.json file to add the NB.GV package.
            string directoryBuildPropsPath = Path.Combine(versionJsonRoot, "Directory.Build.props");

            MSBuild.Project propsFile;
            if (File.Exists(directoryBuildPropsPath))
            {
                propsFile = new MSBuild.Project(directoryBuildPropsPath);
            }
            else
            {
                propsFile = new MSBuild.Project();
            }

            const string PackageReferenceItemType = "PackageReference";
            const string PackageId = "Nerdbank.GitVersioning";

            if (!propsFile.GetItemsByEvaluatedInclude(PackageId).Any(i => i.ItemType == "PackageReference"))
            {
                string packageVersion = GetLatestPackageVersionAsync(PackageId).GetAwaiter().GetResult();
                propsFile.AddItem(
                    PackageReferenceItemType,
                    PackageId,
                    new Dictionary <string, string>
                {
                    { "Version", packageVersion },     // TODO: use the latest version... somehow...
                    { "PrivateAssets", "all" },
                });

                propsFile.Save(directoryBuildPropsPath);
            }

            LibGit2Sharp.Commands.Stage(repository, directoryBuildPropsPath);

            return(ExitCodes.OK);
        }
Ejemplo n.º 24
0
    public void ValidateInvalidVersionParsing(string versionString)
    {
        SemanticVersion version;

        Assert.IsFalse(SemanticVersion.TryParse(versionString, out version), "TryParse Result");
    }
Ejemplo n.º 25
0
        private static IDictionary <string, List <ServiceIndexEntry> > MakeLookup(JObject index)
        {
            var result = new Dictionary <string, List <ServiceIndexEntry> >(StringComparer.Ordinal);

            JToken resources;

            if (index.TryGetValue("resources", out resources))
            {
                foreach (var resource in resources)
                {
                    var id = GetValues(resource["@id"]).SingleOrDefault();

                    Uri uri;
                    if (string.IsNullOrEmpty(id) || !Uri.TryCreate(id, UriKind.Absolute, out uri))
                    {
                        // Skip invalid or missing @ids
                        continue;
                    }

                    var types = GetValues(resource["@type"]).ToArray();
                    var clientVersionToken = resource["clientVersion"];

                    var clientVersions = new List <SemanticVersion>();

                    if (clientVersionToken == null)
                    {
                        // For non-versioned services assume all clients are compatible
                        clientVersions.Add(_defaultVersion);
                    }
                    else
                    {
                        // Parse supported versions
                        foreach (var versionString in GetValues(clientVersionToken))
                        {
                            SemanticVersion version;
                            if (SemanticVersion.TryParse(versionString, out version))
                            {
                                clientVersions.Add(version);
                            }
                        }
                    }

                    // Create service entries
                    foreach (var type in types)
                    {
                        foreach (var version in clientVersions)
                        {
                            List <ServiceIndexEntry> entries;
                            if (!result.TryGetValue(type, out entries))
                            {
                                entries = new List <ServiceIndexEntry>();
                                result.Add(type, entries);
                            }

                            entries.Add(new ServiceIndexEntry(uri, type, version));
                        }
                    }
                }
            }

            // Order versions desc for faster lookup later.
            foreach (var type in result.Keys.ToArray())
            {
                result[type] = result[type].OrderByDescending(e => e.ClientVersion).ToList();
            }

            return(result);
        }
Ejemplo n.º 26
0
        public override bool Execute()
        {
            if (!SemanticVersion.TryParse(SdkVersion, out var currentSdkVersion))
            {
                Log.LogError($"Invalid version: {SdkVersion}");
                return(false);
            }

            var      globalJsonPath = Path.Combine(RepositoryRoot, "global.json");
            DateTime lastWrite;

            try
            {
                lastWrite = File.GetLastWriteTimeUtc(globalJsonPath);
            }
            catch (Exception e)
            {
                Log.LogError($"Error accessing file '{globalJsonPath}': {e.Message}");
                return(false);
            }

            var cachedResult = (CacheEntry)BuildEngine4.GetRegisteredTaskObject(s_cacheKey, RegisteredTaskObjectLifetime.Build);

            if (cachedResult != null && lastWrite == cachedResult.LastWrite)
            {
                // Error has already been reported if the current SDK version is not sufficient.
                if (!cachedResult.Success)
                {
                    Log.LogMessage(MessageImportance.Low, $"Previous .NET Core SDK version check failed.");
                }

                return(cachedResult.Success);
            }

            bool execute()
            {
                string globalJson;

                try
                {
                    globalJson = File.ReadAllText(globalJsonPath);
                }
                catch (Exception e)
                {
                    Log.LogError($"Error reading file '{globalJsonPath}': {e.Message}");
                    return(false);
                }

                // avoid Newtonsoft.Json dependency
                var match = Regex.Match(globalJson, $@"""dotnet""\s*:\s*""([^""]+)""");

                if (!match.Success)
                {
                    Log.LogError($"Unable to determine dotnet version from file '{globalJsonPath}'.");
                    return(false);
                }

                var minSdkVersionStr = match.Groups[1].Value;

                if (!SemanticVersion.TryParse(minSdkVersionStr, out var minSdkVersion))
                {
                    Log.LogError($"DotNet version specified in '{globalJsonPath}' is invalid: {minSdkVersionStr}.");
                    return(false);
                }

                if (currentSdkVersion < minSdkVersion)
                {
                    Log.LogError($"The .NET Core SDK version {currentSdkVersion} is below the minimum required version {minSdkVersion}. You can install newer .NET Core SDK from https://www.microsoft.com/net/download.");
                    return(false);
                }

                return(true);
            }

            bool success = execute();

            BuildEngine4.RegisterTaskObject(s_cacheKey, new CacheEntry(lastWrite, success), RegisteredTaskObjectLifetime.Build, allowEarlyCollection: true);
            return(success);
        }
Ejemplo n.º 27
0
 void Equal(string one, string two)
 {
     Assert.IsTrue(SemanticVersion.TryParse(one, out var v1));
     Assert.IsTrue(SemanticVersion.TryParse(two, out var v2));
     Assert.IsTrue(v1.CompareTo(v2) == 0);
 }
Ejemplo n.º 28
0
        /// <summary>
        /// Internal so available to unit tests
        /// </summary>
        internal static (IReadOnlyCollection <NuGetProject> Projects, Dictionary <string, SemanticVersion> HighestVersions) DeterminePackages(IEnumerable <IProject> applicationProjects, Func <IProject, string> loadDelegate)
        {
            var projects        = new List <NuGetProject>();
            var highestVersions = new Dictionary <string, SemanticVersion>();

            foreach (var project in applicationProjects.OrderBy(x => x.Name))
            {
                string projectContent = null;
                var    document       = project.ProjectFile() != null
                    ? XDocument.Parse(projectContent = loadDelegate(project))
                    : null;

                var projectType = ResolveNuGetScheme(document);
                if (!NuGetProjectSchemeProcessors.TryGetValue(projectType, out var processor))
                {
                    throw new ArgumentOutOfRangeException(nameof(projectType), $"No scheme registered for type {projectType}.");
                }

                var installedPackages = processor.GetInstalledPackages(project, document);

                foreach (var installedPackage in installedPackages)
                {
                    var packageId = installedPackage.Key;

                    if (!highestVersions.TryGetValue(packageId, out var highestVersion) ||
                        highestVersion < installedPackage.Value.Version)
                    {
                        highestVersions[packageId] = installedPackage.Value.Version;
                    }
                }

                var consolidatedPackages = installedPackages.ToDictionary(x => x.Key, x => x.Value.Clone());
                var requestedPackages    = new Dictionary <string, NuGetPackage>();

                foreach (var package in project.NugetPackages())
                {
                    if (!SemanticVersion.TryParse(package.Version, out var semanticVersion))
                    {
                        throw new Exception($"Could not parse '{package.Version}' from Intent metadata for package '{package.Name}' in project '{project.Name}' as a valid Semantic Version 2.0 'version' value.");
                    }

                    if (!highestVersions.TryGetValue(package.Name, out var highestVersion) ||
                        highestVersion < semanticVersion)
                    {
                        highestVersions[package.Name] = highestVersion = semanticVersion;
                    }

                    if (consolidatedPackages.TryGetValue(package.Name, out var consolidatedPackage))
                    {
                        consolidatedPackage.Update(highestVersion, package);
                    }
                    else
                    {
                        consolidatedPackages.Add(package.Name, NuGetPackage.Create(package, highestVersion));
                    }

                    if (requestedPackages.TryGetValue(package.Name, out var requestedPackage))
                    {
                        requestedPackage.Update(highestVersion, package);
                    }
                    else
                    {
                        requestedPackages.Add(package.Name, NuGetPackage.Create(package, highestVersion));
                    }
                }

                projects.Add(new NuGetProject
                {
                    Content           = projectContent,
                    RequestedPackages = requestedPackages,
                    InstalledPackages = installedPackages,
                    Name      = project.Name,
                    FilePath  = project.ProjectFile(),
                    Processor = processor
                });
            }

            return(projects, highestVersions);
        }
Ejemplo n.º 29
0
        static async Task <int> CommandPackAsync([NotNull] PackOptions packOptions, [NotNull] ISnapFilesystem filesystem,
                                                 [NotNull] ISnapAppReader snapAppReader, [NotNull] ISnapAppWriter snapAppWriter, [NotNull] INuGetPackageSources nuGetPackageSources,
                                                 [NotNull] ISnapPack snapPack, [NotNull] INugetService nugetService, [NotNull] ISnapOs snapOs,
                                                 [NotNull] ISnapxEmbeddedResources snapxEmbeddedResources, [NotNull] ISnapExtractor snapExtractor,
                                                 [NotNull] ISnapPackageManager snapPackageManager, [NotNull] ICoreRunLib coreRunLib, [NotNull] ISnapNetworkTimeProvider snapNetworkTimeProvider,
                                                 [NotNull] ILog logger, [NotNull] IDistributedMutexClient distributedMutexClient, [NotNull] string workingDirectory, CancellationToken cancellationToken)
        {
            if (packOptions == null)
            {
                throw new ArgumentNullException(nameof(packOptions));
            }
            if (filesystem == null)
            {
                throw new ArgumentNullException(nameof(filesystem));
            }
            if (snapAppReader == null)
            {
                throw new ArgumentNullException(nameof(snapAppReader));
            }
            if (snapAppWriter == null)
            {
                throw new ArgumentNullException(nameof(snapAppWriter));
            }
            if (nuGetPackageSources == null)
            {
                throw new ArgumentNullException(nameof(nuGetPackageSources));
            }
            if (snapPack == null)
            {
                throw new ArgumentNullException(nameof(snapPack));
            }
            if (nugetService == null)
            {
                throw new ArgumentNullException(nameof(nugetService));
            }
            if (snapOs == null)
            {
                throw new ArgumentNullException(nameof(snapOs));
            }
            if (snapxEmbeddedResources == null)
            {
                throw new ArgumentNullException(nameof(snapxEmbeddedResources));
            }
            if (snapExtractor == null)
            {
                throw new ArgumentNullException(nameof(snapExtractor));
            }
            if (snapPackageManager == null)
            {
                throw new ArgumentNullException(nameof(snapPackageManager));
            }
            if (coreRunLib == null)
            {
                throw new ArgumentNullException(nameof(coreRunLib));
            }
            if (snapNetworkTimeProvider == null)
            {
                throw new ArgumentNullException(nameof(snapNetworkTimeProvider));
            }
            if (logger == null)
            {
                throw new ArgumentNullException(nameof(logger));
            }
            if (distributedMutexClient == null)
            {
                throw new ArgumentNullException(nameof(distributedMutexClient));
            }
            if (workingDirectory == null)
            {
                throw new ArgumentNullException(nameof(workingDirectory));
            }

            var stopwatch = new Stopwatch();

            stopwatch.Restart();

            var(snapApps, snapApp, error, snapsManifestAbsoluteFilename) = BuildSnapAppFromDirectory(filesystem, snapAppReader,
                                                                                                     nuGetPackageSources, packOptions.Id, packOptions.Rid, workingDirectory);
            if (snapApp == null)
            {
                if (!error)
                {
                    logger.Error($"Snap with id {packOptions.Id} was not found in manifest: {snapsManifestAbsoluteFilename}");
                }

                return(1);
            }

            if (!SemanticVersion.TryParse(packOptions.Version, out var semanticVersion))
            {
                logger.Error($"Unable to parse semantic version (v2): {packOptions.Version}");
                return(1);
            }

            snapApp.Version = semanticVersion;

            if (packOptions.ReleasesNotes != null)
            {
                snapApp.ReleaseNotes = packOptions.ReleasesNotes;
            }

            var artifactsDirectory  = BuildArtifactsDirectory(filesystem, workingDirectory, snapApps.Generic, snapApp);
            var installersDirectory = BuildInstallersDirectory(filesystem, workingDirectory, snapApps.Generic, snapApp);
            var packagesDirectory   = BuildPackagesDirectory(filesystem, workingDirectory, snapApps.Generic, snapApp);

            filesystem.DirectoryCreateIfNotExists(installersDirectory);
            filesystem.DirectoryCreateIfNotExists(packagesDirectory);

            var snapAppChannel = snapApp.GetDefaultChannelOrThrow();

            MaybeOverrideLockToken(snapApps, logger, packOptions.Id, packOptions.LockToken);

            if (string.IsNullOrWhiteSpace(snapApps.Generic.Token))
            {
                logger.Error("Please specify a token in your snapx.yml file. A random UUID is sufficient.");
                return(1);
            }

            await using var distributedMutex = WithDistributedMutex(distributedMutexClient, logger, snapApps.BuildLockKey(snapApp), cancellationToken);

            logger.Info($"Schema version: {snapApps.Schema}");
            logger.Info($"Packages directory: {packagesDirectory}");
            logger.Info($"Artifacts directory: {artifactsDirectory}");
            logger.Info($"Installers directory: {installersDirectory}");
            logger.Info($"Pack strategy: {snapApps.Generic.PackStrategy}");
            logger.Info('-'.Repeat(TerminalBufferWidth));
            logger.Info($"Id: {snapApp.Id}");
            logger.Info($"Version: {snapApp.Version}");
            logger.Info($"Channel: {snapAppChannel.Name}");
            logger.Info($"Rid: {snapApp.Target.Rid}");
            logger.Info($"OS: {snapApp.Target.Os.ToString().ToLowerInvariant()}");
            var installersStr = !snapApp.Target.Installers.Any() ? "None" : string.Join(", ", snapApp.Target.Installers);

            logger.Info($"Installers: {installersStr}");
            var shortcutsStr = !snapApp.Target.Shortcuts.Any() ? "None" : string.Join(", ", snapApp.Target.Shortcuts);

            logger.Info($"Shortcuts: {shortcutsStr}");

            logger.Info('-'.Repeat(TerminalBufferWidth));

            var tryAcquireRetries = packOptions.LockRetries == -1 ? int.MaxValue : packOptions.LockRetries;

            if (!await distributedMutex.TryAquireAsync(TimeSpan.FromSeconds(15), tryAcquireRetries))
            {
                logger.Info('-'.Repeat(TerminalBufferWidth));
                return(1);
            }

            logger.Info('-'.Repeat(TerminalBufferWidth));

            var updateFeedPackageSource = await snapPackageManager.GetPackageSourceAsync(snapApp);

            logger.Info("Downloading releases nupkg.");

            var snapReleasesPackageDirectory = filesystem.DirectoryGetParent(packagesDirectory);

            filesystem.DirectoryCreateIfNotExists(snapReleasesPackageDirectory);

            var(snapAppsReleases, _, currentReleasesMemoryStream) = await snapPackageManager.GetSnapsReleasesAsync(snapApp, logger, cancellationToken);

            if (currentReleasesMemoryStream != null)
            {
                await currentReleasesMemoryStream.DisposeAsync();
            }

            if (snapAppsReleases == null)
            {
                if (!logger.Prompt("y|yes", "Unable to find a previous release in any of your NuGet package sources. " +
                                   "Is this the first time you are publishing this application? " +
                                   "NB! The package may not yet be visible to due to upstream caching. [y/n]", infoOnly: packOptions.YesToAllPrompts)
                    )
                {
                    return(1);
                }

                snapAppsReleases = new SnapAppsReleases();
            }
            else
            {
                logger.Info($"Downloaded releases nupkg. Current version: {snapAppsReleases.Version}.");

                if (packOptions.Gc)
                {
                    var releasesRemoved = snapAppsReleases.Gc(snapApp);
                    logger.Info($"Garbage collected (removed) {releasesRemoved} releases.");
                }

                var snapAppChannelReleases = snapAppsReleases.GetReleases(snapApp, snapAppChannel);

                var restoreSummary = await snapPackageManager.RestoreAsync(packagesDirectory, snapAppChannelReleases,
                                                                           updateFeedPackageSource, SnapPackageManagerRestoreType.Pack, logger : logger, cancellationToken : cancellationToken);

                if (!restoreSummary.Success)
                {
                    return(1);
                }

                if (snapAppChannelReleases.Any(x => x.Version >= snapApp.Version))
                {
                    logger.Error($"Version {snapApp.Version} is already published to feed: {updateFeedPackageSource.Name}.");
                    return(1);
                }
            }

            var snapPackageDetails = new SnapPackageDetails
            {
                SnapApp             = snapApp,
                NuspecBaseDirectory = artifactsDirectory,
                PackagesDirectory   = packagesDirectory,
                SnapAppsReleases    = snapAppsReleases
            };

            logger.Info('-'.Repeat(TerminalBufferWidth));
            logger.Info($"Building nupkg: {snapApp.Version}.");

            var pushPackages = new List <string>();

            var(fullNupkgMemoryStream, fullSnapApp, fullSnapRelease, deltaNupkgMemorystream, deltaSnapApp, deltaSnapRelease) =
                await snapPack.BuildPackageAsync(snapPackageDetails, coreRunLib, cancellationToken);

            var fullNupkgAbsolutePath = filesystem.PathCombine(packagesDirectory, fullSnapRelease.Filename);

            await using (fullNupkgMemoryStream)
                await using (deltaNupkgMemorystream)
                {
                    logger.Info($"Writing full nupkg to disk: {fullSnapRelease.Filename}. File size: {fullSnapRelease.FullFilesize.BytesAsHumanReadable()}");
                    await filesystem.FileWriteAsync(fullNupkgMemoryStream, fullNupkgAbsolutePath, default);

                    if (!fullSnapRelease.IsGenesis)
                    {
                        var deltaNupkgAbsolutePath = filesystem.PathCombine(packagesDirectory, deltaSnapRelease.Filename);
                        logger.Info(
                            $"Writing delta nupkg to disk: {deltaSnapRelease.Filename}. File size: {deltaSnapRelease.DeltaFilesize.BytesAsHumanReadable()}");
                        await filesystem.FileWriteAsync(deltaNupkgMemorystream, deltaNupkgAbsolutePath, default);
                    }
                }

            var fullOrDeltaSnapApp           = deltaSnapApp ?? fullSnapApp;
            var fullOrDeltaNupkgAbsolutePath = filesystem.PathCombine(packagesDirectory, fullOrDeltaSnapApp.BuildNugetFilename());

            pushPackages.Add(fullOrDeltaNupkgAbsolutePath);

            logger.Info('-'.Repeat(TerminalBufferWidth));
            logger.Info($"Retrieving network time from: {snapNetworkTimeProvider}.");

            var nowUtc = await SnapUtility.RetryAsync(async() => await snapNetworkTimeProvider.NowUtcAsync(), 3);

            if (!nowUtc.HasValue)
            {
                logger.Error($"Unknown error retrieving network time from: {snapNetworkTimeProvider}");
                return(1);
            }

            var localTimeStr = TimeZoneInfo
                               .ConvertTimeFromUtc(nowUtc.Value, TimeZoneInfo.Local)
                               .ToString("F", CultureInfo.CurrentCulture);

            logger.Info($"Successfully retrieved network time. Time is now: {localTimeStr}");
            logger.Info('-'.Repeat(TerminalBufferWidth));

            fullSnapRelease.CreatedDateUtc = nowUtc.Value;
            if (deltaSnapRelease != null)
            {
                deltaSnapRelease.CreatedDateUtc = nowUtc.Value;
            }
            snapAppsReleases.LastWriteAccessUtc = nowUtc.Value;

            int?forcedDbVersion = null;

            if (packOptions.DbVersion > 0)
            {
                if (packOptions.DbVersion <= snapAppsReleases.DbVersion)
                {
                    logger.Error($"Unable to force database version because version is less than or equal to current database version. \n" +
                                 $"Forced version: {packOptions.DbVersion}.\n" +
                                 $"Current database version: {snapAppsReleases.DbVersion}.");
                    return(1);
                }

                forcedDbVersion = packOptions.DbVersion;

                logger.Info($"Database version is forced because of '--db-version' option. Initial database version: {forcedDbVersion}.");
            }
            else if (fullOrDeltaSnapApp.IsGenesis &&
                     fullOrDeltaSnapApp.Version.Major > snapAppsReleases.Version.Major)
            {
                forcedDbVersion = fullOrDeltaSnapApp.Version.Major;
                logger.Info($"Database version is forced because genesis nupkg detected. Initial database version: {forcedDbVersion}");
            }

            logger.Info($"Building releases nupkg. Current database version: {snapAppsReleases.Version}.");

            var releasesMemoryStream      = snapPack.BuildReleasesPackage(fullOrDeltaSnapApp, snapAppsReleases, forcedDbVersion);
            var releasesNupkgAbsolutePath = snapOs.Filesystem.PathCombine(snapReleasesPackageDirectory, fullOrDeltaSnapApp.BuildNugetReleasesFilename());
            var releasesNupkgFilename     = filesystem.PathGetFileName(releasesNupkgAbsolutePath);
            await snapOs.Filesystem.FileWriteAsync(releasesMemoryStream, releasesNupkgAbsolutePath, cancellationToken);

            pushPackages.Add(releasesNupkgAbsolutePath);

            logger.Info("Finished building releases nupkg.\n" +
                        $"Filename: {releasesNupkgFilename}.\n" +
                        $"Size: {releasesMemoryStream.Length.BytesAsHumanReadable()}.\n" +
                        $"New database version: {snapAppsReleases.Version}.\n" +
                        $"Pack id: {snapAppsReleases.PackId:N}.");

            logger.Info('-'.Repeat(TerminalBufferWidth));

            await using (releasesMemoryStream)
            {
                if (!packOptions.SkipInstallers && fullOrDeltaSnapApp.Target.Installers.Any())
                {
                    var channels = fullOrDeltaSnapApp.IsGenesis ? fullOrDeltaSnapApp.Channels : new List <SnapChannel> {
                        snapAppChannel
                    };

                    foreach (var channel in channels)
                    {
                        var snapAppInstaller = new SnapApp(fullOrDeltaSnapApp);
                        snapAppInstaller.SetCurrentChannel(channel.Name);

                        if (fullOrDeltaSnapApp.Target.Installers.Any(x => x.HasFlag(SnapInstallerType.Offline)))
                        {
                            logger.Info('-'.Repeat(TerminalBufferWidth));

                            var(installerOfflineSuccess, canContinueIfError, installerOfflineExeAbsolutePath) = await BuildInstallerAsync(logger, snapOs, snapxEmbeddedResources, snapAppWriter, snapAppInstaller, coreRunLib,
                                                                                                                                          installersDirectory, fullNupkgAbsolutePath, releasesNupkgAbsolutePath,
                                                                                                                                          true, cancellationToken);

                            if (!installerOfflineSuccess)
                            {
                                if (!canContinueIfError ||
                                    !logger.Prompt("y|yes", "Installer was not built. Do you still want to continue? (y|n)",
                                                   infoOnly: packOptions.YesToAllPrompts))
                                {
                                    logger.Info('-'.Repeat(TerminalBufferWidth));
                                    logger.Error("Unknown error building offline installer.");
                                    return(1);
                                }
                            }
                            else
                            {
                                var installerOfflineExeStat = snapOs.Filesystem.FileStat(installerOfflineExeAbsolutePath);
                                logger.Info($"Successfully built offline installer. File size: {installerOfflineExeStat.Length.BytesAsHumanReadable()}.");
                            }
                        }

                        if (fullOrDeltaSnapApp.Target.Installers.Any(x => x.HasFlag(SnapInstallerType.Web)))
                        {
                            logger.Info('-'.Repeat(TerminalBufferWidth));

                            var(installerWebSuccess, canContinueIfError, installerWebExeAbsolutePath) = await BuildInstallerAsync(logger, snapOs, snapxEmbeddedResources, snapAppWriter, snapAppInstaller, coreRunLib,
                                                                                                                                  installersDirectory, null, releasesNupkgAbsolutePath,
                                                                                                                                  false, cancellationToken);

                            if (!installerWebSuccess)
                            {
                                if (!canContinueIfError ||
                                    !logger.Prompt("y|yes", "Installer was not built. Do you still want to continue? (y|n)",
                                                   infoOnly: packOptions.YesToAllPrompts))
                                {
                                    logger.Info('-'.Repeat(TerminalBufferWidth));
                                    logger.Error("Unknown error building offline installer.");
                                    return(1);
                                }
                            }
                            else
                            {
                                var installerWebExeStat = snapOs.Filesystem.FileStat(installerWebExeAbsolutePath);
                                logger.Info($"Successfully built web installer. File size: {installerWebExeStat.Length.BytesAsHumanReadable()}.");
                            }
                        }
                    }
                }
            }

            if (snapApps.Generic.PackStrategy == SnapAppsPackStrategy.push)
            {
                await PushPackagesAsync(packOptions, logger, filesystem, nugetService,
                                        snapPackageManager, distributedMutex, snapAppsReleases, fullOrDeltaSnapApp, snapAppChannel, pushPackages, cancellationToken);
            }

            logger.Info($"Fetching releases overview from feed {updateFeedPackageSource.Name}.");

            await CommandListAsync(new ListOptions { Id = fullOrDeltaSnapApp.Id }, filesystem, snapAppReader,
                                   nuGetPackageSources, nugetService, snapExtractor, snapPackageManager, logger, workingDirectory, cancellationToken);

            logger.Info('-'.Repeat(TerminalBufferWidth));
            logger.Info($"Pack completed in {stopwatch.Elapsed.TotalSeconds:F1}s.");

            return(0);
        }
Ejemplo n.º 30
0
        /*********
        ** Private methods
        *********/
        /// <summary>Get the metadata for a mod.</summary>
        /// <param name="search">The mod data to match.</param>
        /// <param name="wikiData">The wiki data.</param>
        /// <param name="includeExtendedMetadata">Whether to include extended metadata for each mod.</param>
        /// <returns>Returns the mod data if found, else <c>null</c>.</returns>
        private async Task <ModEntryModel> GetModData(ModSearchEntryModel search, WikiCompatibilityEntry[] wikiData, bool includeExtendedMetadata)
        {
            // crossreference data
            ModDataRecord          record    = this.ModDatabase.Get(search.ID);
            WikiCompatibilityEntry wikiEntry = wikiData.FirstOrDefault(entry => entry.ID.Contains(search.ID.Trim(), StringComparer.InvariantCultureIgnoreCase));

            string[] updateKeys = this.GetUpdateKeys(search.UpdateKeys, record, wikiEntry).ToArray();

            // get latest versions
            ModEntryModel result = new ModEntryModel {
                ID = search.ID
            };
            IList <string> errors = new List <string>();

            foreach (string updateKey in updateKeys)
            {
                // fetch data
                ModInfoModel data = await this.GetInfoForUpdateKeyAsync(updateKey);

                if (data.Error != null)
                {
                    errors.Add(data.Error);
                    continue;
                }

                // handle main version
                if (data.Version != null)
                {
                    if (!SemanticVersion.TryParse(data.Version, out ISemanticVersion version))
                    {
                        errors.Add($"The update key '{updateKey}' matches a mod with invalid semantic version '{data.Version}'.");
                        continue;
                    }

                    if (this.IsNewer(version, result.Main?.Version))
                    {
                        result.Main = new ModEntryVersionModel(version, data.Url);
                    }
                }

                // handle optional version
                if (data.PreviewVersion != null)
                {
                    if (!SemanticVersion.TryParse(data.PreviewVersion, out ISemanticVersion version))
                    {
                        errors.Add($"The update key '{updateKey}' matches a mod with invalid optional semantic version '{data.PreviewVersion}'.");
                        continue;
                    }

                    if (this.IsNewer(version, result.Optional?.Version))
                    {
                        result.Optional = new ModEntryVersionModel(version, data.Url);
                    }
                }
            }

            // get unofficial version
            if (wikiEntry?.UnofficialVersion != null && this.IsNewer(wikiEntry.UnofficialVersion, result.Main?.Version) && this.IsNewer(wikiEntry.UnofficialVersion, result.Optional?.Version))
            {
                result.Unofficial = new ModEntryVersionModel(wikiEntry.UnofficialVersion, this.WikiCompatibilityPageUrl);
            }

            // fallback to preview if latest is invalid
            if (result.Main == null && result.Optional != null)
            {
                result.Main     = result.Optional;
                result.Optional = null;
            }

            // special cases
            if (result.ID == "Pathoschild.SMAPI")
            {
                if (result.Main != null)
                {
                    result.Main.Url = "https://smapi.io/";
                }
                if (result.Optional != null)
                {
                    result.Optional.Url = "https://smapi.io/";
                }
            }

            // add extended metadata
            if (includeExtendedMetadata && (wikiEntry != null || record != null))
            {
                result.Metadata = new ModExtendedMetadataModel(wikiEntry, record);
            }

            // add result
            result.Errors = errors.ToArray();
            return(result);
        }