독립 control plane 구성을 위해 기존 Dart CLI/runtime을 runner 앱 경계로 옮기고, 후속 client/core/root 작업을 같은 마일스톤 task group에 연결한다.
215 lines
5.6 KiB
Dart
215 lines
5.6 KiB
Dart
// ignore_for_file: depend_on_referenced_packages
|
|
|
|
import 'dart:async';
|
|
import 'dart:convert';
|
|
import 'dart:io';
|
|
import 'dart:math';
|
|
|
|
import 'package:dart_framework/utils/system_util.dart';
|
|
import 'package:path/path.dart' as path;
|
|
|
|
import 'cli_style.dart';
|
|
import '../oto/core/system_runtime.dart';
|
|
|
|
final _colorCodeMap = {
|
|
Color.black: "30",
|
|
Color.red: "31",
|
|
Color.green: "32",
|
|
Color.yellow: "33",
|
|
Color.blue: "34",
|
|
Color.magenta: "35",
|
|
Color.cyan: "36",
|
|
Color.lightGray: "37",
|
|
Color.darkGray: "90",
|
|
Color.redStrong: "91",
|
|
Color.greenStrong: "92",
|
|
Color.yellowStrong: "93",
|
|
Color.blueStrong: "94",
|
|
Color.magentaStrong: "95",
|
|
Color.cyanStrong: "96",
|
|
Color.white: "97"
|
|
};
|
|
|
|
final _backgroundCodeMap = {
|
|
Color.black: "40",
|
|
Color.red: "41",
|
|
Color.green: "42",
|
|
Color.yellow: "43",
|
|
Color.blue: "44",
|
|
Color.magenta: "45",
|
|
Color.cyan: "46",
|
|
Color.lightGray: "47",
|
|
Color.darkGray: "100",
|
|
Color.redStrong: "101",
|
|
Color.greenStrong: "102",
|
|
Color.yellowStrong: "103",
|
|
Color.blueStrong: "104",
|
|
Color.magentaStrong: "105",
|
|
Color.cyanStrong: "106",
|
|
Color.white: "107"
|
|
};
|
|
|
|
final _styleCodeMap = {
|
|
Style.bold: "1",
|
|
Style.dim: "2",
|
|
Style.underline: "4",
|
|
Style.reverse: "7"
|
|
};
|
|
|
|
abstract class Printer {
|
|
Printer();
|
|
factory Printer.windows(
|
|
{SystemRuntime runtime = const DefaultSystemRuntime()}) =>
|
|
_PrinterWindows(runtime);
|
|
factory Printer.unix(
|
|
{SystemRuntime runtime = const DefaultSystemRuntime()}) =>
|
|
_PrinterUnix(runtime);
|
|
|
|
String getStyle(String message,
|
|
{Color? color, Color? background, Style? style}) {
|
|
var combine = '';
|
|
if (color != null) {
|
|
combine = _colorCodeMap[color]!;
|
|
}
|
|
if (background != null) {
|
|
combine = combineText(combine, _backgroundCodeMap[background]!);
|
|
}
|
|
if (style != null) {
|
|
combine = combineText(combine, _styleCodeMap[style]!);
|
|
}
|
|
return combine;
|
|
}
|
|
|
|
String combineText(String combine, String item) {
|
|
if (combine == '') {
|
|
combine = item;
|
|
} else {
|
|
combine += ';$item';
|
|
}
|
|
return combine;
|
|
}
|
|
|
|
Future<File> getTempFile(String content, String extension) async {
|
|
var now = DateTime.now();
|
|
var time =
|
|
'${now.hour}${now.minute}${now.second}${now.millisecond}${now.microsecond}';
|
|
var tempFile = File(path.join(Directory.systemTemp.path,
|
|
'temp_${time}_${Random().nextInt(1000)}.$extension'));
|
|
await tempFile.writeAsString(content);
|
|
return dataFutrue(tempFile);
|
|
}
|
|
|
|
Future printCLI(List<String> printList) async {}
|
|
}
|
|
|
|
class _PrinterWindows extends Printer {
|
|
final SystemRuntime runtime;
|
|
_PrinterWindows(this.runtime);
|
|
|
|
@override
|
|
String getStyle(String message,
|
|
{Color? color, Color? background, Style? style}) {
|
|
var combine = super
|
|
.getStyle(message, color: color, background: background, style: style);
|
|
return '%ESC%[${combine}m$message%ESC%[0m';
|
|
}
|
|
|
|
String removeTags(String value) {
|
|
return value
|
|
.replaceAll('^', '^^')
|
|
.replaceAll('<', '^<')
|
|
.replaceAll('>', '^>')
|
|
.replaceAll('[', '^[')
|
|
.replaceAll('╷', '^╷')
|
|
.replaceAll('│', '^│')
|
|
.replaceAll('╵', '^╵')
|
|
.replaceAll(']', '^]')
|
|
.replaceAll('|', '^|')
|
|
.replaceAll('\r', '')
|
|
.replaceAll('\n', '');
|
|
}
|
|
|
|
@override
|
|
Future printCLI(List<String> printList) async {
|
|
StringBuffer message = StringBuffer();
|
|
message.writeln('@echo off\r');
|
|
message.writeln('chcp 65001 > nul');
|
|
message.writeln('setlocal\r');
|
|
message.writeln('call :setESC\r');
|
|
|
|
if (printList.length == 1) {
|
|
message.writeln('echo | set /p=${removeTags(printList.first)}');
|
|
} else {
|
|
for (var item in printList) {
|
|
item = removeTags(item);
|
|
if (item.trim().isEmpty) {
|
|
message.writeln('echo.\r');
|
|
} else {
|
|
message.writeln('echo $item\r');
|
|
}
|
|
}
|
|
}
|
|
message.writeln(':setESC\r');
|
|
message.writeln(
|
|
'''for /F "tokens=1,2 delims=#" %%a in ('"prompt #\$H#\$E# & echo on & for %%b in (1) do rem"') do (\r''');
|
|
message.writeln(' set ESC=%%b\r');
|
|
message.writeln(' exit /B 0\r');
|
|
message.writeln(')\r');
|
|
message.writeln('exit /B 0\r');
|
|
|
|
var temp = await getTempFile(message.toString(), 'bat');
|
|
await runtime
|
|
.runExecutable('cmd', ['/C', temp.path],
|
|
stderrEncoding: utf8, stdoutEncoding: utf8)
|
|
.then((ProcessResult result) {
|
|
print(result.stdout);
|
|
|
|
String error = result.stderr;
|
|
if (error.isNotEmpty) {
|
|
print(
|
|
'=============== Error ===============\r\n${result.stderr}\r\n\r\nr\n=============== Script ===============\r\n${message.toString()}');
|
|
}
|
|
});
|
|
await temp.delete();
|
|
return simpleFuture;
|
|
}
|
|
}
|
|
|
|
class _PrinterUnix extends Printer {
|
|
final SystemRuntime runtime;
|
|
_PrinterUnix(this.runtime);
|
|
|
|
@override
|
|
String getStyle(String message,
|
|
{Color? color, Color? background, Style? style}) {
|
|
var combine = super
|
|
.getStyle(message, color: color, background: background, style: style);
|
|
return '\\e[${combine}m$message\\e[0m';
|
|
}
|
|
|
|
@override
|
|
Future printCLI(List<String> printList) async {
|
|
StringBuffer message = StringBuffer();
|
|
message.write('echo -e "');
|
|
|
|
for (var item in printList) {
|
|
message.writeln(item);
|
|
}
|
|
message.write('"');
|
|
|
|
var temp = await getTempFile(message.toString(), 'sh');
|
|
var shellExe = runtime.isMacOS ? 'zsh' : 'bash';
|
|
await runtime
|
|
.runExecutable(
|
|
shellExe,
|
|
[temp.path],
|
|
stdoutEncoding: utf8,
|
|
stderrEncoding: utf8,
|
|
)
|
|
.then((ProcessResult result) {
|
|
print(result.stdout);
|
|
});
|
|
await temp.delete();
|
|
return simpleFuture;
|
|
}
|
|
}
|