blob: 47d290a78acd64ad3c0aad67cc3ee469f1a1c778 [file] [log] [blame]
// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import 'dart:async';
import 'package:pub_semver/pub_semver.dart';
import '../command.dart';
import '../command_runner.dart';
import '../io.dart';
import '../package_name.dart';
import '../pubspec.dart';
import '../utils.dart';
/// Handles the `global activate` pub command.
class GlobalActivateCommand extends PubCommand {
@override
String get name => 'activate';
@override
String get description => "Make a package's executables globally available.";
@override
String get argumentsDescription => '<package> [version-constraint]';
GlobalActivateCommand() {
argParser.addOption(
'source',
abbr: 's',
help: 'The source used to find the package.',
allowed: ['git', 'hosted', 'path'],
defaultsTo: 'hosted',
);
argParser.addOption('git-path', help: 'Path of git package in repository');
argParser.addOption(
'git-ref',
help: 'Git branch or commit to be retrieved',
);
argParser.addMultiOption(
'features',
abbr: 'f',
help: 'Feature(s) to enable.',
hide: true,
);
argParser.addMultiOption(
'omit-features',
abbr: 'F',
help: 'Feature(s) to disable.',
hide: true,
);
argParser.addFlag(
'no-executables',
negatable: false,
help: 'Do not put executables on PATH.',
);
argParser.addMultiOption(
'executable',
abbr: 'x',
help: 'Executable(s) to place on PATH.',
);
argParser.addFlag(
'overwrite',
negatable: false,
help: 'Overwrite executables from other packages with the same name.',
);
argParser.addOption(
'hosted-url',
abbr: 'u',
help:
'A custom pub server URL for the package. Only applies when using the `hosted` source.',
);
}
@override
Future<void> runProtected() async {
// Default to `null`, which means all executables.
List<String>? executables;
if (argResults.wasParsed('executable')) {
if (argResults.wasParsed('no-executables')) {
usageException('Cannot pass both --no-executables and --executable.');
}
executables = argResults.multiOption('executable');
} else if (argResults.flag('no-executables')) {
// An empty list means no executables.
executables = [];
}
final overwrite = argResults.flag('overwrite');
Iterable<String> args = argResults.rest;
String readArg([String error = '']) {
if (args.isEmpty) usageException(error);
var arg = args.first;
args = args.skip(1);
return arg;
}
void validateNoExtraArgs() {
if (args.isEmpty) return;
var unexpected = args.map((arg) => '"$arg"');
var arguments = pluralize('argument', unexpected.length);
usageException('Unexpected $arguments ${toSentence(unexpected)}.');
}
if (argResults.optionWithDefault('source') != 'git' &&
(argResults.option('git-path') != null ||
argResults.option('git-ref') != null)) {
usageException(
'Options `--git-path` and `--git-ref` can only be used with --source=git.',
);
}
switch (argResults.optionWithDefault('source')) {
case 'git':
var repo = readArg('No Git repository given.');
validateNoExtraArgs();
return globals.activateGit(
repo,
executables,
overwriteBinStubs: overwrite,
path: argResults.option('git-path'),
ref: argResults.option('git-ref'),
);
case 'hosted':
var package = readArg('No package to activate given.');
PackageRef ref;
try {
ref = cache.hosted
.refFor(package, url: argResults.option('hosted-url'));
} on FormatException catch (e) {
usageException('Invalid hosted-url: $e');
}
// Parse the version constraint, if there is one.
var constraint = VersionConstraint.any;
if (args.isNotEmpty) {
try {
constraint = VersionConstraint.parse(readArg());
} on FormatException catch (error) {
usageException(error.message);
}
}
validateNoExtraArgs();
if (!packageNameRegExp.hasMatch(package)) {
final suggestion = dirExists(package)
? '\n\nDid you mean `$topLevelProgram pub global activate --source path ${escapeShellArgument(package)}`?'
: '';
usageException('Not a valid package name: "$package"$suggestion');
}
return globals.activateHosted(
ref.withConstraint(constraint),
executables,
overwriteBinStubs: overwrite,
);
case 'path':
var path = readArg('No package to activate given.');
validateNoExtraArgs();
return globals.activatePath(
path,
executables,
overwriteBinStubs: overwrite,
);
}
throw StateError('unreachable');
}
}