blob: 645d7652513bdf86b0059b7ed45e527c1df772aa [file] [log] [blame]
// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
library package_config.packages_impl;
import "dart:collection" show UnmodifiableMapView;
import "dart:io" show Directory;
import "package:path/path.dart" as path;
import "../packages.dart";
import "util.dart" show checkValidPackageUri;
/// A [Packages] null-object.
class NoPackages implements Packages {
const NoPackages();
Uri resolve(Uri packageUri, {Uri notFound(Uri packageUri)}) {
String packageName = checkValidPackageUri(packageUri);
if (notFound != null) return notFound(packageUri);
throw new ArgumentError.value(packageUri, "packageUri",
'No package named "$packageName"');
}
Iterable<String> get packages => new Iterable<String>.generate(0);
Map<String, Uri> asMap() => const<String,Uri>{};
}
/// Base class for [Packages] implementations.
///
/// This class implements the [resolve] method in terms of a private
/// member
abstract class _PackagesBase implements Packages {
Uri resolve(Uri packageUri, {Uri notFound(Uri packageUri)}) {
packageUri = _normalizePath(packageUri);
String packageName = checkValidPackageUri(packageUri);
Uri packageBase = _getBase(packageName);
if (packageBase == null) {
if (notFound != null) return notFound(packageUri);
throw new ArgumentError.value(packageUri, "packageUri",
'No package named "$packageName"');
}
String packagePath = packageUri.path.substring(packageName.length + 1);
return packageBase.resolve(packagePath);
}
/// Find a base location for a package name.
///
/// Returns `null` if no package exists with that name, and that can be
/// determined.
Uri _getBase(String packageName);
// TODO: inline to uri.normalizePath() when we move to 1.11
static Uri _normalizePath(Uri uri) => new Uri().resolveUri(uri);
}
/// A [Packages] implementation based on an existing map.
class MapPackages extends _PackagesBase {
final Map<String, Uri> _mapping;
MapPackages(this._mapping);
Uri _getBase(String packageName) => _mapping[packageName];
Iterable<String> get packages => _mapping.keys;
Map<String, Uri> asMap() => new UnmodifiableMapView<String, Uri>(_mapping);
}
/// A [Packages] implementation based on a local directory.
class FilePackagesDirectoryPackages extends _PackagesBase {
final Directory _packageDir;
FilePackagesDirectoryPackages(this._packageDir);
Uri _getBase(String packageName) =>
new Uri.file(path.join(_packageDir.path, packageName, '.'));
Iterable<String> _listPackageNames() {
return _packageDir.listSync()
.where((e) => e is Directory)
.map((e) => path.basename(e.path));
}
Iterable<String> get packages {
return _listPackageNames();
}
Map<String, Uri> asMap() {
var result = <String, Uri>{};
for (var packageName in _listPackageNames()) {
result[packageName] = _getBase(packageName);
}
return new UnmodifiableMapView<String, Uri>(result);
}
}
/// A [Packages] implementation based on a remote (e.g., HTTP) directory.
///
/// There is no way to detect which packages exist short of trying to use
/// them. You can't necessarily check whether a directory exists,
/// except by checking for a know file in the directory.
class NonFilePackagesDirectoryPackages extends _PackagesBase {
final Uri _packageBase;
NonFilePackagesDirectoryPackages(this._packageBase);
Uri _getBase(String packageName) => _packageBase.resolve("$packageName/");
Error _failListingPackages() {
return new UnsupportedError(
"Cannot list packages for a ${_packageBase.scheme}: "
"based package root");
}
Iterable<String> get packages {
throw _failListingPackages();
}
Map<String, Uri> asMap() {
throw _failListingPackages();
}
}