Exemple #1
0
        /// <summary>
        /// Gets file path for specific package.
        /// </summary>
        protected internal virtual string GetDownloadedFilePath(IPackage package, string cwd)
        {
            var uri      = new Uri(package.GetDistUri());
            var filename = Security.Md5($"{cwd}{package}{package.GetDistReference()}{package.GetDistShasum()}");

            return(Path.Combine(GetTempDirectory(), "download", $"{filename}{Path.GetExtension(uri.AbsolutePath)}"));
        }
Exemple #2
0
        /// <summary>
        /// Dump the package instance to <see cref="ConfigBucket"/>.
        /// </summary>
        /// <typeparam name="T">The type of the config struct.</typeparam>
        /// <param name="package">The package instance.</param>
        /// <returns>The <see cref="ConfigBucket"/> instance.</returns>
        public T Dump <T>(IPackage package)
            where T : ConfigBucketBase, new()
        {
            var data = new T
            {
                Name               = package.GetNamePretty(),
                Version            = package.GetVersionPretty(),
                VersionNormalized  = package.GetVersion(),
                ReleaseDate        = package.GetReleaseDate(),
                PackageType        = package.GetPackageType(),
                NotificationUri    = package.GetNotificationUri(),
                Binaries           = package.GetBinaries().ZeroAsNull(),
                Archive            = package.GetArchives().ZeroAsNull(),
                Extra              = package.GetExtra(),
                InstallationSource = package.GetInstallationSource(),
            };

            if (!string.IsNullOrEmpty(package.GetSourceType()))
            {
                data.Source = new ConfigResource
                {
                    Type      = package.GetSourceType(),
                    Uri       = package.GetSourceUri(),
                    Reference = package.GetSourceReference(),
                    Mirrors   = package.GetSourceMirrors().ZeroAsNull(),
                };
            }

            if (!string.IsNullOrEmpty(package.GetDistType()))
            {
                data.Dist = new ConfigResource
                {
                    Type      = package.GetDistType(),
                    Uri       = package.GetDistUri(),
                    Reference = package.GetDistReference(),
                    Mirrors   = package.GetDistMirrors().ZeroAsNull(),
                    Shasum    = package.GetDistShasum(),
                };
            }

            data.Requires    = LinksToDictonary(package.GetRequires());
            data.RequiresDev = LinksToDictonary(package.GetRequiresDev());
            data.Conflicts   = LinksToDictonary(package.GetConflicts());
            data.Provides    = LinksToDictonary(package.GetProvides());
            data.Replaces    = LinksToDictonary(package.GetReplaces());

            var suggests = package.GetSuggests();

            if (suggests != null && suggests.Count > 0)
            {
                data.Suggests = new SortedDictionary <string, string>(suggests);
            }

            if (package is IPackageComplete packageComplete)
            {
                data.Licenses     = packageComplete.GetLicenses().ZeroAsNull();
                data.Authors      = packageComplete.GetAuthors().ZeroAsNull();
                data.Description  = packageComplete.GetDescription();
                data.Homepage     = packageComplete.GetHomepage();
                data.Keywords     = packageComplete.GetKeywords().ZeroAsNull();
                data.Repositories = packageComplete.GetRepositories().ZeroAsNull();

                if (packageComplete.IsDeprecated)
                {
                    var replacement = packageComplete.GetReplacementPackage();
                    if (string.IsNullOrEmpty(replacement))
                    {
                        data.Deprecated = true;
                    }
                    else
                    {
                        data.Deprecated = replacement;
                    }
                }

                data.Scripts = packageComplete.GetScripts();

                var supports = packageComplete.GetSupport();
                if (supports != null && supports.Count > 0)
                {
                    data.Support = new SortedDictionary <string, string>(supports);
                }
            }

            if (package is IPackageRoot packageRoot)
            {
                data.MinimumStability = packageRoot.GetMinimumStability();
                data.Platforms        = packageRoot.GetPlatforms();
            }

            if (data.Keywords != null)
            {
                Array.Sort(data.Keywords);
            }

            return(data);
        }
Exemple #3
0
        /// <inheritdoc cref="IDownloader.Download(IPackage, string)" />
        public virtual Task Download(IPackage package, string cwd, bool output)
        {
            if (string.IsNullOrEmpty(package.GetDistUri()))
            {
                throw new RuntimeException("The given package is missing url information.");
            }

            var downloadedFilePath = GetDownloadedFilePath(package, cwd);

            fileSystem.Delete(cwd);

            void DoDownload(string uri)
            {
                var processedUri = ProcessUri(package, uri);

                if (eventDispatcher != null)
                {
                    var preFileDownloadEvent = new PreFileDownloadEventArgs(PluginEvents.PreFileDownload, transport, processedUri);
                    eventDispatcher.Dispatch(this, preFileDownloadEvent);
                }

                try
                {
                    var checksum = package.GetDistShasum();
                    var cacheKey = GetCacheKey(package, processedUri);

                    void DownloadFromHttp(int retries = 3)
                    {
                        SException processException = null;

                        while (retries-- > 0)
                        {
                            try
                            {
                                transport.Copy(
                                    processedUri,
                                    downloadedFilePath,
                                    new ReportDownloadProgress(io, $"{GetDownloadingPrompt(package)}: "));
                                break;
                            }
                            catch (TransportException ex)
                            {
                                // clean up immediately. otherwise it will lead to failure forever.
                                fileSystem.Delete(downloadedFilePath);

                                // if we got an http response with a proper code, then
                                // requesting again will probably not help, abort.
                                var serverProblems = new[]
                                {
                                    HttpStatusCode.InternalServerError,
                                    HttpStatusCode.BadGateway,
                                    HttpStatusCode.ServiceUnavailable,
                                    HttpStatusCode.GatewayTimeout,
                                };

                                if (ex.HttpStatusCode != 0 &&
                                    (!Array.Exists(serverProblems, (code) => code == ex.HttpStatusCode) || retries <= 0))
                                {
                                    throw;
                                }

                                processException = ex;
                                Thread.Sleep(500);
                            }
                        }

                        if (processException != null)
                        {
                            ExceptionDispatchInfo.Capture(processException).Throw();
                        }

                        if (cache != null && cache.CopyFrom(cacheKey, downloadedFilePath))
                        {
                            lastCacheWrites[package.GetName()] = cacheKey;
                        }
                    }

                    // use from cache if it is present and has a valid checksum
                    // or we have no checksum to check against
                    if (cache != null && cache.Sha1(cacheKey, checksum) && cache.CopyTo(cacheKey, downloadedFilePath))
                    {
                        if (output)
                        {
                            io.WriteError($"  - Loading <info>{package.GetName()}</info> (<comment>{package.GetVersionPrettyFull()}</comment>) from cache", false);
                        }
                    }
                    else
                    {
                        if (output)
                        {
                            io.WriteError(GetDownloadingPrompt(package), false);
                        }

                        DownloadFromHttp();
                    }

                    // Verify the file to ensure that the file is not damaged.
                    if (!fileSystem.Exists(downloadedFilePath, FileSystemOptions.File))
                    {
                        throw new UnexpectedException($"{uri} could not be saved to {downloadedFilePath} , make sure the directory is writable and you have internet connectivity.");
                    }

                    if (!string.IsNullOrEmpty(checksum))
                    {
                        using (var stream = fileSystem.Read(downloadedFilePath))
                        {
                            if (Security.Sha1(stream) != checksum)
                            {
                                throw new UnexpectedException($"The checksum verification of the file failed (downloaded from {uri})");
                            }
                        }
                    }
                }
                catch
                {
                    fileSystem.Delete(downloadedFilePath);
                    ClearLastCacheWrite(package);
                    throw;
                }
                finally
                {
                    if (output)
                    {
                        io.OverwriteError(string.Empty, false);
                    }
                }
            }

            void Start()
            {
                var uris = package.GetDistUris();

                // The performance popped from the tail will be better
                // than popping out from the head
                Array.Reverse(uris);
                while (uris.Length > 0)
                {
                    var uri = Arr.Pop(ref uris);
                    try
                    {
                        DoDownload(uri);
                        break;
                    }
                    catch (SException ex)
                    {
                        if (io.IsDebug)
                        {
                            io.WriteError(string.Empty);
                            io.WriteError($"Faild: [{ex.GetType()}] {ex.Message}");
                        }
                        else if (uris.Length > 0)
                        {
                            io.WriteError(string.Empty);
                            io.WriteError($" Failed, trying the next URL ({ex.Message})");
                        }

                        if (uris.Length <= 0)
                        {
                            throw;
                        }
                    }
                }
            }

            return(Task.Run(Start));
        }