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
9c05c345
Commit
9c05c345
authored
Feb 13, 2017
by
Todd Volkert
Committed by
GitHub
Feb 13, 2017
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Enable record/replay of file system activity and platform metadata (#8104)
parent
ea74e076
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
129 additions
and
35 deletions
+129
-35
file_system.dart
packages/flutter_tools/lib/src/base/file_system.dart
+74
-0
platform.dart
packages/flutter_tools/lib/src/base/platform.dart
+29
-0
process_manager.dart
packages/flutter_tools/lib/src/base/process_manager.dart
+12
-32
flutter_command_runner.dart
.../flutter_tools/lib/src/runner/flutter_command_runner.dart
+14
-3
No files found.
packages/flutter_tools/lib/src/base/file_system.dart
View file @
9c05c345
...
...
@@ -5,14 +5,17 @@
import
'package:file/file.dart'
;
import
'package:file/local.dart'
;
import
'package:file/memory.dart'
;
import
'package:file/record_replay.dart'
;
import
'package:path/path.dart'
as
path
;
import
'common.dart'
show
throwToolExit
;
import
'context.dart'
;
import
'process.dart'
;
export
'package:file/file.dart'
;
export
'package:file/local.dart'
;
const
String
_kRecordingType
=
'file'
;
const
FileSystem
_kLocalFs
=
const
LocalFileSystem
();
/// Currently active implementation of the file system.
...
...
@@ -21,6 +24,36 @@ const FileSystem _kLocalFs = const LocalFileSystem();
/// with [MemoryFileSystem].
FileSystem
get
fs
=>
context
==
null
?
_kLocalFs
:
context
[
FileSystem
];
/// Enables recording of file system activity to the specified base recording
/// [location].
///
/// This sets the [active file system](fs) to one that records all invocation
/// activity before delegating to a [LocalFileSystem].
///
/// Activity will be recorded in a subdirectory of [location] named `"file"`.
/// It is permissible for [location] to represent an existing non-empty
/// directory as long as there is no collision with the `"file"` subdirectory.
void
enableRecordingFileSystem
(
String
location
)
{
Directory
dir
=
getRecordingSink
(
location
,
_kRecordingType
);
RecordingFileSystem
fileSystem
=
new
RecordingFileSystem
(
delegate:
_kLocalFs
,
destination:
dir
);
addShutdownHook
(()
=>
fileSystem
.
recording
.
flush
());
context
.
setVariable
(
FileSystem
,
fileSystem
);
}
/// Enables file system replay mode.
///
/// This sets the [active file system](fs) to one that replays invocation
/// activity from a previously recorded set of invocations.
///
/// [location] must represent a directory to which file system activity has
/// been recorded (i.e. the result of having been previously passed to
/// [enableRecordingFileSystem]), or a [ToolExit] will be thrown.
void
enableReplayFileSystem
(
String
location
)
{
Directory
dir
=
getReplaySource
(
location
,
_kRecordingType
);
context
.
setVariable
(
FileSystem
,
new
ReplayFileSystem
(
recording:
dir
));
}
/// Create the ancestor directories of a file path if they do not already exist.
void
ensureDirectoryExists
(
String
filePath
)
{
String
dirPath
=
path
.
dirname
(
filePath
);
...
...
@@ -56,3 +89,44 @@ void copyDirectorySync(Directory srcDir, Directory destDir) {
}
});
}
/// Gets a directory to act as a recording destination, creating the directory
/// as necessary.
///
/// The directory will exist in the local file system, be named [basename], and
/// be a child of the directory identified by [dirname].
///
/// If the target directory already exists as a directory, the existing
/// directory must be empty, or a [ToolExit] will be thrown. If the target
/// directory exists as an entity other than a directory, a [ToolExit] will
/// also be thrown.
Directory
getRecordingSink
(
String
dirname
,
String
basename
)
{
String
location
=
_kLocalFs
.
path
.
join
(
dirname
,
basename
);
switch
(
_kLocalFs
.
typeSync
(
location
,
followLinks:
false
))
{
case
FileSystemEntityType
.
FILE
:
case
FileSystemEntityType
.
LINK
:
throwToolExit
(
'Invalid record-to location:
$dirname
("
$basename
" exists as non-directory)'
);
break
;
case
FileSystemEntityType
.
DIRECTORY
:
if
(
_kLocalFs
.
directory
(
location
).
listSync
(
followLinks:
false
).
isNotEmpty
)
throwToolExit
(
'Invalid record-to location:
$dirname
("
$basename
" is not empty)'
);
break
;
case
FileSystemEntityType
.
NOT_FOUND
:
_kLocalFs
.
directory
(
location
).
createSync
(
recursive:
true
);
}
return
_kLocalFs
.
directory
(
location
);
}
/// Gets a directory that holds a saved recording to be used for the purpose of
/// replay.
///
/// The directory will exist in the local file system, be named [basename], and
/// be a child of the directory identified by [dirname].
///
/// If the target directory does not exist, a [ToolExit] will be thrown.
Directory
getReplaySource
(
String
dirname
,
String
basename
)
{
Directory
dir
=
_kLocalFs
.
directory
(
_kLocalFs
.
path
.
join
(
dirname
,
basename
));
if
(!
dir
.
existsSync
())
throwToolExit
(
'Invalid replay-from location:
$dirname
("
$basename
" does not exist)'
);
return
dir
;
}
packages/flutter_tools/lib/src/base/platform.dart
View file @
9c05c345
...
...
@@ -2,12 +2,41 @@
// 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:platform/platform.dart'
;
import
'context.dart'
;
import
'file_system.dart'
;
export
'package:platform/platform.dart'
;
const
Platform
_kLocalPlatform
=
const
LocalPlatform
();
const
String
_kRecordingType
=
'platform'
;
Platform
get
platform
=>
context
==
null
?
_kLocalPlatform
:
context
[
Platform
];
/// Enables serialization of the current [platform] to the specified base
/// recording [location].
///
/// Platform metadata will be recorded in a subdirectory of [location] named
/// `"platform"`. It is permissible for [location] to represent an existing
/// non-empty directory as long as there is no collision with the `"platform"`
/// subdirectory.
Future
<
Null
>
enableRecordingPlatform
(
String
location
)
async
{
Directory
dir
=
getRecordingSink
(
location
,
_kRecordingType
);
File
file
=
_getPlatformManifest
(
dir
);
await
file
.
writeAsString
(
platform
.
toJson
(),
flush:
true
);
}
Future
<
Null
>
enableReplayPlatform
(
String
location
)
async
{
Directory
dir
=
getReplaySource
(
location
,
_kRecordingType
);
File
file
=
_getPlatformManifest
(
dir
);
String
json
=
await
file
.
readAsString
();
context
.
setVariable
(
Platform
,
new
FakePlatform
.
fromJson
(
json
));
}
File
_getPlatformManifest
(
Directory
dir
)
{
String
path
=
dir
.
fileSystem
.
path
.
join
(
dir
.
path
,
'MANIFEST.txt'
);
return
dir
.
fileSystem
.
file
(
path
);
}
packages/flutter_tools/lib/src/base/process_manager.dart
View file @
9c05c345
...
...
@@ -12,42 +12,26 @@ import 'context.dart';
import
'file_system.dart'
;
import
'process.dart'
;
const
String
_kRecordingType
=
'process'
;
/// The active process manager.
ProcessManager
get
processManager
=>
context
[
ProcessManager
];
/// Enables recording of process invocation activity to the specified location.
/// Enables recording of process invocation activity to the specified base
/// recording [location].
///
/// This sets the [active process manager](processManager) to one that records
/// all process activity before delegating to a [LocalProcessManager].
///
/// [location] must either represent a valid, empty directory or a non-existent
/// file system entity, in which case a directory will be created at that path.
/// Process invocation activity will be serialized to opaque files in that
/// directory. The resulting (populated) directory will be suitable for use
/// with [enableReplayProcessManager].
/// Activity will be recorded in a subdirectory of [location] named `"process"`.
/// It is permissible for [location] to represent an existing non-empty
/// directory as long as there is no collision with the `"process"`
/// subdirectory.
void
enableRecordingProcessManager
(
String
location
)
{
if
(
location
.
isEmpty
)
throwToolExit
(
'record-to location not specified'
);
switch
(
fs
.
typeSync
(
location
,
followLinks:
false
))
{
case
FileSystemEntityType
.
FILE
:
case
FileSystemEntityType
.
LINK
:
throwToolExit
(
'record-to location must reference a directory'
);
break
;
case
FileSystemEntityType
.
DIRECTORY
:
if
(
fs
.
directory
(
location
).
listSync
(
followLinks:
false
).
isNotEmpty
)
throwToolExit
(
'record-to directory must be empty'
);
break
;
case
FileSystemEntityType
.
NOT_FOUND
:
fs
.
directory
(
location
).
createSync
(
recursive:
true
);
}
Directory
dir
=
fs
.
directory
(
location
);
Directory
dir
=
getRecordingSink
(
location
,
_kRecordingType
);
ProcessManager
delegate
=
new
LocalProcessManager
();
RecordingProcessManager
manager
=
new
RecordingProcessManager
(
delegate
,
dir
);
addShutdownHook
(()
async
{
await
manager
.
flush
(
finishRunningProcesses:
true
);
});
addShutdownHook
(()
=>
manager
.
flush
(
finishRunningProcesses:
true
));
context
.
setVariable
(
ProcessManager
,
manager
);
}
...
...
@@ -58,13 +42,9 @@ void enableRecordingProcessManager(String location) {
///
/// [location] must represent a directory to which process activity has been
/// recorded (i.e. the result of having been previously passed to
/// [enableRecordingProcessManager]).
/// [enableRecordingProcessManager])
, or a [ToolExit] will be thrown
.
Future
<
Null
>
enableReplayProcessManager
(
String
location
)
async
{
if
(
location
.
isEmpty
)
throwToolExit
(
'replay-from location not specified'
);
Directory
dir
=
fs
.
directory
(
location
);
if
(!
dir
.
existsSync
())
throwToolExit
(
'replay-from location must reference a directory'
);
Directory
dir
=
getReplaySource
(
location
,
_kRecordingType
);
ProcessManager
manager
;
try
{
...
...
packages/flutter_tools/lib/src/runner/flutter_command_runner.dart
View file @
9c05c345
...
...
@@ -100,7 +100,8 @@ class FlutterCommandRunner extends CommandRunner<Null> {
hide:
!
verboseHelp
,
help:
'Enables recording of process invocations (including stdout and stderr of all such invocations),
\n
'
'and serializes that recording to a directory with the path specified in this flag. If the
\n
'
'and file system access (reads and writes).
\n
'
'Serializes that recording to a directory with the path specified in this flag. If the
\n
'
'directory does not already exist, it will be created.'
);
argParser
.
addOption
(
'replay-from'
,
hide:
!
verboseHelp
,
...
...
@@ -163,11 +164,21 @@ class FlutterCommandRunner extends CommandRunner<Null> {
throwToolExit
(
'--record-to and --replay-from cannot be used together.'
);
if
(
globalResults
[
'record-to'
]
!=
null
)
{
enableRecordingProcessManager
(
globalResults
[
'record-to'
].
trim
());
String
recordTo
=
globalResults
[
'record-to'
].
trim
();
if
(
recordTo
.
isEmpty
)
throwToolExit
(
'record-to location not specified'
);
enableRecordingProcessManager
(
recordTo
);
enableRecordingFileSystem
(
recordTo
);
await
enableRecordingPlatform
(
recordTo
);
}
if
(
globalResults
[
'replay-from'
]
!=
null
)
{
await
enableReplayProcessManager
(
globalResults
[
'replay-from'
].
trim
());
String
replayFrom
=
globalResults
[
'replay-from'
].
trim
();
if
(
replayFrom
.
isEmpty
)
throwToolExit
(
'replay-from location not specified'
);
await
enableReplayProcessManager
(
replayFrom
);
enableReplayFileSystem
(
replayFrom
);
await
enableReplayPlatform
(
replayFrom
);
}
logger
.
quiet
=
globalResults
[
'quiet'
];
...
...
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