Chromium Code Reviews| Index: utils/pub/repo_source.dart |
| diff --git a/utils/pub/repo_source.dart b/utils/pub/repo_source.dart |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..0bfe14b06a6c42bd402520d25cbdfcf446aee8dd |
| --- /dev/null |
| +++ b/utils/pub/repo_source.dart |
| @@ -0,0 +1,116 @@ |
| +// Copyright (c) 2012, 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('dartlang_source'); |
| + |
| +#import('dart:io'); |
| +#import('dart:uri'); |
| +#import('io.dart'); |
| +#import('package.dart'); |
| +#import('source.dart'); |
| +#import('utils.dart'); |
| + |
| +/** |
| + * A package source that installs packages from a package repository that uses |
| + * the same API as pub.dartlang.org. |
| + */ |
| +class RepoSource extends Source { |
| + final String name = "repo"; |
| + |
| + final bool shouldCache = true; |
| + |
| + /** |
| + * The URL of the default package repository. |
| + * |
| + * At time of writing, pub.dartlang.org is not yet online, but it should be |
|
Bob Nystrom
2012/06/22 22:35:44
I'd leave a TODO here to update this comment when
nweiz
2012/06/25 22:25:17
Done.
|
| + * soon. |
| + */ |
| + static final String defaultUrl = "http://pub.dartlang.org"; |
| + |
| + RepoSource(); |
| + |
| + /** |
| + * Downloads a package from a package repository and unpacks it. |
| + */ |
| + Future<bool> install(PackageId id, String destPath) { |
| + var parsedDescription = _parseDescription(id.description); |
| + var name = parsedDescription.first; |
| + var url = parsedDescription.last; |
| + |
| + return ensureDir(destPath).chain((_) { |
| + var fullUrl = "$url/packages/$name/versions/${id.version}.tar.gz"; |
| + var httpStream = httpGet(fullUrl); |
| + var process = Process.start("tar", |
| + ["--extract", "--gunzip", "--directory", destPath]); |
|
Bob Nystrom
2012/06/22 22:35:44
How do you feel about wrapping this in a function
nweiz
2012/06/25 22:25:17
Done.
|
| + var completer = new Completer<int>(); |
| + |
| + httpStream.pipe(process.stdin); |
| + process.stdout.pipe(stdout, close: false); |
| + process.stderr.pipe(stderr, close: false); |
| + |
| + process.onExit = completer.complete; |
| + process.onError = completer.completeException; |
| + return completer.future; |
| + }).transform((exitCode) => exitCode == 0); |
| + } |
| + |
| + /** |
| + * The system cache directory for the repo source contains subdirectories for |
| + * each separate repository URL that's used on the system. Each of these |
| + * subdirectories then contains a subdirectory for each package installed from |
| + * that repository. |
| + */ |
| + String systemCacheDirectory(PackageId id, String parent) { |
| + var parsed = _parseDescription(id.description); |
| + var url = parsed.last.replaceAll(new RegExp(@"^https?://"), ""); |
| + var urlDir = replace(url, new RegExp(@'[<>:"\\/|?*%]'), (match) { |
| + return '%${match[0].charCodeAt(0)}'; |
| + }); |
| + return join(parent, urlDir, "${parsed.first}-${id.version}"); |
| + } |
| + |
| + String packageName(PackageId id) => _parseDescription(id.description).first; |
| + |
| + /** |
| + * Ensures that [description] is a valid repo description. |
| + * |
| + * There are two valid formats. A plain string refers to a package with the |
| + * given name from the default repository, while a map with keys "name" and |
| + * "url" refers to a package with the given name from the repo at the given |
| + * URL. |
| + */ |
| + void validateDescription(description) { |
| + _parseDescription(description); |
| + } |
| + |
| + /** |
| + * Parses the description blob for a package. |
| + * |
| + * If the package parses correctly, this returns a (name, url) pair. If not, |
| + * this throws a descriptive FormatException. |
| + */ |
| + Pair<String, String> _parseDescription(description) { |
| + if (description is String) { |
| + return new Pair<String, String>(description, defaultUrl); |
| + } |
| + |
| + if (description is! Map) { |
| + throw new FormatException( |
| + "The description must be a package name or map."); |
| + } |
| + |
| + if (!description.containsKey("name")) { |
| + throw new FormatException( |
| + "The description map must contain a 'name' key."); |
| + } |
| + |
| + var name = description["name"]; |
| + if (name is! String) { |
| + throw new FormatException("The 'name' key must have a string value."); |
| + } |
| + |
| + var url = description.containsKey("url") ? description["url"] : defaultUrl; |
| + return new Pair<String, String>(name, url); |
| + } |
| +} |