diff --git a/bin/main.dart b/bin/main.dart index 344c5b5..80eff91 100644 --- a/bin/main.dart +++ b/bin/main.dart @@ -1,5 +1,5 @@ -import 'package:dart_framework/core/application.dart'; -import 'package:dart_framework/utils/system_util.dart'; +import 'package:oto_cli/framework/core/application.dart'; +import 'package:oto_cli/framework/utils/system_util.dart'; import 'package:oto_cli/cli/cli.dart'; import 'package:oto_cli/cli/commands/command_scheduler.dart'; import 'package:oto_cli/cli/commands/command_template.dart'; diff --git a/lib/cli/cli.dart b/lib/cli/cli.dart index dbea453..f7ae817 100644 --- a/lib/cli/cli.dart +++ b/lib/cli/cli.dart @@ -5,7 +5,7 @@ import 'dart:convert'; import 'dart:io'; import 'dart:math'; -import 'package:dart_framework/utils/system_util.dart'; +import 'package:oto_cli/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; diff --git a/lib/cli/commands/command_exe.dart b/lib/cli/commands/command_exe.dart index 8ebace3..b195fff 100644 --- a/lib/cli/commands/command_exe.dart +++ b/lib/cli/commands/command_exe.dart @@ -3,11 +3,11 @@ import 'dart:async'; import 'dart:io'; -import 'package:dart_framework/data/isolate_data.dart'; -import 'package:dart_framework/platform/isolate_manager.dart'; +import 'package:oto_cli/framework/data/isolate_data.dart'; +import 'package:oto_cli/framework/platform/isolate_manager.dart'; import 'package:oto_cli/cli/cli.dart'; import 'package:oto_cli/cli/commands/command_base.dart'; -import 'package:dart_framework/utils/system_util.dart'; +import 'package:oto_cli/framework/utils/system_util.dart'; import 'package:oto_cli/oto/application.dart'; import 'package:oto_cli/oto/data/command_data.dart'; diff --git a/lib/cli/commands/command_install.dart b/lib/cli/commands/command_install.dart index b0051d5..f289c8d 100644 --- a/lib/cli/commands/command_install.dart +++ b/lib/cli/commands/command_install.dart @@ -1,8 +1,8 @@ import 'dart:async'; import 'dart:io'; -import 'package:dart_framework/utils/os_startup.dart'; -import 'package:dart_framework/utils/system_util.dart'; +import 'package:oto_cli/framework/utils/os_startup.dart'; +import 'package:oto_cli/framework/utils/system_util.dart'; import 'package:oto_cli/cli/cli.dart'; import 'package:oto_cli/cli/commands/command_base.dart'; import 'package:oto_cli/cli/commands/command_const.dart'; diff --git a/lib/cli/commands/command_manager.dart b/lib/cli/commands/command_manager.dart index 97e6f0e..5aa01d6 100644 --- a/lib/cli/commands/command_manager.dart +++ b/lib/cli/commands/command_manager.dart @@ -1,6 +1,6 @@ import 'dart:async'; -import 'package:dart_framework/utils/system_util.dart'; +import 'package:oto_cli/framework/utils/system_util.dart'; import 'command_base.dart'; import 'package:oto_cli/cli/cli.dart'; diff --git a/lib/cli/commands/command_scheduler.dart b/lib/cli/commands/command_scheduler.dart index 567149d..212e62a 100644 --- a/lib/cli/commands/command_scheduler.dart +++ b/lib/cli/commands/command_scheduler.dart @@ -2,7 +2,7 @@ import 'dart:async'; import 'dart:io'; import 'package:oto_cli/cli/commands/command_base.dart'; -import 'package:dart_framework/utils/system_util.dart'; +import 'package:oto_cli/framework/utils/system_util.dart'; import 'package:oto_cli/cli/commands/scheduler/scheduler_manager.dart'; class CommandScheduler extends CommandBase { diff --git a/lib/cli/commands/command_start.dart b/lib/cli/commands/command_start.dart index 9b13eee..ac2dad2 100644 --- a/lib/cli/commands/command_start.dart +++ b/lib/cli/commands/command_start.dart @@ -1,7 +1,7 @@ import 'dart:async'; import 'package:oto_cli/cli/commands/command_base.dart'; -import 'package:dart_framework/utils/system_util.dart'; +import 'package:oto_cli/framework/utils/system_util.dart'; class CommandStart extends CommandBase { @override diff --git a/lib/cli/commands/command_template.dart b/lib/cli/commands/command_template.dart index fea5a38..45102e3 100644 --- a/lib/cli/commands/command_template.dart +++ b/lib/cli/commands/command_template.dart @@ -1,6 +1,6 @@ import 'dart:async'; -import 'package:dart_framework/utils/system_util.dart'; +import 'package:oto_cli/framework/utils/system_util.dart'; import 'package:oto_cli/cli/cli.dart'; import 'package:oto_cli/cli/commands/command_base.dart'; diff --git a/lib/cli/commands/install/regist_path.dart b/lib/cli/commands/install/regist_path.dart index 25db9b3..a242995 100644 --- a/lib/cli/commands/install/regist_path.dart +++ b/lib/cli/commands/install/regist_path.dart @@ -1,7 +1,7 @@ import 'dart:io'; -import 'package:dart_framework/platform/process.dart'; -import 'package:dart_framework/utils/system_util.dart'; +import 'package:oto_cli/framework/platform/process.dart'; +import 'package:oto_cli/framework/utils/system_util.dart'; class RegistPath { static RegistPath? _instance; diff --git a/lib/cli/commands/scheduler/scheduler_isolate.dart b/lib/cli/commands/scheduler/scheduler_isolate.dart index f7f4764..48fb9a1 100644 --- a/lib/cli/commands/scheduler/scheduler_isolate.dart +++ b/lib/cli/commands/scheduler/scheduler_isolate.dart @@ -1,10 +1,10 @@ import 'dart:io'; import 'package:cron/cron.dart'; -import 'package:dart_framework/data/isolate_data.dart'; -import 'package:dart_framework/platform/isolate_manager.dart'; -import 'package:dart_framework/utils/string_util.dart'; -import 'package:dart_framework/utils/system_util.dart'; +import 'package:oto_cli/framework/data/isolate_data.dart'; +import 'package:oto_cli/framework/platform/isolate_manager.dart'; +import 'package:oto_cli/framework/utils/string_util.dart'; +import 'package:oto_cli/framework/utils/system_util.dart'; import 'package:file_hasher/file_hasher.dart'; import 'package:oto_cli/cli/commands/command_exe.dart'; import 'package:oto_cli/cli/commands/scheduler/scheduler_interval.dart'; diff --git a/lib/cli/commands/scheduler/scheduler_manager.dart b/lib/cli/commands/scheduler/scheduler_manager.dart index 36dbcc8..cf5204c 100644 --- a/lib/cli/commands/scheduler/scheduler_manager.dart +++ b/lib/cli/commands/scheduler/scheduler_manager.dart @@ -4,11 +4,11 @@ import 'dart:collection'; import 'dart:convert'; import 'dart:io'; -import 'package:dart_framework/platform/isolate_manager.dart'; -import 'package:dart_framework/platform/process.dart'; -import 'package:dart_framework/utils/os_startup.dart'; -import 'package:dart_framework/utils/string_util.dart'; -import 'package:dart_framework/utils/system_util.dart'; +import 'package:oto_cli/framework/platform/isolate_manager.dart'; +import 'package:oto_cli/framework/platform/process.dart'; +import 'package:oto_cli/framework/utils/os_startup.dart'; +import 'package:oto_cli/framework/utils/string_util.dart'; +import 'package:oto_cli/framework/utils/system_util.dart'; import 'package:oto_cli/cli/commands/scheduler/data/scheduler_data.dart'; import 'package:oto_cli/cli/commands/scheduler/scheduler_isolate.dart'; import 'package:oto_cli/cli/commands/scheduler/scheduler_linux.dart'; diff --git a/lib/framework/core/app_data_manager.dart b/lib/framework/core/app_data_manager.dart new file mode 100644 index 0000000..8ab9b98 --- /dev/null +++ b/lib/framework/core/app_data_manager.dart @@ -0,0 +1,126 @@ +import 'dart:async'; +import 'dart:convert'; +import 'dart:io'; + +import 'package:oto_cli/framework/platform/process.dart'; +import 'package:oto_cli/framework/model/app_data.dart'; +import 'package:oto_cli/framework/utils/system_util.dart'; + +enum SCMType { Svn, Git } + +class AppDataManager { + AppDataManager._privateConstructor(); + static final AppDataManager _instance = AppDataManager._privateConstructor(); + static AppDataManager get to => _instance; + + late SCMType _scm; + late String _workspace; + late String _relativeAssetPath; + + Future create(SCMType scm, String workspace, + String relativeAssetPath, String name) async { + _scm = scm; + _workspace = workspace; + _relativeAssetPath = relativeAssetPath; + var c = Completer(); + var appData = AppData(); + appData.name = name; + appData.gitCount = await gitCount(); + appData.version = await getVersion(); + appData.buildDate = getBuildTime(); + if (_scm == SCMType.Git) { + appData.gitHash = await getHash(); + } + await createFile(jsonEncode(appData.toJson())); + c.complete(appData); + return c.future; + } + + Future gitCount() async { + var shell = StringBuffer(); + shell.writeln('git rev-list --all HEAD --all --count'); + var process = await ProcessExecutor.start(shell, workspace: _workspace); + await process.waitForExit(); + return dataFutrue(int.parse(process.stdoutArr.last)); + } + + Future getVersion() async { + var c = Completer(); + var number = 0; + var shell = StringBuffer(); + switch (_scm) { + case SCMType.Svn: + break; + case SCMType.Git: + shell.writeln('git rev-list --all HEAD --all --count'); + var process = await ProcessExecutor.start(shell, workspace: _workspace); + await process.waitForExit(); + number = int.parse(process.stdoutArr.last); + break; + } + + var version = numberToVersion(number); + print('#### Version: $version'); + c.complete(version); + return c.future; + } + + String numberToVersion(int number, {int masterVersion = 0}) { + var arr = number.toString().split(''); + var length = arr.length; + var ver = ''; + var versionList = []; + for (int i = 0; i < length; ++i) { + if (i != 0 && i % 3 == 0) { + versionList.add(int.parse(ver)); + ver = ''; + } + ver = arr[length - (i + 1)].toString() + ver; + } + if (ver != '') versionList.add(int.parse(ver)); + + ver = ''; + length = 3; + var list = ['0', '0', '0']; + for (int i = 0; i < length; ++i) { + var versionValue = versionList.length <= i ? 0 : versionList[i]; + var versionStr = i == 2 + ? (versionValue + masterVersion).toString() + : versionValue.toString(); + list[length - (i + 1)] = versionStr; + } + return list.join('.'); + } + + double versionToNumber(String version) { + var value = version.replaceAll('.', ''); + return double.parse(value); + } + + Future getHash() async { + var shell = StringBuffer(); + shell.writeln('git rev-parse HEAD'); + var process = await ProcessExecutor.start(shell, workspace: _workspace); + await process.waitForExit(); + var hash = process.stdoutArr.last; + print('#### Git Hash: $hash'); + return dataFutrue(hash); + } + + String getBuildTime() { + var date = DateTime.now().toString(); + date = date.substring(0, date.lastIndexOf('.')); + print('#### Build Date: $date'); + return date; + } + + Future createFile(String json) async { + var c = Completer(); + var dir = Directory('$_workspace/$_relativeAssetPath'); + if (!dir.existsSync()) dir.createSync(recursive: true); + var file = File('$_workspace/$_relativeAssetPath/app_data.json'); + await file.writeAsString(json); + c.complete(); + return c.future; + } +} diff --git a/lib/framework/core/application.dart b/lib/framework/core/application.dart new file mode 100644 index 0000000..924be93 --- /dev/null +++ b/lib/framework/core/application.dart @@ -0,0 +1,20 @@ +import 'dart:async'; + +import 'package:oto_cli/framework/log/log.dart'; +import 'package:oto_cli/framework/utils/system_util.dart' as system; + +class Application { + Function(Object, StackTrace)? writeLog; + + Application(String name, String appID, Function() func, + Function(Object, StackTrace) errorListener) { + runZonedGuarded(() { + system.initialize(name, appID); + writeLog = (error, stack) => logError('$error:\n$stack'); + func(); + }, (error, stack) { + writeLog?.call(error, stack); + errorListener(error, stack); + }); + } +} diff --git a/lib/framework/data/isolate_data.dart b/lib/framework/data/isolate_data.dart new file mode 100644 index 0000000..107ee29 --- /dev/null +++ b/lib/framework/data/isolate_data.dart @@ -0,0 +1,7 @@ +enum IsolateEvent { ready, exit } + +class IsoMessege { + late String type; + late Object? data; + IsoMessege(this.type, {this.data}); +} diff --git a/lib/framework/log/log.dart b/lib/framework/log/log.dart new file mode 100644 index 0000000..1009f9c --- /dev/null +++ b/lib/framework/log/log.dart @@ -0,0 +1,119 @@ +import 'dart:io'; + +import 'package:oto_cli/framework/platform/platform_base.dart'; +import 'package:oto_cli/framework/utils/path.dart'; +import 'package:oto_cli/framework/utils/string_util.dart'; + +void log(String message) { + _logSend(message, LogType.verbose); +} + +void logWarning(String message) { + _logSend(message, LogType.warning); +} + +void logError(String message) { + _logSend(message, LogType.error); +} + +void _logSend(String message, LogType type) { + var item = LogItem(message, type); + Log.to.append(item); +} + +void logClear() { + Log.to.clear(); +} + +void logEnd() { + Log.to.end(); +} + +enum LogType { verbose, error, warning } + +class LogItem { + late String message; + late String date; + late LogType type; + + LogItem(this.message, this.type) { + date = getDates(); + } + @override + String toString() { + return '[$date][${type.name}] $message'; + } +} + +class Log { + static String? path; + int index = 0; + StringBuffer buffer = StringBuffer(); + final LogWriter _writer = LogWriter(); + Log._privateConstructor() { + initializeLog(); + } + static Log _instance = Log._privateConstructor(); + static Log get to => _instance; + + final List logs = []; + + Log() { + _instance = this; + initializeLog(); + } + + void initializeLog() async { + if (path == null) { + path = Path.dataPath; + if (path!.isNotEmpty) { + path = '$path/logs'; + var dir = Directory(path!); + dir.createSync(recursive: true); + } + } + if (path != null && path!.isNotEmpty) { + _writer.start( + path!, {'request': _onRequestMessage, 'ready': _onReadyMessage}); + } + } + + void _onRequestMessage(Object? data) { + write(); + } + + void _onReadyMessage(Object? data) { + path = data as String; + appendString('Log path: $data'); + } + + void write() { + if (index != logs.length) { + for (int i = logs.length - index - 1; i >= 0; --i) { + buffer.writeln(logs[i].toString()); + } + index = logs.length; + _writer.write(buffer.toString()); + buffer.clear(); + } + } + + void appendString(String message) { + append(LogItem(message, LogType.verbose)); + } + + void append(LogItem item) { + logs.insert(0, item); + } + + void clear() { + logs.clear(); + index = 0; + appendString('Log Restarted.'); + } + + void end() { + write(); + _writer.end(); + } +} diff --git a/lib/framework/model/app_data.dart b/lib/framework/model/app_data.dart new file mode 100644 index 0000000..8f0d411 --- /dev/null +++ b/lib/framework/model/app_data.dart @@ -0,0 +1,18 @@ +import 'package:json_annotation/json_annotation.dart'; + +part 'app_data.g.dart'; + +@JsonSerializable() +class AppData { + AppData(); + + late String name; + late String version; + late int? gitCount; + late String gitHash; + late String buildDate; + + factory AppData.fromJson(Map json) => + _$AppDataFromJson(json); + Map toJson() => _$AppDataToJson(this); +} diff --git a/lib/framework/model/app_data.g.dart b/lib/framework/model/app_data.g.dart new file mode 100644 index 0000000..99ded3d --- /dev/null +++ b/lib/framework/model/app_data.g.dart @@ -0,0 +1,22 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'app_data.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +AppData _$AppDataFromJson(Map json) => AppData() + ..name = json['name'] as String + ..version = json['version'] as String + ..gitCount = (json['gitCount'] as num?)?.toInt() + ..gitHash = json['gitHash'] as String + ..buildDate = json['buildDate'] as String; + +Map _$AppDataToJson(AppData instance) => { + 'name': instance.name, + 'version': instance.version, + 'gitCount': instance.gitCount, + 'gitHash': instance.gitHash, + 'buildDate': instance.buildDate, + }; diff --git a/lib/framework/platform/isolate_manager.dart b/lib/framework/platform/isolate_manager.dart new file mode 100644 index 0000000..f73a4f4 --- /dev/null +++ b/lib/framework/platform/isolate_manager.dart @@ -0,0 +1,276 @@ +import 'dart:isolate'; +import 'dart:async'; + +import 'package:oto_cli/framework/data/isolate_data.dart'; +import 'package:oto_cli/framework/utils/system_util.dart' as system; + +class _IsolateInnerEvent { + static const String ready = '_IsolateInnerEvent.Ready'; + static const String exit = '_IsolateInnerEvent.Exit'; +} + +class _IsolateConstructData { + late int id; + late SendPort mainIsoSender; + late Object? initData; + late String appName; + late String appID; + _IsolateConstructData( + this.id, this.mainIsoSender, this.appName, this.appID, this.initData); +} + +class IsolateHandler { + final int _id; + final Map> _listenerMap = {}; + final Map> _listenerEventMap = {}; + IsolateHandler(this._id); + + void send(String type, {Object? message}) { + IsolateManager.send(_id, IsoMessege(type, data: message)); + } + + void addListener(String type, void Function(Object?) func) { + removeListener(type, func); + if (!_listenerMap.containsKey(type)) { + _listenerMap[type] = []; + } + _listenerMap[type]?.add(func); + } + + void removeListener(String type, void Function(Object? data) func) { + if (_listenerMap.containsKey(type)) { + _listenerMap[type]?.remove(func); + } + } + + void addEventListener(IsolateEvent event, void Function(Object? data) func) { + removeEventListener(event, func); + if (!_listenerEventMap.containsKey(event)) { + _listenerEventMap[event] = []; + } + _listenerEventMap[event]?.add(func); + } + + void removeEventListener( + IsolateEvent event, void Function(Object? data) func) { + if (_listenerEventMap.containsKey(event)) { + _listenerEventMap[event]?.remove(func); + } + } + + void broadcast(String type, Object? data) { + IsolateManager.sendBroadcast(IsoMessege(type, data: data)); + } + + void _isolateEventHandler(IsolateEvent event, Object? data) { + if (_listenerEventMap.containsKey(event)) { + var list = _listenerEventMap[event]; + for (var item in list!) { + item(data); + } + } + } + + void _isolateMessageHandler(IsoMessege message) { + var type = message.type; + if (_listenerMap.containsKey(type)) { + var list = _listenerMap[type]; + for (var item in list!) { + item(message.data); + } + } + } + + void exit() { + IsolateManager.exit(_id); + } +} + +class IsolateManager { + IsolateManager._privateConstructor(); + static final IsolateManager _instance = IsolateManager._privateConstructor(); + static IsolateManager get instance => _instance; + + static int _nonce = 0; + static int get nonce { + if (_nonce == double.maxFinite.toInt()) { + _nonce = 0; + } else { + _nonce++; + } + return _nonce; + } + + final Map _isoMap = {}; + final Map> _innerEventMap = {}; + + static IsolateHandler create(T inst, + {Object? initData}) { + var id = nonce; + var handler = IsolateHandler(id); + instance._create(inst, initData, id, handler._isolateEventHandler, + handler._isolateMessageHandler); + return handler; + } + + void _create( + T inst, + Object? initData, + int id, + Function(IsolateEvent, Object?) isolateEventListener, + Function(IsoMessege) messageListener) async { + final isoListener = ReceivePort(); + inst.id = id; + _isoMap[id] = inst; + _addInnerEvent(id, _IsolateInnerEvent.ready, (message) { + inst.isoListener = message as SendPort; + isolateEventListener(IsolateEvent.ready, id); + }); + await Isolate.spawn( + inst.initialize, + _IsolateConstructData(id, isoListener.sendPort, system.appName, + system.appIdendifier, initData)); + await for (IsoMessege message in isoListener) { + if (message.type == _IsolateInnerEvent.exit) { + isolateEventListener(IsolateEvent.exit, null); + break; + } else if (_filterInnerEvent(id, message)) { + messageListener(message); + } + } + isoListener.close(); + _isoMap.remove(id); + } + + void _addInnerEvent(int id, String type, Function(Object?) listener) { + Map? eventMap; + if (!_innerEventMap.containsKey(id)) { + eventMap = {}; + _innerEventMap[id] = eventMap; + } + eventMap![type] = listener; + } + + bool _filterInnerEvent(int id, IsoMessege message) { + var isNotExist = true; + if (_innerEventMap.containsKey(id) && + _innerEventMap[id]!.containsKey(message.type)) { + isNotExist = false; + _innerEventMap[id]![message.type]!(message.data); + } + return isNotExist; + } + + static void sendBroadcast(IsoMessege message) { + var entries = instance._isoMap.entries; + for (var entry in entries) { + entry.value.insertEvent(message); + } + } + + static void send(int id, IsoMessege message) { + var map = instance._isoMap; + if (map.containsKey(id)) { + map[id]?.insertEvent(message); + } + } + + static void exit(int id) { + var map = instance._isoMap; + if (map.containsKey(id)) { + map[id]!.insertEvent(IsoMessege(_IsolateInnerEvent.exit)); + } + } +} + +class _IsolateEventListener { + late bool executeOnce; + late Function(Object?) listener; + _IsolateEventListener(this.listener, this.executeOnce); +} + +class IsolateBase { + late int id; + late ReceivePort _mainIsoListener; + late SendPort _mainIsoSender; + late SendPort isoListener; + final Map> _eventMap = {}; + final List<_IsolateEventListener> _removeList = []; + + // ignore: library_private_types_in_public_api + Future initialize(_IsolateConstructData initData) async { + id = initData.id; + _mainIsoListener = ReceivePort(); + _mainIsoSender = initData.mainIsoSender; + system.initialize(initData.appName, initData.appID); + + send(IsoMessege(_IsolateInnerEvent.ready, data: _mainIsoListener.sendPort)); + onReady(initData.initData); + await for (IsoMessege message in _mainIsoListener) { + if (message.type == _IsolateInnerEvent.exit) { + send(IsoMessege(_IsolateInnerEvent.exit)); + break; + } else { + _onEvent(message); + } + } + Isolate.exit(_mainIsoSender); + } + + void onReady(Object? initData) async {} + + void send(IsoMessege message) { + _mainIsoSender.send(message); + } + + void _onEvent(IsoMessege message) { + if (_eventMap.containsKey(message.type)) { + var list = _eventMap[message.type]!; + for (var item in list) { + item.listener(message.data); + if (item.executeOnce) { + _removeList.add(item); + } + } + if (_removeList.isNotEmpty) { + for (var item in _removeList) { + removeEventListener(message.type, item.listener); + } + _removeList.clear(); + } + } + } + + void addEventListener(String type, Function(Object?) listener, + {bool executeOnce = false}) { + List<_IsolateEventListener> list; + if (_eventMap.containsKey(type)) { + list = _eventMap[type]!; + } else { + list = []; + _eventMap[type] = list; + } + list.add(_IsolateEventListener(listener, executeOnce)); + } + + void removeEventListener(String type, Function(Object?) listener) { + if (_eventMap.containsKey(type)) { + var list = _eventMap[type]!; + for (int i = 0; i < list.length; ++i) { + var item = list[i]; + if (item.listener == listener) { + list.removeAt(i); + --i; + } + } + } + } + + void insertEvent(IsoMessege message) { + isoListener.send(message); + } + + void exit() { + IsolateManager.exit(id); + } +} diff --git a/lib/framework/platform/platform_base.dart b/lib/framework/platform/platform_base.dart new file mode 100644 index 0000000..e4c5093 --- /dev/null +++ b/lib/framework/platform/platform_base.dart @@ -0,0 +1,20 @@ +import 'dart:typed_data'; + +import 'package:oto_cli/framework/platform/platform_stub.dart' + if (dart.library.io) 'package:oto_cli/framework/platform/platform_io.dart' + if (dart.library.html) 'package:oto_cli/framework/platform/platform_web.dart'; + +abstract class LogWriter { + factory LogWriter() => getLogWriter(); + + void start( + String path, Map messageListenerMap); + void write(String log); + void end(); +} + +void initializeApp(String name, String appID) => initialize(name, appID); + +Future getIPAddressPlatform(String domain) => getIPAddress(domain); + +Future readFileBytePlatform(String filePath) => readFileBytePlatform(filePath); diff --git a/lib/framework/platform/platform_io.dart b/lib/framework/platform/platform_io.dart new file mode 100644 index 0000000..88c464a --- /dev/null +++ b/lib/framework/platform/platform_io.dart @@ -0,0 +1,111 @@ +import 'dart:io'; +import 'dart:typed_data'; + +import 'package:oto_cli/framework/platform/platform_base.dart'; +import 'package:oto_cli/framework/utils/system_util.dart'; +import 'package:oto_cli/framework/utils/path.dart'; +import 'package:path/path.dart' as path; + +import 'package:oto_cli/framework/platform/isolate_manager.dart'; +import 'package:oto_cli/framework/utils/string_util.dart'; +import 'package:oto_cli/framework/data/isolate_data.dart'; + +// Interfaces +LogWriter getLogWriter() => LogWriterIO(); + +void initialize(String name, String appID) { + appIdendifier = appID; + appName = name; + scriptPath = Platform.script.toFilePath(windows: Platform.isWindows); + executablePath = Platform.executable; + isDebug = + path.basenameWithoutExtension(Platform.resolvedExecutable) == 'dart'; + var debugPath = isDebug ? '.debug' : ''; + userPath = Path.userPath; + dataPath = '${Path.dataPath}$debugPath'; + and = Platform.isWindows ? ';' : '&&'; + + intMax = 9007199254740991; + intMin = -intMax; +} + +Future getIPAddress(String domain) async { + late String ipAddress; + var regEx = RegExp(r'(://)([a-zA-Z0-9-.]+)(/|:)'); + var match = regEx.firstMatch(domain); + if (match != null && match.groupCount > 2) { + domain = match.group(2)!; + var list = await InternetAddress.lookup(domain); + for (var address in list) { + ipAddress = address.address; + break; + } + } + return dataFutrue(ipAddress); +} + +Future readFileByte(String filePath) async { + Uri myUri = Uri.parse(filePath); + File audioFile = File.fromUri(myUri); + Uint8List? bytes; + await audioFile.readAsBytes().then((value) { + bytes = Uint8List.fromList(value); + print('reading of bytes is completed'); + }).catchError((onError) { + print('Exception Error while reading audio from path:$onError'); + }); + return dataFutrue(bytes); +} + +class LogWriterIO extends IsolateBase implements LogWriter { + late int _id; + late File _file; + @override + void onReady(Object? initData) async { + if ((initData as String?) != null) { + var dir = Directory(initData as String); + if (dir.existsSync()) { + _file = File(path.normalize( + '${dir.path}/log_${getDates().replaceAll(' ', '_').replaceAll(':', '-')}.txt')); + await _file.create(); + print('[LogWriterIO] onReady - path: ${_file.path}'); + send(IsoMessege('ready', data: _file.path)); + addEventListener('write', onWrite); + requester(); + } + } + } + + void requester() async { + while (true) { + await Future.delayed(const Duration(seconds: 3)); + send(IsoMessege('request')); + } + } + + void onWrite(Object? message) { + if (!_file.existsSync()) _file.createSync(recursive: true); + _file.writeAsStringSync(message as String, mode: FileMode.append); + } + + @override + void start( + String path, Map messageListenerMap) { + var handler = + IsolateManager.create(LogWriterIO(), initData: path); + handler.addEventListener(IsolateEvent.ready, (data) => _id = data as int); + for (var element in messageListenerMap.entries) { + handler.addListener(element.key, element.value); + } + } + + @override + void write(String log) { + IsolateManager.send(_id, IsoMessege('write', data: log)); + } + + @override + void end() { + IsolateManager.exit(_id); + } +} diff --git a/lib/framework/platform/platform_stub.dart b/lib/framework/platform/platform_stub.dart new file mode 100644 index 0000000..a817175 --- /dev/null +++ b/lib/framework/platform/platform_stub.dart @@ -0,0 +1,11 @@ +import 'dart:typed_data'; + +import 'package:oto_cli/framework/platform/platform_base.dart'; + +LogWriter getLogWriter() => throw UnsupportedError('Cannot create a instance'); + +void initialize(String name, String appID) => throw UnsupportedError('Cannot execute method'); + +Future getIPAddress(String domain) => throw UnsupportedError('Cannot execute method'); + +Future readFileByte(String filePath) => throw UnsupportedError('Cannot execute method'); diff --git a/lib/framework/platform/platform_web.dart b/lib/framework/platform/platform_web.dart new file mode 100644 index 0000000..dd4fc2e --- /dev/null +++ b/lib/framework/platform/platform_web.dart @@ -0,0 +1,29 @@ +import 'dart:typed_data'; + +import 'package:oto_cli/framework/platform/platform_base.dart'; +import 'package:oto_cli/framework/utils/system_util.dart'; + +// Interfaces +LogWriter getLogWriter() => LogWriterWeb(); + +void initialize(String name, String appID) { + appIdendifier = appID; + appName = name; + intMax = 9007199254740991; + intMin = -intMax; +} + +Future getIPAddress(String domain) => dataFutrue(''); + +Future readFileByte(String filePath) => dataFutrue(null); + +class LogWriterWeb implements LogWriter { + @override + void start(String path, Map messageListenerMap) {} + + @override + void write(String log) {} + + @override + void end() {} +} diff --git a/lib/framework/platform/process.dart b/lib/framework/platform/process.dart new file mode 100644 index 0000000..fa28261 --- /dev/null +++ b/lib/framework/platform/process.dart @@ -0,0 +1,679 @@ +// ignore_for_file: avoid_init_to_null + +import 'dart:async'; +import 'dart:io'; +import 'dart:convert'; +import 'dart:math'; + +import 'package:oto_cli/framework/log/log.dart'; +import 'package:oto_cli/framework/utils/system_util.dart'; + +typedef LogHandler = Function(String, LogType); + +class ProcessData { + int? exitCode; + late Process _process; + late File file; + late StringBuffer stdout; + late StringBuffer stderr; + final bool _enableStdout; + final bool _enableStderr; + final Completer _completer = Completer(); + LogHandler? _logHandler; + bool _completeStdout = false; + bool _completeStderr = false; + bool _completeExitCode = false; + late Converter, String> _decoder; + + // ignore: no_leading_underscores_for_local_identifiers + ProcessData(this._enableStdout, this._enableStderr, + {LogHandler? logHandler, Converter, String>? decoder}) { + _logHandler = logHandler; + _decoder = + Platform.isWindows ? SystemEncoding().decoder : decoder ?? utf8.decoder; + } + + bool get isSuccess { + if (Platform.isWindows) return exitCode == 1; + return exitCode == 0; + } + + List get stdoutArr { + return getBufferToArray(stdout); + } + + List get stderrArr { + return getBufferToArray(stderr); + } + + List getBufferToArray(StringBuffer buffer) { + var list = []; + var arr = buffer.toString().split('\n'); + var length = arr.length; + for (var i = 0; i < length; ++i) { + if (arr[i].isNotEmpty) { + list.add(arr[i]); + } + } + return list; + } + + Process get process { + return _process; + } + + set process(Process value) { + _process = value; + stdout = StringBuffer(); + stderr = StringBuffer(); + _process.stdout.transform(_decoder).transform(LineSplitter()).listen( + (event) { + stdout.writeln(event); + if (_enableStdout) { + log(event, LogType.verbose); + } + }, onDone: () { + _completeStdout = true; + _checkComplete(); + }); + _process.stderr.transform(_decoder).transform(LineSplitter()).listen( + (event) { + stderr.writeln(event); + if (_enableStderr) { + log('[Error] $event', LogType.error); + } + }, onDone: () { + _completeStderr = true; + _checkComplete(); + }); + _checkExitCode(); + } + + void log(String message, LogType logType) { + if (_logHandler == null) { + print(message); + } else { + _logHandler!(message, logType); + } + } + + void terminate() { + _process.kill(); + _deleteFile(); + } + + void _deleteFile() async { + if (file.existsSync()) { + file.deleteSync(); + } + } + + void _checkExitCode() async { + exitCode = await _process.exitCode; + _completeExitCode = true; + _checkComplete(); + } + + void _checkComplete() { + if (_completeExitCode && _completeStdout && _completeStderr) { + _deleteFile(); + _completer.complete(); + } + } + + Future waitForExit() async { + return _completer.future; + } +} + +class ProcessExecutor { + static bool _initedPowershell = false; + static Future initPowershell() async { + if (!_initedPowershell) { + var result = await Process.run( + 'powershell', + [ + '-Command', + 'Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy RemoteSigned' + ], + runInShell: true, + ); + + _initedPowershell = true; + + if (result.stderr.toString().trim().isNotEmpty) { + print('[Powershell Grant] Error: ${result.stderr}'); + } + } + return simpleFuture; + } + + static Future startExe(String exe, List args, + {String? workspace, + bool? printStdout, + bool? printStderr, + LogHandler? logHandler}) async { + var arg = '$exe ${args.join(' ')}'; + var printStdout_ = printStdout ?? true; + var printStderr_ = printStderr ?? true; + var processData = + ProcessData(printStdout_, printStderr_, logHandler: logHandler); + if (Platform.isMacOS || Platform.isWindows) { + workspace = workspace ?? Directory.systemTemp.path; + if (printStdout_) { + logHandler?.call('Execute Shell: $arg', LogType.verbose); + } + try { + processData.process = + await Process.start(exe, args, workingDirectory: workspace); + } on Exception catch (e) { + logHandler?.call(e.toString(), LogType.error); + } + } else { + logHandler ?? ('This platform not support process executor.'); + } + return dataFutrue(processData); + } + + static Future start(StringBuffer shell, + {Converter, String>? decoder, + String? workspace, + bool? printStdout, + bool? printStderr, + LogHandler? logHandler}) async { + var c = Completer(); + try { + var printStdout_ = printStdout ?? true; + var printStderr_ = printStderr ?? true; + var processData = ProcessData(printStdout_, printStderr_, + logHandler: logHandler, decoder: decoder); + if (Platform.isMacOS || Platform.isLinux) { + workspace = workspace ?? Directory.systemTemp.path; + var file = File('$workspace/$tempFileName'); + processData.file = file; + if (printStdout_) { + logHandler?.call( + 'Execute Shell: ${file.path} \n ${shell.toString()}', + LogType.verbose + ); + } + if (file.existsSync()) { + file.deleteSync(); + } + file.createSync(); + file.writeAsStringSync(shell.toString(), flush: true); + try { + var shellExe = Platform.isMacOS ? 'zsh' : 'bash'; + processData.process = await Process.start(shellExe, [file.path], + workingDirectory: workspace); + } on Exception catch (e) { + logHandler?.call(e.toString(), LogType.error); + } + } else if (Platform.isWindows) { + workspace = workspace ?? Directory.systemTemp.path; + var file = File('$workspace/$tempFileName'); + processData.file = file; + if (printStdout_) { + logHandler?.call( + 'Execute Shell: ${file.path} \n ${shell.toString()}', + LogType.verbose + ); + } + if (await file.exists()) { + await file.delete(); + } + file.createSync(); + file.writeAsStringSync(shell.toString(), flush: true); + + await initPowershell(); + try { + processData.process = await Process.start( + 'powershell', ['-NoProfile', '-File', file.absolute.path]); + } on Exception catch (e) { + logHandler?.call(e.toString(), LogType.error); + } + } else { + logHandler?.call( + 'This platform not support process executor.', LogType.error); + } + c.complete(processData); + await processData.waitForExit(); + } on Exception catch (e) { + logHandler?.call( + 'General Exception in ProcessExecutor.start: $e', LogType.error); + } + return c.future; + } + + static Future run(StringBuffer shell, + {String? workspace, + bool printStdout = true, + bool printStderr = true, + Converter, String>? decoder, + LogHandler? logHandler}) async { + var c = Completer(); + workspace = workspace ?? Directory.systemTemp.path; + var file = File('$workspace/$tempFileName'); + if (printStdout) { + logHandler?.call( + '---------------------------------------------------', + LogType.verbose + ); + logHandler?.call( + 'Shell Path: ${file.path} \nExecute Shell: ${shell.toString()}', + LogType.verbose + ); + } + ProcessResult? processResult; + if (Platform.isMacOS || Platform.isLinux) { + file.createSync(); + file.writeAsStringSync(shell.toString()); + try { + var shellExe = Platform.isMacOS ? 'zsh' : 'bash'; + processResult = await Process.run(shellExe, [file.path], + workingDirectory: workspace); + } on Exception catch (e) { + logHandler?.call(e.toString(), LogType.error); + } finally { + file.deleteSync(); + } + c.complete(processResult); + } else if (Platform.isWindows) { + file.createSync(); + file.writeAsStringSync(shell.toString()); + + print(file.absolute.path); + + await initPowershell(); + + processResult = await Process.run( + 'powershell', + ['-NoProfile', '-File', file.absolute.path], + runInShell: true); + + file.deleteSync(); + c.complete(processResult); + } else { + logHandler?.call( + 'This platform not support process executor.', LogType.error); + c.complete(null); + } + if (processResult != null) { + if (printStdout) { + var stdout = processResult.stdout.toString(); + if (decoder != null) { + stdout = decoder.convert(stdout.codeUnits); + } + logHandler?.call( + '[ProcessExecutor] Result: $stdout', + LogType.verbose + ); + } + if (printStderr) { + var stderr = processResult.stderr.toString(); + if (decoder != null) { + stderr = decoder.convert(stderr.codeUnits); + } + logHandler?.call( + '[ProcessExecutor] Exit Code: ${processResult.exitCode}\nError: $stderr', + LogType.verbose + ); + } + } + return c.future; + } + + static String get tempFileName { + if (Platform.isMacOS || Platform.isLinux) { + return 'temp_${DateTime.now().microsecondsSinceEpoch}.sh'; + } else { + return 'temp_${DateTime.now().microsecondsSinceEpoch}.ps1'; + } + } +} + +class NetStatData { + late String type; + late String from; + late String to; + late String state; + late int pid; + + NetStatData(List categories) { + var count = 0; + var length = categories.length; + for (var i = 0; i < length; ++i) { + var category = categories[i].replaceAll(' ', ''); + if (category.isNotEmpty) { + switch (count) { + case 0: + type = category; + break; + case 1: + from = category; + break; + case 2: + to = category; + break; + case 3: + state = category; + break; + case 4: + var value = int.tryParse(category); + value ??= -1; + pid = value; + break; + } + count++; + } + } + } +} + +bool _removedBat = false; +Future removeTempBat() async { + var c = Completer(); + if (!_removedBat) { + _removedBat = true; + var reg = RegExp(r'(temp_bat_)([0-9_]+)(.bat)'); + var list = Directory.current.listSync(); + for (var item in list) { + var match = reg.stringMatch(item.path); + if (match != null) { + await item.delete(); + } + } + await Future.delayed(Duration(milliseconds: 500)); + } + c.complete(); + return c.future; +} + +Future runGetStdout(StringBuffer shell) async { + var c = Completer(); + var result = await ProcessExecutor.run(shell); + if (result.exitCode == 0 || result.exitCode == 1) { + c.complete(result.stdout); + return c.future; + } else { + throw Exception(result.stderr); + } +} + +Future findUsePortPid(int port) async { + await removeTempBat(); + var c = Completer(); + var shell = StringBuffer('netstat -aon | find "$port"'); + var stdout = ""; + try { + stdout = await runGetStdout(shell); + } on Exception {} + if (stdout == "") { + c.complete(null); + } else { + var netList = []; + var returnPattern = RegExp('\n|\r'); + var list = stdout.split(returnPattern); + for (var item in list) { + item = item.replaceAll(returnPattern, ''); + if (item.isNotEmpty) { + var categories = item.split(' '); + if (categories.isNotEmpty) { + netList.add(NetStatData(categories)); + } + } + } + NetStatData? data = null; + if (netList.length > 1) { + for (var net in netList) { + if (net!.pid != -1) { + data = net; + break; + } + } + } + c.complete(data); + } + return c.future; +} + +Future> findProcess(String searchWord) async { + await removeTempBat(); + var c = Completer>(); + var pList = []; + if (Platform.isWindows) { + var csvPath = File( + '${Directory.systemTemp.absolute.path}\\temp_${Random().nextInt(100000)}.csv'); + var shell = StringBuffer( + 'Get-CimInstance -ClassName Win32_Process | Where-Object { \$_.Name.Contains("$searchWord") } | Select-Object CommandLine, ProcessId | Export-Csv -Path ${csvPath.absolute.path} -NoTypeInformation'); + var result = await ProcessExecutor.run(shell); + if (result.exitCode == 0 && csvPath.existsSync()) { + pList = parseProcessStd(csvPath.readAsStringSync()); + csvPath.deleteSync(); + } + } else if (Platform.isLinux) { + var shell = StringBuffer('ps -ef | grep \'$searchWord\' | grep -v grep'); + var result = await ProcessExecutor.run(shell, printStdout: false); + if (result.exitCode == 0) { + var procList = result.stdout.toString().split('\n'); + for (var proc in procList) { + if (proc.isNotEmpty) { + var info = ProcessInfo(); + var index = proc.indexOf(' '); + proc = proc.substring(index, proc.length).trimLeft(); + index = proc.indexOf(' '); + info.pid = int.parse(proc.substring(0, index)); + proc = proc.substring(index).trimLeft(); + + index = proc.indexOf(' '); + info.ppid = int.parse(proc.substring(0, index)); + proc = proc.substring(index).trimLeft(); + + index = proc.indexOf(' '); + info.cpuUsage = int.parse(proc.substring(0, index)); + proc = proc.substring(index).trimLeft(); + + index = proc.indexOf(' '); + info.startTime = proc.substring(0, index); + proc = proc.substring(index).trimLeft(); + + index = proc.indexOf(' '); + info.sessionName = proc.substring(0, index); + proc = proc.substring(index).trimLeft(); + + index = proc.indexOf(' '); + info.duration = proc.substring(0, index); + + info.name = proc.substring(index).trimLeft(); + pList.add(info); + } + } + } + } else { + var shell = StringBuffer( + 'ps -A | grep \'$searchWord\' | grep -v grep | awk \'{\$2=\$3=""; print \$0}\''); + var result = await ProcessExecutor.run(shell, printStdout: false); + if (result.exitCode == 0) { + var procList = result.stdout.toString().split('\n'); + for (var proc in procList) { + if (proc.isNotEmpty) { + var info = ProcessInfo(); + var index = proc.indexOf(' '); + info.pid = int.parse(proc.substring(0, index)); + info.name = proc.substring(index).trimLeft(); + pList.add(info); + } + } + } + } + c.complete(pList); + return c.future; +} + +List parseProcessStd(String stdout) { + var pList = []; + var returnPattern = RegExp('\n|\r'); + var list = stdout.split(returnPattern); + for (var item in list) { + item = item.replaceAll(returnPattern, ''); + if (item.isNotEmpty && !item.contains('CommandLine')) { + var categories = item.split(','); + if (categories.length > 1) { + pList.add(ProcessInfo.category(categories)); + } + } + } + return pList; +} + +Future findProcessByPid(int pid) async { + var c = Completer(); + var shell = + StringBuffer('tasklist /fi "pid eq ${pid.toString()}" /nh /fo "csv"'); + var stdout = await runGetStdout(shell); + var pList = parseProcessStd(stdout); + if (pList.isNotEmpty) { + c.complete(pList.first); + } else { + c.complete(null); + } + return c.future; +} + +class ProcessSilentExecutor { + static bool _initialized = false; + static Future initialize() async { + if (!_initialized) { + _initialized = true; + var regBat = RegExp(r'(silent_bat_)([0-9_]+)(.bat)'); + var regLog = RegExp(r'(silent_log_)([0-9_]+)(.txt)'); + var list = Directory.current.listSync(); + for (var item in list) { + var matchBat = regBat.stringMatch(item.path); + var matchLog = regLog.stringMatch(item.path); + if (matchBat != null || matchLog != null) { + item.deleteSync(); + } + } + } + } +} + +String getRnadomPostfix() { + return '${DateTime.now().microsecondsSinceEpoch}_${Random().nextInt(100)}'; +} + +File getTempBat({String? fixedName}) { + fixedName ??= getRnadomPostfix(); + File batch = File('${Directory.systemTemp.path}/temp_bat_$fixedName.bat'); + return batch; +} + +class ProcessInfoListener { + late ProcessInfo? _process; + bool isRunning = false; + late Timer? _timer; + late final int _checkInterval; + late Function(ProcessInfoListener, bool)? _connectionListener; + set _isRunning(bool value) { + if (isRunning != value) { + isRunning = value; + changedConnection(); + } + } + + ProcessInfoListener(this._process, this._checkInterval) { + checkLive(); + } + + void checkLive() async { + stopChecker(); + _isRunning = true; + _timer = Timer.periodic(Duration(seconds: _checkInterval), (time) async { + var enable = false; + if (_process != null) { + var proc = await findProcessByPid(_process!.pid); + if (proc != null) { + print('process live'); + enable = true; + _isRunning = true; + } + } + + if (!enable) { + _isRunning = false; + stopChecker(); + } + }); + } + + void stopChecker() { + if (_timer != null) { + _timer!.cancel(); + _timer = null; + } + } + + void changedConnection() { + if (_connectionListener != null) { + _connectionListener!(this, isRunning); + } + } + + Function(ProcessInfoListener, bool)? get endListener { + return _connectionListener; + } + + void addEndListener(Function(ProcessInfoListener, bool)? listener) { + _connectionListener = listener; + } + + void removeConnectionListener() { + _connectionListener = null; + } + + void dispose() { + stopChecker(); + removeConnectionListener(); + _isRunning = false; + _process = null; + } + + void terminate() { + if (isRunning && _process != null) { + Process.killPid(_process?.pid as int); + } + } +} + +class ProcessInfo { + String? startTime; + String? duration; + int? ppid; + int? cpuUsage; + late String name; + late int pid; + late String sessionName; + late int session; + late String memory; + + ProcessInfo(); + ProcessInfo.category(List categories) { + var count = 0; + var length = categories.length; + for (var i = 0; i < length; ++i) { + var category = categories[i].replaceAll('"', ''); + switch (count) { + case 0: + name = category; + break; + case 1: + var value = int.tryParse(category); + value ??= -1; + pid = value; + break; + } + count++; + } + } +} diff --git a/lib/framework/utils/os_startup.dart b/lib/framework/utils/os_startup.dart new file mode 100644 index 0000000..f49d3f5 --- /dev/null +++ b/lib/framework/utils/os_startup.dart @@ -0,0 +1,400 @@ +import 'dart:io'; +import 'dart:async'; + +import 'package:oto_cli/framework/utils/path.dart'; +import 'package:oto_cli/framework/utils/system_util.dart'; +import 'package:oto_cli/framework/platform/process.dart'; +import 'package:path/path.dart' as path; + +class OSStartup { + static _Startup? _instance; + static _Startup? get _current { + if (_instance == null) { + if (Platform.isMacOS) { + _instance = _StartupMac(); + } else if (Platform.isLinux) { + _instance = _StartupLinux(); + } else { + _instance = _StartupWindows(); + } + } + return _instance; + } + + static Future isRegistedStartup(String label) async { + return _current!.isRegistedStartup(label); + } + + static Future registStartup(String executableFilePath, String label, + {List? arguments, + String? logStandardFilePath, + String? logErrorFilePath}) async { + return _current!.registStartup(executableFilePath, label, + arguments: arguments, + logStandardFilePath: logStandardFilePath, + logErrorFilePath: logErrorFilePath); + } + + static Future unregistStartup(String label) async { + return _current!.unregistStartup(label); + } +} + +class _Startup { + Future isRegistedStartup(String label) async { + var c = Completer(); + return c.future; + } + + Future registStartup(String executableFilePath, String label, + {List? arguments, + String? logStandardFilePath, + String? logErrorFilePath}) async { + var c = Completer(); + return c.future; + } + + Future unregistStartup(String label) async { + var c = Completer(); + return c.future; + } +} + +/// ************* MAC *************** +class _StartupMac extends _Startup { + final plistTemplate = """ + + + + KeepAlive + + Label + {LABEL} + ProgramArguments + + {FILE_PATH} + + RunAtLoad + {LOG_STANDARD}{LOG_ERROR} + +"""; + + final pathTemplate = """#!/bin/bash + +# Load .zprofile if it exists +if [ -f ~/.zprofile ]; then + source ~/.zprofile +fi + +# Load .bash_profile if it exists +if [ -f ~/.bash_profile ]; then + source ~/.bash_profile +fi + +# Load .bashrc if it exists (optional) +if [ -f ~/.bashrc ]; then + source ~/.bashrc +fi + +# Load .zshrc if it exists (optional) +if [ -f ~/.zshrc ]; then + source ~/.zshrc +fi + +# Run your command +{COMMAND} +"""; + + final logStandardTemplate = """ + + StandardOutPath + {LOG_STANDARD}"""; + final logErrorTemplate = """ + + StandardErrorPath + {LOG_ERROR}"""; + + @override + Future isRegistedStartup(String label) async { + var c = Completer(); + var plistName = '$label.plist'; + var userPath = Path.userPath; + c.complete( + await File('$userPath/Library/LaunchAgents/$plistName').exists()); + return c.future; + } + + @override + Future registStartup(String executableFilePath, String label, + {List? arguments, + String? logStandardFilePath, + String? logErrorFilePath}) async { + final tagLabel = '{LABEL}'; + final tagPath = '{FILE_PATH}'; + final plistName = '$label.plist'; + final userPath = Path.userPath; + var success = false; + final appDir = Directory('$userPath/Library/$label'); + final file = File('${appDir.path}/launch.sh'); + + if (!appDir.existsSync()) { + appDir.createSync(recursive: true); + } + + var param = arguments == null ? '' : ' ${arguments.join(' ')}'; + var launchContent = + pathTemplate.replaceAll('{COMMAND}', '$executableFilePath$param'); + file.writeAsStringSync(launchContent); + + final tagLogStandard = '{LOG_STANDARD}'; + final tagLogError = '{LOG_ERROR}'; + var plistContent = plistTemplate + .replaceAll(tagLabel, label) + .replaceAll(tagPath, file.path); + if (logStandardFilePath == null) { + plistContent = plistContent.replaceAll(tagLogStandard, ''); + } else { + plistContent = plistContent.replaceAll(tagLogStandard, + logStandardTemplate.replaceAll(tagLogStandard, logStandardFilePath)); + } + if (logErrorFilePath == null) { + plistContent = plistContent.replaceAll(tagLogError, ''); + } else { + plistContent = plistContent.replaceAll(tagLogError, + logErrorTemplate.replaceAll(tagLogError, logErrorFilePath)); + } + var plistFile = File('$userPath/Library/LaunchAgents/$plistName'); + await plistFile.create(); + await plistFile.writeAsString(plistContent); + + var result = await ProcessExecutor.run(StringBuffer( + 'chmod +x "$executableFilePath" && chmod +x "${file.path}" ')); + success = result.exitCode == 0; + + return dataFutrue(success); + } + + @override + Future unregistStartup(String label) async { + var c = Completer(); + var success = false; + var plistName = '$label.plist'; + var userPath = Path.userPath; + var file = File('$userPath/Library/LaunchAgents/$plistName'); + if (file.existsSync()) { + await file.delete(); + success = true; + } + c.complete(success); + return c.future; + } +} + +/// ************* LINUX *************** +class _StartupLinux extends _Startup { + final serviceTemplate = """[Unit] +Description={LABEL} + +[Service] +Type=simple +ExecStart={FILE_PATH} + +[Install] +WantedBy=default.target"""; + + @override + Future isRegistedStartup(String label) async { + var c = Completer(); + var exist = false; + var userPath = Path.userPath; + exist = + await File('$userPath/.config/systemd/user/$label.service').exists(); + c.complete(exist); + return c.future; + } + + @override + Future registStartup(String executableFilePath, String label, + {List? arguments, + String? logStandardFilePath, + String? logErrorFilePath}) async { + var c = Completer(); + final tagLabel = '{LABEL}'; + final tagPath = '{FILE_PATH}'; + ProcessResult? result; + + var userPath = Path.userPath; + var systemPath = '$userPath/.config/systemd/user'; + if (arguments != null) { + for (var arg in arguments) { + executableFilePath += ' $arg'; + } + } + var serviceContent = serviceTemplate + .replaceAll(tagLabel, label) + .replaceAll(tagPath, executableFilePath); + + var serviceFile = File('$systemPath/$label.service'); + await serviceFile.create(); + await serviceFile.writeAsString(serviceContent); + + var shell = StringBuffer(); + shell.write('cd $systemPath && '); + shell.write('systemctl --user enable $label && '); + shell.write('systemctl --user daemon-reload'); + result = await ProcessExecutor.run(shell); + print('exitCode: ${result.exitCode}'); + c.complete(result.exitCode == 0); + return c.future; + } + + @override + Future unregistStartup(String label) async { + var c = Completer(); + var success = false; + var userPath = Path.userPath; + var shell = StringBuffer(); + var systemPath = '$userPath/.config/systemd/user'; + shell.write('cd $systemPath && '); + shell.write('systemctl --user stop $label && '); + shell.write('systemctl --user disable $label && '); + shell.write('systemctl --user daemon-reload'); + var result = await ProcessExecutor.run(shell); + success = result.exitCode == 0; + + if (success) { + success = false; + var file = File('$systemPath/$label.service'); + if (await file.exists()) { + await file.delete(); + success = true; + } + } + c.complete(success); + return c.future; + } +} + +/// ************* WINDOWS *************** +class _StartupWindows extends _Startup { + final startupScriptTemplate = '''Start-Process -FilePath "{EXECUTABLE_PATH}" ` + {ARGUMENTS}-WindowStyle Hidden{LOG_STDOUT}{LOG_STDERR}'''; + + final schedulerScriptTemplate = ''' +\$ScriptPath = "{SCRIPT_PATH}" +\$TaskName = "{TASK_NAME}" +\$Trigger = New-ScheduledTaskTrigger -AtLogOn +\$Trigger +\$Action = New-ScheduledTaskAction -Execute "powershell.exe" -Argument "-ExecutionPolicy Bypass -File `"\$ScriptPath`"" +\$Action +Register-ScheduledTask -TaskName \$TaskName -Action \$Action -Trigger \$Trigger +Exit +'''; + + String getScriptPath(String label) { + return path.join(dataPath.replaceAll('/', '\\'), 'startup', '$label.ps1'); + } + + @override + Future isRegistedStartup(String label) async { + await ProcessExecutor.initPowershell(); + var shell = 'Get-ScheduledTask | Where-Object {\$_.TaskName -eq "$label"}'; + var process = await Process.run('powershell', [shell]); + var exist = false; + if (process.exitCode == 0) { + var existLine = []; + var stdoutList = process.stdout.toString().split('\n'); + for (var item in stdoutList) { + var result = item.trim(); + if (result.isNotEmpty) { + existLine.add(item); + } + } + if (existLine.length > 2) { + exist = true; + } + } + return dataFutrue(exist); + } + + @override + Future registStartup(String executableFilePath, String label, + {List? arguments, + String? logStandardFilePath, + String? logErrorFilePath}) async { + var scriptPath = getScriptPath(label); + var startupScript = startupScriptTemplate.replaceAll( + '{EXECUTABLE_PATH}', executableFilePath.replaceAll('/', '\\')); + var args = ''; + if (arguments != null) { + args = '''-ArgumentList "${arguments.join(' ')}" ` + '''; + } + startupScript = startupScript.replaceAll('{ARGUMENTS}', args); + var logStdout = ''; + if (logStandardFilePath != null) { + logStdout = ''' ` + -RedirectStandardOutput "$logStandardFilePath"'''; + } + startupScript = startupScript.replaceAll('{LOG_STDOUT}', logStdout); + + var logStderr = ''; + if (logErrorFilePath != null) { + logStderr = ''' ` + -RedirectStandardError "$logErrorFilePath"'''; + } + startupScript = startupScript.replaceAll('{LOG_STDERR}', logStderr); + + var startupFile = File(scriptPath); + startupFile.createSync(recursive: true); + startupFile.writeAsStringSync(startupScript, flush: true); + + var schedulerScript = schedulerScriptTemplate + .replaceAll('{SCRIPT_PATH}', scriptPath) + .replaceAll('{TASK_NAME}', label); + + var tempFile = + File('${Directory.systemTemp.path}\\${ProcessExecutor.tempFileName}'); + tempFile.createSync(recursive: true); + tempFile.writeAsStringSync(schedulerScript, flush: true); + + var powershellCommand = + 'Start-Process powershell.exe -ArgumentList "-NoProfile -ExecutionPolicy Bypass -Command `& \'${tempFile.path}\'; exit" -Verb RunAs -WindowStyle Hidden'; + + await ProcessExecutor.initPowershell(); + var process = await Process.run( + 'powershell', ['-Command', powershellCommand, '-Wait']); + + print(process.stdout.toString()); + print(process.stderr.toString()); + print(process.exitCode); + + tempFile.deleteSync(); + + return dataFutrue(process.exitCode == 0); + } + + @override + Future unregistStartup(String label) async { + await ProcessExecutor.initPowershell(); + var shell = 'Unregister-ScheduledTask -TaskName "$label" -Confirm:\$false'; + var process = await Process.run( + 'powershell', + [ + '-Command', + 'Start-Process powershell -ArgumentList \'-NoProfile -ExecutionPolicy Bypass -Command "$shell"\' -Verb RunAs -WindowStyle Hidden' + ], + runInShell: true, + ); + print(process.stdout.toString()); + print(process.stderr.toString()); + print(process.exitCode); + + var scriptFile = File(getScriptPath(label)); + if (scriptFile.existsSync()) { + scriptFile.deleteSync(); + } + + return dataFutrue(process.exitCode == 0); + } +} diff --git a/lib/framework/utils/path.dart b/lib/framework/utils/path.dart new file mode 100644 index 0000000..c10b6f0 --- /dev/null +++ b/lib/framework/utils/path.dart @@ -0,0 +1,132 @@ +import 'dart:io'; +import 'dart:async'; +import 'package:oto_cli/framework/utils/system_util.dart'; +import 'package:path/path.dart' as path; + +enum FileType { none, file, directory, link } + +class Path { + static String get userPath { + String path = ''; + if (Platform.isWindows) { + path = Platform.environment['USERPROFILE'] as String; + } else if (Platform.isMacOS || Platform.isLinux) { + path = Platform.environment['HOME'] as String; + } + return path; + } + + static String get dataPath { + String path = userPath; + if (Platform.isMacOS) { + path = '$path/Library/$appIdendifier'; + } else if (Platform.isLinux) { + path = '$path/.config/$appIdendifier'; + } else if (Platform.isWindows) { + path = '$path/AppData/Local/$appIdendifier'; + } + if (Platform.isWindows) path = path.replaceAll('/', '\\'); + return path; + } + + static String? getParent(String path) { + path = getNormal(path); + var separator = '/'; + int index = path.lastIndexOf(separator); + if (index == -1) { + return null; + } else { + return path.substring(0, index); + } + } + + static String getName(String path) { + path = getNormal(path); + var parent = getParent(path); + var separator = '/'; + return path.replaceAll('$parent$separator', ''); + } + + static String getNormal(String path) { + return path.replaceAll('\\', '/'); + } + + //Remove last slush(/) + static String getNormalizePath(String path) { + var separator = Platform.isMacOS ? '/' : '\\'; + if (path.lastIndexOf(separator) == path.length - 1) { + path = path.substring(0, path.lastIndexOf(separator)); + } + return path; + } + + static FileType getType(String path) { + if (Directory(path).existsSync()) return FileType.directory; + if (File(path).existsSync()) return FileType.file; + return FileType.none; + } + + static Future copy(String startPath, String destPath, bool isDir, + {required List? ignorePattern, + required List? ignoredList, + bool isMove = false, + bool isOverwrite = true}) async { + var c = Completer(); + var result = true; + if (ignorePattern != null) { + for (var pattern in ignorePattern) { + if (startPath.contains(pattern)) { + if (ignoredList != null) ignoredList.add(startPath); + c.complete(true); + return c.future; + } + } + } + try { + var name = Path.getName(startPath); + var destChildPath = path.join(destPath, name); + if (isDir) { + var startDir = Directory(startPath); + var destDir = Directory(destChildPath); + if (!startDir.existsSync()) { + throw ArgumentError('Start - $startPath is not exist'); + } + if (!destDir.existsSync()) destDir.createSync(recursive: true); + var files = startDir.listSync(); + for (var file in files) { + if (file is File) { + await copy(file.path, destDir.path, false, + ignorePattern: ignorePattern, + ignoredList: ignoredList, + isMove: isMove, + isOverwrite: isOverwrite); + } + if (file is Directory) { + await copy(file.path, destDir.path, true, + ignorePattern: ignorePattern, + ignoredList: ignoredList, + isMove: isMove, + isOverwrite: isOverwrite); + } + } + } else { + var destDir = Directory(destPath); + if (!destDir.existsSync()) destDir.createSync(recursive: true); + print('File copy: $startPath --> $destChildPath'); + var file = File(startPath); + var fileDest = File(destChildPath); + if (fileDest.existsSync()) { + await fileDest.delete(); + } + await file.copy(destChildPath); + if (isMove) { + await file.delete(recursive: true); + } + } + } on Exception { + result = false; + } + c.complete(result); + return c.future; + } +} diff --git a/lib/framework/utils/slack/slack_data.dart b/lib/framework/utils/slack/slack_data.dart new file mode 100644 index 0000000..a533cf3 --- /dev/null +++ b/lib/framework/utils/slack/slack_data.dart @@ -0,0 +1,223 @@ +// ignore_for_file: non_constant_identifier_names, avoid_init_to_null, constant_identifier_names +// ignore: depend_on_referenced_packages, implementation_imports + +import 'dart:async'; +import 'dart:convert'; +import 'dart:io'; + +import 'package:json_annotation/json_annotation.dart'; +import 'package:http/http.dart'; +part 'slack_data.g.dart'; + +enum SlackBlockType { header, section, divider, actions } + +enum SlackTextType { mrkdwn, plain_text } + +enum SlackActionType { button, select, image } + +enum SlackActionStyle { danger, primary } + +@JsonSerializable() +class DataSlack { + String channel; + String? text; + late List? blocks = null; + late List? attachments = null; + bool? link_names; + + String get json { + return jsonEncode(toJson()); + } + + DataSlack(this.channel); + + factory DataSlack.fromJson(Map json) => + _$DataSlackFromJson(json); + Map toJson() { + return removeKeys(_$DataSlackToJson(this)); + } +} + +Map removeKeys(Map map) { + var emptyKeys = []; + for (var item in map.entries) { + if (item.value == null) { + emptyKeys.add(item.key); + } + if (item.value is List) { + var list = item.value as List; + if (list.isEmpty) { + emptyKeys.add(item.key); + } + } + } + + for (var key in emptyKeys) { + map.remove(key); + } + return map; +} + +@JsonSerializable() +class SlackBlock { + late SlackBlockType type; + late String? block_id = null; + + SlackBlock(); + + factory SlackBlock.fromJson(Map json) => + _$SlackBlockFromJson(json); + Map toJson() => removeKeys(_$SlackBlockToJson(this)); +} + +@JsonSerializable() +class SlackBlockHeader extends SlackBlock { + late SlackBlockText? text; + + SlackBlockHeader() { + super.type = SlackBlockType.header; + } + + factory SlackBlockHeader.fromJson(Map json) => + _$SlackBlockHeaderFromJson(json); + @override + Map toJson() => removeKeys(_$SlackBlockHeaderToJson(this)); +} + +@JsonSerializable() +class SlackBlockSection extends SlackBlock { + late SlackBlockText? text = null; + late List? fields = null; + late SlackAccessory? accessory = null; + + SlackBlockSection() { + type = SlackBlockType.section; + } + + factory SlackBlockSection.fromJson(Map json) => + _$SlackBlockSectionFromJson(json); + @override + Map toJson() => removeKeys(_$SlackBlockSectionToJson(this)); +} + +@JsonSerializable() +class SlackAccessory { + late SlackActionType type; + late SlackBlockText? text = null; + late String? image_url = null; + late String? alt_text = null; + late String? value = null; + late String? url = null; + + SlackAccessory(); + + factory SlackAccessory.fromJson(Map json) => + _$SlackAccessoryFromJson(json); + Map toJson() => removeKeys(_$SlackAccessoryToJson(this)); +} + +@JsonSerializable() +class SlackBlockText { + SlackTextType type = SlackTextType.mrkdwn; + late String? text = null; + late bool? emoji = null; + + SlackBlockText(); + + factory SlackBlockText.fromJson(Map json) => + _$SlackBlockTextFromJson(json); + Map toJson() => removeKeys(_$SlackBlockTextToJson(this)); +} + +@JsonSerializable() +class SlackAttachment { + String? fallback; + String? color; + String? author_name; + String? author_link; + String? author_icon; + String? title; + String? title_link; + String? pretext; + String? text; + String? image_url; + String? thumb_url; + String? footer; + String? footer_icon; + String? ts; + + late List? blocks = null; + late List? fields = null; + late List? actions = null; + + SlackAttachment(); + + factory SlackAttachment.fromJson(Map json) => + _$SlackAttachmentFromJson(json); + Map toJson() => removeKeys(_$SlackAttachmentToJson(this)); +} + +@JsonSerializable() +class SlackField { + String? title; + String? value; + bool? short = false; + + SlackField(); + SlackField.withParam(this.title, this.value, {this.short}); + + factory SlackField.fromJson(Map json) => + _$SlackFieldFromJson(json); + Map toJson() => removeKeys(_$SlackFieldToJson(this)); +} + +@JsonSerializable() +class SlackAction { + SlackActionType? type; + String? name; + String? text; + String? url; + String? value; + SlackActionStyle? style; + + SlackAction(); + SlackAction.withParam( + this.name, this.text, this.url, this.value, this.type, this.style); + + factory SlackAction.fromJson(Map json) => + _$SlackActionFromJson(json); + Map toJson() => removeKeys(_$SlackActionToJson(this)); +} + +@JsonSerializable() +class SlackConfirm { + String? title; + String? text; + String? ok_text; + String? dismiss_text; +} + +class SlackFile { + String? title; + String? initial_comment; + String? fileName; + String? mimeType; + late File file; + + Future setFileData(MultipartRequest form) async { + if (title != null) { + form.fields['title'] = title!; + } + if (initial_comment != null) { + form.fields['initial_comment'] = initial_comment!; + } + form.fields['filetype'] = "auto"; + if (fileName != null && mimeType != null) { + form.files.add(await MultipartFile.fromPath('file', file.path, + contentType: MediaType(HttpHeaders.contentTypeHeader, mimeType!))); + } + var c = Completer(); + c.complete(form); + return c.future; + } +} diff --git a/lib/framework/utils/slack/slack_data.g.dart b/lib/framework/utils/slack/slack_data.g.dart new file mode 100644 index 0000000..ce144da --- /dev/null +++ b/lib/framework/utils/slack/slack_data.g.dart @@ -0,0 +1,223 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'slack_data.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +DataSlack _$DataSlackFromJson(Map json) => DataSlack( + json['channel'] as String, + ) + ..text = json['text'] as String? + ..blocks = (json['blocks'] as List?) + ?.map((e) => SlackBlock.fromJson(e as Map)) + .toList() + ..attachments = (json['attachments'] as List?) + ?.map((e) => SlackAttachment.fromJson(e as Map)) + .toList() + ..link_names = json['link_names'] as bool?; + +Map _$DataSlackToJson(DataSlack instance) => { + 'channel': instance.channel, + 'text': instance.text, + 'blocks': instance.blocks, + 'attachments': instance.attachments, + 'link_names': instance.link_names, + }; + +SlackBlock _$SlackBlockFromJson(Map json) => SlackBlock() + ..type = $enumDecode(_$SlackBlockTypeEnumMap, json['type']) + ..block_id = json['block_id'] as String?; + +Map _$SlackBlockToJson(SlackBlock instance) => + { + 'type': _$SlackBlockTypeEnumMap[instance.type]!, + 'block_id': instance.block_id, + }; + +const _$SlackBlockTypeEnumMap = { + SlackBlockType.header: 'header', + SlackBlockType.section: 'section', + SlackBlockType.divider: 'divider', + SlackBlockType.actions: 'actions', +}; + +SlackBlockHeader _$SlackBlockHeaderFromJson(Map json) => + SlackBlockHeader() + ..type = $enumDecode(_$SlackBlockTypeEnumMap, json['type']) + ..block_id = json['block_id'] as String? + ..text = json['text'] == null + ? null + : SlackBlockText.fromJson(json['text'] as Map); + +Map _$SlackBlockHeaderToJson(SlackBlockHeader instance) => + { + 'type': _$SlackBlockTypeEnumMap[instance.type]!, + 'block_id': instance.block_id, + 'text': instance.text, + }; + +SlackBlockSection _$SlackBlockSectionFromJson(Map json) => + SlackBlockSection() + ..type = $enumDecode(_$SlackBlockTypeEnumMap, json['type']) + ..block_id = json['block_id'] as String? + ..text = json['text'] == null + ? null + : SlackBlockText.fromJson(json['text'] as Map) + ..fields = (json['fields'] as List?) + ?.map((e) => SlackBlockText.fromJson(e as Map)) + .toList() + ..accessory = json['accessory'] == null + ? null + : SlackAccessory.fromJson(json['accessory'] as Map); + +Map _$SlackBlockSectionToJson(SlackBlockSection instance) => + { + 'type': _$SlackBlockTypeEnumMap[instance.type]!, + 'block_id': instance.block_id, + 'text': instance.text, + 'fields': instance.fields, + 'accessory': instance.accessory, + }; + +SlackAccessory _$SlackAccessoryFromJson(Map json) => + SlackAccessory() + ..type = $enumDecode(_$SlackActionTypeEnumMap, json['type']) + ..text = json['text'] == null + ? null + : SlackBlockText.fromJson(json['text'] as Map) + ..image_url = json['image_url'] as String? + ..alt_text = json['alt_text'] as String? + ..value = json['value'] as String? + ..url = json['url'] as String?; + +Map _$SlackAccessoryToJson(SlackAccessory instance) => + { + 'type': _$SlackActionTypeEnumMap[instance.type]!, + 'text': instance.text, + 'image_url': instance.image_url, + 'alt_text': instance.alt_text, + 'value': instance.value, + 'url': instance.url, + }; + +const _$SlackActionTypeEnumMap = { + SlackActionType.button: 'button', + SlackActionType.select: 'select', + SlackActionType.image: 'image', +}; + +SlackBlockText _$SlackBlockTextFromJson(Map json) => + SlackBlockText() + ..type = $enumDecode(_$SlackTextTypeEnumMap, json['type']) + ..text = json['text'] as String? + ..emoji = json['emoji'] as bool?; + +Map _$SlackBlockTextToJson(SlackBlockText instance) => + { + 'type': _$SlackTextTypeEnumMap[instance.type]!, + 'text': instance.text, + 'emoji': instance.emoji, + }; + +const _$SlackTextTypeEnumMap = { + SlackTextType.mrkdwn: 'mrkdwn', + SlackTextType.plain_text: 'plain_text', +}; + +SlackAttachment _$SlackAttachmentFromJson(Map json) => + SlackAttachment() + ..fallback = json['fallback'] as String? + ..color = json['color'] as String? + ..author_name = json['author_name'] as String? + ..author_link = json['author_link'] as String? + ..author_icon = json['author_icon'] as String? + ..title = json['title'] as String? + ..title_link = json['title_link'] as String? + ..pretext = json['pretext'] as String? + ..text = json['text'] as String? + ..image_url = json['image_url'] as String? + ..thumb_url = json['thumb_url'] as String? + ..footer = json['footer'] as String? + ..footer_icon = json['footer_icon'] as String? + ..ts = json['ts'] as String? + ..blocks = (json['blocks'] as List?) + ?.map((e) => SlackBlock.fromJson(e as Map)) + .toList() + ..fields = (json['fields'] as List?) + ?.map((e) => SlackField.fromJson(e as Map)) + .toList() + ..actions = (json['actions'] as List?) + ?.map((e) => SlackAction.fromJson(e as Map)) + .toList(); + +Map _$SlackAttachmentToJson(SlackAttachment instance) => + { + 'fallback': instance.fallback, + 'color': instance.color, + 'author_name': instance.author_name, + 'author_link': instance.author_link, + 'author_icon': instance.author_icon, + 'title': instance.title, + 'title_link': instance.title_link, + 'pretext': instance.pretext, + 'text': instance.text, + 'image_url': instance.image_url, + 'thumb_url': instance.thumb_url, + 'footer': instance.footer, + 'footer_icon': instance.footer_icon, + 'ts': instance.ts, + 'blocks': instance.blocks, + 'fields': instance.fields, + 'actions': instance.actions, + }; + +SlackField _$SlackFieldFromJson(Map json) => SlackField() + ..title = json['title'] as String? + ..value = json['value'] as String? + ..short = json['short'] as bool?; + +Map _$SlackFieldToJson(SlackField instance) => + { + 'title': instance.title, + 'value': instance.value, + 'short': instance.short, + }; + +SlackAction _$SlackActionFromJson(Map json) => SlackAction() + ..type = $enumDecodeNullable(_$SlackActionTypeEnumMap, json['type']) + ..name = json['name'] as String? + ..text = json['text'] as String? + ..url = json['url'] as String? + ..value = json['value'] as String? + ..style = $enumDecodeNullable(_$SlackActionStyleEnumMap, json['style']); + +Map _$SlackActionToJson(SlackAction instance) => + { + 'type': _$SlackActionTypeEnumMap[instance.type], + 'name': instance.name, + 'text': instance.text, + 'url': instance.url, + 'value': instance.value, + 'style': _$SlackActionStyleEnumMap[instance.style], + }; + +const _$SlackActionStyleEnumMap = { + SlackActionStyle.danger: 'danger', + SlackActionStyle.primary: 'primary', +}; + +SlackConfirm _$SlackConfirmFromJson(Map json) => SlackConfirm() + ..title = json['title'] as String? + ..text = json['text'] as String? + ..ok_text = json['ok_text'] as String? + ..dismiss_text = json['dismiss_text'] as String?; + +Map _$SlackConfirmToJson(SlackConfirm instance) => + { + 'title': instance.title, + 'text': instance.text, + 'ok_text': instance.ok_text, + 'dismiss_text': instance.dismiss_text, + }; diff --git a/lib/framework/utils/slack/slack_sender.dart b/lib/framework/utils/slack/slack_sender.dart new file mode 100644 index 0000000..c0ca38b --- /dev/null +++ b/lib/framework/utils/slack/slack_sender.dart @@ -0,0 +1,137 @@ +// ignore_for_file: unused_local_variable + +import 'dart:async'; + +import 'package:color/color.dart'; +import 'package:oto_cli/framework/utils/system_util.dart'; +import 'package:http/http.dart' as http; + +import 'slack_data.dart'; +import 'package:oto_cli/framework/utils/string_util.dart'; + +enum SlackBuildType { android, ios, windows, mac, web } + +class SlackSender { + //Bot TOKEN + String token; + //API - https://api.slack.com/methods/chat.postMessage + final urlMessagePost = "https://slack.com/api/chat.postMessage"; + //API - https://api.slack.com/methods/files.upload + final urlFileUplaod = "https://slack.com/api/files.upload"; + + SlackSender(this.token); + + String getValidatedUser(String? targetUser) { + targetUser ??= "@here"; + if (targetUser.indexOf("@") != 0) targetUser = "@$targetUser"; + return targetUser; + } + + Future sendData(DataSlack message, + {Function(String)? completeListener, + Function(Object)? errorListener}) async { + return await send(message.json, + completeListener: completeListener, errorListener: errorListener); + } + + Future send(String jsonString, + {Function(String)? completeListener, + Function(Object)? errorListener}) async { + String url = urlMessagePost; + + var header = { + 'Content-Type': 'application/json', + 'Authorization': 'Bearer $token' + }; + print(jsonString); + var response = + await http.post(Uri.parse(url), headers: header, body: jsonString); + + print(response.statusCode); + + if (response.statusCode < 300 && response.statusCode >= 200) { + print(response.body); + if (completeListener != null) { + completeListener(response.body); + print(response.body); + } + } else { + if (errorListener != null) { + errorListener(response); + print(response.body); + } + } + + return simpleFuture; + } + + /// ****************** File Send ******************* + http.MultipartRequest getPostForm(String url, String channel) { + var form = http.MultipartRequest('POST', Uri.parse(url)); + form.fields['token'] = token; + form.fields['channels'] = channel; + return form; + } + + Future sendFile(String channel, SlackFile file, + {Function(String)? completeListener, + Function(Object)? errorListener}) async { + var form = getPostForm(urlFileUplaod, channel); + form = await file.setFileData(form); + var response = await form.send(); + var result = await response.stream.bytesToString(); + print(result); + if (response.statusCode < 300 && response.statusCode >= 200) { + if (completeListener != null) completeListener(result); + } else { + if (errorListener != null) errorListener(result); + } + + return simpleFuture; + } + + /// ****************** Build Send ******************* + Future sendBuild(String appName, SlackBuildType buildType, Color color, + String version, String downloadURL, + {String channel = 'build'}) async { + final buildURL = 'https://toki-labs.com/cdn/build/'; + String thumUrl = buildType == SlackBuildType.android + ? '${buildURL}android.png' + : '${buildURL}appstore.png'; + String projectIcon = "$buildURL$appName/icon.png"; + String emoji = + buildType == SlackBuildType.android ? ":android1: " : ":ios0: "; + String osColor = buildType == SlackBuildType.ios ? "#ED145B" : "#81CA3F"; + var message = DataSlack(channel); + message.attachments = []; + var attachments = message.attachments; + + var attachment = SlackAttachment(); + attachment.color = color.toHexColor().toCssString(); + attachment.fields = [SlackField.withParam(toPascal(appName), null)]; + attachments?.add(attachment); + + var buildTypeStr = buildTypeToString(buildType); + attachment = SlackAttachment(); + attachment.color = osColor; + attachment.author_name = buildTypeStr; + attachment.author_icon = thumUrl; + attachment.thumb_url = projectIcon; + attachment.fields = [ + SlackField.withParam(null, + "Successfully build $buildTypeStr binary file.\nBuild version: *$version*") + ]; + attachment.actions = [ + SlackAction.withParam( + 'build', 'Download', downloadURL, null, SlackActionType.button, null) + ]; + attachments?.add(attachment); + + return await sendData(message); + } + + String buildTypeToString(SlackBuildType type) { + var typeStr = type.name; + return typeStr == 'ios' ? 'iOS' : toPascal(typeStr); + } +} diff --git a/lib/framework/utils/slack/slack_template.dart b/lib/framework/utils/slack/slack_template.dart new file mode 100644 index 0000000..ac565c6 --- /dev/null +++ b/lib/framework/utils/slack/slack_template.dart @@ -0,0 +1,103 @@ +import 'package:oto_cli/framework/utils/slack/slack_data.dart'; + +//Format info +//https://api.slack.com/reference/surfaces/formatting + +class SlackTemplate { + static DataSlack getAttachments(String channel) { + DataSlack data = DataSlack(channel); + + data.attachments = []; + var attachment = SlackAttachment(); + attachment.fallback = 'Plain-text summary of the attachment.'; + attachment.color = '#2eb886'; + attachment.pretext = 'Optional text that appears above the attachment block'; + attachment.author_name = 'Bobby Tables'; + attachment.author_link = 'http://flickr.com/bobby/'; + attachment.author_icon = 'http://flickr.com/icons/bobby.jpg'; + attachment.title = 'Slack API Documentation'; + attachment.title_link = 'https://api.slack.com/'; + attachment.text = 'Optional text that appears within the attachment'; + attachment.fields = [ + SlackField.withParam('Priority', 'High', short: false), + ]; + attachment.image_url = + 'https://upload.wikimedia.org/wikipedia/commons/thumb/7/73/Flat_tick_icon.svg/1024px-Flat_tick_icon.svg.png'; + attachment.thumb_url = + 'https://cdn-icons-png.flaticon.com/512/3771/3771140.png'; + attachment.footer = 'Slack API'; + attachment.footer_icon = + 'https://platform.slack-edge.com/img/default_application_icon.png'; + attachment.ts = '123456789'; + data.attachments!.add(attachment); + return data; + } + + static DataSlack getBlocks(String channel) { + DataSlack data = DataSlack(channel); + + data.attachments = []; + var attachment = SlackAttachment(); + data.blocks = []; + var blockSection = SlackBlockSection(); + blockSection.text = SlackBlockText(); + blockSection.text!.text = + 'Danny Torrence left the following review for your property:'; + data.blocks!.add(blockSection); + + blockSection = SlackBlockSection(); + blockSection.text = SlackBlockText(); + blockSection.text!.text = + ' \n :star: \n Doors had too many axe holes, guest in room 237 was far too rowdy, whole place felt stuck in the 1920s.'; + blockSection.accessory = SlackAccessory(); + blockSection.accessory!.type = SlackActionType.image; + blockSection.accessory!.image_url = + 'https://is5-ssl.mzstatic.com/image/thumb/Purple3/v4/d3/72/5c/d3725c8f-c642-5d69-1904-aa36e4297885/source/256x256bb.jpg'; + blockSection.accessory!.alt_text = 'Haunted hotel image'; + data.blocks!.add(blockSection); + + blockSection = SlackBlockSection(); + blockSection.block_id = 'section789'; + blockSection.fields = []; + var field = SlackBlockText(); + field.text = '*Average Rating*\n1.0'; + blockSection.fields!.add(field); + data.blocks!.add(blockSection); + + attachment.blocks = []; + blockSection = SlackBlockSection(); + blockSection.text = SlackBlockText(); + blockSection.text!.text = '*Alternative hotel options*'; + attachment.blocks!.add(blockSection); + + blockSection = SlackBlockSection(); + blockSection.text = SlackBlockText(); + blockSection.text!.text = ' :star::star:'; + blockSection.accessory = SlackAccessory(); + blockSection.accessory!.type = SlackActionType.button; + blockSection.accessory!.url = 'https://www.google.com'; + blockSection.accessory!.text = SlackBlockText(); + blockSection.accessory!.text!.type = SlackTextType.plain_text; + blockSection.accessory!.text!.text = 'View'; + blockSection.accessory!.text!.emoji = true; + blockSection.accessory!.value = 'view_alternate_1'; + attachment.blocks!.add(blockSection); + + blockSection = SlackBlockSection(); + blockSection.text = SlackBlockText(); + blockSection.text!.text = + ' :star::star::star::star:'; + blockSection.accessory = SlackAccessory(); + blockSection.accessory!.type = SlackActionType.button; + blockSection.accessory!.url = 'https://www.naver.com'; + blockSection.accessory!.text = SlackBlockText(); + blockSection.accessory!.text!.type = SlackTextType.plain_text; + blockSection.accessory!.text!.text = 'View'; + blockSection.accessory!.text!.emoji = true; + blockSection.accessory!.value = 'view_alternate_2'; + attachment.blocks!.add(blockSection); + + data.attachments!.add(attachment); + return data; + } +} diff --git a/lib/framework/utils/string_util.dart b/lib/framework/utils/string_util.dart new file mode 100644 index 0000000..1a5df02 --- /dev/null +++ b/lib/framework/utils/string_util.dart @@ -0,0 +1,44 @@ +import 'dart:convert'; + +String toPascal(String raw) { + return '${raw[0].toUpperCase()}${raw.substring(1).toLowerCase()}'; +} + +String getDates() { + return '${getDate()} ${getTime()}'; +} + +String getDate() { + var now = DateTime.now(); + return '${now.year.toString().substring(2, 4)}-${now.month.toString().padLeft(2, '0')}-${now.day.toString().padLeft(2, '0')}'; +} + +String getTime() { + var now = DateTime.now(); + return '${now.hour.toString().padLeft(2, '0')}:${now.minute.toString().padLeft(2, '0')}:${now.second.toString().padLeft(2, '0')}'; +} + +String jsonPrettyEncode(Object? object) { + return JsonEncoder.withIndent(' ').convert(object); +} + +String incrementVersion(String version, {int fixedLength = 3, bool reverse = false}) { + var parts = version.split('.').map(int.parse).toList(); + if (parts.length < fixedLength) { + var needLength = fixedLength - parts.length; + for (int i = 0; i < needLength; ++i) { + if (reverse) { parts.add(0); } else { parts.insert(0, 0); } + } + } + + for (int i = parts.length - 1; i >= 0; i--) { + if (parts[i] < 999) { + parts[i] += 1; + break; + } else { + parts[i] = 0; + } + } + + return parts.join('.'); +} diff --git a/lib/framework/utils/system_util.dart b/lib/framework/utils/system_util.dart new file mode 100644 index 0000000..9354996 --- /dev/null +++ b/lib/framework/utils/system_util.dart @@ -0,0 +1,112 @@ +import 'dart:async'; +import 'dart:convert'; +import 'dart:typed_data'; + +import 'package:oto_cli/framework/platform/platform_base.dart'; +import 'package:yaml/yaml.dart'; + +enum Environment { + local, + dev, + qa, + product +} + +int intMax = 0; +int intMin = 0; +bool isDebug = true; +String userPath = ''; +String dataPath = ''; +String scriptPath = ''; +String executablePath = ''; +String appIdendifier = ''; +String appName = ''; +String and = '&&'; +Environment environment = Environment.local; + +void initialize(String name, String appID) { + initializeApp(name, appID); + + const env = String.fromEnvironment('ENV', defaultValue: 'local'); + environment = Environment.values.firstWhere( + (e) => e.name == env, + orElse: () => Environment.local, + ); +} + +Map?> envArguments(List arguments) { + var dic = ?>{}; + var list = []; + var length = arguments.length; + for (var i = 0; i < length; ++i) { + var value = arguments[i]; + var key = _getKey(value); + if (key != null) { + var index = i + 1; + list.clear(); + while (index < length) { + var arg = arguments[index]; + if (_getKey(arg) == null) { + list.add(arg); + index++; + } else { + i = index - 1; + break; + } + } + List? arr = List.from(list); + if (arr.isEmpty) arr = null; + dic[key] = arr; + } + } + return dic; +} + +String? _getKey(String value) { + String? key; + if (value.indexOf('-') == 0) { + key = value.substring(1, value.length); + } + return key; +} + +Map? getMapFromJson(String jsonStr) { + Map? map; + if (jsonStr.length > 5) { + JsonCodec codec = JsonCodec(); + try { + map = codec.decode(jsonStr); + } on Exception catch (e, stacktace) { + print('Error: $e\n\n$stacktace'); + } + } + return map; +} + +Map? getMapFromYaml(String yamlStr) { + Map? map; + if (yamlStr.length > 5) { + try { + map = jsonDecode(jsonEncode(loadYaml(yamlStr))); + } on Exception catch (e, stacktace) { + throw Exception('Yaml Pasing error.\n\n$stacktace'); + } + } + return map; +} + +Future getIPAddress(String domain) => getIPAddressPlatform(domain); + +Future get simpleFuture { + var c = Completer(); + c.complete(); + return c.future; +} + +Future dataFutrue(T data) { + var c = Completer(); + c.complete(data); + return c.future; +} + +Future readFileByte(String filePath) => readFileBytePlatform(filePath); diff --git a/lib/oto/application.dart b/lib/oto/application.dart index 5f89bfd..a148256 100644 --- a/lib/oto/application.dart +++ b/lib/oto/application.dart @@ -3,10 +3,10 @@ import 'dart:async'; import 'dart:convert'; import 'dart:io'; -import 'package:dart_framework/log/log.dart'; -import 'package:dart_framework/platform/process.dart'; -import 'package:dart_framework/utils/string_util.dart'; -import 'package:dart_framework/utils/system_util.dart'; +import 'package:oto_cli/framework/log/log.dart'; +import 'package:oto_cli/framework/platform/process.dart'; +import 'package:oto_cli/framework/utils/string_util.dart'; +import 'package:oto_cli/framework/utils/system_util.dart'; import 'package:oto_cli/cli/cli.dart'; import 'package:oto_cli/oto/commands/command.dart'; import 'package:oto_cli/oto/commands/command_registry.dart'; diff --git a/lib/oto/commands/aws/awscli.dart b/lib/oto/commands/aws/awscli.dart index ecd5ab2..787a8d6 100644 --- a/lib/oto/commands/aws/awscli.dart +++ b/lib/oto/commands/aws/awscli.dart @@ -1,5 +1,5 @@ -import 'package:dart_framework/platform/process.dart'; -import 'package:dart_framework/utils/system_util.dart'; +import 'package:oto_cli/framework/platform/process.dart'; +import 'package:oto_cli/framework/utils/system_util.dart'; import 'package:oto_cli/oto/application.dart'; import 'package:oto_cli/oto/commands/command.dart'; import 'package:oto_cli/oto/data/command_data.dart'; diff --git a/lib/oto/commands/build/app_data_creator.dart b/lib/oto/commands/build/app_data_creator.dart index 4c2782b..721f51e 100644 --- a/lib/oto/commands/build/app_data_creator.dart +++ b/lib/oto/commands/build/app_data_creator.dart @@ -1,6 +1,6 @@ import 'dart:async'; -import 'package:dart_framework/core/app_data_manager.dart'; +import 'package:oto_cli/framework/core/app_data_manager.dart'; import 'package:oto_cli/oto/commands/command.dart'; import 'package:oto_cli/oto/data/command_data.dart'; diff --git a/lib/oto/commands/build/build_dart.dart b/lib/oto/commands/build/build_dart.dart index 570c451..18abaac 100644 --- a/lib/oto/commands/build/build_dart.dart +++ b/lib/oto/commands/build/build_dart.dart @@ -1,6 +1,6 @@ import 'dart:async'; -import 'package:dart_framework/platform/process.dart'; -import 'package:dart_framework/utils/system_util.dart'; +import 'package:oto_cli/framework/platform/process.dart'; +import 'package:oto_cli/framework/utils/system_util.dart'; import 'package:oto_cli/oto/application.dart'; import 'package:oto_cli/oto/commands/command.dart'; import 'package:oto_cli/oto/data/command_data.dart'; diff --git a/lib/oto/commands/build/build_dart_compile.dart b/lib/oto/commands/build/build_dart_compile.dart index bf59a5f..cfdf44d 100644 --- a/lib/oto/commands/build/build_dart_compile.dart +++ b/lib/oto/commands/build/build_dart_compile.dart @@ -1,6 +1,6 @@ import 'dart:async'; import 'dart:io'; -import 'package:dart_framework/utils/system_util.dart'; +import 'package:oto_cli/framework/utils/system_util.dart'; import 'package:oto_cli/oto/commands/build/build_dart.dart'; import 'package:oto_cli/oto/commands/command.dart'; import 'package:oto_cli/oto/data/command_data.dart'; diff --git a/lib/oto/commands/build/build_dot_net.dart b/lib/oto/commands/build/build_dot_net.dart index eea7ed2..19dd7ca 100644 --- a/lib/oto/commands/build/build_dot_net.dart +++ b/lib/oto/commands/build/build_dot_net.dart @@ -1,6 +1,6 @@ import 'dart:async'; -import 'package:dart_framework/platform/process.dart'; -import 'package:dart_framework/utils/system_util.dart'; +import 'package:oto_cli/framework/platform/process.dart'; +import 'package:oto_cli/framework/utils/system_util.dart'; import 'package:oto_cli/oto/application.dart'; import 'package:oto_cli/oto/commands/command.dart'; import 'package:oto_cli/oto/data/command_data.dart'; diff --git a/lib/oto/commands/build/build_flutter.dart b/lib/oto/commands/build/build_flutter.dart index 3d9f76c..6cdf6fe 100644 --- a/lib/oto/commands/build/build_flutter.dart +++ b/lib/oto/commands/build/build_flutter.dart @@ -1,6 +1,6 @@ import 'dart:async'; -import 'package:dart_framework/utils/system_util.dart'; +import 'package:oto_cli/framework/utils/system_util.dart'; import 'package:oto_cli/oto/commands/build/build_dart.dart'; import 'package:oto_cli/oto/commands/command.dart'; import 'package:oto_cli/oto/data/command_data.dart'; diff --git a/lib/oto/commands/build/build_ios.dart b/lib/oto/commands/build/build_ios.dart index 008ac5c..521a2ed 100644 --- a/lib/oto/commands/build/build_ios.dart +++ b/lib/oto/commands/build/build_ios.dart @@ -2,15 +2,15 @@ import 'dart:async'; import 'dart:convert'; import 'dart:io'; -import 'package:dart_framework/utils/string_util.dart'; -import 'package:dart_framework/utils/system_util.dart'; +import 'package:oto_cli/framework/utils/string_util.dart'; +import 'package:oto_cli/framework/utils/system_util.dart'; import 'package:oto_cli/oto/commands/build/fastlane_template.dart'; import 'package:xml/xml.dart'; import 'package:oto_cli/oto/application.dart'; import 'package:oto_cli/oto/commands/build/build_flutter.dart'; import 'package:oto_cli/oto/commands/command.dart'; import 'package:oto_cli/oto/data/command_data.dart'; -import 'package:dart_framework/platform/process.dart'; +import 'package:oto_cli/framework/platform/process.dart'; import 'package:path/path.dart' as path; class BuildiOS extends Command { diff --git a/lib/oto/commands/build/build_msbuild.dart b/lib/oto/commands/build/build_msbuild.dart index b3f6600..b699f36 100644 --- a/lib/oto/commands/build/build_msbuild.dart +++ b/lib/oto/commands/build/build_msbuild.dart @@ -2,8 +2,8 @@ import 'dart:async'; import 'dart:io'; -import 'package:dart_framework/platform/process.dart'; -import 'package:dart_framework/utils/system_util.dart'; +import 'package:oto_cli/framework/platform/process.dart'; +import 'package:oto_cli/framework/utils/system_util.dart'; import 'package:oto_cli/oto/application.dart'; import 'package:oto_cli/oto/commands/command.dart'; import 'package:oto_cli/oto/data/command_data.dart'; diff --git a/lib/oto/commands/build/testflight_ios.dart b/lib/oto/commands/build/testflight_ios.dart index 4b21bf3..8a0a925 100644 --- a/lib/oto/commands/build/testflight_ios.dart +++ b/lib/oto/commands/build/testflight_ios.dart @@ -1,6 +1,6 @@ import 'dart:convert'; -import 'package:dart_framework/platform/process.dart'; +import 'package:oto_cli/framework/platform/process.dart'; import 'package:oto_cli/oto/application.dart'; import 'package:oto_cli/oto/commands/build/build_ios.dart'; import 'package:oto_cli/oto/commands/command.dart'; diff --git a/lib/oto/commands/build/xcodeproj.dart b/lib/oto/commands/build/xcodeproj.dart index 6e24346..a5a2435 100644 --- a/lib/oto/commands/build/xcodeproj.dart +++ b/lib/oto/commands/build/xcodeproj.dart @@ -1,6 +1,6 @@ import 'dart:io'; -import 'package:dart_framework/platform/process.dart'; +import 'package:oto_cli/framework/platform/process.dart'; import 'package:oto_cli/oto/application.dart'; import 'package:oto_cli/oto/commands/command.dart'; import 'package:oto_cli/oto/data/command_data.dart'; diff --git a/lib/oto/commands/command.dart b/lib/oto/commands/command.dart index a8d87f7..7e877d1 100644 --- a/lib/oto/commands/command.dart +++ b/lib/oto/commands/command.dart @@ -2,8 +2,8 @@ import 'dart:async'; import 'dart:io'; -import 'package:dart_framework/platform/process.dart'; -import 'package:dart_framework/utils/system_util.dart'; +import 'package:oto_cli/framework/platform/process.dart'; +import 'package:oto_cli/framework/utils/system_util.dart'; import 'package:oto_cli/oto/application.dart'; import 'package:oto_cli/oto/core/tag_system.dart'; import 'package:oto_cli/oto/data/command_data.dart'; diff --git a/lib/oto/commands/docker/docker.dart b/lib/oto/commands/docker/docker.dart index b562b66..4ec7a43 100644 --- a/lib/oto/commands/docker/docker.dart +++ b/lib/oto/commands/docker/docker.dart @@ -1,5 +1,5 @@ -import 'package:dart_framework/platform/process.dart'; -import 'package:dart_framework/utils/system_util.dart'; +import 'package:oto_cli/framework/platform/process.dart'; +import 'package:oto_cli/framework/utils/system_util.dart'; import 'package:oto_cli/oto/application.dart'; import 'package:oto_cli/oto/commands/command.dart'; import 'package:oto_cli/oto/data/command_data.dart'; diff --git a/lib/oto/commands/file/copy.dart b/lib/oto/commands/file/copy.dart index 4e8fc62..09888a9 100644 --- a/lib/oto/commands/file/copy.dart +++ b/lib/oto/commands/file/copy.dart @@ -1,7 +1,7 @@ import 'dart:async'; import 'dart:io'; -import 'package:dart_framework/utils/path.dart'; +import 'package:oto_cli/framework/utils/path.dart'; import 'package:oto_cli/oto/application.dart'; import 'package:oto_cli/oto/commands/command.dart'; import 'package:oto_cli/oto/data/command_data.dart'; diff --git a/lib/oto/commands/file/delete.dart b/lib/oto/commands/file/delete.dart index 4886880..07f90b5 100644 --- a/lib/oto/commands/file/delete.dart +++ b/lib/oto/commands/file/delete.dart @@ -1,7 +1,7 @@ import 'dart:async'; import 'dart:io'; -import 'package:dart_framework/utils/path.dart'; +import 'package:oto_cli/framework/utils/path.dart'; import 'package:oto_cli/oto/application.dart'; import 'package:oto_cli/oto/commands/command.dart'; import 'package:oto_cli/oto/data/command_data.dart'; diff --git a/lib/oto/commands/file/file_diff_check.dart b/lib/oto/commands/file/file_diff_check.dart index 7b3f208..674f109 100644 --- a/lib/oto/commands/file/file_diff_check.dart +++ b/lib/oto/commands/file/file_diff_check.dart @@ -4,7 +4,7 @@ import 'dart:async'; import 'dart:convert'; import 'dart:io'; -import 'package:dart_framework/utils/system_util.dart'; +import 'package:oto_cli/framework/utils/system_util.dart'; import 'package:file_hasher/file_hasher.dart'; import 'package:oto_cli/oto/application.dart'; import 'package:oto_cli/oto/commands/command.dart'; diff --git a/lib/oto/commands/file/rename.dart b/lib/oto/commands/file/rename.dart index 3e88172..c1f6b94 100644 --- a/lib/oto/commands/file/rename.dart +++ b/lib/oto/commands/file/rename.dart @@ -5,7 +5,7 @@ import 'dart:io'; import 'package:oto_cli/oto/application.dart'; import 'package:path/path.dart' as path; -import 'package:dart_framework/utils/path.dart'; +import 'package:oto_cli/framework/utils/path.dart'; import 'package:oto_cli/oto/commands/command.dart'; import 'package:oto_cli/oto/data/command_data.dart'; diff --git a/lib/oto/commands/file/zip.dart b/lib/oto/commands/file/zip.dart index fd690de..44b4791 100644 --- a/lib/oto/commands/file/zip.dart +++ b/lib/oto/commands/file/zip.dart @@ -4,7 +4,7 @@ import 'dart:async'; import 'dart:io'; import 'package:archive/archive_io.dart'; -import 'package:dart_framework/utils/path.dart'; +import 'package:oto_cli/framework/utils/path.dart'; import 'package:oto_cli/oto/application.dart'; import 'package:oto_cli/oto/commands/command.dart'; import 'package:oto_cli/oto/data/command_data.dart'; diff --git a/lib/oto/commands/ftp/ftp.dart b/lib/oto/commands/ftp/ftp.dart index 41ba899..e2bac25 100644 --- a/lib/oto/commands/ftp/ftp.dart +++ b/lib/oto/commands/ftp/ftp.dart @@ -3,7 +3,7 @@ import 'dart:io'; // ignore: depend_on_referenced_packages import 'package:ftpconnect/ftpconnect.dart'; // ignore: implementation_imports -import 'package:dart_framework/utils/path.dart'; +import 'package:oto_cli/framework/utils/path.dart'; import 'package:oto_cli/oto/application.dart'; import 'package:oto_cli/oto/commands/command.dart'; diff --git a/lib/oto/commands/ftp/upload.dart b/lib/oto/commands/ftp/upload.dart index f85cc59..ead3b60 100644 --- a/lib/oto/commands/ftp/upload.dart +++ b/lib/oto/commands/ftp/upload.dart @@ -7,7 +7,7 @@ import 'package:oto_cli/oto/application.dart'; import 'package:oto_cli/oto/commands/command.dart'; import 'package:oto_cli/oto/data/command_data.dart'; import 'package:oto_cli/oto/commands/ftp/ftp.dart'; -import 'package:dart_framework/utils/path.dart'; +import 'package:oto_cli/framework/utils/path.dart'; class Upload extends Command { @override diff --git a/lib/oto/commands/git/git.dart b/lib/oto/commands/git/git.dart index 2703d22..c78b612 100644 --- a/lib/oto/commands/git/git.dart +++ b/lib/oto/commands/git/git.dart @@ -1,11 +1,11 @@ import 'dart:convert'; import 'dart:io'; -import 'package:dart_framework/utils/system_util.dart'; +import 'package:oto_cli/framework/utils/system_util.dart'; import 'package:oto_cli/oto/application.dart'; import 'package:oto_cli/oto/commands/command.dart'; import 'package:oto_cli/oto/data/command_data.dart'; -import 'package:dart_framework/platform/process.dart'; +import 'package:oto_cli/framework/platform/process.dart'; class Git extends Command { @override diff --git a/lib/oto/commands/git/git_hub.dart b/lib/oto/commands/git/git_hub.dart index 4c9ea77..c130931 100644 --- a/lib/oto/commands/git/git_hub.dart +++ b/lib/oto/commands/git/git_hub.dart @@ -3,11 +3,11 @@ import 'dart:convert'; import 'dart:io'; -import 'package:dart_framework/utils/system_util.dart'; +import 'package:oto_cli/framework/utils/system_util.dart'; import 'package:oto_cli/oto/application.dart'; import 'package:oto_cli/oto/commands/command.dart'; import 'package:oto_cli/oto/data/command_data.dart'; -import 'package:dart_framework/platform/process.dart'; +import 'package:oto_cli/framework/platform/process.dart'; class GitHub extends Command { @override diff --git a/lib/oto/commands/gradle/gradle.dart b/lib/oto/commands/gradle/gradle.dart index 51df916..9fbd105 100644 --- a/lib/oto/commands/gradle/gradle.dart +++ b/lib/oto/commands/gradle/gradle.dart @@ -1,5 +1,5 @@ -import 'package:dart_framework/platform/process.dart'; -import 'package:dart_framework/utils/system_util.dart'; +import 'package:oto_cli/framework/platform/process.dart'; +import 'package:oto_cli/framework/utils/system_util.dart'; import 'package:oto_cli/oto/application.dart'; import 'package:oto_cli/oto/commands/command.dart'; import 'package:oto_cli/oto/data/command_data.dart'; diff --git a/lib/oto/commands/jira/jira.dart b/lib/oto/commands/jira/jira.dart index 1f97c92..deb8de6 100644 --- a/lib/oto/commands/jira/jira.dart +++ b/lib/oto/commands/jira/jira.dart @@ -3,8 +3,8 @@ import 'dart:convert'; -import 'package:dart_framework/utils/slack/slack_data.dart'; -import 'package:dart_framework/utils/system_util.dart'; +import 'package:oto_cli/framework/utils/slack/slack_data.dart'; +import 'package:oto_cli/framework/utils/system_util.dart'; import 'package:oto_cli/oto/application.dart'; import 'package:oto_cli/oto/commands/command.dart'; import 'package:oto_cli/oto/data/command_data.dart'; diff --git a/lib/oto/commands/notification/mattermost.dart b/lib/oto/commands/notification/mattermost.dart index c2202f3..2260ef4 100644 --- a/lib/oto/commands/notification/mattermost.dart +++ b/lib/oto/commands/notification/mattermost.dart @@ -3,7 +3,7 @@ import 'dart:async'; import 'package:color/color.dart'; -import 'package:dart_framework/utils/system_util.dart'; +import 'package:oto_cli/framework/utils/system_util.dart'; import 'package:oto_cli/oto/commands/command.dart'; import 'package:oto_cli/oto/data/command_data.dart'; import 'package:oto_cli/oto/utils/mattermost/mattermost_data.dart'; diff --git a/lib/oto/commands/notification/slack.dart b/lib/oto/commands/notification/slack.dart index 74922ae..4133bbb 100644 --- a/lib/oto/commands/notification/slack.dart +++ b/lib/oto/commands/notification/slack.dart @@ -4,13 +4,13 @@ import 'dart:async'; import 'dart:convert'; import 'dart:io'; -import 'package:dart_framework/utils/slack/slack_data.dart'; -import 'package:dart_framework/utils/system_util.dart'; +import 'package:oto_cli/framework/utils/slack/slack_data.dart'; +import 'package:oto_cli/framework/utils/system_util.dart'; import 'package:oto_cli/oto/commands/command.dart'; import 'package:oto_cli/oto/data/command_data.dart'; import 'package:color/color.dart'; -import 'package:dart_framework/utils/slack/slack_sender.dart'; -import 'package:dart_framework/utils/slack/slack_data.dart' as slack_data; +import 'package:oto_cli/framework/utils/slack/slack_sender.dart'; +import 'package:oto_cli/framework/utils/slack/slack_data.dart' as slack_data; class Slack extends Command { @override diff --git a/lib/oto/commands/process/process.dart b/lib/oto/commands/process/process.dart index 46b1534..d31bb3f 100644 --- a/lib/oto/commands/process/process.dart +++ b/lib/oto/commands/process/process.dart @@ -1,8 +1,8 @@ import 'dart:async'; import 'dart:io'; -import 'package:dart_framework/platform/process.dart'; -import 'package:dart_framework/utils/system_util.dart'; +import 'package:oto_cli/framework/platform/process.dart'; +import 'package:oto_cli/framework/utils/system_util.dart'; import 'package:oto_cli/oto/application.dart'; import 'package:oto_cli/oto/commands/command.dart'; import 'package:oto_cli/oto/data/command_data.dart'; diff --git a/lib/oto/commands/proto/protobuf.dart b/lib/oto/commands/proto/protobuf.dart index 16ba4f4..a441e72 100644 --- a/lib/oto/commands/proto/protobuf.dart +++ b/lib/oto/commands/proto/protobuf.dart @@ -1,8 +1,8 @@ -import 'package:dart_framework/utils/system_util.dart'; +import 'package:oto_cli/framework/utils/system_util.dart'; import 'package:oto_cli/oto/application.dart'; import 'package:oto_cli/oto/commands/command.dart'; import 'package:oto_cli/oto/data/command_data.dart'; -import 'package:dart_framework/platform/process.dart'; +import 'package:oto_cli/framework/platform/process.dart'; class Protobuf extends Command { @override diff --git a/lib/oto/commands/shell/shell.dart b/lib/oto/commands/shell/shell.dart index 67036e2..1328b3a 100644 --- a/lib/oto/commands/shell/shell.dart +++ b/lib/oto/commands/shell/shell.dart @@ -1,7 +1,7 @@ import 'dart:async'; import 'dart:io'; -import 'package:dart_framework/platform/process.dart'; -import 'package:dart_framework/utils/system_util.dart'; +import 'package:oto_cli/framework/platform/process.dart'; +import 'package:oto_cli/framework/utils/system_util.dart'; import 'package:oto_cli/oto/application.dart'; import 'package:oto_cli/oto/commands/command.dart'; import 'package:oto_cli/oto/data/command_data.dart'; diff --git a/lib/oto/commands/util/execute_app.dart b/lib/oto/commands/util/execute_app.dart index fd180a3..3ce5c50 100644 --- a/lib/oto/commands/util/execute_app.dart +++ b/lib/oto/commands/util/execute_app.dart @@ -3,7 +3,7 @@ import 'dart:async'; import 'package:oto_cli/oto/application.dart'; import 'package:oto_cli/oto/commands/command.dart'; import 'package:oto_cli/oto/data/command_data.dart'; -import 'package:dart_framework/platform/process.dart'; +import 'package:oto_cli/framework/platform/process.dart'; class ExecuteApp extends Command { @override diff --git a/lib/oto/commands/util/json.dart b/lib/oto/commands/util/json.dart index 7be209b..e382a3d 100644 --- a/lib/oto/commands/util/json.dart +++ b/lib/oto/commands/util/json.dart @@ -1,7 +1,7 @@ import 'dart:convert'; import 'dart:io'; -import 'package:dart_framework/utils/string_util.dart'; +import 'package:oto_cli/framework/utils/string_util.dart'; import 'package:oto_cli/cli/cli.dart'; import 'package:oto_cli/oto/commands/command.dart'; import 'package:oto_cli/oto/data/command_data.dart'; diff --git a/lib/oto/core/data_composer.dart b/lib/oto/core/data_composer.dart index 9776517..c485641 100644 --- a/lib/oto/core/data_composer.dart +++ b/lib/oto/core/data_composer.dart @@ -2,8 +2,8 @@ import 'dart:async'; import 'dart:convert'; import 'dart:io'; -import 'package:dart_framework/platform/process.dart'; -import 'package:dart_framework/utils/system_util.dart'; +import 'package:oto_cli/framework/platform/process.dart'; +import 'package:oto_cli/framework/utils/system_util.dart'; import 'package:oto_cli/cli/cli.dart'; import 'package:oto_cli/oto/application.dart'; import 'package:oto_cli/oto/data/base_data.dart'; diff --git a/lib/oto/core/tag_system.dart b/lib/oto/core/tag_system.dart index 8fd960d..b0fecbc 100644 --- a/lib/oto/core/tag_system.dart +++ b/lib/oto/core/tag_system.dart @@ -1,7 +1,7 @@ // ignore_for_file: avoid_init_to_null import 'dart:io'; -import 'package:dart_framework/utils/path.dart'; +import 'package:oto_cli/framework/utils/path.dart'; import 'package:oto_cli/oto/application.dart'; /// OTO Tag System diff --git a/lib/oto/data/build_data.dart b/lib/oto/data/build_data.dart index 6424b8b..13f72cc 100644 --- a/lib/oto/data/build_data.dart +++ b/lib/oto/data/build_data.dart @@ -1,6 +1,6 @@ // ignore_for_file: non_constant_identifier_names, avoid_init_to_null -import 'package:dart_framework/core/app_data_manager.dart'; +import 'package:oto_cli/framework/core/app_data_manager.dart'; import 'package:json_annotation/json_annotation.dart'; import 'package:oto_cli/oto/commands/build/build_flutter.dart'; import 'package:oto_cli/oto/commands/build/build_msbuild.dart'; diff --git a/lib/oto/data/notification_data.dart b/lib/oto/data/notification_data.dart index 9329e4b..cdab01e 100644 --- a/lib/oto/data/notification_data.dart +++ b/lib/oto/data/notification_data.dart @@ -1,6 +1,6 @@ // ignore_for_file: non_constant_identifier_names, avoid_init_to_null -import 'package:dart_framework/utils/slack/slack_sender.dart'; +import 'package:oto_cli/framework/utils/slack/slack_sender.dart'; import 'package:json_annotation/json_annotation.dart'; import 'package:oto_cli/oto/data/base_data.dart'; import 'package:oto_cli/oto/utils/mattermost/mattermost_sender.dart'; diff --git a/lib/oto/pipeline/pipeline.dart b/lib/oto/pipeline/pipeline.dart index 251c234..97b3f1e 100644 --- a/lib/oto/pipeline/pipeline.dart +++ b/lib/oto/pipeline/pipeline.dart @@ -1,4 +1,4 @@ -import 'package:dart_framework/utils/system_util.dart'; +import 'package:oto_cli/framework/utils/system_util.dart'; import 'package:oto_cli/oto/pipeline/pipeline_contain.dart'; import 'package:oto_cli/oto/pipeline/pipeline_exe.dart'; import 'package:oto_cli/oto/pipeline/pipeline_exe_handle.dart'; diff --git a/lib/oto/pipeline/pipeline_condition.dart b/lib/oto/pipeline/pipeline_condition.dart index 77eccb0..b00748d 100644 --- a/lib/oto/pipeline/pipeline_condition.dart +++ b/lib/oto/pipeline/pipeline_condition.dart @@ -1,6 +1,6 @@ // ignore_for_file: unnecessary_cast, unnecessary_null_comparison -import 'package:dart_framework/core/app_data_manager.dart'; +import 'package:oto_cli/framework/core/app_data_manager.dart'; import 'package:oto_cli/oto/commands/command.dart'; import 'package:oto_cli/oto/data/pipeline_data.dart'; import 'package:oto_cli/oto/pipeline/pipeline.dart'; diff --git a/lib/oto/pipeline/pipeline_contain.dart b/lib/oto/pipeline/pipeline_contain.dart index 127ee24..05fa72e 100644 --- a/lib/oto/pipeline/pipeline_contain.dart +++ b/lib/oto/pipeline/pipeline_contain.dart @@ -1,4 +1,4 @@ -import 'package:dart_framework/utils/system_util.dart'; +import 'package:oto_cli/framework/utils/system_util.dart'; import 'package:oto_cli/oto/commands/command.dart'; import 'package:oto_cli/oto/data/pipeline_data.dart'; import 'package:oto_cli/oto/pipeline/pipeline.dart'; diff --git a/lib/oto/pipeline/pipeline_exe.dart b/lib/oto/pipeline/pipeline_exe.dart index eef637f..4e46333 100644 --- a/lib/oto/pipeline/pipeline_exe.dart +++ b/lib/oto/pipeline/pipeline_exe.dart @@ -1,4 +1,4 @@ -import 'package:dart_framework/utils/system_util.dart'; +import 'package:oto_cli/framework/utils/system_util.dart'; import 'package:oto_cli/cli/cli.dart'; import 'package:oto_cli/oto/application.dart'; import 'package:oto_cli/oto/commands/command.dart'; diff --git a/lib/oto/pipeline/pipeline_exe_handle.dart b/lib/oto/pipeline/pipeline_exe_handle.dart index afd0165..f5b7931 100644 --- a/lib/oto/pipeline/pipeline_exe_handle.dart +++ b/lib/oto/pipeline/pipeline_exe_handle.dart @@ -1,4 +1,4 @@ -import 'package:dart_framework/utils/system_util.dart'; +import 'package:oto_cli/framework/utils/system_util.dart'; import 'package:oto_cli/cli/cli.dart'; import 'package:oto_cli/oto/application.dart'; import 'package:oto_cli/oto/commands/command.dart'; diff --git a/lib/oto/pipeline/pipeline_foreach.dart b/lib/oto/pipeline/pipeline_foreach.dart index a35c674..50aff5f 100644 --- a/lib/oto/pipeline/pipeline_foreach.dart +++ b/lib/oto/pipeline/pipeline_foreach.dart @@ -1,4 +1,4 @@ -import 'package:dart_framework/utils/system_util.dart'; +import 'package:oto_cli/framework/utils/system_util.dart'; import 'package:oto_cli/cli/cli.dart'; import 'package:oto_cli/oto/application.dart'; import 'package:oto_cli/oto/commands/command.dart'; diff --git a/lib/oto/pipeline/pipeline_if.dart b/lib/oto/pipeline/pipeline_if.dart index f1f824e..df29985 100644 --- a/lib/oto/pipeline/pipeline_if.dart +++ b/lib/oto/pipeline/pipeline_if.dart @@ -1,4 +1,4 @@ -import 'package:dart_framework/utils/system_util.dart'; +import 'package:oto_cli/framework/utils/system_util.dart'; import 'package:oto_cli/oto/data/pipeline_data.dart'; import 'package:oto_cli/oto/pipeline/pipeline.dart'; import 'package:oto_cli/oto/pipeline/pipeline_condition.dart'; diff --git a/lib/oto/pipeline/pipeline_switch.dart b/lib/oto/pipeline/pipeline_switch.dart index f78f682..8e3ac17 100644 --- a/lib/oto/pipeline/pipeline_switch.dart +++ b/lib/oto/pipeline/pipeline_switch.dart @@ -1,4 +1,4 @@ -import 'package:dart_framework/utils/system_util.dart'; +import 'package:oto_cli/framework/utils/system_util.dart'; import 'package:oto_cli/oto/data/pipeline_data.dart'; import 'package:oto_cli/oto/pipeline/pipeline.dart'; import 'package:oto_cli/oto/pipeline/pipeline_condition.dart'; diff --git a/lib/oto/pipeline/pipeline_wait_until.dart b/lib/oto/pipeline/pipeline_wait_until.dart index 98d515d..2fcf46e 100644 --- a/lib/oto/pipeline/pipeline_wait_until.dart +++ b/lib/oto/pipeline/pipeline_wait_until.dart @@ -1,4 +1,4 @@ -import 'package:dart_framework/utils/system_util.dart'; +import 'package:oto_cli/framework/utils/system_util.dart'; import 'package:oto_cli/oto/data/pipeline_data.dart'; import 'package:oto_cli/oto/pipeline/pipeline.dart'; import 'package:oto_cli/oto/pipeline/pipeline_condition.dart'; diff --git a/lib/oto/pipeline/pipeline_while.dart b/lib/oto/pipeline/pipeline_while.dart index 9d47f93..0ab41ec 100644 --- a/lib/oto/pipeline/pipeline_while.dart +++ b/lib/oto/pipeline/pipeline_while.dart @@ -1,4 +1,4 @@ -import 'package:dart_framework/utils/system_util.dart'; +import 'package:oto_cli/framework/utils/system_util.dart'; import 'package:oto_cli/oto/data/pipeline_data.dart'; import 'package:oto_cli/oto/pipeline/pipeline.dart'; import 'package:oto_cli/oto/pipeline/pipeline_condition.dart'; diff --git a/lib/oto/utils/mattermost/mattermost_sender.dart b/lib/oto/utils/mattermost/mattermost_sender.dart index fa8c334..f9cf430 100644 --- a/lib/oto/utils/mattermost/mattermost_sender.dart +++ b/lib/oto/utils/mattermost/mattermost_sender.dart @@ -2,8 +2,8 @@ import 'dart:async'; import 'dart:convert'; import 'package:color/color.dart'; -import 'package:dart_framework/utils/string_util.dart'; -import 'package:dart_framework/utils/system_util.dart'; +import 'package:oto_cli/framework/utils/string_util.dart'; +import 'package:oto_cli/framework/utils/system_util.dart'; import 'package:http/http.dart' as http; import 'package:oto_cli/oto/utils/mattermost/mattermost_data.dart'; diff --git a/pubspec.yaml b/pubspec.yaml index 3f41888..1c918cc 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -13,15 +13,13 @@ dependencies: http: ^1.2.0 json_annotation: ^4.8.1 resource_importer: ^0.2.0 - dart_framework: - #path: ../dart_framework - git: - url: toki@toki-labs.com:/Users/toki/git/dart_framework.git - ref: master + yaml: ^3.1.0 color: ^3.0.0 file_hasher: ^0.1.0+0 cron: ^0.6.1 xml: ^6.6.1 + archive: ^4.0.9 + ftpconnect: ^2.0.10 dev_dependencies: lints: ^6.0.0