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
b6ba37d7
Commit
b6ba37d7
authored
Mar 14, 2017
by
Zachary Anderson
Committed by
GitHub
Mar 14, 2017
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Adds initial support for hot reload for Fuchsia to flutter_tool. (#8764)
parent
1b4f817b
Changes
9
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
421 additions
and
63 deletions
+421
-63
executable.dart
packages/flutter_tools/lib/executable.dart
+2
-0
application_package.dart
packages/flutter_tools/lib/src/application_package.dart
+2
-0
artifacts.dart
packages/flutter_tools/lib/src/artifacts.dart
+2
-0
build_info.dart
packages/flutter_tools/lib/src/build_info.dart
+4
-1
build_aot.dart
packages/flutter_tools/lib/src/commands/build_aot.dart
+2
-0
fuchsia_reload.dart
packages/flutter_tools/lib/src/commands/fuchsia_reload.dart
+227
-0
fuchsia_device.dart
packages/flutter_tools/lib/src/fuchsia/fuchsia_device.dart
+102
-0
resident_runner.dart
packages/flutter_tools/lib/src/resident_runner.dart
+9
-0
run_hot.dart
packages/flutter_tools/lib/src/run_hot.dart
+71
-62
No files found.
packages/flutter_tools/lib/executable.dart
View file @
b6ba37d7
...
...
@@ -32,6 +32,7 @@ import 'src/commands/devices.dart';
import
'src/commands/doctor.dart'
;
import
'src/commands/drive.dart'
;
import
'src/commands/format.dart'
;
import
'src/commands/fuchsia_reload.dart'
;
import
'src/commands/install.dart'
;
import
'src/commands/logs.dart'
;
import
'src/commands/packages.dart'
;
...
...
@@ -74,6 +75,7 @@ Future<Null> main(List<String> args) async {
new
DoctorCommand
(),
new
DriveCommand
(),
new
FormatCommand
(),
new
FuchsiaReloadCommand
(),
new
InstallCommand
(),
new
LogsCommand
(),
new
PackagesCommand
(),
...
...
packages/flutter_tools/lib/src/application_package.dart
View file @
b6ba37d7
...
...
@@ -261,6 +261,7 @@ ApplicationPackage getApplicationPackageForPlatform(TargetPlatform platform, {
case
TargetPlatform
.
darwin_x64
:
case
TargetPlatform
.
linux_x64
:
case
TargetPlatform
.
windows_x64
:
case
TargetPlatform
.
fuchsia
:
return
null
;
}
assert
(
platform
!=
null
);
...
...
@@ -286,6 +287,7 @@ class ApplicationPackageStore {
case
TargetPlatform
.
darwin_x64
:
case
TargetPlatform
.
linux_x64
:
case
TargetPlatform
.
windows_x64
:
case
TargetPlatform
.
fuchsia
:
return
null
;
}
return
null
;
...
...
packages/flutter_tools/lib/src/artifacts.dart
View file @
b6ba37d7
...
...
@@ -89,6 +89,7 @@ class CachedArtifacts extends Artifacts {
case
TargetPlatform
.
darwin_x64
:
case
TargetPlatform
.
linux_x64
:
case
TargetPlatform
.
windows_x64
:
case
TargetPlatform
.
fuchsia
:
return
_getHostArtifactPath
(
artifact
,
platform
);
}
assert
(
false
,
'Invalid platform
$platform
.'
);
...
...
@@ -170,6 +171,7 @@ class CachedArtifacts extends Artifacts {
case
TargetPlatform
.
linux_x64
:
case
TargetPlatform
.
darwin_x64
:
case
TargetPlatform
.
windows_x64
:
case
TargetPlatform
.
fuchsia
:
assert
(
mode
==
null
,
'Platform
$platform
does not support different build modes.'
);
return
fs
.
path
.
join
(
engineDir
,
platformName
);
case
TargetPlatform
.
ios
:
...
...
packages/flutter_tools/lib/src/build_info.dart
View file @
b6ba37d7
...
...
@@ -67,7 +67,8 @@ enum TargetPlatform {
ios
,
darwin_x64
,
linux_x64
,
windows_x64
windows_x64
,
fuchsia
,
}
String
getNameForTargetPlatform
(
TargetPlatform
platform
)
{
...
...
@@ -86,6 +87,8 @@ String getNameForTargetPlatform(TargetPlatform platform) {
return
'linux-x64'
;
case
TargetPlatform
.
windows_x64
:
return
'windows-x64'
;
case
TargetPlatform
.
fuchsia
:
return
'fuchsia'
;
}
assert
(
false
);
return
null
;
...
...
packages/flutter_tools/lib/src/commands/build_aot.dart
View file @
b6ba37d7
...
...
@@ -175,6 +175,7 @@ Future<String> _buildAotSnapshot(
case
TargetPlatform
.
darwin_x64
:
case
TargetPlatform
.
linux_x64
:
case
TargetPlatform
.
windows_x64
:
case
TargetPlatform
.
fuchsia
:
assert
(
false
);
}
...
...
@@ -232,6 +233,7 @@ Future<String> _buildAotSnapshot(
case
TargetPlatform
.
darwin_x64
:
case
TargetPlatform
.
linux_x64
:
case
TargetPlatform
.
windows_x64
:
case
TargetPlatform
.
fuchsia
:
assert
(
false
);
}
...
...
packages/flutter_tools/lib/src/commands/fuchsia_reload.dart
0 → 100644
View file @
b6ba37d7
// 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:math'
;
import
'../base/common.dart'
;
import
'../base/file_system.dart'
;
import
'../base/io.dart'
;
import
'../base/platform.dart'
;
import
'../device.dart'
;
import
'../flx.dart'
as
flx
;
import
'../fuchsia/fuchsia_device.dart'
;
import
'../globals.dart'
;
import
'../run_hot.dart'
;
import
'../runner/flutter_command.dart'
;
// Usage:
// With e.g. flutter_gallery already running, a HotRunner can be attached to it
// with:
// $ flutter fuchsia_reload -f ~/fuchsia -a 192.168.1.39 \
// -g //lib/flutter/examples/flutter_gallery:flutter_gallery
class
FuchsiaReloadCommand
extends
FlutterCommand
{
String
_fuchsiaRoot
;
String
_projectRoot
;
String
_projectName
;
String
_fuchsiaProjectPath
;
String
_target
;
String
_address
;
String
_dotPackagesPath
;
@override
final
String
name
=
'fuchsia_reload'
;
@override
final
String
description
=
'Hot reload on Fuchsia.'
;
FuchsiaReloadCommand
()
{
addBuildModeFlags
(
defaultToRelease:
false
);
argParser
.
addOption
(
'address'
,
abbr:
'a'
,
help:
'Fuchsia device network name or address.'
);
argParser
.
addOption
(
'build-type'
,
abbr:
'b'
,
defaultsTo:
'release-x86-64'
,
help:
'Fuchsia build type, e.g. release-x86-64.'
);
argParser
.
addOption
(
'fuchsia-root'
,
abbr:
'f'
,
defaultsTo:
platform
.
environment
[
'FUCHSIA_ROOT'
],
help:
'Path to Fuchsia source tree.'
);
argParser
.
addOption
(
'gn-target'
,
abbr:
'g'
,
help:
'GN target of the application, e.g //path/to/app:app'
);
argParser
.
addOption
(
'target'
,
abbr:
't'
,
defaultsTo:
flx
.
defaultMainPath
,
help:
'Target app path / main entry-point file. '
'Relative to --gn-target path, e.g. lib/main.dart'
);
}
@override
Future
<
Null
>
runCommand
()
async
{
_validateArguments
();
// Find the network ports used on the device by VM service instances.
final
List
<
int
>
servicePorts
=
await
_getServicePorts
();
if
(
servicePorts
.
length
==
0
)
{
throwToolExit
(
"Couldn't find any running Observatory instances."
);
}
for
(
int
port
in
servicePorts
)
{
printStatus
(
"Fuchsia service port:
$port
"
);
}
// TODO(zra): Check that there are running VM services on the returned
// ports, and find the Isolates that are running the target app.
// Set up a device and hot runner and attach the hot runner to the first
// vm service we found.
final
int
firstPort
=
servicePorts
[
0
];
final
FuchsiaDevice
device
=
new
FuchsiaDevice
(
"
$_address
:
$firstPort
"
);
final
HotRunner
hotRunner
=
new
HotRunner
(
device
,
debuggingOptions:
new
DebuggingOptions
.
enabled
(
getBuildMode
()),
target:
_target
,
projectRootPath:
_fuchsiaProjectPath
,
packagesFilePath:
_dotPackagesPath
);
final
Uri
observatoryUri
=
Uri
.
parse
(
"http://
$_address
:
$firstPort
"
);
await
hotRunner
.
attach
(
observatoryUri
);
}
void
_validateArguments
()
{
_fuchsiaRoot
=
argResults
[
'fuchsia-root'
];
if
(
_fuchsiaRoot
==
null
)
{
throwToolExit
(
"Please give the location of the Fuchsia tree with --fuchsia-root"
);
}
if
(!
_directoryExists
(
_fuchsiaRoot
))
{
throwToolExit
(
"Specified --fuchsia-root '
$_fuchsiaRoot
' does not exist"
);
}
_address
=
argResults
[
'address'
];
if
(
_address
==
null
)
{
throwToolExit
(
"Give the address of the device running Fuchsia with --address"
);
}
final
List
<
String
>
gnTarget
=
_extractPathAndName
(
argResults
[
'gn-target'
]);
_projectRoot
=
gnTarget
[
0
];
_projectName
=
gnTarget
[
1
];
_fuchsiaProjectPath
=
"
$_fuchsiaRoot
/
$_projectRoot
"
;
if
(!
_directoryExists
(
_fuchsiaProjectPath
))
{
throwToolExit
(
"Target does not exist in the Fuchsia tree:
$_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
"
);
}
final
String
buildType
=
argResults
[
'build-type'
];
if
(
buildType
==
null
)
{
throwToolExit
(
"Give the build type with --build-type"
);
}
final
String
packagesFileName
=
"
${_projectName}
_dart_package.packages"
;
_dotPackagesPath
=
"
$_fuchsiaRoot
/out/
$buildType
/gen/
$_projectRoot
/
$packagesFileName
"
;
if
(!
_fileExists
(
_dotPackagesPath
))
{
throwToolExit
(
"Couldn't find .packages file at
$_dotPackagesPath
"
);
}
}
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
<
int
>>
_getServicePorts
()
async
{
final
FuchsiaDeviceCommandRunner
runner
=
new
FuchsiaDeviceCommandRunner
(
_fuchsiaRoot
);
final
List
<
String
>
lsOutput
=
await
runner
.
run
(
"ls /tmp/dart.services"
);
final
List
<
int
>
ports
=
new
List
<
int
>();
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
.
parse
(
lastWord
,
onError:
(
_
)
=>
null
);
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
();
}
}
// TODO(zra): When Fuchsia has ssh, this should be changed to use that instead.
class
FuchsiaDeviceCommandRunner
{
final
String
_fuchsiaRoot
;
final
Random
_rng
=
new
Random
(
new
DateTime
.
now
().
millisecondsSinceEpoch
);
FuchsiaDeviceCommandRunner
(
this
.
_fuchsiaRoot
);
Future
<
List
<
String
>>
run
(
String
command
)
async
{
final
int
tag
=
_rng
.
nextInt
(
999999
);
const
String
kNetRunCommand
=
"out/build-magenta/tools/netruncmd"
;
final
String
netruncmd
=
fs
.
path
.
join
(
_fuchsiaRoot
,
kNetRunCommand
);
const
String
kNetCP
=
"out/build-magenta/tools/netcp"
;
final
String
netcp
=
fs
.
path
.
join
(
_fuchsiaRoot
,
kNetCP
);
final
String
remoteStdout
=
"/tmp/netruncmd.
$tag
"
;
final
String
localStdout
=
"
${fs.systemTempDirectory.path}
/netruncmd.
$tag
"
;
final
String
redirectedCommand
=
"
$command
>
$remoteStdout
"
;
// Run the command with output directed to a tmp file.
ProcessResult
result
=
await
Process
.
run
(
netruncmd
,
<
String
>[
":"
,
redirectedCommand
]);
if
(
result
.
exitCode
!=
0
)
{
return
null
;
}
// Copy that file to the local filesystem.
result
=
await
Process
.
run
(
netcp
,
<
String
>[
":
$remoteStdout
"
,
localStdout
]);
// Try to delete the remote file. Don't care about the result;
Process
.
run
(
netruncmd
,
<
String
>[
":"
,
"rm
$remoteStdout
"
]);
if
(
result
.
exitCode
!=
0
)
{
return
null
;
}
// Read the local file.
final
File
f
=
fs
.
file
(
localStdout
);
List
<
String
>
lines
;
try
{
lines
=
await
f
.
readAsLines
();
}
finally
{
f
.
delete
();
}
return
lines
;
}
}
packages/flutter_tools/lib/src/fuchsia/fuchsia_device.dart
0 → 100644
View file @
b6ba37d7
// 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
'../application_package.dart'
;
import
'../build_info.dart'
;
import
'../devfs.dart'
;
import
'../device.dart'
;
/// Read the log for a particular device.
class
_FuchsiaLogReader
extends
DeviceLogReader
{
FuchsiaDevice
_device
;
_FuchsiaLogReader
(
this
.
_device
);
@override
String
get
name
=>
_device
.
name
;
Stream
<
String
>
_logLines
;
@override
Stream
<
String
>
get
logLines
{
_logLines
??=
new
Stream
<
String
>.
empty
();
return
_logLines
;
}
@override
String
toString
()
=>
name
;
}
class
FuchsiaDevice
extends
Device
{
FuchsiaDevice
(
String
id
,
{
this
.
name
})
:
super
(
id
);
@override
bool
get
supportsHotMode
=>
true
;
@override
final
String
name
;
@override
bool
get
isLocalEmulator
=>
false
;
@override
bool
get
supportsStartPaused
=>
false
;
@override
bool
isAppInstalled
(
ApplicationPackage
app
)
=>
false
;
@override
bool
isLatestBuildInstalled
(
ApplicationPackage
app
)
=>
false
;
@override
bool
installApp
(
ApplicationPackage
app
)
=>
false
;
@override
bool
uninstallApp
(
ApplicationPackage
app
)
=>
false
;
@override
bool
isSupported
()
=>
true
;
@override
Future
<
LaunchResult
>
startApp
(
ApplicationPackage
app
,
BuildMode
mode
,
{
String
mainPath
,
String
route
,
DebuggingOptions
debuggingOptions
,
Map
<
String
,
dynamic
>
platformArgs
,
bool
prebuiltApplication:
false
,
DevFSContent
kernelContent
,
bool
applicationNeedsRebuild:
false
,
})
=>
new
Future
<
Null
>.
error
(
'unimplemented'
);
@override
Future
<
bool
>
stopApp
(
ApplicationPackage
app
)
async
{
// Currently we don't have a way to stop an app running on Fuchsia.
return
false
;
}
@override
TargetPlatform
get
targetPlatform
=>
TargetPlatform
.
fuchsia
;
@override
String
get
sdkNameAndVersion
=>
'Fuchsia'
;
_FuchsiaLogReader
_logReader
;
@override
DeviceLogReader
getLogReader
({
ApplicationPackage
app
})
{
_logReader
??=
new
_FuchsiaLogReader
(
this
);
return
_logReader
;
}
@override
DevicePortForwarder
get
portForwarder
=>
null
;
@override
void
clearLogs
()
{
}
@override
bool
get
supportsScreenshot
=>
false
;
}
packages/flutter_tools/lib/src/resident_runner.dart
View file @
b6ba37d7
...
...
@@ -89,6 +89,12 @@ abstract class ResidentRunner {
return
stopApp
();
}
Future
<
Null
>
detach
()
async
{
await
stopEchoingDeviceLog
();
await
preStop
();
appFinished
();
}
Future
<
Null
>
_debugDumpApp
()
async
{
if
(
vmService
!=
null
)
await
vmService
.
vm
.
refreshViews
();
...
...
@@ -273,6 +279,9 @@ abstract class ResidentRunner {
// F10, exit
await
stop
();
return
true
;
}
else
if
(
lower
==
'd'
)
{
await
detach
();
return
true
;
}
return
false
;
...
...
packages/flutter_tools/lib/src/run_hot.dart
View file @
b6ba37d7
...
...
@@ -87,6 +87,74 @@ class HotRunner extends ResidentRunner {
return
true
;
}
Future
<
int
>
attach
(
Uri
observatoryUri
,
{
Completer
<
DebugConnectionInfo
>
connectionInfoCompleter
,
Completer
<
Null
>
appStartedCompleter
,
})
async
{
_observatoryUri
=
observatoryUri
;
try
{
await
connectToServiceProtocol
(
_observatoryUri
);
}
catch
(
error
)
{
printError
(
'Error connecting to the service protocol:
$error
'
);
return
2
;
}
try
{
final
Uri
baseUri
=
await
_initDevFS
();
if
(
connectionInfoCompleter
!=
null
)
{
connectionInfoCompleter
.
complete
(
new
DebugConnectionInfo
(
httpUri:
_observatoryUri
,
wsUri:
vmService
.
wsAddress
,
baseUri:
baseUri
.
toString
()
)
);
}
}
catch
(
error
)
{
printError
(
'Error initializing DevFS:
$error
'
);
return
3
;
}
final
bool
devfsResult
=
await
_updateDevFS
();
if
(!
devfsResult
)
{
printError
(
'Could not perform initial file synchronization.'
);
return
3
;
}
await
vmService
.
vm
.
refreshViews
();
printTrace
(
'Connected to
${vmService.vm.mainView}
.'
);
if
(
stayResident
)
{
setupTerminal
();
registerSignalHandlers
();
}
appStartedCompleter
?.
complete
();
if
(
benchmarkMode
)
{
// We are running in benchmark mode.
printStatus
(
'Running in benchmark mode.'
);
// Measure time to perform a hot restart.
printStatus
(
'Benchmarking hot restart'
);
await
restart
(
fullRestart:
true
);
await
vmService
.
vm
.
refreshViews
();
// TODO(johnmccutchan): Modify script entry point.
printStatus
(
'Benchmarking hot reload'
);
// Measure time to perform a hot reload.
await
restart
(
fullRestart:
false
);
printStatus
(
'Benchmark completed. Exiting application.'
);
await
_cleanupDevFS
();
await
stopEchoingDeviceLog
();
await
stopApp
();
final
File
benchmarkOutput
=
fs
.
file
(
'hot_benchmark.json'
);
benchmarkOutput
.
writeAsStringSync
(
toPrettyJson
(
benchmarkData
));
}
if
(
stayResident
)
return
waitForAppToFinish
();
await
cleanupAtFinish
();
return
0
;
}
@override
Future
<
int
>
run
({
Completer
<
DebugConnectionInfo
>
connectionInfoCompleter
,
...
...
@@ -152,68 +220,9 @@ class HotRunner extends ResidentRunner {
return
2
;
}
_observatoryUri
=
result
.
observatoryUri
;
try
{
await
connectToServiceProtocol
(
_observatoryUri
);
}
catch
(
error
)
{
printError
(
'Error connecting to the service protocol:
$error
'
);
return
2
;
}
try
{
final
Uri
baseUri
=
await
_initDevFS
();
if
(
connectionInfoCompleter
!=
null
)
{
connectionInfoCompleter
.
complete
(
new
DebugConnectionInfo
(
httpUri:
_observatoryUri
,
wsUri:
vmService
.
wsAddress
,
baseUri:
baseUri
.
toString
()
)
);
}
}
catch
(
error
)
{
printError
(
'Error initializing DevFS:
$error
'
);
return
3
;
}
final
bool
devfsResult
=
await
_updateDevFS
();
if
(!
devfsResult
)
{
printError
(
'Could not perform initial file synchronization.'
);
return
3
;
}
await
vmService
.
vm
.
refreshViews
();
printTrace
(
'Connected to
${vmService.vm.mainView}
.'
);
if
(
stayResident
)
{
setupTerminal
();
registerSignalHandlers
();
}
appStartedCompleter
?.
complete
();
if
(
benchmarkMode
)
{
// We are running in benchmark mode.
printStatus
(
'Running in benchmark mode.'
);
// Measure time to perform a hot restart.
printStatus
(
'Benchmarking hot restart'
);
await
restart
(
fullRestart:
true
);
await
vmService
.
vm
.
refreshViews
();
// TODO(johnmccutchan): Modify script entry point.
printStatus
(
'Benchmarking hot reload'
);
// Measure time to perform a hot reload.
await
restart
(
fullRestart:
false
);
printStatus
(
'Benchmark completed. Exiting application.'
);
await
_cleanupDevFS
();
await
stopEchoingDeviceLog
();
await
stopApp
();
final
File
benchmarkOutput
=
fs
.
file
(
'hot_benchmark.json'
);
benchmarkOutput
.
writeAsStringSync
(
toPrettyJson
(
benchmarkData
));
}
if
(
stayResident
)
return
waitForAppToFinish
();
await
cleanupAtFinish
();
return
0
;
return
attach
(
result
.
observatoryUri
,
connectionInfoCompleter:
connectionInfoCompleter
,
appStartedCompleter:
appStartedCompleter
);
}
@override
...
...
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