protected override void CreateFactory() { _factory = new NotFoundInterpreterFactory( Config.Id, Config.Version, Config.Description, Directory.Exists(_dir) ? _dir : null ); }
protected override void CreateFactory() { _factory = new NotFoundInterpreterFactory( Config.Id, Config.Version, string.Format("{0} (unavailable)", Config.Description), Directory.Exists(_dir) ? _dir : null ); }
/// <summary> /// Call to find interpreters in the associated project. Separated from /// the constructor to allow exceptions to be handled without causing /// the project node to be invalid. /// </summary> /// <exception cref="InvalidDataException"> /// One or more interpreters failed to load. The error message should be /// presented to the user, but can otherwise be ignored. /// </exception> public void DiscoverInterpreters() { // <Interpreter Include="InterpreterDirectory"> // <Id>guid</Id> // <BaseInterpreter>guid</BaseInterpreter> // <Version>...</Version> // <InterpreterPath>...</InterpreterPath> // <WindowsInterpreterPath>...</WindowsInterpreterPath> // <LibraryPath>...</LibraryPath> // <PathEnvironmentVariable>...</PathEnvironmentVariable> // <Description>...</Description> // </Interpreter> var errors = new StringBuilder(); errors.AppendLine("Some project interpreters failed to load:"); bool anyChange = false, anyError = false; var projectHome = PathUtils.GetAbsoluteDirectoryPath(_project.DirectoryPath, _project.GetPropertyValue("ProjectHome")); var factories = new Dictionary<IPythonInterpreterFactory, FactoryInfo>(); foreach (var item in _project.GetItems(InterpreterItem)) { IPythonInterpreterFactory fact; Guid id, baseId; // Errors in these options are fatal, so we set anyError and // continue with the next entry. var dir = item.EvaluatedInclude; if (!PathUtils.IsValidPath(dir)) { errors.AppendLine(string.Format("Interpreter has invalid path: {0}", dir ?? "(null)")); anyError = true; continue; } dir = PathUtils.GetAbsoluteDirectoryPath(projectHome, dir); var value = item.GetMetadataValue(IdKey); if (string.IsNullOrEmpty(value) || !Guid.TryParse(value, out id)) { errors.AppendLine(string.Format("Interpreter {0} has invalid value for '{1}': {2}", dir, IdKey, value)); anyError = true; continue; } if (factories.Keys.Any(f => f.Id == id)) { errors.AppendLine(string.Format("Interpreter {0} has a non-unique id: {1}", dir, id)); continue; } var verStr = item.GetMetadataValue(VersionKey); Version ver; if (string.IsNullOrEmpty(verStr) || !Version.TryParse(verStr, out ver)) { errors.AppendLine(string.Format("Interpreter {0} has invalid value for '{1}': {2}", dir, VersionKey, verStr)); anyError = true; continue; } // The rest of the options are non-fatal. We create an instance // of NotFoundError with an amended description, which will // allow the user to remove the entry from the project file // later. bool hasError = false; var description = item.GetMetadataValue(DescriptionKey); if (string.IsNullOrEmpty(description)) { description = PathUtils.CreateFriendlyDirectoryPath(projectHome, dir); } value = item.GetMetadataValue(BaseInterpreterKey); PythonInterpreterFactoryWithDatabase baseInterp = null; if (!string.IsNullOrEmpty(value) && Guid.TryParse(value, out baseId)) { // It's a valid GUID, so find a suitable base. If we // don't find one now, we'll try and figure it out from // the pyvenv.cfg/orig-prefix.txt files later. // Using an empty GUID will always go straight to the // later lookup. if (baseId != Guid.Empty) { baseInterp = _service.FindInterpreter(baseId, ver) as PythonInterpreterFactoryWithDatabase; } } var path = item.GetMetadataValue(InterpreterPathKey); if (!PathUtils.IsValidPath(path)) { errors.AppendLine(string.Format("Interpreter {0} has invalid value for '{1}': {2}", dir, InterpreterPathKey, path)); hasError = true; } else if (!hasError) { path = PathUtils.GetAbsoluteFilePath(dir, path); } var winPath = item.GetMetadataValue(WindowsPathKey); if (!PathUtils.IsValidPath(winPath)) { errors.AppendLine(string.Format("Interpreter {0} has invalid value for '{1}': {2}", dir, WindowsPathKey, winPath)); hasError = true; } else if (!hasError) { winPath = PathUtils.GetAbsoluteFilePath(dir, winPath); } var libPath = item.GetMetadataValue(LibraryPathKey); if (string.IsNullOrEmpty(libPath)) { libPath = "lib"; } if (!PathUtils.IsValidPath(libPath)) { errors.AppendLine(string.Format("Interpreter {0} has invalid value for '{1}': {2}", dir, LibraryPathKey, libPath)); hasError = true; } else if (!hasError) { libPath = PathUtils.GetAbsoluteDirectoryPath(dir, libPath); } var pathVar = item.GetMetadataValue(PathEnvVarKey); if (string.IsNullOrEmpty(pathVar)) { if (baseInterp != null) { pathVar = baseInterp.Configuration.PathEnvironmentVariable; } else { pathVar = "PYTHONPATH"; } } string arch = null; if (baseInterp == null) { arch = item.GetMetadataValue(ArchitectureKey); if (string.IsNullOrEmpty(arch)) { arch = "x86"; } } if (baseInterp == null && !hasError) { // Only thing missing is the base interpreter, so let's try // to find it using paths baseInterp = DerivedInterpreterFactory.FindBaseInterpreterFromVirtualEnv(dir, libPath, _service) as PythonInterpreterFactoryWithDatabase; if (baseInterp == null) { errors.AppendLine(string.Format("Interpreter {0} has invalid value for '{1}': {2}", dir, BaseInterpreterKey, value ?? "(null)")); hasError = true; } } if (hasError) { fact = new NotFoundInterpreterFactory( id, ver, string.Format("{0} (unavailable)", description), Directory.Exists(dir) ? dir : null ); } else if (baseInterp != null) { MigrateOldDerivedInterpreterFactoryDatabase(id, baseInterp.Configuration.Version, dir); fact = new DerivedInterpreterFactory( baseInterp, new InterpreterFactoryCreationOptions { LanguageVersion = baseInterp.Configuration.Version, Id = id, Description = description, InterpreterPath = path, WindowInterpreterPath = winPath, LibraryPath = libPath, PrefixPath = dir, PathEnvironmentVariableName = pathVar, Architecture = baseInterp.Configuration.Architecture, WatchLibraryForNewModules = true } ); } else { fact = InterpreterFactoryCreator.CreateInterpreterFactory(new InterpreterFactoryCreationOptions { LanguageVersion = ver, Id = id, Description = description, InterpreterPath = path, WindowInterpreterPath = winPath, LibraryPath = libPath, PrefixPath = dir, PathEnvironmentVariableName = pathVar, ArchitectureString = arch, WatchLibraryForNewModules = true }); } var existing = FindInterpreter(id, ver); if (existing != null && existing.IsEqual(fact)) { factories[existing] = new FactoryInfo(item, factories[existing].Owned); var disposable = fact as IDisposable; if (disposable != null) { disposable.Dispose(); } } else { _rootPaths[id] = dir; factories[fact] = new FactoryInfo(item, true); anyChange = true; } } // <InterpreterReference Include="{guid};{version}" /> foreach (var item in _project.GetItems(InterpreterReferenceItem)) { var match = InterpreterReferencePath.Match(item.EvaluatedInclude); if (match == null || !match.Success || !match.Groups.Cast<Group>().All(g => g.Success)) { errors.AppendLine(string.Format("Interpreter reference has invalid path: {0}", item.EvaluatedInclude)); anyError = true; continue; } Guid id; var value = match.Groups["id"]; if (string.IsNullOrEmpty(value.Value) || !Guid.TryParse(value.Value, out id)) { errors.AppendLine(string.Format("Interpreter reference has invalid id: {0}", value.Value ?? "(null)")); anyError = true; continue; } Version ver; value = match.Groups["version"]; if (string.IsNullOrEmpty(value.Value) || !Version.TryParse(value.Value, out ver)) { errors.AppendLine(string.Format("Interpreter reference has invalid version: {0}", value.Value ?? "(null)")); anyError = true; continue; } bool owned = false; var fact = _service.FindInterpreter(id, ver); if (fact == null) { owned = true; fact = new NotFoundInterpreterFactory(id, ver); } var existing = FindInterpreter(id, ver); if (existing != null) { factories[existing] = new FactoryInfo(item, factories[existing].Owned); if (owned) { ((PythonInterpreterFactoryWithDatabase)fact).Dispose(); } } else { factories[fact] = new FactoryInfo(item, owned); anyChange = true; } } if (anyChange || _factories == null || factories.Count != _factories.Count) { // Lock here mainly to ensure that any searches complete before // we trigger the changed event. lock (_factoriesLock) { _factories = factories; } OnInterpreterFactoriesChanged(); UpdateActiveInterpreter(); } if (anyError) { throw new InvalidDataException(errors.ToString()); } }
private bool SetNotFoundInterpreterFactory(string interpreterId, Version ver) { var factory = Factory as NotFoundInterpreterFactory; if (factory != null && string.Compare(factory.Configuration.Id, interpreterId) == 0 && factory.Configuration.Version == ver) { // No updates. return false; } else { Factory = new NotFoundInterpreterFactory(interpreterId, ver, InterpreterFactoryProviderId); return true; } }
/// <summary> /// Call to find interpreters in the associated project. Separated from /// the constructor to allow exceptions to be handled without causing /// the project node to be invalid. /// </summary> /// <exception cref="InvalidDataException"> /// One or more interpreters failed to load. The error message should be /// presented to the user, but can otherwise be ignored. /// </exception> public void DiscoverInterpreters() { // <Interpreter Include="InterpreterDirectory"> // <Id>guid</Id> // <BaseInterpreter>guid</BaseInterpreter> // <Version>...</Version> // <InterpreterPath>...</InterpreterPath> // <WindowsInterpreterPath>...</WindowsInterpreterPath> // <LibraryPath>...</LibraryPath> // <PathEnvironmentVariable>...</PathEnvironmentVariable> // <Description>...</Description> // </Interpreter> var errors = new StringBuilder(); errors.AppendLine("Some project interpreters failed to load:"); bool anyChange = false, anyError = false; var projectHome = CommonUtils.GetAbsoluteDirectoryPath(_project.DirectoryPath, _project.GetPropertyValue("ProjectHome")); var factories = new Dictionary <IPythonInterpreterFactory, FactoryInfo>(); foreach (var item in _project.GetItems(InterpreterItem)) { IPythonInterpreterFactory fact; Guid id, baseId; // Errors in these options are fatal, so we set anyError and // continue with the next entry. var dir = item.EvaluatedInclude; if (!CommonUtils.IsValidPath(dir)) { errors.AppendLine(string.Format("Interpreter has invalid path: {0}", dir ?? "(null)")); anyError = true; continue; } dir = CommonUtils.GetAbsoluteDirectoryPath(projectHome, dir); var value = item.GetMetadataValue(IdKey); if (string.IsNullOrEmpty(value) || !Guid.TryParse(value, out id)) { errors.AppendLine(string.Format("Interpreter {0} has invalid value for '{1}': {2}", dir, IdKey, value)); anyError = true; continue; } if (factories.Keys.Any(f => f.Id == id)) { errors.AppendLine(string.Format("Interpreter {0} has a non-unique id: {1}", dir, id)); continue; } var verStr = item.GetMetadataValue(VersionKey); Version ver; if (string.IsNullOrEmpty(verStr) || !Version.TryParse(verStr, out ver)) { errors.AppendLine(string.Format("Interpreter {0} has invalid value for '{1}': {2}", dir, VersionKey, verStr)); anyError = true; continue; } // The rest of the options are non-fatal. We create an instance // of NotFoundError with an amended description, which will // allow the user to remove the entry from the project file // later. bool hasError = false; var description = item.GetMetadataValue(DescriptionKey); if (string.IsNullOrEmpty(description)) { description = CommonUtils.CreateFriendlyDirectoryPath(projectHome, dir); } value = item.GetMetadataValue(BaseInterpreterKey); PythonInterpreterFactoryWithDatabase baseInterp = null; if (!string.IsNullOrEmpty(value) && Guid.TryParse(value, out baseId)) { // It's a valid GUID, so find a suitable base. If we // don't find one now, we'll try and figure it out from // the pyvenv.cfg/orig-prefix.txt files later. // Using an empty GUID will always go straight to the // later lookup. if (baseId != Guid.Empty) { baseInterp = _service.FindInterpreter(baseId, ver) as PythonInterpreterFactoryWithDatabase; } } var path = item.GetMetadataValue(InterpreterPathKey); if (!CommonUtils.IsValidPath(path)) { errors.AppendLine(string.Format("Interpreter {0} has invalid value for '{1}': {2}", dir, InterpreterPathKey, path)); hasError = true; } else if (!hasError) { path = CommonUtils.GetAbsoluteFilePath(dir, path); } var winPath = item.GetMetadataValue(WindowsPathKey); if (!CommonUtils.IsValidPath(winPath)) { errors.AppendLine(string.Format("Interpreter {0} has invalid value for '{1}': {2}", dir, WindowsPathKey, winPath)); hasError = true; } else if (!hasError) { winPath = CommonUtils.GetAbsoluteFilePath(dir, winPath); } var libPath = item.GetMetadataValue(LibraryPathKey); if (string.IsNullOrEmpty(libPath)) { libPath = "lib"; } if (!CommonUtils.IsValidPath(libPath)) { errors.AppendLine(string.Format("Interpreter {0} has invalid value for '{1}': {2}", dir, LibraryPathKey, libPath)); hasError = true; } else if (!hasError) { libPath = CommonUtils.GetAbsoluteDirectoryPath(dir, libPath); } var pathVar = item.GetMetadataValue(PathEnvVarKey); if (string.IsNullOrEmpty(pathVar)) { if (baseInterp != null) { pathVar = baseInterp.Configuration.PathEnvironmentVariable; } else { pathVar = "PYTHONPATH"; } } string arch = null; if (baseInterp == null) { arch = item.GetMetadataValue(ArchitectureKey); if (string.IsNullOrEmpty(arch)) { arch = "x86"; } } if (baseInterp == null && !hasError) { // Only thing missing is the base interpreter, so let's try // to find it using paths baseInterp = DerivedInterpreterFactory.FindBaseInterpreterFromVirtualEnv(dir, libPath, _service) as PythonInterpreterFactoryWithDatabase; if (baseInterp == null) { errors.AppendLine(string.Format("Interpreter {0} has invalid value for '{1}': {2}", dir, BaseInterpreterKey, value ?? "(null)")); hasError = true; } } if (hasError) { fact = new NotFoundInterpreterFactory( id, ver, string.Format("{0} (unavailable)", description), Directory.Exists(dir) ? dir : null ); } else if (baseInterp != null) { MigrateOldDerivedInterpreterFactoryDatabase(id, baseInterp.Configuration.Version, dir); fact = new DerivedInterpreterFactory( baseInterp, new InterpreterFactoryCreationOptions { LanguageVersion = baseInterp.Configuration.Version, Id = id, Description = description, InterpreterPath = path, WindowInterpreterPath = winPath, LibraryPath = libPath, PrefixPath = dir, PathEnvironmentVariableName = pathVar, Architecture = baseInterp.Configuration.Architecture, WatchLibraryForNewModules = true } ); } else { fact = InterpreterFactoryCreator.CreateInterpreterFactory(new InterpreterFactoryCreationOptions { LanguageVersion = ver, Id = id, Description = description, InterpreterPath = path, WindowInterpreterPath = winPath, LibraryPath = libPath, PrefixPath = dir, PathEnvironmentVariableName = pathVar, ArchitectureString = arch, WatchLibraryForNewModules = true }); } var existing = FindInterpreter(id, ver); if (existing != null && existing.IsEqual(fact)) { factories[existing] = new FactoryInfo(item, factories[existing].Owned); var disposable = fact as IDisposable; if (disposable != null) { disposable.Dispose(); } } else { _rootPaths[id] = dir; factories[fact] = new FactoryInfo(item, true); anyChange = true; } } // <InterpreterReference Include="{guid};{version}" /> foreach (var item in _project.GetItems(InterpreterReferenceItem)) { var match = InterpreterReferencePath.Match(item.EvaluatedInclude); if (match == null || !match.Success || !match.Groups.Cast <Group>().All(g => g.Success)) { errors.AppendLine(string.Format("Interpreter reference has invalid path: {0}", item.EvaluatedInclude)); anyError = true; continue; } Guid id; var value = match.Groups["id"]; if (string.IsNullOrEmpty(value.Value) || !Guid.TryParse(value.Value, out id)) { errors.AppendLine(string.Format("Interpreter reference has invalid id: {0}", value.Value ?? "(null)")); anyError = true; continue; } Version ver; value = match.Groups["version"]; if (string.IsNullOrEmpty(value.Value) || !Version.TryParse(value.Value, out ver)) { errors.AppendLine(string.Format("Interpreter reference has invalid version: {0}", value.Value ?? "(null)")); anyError = true; continue; } bool owned = false; var fact = _service.FindInterpreter(id, ver); if (fact == null) { owned = true; fact = new NotFoundInterpreterFactory(id, ver); } var existing = FindInterpreter(id, ver); if (existing != null) { factories[existing] = new FactoryInfo(item, factories[existing].Owned); if (owned) { ((PythonInterpreterFactoryWithDatabase)fact).Dispose(); } } else { factories[fact] = new FactoryInfo(item, owned); anyChange = true; } } if (anyChange || _factories == null || factories.Count != _factories.Count) { // Lock here mainly to ensure that any searches complete before // we trigger the changed event. lock (_factoriesLock) { _factories = factories; } OnInterpreterFactoriesChanged(); UpdateActiveInterpreter(); } if (anyError) { throw new InvalidDataException(errors.ToString()); } }