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());
            }
        }
Exemple #4
0
 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;
     }
 }
Exemple #5
0
        /// <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());
            }
        }
Exemple #6
0
 protected override void CreateFactory()
 {
     _factory = new NotFoundInterpreterFactory(
         Config.Id,
         Config.Version,
         Config.Description,
         Directory.Exists(_dir) ? _dir : null
     );
 }