コード例 #1
0
ファイル: PackageActionHelpers.cs プロジェクト: ZHJEE/OpenTAP
        internal static List <PackageDef> GatherPackagesAndDependencyDefs(Installation installation, PackageSpecifier[] pkgRefs, string[] packageNames, string Version, CpuArchitecture arch, string OS, List <IPackageRepository> repositories, bool force, bool includeDependencies, bool askToIncludeDependencies, bool noDowngrade)
        {
            List <PackageDef> gatheredPackages = new List <PackageDef>();

            List <PackageSpecifier> packages = new List <PackageSpecifier>();

            if (pkgRefs != null)
            {
                packages = pkgRefs.ToList();
            }
            else
            {
                if (packageNames == null)
                {
                    throw new Exception("No packages specified.");
                }
                foreach (string packageName in packageNames)
                {
                    var version = Version;
                    if (Path.GetExtension(packageName).ToLower().EndsWith("tappackages"))
                    {
                        var tempDir          = Path.GetTempPath();
                        var bundleFiles      = PluginInstaller.UnpackPackage(packageName, tempDir);
                        var packagesInBundle = bundleFiles.Select(PackageDef.FromPackage);

                        // A packages file may contain the several variants of the same package, try to select one based on OS and Architecture
                        foreach (IGrouping <string, PackageDef> grp in packagesInBundle.GroupBy(p => p.Name))
                        {
                            var selected = grp.ToList();
                            if (selected.Count == 1)
                            {
                                gatheredPackages.Add(selected.First());
                                continue;
                            }
                            if (!string.IsNullOrEmpty(OS))
                            {
                                selected = selected.Where(p => p.OS.ToLower().Split(',').Any(OS.ToLower().Contains)).ToList();
                                if (selected.Count == 1)
                                {
                                    gatheredPackages.Add(selected.First());
                                    log.Debug("TapPackages file contains packages for several operating systems. Picking only the one for {0}.", OS);
                                    continue;
                                }
                            }
                            if (arch != CpuArchitecture.Unspecified)
                            {
                                selected = selected.Where(p => ArchitectureHelper.CompatibleWith(arch, p.Architecture)).ToList();
                                if (selected.Count == 1)
                                {
                                    gatheredPackages.Add(selected.First());
                                    log.Debug("TapPackages file contains packages for several CPU architectures. Picking only the one for {0}.", arch);
                                    continue;
                                }
                            }
                            throw new Exception("TapPackages file contains multiple variants of the same package. Unable to autoselect a suitable one.");
                        }
                    }
                    else if (string.IsNullOrWhiteSpace(packageName) == false)
                    {
                        packages.Add(new PackageSpecifier(packageName, VersionSpecifier.Parse(version ?? ""), arch, OS));
                    }
                }
            }

            foreach (var packageReference in packages)
            {
                var       installedPackages = installation.GetPackages();
                Stopwatch timer             = Stopwatch.StartNew();
                if (File.Exists(packageReference.Name))
                {
                    var package = PackageDef.FromPackage(packageReference.Name);

                    if (noDowngrade)
                    {
                        var installedPackage = installedPackages.FirstOrDefault(p => p.Name == package.Name);
                        if (installedPackage != null && installedPackage.Version.CompareTo(package.Version) >= 0)
                        {
                            log.Info($"The same or a newer version of package '{package.Name}' in already installed.");
                            continue;
                        }
                    }

                    gatheredPackages.Add(package);
                    log.Debug(timer, "Found package {0} locally.", packageReference.Name);
                }
                else
                {
                    PackageDef package = PackageActionHelpers.FindPackage(packageReference, force, installation, repositories);

                    if (noDowngrade)
                    {
                        var installedPackage = installedPackages.FirstOrDefault(p => p.Name == package.Name);
                        if (installedPackage != null && installedPackage.Version.CompareTo(package.Version) >= 0)
                        {
                            log.Info($"The same or a newer version of package '{package.Name}' in already installed.");
                            continue;
                        }
                    }

                    if (PackageCacheHelper.PackageIsFromCache(package))
                    {
                        log.Debug(timer, "Found package {0} version {1} in local cache", package.Name, package.Version);
                    }
                    else
                    {
                        log.Debug(timer, "Found package {0} version {1}", package.Name, package.Version);
                    }

                    gatheredPackages.Add(package);
                }
            }

            if (gatheredPackages.All(p => p.IsBundle()))
            {
                // If we are just installing bundles, we can assume that dependencies should also be installed
                includeDependencies = true;
            }

            log.Debug("Resolving dependencies.");
            var resolver = new DependencyResolver(installation, gatheredPackages, repositories);

            if (resolver.UnknownDependencies.Any())
            {
                foreach (var dep in resolver.UnknownDependencies)
                {
                    string message = string.Format("A package dependency named '{0}' with a version compatible with {1} could not be found in any repository.", dep.Name, dep.Version);

                    if (force)
                    {
                        log.Warning(message);
                        log.Warning("Continuing without downloading dependencies. Plugins will likely not work as expected.", dep.Name);
                    }
                    else
                    {
                        log.Error(message);
                    }
                }
                if (!force)
                {
                    log.Info("To download package dependencies despite the conflicts, use the --force option.");
                    return(null);
                }
            }
            else if (resolver.MissingDependencies.Any())
            {
                string dependencyArgsHint = "";
                if (!includeDependencies)
                {
                    dependencyArgsHint = $" (use --dependencies to also get these)";
                }
                if (resolver.MissingDependencies.Count > 1)
                {
                    log.Info("{0} required dependencies are currently not installed{1}.", resolver.MissingDependencies.Count, dependencyArgsHint);
                }
                else
                {
                    log.Info("A required dependency is currently not installed{0}.", dependencyArgsHint);
                }


                if (includeDependencies)
                {
                    //log.Debug($"Currently set to download dependencies quietly.");
                    foreach (var package in resolver.MissingDependencies)
                    {
                        log.Debug("Adding dependency {0} {1}", package.Name, package.Version);
                        gatheredPackages.Insert(0, package);
                    }
                }
                else if (askToIncludeDependencies)
                {
                    var pkgs = new List <DepRequest>();

                    foreach (var package in resolver.MissingDependencies)
                    {
                        // Handle each package at a time.
                        DepRequest req = null;
                        pkgs.Add(req = new DepRequest {
                            PackageName = package.Name, message = string.Format("Add dependency {0} {1} ?", package.Name, package.Version), Response = DepResponse.Add
                        });
                        UserInput.Request(req, true);
                    }

                    foreach (var pkg in resolver.MissingDependencies)
                    {
                        var res = pkgs.FirstOrDefault(r => r.PackageName == pkg.Name);

                        if ((res != null) && res.Response == DepResponse.Add)
                        {
                            gatheredPackages.Insert(0, pkg);
                        }
                    }
                }
            }

            return(gatheredPackages);
        }
コード例 #2
0
ファイル: Installer.cs プロジェクト: ZHJEE/OpenTAP
        internal void InstallThread()
        {
            if (cancellationToken.IsCancellationRequested)
            {
                return;
            }

            try
            {
                waitForPackageFilesFree(TapDir, PackagePaths);

                int progressPercent = 10;
                OnProgressUpdate(progressPercent, "");
                foreach (string fileName in PackagePaths)
                {
                    try
                    {
                        OnProgressUpdate(progressPercent, "Installing " + Path.GetFileNameWithoutExtension(fileName));
                        Stopwatch  timer = Stopwatch.StartNew();
                        PackageDef pkg   = PluginInstaller.InstallPluginPackage(TapDir, fileName);

                        log.Info(timer, "Installed " + pkg.Name + " version " + pkg.Version);

                        progressPercent += 80 / PackagePaths.Count();

                        if (pkg.Files.Any(s => s.Plugins.Any(p => p.BaseType == nameof(ICustomPackageData))) && PackagePaths.Last() != fileName)
                        {
                            log.Info(timer, $"Package '{pkg.Name}' contains possibly relevant plugins for next package installations. Searching for plugins..");
                            PluginManager.DirectoriesToSearch.Add(TapDir);
                            PluginManager.SearchAsync();
                        }
                    }
                    catch
                    {
                        if (!ForceInstall)
                        {
                            if (PackagePaths.Last() != fileName)
                            {
                                log.Warning("Aborting installation of remaining packages (use --force to override this behavior).");
                            }
                            throw;
                        }
                        else
                        {
                            if (PackagePaths.Last() != fileName)
                            {
                                log.Warning("Continuing installation of remaining packages (--force argument used).");
                            }
                        }
                    }
                }
                OnProgressUpdate(90, "");

                if (DoSleep)
                {
                    Thread.Sleep(100);
                }

                OnProgressUpdate(100, "Plugin installed.");
                Thread.Sleep(50); // Let Eventhandler get the last OnProgressUpdate
            }
            catch (Exception ex)
            {
                OnError(ex);
                return;
            }

            Installation installation = new Installation(TapDir);

            installation.AnnouncePackageChange();
        }
コード例 #3
0
ファイル: Installer.cs プロジェクト: ZHJEE/OpenTAP
        private void waitForPackageFilesFree(string tapDir, List <string> PackagePaths)
        {
            // ignore tap.exe as it is not meant to be overwritten.
            bool exclude(string filename) => filename.ToLower() == "tap" || filename.ToLower() == "tap.exe";

            List <FileInfo> filesInUse = new List <FileInfo>();

            foreach (string packageFileName in PackagePaths)
            {
                foreach (string file in PluginInstaller.FilesInPackage(packageFileName))
                {
                    string fullPath = Path.Combine(tapDir, file);
                    string filename = Path.GetFileName(file);
                    if (exclude(filename))
                    {
                        continue;
                    }
                    if (IsFileLocked(new FileInfo(fullPath)))
                    {
                        filesInUse.Add(new FileInfo(fullPath));
                    }
                }
            }

            // Check if the files that are in use are used by any other package
            var packages = PackagePaths.Select(p => p.EndsWith("TapPackage") ? PackageDef.FromPackage(p) : PackageDef.FromXml(p));
            var remainingInstalledPlugins = new Installation(tapDir).GetPackages().Where(i => packages.Any(p => p.Name == i.Name) == false);
            var filesToRemain             = remainingInstalledPlugins.SelectMany(p => p.Files).Select(f => f.RelativeDestinationPath).Distinct(StringComparer.InvariantCultureIgnoreCase);

            filesInUse = filesInUse.Where(f => filesToRemain.Contains(f.Name, StringComparer.InvariantCultureIgnoreCase) == false).ToList();

            if (filesInUse.Count > 0)
            {
                log.Info("Following files cannot be modified because they are in use:");
                foreach (var file in filesInUse)
                {
                    log.Info("- " + file.FullName);

                    var loaded_asm = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault(x => x.IsDynamic == false && x.Location == file.FullName);
                    if (loaded_asm != null)
                    {
                        throw new InvalidOperationException($"The file '{file.FullName}' is being used by this process.");
                    }
                }

                var allProcesses = Process.GetProcesses().Where(p =>
                                                                p.ProcessName.ToLowerInvariant().Contains("opentap") &&
                                                                p.ProcessName.ToLowerInvariant().Contains("vshost") == false &&
                                                                p.ProcessName != Assembly.GetExecutingAssembly().GetName().Name).ToArray();
                if (allProcesses.Any())
                {
                    // The file could be locked by someone other than OpenTAP processes. We should not assume it's OpenTAP holding the file.
                    log.Warning(Environment.NewLine + "To continue, try closing applications that could be using the files.");
                    foreach (var process in allProcesses)
                    {
                        log.Warning("- " + process.ProcessName);
                    }
                }

                log.Warning(Environment.NewLine + "Waiting for files to become unlocked...");

                while (isPackageFilesInUse(tapDir, PackagePaths, exclude))
                {
                    if (cancellationToken.IsCancellationRequested)
                    {
                        return;
                    }
                    if (!isTapRunning())
                    {
                        OnError(new IOException("One or more plugin files are in use. View log for more information."));
                    }
                    Thread.Sleep(300);
                }
            }
        }
コード例 #4
0
ファイル: Installer.cs プロジェクト: ZHJEE/OpenTAP
        internal bool RunCommand(string command, bool force, bool modifiesPackageFiles)
        {
            var verb = System.Globalization.CultureInfo.CurrentCulture.TextInfo.ToTitleCase(command.ToLower()) + "ed";

            try
            {
                if (modifiesPackageFiles)
                {
                    waitForPackageFilesFree(TapDir, PackagePaths);
                }

                if (cancellationToken.IsCancellationRequested)
                {
                    log.Debug("Received abort while waiting for package files to be unlocked.");
                    return(false);
                }

                double progressPercent = 10;
                OnProgressUpdate((int)progressPercent, "");

                PluginInstaller pi = new PluginInstaller();

                foreach (string fileName in PackagePaths)
                {
                    PackageDef pkg = PackageDef.FromXml(fileName);
                    OnProgressUpdate((int)progressPercent, string.Format("Running command '{0}' on '{1}'", command, pkg.Name));
                    Stopwatch timer = Stopwatch.StartNew();
                    var       res   = pi.ExecuteAction(pkg, command, force, TapDir);

                    if (res == ActionResult.Error)
                    {
                        OnProgressUpdate(100, "Done");
                        return(false);
                    }
                    else if (res == ActionResult.NothingToDo)
                    {
                        log.Info(string.Format("Tried to {0} {1}, but there was nothing to do.", command, pkg.Name));
                    }
                    else
                    {
                        log.Info(timer, string.Format("{1} {0} version {2}.", pkg.Name, verb, pkg.Version));
                    }

                    progressPercent += (double)80 / PackagePaths.Count();
                }
                OnProgressUpdate(90, "");

                if (DoSleep)
                {
                    Thread.Sleep(100);
                }

                OnProgressUpdate(100, "Done");
                Thread.Sleep(50); // Let Eventhandler get the last OnProgressUpdate
            }
            catch (Exception ex)
            {
                OnError(ex);
                return(false);
            }

            new Installation(TapDir).AnnouncePackageChange();

            return(true);
        }
コード例 #5
0
ファイル: PluginInstaller.cs プロジェクト: ZHJEE/OpenTAP
        private static ActionResult DoUninstall(PluginInstaller pluginInstaller, ActionExecuter action, PackageDef package, bool force, string target)
        {
            var result      = ActionResult.Ok;
            var destination = package.IsSystemWide() ? PackageDef.SystemWideInstallationDirectory : target;

            var filesToRemain = new Installation(destination).GetPackages().Where(p => p.Name != package.Name).SelectMany(p => p.Files).Select(f => f.RelativeDestinationPath).Distinct(StringComparer.InvariantCultureIgnoreCase).ToHashSet(StringComparer.InvariantCultureIgnoreCase);

            try
            {
                CustomPackageActionHelper.RunCustomActions(package, PackageActionStage.Uninstall, new CustomPackageActionArgs(null, force));
            }
            catch (Exception ex)
            {
                log.Error(ex);
                result = ActionResult.Error;
            }

            try
            {
                if (action.ExecutePackageActionSteps(package, force, target) == ActionResult.Error)
                {
                    throw new Exception();
                }
            }
            catch
            {
                log.Error($"Uninstall package action failed to execute for package '{package.Name}'.");
                result = ActionResult.Error;
            }

            foreach (var file in package.Files)
            {
                if (file.RelativeDestinationPath == "tap" || file.RelativeDestinationPath.ToLower() == "tap.exe") // ignore tap.exe as it is not meant to be overwritten.
                {
                    continue;
                }

                string fullPath;
                if (package.IsSystemWide())
                {
                    fullPath = Path.Combine(PackageDef.SystemWideInstallationDirectory, file.RelativeDestinationPath);
                }
                else
                {
                    fullPath = Path.Combine(destination, file.RelativeDestinationPath);
                }

                if (filesToRemain.Contains(file.RelativeDestinationPath))
                {
                    log.Debug("Skipping deletion of file '{0}' since it is required by another plugin package.", file.RelativeDestinationPath);
                    continue;
                }

                try
                {
                    log.Debug("Deleting file '{0}'.", file.RelativeDestinationPath);
                    File.Delete(fullPath);
                }
                catch (Exception e)
                {
                    log.Debug(e);
                    result = ActionResult.Error;
                }

                DeleteEmptyDirectory(new FileInfo(fullPath).Directory);
            }

            var packageFile = PackageDef.GetDefaultPackageMetadataPath(package, target);

            if (!File.Exists(packageFile))
            {
                // TAP 8.x support:
                packageFile = $"Package Definitions/{package.Name}.package.xml";
            }
            if (File.Exists(packageFile))
            {
                log.Debug("Deleting file '{0}'.", packageFile);
                File.Delete(packageFile);
                DeleteEmptyDirectory(new FileInfo(packageFile).Directory);
            }
            return(result);
        }
コード例 #6
0
ファイル: PluginInstaller.cs プロジェクト: ZHJEE/OpenTAP
        /// <summary>
        /// Uninstalls a package.
        /// </summary>
        internal static void Uninstall(PackageDef package, string target)
        {
            var pi = new PluginInstaller();

            pi.ExecuteAction(package, "uninstall", true, target);
        }