コード例 #1
0
        /// <summary>
        ///     Fetches the specified <paramref name="packageArchive"/> and returns the binary data.
        /// </summary>
        /// <param name="packageArchive">The <see cref="IPackageArchive"/> to fetch.</param>
        /// <returns>
        ///     A Result containing the result of the operation and the <see cref="byte"/> array containing the fetched data.
        /// </returns>
        public IResult <byte[]> FetchPackageArchive(IPackageArchive packageArchive)
        {
            Guid guid = logger.EnterMethod(xLogger.Params(packageArchive));

            logger.Info($"Fetching Package Archive '{packageArchive?.FQN}'...");

            IResult <byte[]> retVal = new Result <byte[]>();

            if (packageArchive == default(IPackageArchive))
            {
                retVal.AddError($"The specified Package Archive is null.");
            }
            else if (string.IsNullOrEmpty(packageArchive.FileName))
            {
                retVal.AddError($"The specified Package Archive contains an null or empty Filename.");
            }
            else if (!Platform.FileExists(packageArchive.FileName))
            {
                retVal.AddError($"The specified Package Archive file '{packageArchive.FileName}' can not be found.");
            }
            else
            {
                logger.Debug($"Package Archive '{packageArchive.FQN}' found in '{packageArchive.FileName}'; reading from disk...");
                retVal = Platform.ReadFileBytes(packageArchive.FileName);
            }

            retVal.LogResult(logger);
            logger.ExitMethod(guid);
            return(retVal);
        }
コード例 #2
0
        private bool CompressFiles(IList <PackageFileInfo> additionalFiles)
        {
            using (IPackageArchive package = CreatePackageArchive())
            {
                Log.LogMessage("Packaging {0} files", Files.Length);


                string targetDir = null;
                if (WebsiteFiles != null && WebsiteFiles.Length > 0 && CombineWithWebsite)
                {
                    targetDir = "ClickOnce";
                    CompressFileSet(package, WebsiteBasePath, null, WebsiteFiles
                                    .Where(MatchFilter)
                                    .Select(f => f.ItemSpec), false);
                }
                CompressFileSet(package, BasePath, targetDir, Files
                                .Where(MatchFilter)
                                .Select(f => f.ItemSpec), CombineWithWebsite);

                if (additionalFiles != null)
                {
                    foreach (PackageFileInfo info in additionalFiles)
                    {
                        CompressFile(package, info.SourcePath,
                                     (string.IsNullOrEmpty(targetDir) ? string.Empty : targetDir + "/") + info.DestPath);
                    }
                }
                return(package.Finish());
            }
        }
コード例 #3
0
        public async Task <HttpResponseMessage> PackageArchivesDelete(string fqn)
        {
            HttpResponseMessage retVal;

            if (string.IsNullOrEmpty(fqn))
            {
                retVal = Request.CreateResponse(HttpStatusCode.BadRequest, new ParameterValidator().AddError("fqn", "The specified Fully Qualified Name is null or empty.").Result, JsonFormatter());
            }
            else
            {
                IPackageArchive findResult = await PackageManager.FindPackageArchiveAsync(fqn);

                if (findResult != default(IPackageArchive))
                {
                    IResult deleteResult = await PackageManager.DeletePackageArchiveAsync(findResult);

                    if (deleteResult.ResultCode != ResultCode.Failure)
                    {
                        retVal = Request.CreateResponse(HttpStatusCode.NoContent);
                    }
                    else
                    {
                        HttpErrorResult result = new HttpErrorResult($"Failed to delete Package Archive '{fqn}'.", deleteResult);
                        retVal = Request.CreateResponse(HttpStatusCode.InternalServerError, result, JsonFormatter());
                    }
                }
                else
                {
                    retVal = Request.CreateResponse(HttpStatusCode.NotFound);
                }
            }

            return(retVal);
        }
コード例 #4
0
        /// <summary>
        ///     Retrieves the <see cref="PackageVerification"/> for the specified <paramref name="packageArchive"/>.
        /// </summary>
        /// <param name="packageArchive">The <see cref="IPackageArchive"/> instance to verify.</param>
        /// <returns>The <see cref="PackageVerification"/> result.</returns>
        private PackageVerification GetPackageArchiveVerification(IPackageArchive packageArchive)
        {
            PackageVerification retVal;

            try
            {
                PackageVerifier.Updated += PackageVerifierUpdated;
                bool verification = PackageVerifier.VerifyPackage(packageArchive.FileName);

                if (verification)
                {
                    retVal = PackageVerification.Verified;
                }
                else
                {
                    retVal = PackageVerification.Refuted;
                }
            }
            catch (Exception ex)
            {
                logger.Debug($"Failed to verifiy Package Archive '{packageArchive.FQN}': {ex.Message}");
                retVal = PackageVerification.Refuted;
            }
            finally
            {
                PackageVerifier.Updated -= PackageVerifierUpdated;
            }

            return(retVal);
        }
コード例 #5
0
        /// <summary>
        ///     Initializes a new instance of the <see cref="PackageArchiveSummaryData"/> class with the specified <paramref name="packageArchive"/>.
        /// </summary>
        /// <param name="packageArchive">The <see cref="IPackageArchive"/> instance from which to copy values.</param>
        public PackageArchiveSummaryData(IPackageArchive packageArchive)
        {
            this.CopyPropertyValuesFrom(packageArchive);

            if (packageArchive.Manifest != default(IPackageManifest))
            {
                Manifest = new PackageManifestSummaryData(packageArchive.Manifest);
            }
        }
コード例 #6
0
        /// <summary>
        ///     Adds a <see cref="IPackageArchive"/> from the specified binary <paramref name="data"/>.
        /// </summary>
        /// <remarks>
        ///     The resulting Package archive file is saved to the Packages directory with a filename composed of the Fully
        ///     Qualified Name and Version of the Package.
        /// </remarks>
        /// <param name="data">The binary data to save.</param>
        /// <returns>A Result containing the result of the operation and the created <see cref="IPackageArchive"/> instance.</returns>
        public IResult <IPackageArchive> AddPackageArchive(byte[] data)
        {
            Guid guid = logger.EnterMethod();

            logger.Info("Creating new Package...");

            IResult <IPackageArchive> retVal = new Result <IPackageArchive>();
            string tempFile            = Path.Combine(PlatformManager.Directories.Temp, Guid.NewGuid().ToString());
            string destinationFilename = default(string);

            if (data.Length == 0)
            {
                retVal.AddError($"The specified binary payload is empty.");
            }
            else
            {
                logger.Debug($"Saving new Package to '{tempFile}'...");
                retVal.Incorporate(Platform.WriteFileBytes(tempFile, data));

                if (retVal.ResultCode != ResultCode.Failure)
                {
                    IResult <IPackageArchive> readResult = PackageFactory.GetPackageArchive(tempFile);

                    retVal.Incorporate(readResult);

                    if (retVal.ResultCode != ResultCode.Failure)
                    {
                        IPackageArchive package = readResult.ReturnValue;

                        destinationFilename = package.FQN + "." + package.Manifest.Version + PackagingConstants.PackageFilenameExtension;
                        destinationFilename = ReplaceInvalidCharacters(destinationFilename);
                        destinationFilename = Path.Combine(PlatformManager.Directories.PackageArchives, destinationFilename);

                        logger.Debug($"Copying temporary Package '{tempFile}' to final destination '{destinationFilename}'...");
                        retVal.Incorporate(Platform.CopyFile(tempFile, destinationFilename, true));

                        if (retVal.ResultCode != ResultCode.Failure)
                        {
                            ScanPackageArchives();
                            retVal.ReturnValue = FindPackageArchive(readResult.ReturnValue.FQN);
                        }
                    }
                }
            }

            if (retVal.ResultCode != ResultCode.Failure)
            {
                logger.Debug($"Package Archive successfully saved to {destinationFilename}. Sending PackageArchiveAdded Event...");
                Task.Run(() => PackageArchiveAdded?.Invoke(this, new PackageArchiveEventArgs(retVal.ReturnValue)));
            }

            retVal.LogResult(logger);
            logger.ExitMethod(guid);
            return(retVal);
        }
コード例 #7
0
        private void CompressFile(IPackageArchive zOutstream, string file, string entryName)
        {
            fileEntries.Add(entryName);

            Log.LogMessage(MessageImportance.Low, "Adding {0}", entryName);

            using (FileStream fs = File.OpenRead(file)) //TODO: Exchange with CopyTo
            {
                zOutstream.AddEntry(entryName, File.GetLastWriteTime(file), fs);
            }
        }
コード例 #8
0
        public async Task <HttpResponseMessage> PackagesInstall(string fqn, [FromBody] PackageInstallationOptions options)
        {
            HttpResponseMessage retVal;
            ParameterValidator  validator = new ParameterValidator(ModelState);

            if (string.IsNullOrEmpty(fqn))
            {
                retVal = Request.CreateResponse(HttpStatusCode.BadRequest, new ParameterValidator().AddError("fqn", "The specified Fully Qualified Name is null or empty.").Result, JsonFormatter());
            }
            else if (!validator.IsValid)
            {
                retVal = Request.CreateResponse(HttpStatusCode.BadRequest, validator.Result);
            }
            else
            {
                IPackageArchive findResult = await PackageManager.FindPackageArchiveAsync(fqn);

                if (findResult != default(IPackageArchive))
                {
                    PackageInstallationOptions installOptions = new PackageInstallationOptions()
                    {
                        Overwrite        = options.Overwrite,
                        SkipVerification = options.SkipVerification,
                        PublicKey        = options.PublicKey,
                    };

                    IResult <IPackage> installResult = await PackageManager.InstallPackageAsync(findResult, installOptions);

                    if (installResult.ResultCode != ResultCode.Failure)
                    {
                        retVal = Request.CreateResponse(HttpStatusCode.OK, installResult.ReturnValue, JsonFormatter());
                    }
                    else
                    {
                        HttpErrorResult result = new HttpErrorResult($"Failed to install Package '{fqn}'.", installResult);
                        retVal = Request.CreateResponse(HttpStatusCode.InternalServerError, result, JsonFormatter());
                    }
                }
                else
                {
                    retVal = Request.CreateResponse(HttpStatusCode.NotFound);
                }
            }

            return(retVal);
        }
コード例 #9
0
        /// <summary>
        ///     Verifies the specified <paramref name="packageArchive"/> using the specified <paramref name="publicKey"/>.
        /// </summary>
        /// <param name="packageArchive">The <see cref="IPackageArchive"/> to verify.</param>
        /// <param name="publicKey">The PGP Public Key with which to verify the package.</param>
        /// <returns>
        ///     A Result containing the result of the operation and a value indicating whether the <see cref="IPackageArchive"/> is valid.
        /// </returns>
        public IResult <bool> VerifyPackageArchive(IPackageArchive packageArchive, string publicKey)
        {
            Guid guid = logger.EnterMethod(xLogger.Params(packageArchive, publicKey), true);

            logger.Info($"Verifying Package '{packageArchive?.FQN}'...");

            IResult <bool> retVal = new Result <bool>();

            if (packageArchive == default(IPackageArchive))
            {
                retVal.AddError($"The specified Package Archive is null.");
            }
            else if (string.IsNullOrEmpty(packageArchive.FileName))
            {
                retVal.AddError($"The specified Package Archive contains a null or empty FileName.");
            }
            else if (!Platform.FileExists(packageArchive.FileName))
            {
                retVal.AddError($"The specified Package Archive file '{packageArchive.FileName}' can not be found.");
            }
            else
            {
                PackageVerifier verifier = new PackageVerifier();
                verifier.Updated += (sender, e) =>
                {
                    logger.Debug($"     PackageVerifier: {e.Message}");
                    retVal.AddInfo(e.Message);
                };

                try
                {
                    retVal.ReturnValue = verifier.VerifyPackage(packageArchive.FileName, publicKey);
                }
                catch (Exception ex)
                {
                    logger.Exception(LogLevel.Debug, ex);
                    retVal.AddError(ex.Message);
                }
            }

            retVal.LogResult(logger);
            logger.ExitMethod(guid);
            return(retVal);
        }
コード例 #10
0
        public async Task <HttpResponseMessage> PackageArchivesGetFqnVerification(string fqn, string publicKey = default(string))
        {
            HttpResponseMessage retVal;

            if (string.IsNullOrEmpty(fqn))
            {
                retVal = Request.CreateResponse(HttpStatusCode.BadRequest, new ParameterValidator().AddError("fqn", "The specified Fully Qualified Name is null or empty.").Result, JsonFormatter());
            }
            else if (publicKey != default(string) && !new Regex(PackagingConstants.KeyRegEx).IsMatch(publicKey))
            {
                retVal = Request.CreateResponse(HttpStatusCode.BadRequest, new ParameterValidator().AddError("publicKey", "The specified PGP public key is not a valid key.").Result, JsonFormatter());
            }
            else
            {
                IPackageArchive findResult = await PackageManager.FindPackageArchiveAsync(fqn);

                if (findResult != default(IPackageArchive))
                {
                    IResult <bool> verifyResult = await PackageManager.VerifyPackageArchiveAsync(findResult);

                    if (verifyResult.ResultCode != ResultCode.Failure)
                    {
                        retVal = Request.CreateResponse(HttpStatusCode.OK, new PackageArchiveVerificationData(verifyResult), JsonFormatter());
                    }
                    else
                    {
                        HttpErrorResult result = new HttpErrorResult($"Failed to verify Package Archive '{fqn}'.", verifyResult);
                        retVal = Request.CreateResponse(HttpStatusCode.InternalServerError, result, JsonFormatter());
                    }
                }
                else
                {
                    retVal = Request.CreateResponse(HttpStatusCode.NotFound);
                }
            }

            return(retVal);
        }
コード例 #11
0
        public async Task <HttpResponseMessage> PackageArchivesGetFqnFile(string fqn)
        {
            HttpResponseMessage retVal;

            if (string.IsNullOrEmpty(fqn))
            {
                retVal = Request.CreateResponse(HttpStatusCode.BadRequest, new ParameterValidator().AddError("fqn", "The specified Fully Qualified Name is null or empty.").Result, JsonFormatter());
            }
            else
            {
                IPackageArchive findResult = await PackageManager.FindPackageArchiveAsync(fqn);

                if (findResult != default(IPackageArchive))
                {
                    IResult <byte[]> readResult = await PackageManager.FetchPackageArchiveAsync(findResult);

                    if (readResult.ResultCode != ResultCode.Failure)
                    {
                        retVal         = Request.CreateResponse(HttpStatusCode.OK);
                        retVal.Content = new ByteArrayContent(readResult.ReturnValue);
                        retVal.Content.Headers.ContentDisposition          = new ContentDispositionHeaderValue("attachment");
                        retVal.Content.Headers.ContentDisposition.FileName = Path.GetFileName(findResult.FileName);
                    }
                    else
                    {
                        HttpErrorResult result = new HttpErrorResult($"Failed to retrieve contents of Package Archive '{fqn}'.", readResult);
                        retVal = Request.CreateResponse(HttpStatusCode.InternalServerError, result, JsonFormatter());
                    }
                }
                else
                {
                    retVal = Request.CreateResponse(HttpStatusCode.NotFound);
                }
            }

            return(retVal);
        }
コード例 #12
0
        /// <summary>
        ///     Deletes the specified <see cref="IPackageArchive"/> from disk.
        /// </summary>
        /// <param name="packageArchive">The <see cref="IPackageArchive"/> to delete.</param>
        /// <returns>A Result containing the result of the operation.</returns>
        public IResult DeletePackageArchive(IPackageArchive packageArchive)
        {
            Guid guid = logger.EnterMethod(xLogger.Params(packageArchive));

            logger.Info($"Deleting Package {packageArchive?.FQN}...");

            IResult retVal = new Result();

            if (packageArchive == default(IPackageArchive))
            {
                retVal.AddError($"The specified Package Archive is null.");
            }
            else if (string.IsNullOrEmpty(packageArchive.FileName))
            {
                retVal.AddError($"The specified Package Archive contains an null or empty Filename.");
            }
            else if (!Platform.FileExists(packageArchive.FileName))
            {
                retVal.AddError($"The specified Package Archive file '{packageArchive.FileName}' can not be found.");
            }
            else
            {
                logger.Debug($"Deleting Package file '{packageArchive.FileName}'...");
                retVal = Platform.DeleteFile(packageArchive.FileName);
            }

            if (retVal.ResultCode != ResultCode.Failure)
            {
                logger.Debug($"Package {packageArchive.FileName} deleted successfully.  Sending PackageArchiveDeleted Event...");
                Task.Run(() => PackageArchiveDeleted?.Invoke(this, new PackageArchiveEventArgs(packageArchive)));
            }

            retVal.LogResult(logger);
            logger.ExitMethod(guid);
            return(retVal);
        }
コード例 #13
0
        public async Task <HttpResponseMessage> PackageArchivesGetFqn(string fqn)
        {
            HttpResponseMessage retVal;

            if (string.IsNullOrEmpty(fqn))
            {
                retVal = Request.CreateResponse(HttpStatusCode.BadRequest, new ParameterValidator().AddError("fqn", "The specified Fully Qualified Name is null or empty.").Result, JsonFormatter());
            }
            else
            {
                IPackageArchive packageArchive = await PackageManager.FindPackageArchiveAsync(fqn);

                if (packageArchive != default(IPackageArchive))
                {
                    retVal = Request.CreateResponse(HttpStatusCode.OK, packageArchive, JsonFormatter());
                }
                else
                {
                    retVal = Request.CreateResponse(HttpStatusCode.NotFound, JsonFormatter());
                }
            }

            return(retVal);
        }
コード例 #14
0
 /// <summary>
 ///     Asynchronously deletes the specified <see cref="IPackageArchive"/> from disk.
 /// </summary>
 /// <param name="packageArchive">The <see cref="IPackageArchive"/> to delete.</param>
 /// <returns>A Result containing the result of the operation.</returns>
 public Task <IResult> DeletePackageArchiveAsync(IPackageArchive packageArchive)
 {
     return(Task.Run(() => DeletePackageArchive(packageArchive)));
 }
コード例 #15
0
 /// <summary>
 ///     Initializes a new instance of the <see cref="PackageArchiveEventArgs"/> class.
 /// </summary>
 /// <param name="packageArchive">The <see cref="IPackageArchive"/> associated with the event.</param>
 public PackageArchiveEventArgs(IPackageArchive packageArchive)
 {
     PackageArchive = packageArchive;
 }
コード例 #16
0
 /// <summary>
 ///     Asynchronously fetches the specified <paramref name="packageArchive"/> and returns the binary data.
 /// </summary>
 /// <param name="packageArchive">The <see cref="IPackageArchive"/> to fetch.</param>
 /// <returns>
 ///     A Result containing the result of the operation and the <see cref="byte"/> array containing the fetched data.
 /// </returns>
 public Task <IResult <byte[]> > FetchPackageArchiveAsync(IPackageArchive packageArchive)
 {
     return(Task.Run(() => FetchPackageArchive(packageArchive)));
 }
コード例 #17
0
        private bool CompressFileSet(IPackageArchive zOutstream, string basePath, string targetDir, IEnumerable <string> fileNames, bool addDeploy)
        {
            addedDirs.Clear();
            fileEntries.Clear();

            basePath = Path.GetFullPath(basePath);
            // add files to zip
            foreach (string fn in fileNames)
            {
                string file = Path.GetFullPath(fn);

                if (!File.Exists(file))
                {
                    Log.LogError("File '{0}' not found.", file);
                    return(false);
                }

                // the name of the zip entry
                string entryName;

                // determine name of the zip entry
                if (file.StartsWith(basePath, StringComparison.OrdinalIgnoreCase))
                {
                    entryName = file.Substring(basePath.Length);
                    if (entryName.Length > 0 && entryName[0] == Path.DirectorySeparatorChar)
                    {
                        entryName = entryName.Substring(1);
                    }

                    if (!string.IsNullOrEmpty(targetDir))
                    {
                        entryName = Path.Combine(targetDir, entryName);
                    }

                    // remember that directory was added to zip file, so
                    // that we won't add it again later
                    string dir = Path.GetDirectoryName(file);
                    if (!addedDirs.Contains(dir))
                    {
                        addedDirs.Add(dir);
                    }
                }
                else
                {
                    entryName = Path.GetFileName(file);
                }

                if (addDeploy)
                {
                    entryName = AddDeploySuffix(entryName);
                }

                entryName = ReplaceDirectorySeparators(entryName);

                if (fileEntries.Contains(entryName))
                {
                    Log.LogError("Dublicate file was found: {0}", entryName);
                    return(false);
                }

                CompressFile(zOutstream, file, entryName);
            }

            return(true);
        }
コード例 #18
0
 /// <summary>
 ///     Asynchronously verifies the specified <paramref name="packageArchive"/>.
 /// </summary>
 /// <param name="packageArchive">The <see cref="IPackageArchive"/> to verify.</param>
 /// <returns>
 ///     A Result containing the result of the operation and a value indicating whether the <see cref="IPackageArchive"/> is valid.
 /// </returns>
 public Task <IResult <bool> > VerifyPackageArchiveAsync(IPackageArchive packageArchive)
 {
     return(Task.Run(() => VerifyPackageArchive(packageArchive)));
 }
コード例 #19
0
 /// <summary>
 ///     Installs the specified <paramref name="packageArchive"/>.
 /// </summary>
 /// <param name="packageArchive">The <see cref="IPackageArchive"/> to install.</param>
 /// <returns>A Result containing the result of the operation and the installed <see cref="IPackage"/>.</returns>
 public IResult <IPackage> InstallPackage(IPackageArchive packageArchive)
 {
     return(InstallPackage(packageArchive, new PackageInstallationOptions()));
 }
コード例 #20
0
 /// <summary>
 ///     Verifies the specified <paramref name="packageArchive"/>.
 /// </summary>
 /// <param name="packageArchive">The <see cref="IPackageArchive"/> to verify.</param>
 /// <returns>
 ///     A Result containing the result of the operation and a value indicating whether the <see cref="IPackageArchive"/> is valid.
 /// </returns>
 public IResult <bool> VerifyPackageArchive(IPackageArchive packageArchive)
 {
     return(VerifyPackageArchive(packageArchive, string.Empty));
 }
コード例 #21
0
 /// <summary>
 ///     Asynchronously installs the specified <paramref name="packageArchive"/> with the specified <paramref name="options"/>.
 /// </summary>
 /// <param name="packageArchive">The <see cref="IPackageArchive"/> to install.</param>
 /// <param name="options">The <see cref="PackageInstallationOptions"/> for the installation.</param>
 /// <returns>A Result containing the result of the operation and the installed <see cref="IPackage"/>.</returns>
 public async Task <IResult <IPackage> > InstallPackageAsync(IPackageArchive packageArchive, PackageInstallationOptions options)
 {
     return(await Task.Run(() => InstallPackage(packageArchive, options)));
 }
コード例 #22
0
        /// <summary>
        ///     Installs the specified <paramref name="packageArchive"/> with the specified <paramref name="options"/>.
        /// </summary>
        /// <param name="packageArchive">The <see cref="IPackageArchive"/> to install.</param>
        /// <param name="options">The <see cref="PackageInstallationOptions"/> for the installation.</param>
        /// <returns>A Result containing the result of the operation and the installed <see cref="IPackage"/>.</returns>
        public IResult <IPackage> InstallPackage(IPackageArchive packageArchive, PackageInstallationOptions options)
        {
            Guid guid = logger.EnterMethod(xLogger.Params(packageArchive, options), true);

            logger.Info($"Installing Package '{packageArchive?.FQN}' from '{packageArchive?.FileName}'...");

            IResult <IPackage> retVal      = new Result <IPackage>();
            string             destination = default(string);

            if (packageArchive == default(IPackageArchive))
            {
                retVal.AddError($"The specified Package Archive is null.");
            }
            else if (string.IsNullOrEmpty(packageArchive.FileName))
            {
                retVal.AddError($"The specified Package Archive contains a null or empty FileName.");
            }
            else if (!Platform.FileExists(packageArchive.FileName))
            {
                retVal.AddError($"The specified Package Archive file '{packageArchive.FileName}' can not be found.");
            }
            else if (options == default(PackageInstallationOptions))
            {
                retVal.AddError($"Installation options were specified but are null.");
            }
            else if (options?.PublicKey != default(string) && options.PublicKey == string.Empty)
            {
                retVal.AddError($"The PGP installation key is specified but is empty.");
            }
            else
            {
                PackageExtractor extractor = new PackageExtractor();
                extractor.Updated += (sender, e) => logger.Debug($"    PackageExtractor: {e.Message}");

                // determine the installation directory; should look like \path\to\Plugins\FQN\
                destination = ReplaceInvalidCharacters(packageArchive.FQN);
                destination = Path.Combine(PlatformManager.Directories.Packages, destination);

                logger.Debug($"Install directory: '{destination}'; overwrite={options.Overwrite}, skipVerification={options.SkipVerification}");

                try
                {
                    extractor.ExtractPackage(packageArchive.FileName, destination, options?.PublicKey, options.Overwrite, options.SkipVerification);
                }
                catch (Exception ex)
                {
                    logger.Exception(LogLevel.Debug, ex);
                    retVal.AddError(ex.Message);
                }

                ScanPackages();

                retVal.ReturnValue = FindPackage(packageArchive.FQN);
            }

            if (retVal.ResultCode != ResultCode.Failure)
            {
                logger.Debug($"Package {retVal.ReturnValue.FQN} installed successfully. Sending PackageInstalled Event...");
                Task.Run(() => PackageInstalled?.Invoke(this, new PackageInstallEventArgs(retVal.ReturnValue, destination)));
            }

            retVal.LogResult(logger);
            logger.ExitMethod(guid);
            return(retVal);
        }