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
f877c97b
Unverified
Commit
f877c97b
authored
Sep 10, 2019
by
Jonah Williams
Committed by
GitHub
Sep 10, 2019
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Use persisted build information to automatically clean old outputs in assemble (#39654)
parent
03e81003
Changes
5
Show whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
235 additions
and
135 deletions
+235
-135
build_system.dart
...ages/flutter_tools/lib/src/build_system/build_system.dart
+188
-124
linux.dart
...ges/flutter_tools/lib/src/build_system/targets/linux.dart
+0
-1
macos.dart
...ges/flutter_tools/lib/src/build_system/targets/macos.dart
+0
-8
windows.dart
...s/flutter_tools/lib/src/build_system/targets/windows.dart
+0
-1
build_system_test.dart
...ls/test/general.shard/build_system/build_system_test.dart
+47
-1
No files found.
packages/flutter_tools/lib/src/build_system/build_system.dart
View file @
f877c97b
...
@@ -115,96 +115,19 @@ abstract class Target {
...
@@ -115,96 +115,19 @@ abstract class Target {
/// The action which performs this build step.
/// The action which performs this build step.
Future
<
void
>
build
(
Environment
environment
);
Future
<
void
>
build
(
Environment
environment
);
/// Collect hashes for all inputs to determine if any have changed.
/// Create a [Node] with resolved inputs and outputs.
///
Node
_toNode
(
Environment
environment
)
{
/// Returns whether this target can be skipped.
final
List
<
File
>
inputs
=
resolveInputs
(
environment
);
Future
<
bool
>
computeChanges
(
final
List
<
File
>
outputs
=
resolveOutputs
(
environment
);
List
<
File
>
inputs
,
return
Node
(
Environment
environment
,
this
,
FileHashStore
fileHashStore
,
inputs
,
)
async
{
outputs
,
final
File
stamp
=
_findStampFile
(
environment
);
<
Node
>[
final
Set
<
String
>
previousInputs
=
<
String
>{};
for
(
Target
target
in
dependencies
)
target
.
_toNode
(
environment
)
final
List
<
String
>
previousOutputs
=
<
String
>[];
],
bool
canSkip
=
true
;
environment
);
// If the stamp file doesn't exist, we haven't run this step before and
// all inputs were added.
if
(
stamp
.
existsSync
())
{
final
String
content
=
stamp
.
readAsStringSync
();
// Something went wrong writing the stamp file.
if
(
content
==
null
||
content
.
isEmpty
)
{
stamp
.
deleteSync
();
// Malformed stamp file, not safe to skip.
canSkip
=
false
;
}
else
{
final
Map
<
String
,
Object
>
values
=
json
.
decode
(
content
);
final
List
<
Object
>
inputs
=
values
[
'inputs'
];
final
List
<
Object
>
outputs
=
values
[
'outputs'
];
inputs
.
cast
<
String
>().
forEach
(
previousInputs
.
add
);
outputs
.
cast
<
String
>().
forEach
(
previousOutputs
.
add
);
}
}
else
{
// No stamp file, not safe to skip.
canSkip
=
false
;
}
// For each input, first determine if we've already computed the hash
// for it. Then collect it to be sent off for hashing as a group.
final
List
<
File
>
sourcesToHash
=
<
File
>[];
final
List
<
File
>
missingInputs
=
<
File
>[];
for
(
File
file
in
inputs
)
{
if
(!
file
.
existsSync
())
{
missingInputs
.
add
(
file
);
continue
;
}
final
String
absolutePath
=
file
.
resolveSymbolicLinksSync
();
final
String
previousHash
=
fileHashStore
.
previousHashes
[
absolutePath
];
if
(
fileHashStore
.
currentHashes
.
containsKey
(
absolutePath
))
{
final
String
currentHash
=
fileHashStore
.
currentHashes
[
absolutePath
];
if
(
currentHash
!=
previousHash
)
{
canSkip
=
false
;
}
}
else
{
sourcesToHash
.
add
(
file
);
}
}
// For each output, first determine if we've already computed the hash
// for it. Then collect it to be sent off for hashing as a group.
for
(
String
previousOutput
in
previousOutputs
)
{
final
File
file
=
fs
.
file
(
previousOutput
);
if
(!
file
.
existsSync
())
{
canSkip
=
false
;
continue
;
}
final
String
absolutePath
=
file
.
resolveSymbolicLinksSync
();
final
String
previousHash
=
fileHashStore
.
previousHashes
[
absolutePath
];
if
(
fileHashStore
.
currentHashes
.
containsKey
(
absolutePath
))
{
final
String
currentHash
=
fileHashStore
.
currentHashes
[
absolutePath
];
if
(
currentHash
!=
previousHash
)
{
canSkip
=
false
;
}
}
else
{
sourcesToHash
.
add
(
file
);
}
}
// If we depend on a file that doesnt exist on disk, kill the build.
if
(
missingInputs
.
isNotEmpty
)
{
throw
MissingInputException
(
missingInputs
,
name
);
}
// If we have files to hash, compute them asynchronously and then
// update the result.
if
(
sourcesToHash
.
isNotEmpty
)
{
final
List
<
File
>
dirty
=
await
fileHashStore
.
hashFiles
(
sourcesToHash
);
if
(
dirty
.
isNotEmpty
)
{
canSkip
=
false
;
}
}
return
canSkip
;
}
}
/// Invoke to remove the stamp file if the [buildAction] threw an exception;
/// Invoke to remove the stamp file if the [buildAction] threw an exception;
...
@@ -253,12 +176,8 @@ abstract class Target {
...
@@ -253,12 +176,8 @@ abstract class Target {
/// which uses functions, behaviors, or patterns.
/// which uses functions, behaviors, or patterns.
List
<
File
>
resolveOutputs
(
List
<
File
>
resolveOutputs
(
Environment
environment
,
Environment
environment
,
{
bool
implicit
=
true
,
}
)
{
)
{
final
List
<
File
>
outputEntities
=
_resolveConfiguration
(
outputs
,
environment
,
implicit:
implicit
,
inputs:
false
);
final
List
<
File
>
outputEntities
=
_resolveConfiguration
(
outputs
,
environment
,
inputs:
false
);
if
(
implicit
)
{
verifyOutputDirectories
(
outputEntities
,
environment
,
this
);
}
return
outputEntities
;
return
outputEntities
;
}
}
...
@@ -279,9 +198,9 @@ abstract class Target {
...
@@ -279,9 +198,9 @@ abstract class Target {
'name'
:
name
,
'name'
:
name
,
'dependencies'
:
dependencies
.
map
((
Target
target
)
=>
target
.
name
).
toList
(),
'dependencies'
:
dependencies
.
map
((
Target
target
)
=>
target
.
name
).
toList
(),
'inputs'
:
resolveInputs
(
environment
)
'inputs'
:
resolveInputs
(
environment
)
.
map
((
File
file
)
=>
file
.
resolveSymbolicLinksSync
()
)
.
map
((
File
file
)
=>
file
.
path
)
.
toList
(),
.
toList
(),
'outputs'
:
resolveOutputs
(
environment
,
implicit:
false
)
'outputs'
:
resolveOutputs
(
environment
)
.
map
((
File
file
)
=>
file
.
path
)
.
map
((
File
file
)
=>
file
.
path
)
.
toList
(),
.
toList
(),
'stamp'
:
_findStampFile
(
environment
).
absolute
.
path
,
'stamp'
:
_findStampFile
(
environment
).
absolute
.
path
,
...
@@ -484,10 +403,11 @@ class BuildSystem {
...
@@ -484,10 +403,11 @@ class BuildSystem {
// Perform sanity checks on build.
// Perform sanity checks on build.
checkCycles
(
target
);
checkCycles
(
target
);
final
Node
node
=
target
.
_toNode
(
environment
);
final
_BuildInstance
buildInstance
=
_BuildInstance
(
environment
,
fileCache
,
buildSystemConfig
);
final
_BuildInstance
buildInstance
=
_BuildInstance
(
environment
,
fileCache
,
buildSystemConfig
);
bool
passed
=
true
;
bool
passed
=
true
;
try
{
try
{
passed
=
await
buildInstance
.
invokeTarget
(
target
);
passed
=
await
buildInstance
.
invokeTarget
(
node
);
}
finally
{
}
finally
{
// Always persist the file cache to disk.
// Always persist the file cache to disk.
fileCache
.
persist
();
fileCache
.
persist
();
...
@@ -543,24 +463,23 @@ class _BuildInstance {
...
@@ -543,24 +463,23 @@ class _BuildInstance {
// Exceptions caught during the build process.
// Exceptions caught during the build process.
final
Map
<
String
,
ExceptionMeasurement
>
exceptionMeasurements
=
<
String
,
ExceptionMeasurement
>{};
final
Map
<
String
,
ExceptionMeasurement
>
exceptionMeasurements
=
<
String
,
ExceptionMeasurement
>{};
Future
<
bool
>
invokeTarget
(
Target
target
)
async
{
Future
<
bool
>
invokeTarget
(
Node
node
)
async
{
final
List
<
bool
>
results
=
await
Future
.
wait
(
target
.
dependencies
.
map
(
invokeTarget
));
final
List
<
bool
>
results
=
await
Future
.
wait
(
node
.
dependencies
.
map
(
invokeTarget
));
if
(
results
.
any
((
bool
result
)
=>
!
result
))
{
if
(
results
.
any
((
bool
result
)
=>
!
result
))
{
return
false
;
return
false
;
}
}
final
AsyncMemoizer
<
bool
>
memoizer
=
pending
[
target
.
name
]
??=
AsyncMemoizer
<
bool
>();
final
AsyncMemoizer
<
bool
>
memoizer
=
pending
[
node
.
target
.
name
]
??=
AsyncMemoizer
<
bool
>();
return
memoizer
.
runOnce
(()
=>
_invokeInternal
(
target
));
return
memoizer
.
runOnce
(()
=>
_invokeInternal
(
node
));
}
}
Future
<
bool
>
_invokeInternal
(
Target
target
)
async
{
Future
<
bool
>
_invokeInternal
(
Node
node
)
async
{
final
PoolResource
resource
=
await
resourcePool
.
request
();
final
PoolResource
resource
=
await
resourcePool
.
request
();
final
Stopwatch
stopwatch
=
Stopwatch
()..
start
();
final
Stopwatch
stopwatch
=
Stopwatch
()..
start
();
bool
passed
=
true
;
bool
passed
=
true
;
bool
skipped
=
false
;
bool
skipped
=
false
;
try
{
try
{
final
List
<
File
>
inputs
=
target
.
resolveInputs
(
environment
);
final
bool
canSkip
=
await
node
.
computeChanges
(
environment
,
fileCache
);
final
bool
canSkip
=
await
target
.
computeChanges
(
inputs
,
environment
,
fileCache
);
for
(
File
input
in
node
.
inputs
)
{
for
(
File
input
in
inputs
)
{
// The build system should produce a list of aggregate input and output
// The build system should produce a list of aggregate input and output
// files for the overall build. The goal is to provide this to a hosting
// files for the overall build. The goal is to provide this to a hosting
// build system, such as Xcode, to configure logic for when to skip the
// build system, such as Xcode, to configure logic for when to skip the
...
@@ -578,35 +497,39 @@ class _BuildInstance {
...
@@ -578,35 +497,39 @@ class _BuildInstance {
}
}
if
(
canSkip
)
{
if
(
canSkip
)
{
skipped
=
true
;
skipped
=
true
;
printStatus
(
'Skipping target:
${target.name}
'
);
printStatus
(
'Skipping target:
${node.target.name}
'
);
final
List
<
File
>
outputs
=
target
.
resolveOutputs
(
environment
,
implicit:
true
);
for
(
File
output
in
node
.
outputs
)
{
for
(
File
output
in
outputs
)
{
outputFiles
[
output
.
path
]
=
output
;
outputFiles
[
output
.
resolveSymbolicLinksSync
()]
=
output
;
}
}
}
else
{
}
else
{
printStatus
(
'
${target.name}
: Starting'
);
printStatus
(
'
${
node.
target.name}
: Starting'
);
await
target
.
build
(
environment
);
await
node
.
target
.
build
(
environment
);
printStatus
(
'
${target.name}
: Complete'
);
printStatus
(
'
${
node.
target.name}
: Complete'
);
final
List
<
File
>
outputs
=
target
.
resolveOutputs
(
environment
,
implicit:
true
);
// Update hashes for output files.
// Update hashes for output files.
await
fileCache
.
hashFiles
(
outputs
);
await
fileCache
.
hashFiles
(
node
.
outputs
);
target
.
_writeStamp
(
inputs
,
outputs
,
environment
);
node
.
target
.
_writeStamp
(
node
.
inputs
,
node
.
outputs
,
environment
);
for
(
File
output
in
outputs
)
{
for
(
File
output
in
node
.
outputs
)
{
outputFiles
[
output
.
resolveSymbolicLinksSync
()]
=
output
;
outputFiles
[
output
.
path
]
=
output
;
}
// Delete outputs from previous stages that are no longer a part of the build.
for
(
String
previousOutput
in
node
.
previousOutputs
)
{
if
(!
outputFiles
.
containsKey
(
previousOutput
))
{
fs
.
file
(
previousOutput
).
deleteSync
();
}
}
}
}
}
}
catch
(
exception
,
stackTrace
)
{
}
catch
(
exception
,
stackTrace
)
{
target
.
clearStamp
(
environment
);
node
.
target
.
clearStamp
(
environment
);
passed
=
false
;
passed
=
false
;
skipped
=
false
;
skipped
=
false
;
exceptionMeasurements
[
target
.
name
]
=
ExceptionMeasurement
(
exceptionMeasurements
[
node
.
target
.
name
]
=
ExceptionMeasurement
(
target
.
name
,
exception
,
stackTrace
);
node
.
target
.
name
,
exception
,
stackTrace
);
}
finally
{
}
finally
{
resource
.
release
();
resource
.
release
();
stopwatch
.
stop
();
stopwatch
.
stop
();
stepTimings
[
target
.
name
]
=
PerformanceMeasurement
(
stepTimings
[
node
.
target
.
name
]
=
PerformanceMeasurement
(
target
.
name
,
stopwatch
.
elapsedMilliseconds
,
skipped
,
passed
);
node
.
target
.
name
,
stopwatch
.
elapsedMilliseconds
,
skipped
,
passed
);
}
}
return
passed
;
return
passed
;
}
}
...
@@ -661,7 +584,7 @@ void verifyOutputDirectories(List<File> outputs, Environment environment, Target
...
@@ -661,7 +584,7 @@ void verifyOutputDirectories(List<File> outputs, Environment environment, Target
missingOutputs
.
add
(
sourceFile
);
missingOutputs
.
add
(
sourceFile
);
continue
;
continue
;
}
}
final
String
path
=
sourceFile
.
resolveSymbolicLinksSync
()
;
final
String
path
=
sourceFile
.
path
;
if
(!
path
.
startsWith
(
buildDirectory
)
&&
!
path
.
startsWith
(
projectDirectory
))
{
if
(!
path
.
startsWith
(
buildDirectory
)
&&
!
path
.
startsWith
(
projectDirectory
))
{
throw
MisplacedOutputException
(
path
,
target
.
name
);
throw
MisplacedOutputException
(
path
,
target
.
name
);
}
}
...
@@ -670,3 +593,144 @@ void verifyOutputDirectories(List<File> outputs, Environment environment, Target
...
@@ -670,3 +593,144 @@ void verifyOutputDirectories(List<File> outputs, Environment environment, Target
throw
MissingOutputException
(
missingOutputs
,
target
.
name
);
throw
MissingOutputException
(
missingOutputs
,
target
.
name
);
}
}
}
}
/// A node in the build graph.
class
Node
{
Node
(
this
.
target
,
this
.
inputs
,
this
.
outputs
,
this
.
dependencies
,
Environment
environment
)
{
final
File
stamp
=
target
.
_findStampFile
(
environment
);
// If the stamp file doesn't exist, we haven't run this step before and
// all inputs were added.
if
(!
stamp
.
existsSync
())
{
// No stamp file, not safe to skip.
_dirty
=
true
;
return
;
}
final
String
content
=
stamp
.
readAsStringSync
();
// Something went wrong writing the stamp file.
if
(
content
==
null
||
content
.
isEmpty
)
{
stamp
.
deleteSync
();
// Malformed stamp file, not safe to skip.
_dirty
=
true
;
return
;
}
Map
<
String
,
Object
>
values
;
try
{
values
=
json
.
decode
(
content
);
}
on
FormatException
{
// The json is malformed in some way.
_dirty
=
true
;
return
;
}
final
Object
inputs
=
values
[
'inputs'
];
final
Object
outputs
=
values
[
'outputs'
];
if
(
inputs
is
List
<
Object
>
&&
outputs
is
List
<
Object
>)
{
inputs
?.
cast
<
String
>()?.
forEach
(
previousInputs
.
add
);
outputs
?.
cast
<
String
>()?.
forEach
(
previousOutputs
.
add
);
}
else
{
// The json is malformed in some way.
_dirty
=
true
;
}
}
/// The resolved input files.
///
/// These files may not yet exist if they are produced by previous steps.
final
List
<
File
>
inputs
;
/// The resolved output files.
///
/// These files may not yet exist if the target hasn't run yet.
final
List
<
File
>
outputs
;
/// The target definition which contains the build action to invoke.
final
Target
target
;
/// All of the nodes that this one depends on.
final
List
<
Node
>
dependencies
;
/// Output file paths from the previous invocation of this build node.
final
Set
<
String
>
previousOutputs
=
<
String
>{};
/// Inout file paths from the previous invocation of this build node.
final
Set
<
String
>
previousInputs
=
<
String
>{};
/// Whether this node needs an action performed.
bool
get
dirty
=>
_dirty
;
bool
_dirty
=
false
;
/// Collect hashes for all inputs to determine if any have changed.
///
/// Returns whether this target can be skipped.
Future
<
bool
>
computeChanges
(
Environment
environment
,
FileHashStore
fileHashStore
,
)
async
{
final
Set
<
String
>
currentOutputPaths
=
<
String
>{
for
(
File
file
in
outputs
)
file
.
path
};
// For each input, first determine if we've already computed the hash
// for it. Then collect it to be sent off for hashing as a group.
final
List
<
File
>
sourcesToHash
=
<
File
>[];
final
List
<
File
>
missingInputs
=
<
File
>[];
for
(
File
file
in
inputs
)
{
if
(!
file
.
existsSync
())
{
missingInputs
.
add
(
file
);
continue
;
}
final
String
absolutePath
=
file
.
path
;
final
String
previousHash
=
fileHashStore
.
previousHashes
[
absolutePath
];
if
(
fileHashStore
.
currentHashes
.
containsKey
(
absolutePath
))
{
final
String
currentHash
=
fileHashStore
.
currentHashes
[
absolutePath
];
if
(
currentHash
!=
previousHash
)
{
_dirty
=
true
;
}
}
else
{
sourcesToHash
.
add
(
file
);
}
}
// For each output, first determine if we've already computed the hash
// for it. Then collect it to be sent off for hashing as a group.
for
(
String
previousOutput
in
previousOutputs
)
{
// output paths changed.
if
(!
currentOutputPaths
.
contains
(
previousOutput
))
{
_dirty
=
true
;
// if this isn't a current output file there is no reason to compute the hash.
continue
;
}
final
File
file
=
fs
.
file
(
previousOutput
);
if
(!
file
.
existsSync
())
{
_dirty
=
true
;
continue
;
}
final
String
absolutePath
=
file
.
path
;
final
String
previousHash
=
fileHashStore
.
previousHashes
[
absolutePath
];
if
(
fileHashStore
.
currentHashes
.
containsKey
(
absolutePath
))
{
final
String
currentHash
=
fileHashStore
.
currentHashes
[
absolutePath
];
if
(
currentHash
!=
previousHash
)
{
_dirty
=
true
;
}
}
else
{
sourcesToHash
.
add
(
file
);
}
}
// If we depend on a file that doesnt exist on disk, kill the build.
if
(
missingInputs
.
isNotEmpty
)
{
throw
MissingInputException
(
missingInputs
,
target
.
name
);
}
// If we have files to hash, compute them asynchronously and then
// update the result.
if
(
sourcesToHash
.
isNotEmpty
)
{
final
List
<
File
>
dirty
=
await
fileHashStore
.
hashFiles
(
sourcesToHash
);
if
(
dirty
.
isNotEmpty
)
{
_dirty
=
true
;
}
}
return
!
_dirty
;
}
}
packages/flutter_tools/lib/src/build_system/targets/linux.dart
View file @
f877c97b
...
@@ -29,7 +29,6 @@ class UnpackLinux extends Target {
...
@@ -29,7 +29,6 @@ class UnpackLinux extends Target {
Source
.
pattern
(
'{PROJECT_DIR}/linux/flutter/flutter_plugin_registrar.h'
),
Source
.
pattern
(
'{PROJECT_DIR}/linux/flutter/flutter_plugin_registrar.h'
),
Source
.
pattern
(
'{PROJECT_DIR}/linux/flutter/flutter_glfw.h'
),
Source
.
pattern
(
'{PROJECT_DIR}/linux/flutter/flutter_glfw.h'
),
Source
.
pattern
(
'{PROJECT_DIR}/linux/flutter/icudtl.dat'
),
Source
.
pattern
(
'{PROJECT_DIR}/linux/flutter/icudtl.dat'
),
Source
.
pattern
(
'{PROJECT_DIR}/linux/flutter/cpp_client_wrapper_glfw/*'
),
];
];
@override
@override
...
...
packages/flutter_tools/lib/src/build_system/targets/macos.dart
View file @
f877c97b
...
@@ -122,9 +122,6 @@ abstract class UnpackMacOS extends Target {
...
@@ -122,9 +122,6 @@ abstract class UnpackMacOS extends Target {
final
Directory
targetDirectory
=
environment
final
Directory
targetDirectory
=
environment
.
outputDir
.
outputDir
.
childDirectory
(
'FlutterMacOS.framework'
);
.
childDirectory
(
'FlutterMacOS.framework'
);
if
(
targetDirectory
.
existsSync
())
{
targetDirectory
.
deleteSync
(
recursive:
true
);
}
final
ProcessResult
result
=
await
processManager
final
ProcessResult
result
=
await
processManager
.
run
(<
String
>[
'cp'
,
'-R'
,
basePath
,
targetDirectory
.
path
]);
.
run
(<
String
>[
'cp'
,
'-R'
,
basePath
,
targetDirectory
.
path
]);
...
@@ -325,11 +322,6 @@ abstract class MacOSBundleFlutterAssets extends Target {
...
@@ -325,11 +322,6 @@ abstract class MacOSBundleFlutterAssets extends Target {
final
Directory
assetDirectory
=
outputDirectory
final
Directory
assetDirectory
=
outputDirectory
.
childDirectory
(
'Resources'
)
.
childDirectory
(
'Resources'
)
.
childDirectory
(
'flutter_assets'
);
.
childDirectory
(
'flutter_assets'
);
// We're not smart enough to only remove assets that are removed. If
// anything changes blow away the whole directory.
if
(
assetDirectory
.
existsSync
())
{
assetDirectory
.
deleteSync
(
recursive:
true
);
}
assetDirectory
.
createSync
(
recursive:
true
);
assetDirectory
.
createSync
(
recursive:
true
);
final
AssetBundle
assetBundle
=
AssetBundleFactory
.
instance
.
createBundle
();
final
AssetBundle
assetBundle
=
AssetBundleFactory
.
instance
.
createBundle
();
final
int
result
=
await
assetBundle
.
build
(
final
int
result
=
await
assetBundle
.
build
(
...
...
packages/flutter_tools/lib/src/build_system/targets/windows.dart
View file @
f877c97b
...
@@ -32,7 +32,6 @@ class UnpackWindows extends Target {
...
@@ -32,7 +32,6 @@ class UnpackWindows extends Target {
Source
.
pattern
(
'{PROJECT_DIR}/windows/flutter/flutter_plugin_registrar.h'
),
Source
.
pattern
(
'{PROJECT_DIR}/windows/flutter/flutter_plugin_registrar.h'
),
Source
.
pattern
(
'{PROJECT_DIR}/windows/flutter/flutter_windows.h'
),
Source
.
pattern
(
'{PROJECT_DIR}/windows/flutter/flutter_windows.h'
),
Source
.
pattern
(
'{PROJECT_DIR}/windows/flutter/icudtl.dat'
),
Source
.
pattern
(
'{PROJECT_DIR}/windows/flutter/icudtl.dat'
),
Source
.
pattern
(
'{PROJECT_DIR}/windows/flutter/cpp_client_wrapper/*'
),
];
];
@override
@override
...
...
packages/flutter_tools/test/general.shard/build_system/build_system_test.dart
View file @
f877c97b
...
@@ -126,7 +126,7 @@ void main() {
...
@@ -126,7 +126,7 @@ void main() {
final
BuildResult
result
=
await
buildSystem
.
build
(
badTarget
,
environment
);
final
BuildResult
result
=
await
buildSystem
.
build
(
badTarget
,
environment
);
expect
(
result
.
hasException
,
true
);
expect
(
result
.
hasException
,
true
);
expect
(
result
.
exceptions
.
values
.
single
.
exception
,
isInstanceOf
<
MissingOutput
Exception
>());
expect
(
result
.
exceptions
.
values
.
single
.
exception
,
isInstanceOf
<
FileSystem
Exception
>());
}));
}));
test
(
'Saves a stamp file with inputs and outputs'
,
()
=>
testbed
.
run
(()
async
{
test
(
'Saves a stamp file with inputs and outputs'
,
()
=>
testbed
.
run
(()
async
{
...
@@ -211,6 +211,52 @@ void main() {
...
@@ -211,6 +211,52 @@ void main() {
expect
(
shared
,
1
);
expect
(
shared
,
1
);
}));
}));
test
(
'Automatically cleans old outputs when dag changes'
,
()
=>
testbed
.
run
(()
async
{
final
TestTarget
testTarget
=
TestTarget
((
Environment
envionment
)
async
{
environment
.
buildDir
.
childFile
(
'foo.out'
).
createSync
();
})
..
inputs
=
const
<
Source
>[
Source
.
pattern
(
'{PROJECT_DIR}/foo.dart'
)]
..
outputs
=
const
<
Source
>[
Source
.
pattern
(
'{BUILD_DIR}/foo.out'
)];
fs
.
file
(
'foo.dart'
).
createSync
();
await
buildSystem
.
build
(
testTarget
,
environment
);
expect
(
environment
.
buildDir
.
childFile
(
'foo.out'
).
existsSync
(),
true
);
final
TestTarget
testTarget2
=
TestTarget
((
Environment
envionment
)
async
{
environment
.
buildDir
.
childFile
(
'bar.out'
).
createSync
();
})
..
inputs
=
const
<
Source
>[
Source
.
pattern
(
'{PROJECT_DIR}/foo.dart'
)]
..
outputs
=
const
<
Source
>[
Source
.
pattern
(
'{BUILD_DIR}/bar.out'
)];
await
buildSystem
.
build
(
testTarget2
,
environment
);
expect
(
environment
.
buildDir
.
childFile
(
'bar.out'
).
existsSync
(),
true
);
expect
(
environment
.
buildDir
.
childFile
(
'foo.out'
).
existsSync
(),
false
);
}));
test
(
'reruns build if stamp is corrupted'
,
()
=>
testbed
.
run
(()
async
{
final
TestTarget
testTarget
=
TestTarget
((
Environment
envionment
)
async
{
environment
.
buildDir
.
childFile
(
'foo.out'
).
createSync
();
})
..
inputs
=
const
<
Source
>[
Source
.
pattern
(
'{PROJECT_DIR}/foo.dart'
)]
..
outputs
=
const
<
Source
>[
Source
.
pattern
(
'{BUILD_DIR}/foo.out'
)];
fs
.
file
(
'foo.dart'
).
createSync
();
await
buildSystem
.
build
(
testTarget
,
environment
);
// invalid JSON
environment
.
buildDir
.
childFile
(
'test.stamp'
).
writeAsStringSync
(
'{X'
);
await
buildSystem
.
build
(
testTarget
,
environment
);
// empty file
environment
.
buildDir
.
childFile
(
'test.stamp'
).
writeAsStringSync
(
''
);
await
buildSystem
.
build
(
testTarget
,
environment
);
// invalid format
environment
.
buildDir
.
childFile
(
'test.stamp'
).
writeAsStringSync
(
'{"inputs": 2, "outputs": 3}'
);
await
buildSystem
.
build
(
testTarget
,
environment
);
}));
test
(
'handles a throwing build action'
,
()
=>
testbed
.
run
(()
async
{
test
(
'handles a throwing build action'
,
()
=>
testbed
.
run
(()
async
{
final
BuildResult
result
=
await
buildSystem
.
build
(
fizzTarget
,
environment
);
final
BuildResult
result
=
await
buildSystem
.
build
(
fizzTarget
,
environment
);
...
...
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