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 = _pipListHasFormatOption ? _commands.ListJson() : _commands.List(); var concurrencyLock = alreadyHasConcurrencyLock ? null : await _concurrencyLock.LockAsync(cancellationToken); try { var envVars = await GetEnvironmentVariables(); using (var proc = ProcessOutput.Run( _factory.Configuration.InterpreterPath, args, _factory.Configuration.GetPrefixPath(), envVars, 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 PythonLibraryPath.GetSearchPathsAsync( _factory.Configuration, new FileSystem(new OSPlatform()), new ProcessServices() ); packages = await Task.Run(() => paths.Where(p => p.Type != PythonLibraryPathType.StdLib && 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); _factory.NotifyImportNamesChanged(); }
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 = new List <string>(); args.Add("list"); args.Add("-p"); args.Add(ProcessOutput.QuoteSingleArgument(_factory.Configuration.PrefixPath)); args.Add("--json"); var concurrencyLock = alreadyHasConcurrencyLock ? null : await _concurrencyLock.LockAsync(cancellationToken); try { using (var proc = ProcessOutput.Run( _condaPath, args, _factory.Configuration.PrefixPath, UnbufferedEnv, false, null )) { try { if ((await proc) == 0) { var json = string.Join(Environment.NewLine, proc.StandardOutputLines); try { var data = JArray.Parse(json); packages = data .Select(j => new PackageSpec(j.Value <string>("name"), j.Value <string>("version"))) .Where(p => p.IsValid) .OrderBy(p => p.Name) .ToList(); } catch (Newtonsoft.Json.JsonException ex) { Debug.WriteLine("Failed to parse: {0}".FormatInvariant(ex.Message)); Debug.WriteLine(json); } } } catch (OperationCanceledException) { // Process failed to run Debug.WriteLine("Failed to run conda to collect installed packages"); foreach (var line in proc.StandardOutputLines) { Debug.WriteLine(line); } } } } finally { concurrencyLock?.Dispose(); } // Outside of concurrency lock, still in working lock _installedPackages.Clear(); if (packages != null) { _installedPackages.AddRange(packages); } _everCached = true; } finally { workingLock?.Dispose(); } InstalledPackagesChanged?.Invoke(this, EventArgs.Empty); _factory.NotifyImportNamesChanged(); }