Initial commit.
diff --git a/pkgs/io/.gitignore b/pkgs/io/.gitignore new file mode 100644 index 0000000..dd3394e --- /dev/null +++ b/pkgs/io/.gitignore
@@ -0,0 +1,3 @@ +.pub/ +.packages +pubspec.lock
diff --git a/pkgs/io/.travis.yml b/pkgs/io/.travis.yml new file mode 100644 index 0000000..ccd3815 --- /dev/null +++ b/pkgs/io/.travis.yml
@@ -0,0 +1,20 @@ +language: dart +sudo: false +dart: + - dev + - stable +cache: + directories: + - $HOME/.pub-cache +dart_task: + - test: --platform vm + install_dartium: true + - dartanalyzer + - dartfmt +matrix: + # Only run dartfmt checks with stable. + exclude: + - dart: dev + dart_task: dartfmt + - dart: dev + dart_task: dartanalyzer
diff --git a/pkgs/io/AUTHORS b/pkgs/io/AUTHORS new file mode 100644 index 0000000..ff09364 --- /dev/null +++ b/pkgs/io/AUTHORS
@@ -0,0 +1,7 @@ +# Below is a list of people and organizations that have contributed +# to the project. Names should be added to the list like so: +# +# Name/Organization <email address> + +Google Inc. +
diff --git a/pkgs/io/CHANGELOG.md b/pkgs/io/CHANGELOG.md new file mode 100644 index 0000000..9334d24 --- /dev/null +++ b/pkgs/io/CHANGELOG.md
@@ -0,0 +1,7 @@ +## 0.1.0 + +- Initial commit of `FutureOr<bool> String isExecutable(path)`: + +```dart + +``` \ No newline at end of file
diff --git a/pkgs/io/LICENSE b/pkgs/io/LICENSE new file mode 100644 index 0000000..e76eb0c --- /dev/null +++ b/pkgs/io/LICENSE
@@ -0,0 +1,26 @@ +Copyright 2017, 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 package:dom 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. \ No newline at end of file
diff --git a/pkgs/io/README.md b/pkgs/io/README.md new file mode 100644 index 0000000..e470cf5 --- /dev/null +++ b/pkgs/io/README.md
@@ -0,0 +1,12 @@ +# io + +Contains utilities for the Dart VM's `dart:io`. + +## Usage + +### Files + +#### `isExecutable` + +Returns whether a provided file path is considered _executable_ on the host +operating system.
diff --git a/pkgs/io/analysis_options.yaml b/pkgs/io/analysis_options.yaml new file mode 100644 index 0000000..cf2c891 --- /dev/null +++ b/pkgs/io/analysis_options.yaml
@@ -0,0 +1,54 @@ +analyzer: + strong-mode: + implicit-casts: false + implicit-dynamic: false + +linter: + rules: + # Error Rules + - avoid_empty_else + - comment_references + - control_flow_in_finally + - empty_statements + - hash_and_equals + - invariant_booleans + - iterable_contains_unrelated_type + - list_remove_unrelated_type + - no_adjacent_strings_in_list + - no_duplicate_case_values + - test_types_in_equals + - throw_in_finally + - unrelated_type_equality_checks + - valid_regexps + + # Style Rules + - annotate_overrides + - avoid_init_to_null + - avoid_return_types_on_setters + - camel_case_types + - cascade_invocations + - constant_identifier_names + - directives_ordering + - empty_catches + - empty_constructor_bodies + - implementation_imports + - library_names + - library_prefixes + - non_constant_identifier_names + - omit_local_variable_types + - only_throw_errors + - prefer_adjacent_string_concatenation + - prefer_collection_literals + - prefer_const_constructors + - prefer_contains + - prefer_final_fields + - prefer_final_locals + - prefer_initializing_formals + - prefer_interpolation_to_compose_strings + - prefer_is_empty + - prefer_is_not_empty + - recursive_getters + - slash_for_doc_comments + - type_init_formals + - unnecessary_brace_in_string_interps + - unnecessary_this
diff --git a/pkgs/io/lib/io.dart b/pkgs/io/lib/io.dart new file mode 100644 index 0000000..35a6663 --- /dev/null +++ b/pkgs/io/lib/io.dart
@@ -0,0 +1,6 @@ +// Copyright 2017, 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. + +export 'src/permissions.dart' + show FilePermissionRole, FilePermission, hasPermission, isExecutable;
diff --git a/pkgs/io/lib/src/permissions.dart b/pkgs/io/lib/src/permissions.dart new file mode 100644 index 0000000..d72afd2 --- /dev/null +++ b/pkgs/io/lib/src/permissions.dart
@@ -0,0 +1,72 @@ +// Copyright 2017, 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 'dart:io'; + +/// What type of permission is granted to a file based on file permission roles. +enum _FilePermission { + execute, + write, + read, + setGid, + setUid, + sticky, +} + +/// What type of role is assigned to a file. +enum _FilePermissionRole { + world, + group, + user, +} + +/// Returns whether file [stat] has [permission] for a [role] type. +bool _hasPermission( + FileStat stat, + _FilePermission permission, { + _FilePermissionRole role: _FilePermissionRole.world, +}) { + final index = _permissionBitIndex(permission, role); + return (stat.mode & (1 << index)) != 0; +} + +int _permissionBitIndex(_FilePermission permission, _FilePermissionRole role) { + switch (permission) { + case _FilePermission.setUid: + return 11; + case _FilePermission.setGid: + return 10; + case _FilePermission.sticky: + return 9; + default: + return (role.index * 3) + permission.index; + } +} + +/// Returns whether [path] is considered an executable file on this OS. +/// +/// May optionally define how to implement [getStat] or whether to execute based +/// on whether this is the windows platform ([isWindows]) - if not set it is +/// automatically extracted from `dart:io#Platform`. +/// +/// **NOTE**: On windows this always returns `true`. +FutureOr<bool> isExecutable( + String path, { + bool isWindows, + FutureOr<FileStat> getStat(String path): FileStat.stat, +}) { + // Windows has no concept of executable. + if (isWindows ?? Platform.isWindows) return true; + final stat = getStat(path); + if (stat is FileStat) { + return _isExecutable(stat); + } + return (stat as Future<FileStat>).then(_isExecutable); +} + +bool _isExecutable(FileStat stat) => + stat.type == FileSystemEntityType.FILE && + _FilePermissionRole.values.any( + (role) => _hasPermission(stat, _FilePermission.execute, role: role));
diff --git a/pkgs/io/pubspec.yaml b/pkgs/io/pubspec.yaml new file mode 100644 index 0000000..999e752 --- /dev/null +++ b/pkgs/io/pubspec.yaml
@@ -0,0 +1,12 @@ +name: io +description: > + Utilities for the Dart VM Runtime. +version: 0.1.0 +author: Dart Team <misc@dartlang.org> +homepage: https://github.com/dart-lang/io + +environment: + sdk: ">=1.22.0 <2.0.0" + +dev_dependencies: + test: ^0.12.0
diff --git a/pkgs/io/test/_files/is_executable.sh b/pkgs/io/test/_files/is_executable.sh new file mode 100755 index 0000000..f1f641a --- /dev/null +++ b/pkgs/io/test/_files/is_executable.sh
@@ -0,0 +1 @@ +#!/usr/bin/env bash
diff --git a/pkgs/io/test/_files/is_not_executable.sh b/pkgs/io/test/_files/is_not_executable.sh new file mode 100644 index 0000000..f1f641a --- /dev/null +++ b/pkgs/io/test/_files/is_not_executable.sh
@@ -0,0 +1 @@ +#!/usr/bin/env bash
diff --git a/pkgs/io/test/permissions_test.dart b/pkgs/io/test/permissions_test.dart new file mode 100644 index 0000000..51fbf6b --- /dev/null +++ b/pkgs/io/test/permissions_test.dart
@@ -0,0 +1,35 @@ +// Copyright 2017, 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 'package:io/io.dart'; +import 'package:test/test.dart'; + +void main() { + group('isExecutable', () { + const files = 'test/_files'; + const shellIsExec = '$files/is_executable.sh'; + const shellNotExec = '$files/is_not_executable.sh'; + + group('on shell scripts', () { + test('should return true for "is_executable.sh"', () async { + expect(await isExecutable(shellIsExec), isTrue); + }); + + test('should return false for "is_not_executable.sh"', () async { + expect(await isExecutable(shellNotExec), isFalse); + }); + }, testOn: '!windows'); + group('on shell scripts [windows]', () { + test('should always return true', () { + test('should return true for "is_executable.sh"', () async { + expect(await isExecutable(shellIsExec, isWindows: true), isTrue); + }); + + test('should return true for "is_not_executable.sh"', () async { + expect(await isExecutable(shellNotExec, isWindows: true), isTrue); + }); + }); + }); + }); +}