Skip to content

Commit ff9c46d

Browse files
authored
refactor: refactor flutterw and flutterw/test (#18)
1 parent 5e41687 commit ff9c46d

File tree

15 files changed

+486
-169
lines changed

15 files changed

+486
-169
lines changed
Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
import 'dart:io';
22

3+
import 'package:cli_util/cli_logging.dart';
34
import 'package:flutterw/flutterw.dart';
45

56
Future<void> main(List<String> args) async {
67
final file = File('pubspec.yaml');
78
final config = file.existsSync()
89
? FlutterwConfig.fromFile(file)
910
: FlutterwConfig.empty();
10-
await FlutterwRunner(scripts: config.scripts).run(args);
11+
await FlutterwRunner(scripts: config.scripts, logger: Logger.standard())
12+
.run(args);
1113
}

packages/flutterw/lib/src/commands/help.dart

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
import 'dart:io';
22

33
import 'package:args/command_runner.dart';
4-
5-
import '../runner.dart';
4+
import 'package:flutterw/flutterw.dart';
65

76
class HelpCommand extends Command {
87
@override
@@ -42,10 +41,8 @@ class HelpCommand extends Command {
4241

4342
if (commands[name] == null) {
4443
if (command == null) {
45-
final process = await Process.start(
46-
(runner! as FlutterwRunner).originExecutableName,
47-
['help', ...argResults!.rest]);
48-
return exitCode = await process.exitCode;
44+
return exitCode = await (runner as FlutterwRunner)
45+
.runOrigin(['help', ...argResults!.rest]);
4946
}
5047

5148
command.usageException(

packages/flutterw/lib/src/config.dart

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,26 @@ class FlutterwConfig {
1313

1414
final YamlMap? yaml;
1515

16-
Map<String, dynamic> get scripts {
17-
return (yaml?['scripts'] as Map?)?.cast<String, dynamic>() ?? {};
16+
Map<String, List<String>> get scripts {
17+
final scriptsNode = yaml?['scripts'];
18+
if (scriptsNode == null) {
19+
return {};
20+
}
21+
if (scriptsNode is! Map) {
22+
throw FormatException('scripts in pubspec.yaml should be a Map');
23+
}
24+
final scriptsMap = <String, List<String>>{};
25+
for (var name in scriptsNode.keys) {
26+
final value = scriptsNode[name];
27+
if (value is List) {
28+
scriptsMap[name] = value.map((e) => e.toString().trim()).toList();
29+
} else if (value is String) {
30+
scriptsMap[name] = value.split('&&').map((e) => e.trim()).toList();
31+
} else {
32+
throw FormatException(
33+
'Value of script $name can only be String or List<String>');
34+
}
35+
}
36+
return scriptsMap;
1837
}
1938
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
class ScriptException implements Exception {
2+
final String name;
3+
4+
final dynamic message;
5+
6+
ScriptException(this.name, [this.message]);
7+
8+
@override
9+
String toString() {
10+
if (message == null) return "ScriptException($name)";
11+
return "ScriptException($name): $message";
12+
}
13+
}

packages/flutterw/lib/src/hook.dart

Lines changed: 0 additions & 111 deletions
This file was deleted.
Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,30 @@
11
import 'package:cli_util/cli_logging.dart';
22

33
extension FlutterwLogging on Logger {
4-
void name(String name) {
4+
void script(String name, dynamic value) {
55
stderr(ansi.emphasized('${ansi.yellow}$name${ansi.none}'));
6+
if (value is String) {
7+
stderr(ansi.emphasized(' └> ${ansi.cyan}$value${ansi.none}'));
8+
} else if (value is List) {
9+
for (var item in value) {
10+
stderr(ansi.emphasized(' └> ${ansi.cyan}$item${ansi.none}'));
11+
}
12+
}
613
}
714

8-
void script(String script, bool isVerbose) {
15+
void shell(String shell, bool isVerbose) {
916
if (isVerbose) {
10-
stderr(ansi.emphasized(' └> ${ansi.cyan}$script${ansi.none}'));
17+
stderr(ansi.emphasized('${ansi.cyan}$shell${ansi.none}'));
1118
} else {
12-
progress(ansi.emphasized(' └> ${ansi.cyan}$script${ansi.none}'));
19+
progress(ansi.emphasized('${ansi.cyan}$shell${ansi.none}'));
1320
}
1421
}
1522

1623
void result(bool success) {
1724
if (success) {
18-
stderr(ansi.emphasized(' └> ${ansi.green}SUCCESS${ansi.none}'));
25+
stderr(ansi.emphasized(' └> ${ansi.green}SUCCESS${ansi.none}'));
1926
} else {
20-
stderr(ansi.emphasized(' └> ${ansi.red}FAILED${ansi.none}'));
27+
stderr(ansi.emphasized(' └> ${ansi.red}FAILED${ansi.none}'));
2128
}
2229
}
2330
}
Lines changed: 77 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
1+
import 'dart:io';
2+
13
import 'package:args/args.dart';
24
import 'package:args/command_runner.dart';
3-
import 'package:cli_hook/cli_hook.dart';
45
import 'package:cli_util/cli_logging.dart';
5-
import 'package:cli_wrapper/cli_wrapper.dart';
6+
import 'package:tuple/tuple.dart';
67

78
import 'commands/help.dart';
8-
import 'hook.dart';
9+
import 'exception.dart';
10+
import 'logger.dart';
11+
import 'search.dart';
12+
import 'shell.dart';
913
import 'version.g.dart';
1014

1115
/// A class that can run Flutterw with scripts and command hooks system support.
@@ -17,26 +21,21 @@ import 'version.g.dart';
1721
///
1822
/// await flutterw.run(['pub', 'get']);
1923
/// ```
20-
class FlutterwRunner extends CommandRunner with WrapperRunner, HookRunner {
24+
class FlutterwRunner extends CommandRunner {
2125
FlutterwRunner({
2226
this.scripts = const {},
23-
Logger? logger,
24-
}) : logger = logger ?? Logger.standard(),
25-
super('flutterw',
27+
this.runOrigin = runFlutter,
28+
this.logger,
29+
}) : super('flutterw',
2630
'flutterw wraps flutter with scripts and command hooks support');
2731

28-
/// Scripts map.
29-
/// Each can be a single string or a list of strings
30-
final Map<String, dynamic> scripts;
31-
32-
/// Flutterw Logger
33-
final Logger logger;
32+
final Map<String, List<String>> scripts;
3433

35-
@override
36-
String get originExecutableName => 'flutter';
34+
/// Logger
35+
final Logger? logger;
3736

38-
@override
39-
Map<String, Hook> get hooks => ScriptHook.transform(scripts, logger);
37+
///
38+
final Future<int> Function(List<String>) runOrigin;
4039

4140
@override
4241
String? get usageFooter =>
@@ -56,13 +55,69 @@ class FlutterwRunner extends CommandRunner with WrapperRunner, HookRunner {
5655
}
5756

5857
@override
59-
Future runCommand(ArgResults topLevelResults) {
60-
if (topLevelResults.command == null) {
61-
if (topLevelResults.rest.isNotEmpty &&
62-
topLevelResults.rest.contains('--version')) {
63-
logger.stderr('Flutterw $kFlutterwVersion');
58+
ArgResults parse(Iterable<String> args) {
59+
ArgResults results;
60+
try {
61+
results = argParser.parse(args);
62+
} on ArgParserException catch (e) {
63+
if (e.commands.isEmpty) {
64+
return ArgParser.allowAnything().parse(args);
65+
}
66+
var command = commands[e.commands.first]!;
67+
for (var commandName in e.commands.skip(1)) {
68+
command = command.subcommands[commandName]!;
69+
}
70+
71+
command.usageException(e.message);
72+
}
73+
return results;
74+
}
75+
76+
@override
77+
Future run(Iterable<String> args) async {
78+
// No arguments or contains -h,--help
79+
if (args.isEmpty || args.contains('-h') || args.contains('--help')) {
80+
return super.run(args);
81+
}
82+
final topLevelResults = parse(args);
83+
final commandHooks = searchCommandHooks(args: args, scripts: scripts);
84+
final pre = commandHooks.item1;
85+
if (pre != null) {
86+
await _hook(pre);
87+
}
88+
final command = commandHooks.item2;
89+
dynamic result;
90+
if (command != null) {
91+
result = await _hook(command);
92+
} else {
93+
result = await runCommand(topLevelResults);
94+
}
95+
final post = commandHooks.item3;
96+
if (post != null) {
97+
await _hook(post);
98+
}
99+
return result;
100+
}
101+
102+
@override
103+
Future<dynamic> runCommand(ArgResults topLevelResults) {
104+
if (topLevelResults.command == null && topLevelResults.rest.isNotEmpty) {
105+
if (topLevelResults.rest.contains('--version')) {
106+
stdout.writeln('Flutterw $kFlutterwVersion');
64107
}
108+
return Future.sync(() => runOrigin(topLevelResults.arguments));
65109
}
66110
return super.runCommand(topLevelResults);
67111
}
112+
113+
/// Run hook defined in [scripts]
114+
Future<int> _hook(Tuple2<String, List<String>> hook) async {
115+
logger?.script(hook.item1, scripts[hook.item1]);
116+
final code =
117+
await runShells(scripts[hook.item1]!, hook.item2, logger: logger);
118+
if (code != 0) {
119+
throw ScriptException(hook.item1);
120+
}
121+
return 0;
122+
}
68123
}

0 commit comments

Comments
 (0)