Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(198)

Side by Side Diff: utils/testrunner/pipeline_utils.dart

Issue 14247033: Updated testrunner: (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 7 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 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 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. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 part of pipeline; 5 part of pipeline;
6 6
7 List stdout, stderr, log; 7 List log;
8 var replyPort; 8 var replyPort;
9 int _procId = 1; 9 int _procId = 1;
10 Map _procs = {}; 10 Map _procs = {};
11 11
12 /** 12 /**
13 * Create a file path for a temporary file. The file will be in the 13 * Create a file path for a temporary file. The file will be in the
14 * [tmpDir] directory, with name [basis], but with any extension 14 * [tmpDir] directory, with name [basis], but with any extension
15 * stripped and replaced by [suffix]. 15 * stripped and replaced by [suffix].
16 */ 16 */
17 String createTempName(String tmpDir, String basis, String suffix) { 17 String createTempName(String tmpDir, String basis, [String suffix='']) {
18 var p = new Path(basis); 18 var p = new Path(basis);
19 return '$tmpDir${Platform.pathSeparator}' 19 return '$tmpDir${Platform.pathSeparator}'
20 '${p.filenameWithoutExtension}${suffix}'; 20 '${p.filenameWithoutExtension}${suffix}';
21 } 21 }
22 22
23 /** 23 /**
24 * Given a file path [file], make it absolute if it is relative, 24 * Given a file path [file], make it absolute if it is relative,
25 * and return the result as a [Path]. 25 * and return the result as a [Path].
26 */ 26 */
27 Path getAbsolutePath(String file) { 27 Path getAbsolutePath(String file) {
28 var p = new Path(file).canonicalize(); 28 var p = new Path(file).canonicalize();
29 if (p.isAbsolute) { 29 if (p.isAbsolute) {
30 return p; 30 return p;
31 } else { 31 } else {
32 var cwd = new Path((new Directory.current()).path); 32 var cwd = new Path((new Directory.current()).path);
33 return cwd.join(p); 33 return cwd.join(p);
34 } 34 }
35 } 35 }
36 36
37 /** Get the directory that contains a [file]. */ 37 /** Get the directory that contains a [file]. */
38 String getDirectory(String file) => 38 String getDirectory(String file) =>
39 getAbsolutePath(file).directoryPath.toString(); 39 getAbsolutePath(file).directoryPath.toString();
40 40
41 /** Create a file [fileName] and populate it with [contents]. */ 41 /** Create a file [fileName] and populate it with [contents]. */
42 void writeFile(String fileName, String contents) { 42 void writeFile(String fileName, String contents) {
43 var file = new File(fileName); 43 var file = new File(fileName);
44 var ostream = file.openOutputStream(FileMode.WRITE); 44 file.writeAsStringSync(contents);
45 ostream.writeString(contents);
46 ostream.close();
47 } 45 }
48 46
49 /* 47 /*
50 * Run an external process [cmd] with command line arguments [args]. 48 * Run an external process [cmd] with command line arguments [args].
51 * [timeout] can be used to forcefully terminate the process after 49 * [timeout] can be used to forcefully terminate the process after
52 * some number of seconds. This is used by runCommand and startProcess. 50 * some number of seconds. This is used by runCommand and startProcess.
53 * If [procId] is non-zero (i.e. called from startProcess) then a reference 51 * If [procId] is non-zero (i.e. called from startProcess) then a reference
54 * to the [Process] will be put in a map with key [procId]; in this case 52 * to the [Process] will be put in a map with key [procId]; in this case
55 * the process can be terminated later by calling [stopProcess] and 53 * the process can be terminated later by calling [stopProcess] and
56 * passing in the [procId]. 54 * passing in the [procId].
57 * [outputMonitor] is an optional function that will be called back with each 55 * [outputMonitor] is an optional function that will be called back with each
58 * line of output from the process. 56 * line of output from the process.
59 * Returns a [Future] for when the process terminates. 57 * Returns a [Future] for when the process terminates.
60 */ 58 */
61 Future _processHelper(String command, List<String> args, 59 Future _processHelper(String command, List<String> args,
Siggi Cherem (dart-lang) 2013/04/19 21:39:39 is this duplicate code with the other _processHelp
gram 2013/04/22 23:54:27 No, it is not a dup; it has some subtle difference
Siggi Cherem (dart-lang) 2013/04/23 01:10:04 I think you can use Future.wait instead, using str
gram 2013/04/23 22:53:40 Done.
62 [int timeout = 300, int procId = 0, Function outputMonitor]) { 60 List stdout, List stderr,
63 var completer = procId == 0 ? new Completer() : null; 61 [int timeout = 30, int procId = 0, Function outputMonitor]) {
62 var completer = procId == 0 ? (new Completer()) : null;
63 var timer = null;
64 if (Platform.operatingSystem == 'windows' && command.endsWith('.bat')) {
65 var oldArgs = args;
66 args = new List();
67 args.add('/k');
68 // TODO(gram): We may need some escaping here if any of the
69 // components contain spaces.
70 args.add("$command ${oldArgs.join(' ')}");
71 command='cmd.exe';
72 }
64 log.add('Running $command ${args.join(" ")}'); 73 log.add('Running $command ${args.join(" ")}');
65 var timer = null; 74 // We are not done until the process has exited and both the stdout
66 var stdoutHandler, stderrHandler; 75 // and stderr streams have drained; at that point we want to return
76 // the process exit code. We manage this with local state consisting
77 // of three flags and an int in a List.
78 // There is probably a better way to do this.
79 var doneState = [ false, false, false, 0 ];
67 var processFuture = Process.start(command, args); 80 var processFuture = Process.start(command, args);
68 processFuture.then((process) { 81 processFuture.then((process) {
69 _procs[procId] = process; 82 _procs[procId.toString()] = process;
70 83
71 timer = new Timer(new Duration(seconds: timeout), () { 84 timer = new Timer(new Duration(seconds: timeout), () {
72 timer = null; 85 timer = null;
73 process.kill(); 86 process.kill();
74 }); 87 });
75 88
76 process.onExit = (exitCode) { 89 process.exitCode.then((exitCode) {
77 if (timer != null) { 90 if (timer != null) {
78 timer.cancel(); 91 timer.cancel();
79 } 92 }
80 process.close();
81 if (completer != null) { 93 if (completer != null) {
82 completer.complete(exitCode); 94 doneState[3] = exitCode;
95 _checkComplete(doneState, 2, completer);
83 } 96 }
84 }; 97 });
85 98 _pipeStream(process.stdout, stdout, outputMonitor,
86 _pipeStream(process.stdout, stdout, outputMonitor); 99 doneState, 0, completer);
87 _pipeStream(process.stderr, stderr, outputMonitor); 100 _pipeStream(process.stderr, stderr, outputMonitor,
88 }); 101 doneState, 1, completer);
89 processFuture.handleException((e) { 102 })
103 .catchError((e) {
90 stderr.add("Error starting process:"); 104 stderr.add("Error starting process:");
91 stderr.add(" Command: $command"); 105 stderr.add(" Command: $command");
92 stderr.add(" Error: $e"); 106 stderr.add(" Error: ${e.error}");
93 completePipeline(-1); 107 completePipeline(stdout, stderr, -1);
94 return true;
95 }); 108 });
96 109
97 return completer.future; 110 return completer == null ? null : completer.future;
98 } 111 }
99 112
100 void _pipeStream(InputStream stream, List<String> destination, 113 void _checkComplete(List doneState, int index, Completer completer) {
101 Function outputMonitor) { 114 doneState[index] = true;
102 var source = new StringInputStream(stream); 115 if (completer != null && doneState[0] && doneState[1] && doneState[2]) {
103 source.onLine = () { 116 completer.complete(doneState[3]);
104 if (source.available() == 0) return; 117 }
105 var line = source.readLine(); 118 }
106 while (null != line) { 119
120 void _pipeStream(Stream stream, List<String> destination,
121 Function outputMonitor,
122 List doneState, int stateIndex, Completer completer) {
123 stream
124 .transform(new StringDecoder())
125 .transform(new LineTransformer())
126 .listen((String line) {
107 if (config["immediate"] && line.startsWith('###')) { 127 if (config["immediate"] && line.startsWith('###')) {
108 // TODO - when we dump the list later skip '###' messages if immediate.
109 print(line.substring(3)); 128 print(line.substring(3));
110 } 129 }
111 if (outputMonitor != null) { 130 if (outputMonitor != null) {
112 outputMonitor(line); 131 outputMonitor(line);
113 } 132 }
114 destination.add(line); 133 destination.add(line);
115 line = source.readLine(); 134 },
116 } 135 onDone: () {
117 }; 136 _checkComplete(doneState, stateIndex, completer);
137 });
118 } 138 }
119 139
120 /** 140 /**
121 * Run an external process [cmd] with command line arguments [args]. 141 * Run an external process [cmd] with command line arguments [args].
122 * [timeout] can be used to forcefully terminate the process after 142 * [timeout] can be used to forcefully terminate the process after
123 * some number of seconds. 143 * some number of seconds.
124 * Returns a [Future] for when the process terminates. 144 * Returns a [Future] for when the process terminates.
125 */ 145 */
126 Future runCommand(String command, List<String> args, 146 Future runCommand(String command, List<String> args,
127 [int timeout = 300, Function outputMonitor]) { 147 List stdout, List stderr,
128 return _processHelper(command, args, timeout, outputMonitor:outputMonitor); 148 [int timeout = 30, Function outputMonitor]) {
149 return _processHelper(command, args, stdout, stderr,
150 timeout, 0, outputMonitor);
129 } 151 }
130 152
131 /** 153 /**
132 * Start an external process [cmd] with command line arguments [args]. 154 * Start an external process [cmd] with command line arguments [args].
133 * Returns an ID by which it can later be stopped. 155 * Returns an ID by which it can later be stopped.
134 */ 156 */
135 int startProcess(String command, List<String> args, [Function outputMonitor]) { 157 int startProcess(String command, List<String> args, List stdout, List stderr,
158 [Function outputMonitor]) {
136 int id = _procId++; 159 int id = _procId++;
137 _processHelper(command, args, 3000, id, 160 var f = _processHelper(command, args, stdout, stderr, 3000, id,
138 outputMonitor:outputMonitor).then((e) { 161 outputMonitor);
139 _procs.remove(id); 162 if (f != null) {
140 }); 163 f.then((e) {
164 _procs.remove(id.toString());
165 });
166 }
141 return id; 167 return id;
142 } 168 }
143 169
144 /** Checks if a process is still running. */ 170 /** Checks if a process is still running. */
145 bool isProcessRunning(int id) { 171 bool isProcessRunning(int id) {
146 return _procs.containsKey(id); 172 return _procs.containsKey(id.toString());
147 } 173 }
148 174
149 /** 175 /**
150 * Stop a process previously started with [startProcess] or [runCommand], 176 * Stop a process previously started with [startProcess] or [runCommand],
151 * given the id string. 177 * given the id string.
152 */ 178 */
153 void stopProcess(int id) { 179 void stopProcess(int id) {
154 if (_procs.containsKey(id)) { 180 var sid = id.toString();
155 Process p = _procs.remove(id); 181 if (_procs.containsKey(sid)) {
182 Process p = _procs.remove(sid);
156 p.kill(); 183 p.kill();
157 } 184 }
158 } 185 }
159 186
160 /** Delete a file named [fname] if it exists. */ 187 /** Delete a file named [fname] if it exists. */
161 bool cleanup(String fname) { 188 bool cleanup(String fname) {
162 if (fname != null && !config['keep-files']) { 189 if (fname != null && config['clean-files']) {
163 var f = new File(fname); 190 var f = new File(fname);
164 try { 191 try {
165 if (f.existsSync()) { 192 if (f.existsSync()) {
166 logMessage('Removing $fname'); 193 logMessage('Removing $fname');
167 f.deleteSync(); 194 f.deleteSync();
168 } 195 }
169 } catch (e) { 196 } catch (e) {
170 return false; 197 return false;
171 } 198 }
172 } 199 }
173 return true; 200 return true;
174 } 201 }
175 202
203 /** Delete a directory named [dname] if it exists. */
204 bool cleanupDir(String dname) {
205 if (dname != null && config['clean-files']) {
206 var d = new Directory(dname);
207 try {
208 if (d.existsSync()) {
209 logMessage('Removing $dname');
210 d.deleteSync(recursive: true);
211 }
212 } catch (e) {
213 return false;
214 }
215 }
216 return true;
217 }
218
176 initPipeline(port) { 219 initPipeline(port) {
177 replyPort = port; 220 replyPort = port;
178 stdout = new List(); 221 stdout = new List();
179 stderr = new List(); 222 stderr = new List();
180 log = new List(); 223 log = new List();
181 } 224 }
182 225
183 void completePipeline([exitCode = 0]) { 226 void completePipeline(List stdout, List stderr, [exitCode = 0]) {
184 replyPort.send([stdout, stderr, log, exitCode]); 227 replyPort.send([stdout, stderr, log, exitCode]);
185 } 228 }
186 229
187 /** Utility function to log diagnostic messages. */ 230 /** Utility function to log diagnostic messages. */
188 void logMessage(msg) => log.add(msg); 231 void logMessage(msg) => log.add(msg);
232
233 /** Turn file paths into standard form with forward slashes. */
234 String normalizePath(String p) => (new Path(p)).toString();
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698