OLD | NEW |
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | |
2 // for details. All rights reserved. Use of this source code is governed by a | |
3 // BSD-style license that can be found in the LICENSE file. | |
4 | |
5 /// Helper functionality for invoking Git. | |
6 library pub.git; | 1 library pub.git; |
7 | |
8 import 'dart:async'; | 2 import 'dart:async'; |
9 import 'dart:io'; | 3 import 'dart:io'; |
10 | |
11 import 'package:stack_trace/stack_trace.dart'; | 4 import 'package:stack_trace/stack_trace.dart'; |
12 | |
13 import 'exceptions.dart'; | 5 import 'exceptions.dart'; |
14 import 'io.dart'; | 6 import 'io.dart'; |
15 import 'log.dart' as log; | 7 import 'log.dart' as log; |
16 import 'utils.dart'; | 8 import 'utils.dart'; |
17 | |
18 /// An exception thrown because a git command failed. | |
19 class GitException implements ApplicationException { | 9 class GitException implements ApplicationException { |
20 /// The arguments to the git command. | |
21 final List<String> args; | 10 final List<String> args; |
22 | |
23 /// The standard error emitted by git. | |
24 final String stderr; | 11 final String stderr; |
25 | |
26 String get message => 'Git error. Command: git ${args.join(" ")}\n$stderr'; | 12 String get message => 'Git error. Command: git ${args.join(" ")}\n$stderr'; |
27 | 13 GitException(Iterable<String> args, this.stderr) : args = args.toList(); |
28 GitException(Iterable<String> args, this.stderr) | |
29 : args = args.toList(); | |
30 | |
31 String toString() => message; | 14 String toString() => message; |
32 } | 15 } |
33 | |
34 /// Tests whether or not the git command-line app is available for use. | |
35 bool get isInstalled { | 16 bool get isInstalled { |
36 if (_isInstalledCache != null) return _isInstalledCache; | 17 if (_isInstalledCache != null) return _isInstalledCache; |
37 _isInstalledCache = _gitCommand != null; | 18 _isInstalledCache = _gitCommand != null; |
38 return _isInstalledCache; | 19 return _isInstalledCache; |
39 } | 20 } |
40 bool _isInstalledCache; | 21 bool _isInstalledCache; |
41 | 22 Future<List<String>> run(List<String> args, {String workingDir, Map<String, |
42 /// Run a git process with [args] from [workingDir]. | 23 String> environment}) { |
43 /// | |
44 /// Returns the stdout as a list of strings if it succeeded. Completes to an | |
45 /// exception if it failed. | |
46 Future<List<String>> run(List<String> args, | |
47 {String workingDir, Map<String, String> environment}) { | |
48 if (!isInstalled) { | 24 if (!isInstalled) { |
49 fail("Cannot find a Git executable.\n" | 25 fail( |
50 "Please ensure Git is correctly installed."); | 26 "Cannot find a Git executable.\n" "Please ensure Git is correctly instal
led."); |
51 } | 27 } |
52 | 28 return runProcess( |
53 return runProcess(_gitCommand, args, workingDir: workingDir, | 29 _gitCommand, |
| 30 args, |
| 31 workingDir: workingDir, |
54 environment: environment).then((result) { | 32 environment: environment).then((result) { |
55 if (!result.success) throw new GitException(args, result.stderr.join("\n")); | 33 if (!result.success) throw new GitException(args, result.stderr.join("\n")); |
56 return result.stdout; | 34 return result.stdout; |
57 }); | 35 }); |
58 } | 36 } |
59 | 37 List<String> runSync(List<String> args, {String workingDir, Map<String, |
60 /// Like [run], but synchronous. | 38 String> environment}) { |
61 List<String> runSync(List<String> args, {String workingDir, | |
62 Map<String, String> environment}) { | |
63 if (!isInstalled) { | 39 if (!isInstalled) { |
64 fail("Cannot find a Git executable.\n" | 40 fail( |
65 "Please ensure Git is correctly installed."); | 41 "Cannot find a Git executable.\n" "Please ensure Git is correctly instal
led."); |
66 } | 42 } |
67 | 43 var result = runProcessSync( |
68 var result = runProcessSync(_gitCommand, args, | 44 _gitCommand, |
| 45 args, |
69 workingDir: workingDir, | 46 workingDir: workingDir, |
70 environment: environment); | 47 environment: environment); |
71 if (!result.success) throw new GitException(args, result.stderr.join("\n")); | 48 if (!result.success) throw new GitException(args, result.stderr.join("\n")); |
72 return result.stdout; | 49 return result.stdout; |
73 } | 50 } |
74 | |
75 /// Returns the name of the git command-line app, or null if Git could not be | |
76 /// found on the user's PATH. | |
77 String get _gitCommand { | 51 String get _gitCommand { |
78 if (_commandCache != null) return _commandCache; | 52 if (_commandCache != null) return _commandCache; |
79 | |
80 var command; | 53 var command; |
81 if (_tryGitCommand("git")) { | 54 if (_tryGitCommand("git")) { |
82 _commandCache = "git"; | 55 _commandCache = "git"; |
83 } else if (_tryGitCommand("git.cmd")){ | 56 } else if (_tryGitCommand("git.cmd")) { |
84 _commandCache = "git.cmd"; | 57 _commandCache = "git.cmd"; |
85 } else { | 58 } else { |
86 return null; | 59 return null; |
87 } | 60 } |
88 | |
89 log.fine('Determined git command $command.'); | 61 log.fine('Determined git command $command.'); |
90 return _commandCache; | 62 return _commandCache; |
91 } | 63 } |
92 String _commandCache; | 64 String _commandCache; |
93 | |
94 /// Checks whether [command] is the Git command for this computer. | |
95 bool _tryGitCommand(String command) { | 65 bool _tryGitCommand(String command) { |
96 // If "git --version" prints something familiar, git is working. | |
97 try { | 66 try { |
98 var result = runProcessSync(command, ["--version"]); | 67 var result = runProcessSync(command, ["--version"]); |
99 var regexp = new RegExp("^git version"); | 68 var regexp = new RegExp("^git version"); |
100 return result.stdout.length == 1 && regexp.hasMatch(result.stdout.single); | 69 return result.stdout.length == 1 && regexp.hasMatch(result.stdout.single); |
101 } on ProcessException catch (error, stackTrace) { | 70 } on ProcessException catch (error, stackTrace) { |
102 var chain = new Chain.forTrace(stackTrace); | 71 var chain = new Chain.forTrace(stackTrace); |
103 // If the process failed, they probably don't have it. | |
104 log.message('Git command is not "$command": $error\n$chain'); | 72 log.message('Git command is not "$command": $error\n$chain'); |
105 return false; | 73 return false; |
106 } | 74 } |
107 } | 75 } |
OLD | NEW |