init (v1.24.3)

master
nixo 2020-02-18 21:56:18 +01:00
commit e8e56309a6
22 changed files with 696 additions and 0 deletions

18
.gitignore vendored Normal file
View File

@ -0,0 +1,18 @@
# Dont commit the following directories created by pub.
build/
packages
.buildlog
# Or Settings
.settings
.project
# Or the files created by dart2js.
*.dart.js
*.dart.precompiled.js
*.js_
*.js.deps
*.js.map
# Include when developing application packages.
pubspec.lock

3
.travis.yml Normal file
View File

@ -0,0 +1,3 @@
language: dart
script: ./tool/travis.sh
sudo: false

11
AUTHORS Normal file
View File

@ -0,0 +1,11 @@
# Names should be added to this file with this pattern:
#
# For individuals:
# Name <email address>
#
# For organizations:
# Organization <fnmatch pattern>
#
Google Inc. <*@google.com>
Sean Eagan <seaneagan1@gmail.com>

3
CHANGELOG.md Normal file
View File

@ -0,0 +1,3 @@
## 0.1.3
* Assume owner/group matches that of executable until it's possible to check. (#5)

33
CONTRIBUTING.md Normal file
View File

@ -0,0 +1,33 @@
Want to contribute? Great! First, read this page (including the small print at
the end).
### Before you contribute
Before we can use your code, you must sign the
[Google Individual Contributor License Agreement](https://cla.developers.google.com/about/google-individual)
(CLA), which you can do online. The CLA is necessary mainly because you own the
copyright to your changes, even after your contribution becomes part of our
codebase, so we need your permission to use and distribute your code. We also
need to be sure of various other things—for instance that you'll tell us if you
know that your code infringes on other people's patents. You don't have to sign
the CLA until after you've submitted your code for review and a member has
approved it, but you must do it before we can put your code into our codebase.
Before you start working on a larger contribution, you should get in touch with
us first through the issue tracker with your idea so that we can help out and
possibly guide you. Coordinating up front makes it much easier to avoid
frustration later on.
### Code reviews
All submissions, including submissions by project members, require review.
### File headers
All files in the project must start with the following header.
// 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.
### The small print
Contributions made by corporations are covered by a different agreement than the
one above, the
[Software Grant and Corporate Contributor License Agreement](https://developers.google.com/open-source/cla/corporate).

26
LICENSE Normal file
View File

@ -0,0 +1,26 @@
Copyright 2015, the Dart project authors. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided
with the distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

41
README.md Normal file
View File

@ -0,0 +1,41 @@
which [![pub package](http://img.shields.io/pub/v/which.svg)](https://pub.dartlang.org/packages/which) [![Build Status](https://travis-ci.org/dart-lang/which.svg?branch=master)](https://travis-ci.org/dart-lang/which) [![Coverage Status](https://coveralls.io/repos/dart-lang/which/badge.svg)](https://coveralls.io/r/dart-lang/which)
=====
Check for and locate installed executables. Just like unix [which(1)][unix_which], except:
* Doesn't shell out (fast).
* Cross-platform (works on windows).
## Install
```shell
pub global activate den
den install which
```
## Usage
```dart
import 'dart:io';
import 'package:which/which.dart';
main(arguments) async {
// Asynchronously
var git = await which('git', orElse: () => null);
// Or synchronously
var git = whichSync('git', orElse: () => null);
if (git == null) {
print('Please install git and try again');
exit(1);
}
await Process.run(git, ['add', '-A']);
await Process.run(git, ['commit', '-m', arguments.first]);
}
```
[unix_which]: http://en.wikipedia.org/wiki/Which_%28Unix%29

View File

@ -0,0 +1,39 @@
// 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 which.src.candidate_paths;
import 'dart:io';
import 'package:path/path.dart';
Iterable<String> getCandidatePaths(String command, Map<String, String> environment, bool isWindows, Context context) {
if (context.isAbsolute(command)) return [command];
String getEnvVar(String envVar, String defaultValue) {
var v = environment[envVar];
return v == null ? defaultValue : v;
}
var pathVarSeparator = isWindows ? ";" : ":";
List<String> splitEnvVar(String envVar, String defaultValue) =>
getEnvVar(envVar, defaultValue).split(pathVarSeparator);
var pathEnv = splitEnvVar('PATH', '');
var noExtPaths =
pathEnv.map((pathEntry) => context.join(pathEntry, command));
if (!isWindows) return noExtPaths;
pathEnv.insert(0, context.current);
var pathExt = splitEnvVar('PATHEXT', ".EXE");
if (command.contains('.')) pathExt.insert(0, '');
return noExtPaths.expand((commandPath) =>
pathExt.map((pathExtEntry) => commandPath + pathExtEntry));
}
Iterable<String> getRealCandidatePaths(String command) =>
getCandidatePaths(command, Platform.environment, Platform.isWindows, context);

View File

@ -0,0 +1,55 @@
// 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.
/// See http://dartbug.com/22036
library which.src.has_permission;
class FilePermission {
final int index;
final String _name;
const FilePermission._(this.index, this._name);
static const EXECUTE = const FilePermission._(0, 'EXECUTE');
static const WRITE = const FilePermission._(1, 'WRITE');
static const READ = const FilePermission._(2, 'READ');
static const SET_UID = const FilePermission._(3, 'SET_UID');
static const SET_GID = const FilePermission._(4, 'SET_GID');
static const STICKY = const FilePermission._(5, 'STICKY');
static const List<FilePermission> values = const [EXECUTE, WRITE, READ, SET_UID, SET_GID, STICKY];
String toString() => 'FilePermission.$_name';
}
class FilePermissionRole {
final int index;
final String _name;
const FilePermissionRole._(this.index, this._name);
static const WORLD = const FilePermissionRole._(0, 'WORLD');
static const GROUP = const FilePermissionRole._(1, 'GROUP');
static const OWNER = const FilePermissionRole._(2, 'OWNER');
static const List<FilePermissionRole> values = const [WORLD, GROUP, OWNER];
String toString() => 'FilePermissionRole.$_name';
}
bool hasPermission(int fileStatMode, FilePermission permission, {FilePermissionRole role: FilePermissionRole.WORLD}) {
var bitIndex = _getPermissionBitIndex(permission, role);
return (fileStatMode & (1 << bitIndex)) != 0;
}
int _getPermissionBitIndex(FilePermission permission, FilePermissionRole role) {
switch (permission) {
case FilePermission.SET_UID: return 11;
case FilePermission.SET_GID: return 10;
case FilePermission.STICKY: return 9;
default: return (role.index * 3) + permission.index;
}
}

View File

@ -0,0 +1,36 @@
// 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 which.src.is_executable;
import 'dart:async';
import 'dart:io';
import 'package:when/when.dart';
import 'has_permission.dart';
Future<bool> isExecutable(String path, bool isWindows, Future<FileStat> getStat(path)) =>
_isExecutable(path, isWindows, getStat);
bool isExecutableSync(String path, bool isWindows, FileStat getStat(path)) =>
_isExecutable(path, isWindows, getStat);
_isExecutable(String path, bool isWindows, getStat(path)) =>
when(() => getStat(path), onSuccess: (stat) => isExecutableStat(stat, isWindows));
/// Tests whether the file exists and is executable.
bool isExecutableStat(FileStat stat, bool isWindows) {
if (FileSystemEntityType.FILE != stat.type) return false;
// There is no concept of executable on windows.
if (isWindows) return true;
// TODO: This currently produces false positives (returns true when it
// shouldn't) when the uid/gid of current user and executable don't
// match. Fix if/when uid/gid support is added:
// http://dartbug.com/22037.
return FilePermissionRole.values.any((role) =>
hasPermission(stat.mode, FilePermission.EXECUTE, role: role));
}

21
lib/src/util.dart Normal file
View File

@ -0,0 +1,21 @@
// 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 which.src.util;
import 'dart:async';
/// Transparently call `firstWhere` on a [Stream] or [Iterable].
// TODO: Remove once https://dartbug.com/22028 is fixed.
dynamic firstWhere(sequence, test, { orElse() }) => sequence is Iterable ?
sequence.firstWhere(test, orElse: orElse) :
_streamFirstWhere(sequence, test, orElse: orElse);
Future _streamFirstWhere(Stream stream, test(item), { orElse() }) {
var pairs = stream.asyncMap((item) => test(item).then((result) => [item, result]));
return pairs.firstWhere((pair) => pair.last, defaultValue: () => [orElse(), null]).then((pair) => pair.first);
}
/// The identity function simply returns its argument ([x]).
dynamic identity(x) => x;

55
lib/src/which_impl.dart Normal file
View File

@ -0,0 +1,55 @@
// 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 which.src.which_impl;
import 'dart:async';
import 'package:when/when.dart';
import 'util.dart';
Future<String> which(
String command,
Iterable<String> candidatePaths,
bool isWindows,
Future<bool> isExecutable(String path, bool isWindows),
orElse()) => new Future(() => _which(
command,
candidatePaths,
isWindows,
isExecutable,
orElse,
toSequence: (items) => new Stream.fromIterable(items)));
String whichSync(
String command,
Iterable<String> candidatePaths,
bool isWindows,
bool isExecutable(String path, bool isWindows),
orElse()) => _which(
command,
candidatePaths,
isWindows,
isExecutable,
orElse);
_which(
String command,
Iterable<String> candidatePaths,
bool isWindows,
isExecutable(String path, bool isWindows),
orElse(),
{toSequence(Iterable items): identity}) => when(
() => firstWhere(
toSequence(candidatePaths),
(path) => isExecutable(path, isWindows),
orElse: orElse != null ? orElse : () => _commandNotFound(command, null)),
onError: (e) => _commandNotFound(command, e));
_commandNotFound(String command, e) {
var message = 'Command not found: $command';
if (e != null) message += '\n$e';
throw new StateError(message);
}

32
lib/which.dart Normal file
View File

@ -0,0 +1,32 @@
// 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 which;
import 'dart:async';
import 'dart:io';
import 'src/candidate_paths.dart';
import 'src/is_executable.dart';
import 'src/which_impl.dart' as impl;
/// Returns a future for the first [command] executable in the `PATH`.
///
/// If [command] is not found, [orElse] is called, which defaults to throwing.
Future<String> which(String command, { orElse() }) => new Future(() => impl.which(
command,
getRealCandidatePaths(command),
Platform.isWindows,
(path, isWindows) => isExecutable(path, isWindows, FileStat.stat),
orElse));
/// Returns the first [command] executable in the `PATH`.
///
/// If [command] is not found, [orElse] is called, which defaults to throwing.
String whichSync(String command, { orElse() }) => impl.whichSync(
command,
getRealCandidatePaths(command),
Platform.isWindows,
(path, isWindows) => isExecutableSync(path, isWindows, FileStat.statSync),
orElse);

15
pubspec.yaml Normal file
View File

@ -0,0 +1,15 @@
name: which
version: 0.1.3
authors:
Dart Team <misc@dartlang.org>
Sean Eagan <seaneagan1@gmail.com>
description: Like unix which(1) - check for and locate installed executables.
homepage: https://github.com/dart-lang/which
environment:
sdk: '>=1.0.0 <2.0.0'
dependencies:
path: '>=1.3.1 <2.0.0'
when: '>=0.2.0 <0.3.0'
dev_dependencies:
mockito: '>=0.8.1 <0.9.0'
unittest: '>=0.11.4 <0.12.0'

View File

@ -0,0 +1,29 @@
// 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 which.test.candidate_paths;
import 'package:unittest/unittest.dart';
import 'util.dart';
main() {
group('getCandidatePaths', () {
test('posix', () {
var candidatePaths = getPosixCandidatePaths('z', '/x/y:/a/b/c', '/foo/bar');
expect(candidatePaths, ['/x/y/z', '/a/b/c/z']);
});
test('windows', () {
var candidatePaths = getWindowsCandidatePaths('z', r'C:\x\y;C:\a\b\c', '.EXE;.BAT', r'C:\foo\bar');
expect(candidatePaths, [
r'C:\foo\bar\z.EXE',
r'C:\foo\bar\z.BAT',
r'C:\x\y\z.EXE',
r'C:\x\y\z.BAT',
r'C:\a\b\c\z.EXE',
r'C:\a\b\c\z.BAT']);
});
});
}

View File

@ -0,0 +1,29 @@
// 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 which.test.has_permission;
import 'package:unittest/unittest.dart';
import 'package:which/src/has_permission.dart';
import 'util.dart';
main() {
test('hasPermission', () {
var mode = parseBinary('010101010101');
expect(hasPermission(mode, FilePermission.SET_UID), isFalse);
expect(hasPermission(mode, FilePermission.SET_GID), isTrue);
expect(hasPermission(mode, FilePermission.STICKY), isFalse);
expect(hasPermission(mode, FilePermission.READ, role: FilePermissionRole.OWNER), isTrue);
expect(hasPermission(mode, FilePermission.WRITE, role: FilePermissionRole.OWNER), isFalse);
expect(hasPermission(mode, FilePermission.EXECUTE, role: FilePermissionRole.OWNER), isTrue);
expect(hasPermission(mode, FilePermission.READ, role: FilePermissionRole.GROUP), isFalse);
expect(hasPermission(mode, FilePermission.WRITE, role: FilePermissionRole.GROUP), isTrue);
expect(hasPermission(mode, FilePermission.EXECUTE, role: FilePermissionRole.GROUP), isFalse);
expect(hasPermission(mode, FilePermission.READ, role: FilePermissionRole.WORLD), isTrue);
expect(hasPermission(mode, FilePermission.WRITE, role: FilePermissionRole.WORLD), isFalse);
expect(hasPermission(mode, FilePermission.EXECUTE, role: FilePermissionRole.WORLD), isTrue);
});
}

View File

@ -0,0 +1,77 @@
// 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 which.test.is_executable;
import 'dart:io';
import 'package:mockito/mockito.dart';
import 'package:unittest/unittest.dart';
import 'package:which/src/is_executable.dart';
import 'util.dart';
main() {
group('isExecutableStat', () {
test('false if not a file', () {
var stat = new MockFileStat();
// A directory.
when(stat.type).thenReturn(FileSystemEntityType.DIRECTORY);
var result = isExecutableStat(stat, false);
expect(result, isFalse);
verifyNever(stat.mode);
});
test('true for all files on windows', () {
var stat = new MockFileStat();
// A file.
when(stat.type).thenReturn(FileSystemEntityType.FILE);
var result = isExecutableStat(stat, true);
expect(result, isTrue);
verifyNever(stat.mode);
});
test('true if has world execute permission', () {
var result = isExecutableStat(_getMockFileStat('000000000001'), false);
expect(result, isTrue);
});
test('true if has group execute permission', () {
var result = isExecutableStat(_getMockFileStat('000000001000'), false);
expect(result, isTrue);
});
test('true if has owner execute permission', () {
var result = isExecutableStat(_getMockFileStat('000001000000'), false);
expect(result, isTrue);
});
test('false if has no execute permissions', () {
var result = isExecutableStat(_getMockFileStat('111110110110'), false);
expect(result, isFalse);
});
});
}
MockFileStat _getMockFileStat(String mode) {
var stat = new MockFileStat();
// A file.
when(stat.type).thenReturn(FileSystemEntityType.FILE);
// Last bit is world execute.
when(stat.mode).thenReturn(int.parse(mode, radix: 2));
return stat;
}

19
test/test.dart Normal file
View File

@ -0,0 +1,19 @@
// 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 which.test;
import 'candidate_paths_test.dart' as candidate_paths;
import 'has_permission_test.dart' as has_permission;
import 'is_executable_test.dart' as is_exe;
import 'which_test.dart' as which;
import 'which_impl_test.dart' as which_impl;
main() {
candidate_paths.main();
has_permission.main();
is_exe.main();
which.main();
which_impl.main();
}

41
test/util.dart Normal file
View File

@ -0,0 +1,41 @@
// 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 which.test.util;
import 'dart:io';
import 'package:mockito/mockito.dart';
import 'package:path/path.dart' as path;
import 'package:which/src/candidate_paths.dart';
getPosixCandidatePaths(String command, String pathVar, String current) {
var env = {
'PATH': pathVar
};
var isWindows = false;
var context = new path.Context(style: path.Style.posix, current: current);
return getCandidatePaths(command, env, isWindows, context);
}
getWindowsCandidatePaths(String command, String pathVar, String pathExtVar, String current) {
var env = {
'PATH': pathVar,
'PATHEXT': pathExtVar
};
var isWindows = true;
var context = new path.Context(style: path.Style.windows, current: current);
return getCandidatePaths(command, env, isWindows, context);
}
class MockFileStat extends Mock implements FileStat {
MockFileStat();
noSuchMethod(i) => super.noSuchMethod(i);
}
int parseBinary(String b) => int.parse(b, radix: 2);

58
test/which_impl_test.dart Normal file
View File

@ -0,0 +1,58 @@
// 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 which.test.which_impl;
import 'dart:async';
import 'package:unittest/unittest.dart';
import 'package:which/src/which_impl.dart';
import 'util.dart';
main() {
group('which', () {
test('should complete to the first matching executable in candidate paths', () {
var candidatePaths = getPosixCandidatePaths('z', '/x/y:/a/b/c', '/foo/bar');
return which('z', candidatePaths, false, (path, isWindows) => new Future.value(path == '/x/y/z' || path == '/a/b/c/z'), null)
.then((path) => expect(path, '/x/y/z'));
});
test('should call orElse if command not found', () {
var candidatePaths = getPosixCandidatePaths('z', '/x/y:/a/b/c', '/foo/bar');
return which('z', candidatePaths, false, (path, isWindows) => new Future.value(false), () => '/or/else')
.then((path) => expect(path, '/or/else'));
});
test('should throw state error if command not found and orElse not provided', () {
var future = new Future(() =>
which('z', [], false, (path, isWindows) => new Future.value(false), null));
expect(future, throwsStateError);
});
});
group('whichSync', () {
test('should return the first matching executable in candidate paths', () {
var candidatePaths = getWindowsCandidatePaths('z', r'C:\x\y;C:\a\b\c', '.EXE;.BAT', r'C:\foo\bar');
var result = whichSync('find', candidatePaths, true, (path, isWindows) => path == r'C:\x\y\z.BAT' || path == r'C:\a\b\c\z.BAT', null);
expect(result, r'C:\x\y\z.BAT');
});
test('should call orElse if command not found', () {
var candidatePaths = getWindowsCandidatePaths('z', r'C:\x\y;C:\a\b\c', '.EXE;.BAT', r'C:\foo\bar');
var result = whichSync('find', candidatePaths, true, (path, isWindows) => false, () => r'C:\or\else');
expect(result, r'C:\or\else');
});
test('should throw state error if command not found and orElse not provided', () {
expect(() => whichSync('z', [], true, (path, isWindows) => false, null), throwsStateError);
});
});
}

29
test/which_test.dart Normal file
View File

@ -0,0 +1,29 @@
// 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 which.test.which;
import 'package:path/path.dart';
import 'package:unittest/unittest.dart';
import 'package:which/which.dart';
main() {
group('which', () {
// Any dart:io supported platform (*nix, osx, windows) should have `find`.
test('should find `find`', () => which('find').then(_testResult));
});
group('whichSync', () {
// Any dart:io supported platform (*nix, osx, windows) should have `find`.
test('should find `find`', () {
_testResult(whichSync('find'));
});
});
}
_testResult(String path) {
expect(path, isNotNull);
var base = basenameWithoutExtension(path);
expect(base, 'find');
}

26
tool/travis.sh Executable file
View File

@ -0,0 +1,26 @@
#!/bin/bash
# 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.
# Fast fail the script on failures.
set -e
# Verify that the libraries are error free.
dartanalyzer --fatal-warnings \
lib/which.dart \
test/test.dart
# Run the tests.
dart test/test.dart
# Install dart_coveralls; gather and send coverage data.
if [ "$COVERALLS_TOKEN" ]; then
pub global activate dart_coveralls 0.1.11
pub global run dart_coveralls report \
--token $COVERALLS_TOKEN \
--retry 2 \
--exclude-test-files \
test/test.dart
fi