oto/lib/cli/cli.dart

321 lines
8.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:oto_cli/cli/commands/command_base.dart';
import 'package:oto_cli/cli/commands/command_manager.dart';
import 'package:path/path.dart' as path;
enum Color {
black,
red,
green,
yellow,
blue,
magenta,
cyan,
lightGray,
darkGray,
redStrong,
greenStrong,
yellowStrong,
blueStrong,
magentaStrong,
cyanStrong,
white
}
enum Style { bold, underline, dim, reverse }
class CLIConfig {
String serviceName;
List<String> arguments;
List<CommandBase> commands;
late String executableFileName;
CLIConfig(this.serviceName, this.arguments, this.commands) {
var fileName = path.basename(Platform.resolvedExecutable);
fileName = fileName.replaceAll(path.extension(fileName), '');
executableFileName = fileName;
}
}
class CLI {
static 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"
};
static 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"
};
static final _styleCodeMap = {
Style.bold: "1",
Style.dim: "2",
Style.underline: "4",
Style.reverse: "7"
};
static Printer get printer {
if (Platform.isWindows) {
return Printer.windows();
} else {
return Printer.unix();
}
}
CLI._privateConstructor();
static final CLI _instance = CLI._privateConstructor();
static CLI get current => _instance;
static void initialize(
String serviceName, List<String> arguments, List<CommandBase> commands) {
current.start(serviceName, arguments, commands);
}
static String style(String message,
{Color? color, Color? background, Style? style}) {
return printer.getStyle(message,
color: color, background: background, style: style);
}
static final commandNameSpace = 18;
static get serviceName => CLI.current.config.serviceName;
static get executableFileName => CLI.current.config.executableFileName;
static Future print(List<String> printList,
{Color? color, Color? background}) async {
if (color != null || background != null) {
for (var i = 0; i < printList.length; ++i) {
printList[i] =
CLI.style(printList[i], color: color, background: background);
}
}
await printer.printCLI(printList);
return simpleFuture;
}
static Future printBuffer(StringBuffer buffer,
{Color? color, Color? background}) async {
return await printString(buffer.toString(),
color: color, background: background);
}
static Future printString(String str,
{Color? color, Color? background}) async {
str = str.replaceAll('\r', '');
return await print(str.split('\n'), color: color, background: background);
}
static Future println(String str, {Color? color, Color? background}) async {
str = str.replaceAll('\n', '').replaceAll('\r', '');
return await printString(str, color: color, background: background);
}
late CLIConfig config;
late CommandManager _commandManager;
void start(String serviceName, List<String> arguments,
List<CommandBase> commands) async {
config = CLIConfig(serviceName, arguments, commands);
_commandManager = CommandManager(config.commands);
//find command
String? command;
var args = config.arguments.toList();
if (arguments.isNotEmpty) {
for (var value in args) {
command = value;
break;
}
args.removeAt(0);
}
await _commandManager.execute(command, args);
}
}
//Printer Base
abstract class Printer {
Printer();
factory Printer.windows() => _PrinterWindows();
factory Printer.unix() => _PrinterUnix();
String getStyle(String message,
{Color? color, Color? background, Style? style}) {
var combine = '';
if (color != null) {
combine = CLI._colorCodeMap[color]!;
}
if (background != null) {
combine = combineText(combine, CLI._backgroundCodeMap[background]!);
}
if (style != null) {
combine = combineText(combine, CLI._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 c = Completer<File>();
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);
c.complete(tempFile);
return c.future;
}
Future printCLI(List<String> printList) async {}
}
//Printer windows
class _PrinterWindows extends Printer {
@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 {
var c = Completer();
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 Process.run('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();
c.complete();
return c.future;
}
}
//Printer mac/linux
class _PrinterUnix extends Printer {
@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 {
var c = Completer();
StringBuffer message = StringBuffer();
if (printList.length == 1) {
message.write('echo -n "${printList.first}"');
} else {
message.writeln('echo -e "');
for (var item in printList) {
message.writeln(item);
}
message.write('"');
}
var temp = await getTempFile(message.toString(), 'sh');
var shellExe = Platform.isMacOS ? 'zsh' : 'bash';
await Process.run(shellExe, [temp.path]).then((ProcessResult result) {
print(result.stdout);
});
await temp.delete();
c.complete();
return c.future;
}
}