| // Copyright (c) 2014, Google Inc. Please see the AUTHORS file for details. |
| // All rights reserved. Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| /// A programmatic API for reflecting on Pub's cache directory. |
| library pub_cache; |
| |
| import 'dart:io'; |
| |
| import 'package:path/path.dart' as path; |
| import 'package:pub_semver/pub_semver.dart'; |
| import 'package:yaml/yaml.dart' as yaml; |
| |
| import 'src/impl.dart'; |
| |
| /// A programmatic API for reflecting on Pub's cache directory. |
| class PubCache { |
| /// Return the location of Pub's package cache. |
| static Directory getSystemCacheLocation() { |
| Map env = Platform.environment; |
| |
| if (env.containsKey('PUB_CACHE')) { |
| return new Directory(env['PUB_CACHE']); |
| } else if (Platform.operatingSystem == 'windows') { |
| return new Directory(path.join(env['APPDATA'], 'Pub', 'Cache')); |
| } else { |
| return new Directory('${env['HOME']}/.pub-cache'); |
| } |
| } |
| |
| // The location of the pub cache. |
| final Directory location; |
| |
| late List<Application> _applications; |
| late List<PackageRef> _packageRefs; |
| |
| /// Create a pubcache instance. [dir] defaults to the default platform pub |
| /// cache location. |
| PubCache([Directory? dir]) |
| : location = dir == null ? getSystemCacheLocation() : dir { |
| _parse(); |
| } |
| |
| /// Return the contents of `bin/` - the scripts for the activated applications. |
| List<File> getBinScripts() { |
| Directory dir = _getSubDir(location, 'bin'); |
| return dir.existsSync() |
| ? dir.listSync().where((entity) => entity is File).cast<File>().toList() |
| : <File>[]; |
| } |
| |
| /// Return applications that have been installed via `pub global activate`. |
| List<Application> getGlobalApplications() => _applications; |
| |
| /// Get all the packages and their versions that have been installed into the |
| /// cache. |
| List<PackageRef> getPackageRefs() => _packageRefs; |
| |
| /// Return the list of package names (not versions) that are available in the |
| /// cache. |
| List<String> getCachedPackages() => |
| new Set<String>.from(getPackageRefs().map((p) => p.name)).toList(); |
| |
| /// Return all available cached versions for a given package. |
| List<PackageRef> getAllPackageVersions(String packageName) => |
| getPackageRefs().where((p) => p.name == packageName).toList(); |
| |
| /// Return the most recent verison of the given package contained in the |
| /// cache. This method will prefer to return only release verions. If |
| /// [includePreRelease] is true, then the very latest verision will be |
| /// returned, include pre-release versions. |
| PackageRef? getLatestVersion(String packageName, |
| {bool includePreRelease: false}) { |
| List<PackageRef> refs = getAllPackageVersions(packageName); |
| |
| if (refs.isEmpty) return null; |
| if (refs.length == 1) return refs.first; |
| |
| PackageRef latest = refs.first; |
| |
| if (includePreRelease) { |
| for (int i = 1; i < refs.length; i++) { |
| if (refs[i].version > latest.version) latest = refs[i]; |
| } |
| } else { |
| List<Version> versions = refs.map((ref) => ref.version).toList(); |
| Version latestVersion = Version.primary(versions); |
| for (PackageRef ref in refs) { |
| if (ref.version == latestVersion) latest = ref; |
| } |
| } |
| |
| return latest; |
| } |
| |
| void _parse() { |
| // Read the activated applications. |
| _applications = []; |
| |
| Directory globalPackagesDir = _getSubDir(location, 'global_packages'); |
| if (globalPackagesDir.existsSync()) { |
| _applications = globalPackagesDir |
| .listSync() |
| .where((item) => item is Directory) |
| .map((dir) => new Application._(this, dir as Directory)) |
| .toList(); |
| } |
| |
| // Scan hosted packages |
| _packageRefs = <PackageRef>[]; |
| |
| Directory dartlangDir = new Directory( |
| path.join(location.path, 'hosted', _getHostedPackageDirectoryName())); |
| if (dartlangDir.existsSync()) { |
| _packageRefs.addAll(dartlangDir |
| .listSync() |
| .where((dir) => dir is Directory) |
| .map((dir) => new DirectoryPackageRef('hosted', dir as Directory))); |
| } |
| |
| // Scan for git packages (ignore the git/cache directory). |
| // ace-a1a140cc933e7d44d2955a6d6033308754bb9235 |
| Directory gitDir = new Directory(path.join(location.path, 'git')); |
| if (gitDir.existsSync()) { |
| Iterable<PackageRef> gitRefs = gitDir |
| .listSync() |
| .where( |
| (dir) => dir is Directory && path.basename(dir.path) != 'cache') |
| .map((dir) => new GitDirectoryPackageRef(dir as Directory)); |
| _packageRefs.addAll(gitRefs); |
| } |
| } |
| |
| Directory _getSubDir(Directory dir, String name) => |
| new Directory(path.join(dir.path, name)); |
| |
| String _getHostedPackageDirectoryName() { |
| final url = Uri.parse( |
| Platform.environment['PUB_HOSTED_URL'] ?? 'https://pub.dartlang.org'); |
| return url.host; |
| } |
| } |
| |
| /// A Dart application; a package with an entry-point, available via `pub global |
| /// activate`. |
| class Application { |
| final PubCache _cache; |
| final Directory _dir; |
| |
| List<PackageRef>? _packageRefs; |
| |
| Application._(this._cache, this._dir); |
| |
| /// The name of the defining package. |
| String get name => path.basename(_dir.path); |
| |
| /// The version of the application and of the defining package. |
| Version get version { |
| final ref = getDefiningPackageRef(); |
| return ref == null ? Version.none : ref.version; |
| } |
| |
| /// Return the reference to the defining package. This is the package that |
| /// defines the application. |
| PackageRef? getDefiningPackageRef() { |
| for (PackageRef ref in getPackageRefs()) { |
| if (ref.name == name) return ref; |
| } |
| return null; |
| } |
| |
| /// Return all the package references for the application. This includes the |
| /// defining package as well as the direct and transitive dependencies. |
| List<PackageRef> getPackageRefs() { |
| if (_packageRefs == null) _parsePubspecLock(); |
| return _packageRefs!; |
| } |
| |
| String toString() => '${name} ${version}'; |
| |
| void _parsePubspecLock() { |
| File pubspecLock = new File(path.join(_dir.path, 'pubspec.lock')); |
| Map doc = yaml.loadYaml(pubspecLock.readAsStringSync()); |
| Map packages = doc['packages']; |
| _packageRefs = packages.keys.map((key) { |
| Map m = packages[key]; |
| String source = m['source']; |
| if (source == 'git') { |
| return new PackageRefImpl.git(key, m['version'], m['description'], |
| (curRef) { |
| for (PackageRef ref in _cache.getPackageRefs()) { |
| if (ref == curRef) return ref.resolve(); |
| } |
| return null; |
| }); |
| } else if (source == 'hosted') { |
| return new PackageRefImpl.hosted(key, m['version'], (curRef) { |
| for (PackageRef ref in _cache.getPackageRefs()) { |
| if (ref == curRef) return ref.resolve(); |
| } |
| return null; |
| }); |
| } else if (source == 'path') { |
| return new PackageRefImpl.path(key, m['version'], m['description']); |
| } else { |
| return new PackageRefImpl(source, key, m['version']); |
| } |
| }).toList(); |
| } |
| } |
| |
| /// A package reference, including the package name and version. This package |
| /// reference can be resolved to the actual package on disk. |
| abstract class PackageRef { |
| /// The type of the package reference. Valid types include `hosted` and `git`. |
| String get sourceType; |
| |
| /// The name of the package. |
| String get name; |
| |
| /// The version of the package. |
| Version get version; |
| |
| /// Resolve the package reference into the actual package, including the |
| /// location on disk. |
| Package? resolve(); |
| |
| bool operator ==(other) { |
| return other is PackageRef && |
| this.sourceType == other.sourceType && |
| this.name == other.name && |
| this.version == other.version; |
| } |
| |
| String toString() => '${name} ${version}'; |
| } |
| |
| /// A representation of a package, including the name, version, and location on |
| /// disk. |
| class Package { |
| final Directory location; |
| final String name; |
| final Version version; |
| |
| Package(this.location, this.name, this.version); |
| |
| String toString() => '${name} ${version}'; |
| } |