Internalize dart_framework: remove external git dependency
- Copy all used dart_framework files into lib/framework/ - Replace all package:dart_framework/ imports with package:oto_cli/framework/ - Add yaml, archive, ftpconnect as explicit direct dependencies - Remove dart_framework git dependency from pubspec.yaml Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
da249e3659
commit
e865f7dc8b
78 changed files with 2907 additions and 97 deletions
|
|
@ -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';
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
|
|
|||
126
lib/framework/core/app_data_manager.dart
Normal file
126
lib/framework/core/app_data_manager.dart
Normal file
|
|
@ -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<AppData> create(SCMType scm, String workspace,
|
||||
String relativeAssetPath, String name) async {
|
||||
_scm = scm;
|
||||
_workspace = workspace;
|
||||
_relativeAssetPath = relativeAssetPath;
|
||||
var c = Completer<AppData>();
|
||||
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<int> 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<String> getVersion() async {
|
||||
var c = Completer<String>();
|
||||
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 = <int>[];
|
||||
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 = <String>['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<String> 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;
|
||||
}
|
||||
}
|
||||
20
lib/framework/core/application.dart
Normal file
20
lib/framework/core/application.dart
Normal file
|
|
@ -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);
|
||||
});
|
||||
}
|
||||
}
|
||||
7
lib/framework/data/isolate_data.dart
Normal file
7
lib/framework/data/isolate_data.dart
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
enum IsolateEvent { ready, exit }
|
||||
|
||||
class IsoMessege {
|
||||
late String type;
|
||||
late Object? data;
|
||||
IsoMessege(this.type, {this.data});
|
||||
}
|
||||
119
lib/framework/log/log.dart
Normal file
119
lib/framework/log/log.dart
Normal file
|
|
@ -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<LogItem> 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();
|
||||
}
|
||||
}
|
||||
18
lib/framework/model/app_data.dart
Normal file
18
lib/framework/model/app_data.dart
Normal file
|
|
@ -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<String, dynamic> json) =>
|
||||
_$AppDataFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$AppDataToJson(this);
|
||||
}
|
||||
22
lib/framework/model/app_data.g.dart
Normal file
22
lib/framework/model/app_data.g.dart
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'app_data.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// JsonSerializableGenerator
|
||||
// **************************************************************************
|
||||
|
||||
AppData _$AppDataFromJson(Map<String, dynamic> 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<String, dynamic> _$AppDataToJson(AppData instance) => <String, dynamic>{
|
||||
'name': instance.name,
|
||||
'version': instance.version,
|
||||
'gitCount': instance.gitCount,
|
||||
'gitHash': instance.gitHash,
|
||||
'buildDate': instance.buildDate,
|
||||
};
|
||||
276
lib/framework/platform/isolate_manager.dart
Normal file
276
lib/framework/platform/isolate_manager.dart
Normal file
|
|
@ -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<String, List<void Function(Object?)>> _listenerMap = {};
|
||||
final Map<IsolateEvent, List<void Function(Object?)>> _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<int, IsolateBase> _isoMap = {};
|
||||
final Map<int, Map<String, Function(Object?)>> _innerEventMap = {};
|
||||
|
||||
static IsolateHandler create<T extends IsolateBase>(T inst,
|
||||
{Object? initData}) {
|
||||
var id = nonce;
|
||||
var handler = IsolateHandler(id);
|
||||
instance._create<T>(inst, initData, id, handler._isolateEventHandler,
|
||||
handler._isolateMessageHandler);
|
||||
return handler;
|
||||
}
|
||||
|
||||
void _create<T extends IsolateBase>(
|
||||
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<String, Function(Object?)>? 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<String, List<_IsolateEventListener>> _eventMap = {};
|
||||
final List<_IsolateEventListener> _removeList = [];
|
||||
|
||||
// ignore: library_private_types_in_public_api
|
||||
Future<void> 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);
|
||||
}
|
||||
}
|
||||
20
lib/framework/platform/platform_base.dart
Normal file
20
lib/framework/platform/platform_base.dart
Normal file
|
|
@ -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<String, void Function(Object?)> messageListenerMap);
|
||||
void write(String log);
|
||||
void end();
|
||||
}
|
||||
|
||||
void initializeApp(String name, String appID) => initialize(name, appID);
|
||||
|
||||
Future<String> getIPAddressPlatform(String domain) => getIPAddress(domain);
|
||||
|
||||
Future<Uint8List?> readFileBytePlatform(String filePath) => readFileBytePlatform(filePath);
|
||||
111
lib/framework/platform/platform_io.dart
Normal file
111
lib/framework/platform/platform_io.dart
Normal file
|
|
@ -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<String> 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<Uint8List?> 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<String, void Function(Object?)> messageListenerMap) {
|
||||
var handler =
|
||||
IsolateManager.create<LogWriterIO>(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);
|
||||
}
|
||||
}
|
||||
11
lib/framework/platform/platform_stub.dart
Normal file
11
lib/framework/platform/platform_stub.dart
Normal file
|
|
@ -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<String> getIPAddress(String domain) => throw UnsupportedError('Cannot execute method');
|
||||
|
||||
Future<Uint8List?> readFileByte(String filePath) => throw UnsupportedError('Cannot execute method');
|
||||
29
lib/framework/platform/platform_web.dart
Normal file
29
lib/framework/platform/platform_web.dart
Normal file
|
|
@ -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<String> getIPAddress(String domain) => dataFutrue('');
|
||||
|
||||
Future<Uint8List?> readFileByte(String filePath) => dataFutrue(null);
|
||||
|
||||
class LogWriterWeb implements LogWriter {
|
||||
@override
|
||||
void start(String path, Map<String, void Function(Object?)> messageListenerMap) {}
|
||||
|
||||
@override
|
||||
void write(String log) {}
|
||||
|
||||
@override
|
||||
void end() {}
|
||||
}
|
||||
679
lib/framework/platform/process.dart
Normal file
679
lib/framework/platform/process.dart
Normal file
|
|
@ -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<List<int>, String> _decoder;
|
||||
|
||||
// ignore: no_leading_underscores_for_local_identifiers
|
||||
ProcessData(this._enableStdout, this._enableStderr,
|
||||
{LogHandler? logHandler, Converter<List<int>, 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<String> get stdoutArr {
|
||||
return getBufferToArray(stdout);
|
||||
}
|
||||
|
||||
List<String> get stderrArr {
|
||||
return getBufferToArray(stderr);
|
||||
}
|
||||
|
||||
List<String> getBufferToArray(StringBuffer buffer) {
|
||||
var list = <String>[];
|
||||
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<ProcessData> startExe(String exe, List<String> 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<ProcessData> start(StringBuffer shell,
|
||||
{Converter<List<int>, String>? decoder,
|
||||
String? workspace,
|
||||
bool? printStdout,
|
||||
bool? printStderr,
|
||||
LogHandler? logHandler}) async {
|
||||
var c = Completer<ProcessData>();
|
||||
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<ProcessResult> run(StringBuffer shell,
|
||||
{String? workspace,
|
||||
bool printStdout = true,
|
||||
bool printStderr = true,
|
||||
Converter<List<int>, String>? decoder,
|
||||
LogHandler? logHandler}) async {
|
||||
var c = Completer<ProcessResult>();
|
||||
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<String> 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<String> runGetStdout(StringBuffer shell) async {
|
||||
var c = Completer<String>();
|
||||
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<NetStatData?> findUsePortPid(int port) async {
|
||||
await removeTempBat();
|
||||
var c = Completer<NetStatData?>();
|
||||
var shell = StringBuffer('netstat -aon | find "$port"');
|
||||
var stdout = "";
|
||||
try {
|
||||
stdout = await runGetStdout(shell);
|
||||
} on Exception {}
|
||||
if (stdout == "") {
|
||||
c.complete(null);
|
||||
} else {
|
||||
var netList = <NetStatData?>[];
|
||||
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<List<ProcessInfo>> findProcess(String searchWord) async {
|
||||
await removeTempBat();
|
||||
var c = Completer<List<ProcessInfo>>();
|
||||
var pList = <ProcessInfo>[];
|
||||
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<ProcessInfo> parseProcessStd(String stdout) {
|
||||
var pList = <ProcessInfo>[];
|
||||
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<ProcessInfo?> findProcessByPid(int pid) async {
|
||||
var c = Completer<ProcessInfo?>();
|
||||
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<String> 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++;
|
||||
}
|
||||
}
|
||||
}
|
||||
400
lib/framework/utils/os_startup.dart
Normal file
400
lib/framework/utils/os_startup.dart
Normal file
|
|
@ -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<bool> isRegistedStartup(String label) async {
|
||||
return _current!.isRegistedStartup(label);
|
||||
}
|
||||
|
||||
static Future<bool> registStartup(String executableFilePath, String label,
|
||||
{List<String>? arguments,
|
||||
String? logStandardFilePath,
|
||||
String? logErrorFilePath}) async {
|
||||
return _current!.registStartup(executableFilePath, label,
|
||||
arguments: arguments,
|
||||
logStandardFilePath: logStandardFilePath,
|
||||
logErrorFilePath: logErrorFilePath);
|
||||
}
|
||||
|
||||
static Future<bool> unregistStartup(String label) async {
|
||||
return _current!.unregistStartup(label);
|
||||
}
|
||||
}
|
||||
|
||||
class _Startup {
|
||||
Future<bool> isRegistedStartup(String label) async {
|
||||
var c = Completer<bool>();
|
||||
return c.future;
|
||||
}
|
||||
|
||||
Future<bool> registStartup(String executableFilePath, String label,
|
||||
{List<String>? arguments,
|
||||
String? logStandardFilePath,
|
||||
String? logErrorFilePath}) async {
|
||||
var c = Completer<bool>();
|
||||
return c.future;
|
||||
}
|
||||
|
||||
Future<bool> unregistStartup(String label) async {
|
||||
var c = Completer<bool>();
|
||||
return c.future;
|
||||
}
|
||||
}
|
||||
|
||||
/// ************* MAC ***************
|
||||
class _StartupMac extends _Startup {
|
||||
final plistTemplate = """<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>KeepAlive</key>
|
||||
<false/>
|
||||
<key>Label</key>
|
||||
<string>{LABEL}</string>
|
||||
<key>ProgramArguments</key>
|
||||
<array>
|
||||
<string>{FILE_PATH}</string>
|
||||
</array>
|
||||
<key>RunAtLoad</key>
|
||||
<true/>{LOG_STANDARD}{LOG_ERROR}
|
||||
</dict>
|
||||
</plist>""";
|
||||
|
||||
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 = """
|
||||
|
||||
<key>StandardOutPath</key>
|
||||
<string>{LOG_STANDARD}</string>""";
|
||||
final logErrorTemplate = """
|
||||
|
||||
<key>StandardErrorPath</key>
|
||||
<string>{LOG_ERROR}</string>""";
|
||||
|
||||
@override
|
||||
Future<bool> isRegistedStartup(String label) async {
|
||||
var c = Completer<bool>();
|
||||
var plistName = '$label.plist';
|
||||
var userPath = Path.userPath;
|
||||
c.complete(
|
||||
await File('$userPath/Library/LaunchAgents/$plistName').exists());
|
||||
return c.future;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<bool> registStartup(String executableFilePath, String label,
|
||||
{List<String>? 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<bool> unregistStartup(String label) async {
|
||||
var c = Completer<bool>();
|
||||
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<bool> isRegistedStartup(String label) async {
|
||||
var c = Completer<bool>();
|
||||
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<bool> registStartup(String executableFilePath, String label,
|
||||
{List<String>? arguments,
|
||||
String? logStandardFilePath,
|
||||
String? logErrorFilePath}) async {
|
||||
var c = Completer<bool>();
|
||||
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<bool> unregistStartup(String label) async {
|
||||
var c = Completer<bool>();
|
||||
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<bool> 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 = <String>[];
|
||||
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<bool> registStartup(String executableFilePath, String label,
|
||||
{List<String>? 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<bool> 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);
|
||||
}
|
||||
}
|
||||
132
lib/framework/utils/path.dart
Normal file
132
lib/framework/utils/path.dart
Normal file
|
|
@ -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<bool> copy(String startPath, String destPath, bool isDir,
|
||||
{required List<String>? ignorePattern,
|
||||
required List<String>? ignoredList,
|
||||
bool isMove = false,
|
||||
bool isOverwrite = true}) async {
|
||||
var c = Completer<bool>();
|
||||
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;
|
||||
}
|
||||
}
|
||||
223
lib/framework/utils/slack/slack_data.dart
Normal file
223
lib/framework/utils/slack/slack_data.dart
Normal file
|
|
@ -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<SlackBlock>? blocks = null;
|
||||
late List<SlackAttachment>? attachments = null;
|
||||
bool? link_names;
|
||||
|
||||
String get json {
|
||||
return jsonEncode(toJson());
|
||||
}
|
||||
|
||||
DataSlack(this.channel);
|
||||
|
||||
factory DataSlack.fromJson(Map<String, dynamic> json) =>
|
||||
_$DataSlackFromJson(json);
|
||||
Map<String, dynamic> toJson() {
|
||||
return removeKeys(_$DataSlackToJson(this));
|
||||
}
|
||||
}
|
||||
|
||||
Map<String, dynamic> removeKeys(Map<String, dynamic> 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<String, dynamic> json) =>
|
||||
_$SlackBlockFromJson(json);
|
||||
Map<String, dynamic> toJson() => removeKeys(_$SlackBlockToJson(this));
|
||||
}
|
||||
|
||||
@JsonSerializable()
|
||||
class SlackBlockHeader extends SlackBlock {
|
||||
late SlackBlockText? text;
|
||||
|
||||
SlackBlockHeader() {
|
||||
super.type = SlackBlockType.header;
|
||||
}
|
||||
|
||||
factory SlackBlockHeader.fromJson(Map<String, dynamic> json) =>
|
||||
_$SlackBlockHeaderFromJson(json);
|
||||
@override
|
||||
Map<String, dynamic> toJson() => removeKeys(_$SlackBlockHeaderToJson(this));
|
||||
}
|
||||
|
||||
@JsonSerializable()
|
||||
class SlackBlockSection extends SlackBlock {
|
||||
late SlackBlockText? text = null;
|
||||
late List<SlackBlockText>? fields = null;
|
||||
late SlackAccessory? accessory = null;
|
||||
|
||||
SlackBlockSection() {
|
||||
type = SlackBlockType.section;
|
||||
}
|
||||
|
||||
factory SlackBlockSection.fromJson(Map<String, dynamic> json) =>
|
||||
_$SlackBlockSectionFromJson(json);
|
||||
@override
|
||||
Map<String, dynamic> 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<String, dynamic> json) =>
|
||||
_$SlackAccessoryFromJson(json);
|
||||
Map<String, dynamic> toJson() => removeKeys(_$SlackAccessoryToJson(this));
|
||||
}
|
||||
|
||||
@JsonSerializable()
|
||||
class SlackBlockText {
|
||||
SlackTextType type = SlackTextType.mrkdwn;
|
||||
late String? text = null;
|
||||
late bool? emoji = null;
|
||||
|
||||
SlackBlockText();
|
||||
|
||||
factory SlackBlockText.fromJson(Map<String, dynamic> json) =>
|
||||
_$SlackBlockTextFromJson(json);
|
||||
Map<String, dynamic> 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<SlackBlock>? blocks = null;
|
||||
late List<SlackField>? fields = null;
|
||||
late List<SlackAction>? actions = null;
|
||||
|
||||
SlackAttachment();
|
||||
|
||||
factory SlackAttachment.fromJson(Map<String, dynamic> json) =>
|
||||
_$SlackAttachmentFromJson(json);
|
||||
Map<String, dynamic> 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<String, dynamic> json) =>
|
||||
_$SlackFieldFromJson(json);
|
||||
Map<String, dynamic> 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<String, dynamic> json) =>
|
||||
_$SlackActionFromJson(json);
|
||||
Map<String, dynamic> 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<MultipartRequest> 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<MultipartRequest>();
|
||||
c.complete(form);
|
||||
return c.future;
|
||||
}
|
||||
}
|
||||
223
lib/framework/utils/slack/slack_data.g.dart
Normal file
223
lib/framework/utils/slack/slack_data.g.dart
Normal file
|
|
@ -0,0 +1,223 @@
|
|||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'slack_data.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// JsonSerializableGenerator
|
||||
// **************************************************************************
|
||||
|
||||
DataSlack _$DataSlackFromJson(Map<String, dynamic> json) => DataSlack(
|
||||
json['channel'] as String,
|
||||
)
|
||||
..text = json['text'] as String?
|
||||
..blocks = (json['blocks'] as List<dynamic>?)
|
||||
?.map((e) => SlackBlock.fromJson(e as Map<String, dynamic>))
|
||||
.toList()
|
||||
..attachments = (json['attachments'] as List<dynamic>?)
|
||||
?.map((e) => SlackAttachment.fromJson(e as Map<String, dynamic>))
|
||||
.toList()
|
||||
..link_names = json['link_names'] as bool?;
|
||||
|
||||
Map<String, dynamic> _$DataSlackToJson(DataSlack instance) => <String, dynamic>{
|
||||
'channel': instance.channel,
|
||||
'text': instance.text,
|
||||
'blocks': instance.blocks,
|
||||
'attachments': instance.attachments,
|
||||
'link_names': instance.link_names,
|
||||
};
|
||||
|
||||
SlackBlock _$SlackBlockFromJson(Map<String, dynamic> json) => SlackBlock()
|
||||
..type = $enumDecode(_$SlackBlockTypeEnumMap, json['type'])
|
||||
..block_id = json['block_id'] as String?;
|
||||
|
||||
Map<String, dynamic> _$SlackBlockToJson(SlackBlock instance) =>
|
||||
<String, dynamic>{
|
||||
'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<String, dynamic> 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<String, dynamic>);
|
||||
|
||||
Map<String, dynamic> _$SlackBlockHeaderToJson(SlackBlockHeader instance) =>
|
||||
<String, dynamic>{
|
||||
'type': _$SlackBlockTypeEnumMap[instance.type]!,
|
||||
'block_id': instance.block_id,
|
||||
'text': instance.text,
|
||||
};
|
||||
|
||||
SlackBlockSection _$SlackBlockSectionFromJson(Map<String, dynamic> 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<String, dynamic>)
|
||||
..fields = (json['fields'] as List<dynamic>?)
|
||||
?.map((e) => SlackBlockText.fromJson(e as Map<String, dynamic>))
|
||||
.toList()
|
||||
..accessory = json['accessory'] == null
|
||||
? null
|
||||
: SlackAccessory.fromJson(json['accessory'] as Map<String, dynamic>);
|
||||
|
||||
Map<String, dynamic> _$SlackBlockSectionToJson(SlackBlockSection instance) =>
|
||||
<String, dynamic>{
|
||||
'type': _$SlackBlockTypeEnumMap[instance.type]!,
|
||||
'block_id': instance.block_id,
|
||||
'text': instance.text,
|
||||
'fields': instance.fields,
|
||||
'accessory': instance.accessory,
|
||||
};
|
||||
|
||||
SlackAccessory _$SlackAccessoryFromJson(Map<String, dynamic> json) =>
|
||||
SlackAccessory()
|
||||
..type = $enumDecode(_$SlackActionTypeEnumMap, json['type'])
|
||||
..text = json['text'] == null
|
||||
? null
|
||||
: SlackBlockText.fromJson(json['text'] as Map<String, dynamic>)
|
||||
..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<String, dynamic> _$SlackAccessoryToJson(SlackAccessory instance) =>
|
||||
<String, dynamic>{
|
||||
'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<String, dynamic> json) =>
|
||||
SlackBlockText()
|
||||
..type = $enumDecode(_$SlackTextTypeEnumMap, json['type'])
|
||||
..text = json['text'] as String?
|
||||
..emoji = json['emoji'] as bool?;
|
||||
|
||||
Map<String, dynamic> _$SlackBlockTextToJson(SlackBlockText instance) =>
|
||||
<String, dynamic>{
|
||||
'type': _$SlackTextTypeEnumMap[instance.type]!,
|
||||
'text': instance.text,
|
||||
'emoji': instance.emoji,
|
||||
};
|
||||
|
||||
const _$SlackTextTypeEnumMap = {
|
||||
SlackTextType.mrkdwn: 'mrkdwn',
|
||||
SlackTextType.plain_text: 'plain_text',
|
||||
};
|
||||
|
||||
SlackAttachment _$SlackAttachmentFromJson(Map<String, dynamic> 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<dynamic>?)
|
||||
?.map((e) => SlackBlock.fromJson(e as Map<String, dynamic>))
|
||||
.toList()
|
||||
..fields = (json['fields'] as List<dynamic>?)
|
||||
?.map((e) => SlackField.fromJson(e as Map<String, dynamic>))
|
||||
.toList()
|
||||
..actions = (json['actions'] as List<dynamic>?)
|
||||
?.map((e) => SlackAction.fromJson(e as Map<String, dynamic>))
|
||||
.toList();
|
||||
|
||||
Map<String, dynamic> _$SlackAttachmentToJson(SlackAttachment instance) =>
|
||||
<String, dynamic>{
|
||||
'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<String, dynamic> json) => SlackField()
|
||||
..title = json['title'] as String?
|
||||
..value = json['value'] as String?
|
||||
..short = json['short'] as bool?;
|
||||
|
||||
Map<String, dynamic> _$SlackFieldToJson(SlackField instance) =>
|
||||
<String, dynamic>{
|
||||
'title': instance.title,
|
||||
'value': instance.value,
|
||||
'short': instance.short,
|
||||
};
|
||||
|
||||
SlackAction _$SlackActionFromJson(Map<String, dynamic> 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<String, dynamic> _$SlackActionToJson(SlackAction instance) =>
|
||||
<String, dynamic>{
|
||||
'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<String, dynamic> 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<String, dynamic> _$SlackConfirmToJson(SlackConfirm instance) =>
|
||||
<String, dynamic>{
|
||||
'title': instance.title,
|
||||
'text': instance.text,
|
||||
'ok_text': instance.ok_text,
|
||||
'dismiss_text': instance.dismiss_text,
|
||||
};
|
||||
137
lib/framework/utils/slack/slack_sender.dart
Normal file
137
lib/framework/utils/slack/slack_sender.dart
Normal file
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
103
lib/framework/utils/slack/slack_template.dart
Normal file
103
lib/framework/utils/slack/slack_template.dart
Normal file
|
|
@ -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 =
|
||||
'<https://example.com|Overlook Hotel> \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 = '<https://example.com|Bates Motel> :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 =
|
||||
'<https://example.com|The Great Northern Hotel> :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;
|
||||
}
|
||||
}
|
||||
44
lib/framework/utils/string_util.dart
Normal file
44
lib/framework/utils/string_util.dart
Normal file
|
|
@ -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('.');
|
||||
}
|
||||
112
lib/framework/utils/system_util.dart
Normal file
112
lib/framework/utils/system_util.dart
Normal file
|
|
@ -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<String, List<String>?> envArguments(List<String> arguments) {
|
||||
var dic = <String, List<String>?>{};
|
||||
var list = <String>[];
|
||||
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<String>? arr = List<String>.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<String, dynamic>? getMapFromJson(String jsonStr) {
|
||||
Map<String, dynamic>? 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<String, dynamic>? getMapFromYaml(String yamlStr) {
|
||||
Map<String, dynamic>? 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<String> getIPAddress(String domain) => getIPAddressPlatform(domain);
|
||||
|
||||
Future get simpleFuture {
|
||||
var c = Completer();
|
||||
c.complete();
|
||||
return c.future;
|
||||
}
|
||||
|
||||
Future<T> dataFutrue<T>(T data) {
|
||||
var c = Completer<T>();
|
||||
c.complete(data);
|
||||
return c.future;
|
||||
}
|
||||
|
||||
Future<Uint8List?> readFileByte(String filePath) => readFileBytePlatform(filePath);
|
||||
|
|
@ -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';
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in a new issue