private async Task CreateLibraryWatchers()
        {
            Debug.Assert(_libWatchers != null, "Should not create watchers when suppressed");

            IList <PythonLibraryPath> paths;

            try {
                paths = await PythonTypeDatabase.GetDatabaseSearchPathsAsync(_factory);
            } catch (InvalidOperationException) {
                return;
            }

            paths = paths
                    .Where(p => Directory.Exists(p.Path))
                    .OrderBy(p => p.Path.Length)
                    .ToList();

            var watching = new List <string>();
            var watchers = new List <FileSystemWatcher>();

            foreach (var path in paths)
            {
                if (watching.Any(p => PathUtils.IsSubpathOf(p, path.Path)))
                {
                    continue;
                }

                FileSystemWatcher watcher = null;
                try {
                    watcher = new FileSystemWatcher {
                        IncludeSubdirectories = true,
                        Path         = path.Path,
                        NotifyFilter = NotifyFilters.FileName | NotifyFilters.DirectoryName | NotifyFilters.LastWrite
                    };
                    watcher.Created            += OnChanged;
                    watcher.Deleted            += OnChanged;
                    watcher.Changed            += OnChanged;
                    watcher.Renamed            += OnRenamed;
                    watcher.EnableRaisingEvents = true;

                    watching.Add(path.Path);
                    watchers.Add(watcher);
                } catch (IOException) {
                    // Raced with directory deletion. We normally handle the
                    // library being deleted by disposing the watcher, but this
                    // occurs in response to an event from the watcher. Because
                    // we never got to start watching, we will just dispose
                    // immediately.
                    watcher?.Dispose();
                } catch (ArgumentException ex) {
                    watcher?.Dispose();
                    Debug.WriteLine("Error starting FileSystemWatcher:\r\n{0}", ex);
                }
            }

            List <FileSystemWatcher> oldWatchers;

            lock (_libWatchers) {
                oldWatchers = _libWatchers.ToList();
                _libWatchers.Clear();
                _libWatchers.AddRange(watchers);
            }

            foreach (var oldWatcher in oldWatchers)
            {
                oldWatcher.EnableRaisingEvents = false;
                oldWatcher.Dispose();
            }
        }
Exemple #2
0
        /// <summary>
        /// Determines whether the interpreter factory contains the specified
        /// modules.
        /// </summary>
        /// <returns>The names of the modules that were found.</returns>
        public static async Task <HashSet <string> > FindModulesAsync(this IPythonInterpreterFactory factory, params string[] moduleNames)
        {
            var finding      = new HashSet <string>(moduleNames);
            var found        = new HashSet <string>();
            var withPackages = factory.PackageManager;

            if (withPackages != null)
            {
                foreach (var m in finding)
                {
                    if ((await withPackages.GetInstalledPackageAsync(new PackageSpec(m), CancellationToken.None)).IsValid)
                    {
                        found.Add(m);
                    }
                }
                finding.ExceptWith(found);
                if (!finding.Any())
                {
                    // Found all of them, so stop searching
                    return(found);
                }
            }

            var withDb = factory as PythonInterpreterFactoryWithDatabase;

            if (withDb != null && withDb.IsCurrent)
            {
                var db = withDb.GetCurrentDatabase();
                found.UnionWith(finding.Where(m => db.GetModule(m) != null));

                // Always stop searching after this step
                return(found);
            }

            if (withDb != null)
            {
                try {
                    var paths = await PythonTypeDatabase.GetDatabaseSearchPathsAsync(withDb);

                    found.UnionWith(PythonTypeDatabase.GetDatabaseExpectedModules(withDb.Configuration.Version, paths)
                                    .SelectMany()
                                    .Select(g => g.ModuleName)
                                    .Where(m => finding.Contains(m)));
                } catch (InvalidOperationException) {
                }

                finding.ExceptWith(found);
                if (!finding.Any())
                {
                    // Found all of them, so stop searching
                    return(found);
                }
            }

            return(await Task.Run(() => {
                foreach (var mp in ModulePath.GetModulesInLib(factory.Configuration))
                {
                    if (finding.Remove(mp.ModuleName))
                    {
                        found.Add(mp.ModuleName);
                    }

                    if (!finding.Any())
                    {
                        break;
                    }
                }
                return found;
            }));
        }
        private async Task CacheInstalledPackagesAsync(
            bool alreadyHasLock,
            bool alreadyHasConcurrencyLock,
            CancellationToken cancellationToken
            )
        {
            if (!IsReady)
            {
                await UpdateIsReadyAsync(alreadyHasLock, cancellationToken);

                if (!IsReady)
                {
                    return;
                }
            }

            List <PackageSpec> packages = null;

            var workingLock = alreadyHasLock ? null : await _working.LockAsync(cancellationToken);

            try {
                var args = _extraInterpreterArgs.ToList();

                if (!SupportsDashMPip)
                {
                    args.Add("-c");
                    args.Add("\"import pip; pip.main()\"");
                }
                else
                {
                    args.Add("-m");
                    args.Add("pip");
                }
                args.Add("list");
                if (_pipListHasFormatOption)
                {
                    args.Add("--format=json");
                }

                var concurrencyLock = alreadyHasConcurrencyLock ? null : await _concurrencyLock.LockAsync(cancellationToken);

                try {
                    using (var proc = ProcessOutput.Run(
                               _factory.Configuration.InterpreterPath,
                               args,
                               _factory.Configuration.PrefixPath,
                               UnbufferedEnv,
                               false,
                               null
                               )) {
                        try {
                            if ((await proc) == 0)
                            {
                                if (_pipListHasFormatOption)
                                {
                                    try {
                                        var data = JToken.ReadFrom(new JsonTextReader(new StringListReader(proc.StandardOutputLines)));
                                        packages = data
                                                   .Select(j => new PackageSpec(j.Value <string>("name"), j.Value <string>("version")))
                                                   .Where(p => p.IsValid)
                                                   .OrderBy(p => p.Name)
                                                   .ToList();
                                    } catch (JsonException ex) {
                                        Debug.WriteLine("Failed to parse: {0}".FormatInvariant(ex.Message));
                                        foreach (var l in proc.StandardOutputLines)
                                        {
                                            Debug.WriteLine(l);
                                        }
                                    }
                                }
                                else
                                {
                                    packages = proc.StandardOutputLines
                                               .Select(i => PackageSpec.FromPipList(i))
                                               .Where(p => p.IsValid)
                                               .OrderBy(p => p.Name)
                                               .ToList();
                                }
                            }
                            else if (_pipListHasFormatOption)
                            {
                                // Actually, pip probably doesn't have the --format option
                                Debug.WriteLine("{0} does not support --format".FormatInvariant(_factory.Configuration.InterpreterPath));
                                _pipListHasFormatOption = false;
                                await CacheInstalledPackagesAsync(true, true, cancellationToken);

                                return;
                            }
                            else
                            {
                            }
                        } catch (OperationCanceledException) {
                            // Process failed to run
                            Debug.WriteLine("Failed to run pip to collect packages");
                            foreach (var line in proc.StandardOutputLines)
                            {
                                Debug.WriteLine(line);
                            }
                        }
                    }

                    if (packages == null)
                    {
                        // Pip failed, so return a directory listing
                        var paths = await PythonTypeDatabase.GetDatabaseSearchPathsAsync(_factory);

                        packages = await Task.Run(() => paths.Where(p => !p.IsStandardLibrary && Directory.Exists(p.Path))
                                                  .SelectMany(p => PathUtils.EnumerateDirectories(p.Path, recurse: false))
                                                  .Select(path => Path.GetFileName(path))
                                                  .Select(name => PackageNameRegex.Match(name))
                                                  .Where(match => match.Success)
                                                  .Select(match => new PackageSpec(match.Groups["name"].Value))
                                                  .Where(p => p.IsValid)
                                                  .OrderBy(p => p.Name)
                                                  .ToList());
                    }
                } finally {
                    concurrencyLock?.Dispose();
                }

                // Outside of concurrency lock, still in working lock

                _packages.Clear();
                _packages.AddRange(packages);
                _everCached = true;
            } finally {
                workingLock?.Dispose();
            }

            InstalledPackagesChanged?.Invoke(this, EventArgs.Empty);
        }
Exemple #4
0
        private async Task CacheInstalledPackagesAsync(bool alreadyHasLock, CancellationToken cancellationToken)
        {
            if (!IsReady)
            {
                await UpdateIsReadyAsync(alreadyHasLock, cancellationToken);

                if (!IsReady)
                {
                    return;
                }
            }

            List <PackageSpec> packages = null;

            var workingLock = alreadyHasLock ? null : await _working.LockAsync(cancellationToken);

            try {
                string[] args;
                if (!SupportsDashMPip)
                {
                    args = new[] { "-E", "-c", "import pip; pip.main()", "list" };
                }
                else
                {
                    args = new[] { "-E", "-m", "pip", "list" };
                }

                using (await _concurrencyLock.LockAsync(cancellationToken)) {
                    using (var proc = ProcessOutput.Run(
                               _factory.Configuration.InterpreterPath,
                               args,
                               _factory.Configuration.PrefixPath,
                               UnbufferedEnv,
                               false,
                               null
                               )) {
                        try {
                            if (await proc == 0)
                            {
                                packages = proc.StandardOutputLines
                                           .Select(i => PackageSpec.FromPipList(i))
                                           .Where(p => p.IsValid)
                                           .OrderBy(p => p.Name)
                                           .ToList();
                            }
                        } catch (OperationCanceledException) {
                            // Process failed to run
                            Debug.WriteLine("Failed to run pip to collect packages");
                            Debug.WriteLine(string.Join(Environment.NewLine, proc.StandardOutputLines));
                        }
                    }

                    if (packages == null)
                    {
                        // Pip failed, so return a directory listing
                        var paths = await PythonTypeDatabase.GetDatabaseSearchPathsAsync(_factory);

                        packages = await Task.Run(() => paths.Where(p => !p.IsStandardLibrary)
                                                  .SelectMany(p => PathUtils.EnumerateDirectories(p.Path, recurse: false))
                                                  .Select(path => Path.GetFileName(path))
                                                  .Select(name => PackageNameRegex.Match(name))
                                                  .Where(match => match.Success)
                                                  .Select(match => new PackageSpec(match.Groups["name"].Value))
                                                  .Where(p => p.IsValid)
                                                  .OrderBy(p => p.Name)
                                                  .ToList());
                    }
                }

                // Outside of concurrency lock, still in working lock

                _packages.Clear();
                _packages.AddRange(packages);
                _everCached = true;
            } finally {
                workingLock?.Dispose();
            }

            InstalledPackagesChanged?.Invoke(this, EventArgs.Empty);
        }