From b12e27a4d207a72aafde6d113f915b03e57af07f Mon Sep 17 00:00:00 2001 From: "rnystrom@google.com" Date: Fri, 15 Feb 2013 01:13:07 +0000 Subject: [PATCH] Get rid of join() and encapsulate File and Directory in io.dart. Review URL: https://codereview.chromium.org//12253054 git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@18551 260f80e4-7a28-3924-810f-c04153c831b5 --- utils/pub/command_lish.dart | 2 +- utils/pub/entrypoint.dart | 22 +- utils/pub/git_source.dart | 9 +- utils/pub/hosted_source.dart | 4 +- utils/pub/io.dart | 248 ++++++++-------------- utils/pub/oauth2.dart | 2 +- utils/pub/pub.dart | 12 +- utils/pub/sdk.dart | 4 +- utils/pub/sdk_source.dart | 5 +- utils/pub/source.dart | 6 +- utils/pub/system_cache.dart | 6 +- utils/pub/validator/compiled_dartdoc.dart | 8 +- utils/pub/validator/lib.dart | 2 +- utils/pub/validator/name.dart | 2 +- utils/tests/pub/io_test.dart | 126 +++++------ utils/tests/pub/test_pub.dart | 52 +++-- utils/tests/pub/validator_test.dart | 25 +-- 17 files changed, 245 insertions(+), 290 deletions(-) diff --git a/utils/pub/command_lish.dart b/utils/pub/command_lish.dart index f2e5f052923..d2a033b1da2 100644 --- a/utils/pub/command_lish.dart +++ b/utils/pub/command_lish.dart @@ -136,7 +136,7 @@ class LishCommand extends PubCommand { var rootDir = entrypoint.root.dir; return git.isInstalled.then((gitInstalled) { - if (dirExists(join(rootDir, '.git')) && gitInstalled) { + if (dirExists(path.join(rootDir, '.git')) && gitInstalled) { // List all files that aren't gitignored, including those not checked // in to Git. return git.run(["ls-files", "--cached", "--others", diff --git a/utils/pub/entrypoint.dart b/utils/pub/entrypoint.dart index f778bbb2cd7..054541d4e30 100644 --- a/utils/pub/entrypoint.dart +++ b/utils/pub/entrypoint.dart @@ -53,7 +53,7 @@ class Entrypoint { // TODO(rnystrom): Make this path configurable. /// The path to the entrypoint's "packages" directory. - String get packagesDir => join(root.dir, 'packages'); + String get packagesDir => path.join(root.dir, 'packages'); /// Ensures that the package identified by [id] is installed to the directory. /// Returns the resolved [PackageId]. @@ -70,7 +70,7 @@ class Entrypoint { var pendingOrCompleted = _installs[id]; if (pendingOrCompleted != null) return pendingOrCompleted; - var packageDir = join(packagesDir, id.name); + var packageDir = path.join(packagesDir, id.name); var future = defer(() { ensureDir(path.dirname(packageDir)); if (!dirExists(packageDir)) return; @@ -207,7 +207,7 @@ class Entrypoint { /// Loads the list of concrete package versions from the `pubspec.lock`, if it /// exists. If it doesn't, this completes to an empty [LockFile]. LockFile loadLockFile() { - var lockFilePath = join(root.dir, 'pubspec.lock'); + var lockFilePath = path.join(root.dir, 'pubspec.lock'); if (!fileExists(lockFilePath)) return new LockFile.empty(); return new LockFile.parse(readTextFile(lockFilePath), cache.sources); } @@ -219,7 +219,7 @@ class Entrypoint { if (!id.isRoot) lockFile.packages[id.name] = id; } - var lockFilePath = join(root.dir, 'pubspec.lock'); + var lockFilePath = path.join(root.dir, 'pubspec.lock'); writeTextFile(lockFilePath, lockFile.serialize()); } @@ -227,7 +227,7 @@ class Entrypoint { /// allow a package to import its own files using `package:`. Future _installSelfReference(_) { return defer(() { - var linkPath = join(packagesDir, root.name); + var linkPath = path.join(packagesDir, root.name); // Create the symlink if it doesn't exist. if (entryExists(linkPath)) return; ensureDir(packagesDir); @@ -240,11 +240,11 @@ class Entrypoint { /// into them so that their entrypoints can be run. Do the same for any /// subdirectories of `test/` and `example/`. Future _linkSecondaryPackageDirs(_) { - var binDir = join(root.dir, 'bin'); - var exampleDir = join(root.dir, 'example'); - var testDir = join(root.dir, 'test'); - var toolDir = join(root.dir, 'tool'); - var webDir = join(root.dir, 'web'); + var binDir = path.join(root.dir, 'bin'); + var exampleDir = path.join(root.dir, 'example'); + var testDir = path.join(root.dir, 'test'); + var toolDir = path.join(root.dir, 'tool'); + var webDir = path.join(root.dir, 'web'); return defer(() { if (!dirExists(binDir)) return; return _linkSecondaryPackageDir(binDir); @@ -294,7 +294,7 @@ class Entrypoint { /// Creates a symlink to the `packages` directory in [dir] if none exists. Future _linkSecondaryPackageDir(String dir) { return defer(() { - var to = join(dir, 'packages'); + var to = path.join(dir, 'packages'); if (entryExists(to)) return; return createSymlink(packagesDir, to); }); diff --git a/utils/pub/git_source.dart b/utils/pub/git_source.dart index ab2758efdae..fdb0ed4828c 100644 --- a/utils/pub/git_source.dart +++ b/utils/pub/git_source.dart @@ -5,6 +5,9 @@ library git_source; import 'dart:async'; + +import '../../pkg/path/lib/path.dart' as path; + import 'git.dart' as git; import 'io.dart'; import 'package.dart'; @@ -42,7 +45,7 @@ class GitSource extends Source { "Please ensure Git is correctly installed."); } - ensureDir(join(systemCacheRoot, 'cache')); + ensureDir(path.join(systemCacheRoot, 'cache')); return _ensureRepoCache(id); }).then((_) => systemCacheDirectory(id)).then((path) { revisionCachePath = path; @@ -61,7 +64,7 @@ class GitSource extends Source { Future systemCacheDirectory(PackageId id) { return _revisionAt(id).then((rev) { var revisionCacheName = '${id.name}-$rev'; - return join(systemCacheRoot, revisionCacheName); + return path.join(systemCacheRoot, revisionCacheName); }); } /// Ensures [description] is a Git URL. @@ -148,7 +151,7 @@ class GitSource extends Source { /// [id] (the one in `/git/cache`). String _repoCachePath(PackageId id) { var repoCacheName = '${id.name}-${sha1(_getUrl(id))}'; - return join(systemCacheRoot, 'cache', repoCacheName); + return path.join(systemCacheRoot, 'cache', repoCacheName); } /// Returns the repository URL for [id]. diff --git a/utils/pub/hosted_source.dart b/utils/pub/hosted_source.dart index ef56462d37b..dda00a42c51 100644 --- a/utils/pub/hosted_source.dart +++ b/utils/pub/hosted_source.dart @@ -11,6 +11,8 @@ import 'dart:uri'; // TODO(nweiz): Make this import better. import '../../pkg/http/lib/http.dart' as http; +import '../../pkg/path/lib/path.dart' as path; + import 'http.dart'; import 'io.dart'; import 'log.dart' as log; @@ -99,7 +101,7 @@ class HostedSource extends Source { }); return new Future.immediate( - join(systemCacheRoot, urlDir, "${parsed.first}-${id.version}")); + path.join(systemCacheRoot, urlDir, "${parsed.first}-${id.version}")); } String packageName(description) => _parseDescription(description).first; diff --git a/utils/pub/io.dart b/utils/pub/io.dart index c4f5edfa31c..85a094cedab 100644 --- a/utils/pub/io.dart +++ b/utils/pub/io.dart @@ -22,17 +22,6 @@ export '../../pkg/http/lib/http.dart' show ByteStream; final NEWLINE_PATTERN = new RegExp("\r\n?|\n\r?"); -/// Joins a number of path string parts into a single path. Handles -/// platform-specific path separators. Parts can be [String], [Directory], or -/// [File] objects. -String join(part1, [part2, part3, part4, part5, part6, part7, part8]) { - var parts = [part1, part2, part3, part4, part5, part6, part7, part8] - .map((part) => part == null ? null : _getPath(part)).toList(); - - return path.join(parts[0], parts[1], parts[2], parts[3], parts[4], parts[5], - parts[6], parts[7]); -} - /// Returns whether or not [entry] is nested somewhere within [dir]. This just /// performs a path comparison; it doesn't look at the actual filesystem. bool isBeneath(String entry, String dir) { @@ -40,92 +29,82 @@ bool isBeneath(String entry, String dir) { return !path.isAbsolute(relative) && path.split(relative)[0] != '..'; } -/// Determines if [path], which can be a [String] file path, a [File], or a -/// [Directory] exists on the file system. -bool entryExists(path) => fileExists(path) || dirExists(path); +/// Determines if a file or directory at [path] exists. +bool entryExists(String path) => fileExists(path) || dirExists(path); -/// Determines if [file], which can be a [String] file path or a [File], exists -/// on the file system. -bool fileExists(file) => _getFile(file).existsSync(); +/// Determines if [file] exists on the file system. +bool fileExists(String file) => new File(file).existsSync(); -/// Reads the contents of the text file [file], which can either be a [String] -/// or a [File]. -String readTextFile(file) => _getFile(file).readAsStringSync(Encoding.UTF_8); +/// Reads the contents of the text file [file]. +String readTextFile(String file) => + new File(file).readAsStringSync(Encoding.UTF_8); -/// Reads the contents of the binary file [file], which can either be a [String] -/// or a [File]. -List readBinaryFile(file) { - var path = _getPath(file); - log.io("Reading binary file $path."); - var contents = new File(path).readAsBytesSync(); - log.io("Read ${contents.length} bytes from $path."); +/// Reads the contents of the binary file [file]. +List readBinaryFile(String file) { + log.io("Reading binary file $file."); + var contents = new File(file).readAsBytesSync(); + log.io("Read ${contents.length} bytes from $file."); return contents; } -/// Creates [file] (which can either be a [String] or a [File]), and writes -/// [contents] to it. +/// Creates [file] and writes [contents] to it. /// /// If [dontLogContents] is true, the contents of the file will never be logged. -File writeTextFile(file, String contents, {dontLogContents: false}) { - var path = _getPath(file); - file = new File(path); - +String writeTextFile(String file, String contents, {dontLogContents: false}) { // Sanity check: don't spew a huge file. - log.io("Writing ${contents.length} characters to text file $path."); + log.io("Writing ${contents.length} characters to text file $file."); if (!dontLogContents && contents.length < 1024 * 1024) { log.fine("Contents:\n$contents"); } - return file..writeAsStringSync(contents); -} - -/// Deletes [file], which can be a [String] or a [File]. -File deleteFile(file) => _getFile(file)..delete(); - -/// Creates [file] (which can either be a [String] or a [File]), and writes -/// [contents] to it. -File writeBinaryFile(file, List contents) { - var path = _getPath(file); - file = new File(path); - - log.io("Writing ${contents.length} bytes to binary file $path."); - file.openSync(FileMode.WRITE) - ..writeListSync(contents, 0, contents.length) - ..closeSync(); - log.fine("Wrote text file $path."); + new File(file).writeAsStringSync(contents); return file; } -/// Writes [stream] to a new file at [path], which may be a [String] or a -/// [File]. Will replace any file already at that path. Completes when the file -/// is done being written. -Future createFileFromStream(Stream> stream, path) { - path = _getPath(path); +/// Deletes [file]. +void deleteFile(String file) { + new File(file).delete(); +} - log.io("Creating $path from stream."); +/// Creates [file] and writes [contents] to it. +String writeBinaryFile(String file, List contents) { + log.io("Writing ${contents.length} bytes to binary file $file."); + new File(file).openSync(FileMode.WRITE) + ..writeListSync(contents, 0, contents.length) + ..closeSync(); + log.fine("Wrote text file $file."); + return file; +} - var file = new File(path); - return stream.pipe(wrapOutputStream(file.openOutputStream())).then((_) { - log.fine("Created $path from stream."); +/// Writes [stream] to a new file at path [file]. Will replace any file already +/// at that path. Completes when the file is done being written. +Future createFileFromStream(Stream> stream, String file) { + log.io("Creating $file from stream."); + + var stream = new File(file).openOutputStream(); + return stream.pipe(wrapOutputStream(stream)).then((_) { + log.fine("Created $file from stream."); + return file; }); } /// Creates a directory [dir]. -Directory createDir(dir) => _getDirectory(dir)..createSync(); +String createDir(String dir) { + new Directory(dir).createSync(); + return dir; +} /// Ensures that [dirPath] and all its parent directories exist. If they don't /// exist, creates them. -Directory ensureDir(dirPath) { - dirPath = _getPath(dirPath); - +String ensureDir(String dirPath) { log.fine("Ensuring directory $dirPath exists."); var dir = new Directory(dirPath); - if (dirPath == '.' || dirExists(dirPath)) return dir; + if (dirPath == '.' || dirExists(dirPath)) return dirPath; ensureDir(path.dirname(dirPath)); try { - createDir(dir); + createDir(dirPath); } on DirectoryIOException catch (ex) { // Error 17 means the directory already exists (or 183 on Windows). if (ex.osError.errorCode == 17 || ex.osError.errorCode == 183) { @@ -135,7 +114,7 @@ Directory ensureDir(dirPath) { } } - return dir; + return dirPath; } /// Creates a temp directory whose name will be based on [dir] with a unique @@ -143,35 +122,32 @@ Directory ensureDir(dirPath) { /// created in a platform-dependent temporary location. Returns the path of the /// created directory. String createTempDir([dir = '']) { - var tempDir = _getDirectory(dir).createTempSync(); + var tempDir = new Directory(dir).createTempSync(); log.io("Created temp directory ${tempDir.path}"); return tempDir.path; } -/// Asynchronously recursively deletes [dir], which can be a [String] or a -/// [Directory]. Returns a [Future] that completes when the deletion is done. -Future deleteDir(dir) { - dir = _getDirectory(dir); - - return _attemptRetryable(() => log.ioAsync("delete directory ${dir.path}", - dir.delete(recursive: true))); +/// Asynchronously recursively deletes [dir]. Returns a [Future] that completes +/// when the deletion is done. +Future deleteDir(String dir) { + return _attemptRetryable(() => log.ioAsync("delete directory $dir", + new Directory(dir).delete(recursive: true).then((_) => dir))); } -/// Asynchronously lists the contents of [dir], which can be a [String] -/// directory path or a [Directory]. If [recursive] is `true`, lists +/// Asynchronously lists the contents of [dir]. If [recursive] is `true`, lists /// subdirectory contents (defaults to `false`). If [includeHiddenFiles] is /// `true`, includes files and directories beginning with `.` (defaults to /// `false`). /// /// If [dir] is a string, the returned paths are guaranteed to begin with it. -Future> listDir(dir, +Future> listDir(String dir, {bool recursive: false, bool includeHiddenFiles: false}) { - Future> doList(Directory dir, Set listedDirectories) { + Future> doList(String dir, Set listedDirectories) { var contents = []; var completer = new Completer>(); // Avoid recursive symlinks. - var resolvedPath = new File(dir.path).fullPathSync(); + var resolvedPath = new File(dir).fullPathSync(); if (listedDirectories.contains(resolvedPath)) { return new Future.immediate([]); } @@ -179,15 +155,14 @@ Future> listDir(dir, listedDirectories = new Set.from(listedDirectories); listedDirectories.add(resolvedPath); - log.io("Listing directory ${dir.path}."); - var lister = dir.list(); + log.io("Listing directory $dir."); + var lister = new Directory(dir).list(); lister.onDone = (done) { // TODO(rnystrom): May need to sort here if it turns out onDir and onFile // aren't guaranteed to be called in a certain order. So far, they seem to. if (done) { - log.fine("Listed directory ${dir.path}:\n" - "${contents.join('\n')}"); + log.fine("Listed directory $dir:\n${contents.join('\n')}"); completer.complete(contents); } }; @@ -204,19 +179,19 @@ Future> listDir(dir, lister.onError = (error) => completer.completeError(error, stackTrace); lister.onDir = (file) { if (!includeHiddenFiles && path.basename(file).startsWith('.')) return; - file = join(dir, path.basename(file)); + file = path.join(dir, path.basename(file)); contents.add(file); // TODO(nweiz): don't manually recurse once issue 7358 is fixed. Note that // once we remove the manual recursion, we'll need to explicitly filter // out files in hidden directories. if (recursive) { - children.add(doList(new Directory(file), listedDirectories)); + children.add(doList(file, listedDirectories)); } }; lister.onFile = (file) { if (!includeHiddenFiles && path.basename(file).startsWith('.')) return; - contents.add(join(dir, path.basename(file))); + contents.add(path.join(dir, path.basename(file))); }; return completer.future.then((contents) { @@ -227,17 +202,16 @@ Future> listDir(dir, }); } - return doList(_getDirectory(dir), new Set()); + return doList(dir, new Set()); } -/// Determines if [dir], which can be a [String] directory path or a -/// [Directory], exists on the file system. -bool dirExists(dir) => _getDirectory(dir).existsSync(); +/// Determines if [dir] exists on the file system. +bool dirExists(String dir) => new Directory(dir).existsSync(); /// "Cleans" [dir]. If that directory already exists, it will be deleted. Then a /// new empty directory will be created. Returns a [Future] that completes when /// the new clean directory is created. -Future cleanDir(dir) { +Future cleanDir(String dir) { return defer(() { if (dirExists(dir)) { // Delete it first. @@ -251,13 +225,12 @@ Future cleanDir(dir) { /// Renames (i.e. moves) the directory [from] to [to]. Returns a [Future] with /// the destination directory. -Future renameDir(from, String to) { - from = _getDirectory(from); - log.io("Renaming directory ${from.path} to $to."); +Future renameDir(String from, String to) { + log.io("Renaming directory $from to $to."); - return _attemptRetryable(() => from.rename(to)).then((dir) { - log.fine("Renamed directory ${from.path} to $to."); - return dir; + return _attemptRetryable(() => new Directory(from).rename(to)).then((dir) { + log.fine("Renamed directory $from to $to."); + return to; }); } @@ -291,15 +264,11 @@ Future _attemptRetryable(Future callback()) { return makeAttempt(null); } -/// Creates a new symlink that creates an alias from [from] to [to], both of -/// which can be a [String], [File], or [Directory]. Returns a [Future] which -/// completes to the symlink file (i.e. [to]). +/// Creates a new symlink that creates an alias from [from] to [to]. Returns a +/// [Future] which completes to the symlink file (i.e. [to]). /// /// Note that on Windows, only directories may be symlinked to. -Future createSymlink(from, to) { - from = _getPath(from); - to = _getPath(to); - +Future createSymlink(String from, String to) { log.fine("Creating symlink ($to is a symlink to $from)"); var command = 'ln'; @@ -315,22 +284,19 @@ Future createSymlink(from, to) { args = ['/j', to, from]; } - return runProcess(command, args).then((result) { - // TODO(rnystrom): Check exit code and output? - return new File(to); - }); + // TODO(rnystrom): Check exit code and output? + return runProcess(command, args).then((result) => to); } /// Creates a new symlink that creates an alias from the `lib` directory of -/// package [from] to [to], both of which can be a [String], [File], or -/// [Directory]. Returns a [Future] which completes to the symlink file (i.e. -/// [to]). If [from] does not have a `lib` directory, this shows a warning if -/// appropriate and then does nothing. -Future createPackageSymlink(String name, from, to, +/// package [from] to [to]. Returns a [Future] which completes to the symlink +/// file (i.e. [to]). If [from] does not have a `lib` directory, this shows a +/// warning if appropriate and then does nothing. +Future createPackageSymlink(String name, String from, String to, {bool isSelfLink: false}) { return defer(() { // See if the package has a "lib" directory. - from = join(from, 'lib'); + from = path.join(from, 'lib'); log.fine("Creating ${isSelfLink ? "self" : ""}link for package '$name'."); if (dirExists(from)) return createSymlink(from, to); @@ -342,7 +308,7 @@ Future createPackageSymlink(String name, from, to, 'you will not be able to import any libraries from it.'); } - return _getFile(to); + return to; }); } @@ -360,7 +326,7 @@ String relativeToPub(String target) { utilDir = path.dirname(utilDir); } - return path.normalize(join(utilDir, 'pub', target)); + return path.normalize(path.join(utilDir, 'pub', target)); } // TODO(nweiz): add a ByteSink wrapper to make writing strings to stdout/stderr @@ -643,8 +609,8 @@ class PubProcess { /// Calls [fn] with appropriately modified arguments. [fn] should have the same /// signature as [Process.start], except that the returned [Future] may have a /// type other than [Process]. -Future _doProcess(Function fn, String executable, List args, workingDir, - Map environment) { +Future _doProcess(Function fn, String executable, List args, + String workingDir, Map environment) { // TODO(rnystrom): Should dart:io just handle this? // Spawning a process on Windows will not look for the executable in the // system path. So, if executable looks like it needs that (i.e. it doesn't @@ -657,7 +623,7 @@ Future _doProcess(Function fn, String executable, List args, workingDir, final options = new ProcessOptions(); if (workingDir != null) { - options.workingDirectory = _getDirectory(workingDir).path; + options.workingDirectory = workingDir; } if (environment != null) { @@ -713,11 +679,9 @@ Future withTempDir(Future fn(String path)) { }); } -/// Extracts a `.tar.gz` file from [stream] to [destination], which can be a -/// directory or a path. Returns whether or not the extraction was successful. -Future extractTarGz(Stream> stream, destination) { - destination = _getPath(destination); - +/// Extracts a `.tar.gz` file from [stream] to [destination]. Returns whether +/// or not the extraction was successful. +Future extractTarGz(Stream> stream, String destination) { log.fine("Extracting .tar.gz stream to $destination."); if (Platform.operatingSystem == "windows") { @@ -761,7 +725,8 @@ Future _extractTarGzWindows(Stream> stream, return withTempDir((tempDir) { // Write the archive to a temp file. - return createFileFromStream(stream, join(tempDir, 'data.tar.gz')).then((_) { + var dataFile = path.join(tempDir, 'data.tar.gz'); + return createFileFromStream(stream, dataFile).then((_) { // 7zip can't unarchive from gzip -> tar -> destination all in one step // first we un-gzip it to a tar file. // Note: Setting the working directory instead of passing in a full file @@ -816,7 +781,7 @@ ByteStream createTarGz(List contents, {baseDir}) { if (baseDir == null) baseDir = path.current; baseDir = path.absolute(baseDir); contents = contents.map((entry) { - entry = path.absolute(_getPath(entry)); + entry = path.absolute(entry); if (!isBeneath(entry, baseDir)) { throw 'Entry $entry is not inside $baseDir.'; } @@ -825,7 +790,7 @@ ByteStream createTarGz(List contents, {baseDir}) { if (Platform.operatingSystem != "windows") { var args = ["--create", "--gzip", "--directory", baseDir]; - args.addAll(contents.map(_getPath)); + args.addAll(contents); // TODO(nweiz): It's possible that enough command-line arguments will make // the process choke, so at some point we should save the arguments to a // file and pass them in via --files-from for tar and -i@filename for 7zip. @@ -842,7 +807,7 @@ ByteStream createTarGz(List contents, {baseDir}) { withTempDir((tempDir) { // Create the tar file. - var tarFile = join(tempDir, "intermediate.tar"); + var tarFile = path.join(tempDir, "intermediate.tar"); var args = ["a", "-w$baseDir", tarFile]; args.addAll(contents.map((entry) => '-i!"$entry"')); @@ -897,31 +862,6 @@ class PubProcessResult { bool get success => exitCode == 0; } -/// Gets a dart:io [File] for [entry], which can either already be a File or be -/// a path string. -File _getFile(entry) { - if (entry is File) return entry; - if (entry is String) return new File(entry); - throw 'Entry $entry is not a supported type.'; -} - -/// Gets the path string for [entry], which can either already be a path string, -/// or be a [File] or [Directory]. Allows working generically with "file-like" -/// objects. -String _getPath(entry) { - if (entry is String) return entry; - if (entry is File) return entry.name; - if (entry is Directory) return entry.path; - throw 'Entry $entry is not a supported type.'; -} - -/// Gets a [Directory] for [entry], which can either already be one, or be a -/// [String]. -Directory _getDirectory(entry) { - if (entry is Directory) return entry; - return new Directory(entry); -} - /// Gets a [Uri] for [uri], which can either already be one, or be a [String]. Uri _getUri(uri) { if (uri is Uri) return uri; diff --git a/utils/pub/oauth2.dart b/utils/pub/oauth2.dart index b690c6c85cd..276fb25b62b 100644 --- a/utils/pub/oauth2.dart +++ b/utils/pub/oauth2.dart @@ -147,7 +147,7 @@ void _saveCredentials(SystemCache cache, Credentials credentials) { /// The path to the file in which the user's OAuth2 credentials are stored. String _credentialsFile(SystemCache cache) => - join(cache.rootDir, 'credentials.json'); + path.join(cache.rootDir, 'credentials.json'); /// Gets the user to authorize pub as a client of pub.dartlang.org via oauth2. /// Returns a Future that will complete to a fully-authorized [Client]. diff --git a/utils/pub/pub.dart b/utils/pub/pub.dart index a8371633fe4..569c63c00e5 100644 --- a/utils/pub/pub.dart +++ b/utils/pub/pub.dart @@ -6,12 +6,12 @@ library pub; import 'dart:async'; -import '../../pkg/args/lib/args.dart'; -import '../../pkg/path/lib/path.dart' as path; import 'dart:io'; import 'dart:math'; -import 'http.dart'; -import 'io.dart'; + +import '../../pkg/args/lib/args.dart'; +import '../../pkg/path/lib/path.dart' as path; + import 'command_help.dart'; import 'command_install.dart'; import 'command_lish.dart'; @@ -20,6 +20,8 @@ import 'command_uploader.dart'; import 'command_version.dart'; import 'entrypoint.dart'; import 'exit_codes.dart' as exit_codes; +import 'http.dart'; +import 'io.dart'; import 'log.dart' as log; import 'package.dart'; import 'pubspec.dart'; @@ -116,7 +118,7 @@ main() { cacheDir = Platform.environment['PUB_CACHE']; } else if (Platform.operatingSystem == 'windows') { var appData = Platform.environment['APPDATA']; - cacheDir = join(appData, 'Pub', 'Cache'); + cacheDir = path.join(appData, 'Pub', 'Cache'); } else { cacheDir = '${Platform.environment['HOME']}/.pub-cache'; } diff --git a/utils/pub/sdk.dart b/utils/pub/sdk.dart index 98007b5a40c..1db2a04b9da 100644 --- a/utils/pub/sdk.dart +++ b/utils/pub/sdk.dart @@ -8,6 +8,8 @@ library sdk; import 'dart:io'; import '../../pkg/path/lib/path.dart' as path; + +import 'io.dart'; import 'log.dart' as log; import 'version.dart'; @@ -38,7 +40,7 @@ Version version = _getVersion(); /// Determine the SDK's version number. Version _getVersion() { var revisionPath = path.join(rootDirectory, "version"); - var version = new File(revisionPath).readAsStringSync().trim(); + var version = readTextFile(revisionPath).trim(); // Given a version file like: 0.1.2.0_r17495 // We create a semver like: 0.1.2+0.r17495 diff --git a/utils/pub/sdk_source.dart b/utils/pub/sdk_source.dart index 6fbba095944..1544152e135 100644 --- a/utils/pub/sdk_source.dart +++ b/utils/pub/sdk_source.dart @@ -5,6 +5,9 @@ library sdk_source; import 'dart:async'; + +import '../../pkg/path/lib/path.dart' as path; + import 'io.dart'; import 'package.dart'; import 'pubspec.dart'; @@ -45,7 +48,7 @@ class SdkSource extends Source { /// Gets the path in the SDK's "pkg" directory to the directory containing /// package [id]. Returns `null` if the package could not be found. String _getPackagePath(PackageId id) { - var pkgPath = join(sdk.rootDirectory, "pkg", id.description); + var pkgPath = path.join(sdk.rootDirectory, "pkg", id.description); return dirExists(pkgPath) ? pkgPath : null; } } diff --git a/utils/pub/source.dart b/utils/pub/source.dart index 30fd5ebbebd..1fd93271282 100644 --- a/utils/pub/source.dart +++ b/utils/pub/source.dart @@ -47,7 +47,7 @@ abstract class Source { /// The root directory of this source's cache within the system cache. /// /// This shouldn't be overridden by subclasses. - String get systemCacheRoot => join(systemCache.rootDir, name); + String get systemCacheRoot => path.join(systemCache.rootDir, name); /// Records the system cache to which this source belongs. /// @@ -144,9 +144,9 @@ abstract class Source { /// * It has no pubspec. Future _isCachedPackageCorrupted(String packageDir) { return defer(() { - if (!fileExists(join(packageDir, "pubspec.yaml"))) return true; + if (!fileExists(path.join(packageDir, "pubspec.yaml"))) return true; - var libDir = join(packageDir, "lib"); + var libDir = path.join(packageDir, "lib"); if (dirExists(libDir)) { return listDir(libDir).then((contents) => contents.length == 0); } diff --git a/utils/pub/system_cache.dart b/utils/pub/system_cache.dart index 377ac17fb80..8bd31786c89 100644 --- a/utils/pub/system_cache.dart +++ b/utils/pub/system_cache.dart @@ -7,6 +7,8 @@ library system_cache; import 'dart:io'; import 'dart:async'; +import '../../pkg/path/lib/path.dart' as path; + import 'git_source.dart'; import 'hosted_source.dart'; import 'io.dart'; @@ -30,7 +32,7 @@ class SystemCache { /// The root directory where this package cache is located. final String rootDir; - String get tempDir => join(rootDir, '_temp'); + String get tempDir => path.join(rootDir, '_temp'); /// Packages which are currently being asynchronously installed to the cache. final Map> _pendingInstalls; @@ -105,7 +107,7 @@ class SystemCache { /// cache so that it can move the directory from it. String createTempDir() { var temp = ensureDir(tempDir); - return io.createTempDir(join(temp, 'dir')); + return io.createTempDir(path.join(temp, 'dir')); } /// Delete's the system cache's internal temp directory. diff --git a/utils/pub/validator/compiled_dartdoc.dart b/utils/pub/validator/compiled_dartdoc.dart index 20f69be322e..2d340ba1e83 100644 --- a/utils/pub/validator/compiled_dartdoc.dart +++ b/utils/pub/validator/compiled_dartdoc.dart @@ -28,10 +28,10 @@ class CompiledDartdocValidator extends Validator { // Look for tell-tale Dartdoc output files all in the same directory. var files = [ entry, - join(dir, "index.html"), - join(dir, "styles.css"), - join(dir, "dart-logo-small.png"), - join(dir, "client-live-nav.js") + path.join(dir, "index.html"), + path.join(dir, "styles.css"), + path.join(dir, "dart-logo-small.png"), + path.join(dir, "client-live-nav.js") ]; if (files.every((val) => fileExists(val))) { diff --git a/utils/pub/validator/lib.dart b/utils/pub/validator/lib.dart index c72d309c25e..5a637a4cd9b 100644 --- a/utils/pub/validator/lib.dart +++ b/utils/pub/validator/lib.dart @@ -23,7 +23,7 @@ class LibValidator extends Validator { : super(entrypoint); Future validate() { - var libDir = join(entrypoint.root.dir, "lib"); + var libDir = path.join(entrypoint.root.dir, "lib"); return defer(() { if (!dirExists(libDir)) { diff --git a/utils/pub/validator/name.dart b/utils/pub/validator/name.dart index 6a8cd918ea6..2ad4bc9faa0 100644 --- a/utils/pub/validator/name.dart +++ b/utils/pub/validator/name.dart @@ -48,7 +48,7 @@ class NameValidator extends Validator { /// Returns a list of all libraries in the current package as paths relative /// to the package's root directory. Future> get _libraries { - var libDir = join(entrypoint.root.dir, "lib"); + var libDir = path.join(entrypoint.root.dir, "lib"); return defer(() { if (!dirExists(libDir)) return []; return listDir(libDir, recursive: true); diff --git a/utils/tests/pub/io_test.dart b/utils/tests/pub/io_test.dart index 6c6922c35b7..990dd6cf774 100644 --- a/utils/tests/pub/io_test.dart +++ b/utils/tests/pub/io_test.dart @@ -4,7 +4,9 @@ library io_test; +import '../../../pkg/path/lib/path.dart' as path; import '../../../pkg/unittest/lib/unittest.dart'; + import '../../pub/io.dart'; import '../../pub/utils.dart'; import 'test_pub.dart'; @@ -14,119 +16,119 @@ main() { group('listDir', () { test('lists a simple directory non-recursively', () { - expect(withTempDir((path) { + expect(withTempDir((temp) { var future = defer(() { - writeTextFile(join(path, 'file1.txt'), ''); - writeTextFile(join(path, 'file2.txt'), ''); - createDir(join(path, 'subdir')); - writeTextFile(join(path, 'subdir', 'file3.txt'), ''); - return listDir(path); + writeTextFile(path.join(temp, 'file1.txt'), ''); + writeTextFile(path.join(temp, 'file2.txt'), ''); + createDir(path.join(temp, 'subdir')); + writeTextFile(path.join(temp, 'subdir', 'file3.txt'), ''); + return listDir(temp); }); expect(future, completion(unorderedEquals([ - join(path, 'file1.txt'), - join(path, 'file2.txt'), - join(path, 'subdir') + path.join(temp, 'file1.txt'), + path.join(temp, 'file2.txt'), + path.join(temp, 'subdir') ]))); return future; }), completes); }); test('lists a simple directory recursively', () { - expect(withTempDir((path) { + expect(withTempDir((temp) { var future = defer(() { - writeTextFile(join(path, 'file1.txt'), ''); - writeTextFile(join(path, 'file2.txt'), ''); - createDir(join(path, 'subdir')); - writeTextFile(join(path, 'subdir', 'file3.txt'), ''); - return listDir(path, recursive: true); + writeTextFile(path.join(temp, 'file1.txt'), ''); + writeTextFile(path.join(temp, 'file2.txt'), ''); + createDir(path.join(temp, 'subdir')); + writeTextFile(path.join(temp, 'subdir', 'file3.txt'), ''); + return listDir(temp, recursive: true); }); expect(future, completion(unorderedEquals([ - join(path, 'file1.txt'), - join(path, 'file2.txt'), - join(path, 'subdir'), - join(path, 'subdir', 'file3.txt'), + path.join(temp, 'file1.txt'), + path.join(temp, 'file2.txt'), + path.join(temp, 'subdir'), + path.join(temp, 'subdir', 'file3.txt'), ]))); return future; }), completes); }); test('ignores hidden files by default', () { - expect(withTempDir((path) { + expect(withTempDir((temp) { var future = defer(() { - writeTextFile(join(path, 'file1.txt'), ''); - writeTextFile(join(path, 'file2.txt'), ''); - writeTextFile(join(path, '.file3.txt'), ''); - createDir(join(path, '.subdir')); - writeTextFile(join(path, '.subdir', 'file3.txt'), ''); - return listDir(path, recursive: true); + writeTextFile(path.join(temp, 'file1.txt'), ''); + writeTextFile(path.join(temp, 'file2.txt'), ''); + writeTextFile(path.join(temp, '.file3.txt'), ''); + createDir(path.join(temp, '.subdir')); + writeTextFile(path.join(temp, '.subdir', 'file3.txt'), ''); + return listDir(temp, recursive: true); }); expect(future, completion(unorderedEquals([ - join(path, 'file1.txt'), - join(path, 'file2.txt') + path.join(temp, 'file1.txt'), + path.join(temp, 'file2.txt') ]))); return future; }), completes); }); test('includes hidden files when told to', () { - expect(withTempDir((path) { + expect(withTempDir((temp) { var future = defer(() { - writeTextFile(join(path, 'file1.txt'), ''); - writeTextFile(join(path, 'file2.txt'), ''); - writeTextFile(join(path, '.file3.txt'), ''); - createDir(join(path, '.subdir')); - writeTextFile(join(path, '.subdir', 'file3.txt'), ''); - return listDir(path, recursive: true, includeHiddenFiles: true); + writeTextFile(path.join(temp, 'file1.txt'), ''); + writeTextFile(path.join(temp, 'file2.txt'), ''); + writeTextFile(path.join(temp, '.file3.txt'), ''); + createDir(path.join(temp, '.subdir')); + writeTextFile(path.join(temp, '.subdir', 'file3.txt'), ''); + return listDir(temp, recursive: true, includeHiddenFiles: true); }); expect(future, completion(unorderedEquals([ - join(path, 'file1.txt'), - join(path, 'file2.txt'), - join(path, '.file3.txt'), - join(path, '.subdir'), - join(path, '.subdir', 'file3.txt') + path.join(temp, 'file1.txt'), + path.join(temp, 'file2.txt'), + path.join(temp, '.file3.txt'), + path.join(temp, '.subdir'), + path.join(temp, '.subdir', 'file3.txt') ]))); return future; }), completes); }); test('returns the unresolved paths for symlinks', () { - expect(withTempDir((path) { - var dirToList = join(path, 'dir-to-list'); + expect(withTempDir((temp) { + var dirToList = path.join(temp, 'dir-to-list'); var future = defer(() { - createDir(join(path, 'dir1')); - writeTextFile(join(path, 'dir1', 'file1.txt'), ''); - createDir(join(path, 'dir2')); - writeTextFile(join(path, 'dir2', 'file2.txt'), ''); + createDir(path.join(temp, 'dir1')); + writeTextFile(path.join(temp, 'dir1', 'file1.txt'), ''); + createDir(path.join(temp, 'dir2')); + writeTextFile(path.join(temp, 'dir2', 'file2.txt'), ''); createDir(dirToList); - return createSymlink(join(path, 'dir1'), - join(dirToList, 'linked-dir1')); + return createSymlink(path.join(temp, 'dir1'), + path.join(dirToList, 'linked-dir1')); }).then((_) { - createDir(join(dirToList, 'subdir')); + createDir(path.join(dirToList, 'subdir')); return createSymlink( - join(path, 'dir2'), - join(dirToList, 'subdir', 'linked-dir2')); + path.join(temp, 'dir2'), + path.join(dirToList, 'subdir', 'linked-dir2')); }).then((_) => listDir(dirToList, recursive: true)); expect(future, completion(unorderedEquals([ - join(dirToList, 'linked-dir1'), - join(dirToList, 'linked-dir1', 'file1.txt'), - join(dirToList, 'subdir'), - join(dirToList, 'subdir', 'linked-dir2'), - join(dirToList, 'subdir', 'linked-dir2', 'file2.txt'), + path.join(dirToList, 'linked-dir1'), + path.join(dirToList, 'linked-dir1', 'file1.txt'), + path.join(dirToList, 'subdir'), + path.join(dirToList, 'subdir', 'linked-dir2'), + path.join(dirToList, 'subdir', 'linked-dir2', 'file2.txt'), ]))); return future; }), completes); }); test('works with recursive symlinks', () { - expect(withTempDir((path) { + expect(withTempDir((temp) { var future = defer(() { - writeTextFile(join(path, 'file1.txt'), ''); - return createSymlink(path, join(path, 'linkdir')); - }).then((_) => listDir(path, recursive: true)); + writeTextFile(path.join(temp, 'file1.txt'), ''); + return createSymlink(temp, path.join(temp, 'linkdir')); + }).then((_) => listDir(temp, recursive: true)); expect(future, completion(unorderedEquals([ - join(path, 'file1.txt'), - join(path, 'linkdir') + path.join(temp, 'file1.txt'), + path.join(temp, 'linkdir') ]))); return future; }), completes); diff --git a/utils/tests/pub/test_pub.dart b/utils/tests/pub/test_pub.dart index 34a424c1eca..2a148f214c0 100644 --- a/utils/tests/pub/test_pub.dart +++ b/utils/tests/pub/test_pub.dart @@ -553,7 +553,7 @@ String get testDirectory { /// are assumed to be relative to [sandboxDir]. void scheduleRename(String from, String to) { _schedule((sandboxDir) { - return renameDir(join(sandboxDir, from), join(sandboxDir, to)); + return renameDir(path.join(sandboxDir, from), path.join(sandboxDir, to)); }); } @@ -632,7 +632,7 @@ void confirmPublish(ScheduledProcess pub) { /// [Future] may have a type other than [Process]. Future _doPub(Function fn, sandboxDir, List args, Future tokenEndpoint) { String pathInSandbox(String relPath) { - return join(path.absolute(sandboxDir), relPath); + return path.join(path.absolute(sandboxDir), relPath); } return defer(() { @@ -853,15 +853,15 @@ abstract class Descriptor { /// Validates that at least one file in [dir] matching [name] is valid /// according to [validate]. [validate] should throw or complete to an /// exception if the input path is invalid. - Future _validateOneMatch(String dir, Future validate(String path)) { + Future _validateOneMatch(String dir, Future validate(String entry)) { // Special-case strings to support multi-level names like "myapp/packages". if (name is String) { - var path = join(dir, name); + var entry = path.join(dir, name); return defer(() { - if (!entryExists(path)) { - throw new ExpectException('Entry $path not found.'); + if (!entryExists(entry)) { + throw new ExpectException('Entry $entry not found.'); } - return validate(path); + return validate(entry); }); } @@ -929,13 +929,13 @@ class FileDescriptor extends Descriptor { /// Creates the file within [dir]. Returns a [Future] that is completed after /// the creation is done. - Future create(dir) => - defer(() => writeBinaryFile(join(dir, _stringName), contents)); + Future create(dir) => + defer(() => writeBinaryFile(path.join(dir, _stringName), contents)); /// Deletes the file within [dir]. Returns a [Future] that is completed after /// the deletion is done. Future delete(dir) => - defer(() => deleteFile(join(dir, _stringName))); + defer(() => deleteFile(path.join(dir, _stringName))); /// Validates that this file correctly matches the actual file at [path]. Future validate(String path) { @@ -972,10 +972,10 @@ class DirectoryDescriptor extends Descriptor { /// Creates the file within [dir]. Returns a [Future] that is completed after /// the creation is done. - Future create(parentDir) { + Future create(parentDir) { return defer(() { // Create the directory. - var dir = ensureDir(join(parentDir, _stringName)); + var dir = ensureDir(path.join(parentDir, _stringName)); if (contents == null) return dir; // Recursively create all of its children. @@ -988,7 +988,7 @@ class DirectoryDescriptor extends Descriptor { /// Deletes the directory within [dir]. Returns a [Future] that is completed /// after the deletion is done. Future delete(dir) { - return deleteDir(join(dir, _stringName)); + return deleteDir(path.join(dir, _stringName)); } /// Validates that the directory at [path] contains all of the expected @@ -1050,7 +1050,7 @@ class GitRepoDescriptor extends DirectoryDescriptor { : super(name, contents); /// Creates the Git repository and commits the contents. - Future create(parentDir) { + Future create(parentDir) { return _runGitCommands(parentDir, [ ['init'], ['add', '.'], @@ -1081,10 +1081,7 @@ class GitRepoDescriptor extends DirectoryDescriptor { /// Schedule a Git command to run in this repository. void scheduleGit(List args) { - _schedule((parentDir) { - var gitDir = new Directory(join(parentDir, name)); - return _runGit(args, gitDir); - }); + _schedule((parentDir) => _runGit(args, path.join(parentDir, name))); } Future _runGitCommands(parentDir, List> commands) { @@ -1102,7 +1099,7 @@ class GitRepoDescriptor extends DirectoryDescriptor { }); } - Future> _runGit(List args, Directory workingDir) { + Future> _runGit(List args, String workingDir) { // Explicitly specify the committer information. Git needs this to commit // and we don't want to rely on the buildbots having this already set up. var environment = { @@ -1112,8 +1109,7 @@ class GitRepoDescriptor extends DirectoryDescriptor { 'GIT_COMMITTER_EMAIL': 'pub@dartlang.org' }; - return gitlib.run(args, workingDir: workingDir.path, - environment: environment); + return gitlib.run(args, workingDir: workingDir, environment: environment); } } @@ -1126,13 +1122,15 @@ class TarFileDescriptor extends Descriptor { /// Creates the files and directories within this tar file, then archives /// them, compresses them, and saves the result to [parentDir]. - Future create(parentDir) { + Future create(parentDir) { return withTempDir((tempDir) { return Future.wait(contents.map((child) => child.create(tempDir))) .then((createdContents) { return createTarGz(createdContents, baseDir: tempDir).toBytes(); }).then((bytes) { - return new File(join(parentDir, _stringName)).writeAsBytes(bytes); + var file = path.join(parentDir, _stringName); + writeBinaryFile(file, bytes); + return file; }); }); } @@ -1157,7 +1155,7 @@ class TarFileDescriptor extends Descriptor { // TODO(nweiz): propagate any errors to the return value. See issue 3657. withTempDir((tempDir) { return create(tempDir).then((tar) { - var sourceStream = tar.openInputStream(); + var sourceStream = new File(tar).openInputStream(); return store(wrapInputStream(sourceStream), controller); }); }); @@ -1174,7 +1172,7 @@ class NothingDescriptor extends Descriptor { Future validate(String dir) { return defer(() { - if (entryExists(join(dir, name))) { + if (entryExists(path.join(dir, name))) { throw new ExpectException('File $name in $dir should not exist.'); } }); @@ -1198,10 +1196,10 @@ typedef Validator ValidatorCreator(Entrypoint entrypoint); Future, List>> schedulePackageValidation( ValidatorCreator fn) { return _scheduleValue((sandboxDir) { - var cache = new SystemCache.withSources(join(sandboxDir, cachePath)); + var cache = new SystemCache.withSources(path.join(sandboxDir, cachePath)); return defer(() { - var validator = fn(new Entrypoint(join(sandboxDir, appPath), cache)); + var validator = fn(new Entrypoint(path.join(sandboxDir, appPath), cache)); return validator.validate().then((_) { return new Pair(validator.errors, validator.warnings); }); diff --git a/utils/tests/pub/validator_test.dart b/utils/tests/pub/validator_test.dart index ab67f7713e2..3dbb5adef14 100644 --- a/utils/tests/pub/validator_test.dart +++ b/utils/tests/pub/validator_test.dart @@ -9,11 +9,12 @@ import 'dart:io'; import 'dart:json' as json; import 'dart:math' as math; -import 'test_pub.dart'; import '../../../pkg/http/lib/http.dart' as http; import '../../../pkg/http/lib/testing.dart'; import '../../../pkg/path/lib/path.dart' as path; import '../../../pkg/unittest/lib/unittest.dart'; + +import 'test_pub.dart'; import '../../pub/entrypoint.dart'; import '../../pub/io.dart'; import '../../pub/validator.dart'; @@ -115,20 +116,20 @@ main() { }); integration('has a COPYING file', () { - file(join(appPath, 'LICENSE'), '').scheduleDelete(); - file(join(appPath, 'COPYING'), '').scheduleCreate(); + file(path.join(appPath, 'LICENSE'), '').scheduleDelete(); + file(path.join(appPath, 'COPYING'), '').scheduleCreate(); expectNoValidationError(license); }); integration('has a prefixed LICENSE file', () { - file(join(appPath, 'LICENSE'), '').scheduleDelete(); - file(join(appPath, 'MIT_LICENSE'), '').scheduleCreate(); + file(path.join(appPath, 'LICENSE'), '').scheduleDelete(); + file(path.join(appPath, 'MIT_LICENSE'), '').scheduleCreate(); expectNoValidationError(license); }); integration('has a suffixed LICENSE file', () { - file(join(appPath, 'LICENSE'), '').scheduleDelete(); - file(join(appPath, 'LICENSE.md'), '').scheduleCreate(); + file(path.join(appPath, 'LICENSE'), '').scheduleDelete(); + file(path.join(appPath, 'LICENSE.md'), '').scheduleCreate(); expectNoValidationError(license); }); @@ -272,7 +273,7 @@ main() { }); integration('has no LICENSE file', () { - file(join(appPath, 'LICENSE'), '').scheduleDelete(); + file(path.join(appPath, 'LICENSE'), '').scheduleDelete(); expectValidationError(license); }); @@ -334,7 +335,7 @@ main() { }); integration('has a single library named differently than the package', () { - file(join(appPath, "lib", "test_pkg.dart"), '').scheduleDelete(); + file(path.join(appPath, "lib", "test_pkg.dart"), '').scheduleDelete(); dir(appPath, [ dir("lib", [file("best_pkg.dart", "int i = 0;")]) ]).scheduleCreate(); @@ -342,17 +343,17 @@ main() { }); integration('has no lib directory', () { - dir(join(appPath, "lib")).scheduleDelete(); + dir(path.join(appPath, "lib")).scheduleDelete(); expectValidationError(lib); }); integration('has an empty lib directory', () { - file(join(appPath, "lib", "test_pkg.dart"), '').scheduleDelete(); + file(path.join(appPath, "lib", "test_pkg.dart"), '').scheduleDelete(); expectValidationError(lib); }); integration('has a lib directory containing only src', () { - file(join(appPath, "lib", "test_pkg.dart"), '').scheduleDelete(); + file(path.join(appPath, "lib", "test_pkg.dart"), '').scheduleDelete(); dir(appPath, [ dir("lib", [ dir("src", [file("test_pkg.dart", "int i = 0;")])