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
94ce956f
Unverified
Commit
94ce956f
authored
May 21, 2019
by
Zachary Anderson
Committed by
GitHub
May 21, 2019
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[flutter_tool] Adds support for 'run' for Fuchsia devices (#32849)
parent
3265e159
Changes
15
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
15 changed files
with
1167 additions
and
197 deletions
+1167
-197
application_package.dart
packages/flutter_tools/lib/src/application_package.dart
+4
-1
os.dart
packages/flutter_tools/lib/src/base/os.dart
+33
-0
context_runner.dart
packages/flutter_tools/lib/src/context_runner.dart
+4
-6
amber_ctl.dart
packages/flutter_tools/lib/src/fuchsia/amber_ctl.dart
+76
-0
application_package.dart
...es/flutter_tools/lib/src/fuchsia/application_package.dart
+71
-0
fuchsia_build.dart
packages/flutter_tools/lib/src/fuchsia/fuchsia_build.dart
+3
-2
fuchsia_dev_finder.dart
...ges/flutter_tools/lib/src/fuchsia/fuchsia_dev_finder.dart
+56
-0
fuchsia_device.dart
packages/flutter_tools/lib/src/fuchsia/fuchsia_device.dart
+159
-43
fuchsia_kernel_compiler.dart
...lutter_tools/lib/src/fuchsia/fuchsia_kernel_compiler.dart
+7
-8
fuchsia_pm.dart
packages/flutter_tools/lib/src/fuchsia/fuchsia_pm.dart
+161
-54
fuchsia_sdk.dart
packages/flutter_tools/lib/src/fuchsia/fuchsia_sdk.dart
+38
-18
tiles_ctl.dart
packages/flutter_tools/lib/src/fuchsia/tiles_ctl.dart
+113
-0
resident_runner.dart
packages/flutter_tools/lib/src/resident_runner.dart
+8
-2
build_fuchsia_test.dart
packages/flutter_tools/test/commands/build_fuchsia_test.dart
+96
-53
fuchsa_device_test.dart
packages/flutter_tools/test/fuchsia/fuchsa_device_test.dart
+338
-10
No files found.
packages/flutter_tools/lib/src/application_package.dart
View file @
94ce956f
...
...
@@ -17,6 +17,7 @@ import 'base/os.dart' show os;
import
'base/process.dart'
;
import
'base/user_messages.dart'
;
import
'build_info.dart'
;
import
'fuchsia/application_package.dart'
;
import
'globals.dart'
;
import
'ios/ios_workflow.dart'
;
import
'ios/plist_utils.dart'
as
plist
;
...
...
@@ -66,7 +67,9 @@ class ApplicationPackageFactory {
?
WindowsApp
.
fromWindowsProject
(
FlutterProject
.
current
().
windows
)
:
WindowsApp
.
fromPrebuiltApp
(
applicationBinary
);
case
TargetPlatform
.
fuchsia
:
return
null
;
return
applicationBinary
==
null
?
FuchsiaApp
.
fromFuchsiaProject
(
FlutterProject
.
current
().
fuchsia
)
:
FuchsiaApp
.
fromPrebuiltApp
(
applicationBinary
);
}
assert
(
platform
!=
null
);
return
null
;
...
...
packages/flutter_tools/lib/src/base/os.dart
View file @
94ce956f
...
...
@@ -3,6 +3,8 @@
// found in the LICENSE file.
import
'package:archive/archive.dart'
;
import
'../globals.dart'
;
import
'context.dart'
;
import
'file_system.dart'
;
import
'io.dart'
;
...
...
@@ -72,6 +74,37 @@ abstract class OperatingSystemUtils {
/// Returns the separator between items in the PATH environment variable.
String
get
pathVarSeparator
;
/// Returns an unused network port.
///
/// Returns 0 if an unused port cannot be found.
///
/// The port returned by this function may become used before it is bound by
/// its intended user.
Future
<
int
>
findFreePort
({
bool
ipv6
=
false
})
async
{
int
port
=
0
;
ServerSocket
serverSocket
;
final
InternetAddress
loopback
=
ipv6
?
InternetAddress
.
loopbackIPv6
:
InternetAddress
.
loopbackIPv4
;
try
{
serverSocket
=
await
ServerSocket
.
bind
(
loopback
,
0
);
port
=
serverSocket
.
port
;
}
on
SocketException
catch
(
e
)
{
// If ipv4 loopback bind fails, try ipv6.
if
(!
ipv6
)
{
return
findFreePort
(
ipv6:
true
);
}
printTrace
(
'findFreePort failed:
$e
'
);
}
catch
(
e
)
{
// Failures are signaled by a return value of 0 from this function.
printTrace
(
'findFreePort failed:
$e
'
);
}
finally
{
if
(
serverSocket
!=
null
)
{
await
serverSocket
.
close
();
}
}
return
port
;
}
}
class
_PosixUtils
extends
OperatingSystemUtils
{
...
...
packages/flutter_tools/lib/src/context_runner.dart
View file @
94ce956f
...
...
@@ -27,10 +27,9 @@ import 'devfs.dart';
import
'device.dart'
;
import
'doctor.dart'
;
import
'emulator.dart'
;
import
'fuchsia/fuchsia_kernel_compiler.dart'
;
import
'fuchsia/fuchsia_pm.dart'
;
import
'fuchsia/fuchsia_sdk.dart'
;
import
'fuchsia/fuchsia_workflow.dart'
;
import
'fuchsia/fuchsia_device.dart'
show
FuchsiaDeviceTools
;
import
'fuchsia/fuchsia_sdk.dart'
show
FuchsiaSdk
,
FuchsiaArtifacts
;
import
'fuchsia/fuchsia_workflow.dart'
show
FuchsiaWorkflow
;
import
'ios/cocoapods.dart'
;
import
'ios/ios_workflow.dart'
;
import
'ios/mac.dart'
;
...
...
@@ -76,8 +75,7 @@ Future<T> runInContext<T>(
Flags:
()
=>
const
EmptyFlags
(),
FlutterVersion:
()
=>
FlutterVersion
(
const
SystemClock
()),
FuchsiaArtifacts:
()
=>
FuchsiaArtifacts
.
find
(),
FuchsiaKernelCompiler:
()
=>
FuchsiaKernelCompiler
(),
FuchsiaPM:
()
=>
FuchsiaPM
(),
FuchsiaDeviceTools:
()
=>
FuchsiaDeviceTools
(),
FuchsiaSdk:
()
=>
FuchsiaSdk
(),
FuchsiaWorkflow:
()
=>
FuchsiaWorkflow
(),
GenSnapshot:
()
=>
const
GenSnapshot
(),
...
...
packages/flutter_tools/lib/src/fuchsia/amber_ctl.dart
0 → 100644
View file @
94ce956f
// Copyright 2019 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
'../base/process.dart'
;
import
'fuchsia_device.dart'
;
import
'fuchsia_pm.dart'
;
// usage: amber_ctl <command> [opts]
// Commands
// get_up - get an update for a package
// Options
// -n: name of the package
// -v: version of the package to retrieve, if none is supplied any
// package instance could match
// -m: merkle root of the package to retrieve, if none is supplied
// any package instance could match
//
// get_blob - get the specified content blob
// -i: content ID of the blob
//
// add_src - add a source to the list we can use
// -n: name of the update source (optional, with URL)
// -f: file path or url to a source config file
// -h: SHA256 hash of source config file (optional, with URL)
// -x: do not disable other active sources (if the provided source is
// enabled)
//
// rm_src - remove a source, if it exists
// -n: name of the update source
//
// list_srcs - list the set of sources we can use
//
// enable_src
// -n: name of the update source
// -x: do not disable other active sources
//
// disable_src
// -n: name of the update source
//
// system_update - check for, download, and apply any available system
// update
//
// gc - trigger a garbage collection
//
// print_state - print go routine state of amber process
/// Simple wrapper for interacting with the 'amber_ctl' tool running on the
/// Fuchsia device.
class
FuchsiaAmberCtl
{
/// Teaches the amber instance running on [device] about the Fuchsia package
/// server accessible via [configUrl].
Future
<
bool
>
addSrc
(
FuchsiaDevice
device
,
FuchsiaPackageServer
server
)
async
{
final
String
configUrl
=
'
${server.url}
/config.json'
;
final
RunResult
result
=
await
device
.
shell
(
'amber_ctl add_src -x -f
$configUrl
'
);
return
result
.
exitCode
==
0
;
}
/// Instructs the amber instance running on [device] to forget about the
/// Fuchsia package server that it was accessing via [serverUrl].
Future
<
bool
>
rmSrc
(
FuchsiaDevice
device
,
FuchsiaPackageServer
server
)
async
{
final
RunResult
result
=
await
device
.
shell
(
'amber_ctl rm_src -n
${server.url}
'
);
return
result
.
exitCode
==
0
;
}
/// Instructs the amber instance running on [device] to prefetch the package
/// [packageName].
Future
<
bool
>
getUp
(
FuchsiaDevice
device
,
String
packageName
)
async
{
final
RunResult
result
=
await
device
.
shell
(
'amber_ctl get_up -n
$packageName
'
);
return
result
.
exitCode
==
0
;
}
}
packages/flutter_tools/lib/src/fuchsia/application_package.dart
0 → 100644
View file @
94ce956f
// Copyright 2019 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:meta/meta.dart'
;
import
'../application_package.dart'
;
import
'../base/file_system.dart'
;
import
'../build_info.dart'
;
import
'../project.dart'
;
abstract
class
FuchsiaApp
extends
ApplicationPackage
{
FuchsiaApp
({
@required
String
projectBundleId
})
:
super
(
id:
projectBundleId
);
/// Creates a new [FuchsiaApp] from a fuchsia sub project.
factory
FuchsiaApp
.
fromFuchsiaProject
(
FuchsiaProject
project
)
{
return
BuildableFuchsiaApp
(
project:
project
,
);
}
/// Creates a new [FuchsiaApp] from an existing .far archive.
///
/// [applicationBinary] is the path to the .far archive.
factory
FuchsiaApp
.
fromPrebuiltApp
(
FileSystemEntity
applicationBinary
)
{
return
PrebuiltFuchsiaApp
(
farArchive:
applicationBinary
.
path
,
);
}
@override
String
get
displayName
=>
id
;
/// The location of the 'far' archive containing the built app.
File
farArchive
(
BuildMode
buildMode
);
}
class
PrebuiltFuchsiaApp
extends
FuchsiaApp
{
PrebuiltFuchsiaApp
({
@required
String
farArchive
,
})
:
_farArchive
=
farArchive
,
// TODO(zra): Extract the archive and extract the id from meta/package.
super
(
projectBundleId:
farArchive
);
final
String
_farArchive
;
@override
File
farArchive
(
BuildMode
buildMode
)
=>
fs
.
file
(
_farArchive
);
@override
String
get
name
=>
_farArchive
;
}
class
BuildableFuchsiaApp
extends
FuchsiaApp
{
BuildableFuchsiaApp
({
this
.
project
})
:
super
(
projectBundleId:
project
.
project
.
manifest
.
appName
);
final
FuchsiaProject
project
;
@override
File
farArchive
(
BuildMode
buildMode
)
{
// TODO(zra): Distinguish among build modes.
final
String
outDir
=
getFuchsiaBuildDirectory
();
final
String
pkgDir
=
fs
.
path
.
join
(
outDir
,
'pkg'
);
final
String
appName
=
project
.
project
.
manifest
.
appName
;
return
fs
.
file
(
fs
.
path
.
join
(
pkgDir
,
'
$appName
-0.far'
));
}
@override
String
get
name
=>
project
.
project
.
manifest
.
appName
;
}
packages/flutter_tools/lib/src/fuchsia/fuchsia_build.dart
View file @
94ce956f
...
...
@@ -12,8 +12,8 @@ import '../bundle.dart';
import
'../devfs.dart'
;
import
'../project.dart'
;
import
'fuchsia_kernel_compiler.dart'
;
import
'fuchsia_pm.dart'
;
import
'fuchsia_sdk.dart'
;
// Building a Fuchsia package has a few steps:
// 1. Do the custom kernel compile using the kernel compiler from the Fuchsia
...
...
@@ -30,7 +30,7 @@ Future<void> buildFuchsia(
outDir
.
createSync
(
recursive:
true
);
}
await
fuchsiaKernelCompiler
.
build
(
await
fuchsia
Sdk
.
fuchsia
KernelCompiler
.
build
(
fuchsiaProject:
fuchsiaProject
,
target:
target
,
buildInfo:
buildInfo
);
await
_buildAssets
(
fuchsiaProject
,
target
,
buildInfo
);
await
_buildPackage
(
fuchsiaProject
,
target
,
buildInfo
);
...
...
@@ -96,6 +96,7 @@ Future<void> _buildPackage(
manifestFile
.
writeAsStringSync
(
'meta/package=
$pkgDir
/meta/package
\n
'
,
mode:
FileMode
.
append
);
final
FuchsiaPM
fuchsiaPM
=
fuchsiaSdk
.
fuchsiaPM
;
if
(!
await
fuchsiaPM
.
init
(
pkgDir
,
appName
))
{
return
;
}
...
...
packages/flutter_tools/lib/src/fuchsia/fuchsia_dev_finder.dart
0 → 100644
View file @
94ce956f
// Copyright 2019 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
'../base/common.dart'
;
import
'../base/process.dart'
;
import
'fuchsia_sdk.dart'
;
// Usage: dev_finder <flags> <subcommand> <subcommand args>
//
// Subcommands:
// commands list all command names
// flags describe all known top-level flags
// help describe subcommands and their syntax
// list lists all Fuchsia devices on the network
// resolve attempts to resolve all passed Fuchsia domain names on the
// network
/// A simple wrapper for the Fuchsia SDK's 'dev_finder' tool.
class
FuchsiaDevFinder
{
/// Returns a list of attached devices as a list of strings with entries
/// formatted as follows:
/// 192.168.42.172 scare-cable-skip-joy
Future
<
List
<
String
>>
list
()
async
{
if
(
fuchsiaArtifacts
.
devFinder
==
null
)
{
throwToolExit
(
'Fuchsia dev_finder tool not found.'
);
}
final
List
<
String
>
command
=
<
String
>[
fuchsiaArtifacts
.
devFinder
.
path
,
'list'
,
'-full'
];
final
RunResult
result
=
await
runAsync
(
command
);
return
(
result
.
exitCode
==
0
)
?
result
.
stdout
.
split
(
'
\n
'
)
:
null
;
}
/// Returns the host address by which the device [deviceName] should use for
/// the host.
///
/// The string [deviceName] should be the name of the device from the
/// 'list' command, e.g. 'scare-cable-skip-joy'.
Future
<
String
>
resolve
(
String
deviceName
)
async
{
if
(
fuchsiaArtifacts
.
devFinder
==
null
)
{
throwToolExit
(
'Fuchsia dev_finder tool not found.'
);
}
final
List
<
String
>
command
=
<
String
>[
fuchsiaArtifacts
.
devFinder
.
path
,
'resolve'
,
'-local'
,
'-device-limit'
,
'1'
,
deviceName
];
final
RunResult
result
=
await
runAsync
(
command
);
return
(
result
.
exitCode
==
0
)
?
result
.
stdout
.
trim
()
:
null
;
}
}
packages/flutter_tools/lib/src/fuchsia/fuchsia_device.dart
View file @
94ce956f
This diff is collapsed.
Click to expand it.
packages/flutter_tools/lib/src/fuchsia/fuchsia_kernel_compiler.dart
View file @
94ce956f
...
...
@@ -6,11 +6,10 @@ import 'package:meta/meta.dart';
import
'../artifacts.dart'
;
import
'../base/common.dart'
;
import
'../base/context.dart'
;
import
'../base/file_system.dart'
;
import
'../base/io.dart'
;
import
'../base/logger.dart'
;
import
'../base/process
_manager
.dart'
;
import
'../base/process.dart'
;
import
'../build_info.dart'
;
import
'../convert.dart'
;
import
'../globals.dart'
;
...
...
@@ -18,10 +17,8 @@ import '../project.dart';
import
'fuchsia_sdk.dart'
;
/// The [FuchsiaKernelCompiler] instance.
FuchsiaKernelCompiler
get
fuchsiaKernelCompiler
=>
context
.
get
<
FuchsiaKernelCompiler
>();
/// This is a simple wrapper around the custom kernel compiler from the Fuchsia
/// SDK.
class
FuchsiaKernelCompiler
{
/// Compiles the [fuchsiaProject] with entrypoint [target] to a collection of
/// .dilp files (consisting of the app split along package: boundaries, but
...
...
@@ -33,6 +30,9 @@ class FuchsiaKernelCompiler {
BuildInfo
buildInfo
=
BuildInfo
.
debug
,
})
async
{
// TODO(zra): Use filesystem root and scheme information from buildInfo.
if
(
fuchsiaArtifacts
.
kernelCompiler
==
null
)
{
throwToolExit
(
'Fuchisa kernel compiler not found'
);
}
const
String
multiRootScheme
=
'main-root'
;
final
String
packagesFile
=
fuchsiaProject
.
project
.
packagesFile
.
path
;
final
String
outDir
=
getFuchsiaBuildDirectory
();
...
...
@@ -87,8 +87,7 @@ class FuchsiaKernelCompiler {
artifacts
.
getArtifactPath
(
Artifact
.
engineDartBinary
),
fuchsiaArtifacts
.
kernelCompiler
.
path
,
]..
addAll
(
flags
);
printTrace
(
"Running: '
${command.join(' ')}
'"
);
final
Process
process
=
await
processManager
.
start
(
command
);
final
Process
process
=
await
runCommand
(
command
);
final
Status
status
=
logger
.
startProgress
(
'Building Fuchsia application...'
,
timeout:
null
,
...
...
packages/flutter_tools/lib/src/fuchsia/fuchsia_pm.dart
View file @
94ce956f
...
...
@@ -2,16 +2,15 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import
'../base/context.dart'
;
import
'../base/common.dart'
;
import
'../base/file_system.dart'
;
import
'../base/io.dart'
;
import
'../base/process_manager.dart'
;
import
'../base/process.dart'
;
import
'../convert.dart'
;
import
'../globals.dart'
;
import
'fuchsia_sdk.dart'
;
/// The [FuchsiaPM] instance.
FuchsiaPM
get
fuchsiaPM
=>
context
.
get
<
FuchsiaPM
>();
/// This is a basic wrapper class for the Fuchsia SDK's `pm` tool.
class
FuchsiaPM
{
/// Initializes the staging area at [buildPath] for creating the Fuchsia
...
...
@@ -21,47 +20,27 @@ class FuchsiaPM {
///
/// NB: The [buildPath] should probably be e.g. `build/fuchsia/pkg`, and the
/// [appName] should probably be the name of the app from the pubspec file.
Future
<
bool
>
init
(
String
buildPath
,
String
appName
)
async
{
final
List
<
String
>
command
=
<
String
>[
fuchsiaArtifacts
.
pm
.
path
,
Future
<
bool
>
init
(
String
buildPath
,
String
appName
)
{
return
_runPMCommand
(<
String
>[
'-o'
,
buildPath
,
'-n'
,
appName
,
'init'
,
];
printTrace
(
"Running: '
${command.join(' ')}
'"
);
final
ProcessResult
result
=
await
processManager
.
run
(
command
);
if
(
result
.
exitCode
!=
0
)
{
printError
(
'Error initializing Fuchsia package for
$appName
: '
);
printError
(
result
.
stdout
);
printError
(
result
.
stderr
);
return
false
;
}
return
true
;
]);
}
/// Generates a new private key to be used to sign a Fuchsia package.
///
/// [buildPath] should be the same [buildPath] passed to [init].
Future
<
bool
>
genkey
(
String
buildPath
,
String
outKeyPath
)
async
{
final
List
<
String
>
command
=
<
String
>[
fuchsiaArtifacts
.
pm
.
path
,
Future
<
bool
>
genkey
(
String
buildPath
,
String
outKeyPath
)
{
return
_runPMCommand
(<
String
>[
'-o'
,
buildPath
,
'-k'
,
outKeyPath
,
'genkey'
,
];
printTrace
(
"Running: '
${command.join(' ')}
'"
);
final
ProcessResult
result
=
await
processManager
.
run
(
command
);
if
(
result
.
exitCode
!=
0
)
{
printError
(
'Error generating key for Fuchsia package: '
);
printError
(
result
.
stdout
);
printError
(
result
.
stderr
);
return
false
;
}
return
true
;
]);
}
/// Updates, signs, and seals a Fuchsia package.
...
...
@@ -80,9 +59,8 @@ class FuchsiaPM {
/// where $APPNAME is the same [appName] passed to [init], and meta/package
/// is set up to be the file `meta/package` created by [init].
Future
<
bool
>
build
(
String
buildPath
,
String
keyPath
,
String
manifestPath
)
async
{
final
List
<
String
>
command
=
<
String
>[
fuchsiaArtifacts
.
pm
.
path
,
String
buildPath
,
String
keyPath
,
String
manifestPath
)
{
return
_runPMCommand
(<
String
>[
'-o'
,
buildPath
,
'-k'
,
...
...
@@ -90,16 +68,7 @@ class FuchsiaPM {
'-m'
,
manifestPath
,
'build'
,
];
printTrace
(
"Running: '
${command.join(' ')}
'"
);
final
ProcessResult
result
=
await
processManager
.
run
(
command
);
if
(
result
.
exitCode
!=
0
)
{
printError
(
'Error building Fuchsia package: '
);
printError
(
result
.
stdout
);
printError
(
result
.
stderr
);
return
false
;
}
return
true
;
]);
}
/// Constructs a .far representation of the Fuchsia package.
...
...
@@ -109,10 +78,8 @@ class FuchsiaPM {
///
/// [buildPath] should be the same path passed to [init], and [manfiestPath]
/// should be the same manifest passed to [build].
Future
<
bool
>
archive
(
String
buildPath
,
String
keyPath
,
String
manifestPath
)
async
{
final
List
<
String
>
command
=
<
String
>[
fuchsiaArtifacts
.
pm
.
path
,
Future
<
bool
>
archive
(
String
buildPath
,
String
keyPath
,
String
manifestPath
)
{
return
_runPMCommand
(<
String
>[
'-o'
,
buildPath
,
'-k'
,
...
...
@@ -120,15 +87,155 @@ class FuchsiaPM {
'-m'
,
manifestPath
,
'archive'
,
]);
}
/// Initializes a new package repository at [repoPath] to be later served by
/// the 'serve' command.
Future
<
bool
>
newrepo
(
String
repoPath
)
{
return
_runPMCommand
(<
String
>[
'newrepo'
,
'-repo'
,
repoPath
,
]);
}
/// Spawns an http server in a new process for serving Fuchisa packages.
///
/// The arguemnt [repoPath] should have previously been an arguemnt to
/// [newrepo]. The [host] should be the host reported by
/// [FuchsiaDevFinder.resolve], and [port] should be an unused port for the
/// http server to bind.
Future
<
Process
>
serve
(
String
repoPath
,
String
host
,
int
port
)
async
{
if
(
fuchsiaArtifacts
.
pm
==
null
)
{
throwToolExit
(
'Fuchsia pm tool not found'
);
}
final
List
<
String
>
command
=
<
String
>[
fuchsiaArtifacts
.
pm
.
path
,
'serve'
,
'-repo'
,
repoPath
,
'-l'
,
'
$host
:
$port
'
,
];
printTrace
(
"Running: '
${command.join(' ')}
'"
);
final
ProcessResult
result
=
await
processManager
.
run
(
command
);
if
(
result
.
exitCode
!=
0
)
{
printError
(
'Error archiving Fuchsia package: '
);
printError
(
result
.
stdout
);
printError
(
result
.
stderr
);
final
Process
process
=
await
runCommand
(
command
);
process
.
stdout
.
transform
(
utf8
.
decoder
)
.
transform
(
const
LineSplitter
())
.
listen
(
printTrace
);
process
.
stderr
.
transform
(
utf8
.
decoder
)
.
transform
(
const
LineSplitter
())
.
listen
(
printError
);
return
process
;
}
/// Publishes a Fuchsia package to a served package repository.
///
/// For a package repo initialized with [newrepo] at [repoPath] and served
/// by [serve], this call publishes the `far` package at [packagePath] to
/// the repo such that it will be visible to devices connecting to the
/// package server.
Future
<
bool
>
publish
(
String
repoPath
,
String
packagePath
)
{
return
_runPMCommand
(<
String
>[
'publish'
,
'-a'
,
'-r'
,
repoPath
,
'-f'
,
packagePath
,
]);
}
Future
<
bool
>
_runPMCommand
(
List
<
String
>
args
)
async
{
if
(
fuchsiaArtifacts
.
pm
==
null
)
{
throwToolExit
(
'Fuchsia pm tool not found'
);
}
final
List
<
String
>
command
=
<
String
>[
fuchsiaArtifacts
.
pm
.
path
]
+
args
;
final
RunResult
result
=
await
runAsync
(
command
);
return
result
.
exitCode
==
0
;
}
}
/// A class for running and retaining state for a Fuchsia package server.
///
/// [FuchsiaPackageServer] takes care of initializing the package repository,
/// spinning up the package server, publishing packages, and shutting down the
/// the server.
///
/// Example usage:
/// var server = FuchsiaPackageServer(
/// '/path/to/repo',
/// await FuchsiaDevFinder.resolve(deviceName),
/// await freshPort());
/// try {
/// await server.start();
/// await server.addPackage(farArchivePath);
/// ...
/// } finally {
/// server.stop();
/// }
class
FuchsiaPackageServer
{
FuchsiaPackageServer
(
this
.
_repo
,
this
.
_host
,
this
.
_port
);
final
String
_repo
;
final
String
_host
;
final
int
_port
;
Process
_process
;
/// The url that can be used by the device to access this package server.
String
get
url
=>
'http://
$_host
:
$_port
'
;
/// Usees [FuchiaPM.newrepo] and [FuchsiaPM.serve] to spin up a new Fuchsia
/// package server.
///
/// Returns false if ther repo could not be created or the server could not
/// be spawned, and true otherwise.
Future
<
bool
>
start
()
async
{
if
(
_process
!=
null
)
{
printError
(
'
$this
already started!'
);
return
false
;
}
// initialize a new repo.
if
(!
await
fuchsiaSdk
.
fuchsiaPM
.
newrepo
(
_repo
))
{
printError
(
'Failed to create a new package server repo'
);
return
false
;
}
_process
=
await
fuchsiaSdk
.
fuchsiaPM
.
serve
(
_repo
,
_host
,
_port
);
// Put a completer on _process.exitCode to watch for error.
unawaited
(
_process
.
exitCode
.
whenComplete
(()
{
// If _process is null, then the server was stopped deliberately.
if
(
_process
!=
null
)
{
printError
(
'Error running Fuchsia pm tool "serve" command'
);
}
}));
return
true
;
}
/// Forcefully stops the package server process by sending it SIGTERM.
void
stop
()
{
if
(
_process
!=
null
)
{
_process
.
kill
();
_process
=
null
;
}
}
/// Uses [FuchsiaPM.publish] to add the Fuchsia 'far' package at
/// [packagePath] to the package server.
///
/// Returns true on success and false if the server wasn't started or the
/// publish command failed.
Future
<
bool
>
addPackage
(
File
package
)
async
{
if
(
_process
==
null
)
{
return
false
;
}
return
await
fuchsiaSdk
.
fuchsiaPM
.
publish
(
_repo
,
package
.
path
);
}
@override
String
toString
()
{
final
String
p
=
(
_process
==
null
)
?
'stopped'
:
'running
${_process.pid}
'
;
return
'FuchsiaPackageServer at
$_host
:
$_port
(
$p
)'
;
}
}
packages/flutter_tools/lib/src/fuchsia/fuchsia_sdk.dart
View file @
94ce956f
...
...
@@ -8,12 +8,15 @@ import '../base/context.dart';
import
'../base/file_system.dart'
;
import
'../base/io.dart'
;
import
'../base/platform.dart'
;
import
'../base/process.dart'
;
import
'../base/process_manager.dart'
;
import
'../cache.dart'
;
import
'../convert.dart'
;
import
'../globals.dart'
;
import
'fuchsia_dev_finder.dart'
;
import
'fuchsia_kernel_compiler.dart'
;
import
'fuchsia_pm.dart'
;
/// The [FuchsiaSdk] instance.
FuchsiaSdk
get
fuchsiaSdk
=>
context
.
get
<
FuchsiaSdk
>();
...
...
@@ -25,23 +28,32 @@ FuchsiaArtifacts get fuchsiaArtifacts => context.get<FuchsiaArtifacts>();
/// This workflow assumes development within the fuchsia source tree,
/// including a working fx command-line tool in the user's PATH.
class
FuchsiaSdk
{
/// Interface to the 'pm' tool.
FuchsiaPM
get
fuchsiaPM
=>
_fuchsiaPM
??=
FuchsiaPM
();
FuchsiaPM
_fuchsiaPM
;
/// Interface to the 'dev_finder' tool.
FuchsiaDevFinder
_fuchsiaDevFinder
;
FuchsiaDevFinder
get
fuchsiaDevFinder
=>
_fuchsiaDevFinder
??=
FuchsiaDevFinder
();
/// Interface to the 'kernel_compiler' tool.
FuchsiaKernelCompiler
_fuchsiaKernelCompiler
;
FuchsiaKernelCompiler
get
fuchsiaKernelCompiler
=>
_fuchsiaKernelCompiler
??=
FuchsiaKernelCompiler
();
/// Example output:
/// $ dev_finder list -full
/// > 192.168.42.56 paper-pulp-bush-angel
Future
<
String
>
listDevices
()
async
{
try
{
final
String
path
=
fuchsiaArtifacts
.
devFinder
.
absolute
.
path
;
final
RunResult
process
=
await
runAsync
(<
String
>[
path
,
'list'
,
'-full'
]);
return
process
.
stdout
.
trim
();
}
catch
(
exception
)
{
printTrace
(
'
$exception
'
);
}
if
(
fuchsiaArtifacts
.
devFinder
==
null
)
{
return
null
;
}
final
List
<
String
>
devices
=
await
fuchsiaDevFinder
.
list
();
return
devices
.
isNotEmpty
?
devices
[
0
]
:
null
;
}
/// Returns the fuchsia system logs for an attached device.
///
/// Does not currently support multiple attached devices.
Stream
<
String
>
syslogs
(
String
id
)
{
Process
process
;
try
{
...
...
@@ -50,6 +62,8 @@ class FuchsiaSdk {
process
.
kill
();
});
if
(
fuchsiaArtifacts
.
sshConfig
==
null
)
{
printError
(
'Cannot read device logs: No ssh config.'
);
printError
(
'Have you set FUCHSIA_SSH_CONFIG or FUCHSIA_BUILD_DIR?'
);
return
null
;
}
const
String
remoteCommand
=
'log_listener --clock Local'
;
...
...
@@ -101,6 +115,15 @@ class FuchsiaArtifacts {
final
String
tools
=
fs
.
path
.
join
(
fuchsia
,
'tools'
);
final
String
dartPrebuilts
=
fs
.
path
.
join
(
tools
,
'dart_prebuilts'
);
final
File
devFinder
=
fs
.
file
(
fs
.
path
.
join
(
tools
,
'dev_finder'
));
final
File
platformDill
=
fs
.
file
(
fs
.
path
.
join
(
dartPrebuilts
,
'flutter_runner'
,
'platform_strong.dill'
));
final
File
patchedSdk
=
fs
.
file
(
fs
.
path
.
join
(
dartPrebuilts
,
'flutter_runner'
));
final
File
kernelCompiler
=
fs
.
file
(
fs
.
path
.
join
(
dartPrebuilts
,
'kernel_compiler.snapshot'
));
final
File
pm
=
fs
.
file
(
fs
.
path
.
join
(
tools
,
'pm'
));
// If FUCHSIA_BUILD_DIR is defined, then look for the ssh_config dir
// relative to it. Next, if FUCHSIA_SSH_CONFIG is defined, then use it.
// TODO(zra): Consider passing the ssh config path in with a flag.
...
...
@@ -113,14 +136,11 @@ class FuchsiaArtifacts {
}
return
FuchsiaArtifacts
(
sshConfig:
sshConfig
,
devFinder:
fs
.
file
(
fs
.
path
.
join
(
tools
,
'dev_finder'
)),
platformKernelDill:
fs
.
file
(
fs
.
path
.
join
(
dartPrebuilts
,
'flutter_runner'
,
'platform_strong.dill'
)),
flutterPatchedSdk:
fs
.
file
(
fs
.
path
.
join
(
dartPrebuilts
,
'flutter_runner'
)),
kernelCompiler:
fs
.
file
(
fs
.
path
.
join
(
dartPrebuilts
,
'kernel_compiler.snapshot'
)),
pm:
fs
.
file
(
fs
.
path
.
join
(
tools
,
'pm'
)),
devFinder:
devFinder
.
existsSync
()
?
devFinder
:
null
,
platformKernelDill:
platformDill
.
existsSync
()
?
platformDill
:
null
,
flutterPatchedSdk:
patchedSdk
.
existsSync
()
?
patchedSdk
:
null
,
kernelCompiler:
kernelCompiler
.
existsSync
()
?
kernelCompiler
:
null
,
pm:
pm
.
existsSync
()
?
pm
:
null
,
);
}
...
...
packages/flutter_tools/lib/src/fuchsia/tiles_ctl.dart
0 → 100644
View file @
94ce956f
// Copyright 2019 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
'../base/process.dart'
;
import
'../globals.dart'
;
import
'fuchsia_device.dart'
;
// Usage: tiles_ctl <command>
// Supported commands:
// start
// add [--disable-focus] <url> [<args>...]
// remove <key>
// list
// quit
/// A simple wrapper around the 'tiles_ctl' tool running on the Fuchsia device.
class
FuchsiaTilesCtl
{
/// Finds the key for the app called [appName], or returns -1 if it can't be
/// found.
static
Future
<
int
>
findAppKey
(
FuchsiaDevice
device
,
String
appName
)
async
{
final
FuchsiaTilesCtl
tilesCtl
=
fuchsiaDeviceTools
.
tilesCtl
;
final
Map
<
int
,
String
>
runningApps
=
await
tilesCtl
.
list
(
device
);
if
(
runningApps
==
null
)
{
printTrace
(
'tiles_ctl is not running'
);
return
-
1
;
}
for
(
MapEntry
<
int
,
String
>
entry
in
runningApps
.
entries
)
{
if
(
entry
.
value
.
contains
(
'
$appName
#meta'
))
{
return
entry
.
key
;
}
}
return
-
1
;
}
/// Ensures that tiles is running on the device.
static
Future
<
bool
>
ensureStarted
(
FuchsiaDevice
device
)
async
{
final
FuchsiaTilesCtl
tilesCtl
=
fuchsiaDeviceTools
.
tilesCtl
;
final
Map
<
int
,
String
>
runningApps
=
await
tilesCtl
.
list
(
device
);
if
(
runningApps
==
null
)
{
return
tilesCtl
.
start
(
device
);
}
return
true
;
}
/// Instructs 'tiles' to start on the device.
///
/// Returns true on success and false on failure.
Future
<
bool
>
start
(
FuchsiaDevice
device
)
async
{
final
RunResult
result
=
await
device
.
shell
(
'tiles_ctl start'
);
return
result
.
exitCode
==
0
;
}
/// Returns a mapping of tile keys to app urls.
///
/// Returns an empty mapping if tiles_ctl is running but no apps are running.
/// Returns null if tiles_ctl is not running.
Future
<
Map
<
int
,
String
>>
list
(
FuchsiaDevice
device
)
async
{
// Output of tiles_ctl list has the format:
// Found 1 tiles:
// Tile key 1 url fuchsia-pkg://fuchsia.com/stocks#meta/stocks.cmx ...
final
Map
<
int
,
String
>
tiles
=
<
int
,
String
>{};
final
RunResult
result
=
await
device
.
shell
(
'tiles_ctl list'
);
if
(
result
.
exitCode
!=
0
)
{
return
null
;
}
// Look for evidence that tiles_ctl is not running.
if
(
result
.
stdout
.
contains
(
"Couldn't find tiles component in realm"
))
{
return
null
;
}
// Find lines beginning with 'Tile'
for
(
String
line
in
result
.
stdout
.
split
(
'
\n
'
))
{
final
List
<
String
>
words
=
line
.
split
(
' '
);
if
(
words
.
isNotEmpty
&&
words
[
0
]
==
'Tile'
)
{
final
int
key
=
int
.
tryParse
(
words
[
2
]);
final
String
url
=
words
[
4
];
tiles
[
key
]
=
url
;
}
}
return
tiles
;
}
/// Instructs tiles on the device to begin running the app at [url] in a new
/// tile.
///
/// The app is passed the arguemnts in [args]. Flutter apps receive these
/// arguments as arguments to `main()`. [url] should be formatted as a
/// Fuchsia-style package url, e.g.:
/// fuchsia-pkg://fuchsia.com/flutter_gallery#meta/flutter_gallery.cmx
/// Returns true on success and false on failure.
Future
<
bool
>
add
(
FuchsiaDevice
device
,
String
url
,
List
<
String
>
args
)
async
{
final
RunResult
result
=
await
device
.
shell
(
'tiles_ctl add
$url
${args.join(" ")}
'
);
return
result
.
exitCode
==
0
;
}
/// Instructs tiles on the device to remove the app with key [key].
///
/// Returns true on success and false on failure.
Future
<
bool
>
remove
(
FuchsiaDevice
device
,
int
key
)
async
{
final
RunResult
result
=
await
device
.
shell
(
'tiles_ctl remove
$key
'
);
return
result
.
exitCode
==
0
;
}
/// Instructs tiles on the device to quit.
///
/// Returns true on success and false on failure.
Future
<
bool
>
quit
(
FuchsiaDevice
device
)
async
{
final
RunResult
result
=
await
device
.
shell
(
'tiles_ctl quit'
);
return
result
.
exitCode
==
0
;
}
}
packages/flutter_tools/lib/src/resident_runner.dart
View file @
94ce956f
...
...
@@ -313,9 +313,15 @@ class FlutterDevice {
}
void
startEchoingDeviceLog
()
{
if
(
_loggingSubscription
!=
null
)
if
(
_loggingSubscription
!=
null
)
{
return
;
_loggingSubscription
=
device
.
getLogReader
(
app:
package
).
logLines
.
listen
((
String
line
)
{
}
final
Stream
<
String
>
logStream
=
device
.
getLogReader
(
app:
package
).
logLines
;
if
(
logStream
==
null
)
{
printError
(
'Failed to read device log stream'
);
return
;
}
_loggingSubscription
=
logStream
.
listen
((
String
line
)
{
if
(!
line
.
contains
(
'Observatory listening on http'
))
printStatus
(
line
,
wrap:
false
);
});
...
...
packages/flutter_tools/test/commands/build_fuchsia_test.dart
View file @
94ce956f
...
...
@@ -11,6 +11,7 @@ import 'package:flutter_tools/src/cache.dart';
import
'package:flutter_tools/src/commands/build.dart'
;
import
'package:flutter_tools/src/fuchsia/fuchsia_kernel_compiler.dart'
;
import
'package:flutter_tools/src/fuchsia/fuchsia_pm.dart'
;
import
'package:flutter_tools/src/fuchsia/fuchsia_sdk.dart'
;
import
'package:flutter_tools/src/project.dart'
;
import
'package:meta/meta.dart'
;
import
'package:mockito/mockito.dart'
;
...
...
@@ -25,23 +26,28 @@ void main() {
MemoryFileSystem
memoryFileSystem
;
MockPlatform
linuxPlatform
;
MockPlatform
windowsPlatform
;
MockFuchsiaPM
fuchsiaPM
;
MockFuchsiaKernelCompiler
fuchsiaKernelCompiler
;
MockFuchsiaSdk
fuchsiaSdk
;
MockFuchsiaArtifacts
fuchsiaArtifacts
;
MockFuchsiaArtifacts
fuchsiaArtifactsNoCompiler
;
setUp
(()
{
memoryFileSystem
=
MemoryFileSystem
();
linuxPlatform
=
MockPlatform
();
windowsPlatform
=
MockPlatform
();
fuchsiaPM
=
MockFuchsiaPM
();
fuchsiaKernelCompiler
=
MockFuchsiaKernelCompiler
();
fuchsiaSdk
=
MockFuchsiaSdk
();
fuchsiaArtifacts
=
MockFuchsiaArtifacts
();
fuchsiaArtifactsNoCompiler
=
MockFuchsiaArtifacts
();
when
(
linuxPlatform
.
isLinux
).
thenReturn
(
true
);
when
(
windowsPlatform
.
isWindows
).
thenReturn
(
true
);
when
(
windowsPlatform
.
isLinux
).
thenReturn
(
false
);
when
(
windowsPlatform
.
isMacOS
).
thenReturn
(
false
);
when
(
fuchsiaArtifacts
.
kernelCompiler
).
thenReturn
(
MockFile
());
when
(
fuchsiaArtifactsNoCompiler
.
kernelCompiler
).
thenReturn
(
null
);
});
testUsingContext
(
'Fuchsia build fails when there is no fuchsia project'
,
group
(
'Fuchsia build fails gracefully when'
,
()
{
testUsingContext
(
'there is no Fuchsia project'
,
()
async
{
final
BuildCommand
command
=
BuildCommand
();
applyMocksToCommand
(
command
);
...
...
@@ -52,9 +58,10 @@ void main() {
},
overrides:
<
Type
,
Generator
>{
Platform:
()
=>
linuxPlatform
,
FileSystem:
()
=>
memoryFileSystem
,
FuchsiaArtifacts:
()
=>
fuchsiaArtifacts
,
});
testUsingContext
(
'Fuchsia build fails when
there is no cmx file'
,
()
async
{
testUsingContext
(
'
there is no cmx file'
,
()
async
{
final
BuildCommand
command
=
BuildCommand
();
applyMocksToCommand
(
command
);
fs
.
directory
(
'fuchsia'
).
createSync
(
recursive:
true
);
...
...
@@ -68,9 +75,10 @@ void main() {
},
overrides:
<
Type
,
Generator
>{
Platform:
()
=>
linuxPlatform
,
FileSystem:
()
=>
memoryFileSystem
,
FuchsiaArtifacts:
()
=>
fuchsiaArtifacts
,
});
testUsingContext
(
'Fuchsia build fails
on Windows platform'
,
()
async
{
testUsingContext
(
'
on Windows platform'
,
()
async
{
final
BuildCommand
command
=
BuildCommand
();
applyMocksToCommand
(
command
);
const
String
appName
=
'app_name'
;
...
...
@@ -88,6 +96,29 @@ void main() {
},
overrides:
<
Type
,
Generator
>{
Platform:
()
=>
windowsPlatform
,
FileSystem:
()
=>
memoryFileSystem
,
FuchsiaArtifacts:
()
=>
fuchsiaArtifacts
,
});
testUsingContext
(
'there is no Fuchsia kernel compiler'
,
()
async
{
final
BuildCommand
command
=
BuildCommand
();
applyMocksToCommand
(
command
);
const
String
appName
=
'app_name'
;
fs
.
file
(
fs
.
path
.
join
(
'fuchsia'
,
'meta'
,
'
$appName
.cmx'
))
.
createSync
(
recursive:
true
);
fs
.
file
(
'.packages'
).
createSync
();
fs
.
file
(
fs
.
path
.
join
(
'lib'
,
'main.dart'
)).
createSync
(
recursive:
true
);
final
File
pubspecFile
=
fs
.
file
(
'pubspec.yaml'
)..
createSync
();
pubspecFile
.
writeAsStringSync
(
'name:
$appName
'
);
expect
(
createTestCommandRunner
(
command
)
.
run
(
const
<
String
>[
'build'
,
'fuchsia'
]),
throwsA
(
isInstanceOf
<
ToolExit
>()));
},
overrides:
<
Type
,
Generator
>{
Platform:
()
=>
linuxPlatform
,
FileSystem:
()
=>
memoryFileSystem
,
FuchsiaArtifacts:
()
=>
fuchsiaArtifactsNoCompiler
,
});
});
testUsingContext
(
'Fuchsia build parts fit together right'
,
()
async
{
...
...
@@ -110,8 +141,7 @@ void main() {
},
overrides:
<
Type
,
Generator
>{
Platform:
()
=>
linuxPlatform
,
FileSystem:
()
=>
memoryFileSystem
,
FuchsiaPM:
()
=>
fuchsiaPM
,
FuchsiaKernelCompiler:
()
=>
fuchsiaKernelCompiler
,
FuchsiaSdk:
()
=>
fuchsiaSdk
,
});
}
...
...
@@ -189,3 +219,16 @@ class MockFuchsiaKernelCompiler extends Mock implements FuchsiaKernelCompiler {
fs
.
file
(
manifestPath
).
createSync
(
recursive:
true
);
}
}
class
MockFuchsiaSdk
extends
Mock
implements
FuchsiaSdk
{
@override
final
FuchsiaPM
fuchsiaPM
=
MockFuchsiaPM
();
@override
final
FuchsiaKernelCompiler
fuchsiaKernelCompiler
=
MockFuchsiaKernelCompiler
();
}
class
MockFile
extends
Mock
implements
File
{}
class
MockFuchsiaArtifacts
extends
Mock
implements
FuchsiaArtifacts
{}
packages/flutter_tools/test/fuchsia/fuchsa_device_test.dart
View file @
94ce956f
This diff is collapsed.
Click to expand it.
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