// Copyright 2013 The Flutter Authors. 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' as io; import 'package:meta/meta.dart'; import 'package:path/path.dart' as path; import 'environment.dart'; class FilePath { FilePath.fromCwd(String relativePath) : _absolutePath = path.absolute(relativePath); FilePath.fromWebUi(String relativePath) : _absolutePath = path.join(environment.webUiRootDir.path, relativePath); final String _absolutePath; String get absolute => _absolutePath; String get relativeToCwd => path.relative(_absolutePath); String get relativeToWebUi => path.relative(_absolutePath, from: environment.webUiRootDir.path); @override bool operator ==(dynamic other) { return other is FilePath && _absolutePath == other._absolutePath; } @override String toString() => _absolutePath; } /// Runs [executable] merging its output into the current process' standard out and standard error. Future runProcess( String executable, List arguments, { String workingDirectory, bool mustSucceed: false, }) async { final io.Process process = await io.Process.start( executable, arguments, workingDirectory: workingDirectory, mode: io.ProcessStartMode.inheritStdio, ); final int exitCode = await process.exitCode; if (mustSucceed && exitCode != 0) { throw ProcessException( description: 'Sub-process failed.', executable: executable, arguments: arguments, workingDirectory: workingDirectory, exitCode: exitCode, ); } return exitCode; } /// Runs [executable] and returns its standard output as a string. /// /// If the process fails, throws a [ProcessException]. Future evalProcess( String executable, List arguments, { String workingDirectory, }) async { final io.ProcessResult result = await io.Process.run( executable, arguments, workingDirectory: workingDirectory, ); if (result.exitCode != 0) { throw ProcessException( description: result.stderr, executable: executable, arguments: arguments, workingDirectory: workingDirectory, exitCode: result.exitCode, ); } return result.stdout; } @immutable class ProcessException implements Exception { ProcessException({ @required this.description, @required this.executable, @required this.arguments, @required this.workingDirectory, @required this.exitCode, }); final String description; final String executable; final List arguments; final String workingDirectory; final int exitCode; @override String toString() { final StringBuffer message = StringBuffer(); message ..writeln(description) ..writeln('Command: $executable ${arguments.join(' ')}') ..writeln('Working directory: ${workingDirectory ?? io.Directory.current.path}') ..writeln('Exit code: $exitCode'); return '$message'; } }