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
21861423
Unverified
Commit
21861423
authored
Oct 03, 2022
by
Gary Qian
Committed by
GitHub
Oct 03, 2022
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[flutter_tools] analyze --suggestions --machine command (#112217)
parent
1a93ed3a
Changes
8
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
310 additions
and
15 deletions
+310
-15
executable.dart
packages/flutter_tools/lib/executable.dart
+8
-1
analyze.dart
packages/flutter_tools/lib/src/commands/analyze.dart
+13
-0
validate_project.dart
...ages/flutter_tools/lib/src/commands/validate_project.dart
+27
-7
project_validator.dart
packages/flutter_tools/lib/src/project_validator.dart
+178
-0
flutter_command_runner.dart
.../flutter_tools/lib/src/runner/flutter_command_runner.dart
+2
-3
analyze_suggestion_test.dart
...test/commands.shard/hermetic/analyze_suggestion_test.dart
+3
-3
args_test.dart
packages/flutter_tools/test/general.shard/args_test.dart
+1
-1
analyze_suggestions_integration_test.dart
...tegration.shard/analyze_suggestions_integration_test.dart
+78
-0
No files found.
packages/flutter_tools/lib/executable.dart
View file @
21861423
...
...
@@ -144,7 +144,14 @@ List<FlutterCommand> generateCommands({
terminal:
globals
.
terminal
,
artifacts:
globals
.
artifacts
!,
// new ProjectValidators should be added here for the --suggestions to run
allProjectValidators:
<
ProjectValidator
>[
GeneralInfoProjectValidator
()],
allProjectValidators:
<
ProjectValidator
>[
GeneralInfoProjectValidator
(),
VariableDumpMachineProjectValidator
(
logger:
globals
.
logger
,
fileSystem:
globals
.
fs
,
platform:
globals
.
platform
,
),
],
),
AssembleCommand
(
verboseHelp:
verboseHelp
,
buildSystem:
globals
.
buildSystem
),
AttachCommand
(
verboseHelp:
verboseHelp
),
...
...
packages/flutter_tools/lib/src/commands/analyze.dart
View file @
21861423
...
...
@@ -66,6 +66,12 @@ class AnalyzeCommand extends FlutterCommand {
argParser
.
addFlag
(
'suggestions'
,
help:
'Show suggestions about the current flutter project.'
);
argParser
.
addFlag
(
'machine'
,
negatable:
false
,
help:
'Dumps a JSON with a subset of relevant data about the tool, project, '
'and environment.'
,
hide:
!
verboseHelp
,
);
// Hidden option to enable a benchmarking mode.
argParser
.
addFlag
(
'benchmark'
,
...
...
@@ -128,12 +134,18 @@ class AnalyzeCommand extends FlutterCommand {
return
false
;
}
// Don't run pub if asking for machine output.
if
(
boolArg
(
'machine'
)
!=
null
&&
boolArg
(
'machine'
)!)
{
return
false
;
}
return
super
.
shouldRunPub
;
}
@override
Future
<
FlutterCommandResult
>
runCommand
()
async
{
final
bool
?
suggestionFlag
=
boolArg
(
'suggestions'
);
final
bool
machineFlag
=
boolArg
(
'machine'
)
??
false
;
if
(
suggestionFlag
!=
null
&&
suggestionFlag
==
true
)
{
final
String
directoryPath
;
final
bool
?
watchFlag
=
boolArg
(
'watch'
);
...
...
@@ -159,6 +171,7 @@ class AnalyzeCommand extends FlutterCommand {
allProjectValidators:
_allProjectValidators
,
userPath:
directoryPath
,
processManager:
_processManager
,
machine:
machineFlag
,
).
run
();
}
else
if
(
boolArgDeprecated
(
'watch'
))
{
await
AnalyzeContinuously
(
...
...
packages/flutter_tools/lib/src/commands/validate_project.dart
View file @
21861423
...
...
@@ -19,11 +19,13 @@ class ValidateProject {
required
this
.
userPath
,
required
this
.
processManager
,
this
.
verbose
=
false
,
this
.
machine
=
false
,
});
final
FileSystem
fileSystem
;
final
Logger
logger
;
final
bool
verbose
;
final
bool
machine
;
final
String
userPath
;
final
List
<
ProjectValidator
>
allProjectValidators
;
final
ProcessManager
processManager
;
...
...
@@ -36,6 +38,9 @@ class ValidateProject {
bool
hasCrash
=
false
;
for
(
final
ProjectValidator
validator
in
allProjectValidators
)
{
if
(
validator
.
machineOutput
!=
machine
)
{
continue
;
}
if
(!
results
.
containsKey
(
validator
)
&&
validator
.
supportsProject
(
project
))
{
results
[
validator
]
=
validator
.
start
(
project
).
catchError
((
Object
exception
,
StackTrace
trace
)
{
hasCrash
=
true
;
...
...
@@ -45,15 +50,30 @@ class ValidateProject {
}
final
StringBuffer
buffer
=
StringBuffer
();
final
List
<
String
>
resultsString
=
<
String
>[];
for
(
final
ProjectValidator
validator
in
results
.
keys
)
{
if
(
results
[
validator
]
!=
null
)
{
resultsString
.
add
(
validator
.
title
);
addResultString
(
validator
.
title
,
await
results
[
validator
],
resultsString
);
if
(
machine
)
{
// Print properties
buffer
.
write
(
'{
\n
'
);
for
(
final
Future
<
List
<
ProjectValidatorResult
>>
resultListFuture
in
results
.
values
)
{
final
List
<
ProjectValidatorResult
>
resultList
=
await
resultListFuture
;
int
count
=
0
;
for
(
final
ProjectValidatorResult
result
in
resultList
)
{
count
++;
buffer
.
write
(
' "
${result.name}
":
${result.value}${count < resultList.length ? ',' : ''}
\n
'
);
}
}
buffer
.
write
(
'}'
);
logger
.
printStatus
(
buffer
.
toString
());
}
else
{
final
List
<
String
>
resultsString
=
<
String
>[];
for
(
final
ProjectValidator
validator
in
results
.
keys
)
{
if
(
results
[
validator
]
!=
null
)
{
resultsString
.
add
(
validator
.
title
);
addResultString
(
validator
.
title
,
await
results
[
validator
],
resultsString
);
}
}
buffer
.
writeAll
(
resultsString
,
'
\n
'
);
logger
.
printBox
(
buffer
.
toString
());
}
buffer
.
writeAll
(
resultsString
,
'
\n
'
);
logger
.
printBox
(
buffer
.
toString
());
if
(
hasCrash
)
{
return
const
FlutterCommandResult
(
ExitStatus
.
fail
);
...
...
packages/flutter_tools/lib/src/project_validator.dart
View file @
21861423
...
...
@@ -6,21 +6,199 @@ import 'dart:collection';
import
'package:process/process.dart'
;
import
'base/file_system.dart'
;
import
'base/io.dart'
;
import
'base/logger.dart'
;
import
'base/platform.dart'
;
import
'cache.dart'
;
import
'convert.dart'
;
import
'dart_pub_json_formatter.dart'
;
import
'flutter_manifest.dart'
;
import
'project.dart'
;
import
'project_validator_result.dart'
;
import
'version.dart'
;
abstract
class
ProjectValidator
{
const
ProjectValidator
();
String
get
title
;
bool
get
machineOutput
=>
false
;
bool
supportsProject
(
FlutterProject
project
);
/// Can return more than one result in case a file/command have a lot of info to share to the user
Future
<
List
<
ProjectValidatorResult
>>
start
(
FlutterProject
project
);
}
abstract
class
MachineProjectValidator
extends
ProjectValidator
{
const
MachineProjectValidator
();
@override
bool
get
machineOutput
=>
true
;
}
/// Validator run for all platforms that extract information from the pubspec.yaml.
///
/// Specific info from different platforms should be written in their own ProjectValidator.
class
VariableDumpMachineProjectValidator
extends
MachineProjectValidator
{
VariableDumpMachineProjectValidator
({
required
this
.
logger
,
required
this
.
fileSystem
,
required
this
.
platform
,
});
final
Logger
logger
;
final
FileSystem
fileSystem
;
final
Platform
platform
;
String
_toJsonValue
(
Object
?
obj
)
{
String
value
=
obj
.
toString
();
if
(
obj
is
String
)
{
value
=
'"
$obj
"'
;
}
value
=
value
.
replaceAll
(
r'\'
,
r'\\'
);
return
value
;
}
@override
Future
<
List
<
ProjectValidatorResult
>>
start
(
FlutterProject
project
)
async
{
final
List
<
ProjectValidatorResult
>
result
=
<
ProjectValidatorResult
>[];
result
.
add
(
ProjectValidatorResult
(
name:
'FlutterProject.directory'
,
value:
_toJsonValue
(
project
.
directory
.
absolute
.
path
),
status:
StatusProjectValidator
.
info
,
));
result
.
add
(
ProjectValidatorResult
(
name:
'FlutterProject.metadataFile'
,
value:
_toJsonValue
(
project
.
metadataFile
.
absolute
.
path
),
status:
StatusProjectValidator
.
info
,
));
result
.
add
(
ProjectValidatorResult
(
name:
'FlutterProject.android.exists'
,
value:
_toJsonValue
(
project
.
android
.
existsSync
()),
status:
StatusProjectValidator
.
info
,
));
result
.
add
(
ProjectValidatorResult
(
name:
'FlutterProject.ios.exists'
,
value:
_toJsonValue
(
project
.
ios
.
exists
),
status:
StatusProjectValidator
.
info
,
));
result
.
add
(
ProjectValidatorResult
(
name:
'FlutterProject.web.exists'
,
value:
_toJsonValue
(
project
.
web
.
existsSync
()),
status:
StatusProjectValidator
.
info
,
));
result
.
add
(
ProjectValidatorResult
(
name:
'FlutterProject.macos.exists'
,
value:
_toJsonValue
(
project
.
macos
.
existsSync
()),
status:
StatusProjectValidator
.
info
,
));
result
.
add
(
ProjectValidatorResult
(
name:
'FlutterProject.linux.exists'
,
value:
_toJsonValue
(
project
.
linux
.
existsSync
()),
status:
StatusProjectValidator
.
info
,
));
result
.
add
(
ProjectValidatorResult
(
name:
'FlutterProject.windows.exists'
,
value:
_toJsonValue
(
project
.
windows
.
existsSync
()),
status:
StatusProjectValidator
.
info
,
));
result
.
add
(
ProjectValidatorResult
(
name:
'FlutterProject.fuchsia.exists'
,
value:
_toJsonValue
(
project
.
fuchsia
.
existsSync
()),
status:
StatusProjectValidator
.
info
,
));
result
.
add
(
ProjectValidatorResult
(
name:
'FlutterProject.android.isKotlin'
,
value:
_toJsonValue
(
project
.
android
.
isKotlin
),
status:
StatusProjectValidator
.
info
,
));
result
.
add
(
ProjectValidatorResult
(
name:
'FlutterProject.ios.isSwift'
,
value:
_toJsonValue
(
project
.
ios
.
isSwift
),
status:
StatusProjectValidator
.
info
,
));
result
.
add
(
ProjectValidatorResult
(
name:
'FlutterProject.isModule'
,
value:
_toJsonValue
(
project
.
isModule
),
status:
StatusProjectValidator
.
info
,
));
result
.
add
(
ProjectValidatorResult
(
name:
'FlutterProject.isPlugin'
,
value:
_toJsonValue
(
project
.
isPlugin
),
status:
StatusProjectValidator
.
info
,
));
result
.
add
(
ProjectValidatorResult
(
name:
'FlutterProject.manifest.appname'
,
value:
_toJsonValue
(
project
.
manifest
.
appName
),
status:
StatusProjectValidator
.
info
,
));
// FlutterVersion
final
FlutterVersion
version
=
FlutterVersion
(
workingDirectory:
project
.
directory
.
absolute
.
path
);
result
.
add
(
ProjectValidatorResult
(
name:
'FlutterVersion.frameworkRevision'
,
value:
_toJsonValue
(
version
.
frameworkRevision
),
status:
StatusProjectValidator
.
info
,
));
// Platform
result
.
add
(
ProjectValidatorResult
(
name:
'Platform.operatingSystem'
,
value:
_toJsonValue
(
platform
.
operatingSystem
),
status:
StatusProjectValidator
.
info
,
));
result
.
add
(
ProjectValidatorResult
(
name:
'Platform.isAndroid'
,
value:
_toJsonValue
(
platform
.
isAndroid
),
status:
StatusProjectValidator
.
info
,
));
result
.
add
(
ProjectValidatorResult
(
name:
'Platform.isIOS'
,
value:
_toJsonValue
(
platform
.
isIOS
),
status:
StatusProjectValidator
.
info
,
));
result
.
add
(
ProjectValidatorResult
(
name:
'Platform.isWindows'
,
value:
_toJsonValue
(
platform
.
isWindows
),
status:
StatusProjectValidator
.
info
,
));
result
.
add
(
ProjectValidatorResult
(
name:
'Platform.isMacOS'
,
value:
_toJsonValue
(
platform
.
isMacOS
),
status:
StatusProjectValidator
.
info
,
));
result
.
add
(
ProjectValidatorResult
(
name:
'Platform.isFuchsia'
,
value:
_toJsonValue
(
platform
.
isFuchsia
),
status:
StatusProjectValidator
.
info
,
));
result
.
add
(
ProjectValidatorResult
(
name:
'Platform.pathSeparator'
,
value:
_toJsonValue
(
platform
.
pathSeparator
),
status:
StatusProjectValidator
.
info
,
));
// Cache
result
.
add
(
ProjectValidatorResult
(
name:
'Cache.flutterRoot'
,
value:
_toJsonValue
(
Cache
.
flutterRoot
),
status:
StatusProjectValidator
.
info
,
));
return
result
;
}
@override
bool
supportsProject
(
FlutterProject
project
)
{
// this validator will run for any type of project
return
true
;
}
@override
String
get
title
=>
'Machine JSON variable dump'
;
}
/// Validator run for all platforms that extract information from the pubspec.yaml.
///
/// Specific info from different platforms should be written in their own ProjectValidator.
...
...
packages/flutter_tools/lib/src/runner/flutter_command_runner.dart
View file @
21861423
...
...
@@ -277,9 +277,8 @@ class FlutterCommandRunner extends CommandRunner<void> {
globals
.
printStatus
(
status
);
return
;
}
if
(
machineFlag
)
{
throwToolExit
(
'The "--machine" flag is only valid with the "--version" flag.'
,
exitCode:
2
);
if
(
machineFlag
&&
topLevelResults
.
command
?.
name
!=
'analyze'
)
{
throwToolExit
(
'The "--machine" flag is only valid with the "--version" flag or the "analzye --suggestions" command.'
,
exitCode:
2
);
}
await
super
.
runCommand
(
topLevelResults
);
},
...
...
packages/flutter_tools/test/commands.shard/hermetic/analyze_suggestion_test.dart
View file @
21861423
...
...
@@ -97,7 +97,7 @@ void main() {
allProjectValidators:
<
ProjectValidator
>[
ProjectValidatorDummy
(),
ProjectValidatorSecondDummy
()
]
]
,
);
final
CommandRunner
<
void
>
runner
=
createTestCommandRunner
(
command
);
...
...
@@ -128,7 +128,7 @@ void main() {
processManager:
processManager
,
allProjectValidators:
<
ProjectValidator
>[
ProjectValidatorCrash
(),
]
]
,
);
final
CommandRunner
<
void
>
runner
=
createTestCommandRunner
(
command
);
...
...
@@ -148,7 +148,7 @@ void main() {
platform:
platform
,
terminal:
terminal
,
processManager:
processManager
,
allProjectValidators:
<
ProjectValidator
>[]
allProjectValidators:
<
ProjectValidator
>[]
,
);
final
CommandRunner
<
void
>
runner
=
createTestCommandRunner
(
command
);
Future
<
void
>
result
()
=>
runner
.
run
(<
String
>[
'analyze'
,
'--suggestions'
,
'--watch'
]);
...
...
packages/flutter_tools/test/general.shard/args_test.dart
View file @
21861423
...
...
@@ -25,7 +25,7 @@ void main() {
for
(
final
Command
<
void
>
command
in
runner
.
commands
.
values
)
{
if
(
command
.
name
==
'analyze'
)
{
final
AnalyzeCommand
analyze
=
command
as
AnalyzeCommand
;
expect
(
analyze
.
allProjectValidators
().
length
,
1
);
expect
(
analyze
.
allProjectValidators
().
length
,
2
);
}
}
}));
...
...
packages/flutter_tools/test/integration.shard/analyze_suggestions_integration_test.dart
View file @
21861423
...
...
@@ -2,15 +2,21 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import
'dart:convert'
;
import
'package:args/command_runner.dart'
;
import
'package:flutter_tools/src/base/file_system.dart'
;
import
'package:flutter_tools/src/base/io.dart'
;
import
'package:flutter_tools/src/base/logger.dart'
;
import
'package:flutter_tools/src/base/platform.dart'
;
import
'package:flutter_tools/src/commands/analyze.dart'
;
import
'package:flutter_tools/src/globals.dart'
as
globals
;
import
'package:flutter_tools/src/project_validator.dart'
;
import
'../src/common.dart'
;
import
'../src/context.dart'
;
import
'../src/test_flutter_command_runner.dart'
;
import
'test_utils.dart'
;
void
main
(
)
{
late
FileSystem
fileSystem
;
...
...
@@ -86,4 +92,76 @@ void main() {
expect
(
loggerTest
.
statusText
,
contains
(
expected
));
});
});
group
(
'analyze --suggestions --machine command integration'
,
()
{
late
Directory
tempDir
;
late
Platform
platform
;
setUpAll
(()
async
{
platform
=
const
LocalPlatform
();
tempDir
=
createResolvedTempDirectorySync
(
'run_test.'
);
await
globals
.
processManager
.
run
(<
String
>[
'flutter'
,
'create'
,
'test_project'
],
workingDirectory:
tempDir
.
path
);
});
tearDown
(()
async
{
tryToDelete
(
tempDir
);
});
testUsingContext
(
'analyze --suggesions --machine produces expected values'
,
()
async
{
final
ProcessResult
result
=
await
globals
.
processManager
.
run
(<
String
>[
'flutter'
,
'analyze'
,
'--suggestions'
,
'--machine'
],
workingDirectory:
tempDir
.
childDirectory
(
'test_project'
).
path
);
expect
(
result
.
stdout
is
String
,
true
);
expect
((
result
.
stdout
as
String
).
startsWith
(
'{
\n
'
),
true
);
expect
(
result
.
stdout
,
isNot
(
contains
(
',
\n
}'
)));
// No trailing commas allowed in JSON
expect
((
result
.
stdout
as
String
).
endsWith
(
'}
\n
'
),
true
);
final
Map
<
String
,
dynamic
>
decoded
=
jsonDecode
(
result
.
stdout
as
String
)
as
Map
<
String
,
dynamic
>;
expect
(
decoded
.
containsKey
(
'FlutterProject.android.exists'
),
true
);
expect
(
decoded
.
containsKey
(
'FlutterProject.ios.exists'
),
true
);
expect
(
decoded
.
containsKey
(
'FlutterProject.web.exists'
),
true
);
expect
(
decoded
.
containsKey
(
'FlutterProject.macos.exists'
),
true
);
expect
(
decoded
.
containsKey
(
'FlutterProject.linux.exists'
),
true
);
expect
(
decoded
.
containsKey
(
'FlutterProject.windows.exists'
),
true
);
expect
(
decoded
.
containsKey
(
'FlutterProject.fuchsia.exists'
),
true
);
expect
(
decoded
.
containsKey
(
'FlutterProject.android.isKotlin'
),
true
);
expect
(
decoded
.
containsKey
(
'FlutterProject.ios.isSwift'
),
true
);
expect
(
decoded
.
containsKey
(
'FlutterProject.isModule'
),
true
);
expect
(
decoded
.
containsKey
(
'FlutterProject.isPlugin'
),
true
);
expect
(
decoded
.
containsKey
(
'FlutterProject.manifest.appname'
),
true
);
expect
(
decoded
.
containsKey
(
'FlutterVersion.frameworkRevision'
),
true
);
expect
(
decoded
.
containsKey
(
'FlutterProject.directory'
),
true
);
expect
(
decoded
.
containsKey
(
'FlutterProject.metadataFile'
),
true
);
expect
(
decoded
.
containsKey
(
'Platform.operatingSystem'
),
true
);
expect
(
decoded
.
containsKey
(
'Platform.isAndroid'
),
true
);
expect
(
decoded
.
containsKey
(
'Platform.isIOS'
),
true
);
expect
(
decoded
.
containsKey
(
'Platform.isWindows'
),
true
);
expect
(
decoded
.
containsKey
(
'Platform.isMacOS'
),
true
);
expect
(
decoded
.
containsKey
(
'Platform.isFuchsia'
),
true
);
expect
(
decoded
.
containsKey
(
'Platform.pathSeparator'
),
true
);
expect
(
decoded
.
containsKey
(
'Cache.flutterRoot'
),
true
);
expect
(
decoded
[
'FlutterProject.android.exists'
],
true
);
expect
(
decoded
[
'FlutterProject.ios.exists'
],
true
);
expect
(
decoded
[
'FlutterProject.web.exists'
],
true
);
expect
(
decoded
[
'FlutterProject.macos.exists'
],
true
);
expect
(
decoded
[
'FlutterProject.linux.exists'
],
true
);
expect
(
decoded
[
'FlutterProject.windows.exists'
],
true
);
expect
(
decoded
[
'FlutterProject.fuchsia.exists'
],
false
);
expect
(
decoded
[
'FlutterProject.android.isKotlin'
],
true
);
expect
(
decoded
[
'FlutterProject.ios.isSwift'
],
true
);
expect
(
decoded
[
'FlutterProject.isModule'
],
false
);
expect
(
decoded
[
'FlutterProject.isPlugin'
],
false
);
expect
(
decoded
[
'FlutterProject.manifest.appname'
],
'test_project'
);
expect
(
decoded
[
'FlutterVersion.frameworkRevision'
],
''
);
expect
(
decoded
[
'Platform.isAndroid'
],
false
);
expect
(
decoded
[
'Platform.isIOS'
],
false
);
expect
(
decoded
[
'Platform.isWindows'
],
platform
.
isWindows
);
expect
(
decoded
[
'Platform.isMacOS'
],
platform
.
isMacOS
);
expect
(
decoded
[
'Platform.isFuchsia'
],
platform
.
isFuchsia
);
expect
(
decoded
[
'Platform.pathSeparator'
],
platform
.
pathSeparator
);
},
overrides:
<
Type
,
Generator
>{});
});
}
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