Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in
Toggle navigation
F
Front-End
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
abdullh.alsoleman
Front-End
Commits
81c7af34
Unverified
Commit
81c7af34
authored
Nov 06, 2018
by
Jonah Williams
Committed by
GitHub
Nov 06, 2018
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add fuchsia specific entrypoint (#23916)
parent
cf2fba7b
Changes
15
Show whitespace changes
Inline
Side-by-side
Showing
15 changed files
with
196 additions
and
623 deletions
+196
-623
BUILD.gn
packages/flutter_tools/BUILD.gn
+16
-0
fuchsia_tools.dart
packages/flutter_tools/bin/fuchsia_tools.dart
+9
-0
executable.dart
packages/flutter_tools/lib/executable.dart
+0
-2
fuchsia_executable.dart
packages/flutter_tools/lib/fuchsia_executable.dart
+74
-0
runner.dart
packages/flutter_tools/lib/runner.dart
+2
-1
artifacts.dart
packages/flutter_tools/lib/src/artifacts.dart
+5
-1
attach.dart
packages/flutter_tools/lib/src/commands/attach.dart
+3
-6
fuchsia_reload.dart
packages/flutter_tools/lib/src/commands/fuchsia_reload.dart
+0
-549
compile.dart
packages/flutter_tools/lib/src/compile.dart
+38
-2
context_runner.dart
packages/flutter_tools/lib/src/context_runner.dart
+1
-0
fuchsia_device.dart
packages/flutter_tools/lib/src/fuchsia/fuchsia_device.dart
+3
-3
fuchsia_sdk.dart
packages/flutter_tools/lib/src/fuchsia/fuchsia_sdk.dart
+26
-13
resident_runner.dart
packages/flutter_tools/lib/src/resident_runner.dart
+2
-0
flutter_command.dart
packages/flutter_tools/lib/src/runner/flutter_command.dart
+17
-0
fuchsia_reload_test.dart
...ages/flutter_tools/test/commands/fuchsia_reload_test.dart
+0
-46
No files found.
packages/flutter_tools/BUILD.gn
View file @
81c7af34
...
...
@@ -236,3 +236,19 @@ dart_tool("fuchsia_tester") {
"$flutter_root/shell",
]
}
dart_tool("fuchsia_tools") {
package_name = "fuchsia_tools"
main_dart = "bin/fuchsia_tools.dart"
# Can be left empty as analysis is disabled.
sources = []
disable_analysis = true
deps = [
":flutter_tools",
]
# TODO(jonahwilliams): add a frontend_server as a non dart dep.
}
packages/flutter_tools/bin/fuchsia_tools.dart
0 → 100644
View file @
81c7af34
// Copyright 2018 The Chromium 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
'package:flutter_tools/fuchsia_executable.dart'
as
executable
;
void
main
(
List
<
String
>
args
)
{
executable
.
main
(
args
);
}
packages/flutter_tools/lib/executable.dart
View file @
81c7af34
...
...
@@ -18,7 +18,6 @@ import 'src/commands/doctor.dart';
import
'src/commands/drive.dart'
;
import
'src/commands/emulators.dart'
;
import
'src/commands/format.dart'
;
import
'src/commands/fuchsia_reload.dart'
;
import
'src/commands/ide_config.dart'
;
import
'src/commands/inject_plugins.dart'
;
import
'src/commands/install.dart'
;
...
...
@@ -63,7 +62,6 @@ Future<void> main(List<String> args) async {
DriveCommand
(),
EmulatorsCommand
(),
FormatCommand
(),
FuchsiaReloadCommand
(),
IdeConfigCommand
(
hidden:
!
verboseHelp
),
InjectPluginsCommand
(
hidden:
!
verboseHelp
),
InstallCommand
(),
...
...
packages/flutter_tools/lib/fuchsia_executable.dart
0 → 100644
View file @
81c7af34
// Copyright 2018 The Chromium 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
'package:args/args.dart'
;
import
'runner.dart'
as
runner
;
import
'src/artifacts.dart'
;
import
'src/base/common.dart'
;
import
'src/base/context.dart'
;
import
'src/base/file_system.dart'
;
import
'src/commands/attach.dart'
;
import
'src/commands/devices.dart'
;
import
'src/commands/shell_completion.dart'
;
import
'src/fuchsia/fuchsia_sdk.dart'
;
import
'src/runner/flutter_command.dart'
;
final
ArgParser
parser
=
ArgParser
.
allowAnything
()
..
addOption
(
'verbose'
,
abbr:
'v'
)
..
addOption
(
'help'
,
abbr:
'h'
)
..
addOption
(
'frontend-server'
,
help:
'The path to the frontend server snapshot.'
,
)
..
addOption
(
'dart-sdk'
,
help:
'The path to the patched dart-sdk binary.'
,
)
..
addOption
(
'ssh-config'
,
help:
'The path to the ssh configuration file.'
,
);
/// Main entry point for fuchsia commands.
///
/// This function is intended to be used within the fuchsia source tree.
Future
<
void
>
main
(
List
<
String
>
args
)
async
{
final
ArgResults
results
=
parser
.
parse
(
args
);
final
bool
verbose
=
results
[
'verbose'
];
final
bool
help
=
results
[
'help'
];
final
bool
verboseHelp
=
help
&&
verbose
;
final
File
dartSdk
=
fs
.
file
(
results
[
'dart-sdk'
]);
final
File
frontendServer
=
fs
.
file
(
results
[
'frontend-server'
]);
final
File
sshConfig
=
fs
.
file
(
results
[
'ssh-config'
]);
if
(!
dartSdk
.
existsSync
())
{
throwToolExit
(
'--dart-sdk is required:
${dartSdk.path}
does not exist.'
);
}
if
(!
frontendServer
.
existsSync
())
{
throwToolExit
(
'--frontend-server is required:
${frontendServer.path}
does not exist.'
);
}
if
(!
sshConfig
.
existsSync
())
{
throwToolExit
(
'--ssh-config is required:
${sshConfig.path}
does not exist.'
);
}
await
runner
.
run
(
args
,
<
FlutterCommand
>[
AttachCommand
(
verboseHelp:
verboseHelp
),
DevicesCommand
(),
ShellCompletionCommand
(),
],
verbose:
verbose
,
muteCommandLogging:
help
,
verboseHelp:
verboseHelp
,
overrides:
<
Type
,
Generator
>{
FuchsiaArtifacts:
()
=>
FuchsiaArtifacts
(
sshConfig:
sshConfig
),
Artifacts:
()
=>
OverrideArtifacts
(
parent:
CachedArtifacts
(),
frontendServer:
frontendServer
,
engineDartBinary:
dartSdk
,
)
});
}
packages/flutter_tools/lib/runner.dart
View file @
81c7af34
...
...
@@ -34,6 +34,7 @@ Future<int> run(
bool
verboseHelp
=
false
,
bool
reportCrashes
,
String
flutterVersion
,
Map
<
Type
,
Generator
>
overrides
,
})
{
reportCrashes
??=
!
isRunningOnBot
;
...
...
@@ -63,7 +64,7 @@ Future<int> run(
return
await
_handleToolError
(
error
,
stackTrace
,
verbose
,
args
,
reportCrashes
,
getVersion
);
}
return
0
;
});
}
,
overrides:
overrides
);
}
Future
<
int
>
_handleToolError
(
...
...
packages/flutter_tools/lib/src/artifacts.dart
View file @
81c7af34
...
...
@@ -303,7 +303,6 @@ class LocalEngineArtifacts extends Artifacts {
/// An implementation of [Artifacts] that provides individual overrides.
///
/// If an artifact is not provided, the lookup delegates to the parent.
/// Currently only allows overriding the location of the [frontendServer].
class
OverrideArtifacts
implements
Artifacts
{
/// Creates a new [OverrideArtifacts].
///
...
...
@@ -311,16 +310,21 @@ class OverrideArtifacts implements Artifacts {
OverrideArtifacts
({
@required
this
.
parent
,
this
.
frontendServer
,
this
.
engineDartBinary
,
})
:
assert
(
parent
!=
null
);
final
Artifacts
parent
;
final
File
frontendServer
;
final
File
engineDartBinary
;
@override
String
getArtifactPath
(
Artifact
artifact
,
[
TargetPlatform
platform
,
BuildMode
mode
])
{
if
(
artifact
==
Artifact
.
frontendServerSnapshotForEngineDartSdk
&&
frontendServer
!=
null
)
{
return
frontendServer
.
path
;
}
if
(
artifact
==
Artifact
.
engineDartBinary
&&
engineDartBinary
!=
null
)
{
return
engineDartBinary
.
path
;
}
return
parent
.
getArtifactPath
(
artifact
,
platform
,
mode
);
}
...
...
packages/flutter_tools/lib/src/commands/attach.dart
View file @
81c7af34
...
...
@@ -11,6 +11,7 @@ import '../base/logger.dart';
import
'../base/utils.dart'
;
import
'../cache.dart'
;
import
'../commands/daemon.dart'
;
import
'../compile.dart'
;
import
'../device.dart'
;
import
'../fuchsia/fuchsia_device.dart'
;
import
'../globals.dart'
;
...
...
@@ -48,6 +49,7 @@ class AttachCommand extends FlutterCommand {
usesIsolateFilterOption
(
hide:
!
verboseHelp
);
usesTargetOption
();
usesFilesystemOptions
(
hide:
!
verboseHelp
);
usesFuchsiaOptions
(
hide:
!
verboseHelp
);
argParser
..
addOption
(
'debug-port'
,
...
...
@@ -60,12 +62,6 @@ class AttachCommand extends FlutterCommand {
'project-root'
,
hide:
!
verboseHelp
,
help:
'Normally used only in run target'
,
)..
addOption
(
'module'
,
abbr:
'm'
,
hide:
!
verboseHelp
,
help:
'The name of the module (required if attaching to a fuchsia device)'
,
valueHelp:
'module-name'
,
)..
addFlag
(
'machine'
,
hide:
!
verboseHelp
,
negatable:
false
,
...
...
@@ -180,6 +176,7 @@ class AttachCommand extends FlutterCommand {
fileSystemRoots:
argResults
[
'filesystem-root'
],
fileSystemScheme:
argResults
[
'filesystem-scheme'
],
viewFilter:
argResults
[
'isolate-filter'
],
targetModel:
TargetModel
(
argResults
[
'target-model'
]),
);
flutterDevice
.
observatoryUris
=
<
Uri
>[
observatoryUri
];
final
HotRunner
hotRunner
=
hotRunnerFactory
.
build
(
...
...
packages/flutter_tools/lib/src/commands/fuchsia_reload.dart
deleted
100644 → 0
View file @
cf2fba7b
// Copyright 2017 The Chromium 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:collection'
;
import
'dart:convert'
;
import
'../artifacts.dart'
;
import
'../base/common.dart'
;
import
'../base/context.dart'
;
import
'../base/file_system.dart'
;
import
'../base/io.dart'
;
import
'../base/process_manager.dart'
;
import
'../base/terminal.dart'
;
import
'../base/utils.dart'
;
import
'../bundle.dart'
as
bundle
;
import
'../cache.dart'
;
import
'../context_runner.dart'
;
import
'../device.dart'
;
import
'../fuchsia/fuchsia_device.dart'
;
import
'../globals.dart'
;
import
'../resident_runner.dart'
;
import
'../run_hot.dart'
;
import
'../runner/flutter_command.dart'
;
import
'../vmservice.dart'
;
// Usage:
// With e.g. hello_mod already running, a HotRunner can be attached to it.
//
// From a Fuchsia in-tree build:
// $ flutter fuchsia_reload --address 192.168.1.39 \
// --build-dir ~/fuchsia/out/x64 \
// --gn-target //topaz/examples/ui/hello_mod:hello_mod
//
// From out of tree:
// $ flutter fuchsia_reload --address 192.168.1.39 \
// --mod_name hello_mod \
// --path /path/to/hello_mod
// --dot-packages /path/to/hello_mod_out/app.packages \
// --ssh-config /path/to/ssh_config \
// --target /path/to/hello_mod/lib/main.dart
final
String
ipv4Loopback
=
InternetAddress
.
loopbackIPv4
.
address
;
class
FuchsiaReloadCommand
extends
FlutterCommand
{
FuchsiaReloadCommand
()
{
addBuildModeFlags
(
defaultToRelease:
false
);
argParser
.
addOption
(
'frontend-server'
,
abbr:
'f'
,
help:
'The frontend server location'
);
argParser
.
addOption
(
'address'
,
abbr:
'a'
,
help:
'Fuchsia device network name or address.'
);
argParser
.
addOption
(
'build-dir'
,
abbr:
'b'
,
defaultsTo:
null
,
help:
'Fuchsia build directory, e.g. out/release-x86-64.'
);
argParser
.
addOption
(
'dot-packages'
,
abbr:
'd'
,
defaultsTo:
null
,
help:
'Path to the mod
\'
s .packages file. Required if no'
'GN target specified.'
);
argParser
.
addOption
(
'gn-target'
,
abbr:
'g'
,
help:
'GN target of the application, e.g //path/to/app:app.'
);
argParser
.
addOption
(
'isolate-number'
,
abbr:
'i'
,
help:
'To reload only one instance, specify the isolate number, e.g. '
'the number in foo
\
$main
-###### given by --list.'
);
argParser
.
addFlag
(
'list'
,
abbr:
'l'
,
defaultsTo:
false
,
help:
'Lists the running modules. '
);
argParser
.
addOption
(
'mod-name'
,
abbr:
'm'
,
help:
'Name of the flutter mod. If used with -g, overrides the name '
'inferred from the GN target.'
);
argParser
.
addOption
(
'path'
,
abbr:
'p'
,
defaultsTo:
null
,
help:
'Path to the flutter mod project.'
);
argParser
.
addOption
(
'ssh-config'
,
abbr:
's'
,
defaultsTo:
null
,
help:
'Path to the Fuchsia target
\'
s ssh config file.'
);
argParser
.
addOption
(
'target'
,
abbr:
't'
,
defaultsTo:
bundle
.
defaultMainPath
,
help:
'Target app path / main entry-point file. '
'Relative to --path or --gn-target path, e.g. lib/main.dart.'
);
}
@override
final
String
name
=
'fuchsia_reload'
;
@override
final
String
description
=
'Hot reload on Fuchsia.'
;
String
_modName
;
String
_isolateNumber
;
String
_fuchsiaProjectPath
;
String
_target
;
String
_address
;
String
_dotPackagesPath
;
String
_sshConfig
;
File
_frontendServerSnapshot
;
bool
_list
;
@override
Future
<
FlutterCommandResult
>
runCommand
()
async
{
Cache
.
releaseLockEarly
();
await
_validateArguments
();
await
runInContext
<
void
>(()
async
{
// Find the network ports used on the device by VM service instances.
final
List
<
int
>
deviceServicePorts
=
await
_getServicePorts
();
if
(
deviceServicePorts
.
isEmpty
)
throwToolExit
(
'Couldn
\'
t find any running Observatory instances.'
);
for
(
int
port
in
deviceServicePorts
)
printTrace
(
'Fuchsia service port:
$port
'
);
// Set up ssh tunnels to forward the device ports to local ports.
final
List
<
_PortForwarder
>
forwardedPorts
=
await
_forwardPorts
(
deviceServicePorts
);
// Wrap everything in try/finally to make sure we kill the ssh processes
// doing the port forwarding.
try
{
final
List
<
int
>
servicePorts
=
forwardedPorts
.
map
<
int
>((
_PortForwarder
pf
)
=>
pf
.
port
).
toList
();
if
(
_list
)
{
await
_listVMs
(
servicePorts
);
// Port forwarding stops when the command ends. Keep the program running
// until directed by the user so that Observatory URLs that we print
// continue to work.
printStatus
(
'Press Enter to exit.'
);
await
stdin
.
first
;
return
null
;
}
// Check that there are running VM services on the returned
// ports, and find the Isolates that are running the target app.
final
String
isolateName
=
'
$_modName
\
$main$_isolateNumber
'
;
final
List
<
int
>
targetPorts
=
await
_filterPorts
(
servicePorts
,
isolateName
);
if
(
targetPorts
.
isEmpty
)
throwToolExit
(
'No VMs found running
$_modName
.'
);
for
(
int
port
in
targetPorts
)
printTrace
(
'Found
$_modName
at
$port
'
);
// Set up a device and hot runner and attach the hot runner to the first
// vm service we found.
final
List
<
String
>
fullAddresses
=
targetPorts
.
map
<
String
>((
int
p
)
=>
'
$ipv4Loopback
:
$p
'
).
toList
();
final
List
<
Uri
>
observatoryUris
=
fullAddresses
.
map
<
Uri
>((
String
a
)
=>
Uri
.
parse
(
'http://
$a
'
))
.
toList
();
final
FuchsiaDevice
device
=
FuchsiaDevice
(
fullAddresses
[
0
],
name:
_address
);
final
FlutterDevice
flutterDevice
=
FlutterDevice
(
device
,
trackWidgetCreation:
false
,
viewFilter:
isolateName
,
);
flutterDevice
.
observatoryUris
=
observatoryUris
;
final
HotRunner
hotRunner
=
HotRunner
(<
FlutterDevice
>[
flutterDevice
],
debuggingOptions:
DebuggingOptions
.
enabled
(
getBuildInfo
()),
target:
_target
,
projectRootPath:
_fuchsiaProjectPath
,
packagesFilePath:
_dotPackagesPath
,
);
printStatus
(
'Connecting to
$_modName
'
);
await
hotRunner
.
attach
();
}
finally
{
await
Future
.
wait
<
void
>(
forwardedPorts
.
map
<
Future
<
void
>>((
_PortForwarder
pf
)
=>
pf
.
stop
()));
}
},
overrides:
<
Type
,
Generator
>{
Artifacts:
()
=>
OverrideArtifacts
(
parent:
artifacts
,
frontendServer:
_frontendServerSnapshot
),
});
return
null
;
}
// A cache of VMService connections.
final
HashMap
<
int
,
VMService
>
_vmServiceCache
=
HashMap
<
int
,
VMService
>();
Future
<
VMService
>
_getVMService
(
int
port
)
async
{
if
(!
_vmServiceCache
.
containsKey
(
port
))
{
final
String
addr
=
'http://
$ipv4Loopback
:
$port
'
;
final
Uri
uri
=
Uri
.
parse
(
addr
);
final
VMService
vmService
=
await
VMService
.
connect
(
uri
);
_vmServiceCache
[
port
]
=
vmService
;
}
return
_vmServiceCache
[
port
];
}
Future
<
List
<
FlutterView
>>
_getViews
(
List
<
int
>
ports
)
async
{
final
List
<
FlutterView
>
views
=
<
FlutterView
>[];
for
(
int
port
in
ports
)
{
final
VMService
vmService
=
await
_getVMService
(
port
);
await
vmService
.
getVM
();
await
vmService
.
refreshViews
();
views
.
addAll
(
vmService
.
vm
.
views
);
}
return
views
;
}
// Find ports where there is a view isolate with the given name
Future
<
List
<
int
>>
_filterPorts
(
List
<
int
>
ports
,
String
viewFilter
)
async
{
printTrace
(
'Looing for view
$viewFilter
'
);
final
List
<
int
>
result
=
<
int
>[];
for
(
FlutterView
v
in
await
_getViews
(
ports
))
{
if
(
v
.
uiIsolate
==
null
)
continue
;
final
Uri
addr
=
v
.
owner
.
vmService
.
httpAddress
;
printTrace
(
'At
$addr
, found view:
${v.uiIsolate.name}
'
);
if
(
v
.
uiIsolate
.
name
.
contains
(
viewFilter
))
result
.
add
(
addr
.
port
);
}
return
result
;
}
String
_vmServiceToString
(
VMService
vmService
,
{
int
tabDepth
=
0
})
{
final
Uri
addr
=
vmService
.
httpAddress
;
final
String
embedder
=
vmService
.
vm
.
embedder
;
final
int
numIsolates
=
vmService
.
vm
.
isolates
.
length
;
final
String
maxRSS
=
getSizeAsMB
(
vmService
.
vm
.
maxRSS
);
final
String
heapSize
=
getSizeAsMB
(
vmService
.
vm
.
heapAllocatedMemoryUsage
);
int
totalNewUsed
=
0
;
int
totalNewCap
=
0
;
int
totalOldUsed
=
0
;
int
totalOldCap
=
0
;
int
totalExternal
=
0
;
for
(
Isolate
i
in
vmService
.
vm
.
isolates
)
{
totalNewUsed
+=
i
.
newSpace
.
used
;
totalNewCap
+=
i
.
newSpace
.
capacity
;
totalOldUsed
+=
i
.
oldSpace
.
used
;
totalOldCap
+=
i
.
oldSpace
.
capacity
;
totalExternal
+=
i
.
newSpace
.
external
;
totalExternal
+=
i
.
oldSpace
.
external
;
}
final
String
newUsed
=
getSizeAsMB
(
totalNewUsed
);
final
String
newCap
=
getSizeAsMB
(
totalNewCap
);
final
String
oldUsed
=
getSizeAsMB
(
totalOldUsed
);
final
String
oldCap
=
getSizeAsMB
(
totalOldCap
);
final
String
external
=
getSizeAsMB
(
totalExternal
);
final
String
tabs
=
'
\t
'
*
tabDepth
;
final
String
extraTabs
=
'
\t
'
*
(
tabDepth
+
1
);
final
StringBuffer
stringBuffer
=
StringBuffer
(
'
$tabs${terminal.bolden('$embedder at $addr')}
\n
'
'
${extraTabs}
RSS:
$maxRSS
\n
'
'
${extraTabs}
Native allocations:
$heapSize
\n
'
'
${extraTabs}
New Spaces:
$newUsed
of
$newCap
\n
'
'
${extraTabs}
Old Spaces:
$oldUsed
of
$oldCap
\n
'
'
${extraTabs}
External:
$external
\n
'
'
${extraTabs}
Isolates:
$numIsolates
\n
'
);
for
(
Isolate
isolate
in
vmService
.
vm
.
isolates
)
{
stringBuffer
.
write
(
_isolateToString
(
isolate
,
tabDepth:
tabDepth
+
1
));
}
return
stringBuffer
.
toString
();
}
String
_isolateToString
(
Isolate
isolate
,
{
int
tabDepth
=
0
})
{
final
Uri
vmServiceAddr
=
isolate
.
owner
.
vmService
.
httpAddress
;
final
String
name
=
isolate
.
name
;
final
String
shortName
=
name
.
substring
(
0
,
name
.
indexOf
(
'
\$
'
));
const
String
main
=
'
\
$main
-'
;
final
String
number
=
name
.
substring
(
name
.
indexOf
(
main
)
+
main
.
length
);
// The Observatory requires somewhat non-standard URIs that the Uri class
// can't build for us, so instead we build them by hand.
final
String
isolateIdQuery
=
'?isolateId=isolates%2F
$number
'
;
final
String
isolateAddr
=
'
$vmServiceAddr
/#/inspect
$isolateIdQuery
'
;
final
String
debuggerAddr
=
'
$vmServiceAddr
/#/debugger
$isolateIdQuery
'
;
final
String
newUsed
=
getSizeAsMB
(
isolate
.
newSpace
.
used
);
final
String
newCap
=
getSizeAsMB
(
isolate
.
newSpace
.
capacity
);
final
String
newFreq
=
'
${isolate.newSpace.avgCollectionTime.inMilliseconds}
ms'
;
final
String
newPer
=
'
${isolate.newSpace.avgCollectionPeriod.inSeconds}
s'
;
final
String
oldUsed
=
getSizeAsMB
(
isolate
.
oldSpace
.
used
);
final
String
oldCap
=
getSizeAsMB
(
isolate
.
oldSpace
.
capacity
);
final
String
oldFreq
=
'
${isolate.oldSpace.avgCollectionTime.inMilliseconds}
ms'
;
final
String
oldPer
=
'
${isolate.oldSpace.avgCollectionPeriod.inSeconds}
s'
;
final
String
external
=
getSizeAsMB
(
isolate
.
newSpace
.
external
+
isolate
.
oldSpace
.
external
);
final
String
tabs
=
'
\t
'
*
tabDepth
;
final
String
extraTabs
=
'
\t
'
*
(
tabDepth
+
1
);
return
'
$tabs${terminal.bolden(shortName)}
\n
'
'
${extraTabs}
Isolate number:
$number
\n
'
'
${extraTabs}
Observatory:
$isolateAddr
\n
'
'
${extraTabs}
Debugger:
$debuggerAddr
\n
'
'
${extraTabs}
New gen:
$newUsed
used of
$newCap
, GC:
$newFreq
every
$newPer
\n
'
'
${extraTabs}
Old gen:
$oldUsed
used of
$oldCap
, GC:
$oldFreq
every
$oldPer
\n
'
'
${extraTabs}
External:
$external
\n
'
;
}
Future
<
void
>
_listVMs
(
List
<
int
>
ports
)
async
{
for
(
int
port
in
ports
)
{
final
VMService
vmService
=
await
_getVMService
(
port
);
await
vmService
.
getVM
();
await
vmService
.
refreshViews
();
printStatus
(
_vmServiceToString
(
vmService
));
}
}
Future
<
void
>
_validateArguments
()
async
{
final
String
fuchsiaBuildDir
=
argResults
[
'build-dir'
];
final
String
gnTarget
=
argResults
[
'gn-target'
];
_frontendServerSnapshot
=
fs
.
file
(
argResults
[
'frontend-server'
]);
if
(!
_frontendServerSnapshot
.
existsSync
())
{
throwToolExit
(
'Must provide a frontend-server snapshot'
);
}
if
(
fuchsiaBuildDir
!=
null
)
{
if
(
gnTarget
==
null
)
throwToolExit
(
'Must provide --gn-target when specifying --build-dir.'
);
if
(!
_directoryExists
(
fuchsiaBuildDir
))
throwToolExit
(
'Specified --build-dir "
$fuchsiaBuildDir
" does not exist.'
);
_sshConfig
=
'
$fuchsiaBuildDir
/ssh-keys/ssh_config'
;
}
// If sshConfig path not available from the fuchsiaBuildDir, get from command line.
_sshConfig
??=
argResults
[
'ssh-config'
];
if
(
_sshConfig
==
null
)
throwToolExit
(
'Provide the path to the ssh config file with --ssh-config.'
);
if
(!
_fileExists
(
_sshConfig
))
throwToolExit
(
'Couldn
\'
t find ssh config file at
$_sshConfig
.'
);
_address
=
argResults
[
'address'
];
if
(
_address
==
null
&&
fuchsiaBuildDir
!=
null
)
{
final
ProcessResult
result
=
await
processManager
.
run
(<
String
>[
'fx'
,
'netaddr'
,
'--fuchsia'
]);
if
(
result
.
exitCode
==
0
)
_address
=
result
.
stdout
.
trim
();
else
printStatus
(
'netaddr failed:
\n
stdout:
${result.stdout}
\n
stderr:
${result.stderr}
'
);
}
if
(
_address
==
null
)
throwToolExit
(
'Give the address of the device running Fuchsia with --address.'
);
_list
=
argResults
[
'list'
];
if
(
_list
)
{
// For --list, we only need the ssh config and device address.
return
;
}
String
projectRoot
;
if
(
gnTarget
!=
null
)
{
if
(
fuchsiaBuildDir
==
null
)
throwToolExit
(
'Must provide --build-dir when specifying --gn-target.'
);
final
List
<
String
>
targetInfo
=
_extractPathAndName
(
gnTarget
);
projectRoot
=
targetInfo
[
0
];
_modName
=
targetInfo
[
1
];
_fuchsiaProjectPath
=
'
$fuchsiaBuildDir
/../../
$projectRoot
'
;
}
else
if
(
argResults
[
'path'
]
!=
null
)
{
_fuchsiaProjectPath
=
argResults
[
'path'
];
}
if
(
_fuchsiaProjectPath
==
null
)
throwToolExit
(
'Provide the mod project path with --path.'
);
if
(!
_directoryExists
(
_fuchsiaProjectPath
))
throwToolExit
(
'Cannot locate project at
$_fuchsiaProjectPath
.'
);
final
String
relativeTarget
=
argResults
[
'target'
];
if
(
relativeTarget
==
null
)
throwToolExit
(
'Give the application entry point with --target.'
);
_target
=
'
$_fuchsiaProjectPath
/
$relativeTarget
'
;
if
(!
_fileExists
(
_target
))
throwToolExit
(
'Couldn
\'
t find application entry point at
$_target
.'
);
if
(
argResults
[
'mod-name'
]
!=
null
)
_modName
=
argResults
[
'mod-name'
];
if
(
_modName
==
null
)
throwToolExit
(
'Provide the mod name with --mod-name.'
);
if
(
argResults
[
'dot-packages'
]
!=
null
)
{
_dotPackagesPath
=
argResults
[
'dot-packages'
];
}
else
if
(
fuchsiaBuildDir
!=
null
)
{
final
String
packagesFileName
=
'
${_modName}
_dart_library.packages'
;
_dotPackagesPath
=
'
$fuchsiaBuildDir
/dartlang/gen/
$projectRoot
/
$packagesFileName
'
;
}
if
(
_dotPackagesPath
==
null
)
throwToolExit
(
'Provide the .packages path with --dot-packages.'
);
if
(!
_fileExists
(
_dotPackagesPath
))
throwToolExit
(
'Couldn
\'
t find .packages file at
$_dotPackagesPath
.'
);
final
String
isolateNumber
=
argResults
[
'isolate-number'
];
if
(
isolateNumber
==
null
)
{
_isolateNumber
=
''
;
}
else
{
_isolateNumber
=
'-
$isolateNumber
'
;
}
}
List
<
String
>
_extractPathAndName
(
String
gnTarget
)
{
final
String
errorMessage
=
'fuchsia_reload --target "
$gnTarget
" should have the form: '
'"//path/to/app:name"'
;
// Separate strings like //path/to/target:app into [path/to/target, app]
final
int
lastColon
=
gnTarget
.
lastIndexOf
(
':'
);
if
(
lastColon
<
0
)
throwToolExit
(
errorMessage
);
final
String
name
=
gnTarget
.
substring
(
lastColon
+
1
);
// Skip '//' and chop off after :
if
((
gnTarget
.
length
<
3
)
||
(
gnTarget
[
0
]
!=
'/'
)
||
(
gnTarget
[
1
]
!=
'/'
))
throwToolExit
(
errorMessage
);
final
String
path
=
gnTarget
.
substring
(
2
,
lastColon
);
return
<
String
>[
path
,
name
];
}
Future
<
List
<
_PortForwarder
>>
_forwardPorts
(
List
<
int
>
remotePorts
)
async
{
final
List
<
_PortForwarder
>
forwarders
=
<
_PortForwarder
>[];
for
(
int
port
in
remotePorts
)
{
final
_PortForwarder
f
=
await
_PortForwarder
.
start
(
_sshConfig
,
_address
,
port
);
forwarders
.
add
(
f
);
}
return
forwarders
;
}
Future
<
List
<
int
>>
_getServicePorts
()
async
{
final
FuchsiaDeviceCommandRunner
runner
=
FuchsiaDeviceCommandRunner
(
_address
,
_sshConfig
);
final
List
<
String
>
lsOutput
=
await
runner
.
run
(
'ls /tmp/dart.services'
);
final
List
<
int
>
ports
=
<
int
>[];
if
(
lsOutput
!=
null
)
{
for
(
String
s
in
lsOutput
)
{
final
String
trimmed
=
s
.
trim
();
final
int
lastSpace
=
trimmed
.
lastIndexOf
(
' '
);
final
String
lastWord
=
trimmed
.
substring
(
lastSpace
+
1
);
if
((
lastWord
!=
'.'
)
&&
(
lastWord
!=
'..'
))
{
final
int
value
=
int
.
tryParse
(
lastWord
);
if
(
value
!=
null
)
ports
.
add
(
value
);
}
}
}
return
ports
;
}
bool
_directoryExists
(
String
path
)
{
final
Directory
d
=
fs
.
directory
(
path
);
return
d
.
existsSync
();
}
bool
_fileExists
(
String
path
)
{
final
File
f
=
fs
.
file
(
path
);
return
f
.
existsSync
();
}
}
// Instances of this class represent a running ssh tunnel from the host to a
// VM service running on a Fuchsia device. [process] is the ssh process running
// the tunnel and [port] is the local port.
class
_PortForwarder
{
_PortForwarder
.
_
(
this
.
_remoteAddress
,
this
.
_remotePort
,
this
.
_localPort
,
this
.
_process
,
this
.
_sshConfig
);
final
String
_remoteAddress
;
final
int
_remotePort
;
final
int
_localPort
;
final
Process
_process
;
final
String
_sshConfig
;
int
get
port
=>
_localPort
;
static
Future
<
_PortForwarder
>
start
(
String
sshConfig
,
String
address
,
int
remotePort
)
async
{
final
int
localPort
=
await
_potentiallyAvailablePort
();
if
(
localPort
==
0
)
{
printStatus
(
'_PortForwarder failed to find a local port for
$address
:
$remotePort
'
);
return
_PortForwarder
.
_
(
null
,
0
,
0
,
null
,
null
);
}
const
String
dummyRemoteCommand
=
'date'
;
final
List
<
String
>
command
=
<
String
>[
'ssh'
,
'-F'
,
sshConfig
,
'-nNT'
,
'-vvv'
,
'-f'
,
'-L'
,
'
$localPort
:
$ipv4Loopback
:
$remotePort
'
,
address
,
dummyRemoteCommand
];
printTrace
(
"_PortForwarder running '
${command.join(' ')}
'"
);
final
Process
process
=
await
processManager
.
start
(
command
);
process
.
stderr
.
transform
<
String
>(
utf8
.
decoder
)
.
transform
<
String
>(
const
LineSplitter
())
.
listen
((
String
data
)
{
printTrace
(
data
);
});
// Best effort to print the exit code.
process
.
exitCode
.
then
<
void
>((
int
c
)
{
// ignore: unawaited_futures
printTrace
(
"'
${command.join(' ')}
' exited with exit code
$c
"
);
});
printTrace
(
'Set up forwarding from
$localPort
to
$address
:
$remotePort
'
);
return
_PortForwarder
.
_
(
address
,
remotePort
,
localPort
,
process
,
sshConfig
);
}
Future
<
void
>
stop
()
async
{
// Kill the original ssh process if it is still around.
if
(
_process
!=
null
)
{
printTrace
(
'_PortForwarder killing
${_process.pid}
for port
$_localPort
'
);
_process
.
kill
();
}
// Cancel the forwarding request.
final
List
<
String
>
command
=
<
String
>[
'ssh'
,
'-F'
,
_sshConfig
,
'-O'
,
'cancel'
,
'-vvv'
,
'-L'
,
'
$_localPort
:
$ipv4Loopback
:
$_remotePort
'
,
_remoteAddress
];
final
ProcessResult
result
=
await
processManager
.
run
(
command
);
printTrace
(
command
.
join
(
' '
));
if
(
result
.
exitCode
!=
0
)
{
printTrace
(
'Command failed:
\n
stdout:
${result.stdout}
\n
stderr:
${result.stderr}
'
);
}
}
static
Future
<
int
>
_potentiallyAvailablePort
()
async
{
int
port
=
0
;
ServerSocket
s
;
try
{
s
=
await
ServerSocket
.
bind
(
ipv4Loopback
,
0
);
port
=
s
.
port
;
}
catch
(
e
)
{
// Failures are signaled by a return value of 0 from this function.
printTrace
(
'_potentiallyAvailablePort failed:
$e
'
);
}
if
(
s
!=
null
)
await
s
.
close
();
return
port
;
}
}
class
FuchsiaDeviceCommandRunner
{
FuchsiaDeviceCommandRunner
(
this
.
_address
,
this
.
_sshConfig
);
final
String
_address
;
final
String
_sshConfig
;
Future
<
List
<
String
>>
run
(
String
command
)
async
{
final
List
<
String
>
args
=
<
String
>[
'ssh'
,
'-F'
,
_sshConfig
,
_address
,
command
];
printTrace
(
args
.
join
(
' '
));
final
ProcessResult
result
=
await
processManager
.
run
(
args
);
if
(
result
.
exitCode
!=
0
)
{
printStatus
(
'Command failed:
$command
\n
stdout:
${result.stdout}
\n
stderr:
${result.stderr}
'
,
wrap:
false
);
return
null
;
}
printTrace
(
result
.
stdout
);
return
result
.
stdout
.
split
(
'
\n
'
);
}
}
packages/flutter_tools/lib/src/compile.dart
View file @
81c7af34
...
...
@@ -24,6 +24,38 @@ KernelCompiler get kernelCompiler => context[KernelCompiler];
typedef
CompilerMessageConsumer
=
void
Function
(
String
message
,
{
bool
emphasis
,
TerminalColor
color
});
/// The target model describes the set of core libraries that are availible within
/// the SDK.
class
TargetModel
{
/// Parse a [TargetModel] from a raw string.
///
/// Throws an [AssertionError] if passed a value other than 'flutter' or
/// 'flutter_runner'.
factory
TargetModel
(
String
rawValue
)
{
switch
(
rawValue
)
{
case
'flutter'
:
return
flutter
;
case
'flutter_runner'
:
return
flutterRunner
;
}
assert
(
false
);
return
null
;
}
const
TargetModel
.
_
(
this
.
_value
);
/// The flutter patched dart SDK
static
const
TargetModel
flutter
=
TargetModel
.
_
(
'flutter'
);
/// The fuchsia patched SDK.
static
const
TargetModel
flutterRunner
=
TargetModel
.
_
(
'flutter_runner'
);
final
String
_value
;
@override
String
toString
()
=>
_value
;
}
class
CompilerOutput
{
const
CompilerOutput
(
this
.
outputFilename
,
this
.
errorCount
);
...
...
@@ -122,6 +154,7 @@ class KernelCompiler {
String
mainPath
,
String
outputFilePath
,
String
depFilePath
,
TargetModel
targetModel
=
TargetModel
.
flutter
,
bool
linkPlatformKernelIn
=
false
,
bool
aot
=
false
,
@required
bool
trackWidgetCreation
,
...
...
@@ -172,7 +205,7 @@ class KernelCompiler {
'--sdk-root'
,
sdkRoot
,
'--strong'
,
'--target=
flutter
'
,
'--target=
$targetModel
'
,
];
if
(
trackWidgetCreation
)
command
.
add
(
'--track-widget-creation'
);
...
...
@@ -301,12 +334,14 @@ class ResidentCompiler {
String
fileSystemScheme
,
CompilerMessageConsumer
compilerMessageConsumer
=
printError
,
String
initializeFromDill
,
TargetModel
targetModel
=
TargetModel
.
flutter
,
bool
unsafePackageSerialization
})
:
assert
(
_sdkRoot
!=
null
),
_trackWidgetCreation
=
trackWidgetCreation
,
_packagesPath
=
packagesPath
,
_fileSystemRoots
=
fileSystemRoots
,
_fileSystemScheme
=
fileSystemScheme
,
_targetModel
=
targetModel
,
_stdoutHandler
=
_StdoutHandler
(
consumer:
compilerMessageConsumer
),
_controller
=
StreamController
<
_CompilationRequest
>(),
_initializeFromDill
=
initializeFromDill
,
...
...
@@ -318,6 +353,7 @@ class ResidentCompiler {
final
bool
_trackWidgetCreation
;
final
String
_packagesPath
;
final
TargetModel
_targetModel
;
final
List
<
String
>
_fileSystemRoots
;
final
String
_fileSystemScheme
;
String
_sdkRoot
;
...
...
@@ -409,7 +445,7 @@ class ResidentCompiler {
_sdkRoot
,
'--incremental'
,
'--strong'
,
'--target=
flutter
'
,
'--target=
$_targetModel
'
,
];
if
(
outputPath
!=
null
)
{
command
.
addAll
(<
String
>[
'--output-dill'
,
outputPath
]);
...
...
packages/flutter_tools/lib/src/context_runner.dart
View file @
81c7af34
...
...
@@ -65,6 +65,7 @@ Future<T> runInContext<T>(
DoctorValidatorsProvider:
()
=>
DoctorValidatorsProvider
.
defaultInstance
,
EmulatorManager:
()
=>
EmulatorManager
(),
FuchsiaSdk:
()
=>
FuchsiaSdk
(),
FuchsiaArtifacts:
()
=>
FuchsiaArtifacts
(),
FuchsiaWorkflow:
()
=>
FuchsiaWorkflow
(),
Flags:
()
=>
const
EmptyFlags
(),
FlutterVersion:
()
=>
FlutterVersion
(
const
Clock
()),
...
...
packages/flutter_tools/lib/src/fuchsia/fuchsia_device.dart
View file @
81c7af34
...
...
@@ -172,7 +172,7 @@ class FuchsiaDevice extends Device {
/// Run `command` on the Fuchsia device shell.
Future
<
String
>
shell
(
String
command
)
async
{
final
RunResult
result
=
await
runAsync
(<
String
>[
'ssh'
,
'-F'
,
fuchsia
Sdk
.
sshConfig
.
absolute
.
path
,
id
,
command
]);
'ssh'
,
'-F'
,
fuchsia
Artifacts
.
sshConfig
.
absolute
.
path
,
id
,
command
]);
if
(
result
.
exitCode
!=
0
)
{
throwToolExit
(
'Command failed:
$command
\n
stdout:
${result.stdout}
\n
stderr:
${result.stderr}
'
);
return
null
;
...
...
@@ -228,7 +228,7 @@ class _FuchsiaPortForwarder extends DevicePortForwarder {
// Note: the provided command works around a bug in -N, see US-515
// for more explanation.
final
List
<
String
>
command
=
<
String
>[
'ssh'
,
'-6'
,
'-F'
,
fuchsia
Sdk
.
sshConfig
.
absolute
.
path
,
'-nNT'
,
'-vvv'
,
'-f'
,
'ssh'
,
'-6'
,
'-F'
,
fuchsia
Artifacts
.
sshConfig
.
absolute
.
path
,
'-nNT'
,
'-vvv'
,
'-f'
,
'-L'
,
'
$hostPort
:
$_ipv4Loopback
:
$devicePort
'
,
device
.
id
,
'true'
];
final
Process
process
=
await
processManager
.
start
(
command
);
...
...
@@ -252,7 +252,7 @@ class _FuchsiaPortForwarder extends DevicePortForwarder {
final
Process
process
=
_processes
.
remove
(
forwardedPort
.
hostPort
);
process
?.
kill
();
final
List
<
String
>
command
=
<
String
>[
'ssh'
,
'-F'
,
fuchsia
Sdk
.
sshConfig
.
absolute
.
path
,
'-O'
,
'cancel'
,
'-vvv'
,
'ssh'
,
'-F'
,
fuchsia
Artifacts
.
sshConfig
.
absolute
.
path
,
'-O'
,
'cancel'
,
'-vvv'
,
'-L'
,
'
${forwardedPort.hostPort}
:
$_ipv4Loopback
:
${forwardedPort.devicePort}
'
,
device
.
id
];
final
ProcessResult
result
=
await
processManager
.
run
(
command
);
if
(
result
.
exitCode
!=
0
)
{
...
...
packages/flutter_tools/lib/src/fuchsia/fuchsia_sdk.dart
View file @
81c7af34
...
...
@@ -17,6 +17,9 @@ import '../globals.dart';
/// The [FuchsiaSdk] instance.
FuchsiaSdk
get
fuchsiaSdk
=>
context
[
FuchsiaSdk
];
/// The [FuchsiaArtifacts] instance.
FuchsiaArtifacts
get
fuchsiaArtifacts
=>
context
[
FuchsiaArtifacts
];
/// The Fuchsia SDK shell commands.
///
/// This workflow assumes development within the fuchsia source tree,
...
...
@@ -26,19 +29,6 @@ class FuchsiaSdk {
static
const
List
<
String
>
_netlsCommand
=
<
String
>[
'fx'
,
'netls'
,
'--nowait'
];
static
const
List
<
String
>
_syslogCommand
=
<
String
>[
'fx'
,
'syslog'
];
/// The location of the SSH configuration file used to interact with a
/// fuchsia device.
///
/// Requires the env variable `BUILD_DIR` to be set.
File
get
sshConfig
{
if
(
_sshConfig
==
null
)
{
final
String
buildDirectory
=
platform
.
environment
[
'BUILD_DIR'
];
_sshConfig
=
fs
.
file
(
'
$buildDirectory
/ssh-keys/ssh_config'
);
}
return
_sshConfig
;
}
File
_sshConfig
;
/// Invokes the `netaddr` command.
///
/// This returns the network address of an attached fuchsia device. Does
...
...
@@ -100,3 +90,26 @@ class FuchsiaSdk {
return
null
;
}
}
/// Fuchsia-specific artifacts used to interact with a device.
class
FuchsiaArtifacts
{
/// Creates a new [FuchsiaArtifacts].
///
/// May optionally provide a file `sshConfig` file.
FuchsiaArtifacts
({
File
sshConfig
})
:
_sshConfig
=
sshConfig
;
/// The location of the SSH configuration file used to interact with a
/// fuchsia device.
///
/// Requires the env variable `BUILD_DIR` to be set if not provided by
/// the constructor.
File
get
sshConfig
{
if
(
_sshConfig
==
null
)
{
final
String
buildDirectory
=
platform
.
environment
[
'BUILD_DIR'
];
_sshConfig
=
fs
.
file
(
'
$buildDirectory
/ssh-keys/ssh_config'
);
}
return
_sshConfig
;
}
File
_sshConfig
;
}
packages/flutter_tools/lib/src/resident_runner.dart
View file @
81c7af34
...
...
@@ -35,6 +35,7 @@ class FlutterDevice {
this
.
fileSystemRoots
,
this
.
fileSystemScheme
,
this
.
viewFilter
,
TargetModel
targetModel
=
TargetModel
.
flutter
,
ResidentCompiler
generator
,
})
:
assert
(
trackWidgetCreation
!=
null
),
generator
=
generator
??
ResidentCompiler
(
...
...
@@ -42,6 +43,7 @@ class FlutterDevice {
trackWidgetCreation:
trackWidgetCreation
,
fileSystemRoots:
fileSystemRoots
,
fileSystemScheme:
fileSystemScheme
,
targetModel:
targetModel
,
);
final
Device
device
;
...
...
packages/flutter_tools/lib/src/runner/flutter_command.dart
View file @
81c7af34
...
...
@@ -193,6 +193,23 @@ abstract class FlutterCommand extends Command<void> {
'--release or --profile; --debug always has this enabled.'
);
}
void
usesFuchsiaOptions
({
bool
hide
=
false
})
{
argParser
.
addOption
(
'target-model'
,
help:
'Target model that determines what core libraries are available'
,
defaultsTo:
'flutter'
,
hide:
hide
,
allowed:
const
<
String
>[
'flutter'
,
'flutter_runner'
],
);
argParser
.
addOption
(
'module'
,
abbr:
'm'
,
hide:
hide
,
help:
'The name of the module (required if attaching to a fuchsia device)'
,
valueHelp:
'module-name'
,
);
}
set
defaultBuildMode
(
BuildMode
value
)
{
_defaultBuildMode
=
value
;
}
...
...
packages/flutter_tools/test/commands/fuchsia_reload_test.dart
deleted
100644 → 0
View file @
cf2fba7b
// Copyright 2017 The Chromium 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:convert'
;
import
'dart:io'
;
import
'package:flutter_tools/src/commands/fuchsia_reload.dart'
;
import
'package:mockito/mockito.dart'
;
import
'package:process/process.dart'
;
import
'../src/common.dart'
;
import
'../src/context.dart'
;
void
main
(
)
{
group
(
'FuchsiaDeviceCommandRunner'
,
()
{
testUsingContext
(
'a test'
,
()
async
{
final
FuchsiaDeviceCommandRunner
commandRunner
=
FuchsiaDeviceCommandRunner
(
'8.8.9.9'
,
'~/fuchsia/out/release-x86-64'
);
final
List
<
String
>
ports
=
await
commandRunner
.
run
(
'ls /tmp'
);
expect
(
ports
,
hasLength
(
3
));
expect
(
ports
[
0
],
equals
(
'1234'
));
expect
(
ports
[
1
],
equals
(
'5678'
));
expect
(
ports
[
2
],
equals
(
'5'
));
},
overrides:
<
Type
,
Generator
>{
ProcessManager:
()
=>
MockProcessManager
(),
});
});
}
class
MockProcessManager
extends
Mock
implements
ProcessManager
{
@override
Future
<
ProcessResult
>
run
(
List
<
dynamic
>
command
,
{
String
workingDirectory
,
Map
<
String
,
String
>
environment
,
bool
includeParentEnvironment
=
true
,
bool
runInShell
=
false
,
Encoding
stdoutEncoding
=
systemEncoding
,
Encoding
stderrEncoding
=
systemEncoding
,
})
async
{
return
ProcessResult
(
0
,
0
,
'1234
\n
5678
\n
5'
,
''
);
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment