Пример #1
0
        public override bool Serialize(XElement elem, object obj, ITypeData type)
        {
            if (endnode == null)
            {
                endnode = elem;
                bool ok = Serializer.Serialize(elem, obj, type);

                if (WritePackageDependencies) // Allow a serializer futher down the stack to disable the <Package.Dependencies> tag
                {
                    var pluginsNode   = new XElement(PackageDependenciesName);
                    var allAssemblies = Serializer.GetUsedTypes().Select(getAssemblyName).Where(x => x != null).ToHashSet(StringComparer.InvariantCultureIgnoreCase);
                    var plugins       = new Installation(Path.GetDirectoryName(PluginManager.GetOpenTapAssembly().Location)).GetPackages();

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

                    foreach (var plugin in plugins)
                    {
                        foreach (var file in plugin.Files)
                        {
                            var filename = Path.GetFileName(file.FileName.Replace("\\", "/"));

                            if (allAssemblies.Contains(filename))
                            {
                                packages.Add(plugin);
                                break;
                            }
                        }
                    }

                    foreach (var pkg in packages)
                    {
                        var newnode = new XElement(PackageDependencyName);
                        newnode.Add(new XAttribute(NameName, pkg.Name));
                        if (pkg.Version != null)
                        {
                            newnode.Add(new XAttribute(VersionName, pkg.Version));
                        }
                        pluginsNode.Add(newnode);
                    }
                    elem.Add(pluginsNode);
                }

                endnode = null;
                return(ok);
            }
            return(false);
        }
Пример #2
0
        public override int Execute(CancellationToken cancellationToken)
        {
            if (Packages == null)
            {
                throw new Exception("No packages specified.");
            }

            var target = LockingPackageAction.GetLocalInstallationDir();


            Installer installer = new Installer(target, cancellationToken)
            {
                DoSleep = false
            };

            installer.ProgressUpdate += RaiseProgressUpdate;
            installer.Error          += RaiseError;

            var installedPackages = new Installation(target).GetPackages();

            bool anyUnrecognizedPlugins = false;

            foreach (string pack in Packages)
            {
                PackageDef package = installedPackages.FirstOrDefault(p => p.Name == pack);

                if (package != null && package.PackageSource is InstalledPackageDefSource source)
                {
                    installer.PackagePaths.Add(source.PackageDefFilePath);
                }
                else if (!IgnoreMissing)
                {
                    log.Error("Package '{0}' is not installed", pack);
                    anyUnrecognizedPlugins = true;
                }
            }

            if (anyUnrecognizedPlugins)
            {
                return(-2);
            }

            return(installer.RunCommand("test", false, false) ? 0 : -1);
        }
Пример #3
0
        protected override int LockedExecute(CancellationToken cancellationToken)
        {
            if (OutputPaths.Length > Packages.Length)
            {
                throw new Exception("More OutputPaths specified than packages. Exiting.");
            }

            string       destinationDir          = Target ?? Directory.GetCurrentDirectory();
            Installation destinationInstallation = new Installation(destinationDir);

            List <IPackageRepository> repositories = new List <IPackageRepository>();

            if (Repository == null)
            {
                repositories.AddRange(PackageManagerSettings.Current.Repositories.Where(p => p.IsEnabled).Select(s => s.Manager).ToList());
            }
            else
            {
                repositories.AddRange(Repository.Select(s => PackageRepositoryHelpers.DetermineRepositoryType(s)));
            }

            List <PackageDef> PackagesToDownload = PackageActionHelpers.GatherPackagesAndDependencyDefs(destinationInstallation, PackageReferences, Packages, Version, Architecture, OS, repositories, ForceInstall, InstallDependencies, false, false);

            if (PackagesToDownload == null)
            {
                return(2);
            }

            if (!DryRun)
            {
                // If OutputPaths are specified, download the specified packages to those locations before downloading the remaining files
                // Place the remaining files in the same location as the last named location
                for (int i = 0; i < OutputPaths.Length; i++)
                {
                    var outputPath  = OutputPaths[i];
                    var packageName = Packages[i];
                    var package     = PackagesToDownload.First(p =>
                                                               p.Name == packageName || (p.PackageSource is FilePackageDefSource s &&
                                                                                         s.PackageFilePath == Path.GetFullPath(packageName)));

                    string filename = null;

                    // Treat path as a directory if it ends with '/'
                    if (outputPath.EndsWith("/") || outputPath.EndsWith(Path.DirectorySeparatorChar.ToString()))
                    {
                        Directory.CreateDirectory(outputPath);
                    }
                    if (Directory.Exists(outputPath))
                    {
                        destinationDir = outputPath;
                    }
                    // Otherwise, treat it as a full path
                    else
                    {
                        var file = new FileInfo(outputPath);
                        destinationDir = file.DirectoryName;
                        Directory.CreateDirectory(destinationDir);
                        filename = file.FullName;
                    }

                    PackageActionHelpers.DownloadPackages(destinationDir, new List <PackageDef>()
                    {
                        package
                    },
                                                          new List <string>()
                    {
                        filename
                    });
                    PackagesToDownload.Remove(package);
                }

                // Download the remaining packages
                PackageActionHelpers.DownloadPackages(destinationDir, PackagesToDownload);
            }
            else
            {
                log.Info("Dry run completed. Specified packages are available.");
            }

            DownloadedPackages = PackagesToDownload;
            return(0);
        }
Пример #4
0
        protected override int LockedExecute(CancellationToken cancellationToken)
        {
            if (OS == null)
            {
                switch (Environment.OSVersion.Platform)
                {
                case PlatformID.MacOSX:
                    OS = "OSX";
                    break;

                case PlatformID.Unix:
                    OS = "Linux";
                    break;

                default:
                    OS = "Windows";
                    break;
                }
            }

            List <IPackageRepository> repositories = new List <IPackageRepository>();

            if (Installed == false)
            {
                if (Repository == null)
                {
                    repositories.AddRange(PackageManagerSettings.Current.Repositories.Where(p => p.IsEnabled).Select(s => s.Manager));
                }
                else
                {
                    repositories.AddRange(Repository.Select(s => PackageRepositoryHelpers.DetermineRepositoryType(s)));
                }
            }

            if (Target == null)
            {
                Target = FileSystemHelper.GetCurrentInstallationDirectory();
            }

            HashSet <PackageDef> installed = new Installation(Target).GetPackages().ToHashSet();


            VersionSpecifier versionSpec = VersionSpecifier.Parse("^");

            if (!String.IsNullOrWhiteSpace(Version))
            {
                versionSpec = VersionSpecifier.Parse(Version);
            }

            if (string.IsNullOrEmpty(Name))
            {
                var packages = installed.ToList();
                packages.AddRange(PackageRepositoryHelpers.GetPackageNameAndVersionFromAllRepos(repositories, new PackageSpecifier("", versionSpec, Architecture, OS)));

                if (Installed)
                {
                    packages = packages.Where(p => installed.Any(i => i.Name == p.Name)).ToList();
                }

                PrintReadable(packages, installed);
            }
            else
            {
                IPackageIdentifier package = installed.FirstOrDefault(p => p.Name == Name);

                if (Installed)
                {
                    if (package is null)
                    {
                        log.Info($"{Name} is not installed");
                        return(-1);
                    }

                    log.Info(package.Version.ToString());
                    return(0);
                }


                List <PackageVersion> versions = null;

                if (All)
                {
                    versions = PackageRepositoryHelpers.GetAllVersionsFromAllRepos(repositories, Name).Distinct().ToList();
                    var versionsCount = versions.Count;
                    if (versionsCount == 0) // No versions
                    {
                        log.Info($"No versions of '{Name}'.");
                        return(0);
                    }

                    if (Version != null) // Version is specified by user
                    {
                        versions = versions.Where(v => versionSpec.IsCompatible(v.Version)).ToList();
                    }

                    if (versions.Any() == false && versionsCount > 0)
                    {
                        log.Info($"Package '{Name}' does not exists with version '{Version}'.");
                        log.Info($"Package '{Name}' exists in {versionsCount} other versions, please specify a different version.");
                        return(0);
                    }
                }
                else
                {
                    var opentap = new Installation(Target).GetOpenTapPackage();
                    versions = PackageRepositoryHelpers.GetAllVersionsFromAllRepos(repositories, Name, opentap).Distinct().ToList();

                    versions = versions.Where(s => s.IsPlatformCompatible(Architecture, OS)).ToList();

                    if (versions.Any() == false) // No compatible versions
                    {
                        versions = PackageRepositoryHelpers.GetAllVersionsFromAllRepos(repositories, Name).ToList();
                        if (versions.Any())
                        {
                            log.Warning($"There are no compatible versions of '{Name}'.");
                            log.Info($"There are {versions.Count} incompatible versions available. Use '--all' to show these.");
                        }
                        else
                        {
                            log.Warning($"Package '{Name}' could not be found in any repository.");
                        }

                        return(0);
                    }


                    versions = versions.Where(v => versionSpec.IsCompatible(v.Version)).ToList();
                    if (versions.Any() == false) // No versions that are compatible
                    {
                        if (string.IsNullOrEmpty(Version))
                        {
                            log.Warning($"There are no released versions of '{Name}'.");
                        }
                        else
                        {
                            log.Warning($"Package '{Name}' does not exists with version '{Version}'.");
                        }

                        var anyPrereleaseSpecifier = new VersionSpecifier(versionSpec.Major, versionSpec.Minor, versionSpec.Patch, versionSpec.PreRelease, versionSpec.BuildMetadata, VersionMatchBehavior.AnyPrerelease | versionSpec.MatchBehavior);
                        versions = versions.Where(v => anyPrereleaseSpecifier.IsCompatible(v.Version)).ToList();
                        if (versions.Any())
                        {
                            log.Info($"There are {versions.Count} pre-released versions available. Use '--version <pre-release>' (e.g. '--version rc') or '--all' to show these.");
                        }

                        return(0);
                    }
                }
                PrintVersionsReadable(package, versions);
            }
            return(0);
        }
Пример #5
0
        public override bool Deserialize(XElement element, ITypeData t, Action <object> setter)
        {
            var dep = element.Element(PackageDependenciesName);

            if (dep == null)
            {
                return(false);
            }

            dep.Remove();
            if (element.IsEmpty)
            {
                element.Value = ""; // little hack to ensure that the element is not created empty. (leading to null values).
            }
            var plugins = new Installation(Path.GetDirectoryName(Assembly.GetAssembly(typeof(PluginManager)).Location)).GetPackages().ToDictionary(x => x.Name);

            List <string> errors = new List <string>();

            foreach (var pkg in dep.Elements(PackageDependencyName))
            {
                var nameattr    = pkg.Attribute(NameName);
                var versionattr = pkg.Attribute(VersionName);
                if (nameattr == null || versionattr == null)
                {
                    continue;
                }

                var name          = nameattr.Value;
                var versionString = versionattr.Value;
                if (!SemanticVersion.TryParse(versionString, out SemanticVersion version))
                {
                    errors.Add($"Version '{versionString}' of dependent package '{name}' could not be parsed.");
                    return(false);
                }

                if (!plugins.ContainsKey(name))
                {
                    string legacyTapBasePackageName = "TAP Base";
                    if (name == legacyTapBasePackageName)
                    {
                        Log.Warning($"The saved data depends on an older, incompatible version of OpenTAP. Migrating from OpenTAP {version} to the installed version. Please verify the test plan settings.");
                        continue;
                    }
                    else
                    {
                        errors.Add($"Package '{name}' is required to load the test plan, but it is not installed.");
                    }

                    if (UsePlatformInteraction)
                    {
                        interactiveInstallPackage(name, version);
                    }
                }
                else if (!(version.IsCompatible(plugins[name].Version)))
                {
                    errors.Add($"Package '{name}' version {version} is required to load the saved data and the installed version ({plugins[name].Version}) is not compatible.");
                }
            }

            foreach (var error in errors)
            {
                Log.Error(error);
                Serializer.PushError(element, error);
            }

            return(false);
        }
Пример #6
0
        internal static PackageDef FindPackage(PackageSpecifier packageReference, bool force, Installation installation, List <IPackageRepository> repositories)
        {
            IPackageIdentifier[] compatibleWith;
            if (!force)
            {
                var tapPackage = installation.GetOpenTapPackage();
                if (tapPackage != null)
                {
                    compatibleWith = new[] { installation.GetOpenTapPackage() }
                }
                ;
                else
                {
                    compatibleWith = new[] { new PackageIdentifier("OpenTAP", PluginManager.GetOpenTapAssembly().SemanticVersion.ToString(), CpuArchitecture.Unspecified, "") }
                };
            }
            else
            {
                compatibleWith = Array.Empty <IPackageIdentifier>();
            }

            var compatiblePackages = PackageRepositoryHelpers.GetPackagesFromAllRepos(repositories, packageReference, compatibleWith);

            // Of the compatible packages, pick the one with the highest version number. If that package is available from several repositories, pick the one with the lowest index in the list in PackageManagerSettings
            PackageDef package = null;

            if (compatiblePackages.Any())
            {
                package = compatiblePackages.GroupBy(p => p.Version).OrderByDescending(g => g.Key).FirstOrDefault()
                          .OrderBy(p => repositories.IndexWhen(e => NormalizeRepoUrl(e.Url) == NormalizeRepoUrl((p.PackageSource as IRepositoryPackageDefSource)?.RepositoryUrl))).FirstOrDefault();
            }

            // If no package was found, try to figure out why
            if (package == null)
            {
                var compatibleVersions = PackageRepositoryHelpers.GetAllVersionsFromAllRepos(repositories, packageReference.Name, compatibleWith);
                var versions           = PackageRepositoryHelpers.GetAllVersionsFromAllRepos(repositories, packageReference.Name);

                // Any packages compatible with opentap and platform
                var filteredVersions = compatibleVersions.Where(v => v.IsPlatformCompatible(packageReference.Architecture, packageReference.OS)).ToList();
                if (filteredVersions.Any())
                {
                    // if the specified version exist, don't say it could not be found.
                    if (versions.Any(v => packageReference.Version.IsCompatible(v.Version)))
                    {
                        throw new ExitCodeException(1, $"Package '{packageReference.Name}' matching version '{packageReference.Version}' is not compatible. Latest compatible version is '{filteredVersions.FirstOrDefault().Version}'.");
                    }
                    else
                    {
                        throw new ExitCodeException(1, $"Package '{packageReference.Name}' matching version '{packageReference.Version}' could not be found. Latest compatible version is '{filteredVersions.FirstOrDefault().Version}'.");
                    }
                }

                // Any compatible with platform but not opentap
                filteredVersions = versions.Where(v => v.IsPlatformCompatible(packageReference.Architecture, packageReference.OS)).ToList();
                if (filteredVersions.Any() && compatibleWith.Any())
                {
                    var opentapPackage = compatibleWith.First();
                    throw new ExitCodeException(1, $"Package '{packageReference.Name}' does not exist in a version compatible with '{opentapPackage.Name}' version '{opentapPackage.Version}'.");
                }

                // Any compatible with opentap but not platform
                if (compatibleVersions.Any())
                {
                    if (packageReference.Version != VersionSpecifier.Any || packageReference.OS != null || packageReference.Architecture != CpuArchitecture.Unspecified)
                    {
                        throw new ExitCodeException(1,
                                                    string.Format("No '{0}' package {1} was found.", packageReference.Name, string.Join(" and ",
                                                                                                                                        new string[] {
                            packageReference.Version != VersionSpecifier.Any ? $"compatible with version '{packageReference.Version}'": null,
                            packageReference.OS != null ? $"compatible with '{packageReference.OS}' operating system" : null,
                            packageReference.Architecture != CpuArchitecture.Unspecified ? $"with '{packageReference.Architecture}' architecture" : null
                        }.Where(x => x != null).ToArray())));
                    }
                    else
                    {
                        throw new ExitCodeException(1, $"Package '{packageReference.Name}' does not exist in a version compatible with this OS and architecture.");
                    }
                }

                // Any version
                if (versions.Any())
                {
                    var opentapPackage = compatibleWith.FirstOrDefault();
                    if (opentapPackage != null)
                    {
                        throw new ExitCodeException(1, $"Package '{packageReference.Name}' does not exist in a version compatible with this OS, architecture and '{opentapPackage.Name}' version '{opentapPackage.Version}'.");
                    }
                    else
                    {
                        throw new ExitCodeException(1, $"Package '{packageReference.Name}' does not exist in a version compatible with this OS and architecture.");
                    }
                }

                throw new ExitCodeException(1, $"Package '{packageReference.Name}' could not be found in any repository.");
            }
            return(package);
        }
Пример #7
0
        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);
        }
Пример #8
0
        internal static void findDependencies(this PackageDef pkg, List <string> excludeAdd, List <AssemblyData> searchedFiles)
        {
            bool foundNew = false;

            var notFound = new HashSet <string>();

            // First update the pre-entered dependencies
            var installed = new Installation(Directory.GetCurrentDirectory()).GetPackages().Where(p => p.Name != pkg.Name).ToList();

            List <string> brokenPackageNames = new List <string>();

            List <AssemblyData> getPackageAssemblues(PackageDef pkgDef)
            {
                List <AssemblyData> output = new List <AssemblyData>();

                foreach (var f in pkgDef.Files)
                {
                    var asms = searchedFiles.Where(sf => PathUtils.AreEqual(f.FileName, sf.Location))
                               .Where(sf => IsDotNetAssembly(sf.Location)).ToList();
                    if (asms.Count == 0 && (Path.GetExtension(f.FileName).Equals(".dll", StringComparison.OrdinalIgnoreCase) || Path.GetExtension(f.FileName).Equals(".exe", StringComparison.OrdinalIgnoreCase)))
                    {
                        if (File.Exists(f.FileName))
                        {
                            // If the pluginSearcher found assemblies that are located somewhere not expected by the package definition, the package might appear broken.
                            // But if the file found by the pluginSearcher is the same as the one expected by the package definition we should not count it as broken.
                            // This could cause a package to not be added as a dependencies.
                            // E.g. when debugging and the OpenTAP.Cli.dll is both in the root build dir and in "Packages/OpenTAP"
                            var asmsIdenticalFilename = searchedFiles.Where(sf => Path.GetFileName(f.FileName) == Path.GetFileName(sf.Location));
                            var asmsIdentical         = asmsIdenticalFilename.Where(sf => PathUtils.CompareFiles(f.FileName, sf.Location));
                            output.AddRange(asmsIdentical);
                            continue;
                        }

                        if (!brokenPackageNames.Contains(pkgDef.Name) && IsDotNetAssembly(f.FileName))
                        {
                            brokenPackageNames.Add(pkgDef.Name);
                            log.Warning($"Package '{pkgDef.Name}' is not installed correctly?  Referenced file '{f.FileName}' was not found.");
                        }
                    }
                    output.AddRange(asms);
                }
                return(output);
            };

            var packageAssemblies = new Memorizer <PackageDef, List <AssemblyData> >(getPackageAssemblues);

            // check versions of any hardcoded dependencies against what is currently installed
            foreach (PackageDependency dep in pkg.Dependencies)
            {
                var installedPackage = installed.FirstOrDefault(ip => ip.Name == dep.Name);
                if (installedPackage != null)
                {
                    if (dep.Version == null)
                    {
                        dep.Version = new VersionSpecifier(installedPackage.Version, VersionMatchBehavior.Compatible);
                        log.Info("A version was not specified for package dependency {0}. Using installed version ({1}).", dep.Name, dep.Version);
                    }
                    else
                    {
                        if (!dep.Version.IsCompatible(installedPackage.Version))
                        {
                            throw new ExitCodeException((int)PackageCreateAction.ExitCodes.PackageDependencyError, $"Installed version of {dep.Name} ({installedPackage.Version}) is incompatible with dependency specified in package definition ({dep.Version}).");
                        }
                    }
                }
                else
                {
                    throw new ExitCodeException((int)PackageCreateAction.ExitCodes.PackageDependencyError,
                                                $"Package dependency '{dep.Name}' specified in package definition is not installed. Please install a compatible version first.");
                }
            }

            // Find additional dependencies
            do
            {
                foundNew = false;

                // Find everything we already know about
                var offeredByDependencies = AssembliesOfferedBy(installed, pkg.Dependencies, false, packageAssemblies).ToList();
                var offeredByThis         = packageAssemblies[pkg]
                                            .Where(f => f != null)
                                            .ToList();

                var anyOffered = offeredByDependencies.Concat(offeredByThis).ToList();

                // Find our dependencies and subtract the above two lists
                var dependentAssemblyNames = pkg.Files
                                             .SelectMany(fs => fs.DependentAssemblies)
                                             .Where(r => r.Name != "mscorlib") // Special case. We should not bundle the framework assemblies.
                                             .Where(r => !anyOffered.Any(of => AssemblyRefUtils.IsCompatibleReference(of, r)))
                                             .Distinct().Where(x => !excludeAdd.Contains(x.Name)).ToList();

                // If there's anything left we start resolving
                if (dependentAssemblyNames.Any())
                {
                    // First look in installed packages
                    var packageCandidates = new Dictionary <PackageDef, int>();
                    foreach (var f in installed)
                    {
                        var candidateAsms = packageAssemblies[f].Where(asm => dependentAssemblyNames.Any(dep => (dep.Name == asm.Name))).ToList();

                        // Don't consider a package that only matches assemblies in the Dependencies subfolder
                        candidateAsms.RemoveAll(asm => asm.Location.Contains("Dependencies")); // TODO: less lazy check for Dependencies subfolder would be good.

                        if (candidateAsms.Count > 0)
                        {
                            packageCandidates[f] = candidateAsms.Count;
                        }
                    }

                    // Look at the most promising candidate (i.e. the one containing most assemblies with the same names as things we need)
                    PackageDef candidatePkg = packageCandidates.OrderByDescending(k => k.Value).FirstOrDefault().Key;

                    if (candidatePkg != null)
                    {
                        foreach (AssemblyData candidateAsm in packageAssemblies[candidatePkg])
                        {
                            var requiredAsm = dependentAssemblyNames.FirstOrDefault(dep => dep.Name == candidateAsm.Name);
                            if (requiredAsm != null)
                            {
                                if (OpenTap.Utils.Compatible(candidateAsm.Version, requiredAsm.Version))
                                {
                                    log.Info($"Satisfying assembly reference to {requiredAsm.Name} by adding dependency on package {candidatePkg.Name}");
                                    if (candidateAsm.Version != requiredAsm.Version)
                                    {
                                        log.Warning($"Version of {requiredAsm.Name} in {candidatePkg.Name} is different from the version referenced in this package ({requiredAsm.Version} vs {candidateAsm.Version}).");
                                        log.Warning($"Consider changing your version of {requiredAsm.Name} to {candidateAsm.Version} to match that in {candidatePkg.Name}.");
                                    }
                                    foundNew = true;
                                }
                                else
                                {
                                    var depender = pkg.Files.FirstOrDefault(f => f.DependentAssemblies.Contains(requiredAsm));
                                    if (depender == null)
                                    {
                                        log.Error($"This package require assembly {requiredAsm.Name} in version {requiredAsm.Version} while that assembly is already installed through package '{candidatePkg.Name}' in version {candidateAsm.Version}.");
                                    }
                                    else
                                    {
                                        log.Error($"{Path.GetFileName(depender.FileName)} in this package require assembly {requiredAsm.Name} in version {requiredAsm.Version} while that assembly is already installed through package '{candidatePkg.Name}' in version {candidateAsm.Version}.");
                                    }
                                    //log.Error($"Please align the version of {requiredAsm.Name} to ensure interoperability with package '{candidate.Key.Name}' or uninstall that package.");
                                    throw new ExitCodeException((int)PackageCreateAction.ExitCodes.AssemblyDependencyError,
                                                                $"Please align the version of {requiredAsm.Name} ({candidateAsm.Version} vs {requiredAsm.Version})  to ensure interoperability with package '{candidatePkg.Name}' or uninstall that package.");
                                }
                            }
                        }
                        if (foundNew)
                        {
                            log.Info("Adding dependency on package '{0}' version {1}", candidatePkg.Name, candidatePkg.Version);

                            PackageDependency pd = new PackageDependency(candidatePkg.Name, new VersionSpecifier(candidatePkg.Version, VersionMatchBehavior.Compatible));
                            pkg.Dependencies.Add(pd);
                        }
                    }
                    else
                    {
                        // No installed package can offer any of the remaining referenced assemblies.
                        // add them as payload in this package in the Dependencies subfolder
                        foreach (var unknown in dependentAssemblyNames)
                        {
                            var foundAsms = searchedFiles.Where(asm => (asm.Name == unknown.Name) && OpenTap.Utils.Compatible(asm.Version, unknown.Version)).ToList();
                            var foundAsm  = foundAsms.FirstOrDefault();

                            if (foundAsm != null)
                            {
                                AddFileDependencies(pkg, unknown, foundAsm);
                                packageAssemblies.Invalidate(pkg);
                                foundNew = true;
                            }
                            else if (!notFound.Contains(unknown.Name))
                            {
                                log.Debug("'{0}' could not be found in any of {1} searched assemblies, or is already added.", unknown.Name, searchedFiles.Count);
                                notFound.Add(unknown.Name);
                            }
                        }
                    }
                }
            }while (foundNew);
        }
Пример #9
0
        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();
        }
Пример #10
0
        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);
                }
            }
        }
Пример #11
0
 public static Issue CheckDependencies(Installation installation, IEnumerable <string> newPackages, LogEventType severity = LogEventType.Error)
 {
     return(checkPackages(installation.GetPackages(), newPackages.Select(Path.GetFullPath).ToArray(), severity));
 }
Пример #12
0
        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);
        }
Пример #13
0
        internal static void RunIsolated(string application = null, string target = null, IsolatedPackageAction isolatedAction = null)
        {
            using (var tpmClient = new ExecutorClient())
            {
                var packages = new Installation(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location)).GetPackages();
                PackageDef findPackageWithFile(string file)
                {
                    foreach (var package in packages)
                    {
                        foreach (var pkgfile in package.Files)
                        {
                            var filePath = Path.Combine(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location), pkgfile.FileName);

                            if (string.Equals(NormalizePath(filePath), NormalizePath(file), StringComparison.OrdinalIgnoreCase))
                            {
                                return(package);
                            }
                        }
                    }
                    return(null);
                }

                var        exec = application ?? Assembly.GetEntryAssembly().Location;
                PackageDef pkg  = findPackageWithFile(Path.GetFullPath(exec));
                if (pkg == null)
                {
                    throw new InvalidOperationException($"{Path.GetFileName(exec)} was not installed through a package.");
                }
                var dependencies = pkg.Dependencies.ToList();

                if (isolatedAction != null)
                {
                    // If the executing IsolatedPackageAction does not origin from OpenTAP package, we need to include it when we copy and run isolated
                    var        actionAsm             = isolatedAction.GetType().Assembly.Location;
                    PackageDef isolatedActionPackage = findPackageWithFile(Path.GetFullPath(actionAsm));
                    if (isolatedActionPackage == null)
                    {
                        throw new InvalidOperationException($"{Path.GetFileName(actionAsm)} was not installed through a package.");
                    }
                    if (pkg.Name != isolatedActionPackage.Name)
                    {
                        if (!dependencies.Any(p => p.Name == isolatedActionPackage.Name))
                        {
                            dependencies.Add(new PackageDependency(isolatedActionPackage.Name, new VersionSpecifier(isolatedActionPackage.Version, VersionMatchBehavior.Compatible)));
                        }
                    }
                }

                // when installing/uninstalling packages we might need to use custom package actions as well.
                var extraDependencies = PluginManager.GetPlugins <ICustomPackageAction>().Select(t => t.Assembly.Location).Distinct().ToList();
                foreach (var exDep in extraDependencies)
                {
                    var package = findPackageWithFile(exDep);
                    if (package != null && !dependencies.Any(p => p.Name == package.Name))
                    {
                        dependencies.Add(new PackageDependency(package.Name, new VersionSpecifier(package.Version, VersionMatchBehavior.Compatible)));
                    }
                }

                var deps = OpenTap.Utils.FlattenHeirarchy(dependencies, dep => (IEnumerable <PackageDependency>)packages.FirstOrDefault(x => x.Name == dep.Name)?.Dependencies ?? Array.Empty <PackageDependency>(), distinct: true);

                if (false == deps.Any(x => x.Name == pkg.Name))
                {
                    deps.Add(new PackageDependency(pkg.Name, new VersionSpecifier(pkg.Version, VersionMatchBehavior.Compatible)));
                }

                bool force = isolatedAction?.Force ?? false;

                List <string> allFiles = new List <string>();
                foreach (var d in deps)
                {
                    var availPackages = packages.Where(p => p.Name == d.Name);
                    var package       = availPackages.FirstOrDefault(p => d.Version.IsCompatible(p.Version));
                    if (package == null)
                    {
                        package = availPackages.FirstOrDefault();
                        if (!force)
                        {
                            if (package != null)
                            {
                                throw new Exception($"Cannot find compatible dependency '{d.Name}' {d.Version}. Version {package.Version} is installed.");
                            }
                            throw new Exception($"Cannot find needed dependency '{d.Name}'.");
                        }

                        log.Warning("Unable to find compatible package, using {0} v{1} instead.", package.Name, package.Version);
                    }

                    var defPath = String.Join("/", PackageDef.PackageDefDirectory, package.Name, PackageDef.PackageDefFileName);
                    if (File.Exists(defPath))
                    {
                        allFiles.Add(defPath);
                    }

                    var fs             = package.Files;
                    var brokenPackages = new HashSet <string>();
                    foreach (var file in fs)
                    {
                        string loc = Path.Combine(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location), file.FileName);
                        if (!File.Exists(loc))
                        {
                            brokenPackages.Add(package.Name);
                            log.Debug($"Could not find file '{loc}' part of package '{package.Name}'.");
                            continue;
                        }

                        allFiles.Add(file.FileName);
                    }

                    foreach (var name in brokenPackages)
                    {
                        log.Warning($"Package '{name}' has missing files and is broken.");
                    }
                }

                string tempFolder = Path.GetFullPath(FileSystemHelper.CreateTempDirectory());

                foreach (var _loc in allFiles.Distinct())
                {
                    string loc = Path.Combine(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location), _loc);

                    var newloc = Path.Combine(tempFolder, _loc);
                    OpenTap.FileSystemHelper.EnsureDirectory(newloc);
                    if (File.Exists(newloc))
                    {
                        continue;
                    }
                    File.Copy(loc, newloc);
                }

                { // tell TPM Server to start new app.
                    var loc = application ?? Assembly.GetEntryAssembly().Location;
                    if (string.Equals(".dll", Path.GetExtension(loc), StringComparison.OrdinalIgnoreCase))
                    {  //.netcore wierdness.
                        loc = Path.ChangeExtension(loc, "exe");
                        if (File.Exists(loc) == false)
                        {
                            loc = loc.Substring(0, loc.Length - ".exe".Length);
                        }
                    }

                    var newname = Path.Combine(tempFolder, Path.GetFileName(loc));

                    newname = $"\"{newname}\"";  // there could be whitespace in the name.

                    // now that we start from a different dir, we need to supply a --target argument
                    if (target != null)
                    {
                        newname = $"{newname} --target \"{target}\"";
                    }

                    tpmClient.MessageServer("run " + newname);
                    tpmClient.Dispose();
                }
            }
        }
Пример #14
0
        private void GetPackageInfo(PackageDef package, List <PackageVersion> packageVersions,
                                    Installation installation)
        {
            var allPackages      = installation.GetPackages();
            var latestVersion    = packageVersions?.Max(p => p.Version);
            var packageInstalled = allPackages.Contains(package);

            if (!packageInstalled)
            {
                allPackages.Add(package);
            }

            var tree   = DependencyAnalyzer.BuildAnalyzerContext(allPackages);
            var issues = tree.GetIssues(package);

            ParseDescription(package.Description);

            // Get similar releases to get available platforms and architectures
            var similarReleases = packageVersions.Where(x =>
                                                        x.Version.Major == package.Version.Major && x.Version.Minor == package.Version.Minor).ToList();

            AddWritePair("Package Name", package.Name);

            AddWritePair("Group", package.Group);

            var installedVersion = installation.GetPackages().Where(x => x.Name == package.Name)?.FirstOrDefault()?.Version;
            var installedString  = installedVersion == null ? "(not installed)" : $"({installedVersion} installed)";

            AddWritePair("Version", $"{package.Version} {installedString}");

            if (latestVersion != null && installedVersion != null && latestVersion != installedVersion)
            {
                AddWritePair("Newest Version in Repository", $"{latestVersion}");
            }

            AddWritePair("Compatible Architectures", string.Join(Environment.NewLine, similarReleases.Select(x => x.Architecture).Distinct()));
            AddWritePair("Compatible Platforms", string.Join(Environment.NewLine, similarReleases.Select(x => x.OS).Distinct()));

            if (packageInstalled == false)
            {
                AddWritePair("Compatibility Issues", issues.Any()
                    ? $"{(string.Join(Environment.NewLine, issues.Select(x => $"{x.PackageName} - {x.IssueType.ToString()}")))}"
                    : "none");
            }

            AddWritePair("Owner", package.Owner);
            var licenseString = (package.LicenseRequired ?? "").Replace("&", " and ").Replace("|", " or ");

            AddWritePair("License Required", licenseString);
            AddWritePair("SourceUrl", package.SourceUrl);
            if (package.PackageSource is IRepositoryPackageDefSource repoPkg)
            {
                AddWritePair("Repository", repoPkg.RepositoryUrl);
            }
            AddWritePair("Package Type", package.FileType);
            AddWritePair("Package Class", package.Class);

            var tags = package.Tags?.Split(new string[] { " ", "," }, StringSplitOptions.RemoveEmptyEntries);

            if (tags?.Length > 0)
            {
                AddWritePair("Package Tags", string.Join(" ", tags));
            }

            if (package.Dependencies.Count > 0)
            {
                AddWritePair("Dependencies", string.Join(Environment.NewLine, package.Dependencies.Select(x => x.Name)));
            }

            foreach (var(key, value) in SubTags)
            {
                AddWritePair(key, value);
            }

            AddWritePair("Description", Description);

            if (IncludeFiles)
            {
                if (package.Files.Count > 0)
                {
                    AddWritePair("Files", string.Join(Environment.NewLine, package.Files.Select(x => x.RelativeDestinationPath.Replace("\\", "/"))));
                }
            }

            if (IncludePlugins)
            {
                var plugins = package.Files.Select(x => x.Plugins);

                var sb = new StringBuilder();
                foreach (var plugin in plugins)
                {
                    foreach (var p in plugin)
                    {
                        var name = p.Name;
                        var desc = p.Description;
                        sb.Append(!string.IsNullOrWhiteSpace(desc) ? $"{name} ({desc}){Environment.NewLine}" : $"{name}{Environment.NewLine}");
                    }
                }
                AddWritePair("Plugins", sb.ToString());
            }

            WritePairs();
        }
Пример #15
0
        private PackageDef GetPackageDef(Installation targetInstallation)
        {
            // Try a number of methods to obtain the PackageDef in order of precedence
            var        packageRef = new PackageSpecifier(Name, VersionSpecifier.Parse(Version ?? ""), Architecture, OS);
            PackageDef package;

            // a relative or absolute file path
            if (File.Exists(Name))
            {
                package = PackageDef.FromPackage(Name);

                if (package != null)
                {
                    Offline = true;
                    return(package);
                }
            }

            // a currently installed package
            package = targetInstallation.GetPackages().FirstOrDefault(p => p.Name == Name && versionSpec.IsCompatible(p.Version));
            if (package != null)
            {
                return(package);
            }

            if (Offline == false)
            {
                try
                {
                    // a release from repositories
                    package = repositories.SelectMany(x => x.GetPackages(packageRef))
                              .FindMax(p => p.Version);
                    if (package != null)
                    {
                        return(package);
                    }
                }
                catch (System.Net.WebException e)
                {
                    // not connected to the internet
                    log.Error(e.Message);
                    log.Warning("Could not connect to repository. Showing results for local install");
                    DisableHttpRepositories();

                    package = repositories.SelectMany(x => x.GetPackages(packageRef))
                              .FindMax(p => p.Version);
                    if (package != null)
                    {
                        return(package);
                    }
                }
            }

            if (!string.IsNullOrWhiteSpace(Version))
            {
                log.Warning($"{Name} version {Version} not found.");
            }

            if (Offline == false && string.IsNullOrWhiteSpace(Version))
            {
                // a prerelease from repositories
                packageRef = new PackageSpecifier(Name, VersionSpecifier.Parse("any"), Architecture, OS);
                package    = repositories.SelectMany(x => x.GetPackages(packageRef))
                             .FindMax(p => p.Version);
            }

            return(package);
        }