Merge pull request #1 from dart-lang/devoncarew_scan_cache

Devoncarew scan cache
diff --git a/test/all_test.dart b/example/list.dart
similarity index 60%
rename from test/all_test.dart
rename to example/list.dart
index 113924b..7a40694 100644
--- a/test/all_test.dart
+++ b/example/list.dart
@@ -3,12 +3,13 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'package:pubcache/pubcache.dart';
-import 'package:unittest/unittest.dart';
 
-main() {
-  group('A group of tests', () {
-    test('First Test', () {
+void main(List<String> args) {
+  PubCache cache = new PubCache();
 
-    });
+  print('activated applications:');
+
+  cache.getGlobalApplications().forEach((app) {
+    print('  ${app}');
   });
 }
diff --git a/lib/pubcache.dart b/lib/pubcache.dart
index 50b808e..e9516ce 100644
--- a/lib/pubcache.dart
+++ b/lib/pubcache.dart
@@ -4,4 +4,193 @@
 
 library pubcache;
 
-main() => print('foo');
+import 'dart:io';
+
+import 'package:path/path.dart' as path;
+import 'package:pub_semver/pub_semver.dart';
+import 'package:yaml/yaml.dart' as yaml;
+
+// TODO: do things like get all the versions for a package?
+
+// TODO: get the latest version for a package?
+
+// TODO: get the latest non-dev version for a package?
+
+// TODO: get all the packages (id's only) in the pubcache
+
+/**
+ * TODO:
+ */
+class PubCache {
+
+  static Directory getSystemCacheLocation() {
+    if (Platform.environment.containsKey('PUB_CACHE')) {
+      return new Directory(Platform.environment['PUB_CACHE']);
+    } else if (Platform.operatingSystem == 'windows') {
+      var appData = Platform.environment['APPDATA'];
+      return new Directory(path.join(appData, 'Pub', 'Cache'));
+    } else {
+      return new Directory('${Platform.environment['HOME']}/.pub-cache');
+    }
+  }
+
+  final Directory location;
+
+  List<Application> _applications;
+  List<PackageRef> _packageRefs;
+
+  PubCache([Directory dir]) :
+      location = dir == null ? getSystemCacheLocation() : dir {
+    _parse();
+  }
+
+  /**
+   * Return the contents of `bin/` - the scripts for the activated applications.
+   */
+  List<File> getBinaries() {
+    Directory dir = _getSubDir(location, 'bin');
+    return dir.existsSync() ? dir.listSync() : [];
+  }
+
+  List<Application> getGlobalApplications() => _applications;
+
+  List<PackageRef> getPackageRefs() => _packageRefs;
+
+  void _parse() {
+    // Read the activated applications.
+    _applications = [];
+
+    Directory globalPackagesDir = _getSubDir(location, 'global_packages');
+    if (globalPackagesDir.existsSync()) {
+      _applications = globalPackagesDir.listSync().map(
+          (dir) => new Application._(this, dir)).toList();
+    }
+
+    // TODO: Scan for git packages.
+
+    // Scan hosted packages - just pub.dartlang.org for now.
+    _packageRefs = [];
+
+    Directory dartlangDir = new Directory(
+        path.join(location.path, 'hosted', 'pub.dartlang.org'));
+    if (dartlangDir.existsSync()) {
+      _packageRefs = dartlangDir.listSync()
+          .where((dir) => dir is Directory)
+          .map((dir) => new _DirectoryPackageRef('hosted', dir))
+          .toList();
+    }
+  }
+
+  Directory _getSubDir(Directory dir, String name) =>
+      new Directory(path.join(dir.path, name));
+}
+
+class Application {
+  final PubCache _cache;
+  final Directory _dir;
+
+  List<PackageRef> _packageRefs;
+  Version _version;
+
+  Application._(this._cache, this._dir);
+
+  String get name => path.basename(_dir.path);
+
+  Version get version {
+    if (_packageRefs == null) _parsePubspecLock();
+    return _version;
+  }
+
+  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];
+      return new _AppPackageRef(_cache, m['source'], key, m['version']);
+    }).toList();
+
+    String name = this.name;
+
+    for (PackageRef ref in _packageRefs) {
+      if (ref.name == name) {
+        _version = ref.version;
+        break;
+      }
+    }
+  }
+}
+
+abstract class PackageRef {
+  String get sourceType;
+  String get name;
+  Version get version;
+
+  Package resolve();
+
+  bool operator ==(other) {
+    return this.sourceType == other.sourceType
+        && this.name == other.name
+        && this.version == other.version;
+  }
+
+  String toString() => '${name} ${version}';
+}
+
+class _AppPackageRef extends PackageRef {
+  final PubCache cache;
+  final String sourceType;
+  final String name;
+  final Version version;
+
+  _AppPackageRef(this.cache, this.sourceType, this.name, String ver) :
+      version = new Version.parse(ver);
+
+  Package resolve() {
+    for (PackageRef ref in cache.getPackageRefs()) {
+      if (ref == this) return ref.resolve();
+    }
+
+    return null;
+  }
+}
+
+class _DirectoryPackageRef extends PackageRef {
+  final String sourceType;
+  final Directory directory;
+
+  String _name;
+  Version _version;
+
+  _DirectoryPackageRef(this.sourceType, this.directory) {
+    _name = path.basename(this.directory.path);
+
+    int index = _name.indexOf('-');
+    if (index != -1) {
+      _version = new Version.parse(_name.substring(index + 1));
+      _name = _name.substring(0, index);
+    }
+  }
+
+  String get name => _name;
+  Version get version => _version;
+
+  Package resolve() => new Package(directory, name, version);
+}
+
+class Package {
+  final Directory location;
+  final String name;
+  final Version version;
+
+  Package(this.location, this.name, this.version);
+
+  String toString() => '${name} ${version}';
+}
diff --git a/pubspec.yaml b/pubspec.yaml
index 0ac7238..6a3a6a0 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -7,7 +7,10 @@
 environment:
   sdk: '>=1.0.0 <2.0.0'
 
-#dependencies:
-#  lib_name: any
+dependencies:
+  path: '^1.0.0'
+  pub_semver: '^1.0.0'
+  yaml: '^2.0.0'
+
 dev_dependencies:
   unittest: any
diff --git a/test/all.dart b/test/all.dart
new file mode 100644
index 0000000..e32f7d9
--- /dev/null
+++ b/test/all.dart
@@ -0,0 +1,9 @@
+// Copyright (c) 2015, the Dart project authors.  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.
+
+import 'pubcache_test.dart' as pubcache_test;
+
+void main() {
+  pubcache_test.defineTests();
+}
diff --git a/test/pubcache_test.dart b/test/pubcache_test.dart
new file mode 100644
index 0000000..187f8dc
--- /dev/null
+++ b/test/pubcache_test.dart
@@ -0,0 +1,35 @@
+// Copyright (c) 2015, the Dart project authors.  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.
+
+library pubcache_test;
+
+import 'dart:io';
+
+import 'package:path/path.dart' as path;
+import 'package:pubcache/pubcache.dart';
+import 'package:unittest/unittest.dart';
+
+void main() => defineTests();
+
+void defineTests() {
+  group('PubCache', () {
+    test('getSystemCacheLocation', () {
+      Directory cacheDir = PubCache.getSystemCacheLocation();
+      expect(cacheDir, isNotNull);
+      expect(path.basename(cacheDir.path), contains('pub-cache'));
+    });
+
+    test('PubCache', () {
+      PubCache cache = new PubCache();
+      expect(cache, isNotNull);
+      expect(cache.location, isNotNull);
+      expect(path.basename(cache.location.path), contains('pub-cache'));
+    });
+
+    test('getBinaries', () {
+      PubCache cache = new PubCache();
+      expect(cache.getBinaries(), isNotNull);
+    });
+  });
+}
diff --git a/tool/travis.sh b/tool/travis.sh
index 70ea632..a71870a 100755
--- a/tool/travis.sh
+++ b/tool/travis.sh
@@ -9,7 +9,9 @@
 
 # Verify that the libraries are error free.
 dartanalyzer --fatal-warnings \
-  lib/sample.dart
+  example/list.dart
+  lib/pubcache.dart
+  test/all.dart
 
 # Run the tests.
 dart test/all.dart