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); }
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); }