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
This commit is contained in:
rnystrom@google.com 2013-02-15 01:13:07 +00:00
parent 10f7ad94ae
commit b12e27a4d2
17 changed files with 245 additions and 290 deletions

View file

@ -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",

View file

@ -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);
});

View file

@ -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<String> 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 `<system cache>/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].

View file

@ -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;

View file

@ -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<int> 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<int> 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<int> 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<File> createFileFromStream(Stream<List<int>> 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<int> 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<String> createFileFromStream(Stream<List<int>> 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<Directory> 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<String> 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<List<String>> listDir(dir,
Future<List<String>> listDir(String dir,
{bool recursive: false, bool includeHiddenFiles: false}) {
Future<List<String>> doList(Directory dir, Set<String> listedDirectories) {
Future<List<String>> doList(String dir, Set<String> listedDirectories) {
var contents = <String>[];
var completer = new Completer<List<String>>();
// 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<List<String>> listDir(dir,
listedDirectories = new Set<String>.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<List<String>> 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<List<String>> listDir(dir,
});
}
return doList(_getDirectory(dir), new Set<String>());
return doList(dir, new Set<String>());
}
/// 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<Directory> cleanDir(dir) {
Future<String> cleanDir(String dir) {
return defer(() {
if (dirExists(dir)) {
// Delete it first.
@ -251,13 +225,12 @@ Future<Directory> cleanDir(dir) {
/// Renames (i.e. moves) the directory [from] to [to]. Returns a [Future] with
/// the destination directory.
Future<Directory> renameDir(from, String to) {
from = _getDirectory(from);
log.io("Renaming directory ${from.path} to $to.");
Future<String> 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<File> createSymlink(from, to) {
from = _getPath(from);
to = _getPath(to);
Future<String> createSymlink(String from, String to) {
log.fine("Creating symlink ($to is a symlink to $from)");
var command = 'ln';
@ -315,22 +284,19 @@ Future<File> 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<File> 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<String> 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<File> 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<String> args, workingDir,
Map<String, String> environment) {
Future _doProcess(Function fn, String executable, List<String> args,
String workingDir, Map<String, String> 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<String> 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<bool> extractTarGz(Stream<List<int>> stream, destination) {
destination = _getPath(destination);
/// Extracts a `.tar.gz` file from [stream] to [destination]. Returns whether
/// or not the extraction was successful.
Future<bool> extractTarGz(Stream<List<int>> stream, String destination) {
log.fine("Extracting .tar.gz stream to $destination.");
if (Platform.operatingSystem == "windows") {
@ -761,7 +725,8 @@ Future<bool> _extractTarGzWindows(Stream<List<int>> 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;

View file

@ -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].

View file

@ -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';
}

View file

@ -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

View file

@ -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;
}
}

View file

@ -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<bool> _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);
}

View file

@ -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<PackageId, Future<Package>> _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.

View file

@ -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))) {

View file

@ -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)) {

View file

@ -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<List<String>> 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);

View file

@ -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);

View file

@ -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<Uri> 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<File> create(dir) =>
defer(() => writeBinaryFile(join(dir, _stringName), contents));
Future<String> 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<Directory> create(parentDir) {
Future<String> 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<Directory> 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<String> 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<List<String>> commands) {
@ -1102,7 +1099,7 @@ class GitRepoDescriptor extends DirectoryDescriptor {
});
}
Future<List<String>> _runGit(List<String> args, Directory workingDir) {
Future<List<String>> _runGit(List<String> 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<File> create(parentDir) {
Future<String> 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<Pair<List<String>, List<String>>> 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);
});

View file

@ -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;")])