독립 control plane 구성을 위해 기존 Dart CLI/runtime을 runner 앱 경계로 옮기고, 후속 client/core/root 작업을 같은 마일스톤 task group에 연결한다.
215 lines
6 KiB
Dart
215 lines
6 KiB
Dart
// ignore_for_file: avoid_init_to_null
|
|
|
|
import 'dart:async';
|
|
import 'dart:convert';
|
|
import 'dart:io';
|
|
|
|
import 'package:dart_framework/data/isolate_data.dart';
|
|
import 'package:dart_framework/platform/isolate_manager.dart';
|
|
import 'package:oto/cli/cli.dart';
|
|
import 'package:oto/cli/commands/command_base.dart';
|
|
import 'package:dart_framework/utils/system_util.dart';
|
|
import 'package:oto/oto/application.dart';
|
|
import 'package:oto/oto/core/build_result.dart';
|
|
import 'package:oto/oto/data/command_data.dart';
|
|
|
|
class CommandExe extends CommandBase {
|
|
IsolateHandler? _handler;
|
|
bool _complete = false;
|
|
bool _ready = false;
|
|
int _exitCode = 0;
|
|
Map<String, dynamic>? _resultJson;
|
|
final Future<void> Function(String) _printString;
|
|
|
|
CommandExe({Future<void> Function(String)? printString})
|
|
: _printString = printString ??
|
|
((value) async {
|
|
stdout.writeln(value);
|
|
});
|
|
|
|
@override
|
|
Map<String, List<String>> get arguments => {
|
|
'-j': ["Used when it's a Jenkins build."],
|
|
'-t': ["This is the setup for testing."],
|
|
'-f {file path}': ["Run the yaml file to process."],
|
|
'--file {file path}': ["Run the yaml file to process."],
|
|
'--json': ["Output execution result as structured JSON format."]
|
|
};
|
|
@override
|
|
String get name => 'exe';
|
|
|
|
@override
|
|
bool shouldPrintExecuteLog(List<String> parameters) {
|
|
return !parameters.contains('--json');
|
|
}
|
|
|
|
@override
|
|
Future execute(List<String> parameters) async {
|
|
BuildType? buildType;
|
|
String? filePath;
|
|
bool isJson = false;
|
|
bool hasUnknownOption = false;
|
|
|
|
if (parameters.isEmpty) {
|
|
printHelp();
|
|
return simpleFuture;
|
|
}
|
|
|
|
for (int i = 0; i < parameters.length; i++) {
|
|
final param = parameters[i];
|
|
if (param == '--json') {
|
|
isJson = true;
|
|
} else if (param == '-j') {
|
|
buildType = BuildType.jenkins;
|
|
} else if (param == '-t') {
|
|
buildType = BuildType.test;
|
|
} else if (param.startsWith('-f')) {
|
|
buildType = BuildType.file;
|
|
if (param == '-f') {
|
|
if (i + 1 < parameters.length) {
|
|
filePath = parameters[++i];
|
|
} else {
|
|
hasUnknownOption = true;
|
|
}
|
|
} else {
|
|
filePath = param.substring(2);
|
|
}
|
|
} else if (param.startsWith('--file=')) {
|
|
buildType = BuildType.file;
|
|
filePath = param.substring('--file='.length);
|
|
} else if (param == '--file') {
|
|
buildType = BuildType.file;
|
|
if (i + 1 < parameters.length) {
|
|
filePath = parameters[++i];
|
|
} else {
|
|
hasUnknownOption = true;
|
|
}
|
|
} else {
|
|
hasUnknownOption = true;
|
|
}
|
|
}
|
|
|
|
if (hasUnknownOption || buildType == null) {
|
|
printHelp();
|
|
return simpleFuture;
|
|
}
|
|
|
|
final logEnable = !isJson;
|
|
|
|
if (buildType == BuildType.file) {
|
|
if (filePath == null || filePath.isEmpty) {
|
|
printHelp();
|
|
return simpleFuture;
|
|
}
|
|
await startYaml(filePath, logEnable: logEnable);
|
|
} else {
|
|
_handler = IsolateManager.create(IsolateExe(buildType, logEnable: logEnable));
|
|
await isComplete();
|
|
}
|
|
|
|
if (isJson && _resultJson != null) {
|
|
await _printString(const JsonEncoder.withIndent(' ').convert(_resultJson));
|
|
}
|
|
|
|
exitCode = _exitCode;
|
|
_handler?.exit();
|
|
return simpleFuture;
|
|
}
|
|
|
|
Future executeScheduler(
|
|
DataBuild build, bool logEnable, String logPath) async {
|
|
_handler =
|
|
IsolateManager.create(IsolateExe.scheduler(build, logEnable, logPath));
|
|
await isComplete();
|
|
_handler?.exit();
|
|
return simpleFuture;
|
|
}
|
|
|
|
Future isComplete() async {
|
|
_ready = false;
|
|
_complete = false;
|
|
_exitCode = 0;
|
|
_resultJson = null;
|
|
_handler!.addEventListener(IsolateEvent.ready, (data) => _ready = true);
|
|
_handler!.addListener('complete', (data) {
|
|
if (data is Map) {
|
|
_resultJson = Map<String, dynamic>.from(data);
|
|
_exitCode = (_resultJson!['exitCode'] as num?)?.toInt() ?? 10;
|
|
} else if (data is int) {
|
|
_exitCode = data;
|
|
}
|
|
_complete = true;
|
|
});
|
|
while (!(_complete && _ready)) {
|
|
await Future.delayed(const Duration(milliseconds: 200));
|
|
}
|
|
return simpleFuture;
|
|
}
|
|
|
|
Future startYaml(String target, {bool logEnable = true}) async {
|
|
var file = File(target);
|
|
if (file.existsSync()) {
|
|
_handler = IsolateManager.create(IsolateExe(BuildType.file,
|
|
logEnable: logEnable,
|
|
yamlContent: file.readAsStringSync(
|
|
/*encoding: Platform.isWindows ? eucKr : systemEncoding*/)));
|
|
await isComplete();
|
|
} else {
|
|
_exitCode = 10;
|
|
if (!logEnable) {
|
|
final failureResult = BuildResult.failure(
|
|
'There are no files in path "$target"',
|
|
null,
|
|
exitCode: 10,
|
|
);
|
|
_resultJson = failureResult.toJson();
|
|
} else {
|
|
await CLI.print([
|
|
CLI.style('There are no files in path "$target"', color: Color.red)
|
|
]);
|
|
}
|
|
}
|
|
return simpleFuture;
|
|
}
|
|
|
|
@override
|
|
String getDescription() {
|
|
return ':::: Read documents written in yaml to do process task.';
|
|
}
|
|
}
|
|
|
|
class IsolateExe extends IsolateBase {
|
|
late BuildType _buildType;
|
|
bool _logEnable = true;
|
|
DataBuild? _build = null;
|
|
String? _yamleContent = null;
|
|
String? _logPath = null;
|
|
|
|
IsolateExe(this._buildType,
|
|
{String? yamlContent,
|
|
DataBuild? build,
|
|
bool logEnable = true,
|
|
String? logPath}) {
|
|
_yamleContent = yamlContent;
|
|
_build = build;
|
|
_logEnable = logEnable;
|
|
_logPath = logPath;
|
|
}
|
|
|
|
factory IsolateExe.scheduler(
|
|
DataBuild build, bool logEnable, String logPath) {
|
|
return IsolateExe(BuildType.scheduler,
|
|
build: build, logEnable: logEnable, logPath: logPath);
|
|
}
|
|
|
|
@override
|
|
void onReady(Object? initData) async {
|
|
final result = await Application.instance.build(_buildType,
|
|
yamlContent: _yamleContent,
|
|
buildData: _build,
|
|
logEnable: _logEnable,
|
|
logPath: _logPath);
|
|
send(IsoMessege('complete', data: result.toJson()));
|
|
}
|
|
}
|
|
|