private static List <PythonInstall> FindEnvironments(bool force_registry, Request request) { List <PythonInstall> result = new List <PythonInstall>(); string requested_location = request.GetOptionValue("PythonLocation"); if (!force_registry && !string.IsNullOrEmpty(requested_location)) { PythonInstall install = FromPath(requested_location, request); if (install != null) { result.Add(install); } } else { HashSet <string> seen_paths = new HashSet <string>(); if (Environment.Is64BitOperatingSystem) { FindEnvironments(result, true, false, seen_paths, request); } FindEnvironments(result, false, false, seen_paths, request); FindEnvironments(result, false, true, seen_paths, request); } return(result); }
private static void FindEnvironments(List <PythonInstall> result, bool win64, bool user, HashSet <string> seen_paths, Request request) { using (RegistryKey basekey = RegistryKey.OpenBaseKey( user ? RegistryHive.CurrentUser : RegistryHive.LocalMachine, win64 ? RegistryView.Registry64 : RegistryView.Registry32)) { RegistryKey pythoncore = basekey.OpenSubKey(@"Software\Python\PythonCore"); if (pythoncore != null) { foreach (string version in pythoncore.GetSubKeyNames()) { RegistryKey installpathkey = pythoncore.OpenSubKey(string.Format(@"{0}\InstallPath", version)); if (installpathkey != null) { string path = installpathkey.GetValue(null).ToString(); if (!seen_paths.Add(path)) { continue; } PythonInstall install = FromPath(path, request); if (install != null) { install.from_registry = true; install.reg_user = user; result.Add(install); request.Debug("Python::FindInstalledEnvironments found {0} in {1}", install.version, install.install_path); } installpathkey.Dispose(); } } pythoncore.Dispose(); } } }
public static PythonInstall FromPath(string installpath, Request request) { try { PythonInstall result = new PythonInstall(); if (Directory.Exists(installpath)) { result.install_path = installpath; result.exe_path = Path.Combine(installpath, "python.exe"); } else { result.install_path = Path.GetDirectoryName(installpath); result.exe_path = installpath; } result.ReadInterpreterInfo(request); string requested_version_str = request.GetOptionValue("PythonVersion"); if (!string.IsNullOrEmpty(requested_version_str)) { VersionIdentifier requested_version = new VersionIdentifier(requested_version_str); if (!requested_version.IsPrefix(result.version)) { return(null); } } return(result); } catch (Exception e) { request.Debug("Python at {0} isn't usable: {1}", installpath, e); } return(null); }
public bool CheckDependencies(PythonInstall install, out DistRequirement failed_dependency, Request request) { failed_dependency = new DistRequirement(); if (requires_dist.Count == 0) { return(true); } List <PythonPackage> installed_packages = new List <PythonPackage>(install.FindInstalledPackages(null, null, request)); foreach (var dep in requires_dist) { if (dep.marker != null && !dep.marker.Eval(install)) { continue; } bool satisfied_dependency = false; foreach (var package in installed_packages) { if (package.SatisfiesDependency(install, dep, request)) { satisfied_dependency = true; break; } } if (!satisfied_dependency) { failed_dependency = dep; return(false); } } return(true); }
private static PythonInstall FromReleaseRes(JObject res, Request request) { string release_name = res["name"].ToString(); PythonInstall result = new PythonInstall(); result.version = new VersionIdentifier(release_name.Substring(7)); var parts = res["resource_uri"].ToString().TrimEnd('/').Split('/'); result.web_resource = parts[parts.Length - 1]; result.source = "Python.org"; return(result); }
public static PythonPackage FromFastReference(string fastreference, Request request) { if (fastreference.StartsWith("distinfo:")) { string[] parts = fastreference.Substring(9).Split(new char[] { '|' }, 2); PythonInstall install = PythonInstall.FromPath(parts[0], request); return(FromDistInfo(parts[1], install, request)); } else if (fastreference.StartsWith("egginfo:")) { string[] parts = fastreference.Substring(8).Split(new char[] { '|' }, 2); PythonInstall install = PythonInstall.FromPath(parts[0], request); return(FromEggInfo(parts[1], install, request)); } else if (fastreference.StartsWith("pypi:")) { string[] parts = fastreference.Substring(5).Split(new char[] { '#' }, 3); string source = parts[0]; string sourceurl = parts[1]; parts = parts[2].Split(new char[] { '/' }); string name = parts[0]; string version = parts[1]; return(PyPI.GetPackage(new Tuple <string, string>(source, sourceurl), name, version, request)); } else if (fastreference.StartsWith("archive:")) { string[] parts = fastreference.Substring(8).Split(new char[] { '/' }, 3); string name = parts[0]; string version = parts[1]; string archive_path = parts[2]; foreach (var package in PackagesFromFile(archive_path, request)) { if (package.name == name && package.version.Compare(version) == 0) { return(package); } } } else if (fastreference.StartsWith("pythonweb:")) { return(PythonWebsite.PackageFromWebResource(fastreference.Substring(10), request)); } else if (fastreference.StartsWith("installedpython:")) { return(PythonInstall.FromPath(fastreference.Substring(16), request)); } return(null); }
private bool CanInstall(PythonInstall install, PackageDownload download, out bool install_specific, Request request) { install_specific = false; if (download.packagetype == "bdist_wheel") { string tag = download.basename; if (tag.EndsWith(".whl")) { tag = tag.Substring(0, tag.Length - 4); } int platform_dash = tag.LastIndexOf('-'); if (platform_dash <= 0) { return(false); } int abi_dash = tag.LastIndexOf('-', platform_dash - 1); if (abi_dash <= 0) { return(false); } int python_dash = tag.LastIndexOf('-', abi_dash - 1); if (python_dash <= 0) { return(false); } tag = tag.Substring(python_dash + 1); install_specific = true; if (install.CompatibleWithTag(tag)) { return(true); } return(false); } else if (download.packagetype == "sdist") { install_specific = false; return(true); } return(true); }
private bool Install(PythonInstall install, PackageDownload download, Request request) { if (download.packagetype != "bdist_wheel") { if (!install.InstallPip(request)) { return(false); } } string tempdir, filename; if (!DoDownload(download, out tempdir, out filename, request)) { return(false); } try { if (download.packagetype == "bdist_wheel") { foreach (var package in PackagesFromFile(filename, request)) { if (package.MatchesName(name) && package.version.raw_version_string == version.raw_version_string) { return(package.Install(install, request)); } } request.Error(ErrorCategory.MetadataError, name, "Downloaded package file doesn't contain the expected package."); return(false); } else { return(install.InstallViaPip(filename, request)); } } finally { File.Delete(filename); Directory.Delete(tempdir); } }
public bool SatisfiesDependency(PythonInstall install, DistRequirement dep, Request request) { if (dep.marker != null && !dep.marker.Eval(install)) { // FIXME: handle this, somehow? return(true); } if (!MatchesName(dep.name)) { return(false); } if (dep.has_version_specifier) { if (!dep.version_specifier.MatchesVersion(version)) { return(false); } } return(true); }
public static PythonPackage FromEggInfo(string path, PythonInstall install, Request request) { var result = new PythonPackage(null); result.status = Constants.PackageStatus.Installed; result.egginfo_path = path; result.install = install; try { result.ReadMetadata(Path.Combine(path, "PKG-INFO")); } catch (Exception e) { request.Debug(string.Format("Unexpected Exception thrown in 'Python::FromEggInfo' -- {1}\\{2}\r\n{3}"), e.GetType().Name, e.Message, e.StackTrace); } if (result.name != null) { return(result); } return(null); }
private static bool InstallDependencies(PythonInstall install, Dictionary <string, PythonPackage> deps, Request request) { while (deps.Count != 0) { var enumerator = deps.GetEnumerator(); enumerator.MoveNext(); PythonPackage package = enumerator.Current.Value; bool unsatisfied_deps = true; while (unsatisfied_deps) { unsatisfied_deps = false; foreach (var dep in package.requires_dist) { if (dep.marker != null && !dep.marker.Eval(install)) { continue; } if (deps.ContainsKey(NormalizeName(dep.name))) { // FIXME: Infinite loop if dep graph has cycles package = deps[NormalizeName(dep.name)]; unsatisfied_deps = true; break; } } } if (!package.Install(install, request)) { return(false); } deps.Remove(NormalizeName(package.name)); } return(true); }
public bool CanInstall(PythonInstall install, bool install_64bit, Request request) { if (is_wheel) { if (this.tags == null) { return(true); } foreach (var tag in this.tags) { if (install.CompatibleWithTag(tag, install_64bit)) { return(true); } } return(false); } else if (source != null) { bool any_install_specific_download = false; foreach (var download in downloads) { bool install_specific; if (CanInstall(install, download, install_64bit, out install_specific, request)) { return(true); } if (install_specific) { any_install_specific_download = true; } } return(!any_install_specific_download); } return(true); }
public void GetInstalledPackages(string name, string requiredVersion, string minimumVersion, string maximumVersion, Request request) { request.Debug("Calling '{0}::GetInstalledPackages({1},{2},{3},{4})'", ProviderName, name, requiredVersion, minimumVersion, maximumVersion); VersionIdentifier required = string.IsNullOrEmpty(requiredVersion) ? null : new VersionIdentifier(requiredVersion); VersionIdentifier minimum = string.IsNullOrEmpty(minimumVersion) ? null : new VersionIdentifier(minimumVersion); VersionIdentifier maximum = string.IsNullOrEmpty(maximumVersion) ? null : new VersionIdentifier(maximumVersion); foreach (var install in PythonInstall.FindEnvironments(request)) { if (string.IsNullOrEmpty(name) || name == "Python") { install.YieldSelf(request); } foreach (var package in install.FindInstalledPackages(name, requiredVersion, request)) { if ((required == null || required.Compare(package.version) == 0) && (minimum == null || minimum.Compare(package.version) <= 0) && (maximum == null || maximum.Compare(package.version) >= 0)) { package.YieldSelf(request); } } } }
public void InstallPackage(string fastPackageReference, Request request) { request.Debug("Calling '{0}::InstallPackage' '{1}'", ProviderName, fastPackageReference); var package = PythonPackage.FromFastReference(fastPackageReference, request); if (package is PythonInstall) { ((PythonInstall)package).Install(request); return; } bool retried = false; retry: List <PythonInstall> usableinstalls = new List <PythonInstall>(); List <PythonInstall> unusableinstalls = new List <PythonInstall>(); foreach (var candidateinstall in PythonInstall.FindEnvironments(request)) { if (package.CanInstall(candidateinstall, request)) { usableinstalls.Add(candidateinstall); } else { unusableinstalls.Add(candidateinstall); } } if (usableinstalls.Count == 1) { package.Install(usableinstalls[0], request); } else if (usableinstalls.Count == 0) { // Need to install a Python if (retried) { request.Error(ErrorCategory.NotImplemented, package.name, "Failed to install a Python interpreter"); return; } List <PythonPackage> candidate_pythons = new List <PythonPackage>( PythonWebsite.Search("Python", null, null, null, true, request)); candidate_pythons.Sort(new PackageVersionComparer()); bool installed = false; for (int i = candidate_pythons.Count - 1; i >= 0; i--) { if (Environment.Is64BitOperatingSystem && ((PythonInstall)candidate_pythons[i]).CanInstall(true, request) && package.CanInstall((PythonInstall)candidate_pythons[i], true, request)) { ((PythonInstall)candidate_pythons[i]).Install(true, request); installed = true; break; } else if (((PythonInstall)candidate_pythons[i]).CanInstall(false, request) && package.CanInstall((PythonInstall)candidate_pythons[i], true, request)) { ((PythonInstall)candidate_pythons[i]).Install(false, request); installed = true; break; } } if (installed) { retried = true; goto retry; } else { request.Error(ErrorCategory.NotImplemented, package.name, "Couldn't find a Python interpreter to install for this"); return; } } else if (usableinstalls.Count > 1) { if (request.GetOptionValue("Force") == "True") { PythonInstall greatest = usableinstalls[0]; foreach (var candidate in usableinstalls) { if (candidate.version.Compare(greatest.version) > 0) { greatest = candidate; } } package.Install(greatest, request); } else { request.Warning("Multiple installed Python interpreters could satisfy this request:"); foreach (var install in usableinstalls) { request.Warning(" Python version '{0}' at '{1}'", install.version, install.exe_path); } request.Warning("Please select a Python to install to, using e.g. -PythonVersion 3.2 or -PythonLocation c:\\python32\\python.exe"); request.Error(ErrorCategory.NotSpecified, package.name, "Not enough information to select a Python interpreter for the install"); } } }
public bool Install(PythonInstall install, Request request) { DistRequirement failed_dependency; request.Debug("Installing {0} {1}", name, version.ToString()); if (incomplete_metadata) { return(PyPI.GetPackage(new Tuple <string, string>(source, sourceurl), name, version.raw_version_string, request).Install(install, request)); } if (!CheckDependencies(install, out failed_dependency, request)) { var deps = SimpleResolveDependencies(install, out failed_dependency, request); if (deps == null) { request.Error(ErrorCategory.NotInstalled, name, string.Format("Dependency '{0}' not found, unable to resolve automatically.", failed_dependency.raw_string)); return(false); } if (!InstallDependencies(install, deps, request)) { return(false); } } if (is_wheel) { if (install.InstallWheel(archive_path, request) != 0) { request.Error(ErrorCategory.NotSpecified, name, "wheel install failed"); return(false); } foreach (var package in install.FindInstalledPackages(name, null, request)) { if (package.version.raw_version_string != version.raw_version_string) { package.Uninstall(request); } } return(true); } else if (source != null) { PackageDownload?fallback_download = null; foreach (var download in downloads) { bool install_specific; if (CanInstall(install, download, out install_specific, request)) { if (install_specific) { return(Install(install, download, request)); } else if (fallback_download == null) { fallback_download = download; } } } if (fallback_download != null) { return(Install(install, fallback_download.Value, request)); } request.Error(ErrorCategory.NotImplemented, name, "installing not implemented for this package type"); return(false); } else { request.Error(ErrorCategory.NotImplemented, name, "installing not implemented for this package type"); return(false); } }
internal bool Eval(PythonInstall install) { return(ValueIsTrue(RealEval(install))); }
private object RealEval(PythonInstall install) { object result = null; int i; switch (type) { case MarkerType.And: result = submarkers[0].RealEval(install); i = 1; while (i < submarkers.Length && ValueIsTrue(result)) { result = submarkers[i++].RealEval(install); } break; case MarkerType.Or: result = submarkers[0].RealEval(install); i = 1; while (i < submarkers.Length && !ValueIsTrue(result)) { result = submarkers[i++].RealEval(install); } break; case MarkerType.StringLiteral: result = str_value; break; case MarkerType.StringVariable: result = install.get_string_marker_variable(marker_variable); break; case MarkerType.VersionVariable: result = install.get_version_marker_variable(marker_variable); break; case MarkerType.ExtraVariable: result = ""; // FIXME: add support for specifying extras? break; case MarkerType.ComparisonList: object a, b; a = submarkers[0].RealEval(install); if (a is bool) { throw new Exception("can't do comparisons with booleans"); } bool res = true, version_comparison; i = 0; while (res && i < comparisons.Length) { b = submarkers[i + 1].RealEval(install); if (b is bool) { throw new Exception("can't do comparisons with booleans"); } var cmp = comparisons[i]; if (cmp == ComparisonType.In || cmp == ComparisonType.NotIn) { version_comparison = false; } else if (cmp == ComparisonType.Equal || cmp == ComparisonType.NotEqual) { version_comparison = (a is VersionIdentifier || b is VersionIdentifier); } else { version_comparison = true; } if (version_comparison) { VersionIdentifier va, vb; va = (a as VersionIdentifier) ?? new VersionIdentifier((string)a); vb = (b as VersionIdentifier) ?? new VersionIdentifier((string)b); switch (cmp) { case ComparisonType.Equal: res = va.Compare(vb) == 0; break; case ComparisonType.NotEqual: res = va.Compare(vb) != 0; break; case ComparisonType.LT: res = va.Compare(vb) < 0; break; case ComparisonType.GT: res = va.Compare(vb) > 0; break; case ComparisonType.LTE: res = va.Compare(vb) <= 0; break; case ComparisonType.GTE: res = va.Compare(vb) >= 0; break; } } else { string sa, sb; sa = (a as string) ?? ((VersionIdentifier)a).raw_version_string; sb = (b as string) ?? ((VersionIdentifier)b).raw_version_string; switch (cmp) { case ComparisonType.Equal: res = sa == sb; break; case ComparisonType.NotEqual: res = sa != sb; break; case ComparisonType.In: res = sb.Contains(sa); break; case ComparisonType.NotIn: res = !sb.Contains(sa); break; } } a = b; i++; } result = res; break; } return(result); }
private Dictionary <string, PythonPackage> SimpleResolveDependencies(PythonInstall install, out DistRequirement failed_dependency, Request request) { Dictionary <string, PythonPackage> result = new Dictionary <string, PythonPackage>(); Queue <DistRequirement> to_resolve = new Queue <DistRequirement>(); var installed_packages = new Dictionary <string, PythonPackage>(); bool need_recheck = true; // True if we're [up|down]grading a package, and therefore may need to recheck deps foreach (var package in install.FindInstalledPackages(null, null, request)) { installed_packages[package.name] = package; } while (need_recheck) { need_recheck = false; to_resolve.Clear(); foreach (var dep in requires_dist) { request.Debug("Adding dependency {0}", dep.raw_string); to_resolve.Enqueue(dep); } result.Clear(); while (to_resolve.Count != 0) { var dep = to_resolve.Dequeue(); PythonPackage package; request.Debug("Examining dependency {0}", dep.raw_string); if (dep.marker != null && !dep.marker.Eval(install)) { request.Debug("Does not apply to current Python environment"); continue; } if (result.TryGetValue(NormalizeName(dep.name), out package)) { if (!package.SatisfiesDependency(install, dep, request)) { failed_dependency = dep; return(null); } request.Debug("Satisfied by package to install {0} {1}", package.name, package.version.ToString()); } else { if (installed_packages.TryGetValue(NormalizeName(dep.name), out package)) { if (package.SatisfiesDependency(install, dep, request)) { request.Debug("Satisfied by installed package {0} {1}", package.name, package.version.ToString()); continue; } else { request.Debug("Not satisfied by installed package {0} {1}", package.name, package.version.ToString()); need_recheck = true; } } // find newest version of package that satisfies dependency package = null; foreach (var candidate_package in PyPI.ExactSearch(dep.name, request)) { request.Debug("Examining {0} {1}", candidate_package.name, candidate_package.version.ToString()); if (candidate_package.SatisfiesDependency(install, dep, request)) { package = candidate_package; break; } } if (package == null) { request.Debug("Cannot satisfy dependency"); failed_dependency = dep; return(null); } request.Debug("Selecting {0} {1}", package.name, package.version.ToString()); // need to do another request to find dependencies if (package.incomplete_metadata) { package = PyPI.GetPackage(new Tuple <string, string>(package.source, package.sourceurl), package.name, package.version.raw_version_string, request); } // add its dependencies to queue foreach (var dep2 in package.requires_dist) { request.Debug("Adding dependency {0}", dep2.raw_string); to_resolve.Enqueue(dep2); } result[NormalizeName(package.name)] = package; } } } failed_dependency = default(DistRequirement); return(result); }