Esempio n. 1
0
    /// <summary>
    /// Creates a temporary directory from a retrieval method. Sets missing properties in the process.
    /// </summary>
    /// <param name="retrievalMethod">The retrieval method.</param>
    /// <param name="handler">A callback object used when the the user is to be informed about progress.</param>
    /// <param name="localPath">An optional local file path where the <paramref name="retrievalMethod"/> has already been downloaded. Leave <c>null</c> to download automatically.</param>
    /// <returns>A temporary directory built using the retrieval method.</returns>
    /// <exception cref="OperationCanceledException">The user canceled the task.</exception>
    /// <exception cref="WebException">A file could not be downloaded from the internet.</exception>
    /// <exception cref="IOException">There is a problem writing a temporary file.</exception>
    /// <exception cref="UnauthorizedAccessException">Write access to a temporary file is not permitted.</exception>
    public static TemporaryDirectory ToTempDir(this DownloadRetrievalMethod retrievalMethod, ITaskHandler handler, string?localPath = null)
    {
        #region Sanity checks
        if (retrievalMethod == null)
        {
            throw new ArgumentNullException(nameof(retrievalMethod));
        }
        if (handler == null)
        {
            throw new ArgumentNullException(nameof(handler));
        }
        #endregion

        var tempDir = new TemporaryDirectory("0publish");
        try
        {
            var builder = new DirectoryBuilder(tempDir);
            builder.Add(retrievalMethod, new SimpleCommandExecutor(), handler, localPath);
            return(tempDir);
        }
        catch
        {
            tempDir.Dispose();
            throw;
        }
    }
Esempio n. 2
0
        /// <summary>
        /// Downloads a <see cref="DownloadRetrievalMethod"/> to a temporary file.
        /// </summary>
        /// <param name="retrievalMethod">The file to download.</param>
        /// <param name="tag">The <see cref="ITask.Tag"/> to set for the download process.</param>
        /// <returns>The downloaded temporary file.</returns>
        /// <exception cref="OperationCanceledException">A download was canceled from another thread.</exception>
        /// <exception cref="WebException">A file could not be downloaded from the internet.</exception>
        /// <exception cref="IOException">A downloaded file could not be written to the disk or.</exception>
        /// <exception cref="UnauthorizedAccessException">Write access to <see cref="IImplementationStore"/> is not permitted.</exception>
        protected virtual TemporaryFile Download(DownloadRetrievalMethod retrievalMethod, object?tag = null)
        {
            #region Sanity checks
            if (retrievalMethod == null)
            {
                throw new ArgumentNullException(nameof(retrievalMethod));
            }
            #endregion

            retrievalMethod.Validate();

            var tempFile = new TemporaryFile("0install-fetcher");
            try
            {
                Handler.RunTask(new DownloadFile(retrievalMethod.Href, tempFile, retrievalMethod.DownloadSize)
                {
                    Tag = tag
                });
                return(tempFile);
            }
            #region Error handling
            catch
            {
                tempFile.Dispose();
                throw;
            }
            #endregion
        }
Esempio n. 3
0
        /// <inheritdoc/>
        protected override TemporaryFile Download(DownloadRetrievalMethod retrievalMethod, object tag = null)
        {
            #region Sanity checks
            if (retrievalMethod == null)
            {
                throw new ArgumentNullException(nameof(retrievalMethod));
            }
            #endregion

            retrievalMethod.Validate();

            try
            {
                return(base.Download(retrievalMethod, tag));
            }
            catch (WebException ex) when(!retrievalMethod.Href.IsLoopback)
            {
                Log.Warn(ex);
                Log.Info("Trying mirror");

                try
                {
                    var mirrored = (DownloadRetrievalMethod)retrievalMethod.CloneRecipeStep();
                    mirrored.Href = GetMirrorUrl(retrievalMethod.Href);
                    return(base.Download(mirrored, tag));
                }
                catch (WebException)
                {
                    // Report the original problem instead of mirror errors
                    throw ex.PreserveStack();
                }
            }
        }
Esempio n. 4
0
    /// <summary>
    /// Sets missing properties on the retrieval method if they can be inferred.
    /// </summary>
    /// <param name="retrievalMethod">The retrieval method.</param>
    /// <param name="executor">Used to modify properties in an undoable fashion.</param>
    /// <param name="localPath">An optional local file path where the <paramref name="retrievalMethod"/> has already been downloaded.</param>
    public static void SetMissing(this DownloadRetrievalMethod retrievalMethod, ICommandExecutor executor, string?localPath = null)
    {
        #region Sanity checks
        if (retrievalMethod == null)
        {
            throw new ArgumentNullException(nameof(retrievalMethod));
        }
        if (executor == null)
        {
            throw new ArgumentNullException(nameof(executor));
        }
        #endregion

        switch (retrievalMethod)
        {
        case Archive archive when string.IsNullOrEmpty(archive.MimeType):
            executor.Execute(SetValueCommand.For(() => archive.MimeType,
                                                 Archive.GuessMimeType(localPath ?? archive.Href.OriginalString)));

            break;

        case SingleFile file when string.IsNullOrEmpty(file.Destination):
            executor.Execute(SetValueCommand.For(() => file.Destination,
                                                 Path.GetFileName(localPath ?? file.Href.GetLocalFileName())));

            break;
        }
    }
        /// <inheritdoc/>
        protected override TemporaryFile Download(DownloadRetrievalMethod retrievalMethod, object?tag = null)
        {
            #region Sanity checks
            if (retrievalMethod == null)
            {
                throw new ArgumentNullException(nameof(retrievalMethod));
            }
            #endregion

            retrievalMethod.Validate();

            try
            {
                return(base.Download(retrievalMethod, tag));
            }
            catch (WebException ex) when(!retrievalMethod.Href.IsLoopback && _config.FeedMirror != null)
            {
                Log.Warn(ex);
                Log.Info("Trying mirror");

                try
                {
                    var mirrored = (DownloadRetrievalMethod)retrievalMethod.Clone();
                    mirrored.Href = new Uri($"{_config.FeedMirror.EnsureTrailingSlash().AbsoluteUri}archive/{retrievalMethod.Href.Scheme}/{retrievalMethod.Href.Host}/{string.Concat(retrievalMethod.Href.Segments).TrimStart('/').Replace("/", "%23")}");
                    return(base.Download(mirrored, tag));
                }
                catch (WebException)
                {
                    // Report the original problem instead of mirror errors
                    throw ex.PreserveStack();
                }
            }
        }
Esempio n. 6
0
        public static TemporaryFile Download([NotNull] this DownloadRetrievalMethod retrievalMethod, [NotNull] ITaskHandler handler, [CanBeNull] ICommandExecutor executor = null)
        {
            #region Sanity checks
            if (retrievalMethod == null)
            {
                throw new ArgumentNullException("retrievalMethod");
            }
            if (handler == null)
            {
                throw new ArgumentNullException("handler");
            }
            #endregion

            if (executor == null)
            {
                executor = new SimpleCommandExecutor();
            }
            if (retrievalMethod.Href == null)
            {
                throw new ArgumentException(Resources.HrefMissing, "retrievalMethod");
            }
            new PerTypeDispatcher <DownloadRetrievalMethod>(ignoreMissing: false)
            {
                // ReSharper disable AccessToDisposedClosure
                (Archive archive) =>
                {
                    // Guess MIME types now because the file ending is not known later
                    if (string.IsNullOrEmpty(archive.MimeType))
                    {
                        string mimeType = Archive.GuessMimeType(archive.Href.OriginalString);
                        executor.Execute(new SetValueCommand <string>(() => archive.MimeType, value => archive.MimeType = value, mimeType));
                    }
                },
                (SingleFile file) =>
                {
                    // Guess file name based on URL
                    if (string.IsNullOrEmpty(file.Destination))
                    {
                        string destination = file.Href.OriginalString.GetRightPartAtLastOccurrence('/').StripCharacters(Path.GetInvalidFileNameChars());
                        executor.Execute(new SetValueCommand <string>(() => file.Destination, value => file.Destination = value, destination));
                    }
                }
                // ReSharper restore AccessToDisposedClosure
            }.Dispatch(retrievalMethod);

            // Download the file
            var href           = ModelUtils.GetAbsoluteHref(retrievalMethod.Href, string.IsNullOrEmpty(executor.Path) ? null : new FeedUri(executor.Path));
            var downloadedFile = new TemporaryFile("0publish");
            handler.RunTask(new DownloadFile(href, downloadedFile)); // Defer task to handler

            // Set downloaded file size
            long newSize = new FileInfo(downloadedFile).Length;
            if (retrievalMethod.Size != newSize)
            {
                executor.Execute(new SetValueCommand <long>(() => retrievalMethod.Size, value => retrievalMethod.Size = value, newSize));
            }

            return(downloadedFile);
        }
    /// <summary>
    /// Applies a retrieval method to the implementation. Sets missing properties in the process.
    /// </summary>
    /// <param name="builder">The builder.</param>
    /// <param name="retrievalMethod">The retrieval method.</param>
    /// <param name="executor">Used to modify properties in an undoable fashion.</param>
    /// <param name="handler">A callback object used when the the user needs to be informed about IO tasks.</param>
    /// <param name="localPath">An optional local file path where the <paramref name="retrievalMethod"/> has already been downloaded.</param>
    /// <exception cref="OperationCanceledException">The user canceled the task.</exception>
    /// <exception cref="WebException">A file could not be downloaded from the internet.</exception>
    /// <exception cref="IOException">There is a problem accessing <paramref name="localPath"/>.</exception>
    /// <exception cref="UnauthorizedAccessException">Read access to <paramref name="localPath"/> is not permitted.</exception>
    public static void Add(this IBuilder builder, DownloadRetrievalMethod retrievalMethod, ICommandExecutor executor, ITaskHandler handler, string?localPath = null)
    {
        #region Sanity checks
        if (builder == null)
        {
            throw new ArgumentNullException(nameof(builder));
        }
        if (retrievalMethod == null)
        {
            throw new ArgumentNullException(nameof(retrievalMethod));
        }
        if (executor == null)
        {
            throw new ArgumentNullException(nameof(executor));
        }
        if (handler == null)
        {
            throw new ArgumentNullException(nameof(handler));
        }
        #endregion

        void Process(Stream stream)
        {
            retrievalMethod.SetMissing(executor, localPath);

            builder.Add(retrievalMethod, stream, handler);

            long size = stream.Length;

            if (retrievalMethod is Archive archive)
            {
                size -= archive.StartOffset;
            }
            if (retrievalMethod.Size != size)
            {
                executor.Execute(SetValueCommand.For(() => retrievalMethod.Size, newValue: size));
            }
        }

        if (localPath == null)
        {
            try
            {
                handler.RunTask(new DownloadFile(ModelUtils.GetAbsoluteHref(retrievalMethod.Href, executor.Path), Process));
            }
            #region Error handling
            catch (UriFormatException ex)
            {
                // Wrap exception since only certain exception types are allowed
                throw new WebException(ex.Message, ex);
            }
            #endregion
        }
        else
        {
            handler.RunTask(new ReadFile(localPath, Process));
        }
    }
Esempio n. 8
0
        private void Retrieve(DownloadRetrievalMethod retrievalMethod)
        {
            _feedBuilder.RetrievalMethod = retrievalMethod;

            using (var handler = new GuiTaskHandler(this))
            {
                _feedBuilder.TemporaryDirectory = checkLocalCopy.Checked
                    ? retrievalMethod.LocalApply(textBoxLocalPath.Text, handler)
                    : retrievalMethod.DownloadAndApply(handler);
            }
        }
Esempio n. 9
0
        private void Retrieve(DownloadRetrievalMethod retrievalMethod, string localPath)
        {
            _feedBuilder.RetrievalMethod = retrievalMethod;

            using (var handler = new DialogTaskHandler(this))
            {
                _feedBuilder.TemporaryDirectory = (localPath == null)
                    ? retrievalMethod.DownloadAndApply(handler)
                    : retrievalMethod.LocalApply(localPath, handler);
            }
        }
Esempio n. 10
0
    /// <summary>
    /// Adds a downloaded file to the implementation.
    /// </summary>
    /// <param name="builder">The builder.</param>
    /// <param name="retrievalMethod">The metadata of the file.</param>
    /// <param name="stream">The contents of the file.</param>
    /// <param name="handler">A callback object used when the the user needs to be informed about IO tasks.</param>
    /// <param name="tag">A <see cref="ITask.Tag"/> used to group progress bars. Usually <see cref="ManifestDigest.Best"/>.</param>
    /// <exception cref="UnauthorizedAccessException">Access to a resource was denied.</exception>
    /// <exception cref="IOException">An IO operation failed.</exception>
    public static void Add(this IBuilder builder, DownloadRetrievalMethod retrievalMethod, Stream stream, ITaskHandler handler, object?tag = null)
    {
        switch (retrievalMethod)
        {
        case SingleFile singleFile:
            builder.AddFile(singleFile, stream);
            break;

        case Archive archive:
            builder.AddArchive(archive, stream, handler, tag);
            break;

        default:
            throw new NotSupportedException($"Unknown download retrieval method: ${retrievalMethod}");
        }
    }
        /// <summary>
        /// Downloads and applies a <see cref="RetrievalMethod"/> and adds missing properties.
        /// </summary>
        /// <param name="retrievalMethod">The <see cref="RetrievalMethod"/> to be downloaded.</param>
        /// <param name="handler">A callback object used when the the user is to be informed about progress.</param>
        /// <param name="executor">Used to apply properties in an undoable fashion.</param>
        /// <returns>A temporary directory containing the extracted content.</returns>
        /// <exception cref="OperationCanceledException">The user canceled the task.</exception>
        /// <exception cref="UriFormatException"><see cref="DownloadRetrievalMethod.Href"/> inside <paramref name="retrievalMethod"/> is a relative URI that cannot be resolved.</exception>
        /// <exception cref="IOException">There is a problem access a temporary file.</exception>
        /// <exception cref="WebException">A file could not be downloaded from the internet.</exception>
        /// <exception cref="UnauthorizedAccessException">Read or write access to a temporary file is not permitted.</exception>
        /// <exception cref="NotSupportedException">A <see cref="Archive.MimeType"/> is not supported.</exception>
        public static TemporaryDirectory DownloadAndApply(this RetrievalMethod retrievalMethod, ITaskHandler handler, ICommandExecutor?executor = null)
        {
            #region Sanity checks
            if (retrievalMethod == null)
            {
                throw new ArgumentNullException(nameof(retrievalMethod));
            }
            if (handler == null)
            {
                throw new ArgumentNullException(nameof(handler));
            }
            #endregion

            return(retrievalMethod switch
            {
                DownloadRetrievalMethod download => download.DownloadAndApply(handler, executor),
                Recipe recipe => recipe.DownloadAndApply(handler, executor),
                _ => throw new NotSupportedException(Resources.UnknownRetrievalMethodType)
            });
Esempio n. 12
0
        public static TemporaryDirectory DownloadAndApply([NotNull] this DownloadRetrievalMethod retrievalMethod, [NotNull] ITaskHandler handler, [CanBeNull] ICommandExecutor executor = null)
        {
            #region Sanity checks
            if (retrievalMethod == null)
            {
                throw new ArgumentNullException("retrievalMethod");
            }
            if (handler == null)
            {
                throw new ArgumentNullException("handler");
            }
            #endregion

            using (var downloadedFile = retrievalMethod.Download(handler, executor))
            {
                var extractionDir = new TemporaryDirectory("0publish");
                try
                {
                    new PerTypeDispatcher <DownloadRetrievalMethod>(ignoreMissing: false)
                    {
                        // ReSharper disable AccessToDisposedClosure
                        (Archive archive) => archive.Apply(downloadedFile, extractionDir, handler),
                        (SingleFile file) => file.Apply(downloadedFile, extractionDir, handler)
                        // ReSharper restore AccessToDisposedClosure
                    }.Dispatch(retrievalMethod);
                }
                #region Error handling
                catch
                {
                    extractionDir.Dispose();
                    throw;
                }
                #endregion

                return(extractionDir);
            }
        }
Esempio n. 13
0
        public static TemporaryDirectory LocalApply([NotNull] this DownloadRetrievalMethod retrievalMethod, string localPath, [NotNull] ITaskHandler handler, [CanBeNull] ICommandExecutor executor = null)
        {
            #region Sanity checks
            if (retrievalMethod == null)
            {
                throw new ArgumentNullException("retrievalMethod");
            }
            if (string.IsNullOrEmpty(localPath))
            {
                throw new ArgumentNullException("localPath");
            }
            if (handler == null)
            {
                throw new ArgumentNullException("handler");
            }
            #endregion

            if (executor == null)
            {
                executor = new SimpleCommandExecutor();
            }

            // Set local file size
            long newSize = new FileInfo(localPath).Length;
            if (retrievalMethod.Size != newSize)
            {
                executor.Execute(new SetValueCommand <long>(() => retrievalMethod.Size, value => retrievalMethod.Size = value, newSize));
            }

            var extractionDir = new TemporaryDirectory("0publish");
            try
            {
                new PerTypeDispatcher <DownloadRetrievalMethod>(ignoreMissing: true)
                {
                    // ReSharper disable AccessToDisposedClosure
                    (Archive archive) =>
                    {
                        // Guess MIME types now because the file ending is not known later
                        if (string.IsNullOrEmpty(archive.MimeType))
                        {
                            string mimeType = Archive.GuessMimeType(localPath);
                            executor.Execute(new SetValueCommand <string>(() => archive.MimeType, value => archive.MimeType = value, mimeType));
                        }

                        archive.Apply(localPath, extractionDir, handler);
                    },
                    (SingleFile file) =>
                    {
                        // Guess file name based on local path
                        if (string.IsNullOrEmpty(file.Destination))
                        {
                            string destination = Path.GetFileName(localPath);
                            executor.Execute(new SetValueCommand <string>(() => file.Destination, value => file.Destination = value, destination));
                        }

                        file.Apply(localPath, extractionDir, handler);
                    }
                    // ReSharper restore AccessToDisposedClosure
                }.Dispatch(retrievalMethod);
            }
            #region Error handling
            catch
            {
                extractionDir.Dispose();
                throw;
            }
            #endregion

            return(extractionDir);
        }