mirror of
https://github.com/lollipopkit/flutter_server_box.git
synced 2025-12-17 23:34:24 +01:00
new: settings of containerTrySudo usePodman
This commit is contained in:
@@ -74,7 +74,7 @@ class Backup {
|
||||
spis = Stores.server.fetch(),
|
||||
snippets = Stores.snippet.fetch(),
|
||||
keys = Stores.key.fetch(),
|
||||
container = Stores.docker.box.toJson(),
|
||||
container = Stores.container.box.toJson(),
|
||||
settings = Stores.setting.box.toJson(),
|
||||
lastModTime = Stores.lastModTime,
|
||||
history = Stores.history.box.toJson();
|
||||
@@ -176,19 +176,19 @@ class Backup {
|
||||
}
|
||||
|
||||
// Container
|
||||
final nowContainer = Stores.docker.box.keys.toSet();
|
||||
final nowContainer = Stores.container.box.keys.toSet();
|
||||
final bakContainer = container.keys.toSet();
|
||||
final newContainer = bakContainer.difference(nowContainer);
|
||||
final delContainer = nowContainer.difference(bakContainer);
|
||||
final updateContainer = nowContainer.intersection(bakContainer);
|
||||
for (final s in newContainer) {
|
||||
Stores.docker.box.put(s, container[s]);
|
||||
Stores.container.box.put(s, container[s]);
|
||||
}
|
||||
for (final s in delContainer) {
|
||||
Stores.docker.box.delete(s);
|
||||
Stores.container.box.delete(s);
|
||||
}
|
||||
for (final s in updateContainer) {
|
||||
Stores.docker.box.put(s, container[s]);
|
||||
Stores.container.box.put(s, container[s]);
|
||||
}
|
||||
|
||||
Pros.reload();
|
||||
|
||||
@@ -17,48 +17,48 @@ final _dockerNotFound =
|
||||
RegExp(r"command not found|Unknown command|Command '\w+' not found");
|
||||
|
||||
class ContainerProvider extends ChangeNotifier {
|
||||
SSHClient? client;
|
||||
String? userName;
|
||||
final SSHClient? client;
|
||||
final String userName;
|
||||
final String hostId;
|
||||
final BuildContext context;
|
||||
List<ContainerPs>? items;
|
||||
List<ContainerImg>? images;
|
||||
String? version;
|
||||
ContainerErr? error;
|
||||
String? hostId;
|
||||
String? runLog;
|
||||
BuildContext? context;
|
||||
ContainerType type;
|
||||
|
||||
ContainerProvider({
|
||||
this.client,
|
||||
this.userName,
|
||||
this.hostId,
|
||||
this.context,
|
||||
}) : type = Stores.docker.getType(hostId) {
|
||||
required this.client,
|
||||
required this.userName,
|
||||
required this.hostId,
|
||||
required this.context,
|
||||
}) : type = Stores.container.getType(hostId) {
|
||||
refresh();
|
||||
}
|
||||
|
||||
Future<void> setType(ContainerType type) async {
|
||||
this.type = type;
|
||||
Stores.docker.setType(hostId, type);
|
||||
Stores.container.setType(type, hostId);
|
||||
error = runLog = items = images = version = null;
|
||||
notifyListeners();
|
||||
await refresh();
|
||||
}
|
||||
|
||||
Future<bool> _checkDockerInstalled(SSHClient client) async {
|
||||
final session = await client.execute("docker");
|
||||
await session.done;
|
||||
// debugPrint('docker code: ${session.exitCode}');
|
||||
return session.exitCode == 0;
|
||||
}
|
||||
// Future<bool> _checkDockerInstalled(SSHClient client) async {
|
||||
// final session = await client.execute("docker");
|
||||
// await session.done;
|
||||
// // debugPrint('docker code: ${session.exitCode}');
|
||||
// return session.exitCode == 0;
|
||||
// }
|
||||
|
||||
String _removeSudoPrompts(String value) {
|
||||
final regex = RegExp(r"\[sudo\] password for \w+:");
|
||||
if (value.startsWith(regex)) {
|
||||
return value.replaceFirstMapped(regex, (match) => "");
|
||||
}
|
||||
return value;
|
||||
}
|
||||
// String _removeSudoPrompts(String value) {
|
||||
// final regex = RegExp(r"\[sudo\] password for \w+:");
|
||||
// if (value.startsWith(regex)) {
|
||||
// return value.replaceFirstMapped(regex, (match) => "");
|
||||
// }
|
||||
// return value;
|
||||
// }
|
||||
|
||||
Future<bool> _requiresSudo() async {
|
||||
final psResult = await client?.run(_wrap(ContainerCmdType.ps.exec(type)));
|
||||
@@ -69,31 +69,22 @@ class ContainerProvider extends ChangeNotifier {
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Docker Logic:
|
||||
/// - Check if docker is installed, if not, return error, if yes, continue
|
||||
/// - Check permission, if permission denied and no DOCKER_HOST, return error
|
||||
Future<void> refresh() async {
|
||||
var raw = '';
|
||||
var rawErr = '';
|
||||
debugPrint('exec: ${_wrap(ContainerCmdType.execAll(type))}');
|
||||
|
||||
final sudo = await _requiresSudo();
|
||||
final sudo =
|
||||
await _requiresSudo() && Stores.setting.containerTrySudo.fetch();
|
||||
|
||||
await client?.execWithPwd(
|
||||
_wrap(ContainerCmdType.execAll(type, sudo: sudo)),
|
||||
context: context,
|
||||
onStdout: (data, _) => raw = '$raw$data',
|
||||
onStderr: (data, _) => raw = '$rawErr$data',
|
||||
);
|
||||
|
||||
raw = _removeSudoPrompts(raw);
|
||||
rawErr = _removeSudoPrompts(rawErr);
|
||||
|
||||
debugPrint('result raw [$raw, $rawErr]');
|
||||
|
||||
final dockerInstalled = await _checkDockerInstalled(client!);
|
||||
// debugPrint("docker installed = $dockerInstalled");
|
||||
|
||||
if (!dockerInstalled ||
|
||||
raw.contains(_dockerNotFound) ||
|
||||
rawErr.contains(_dockerNotFound)) {
|
||||
if (raw.contains(_dockerNotFound)) {
|
||||
error = ContainerErr(type: ContainerErrType.notInstalled);
|
||||
notifyListeners();
|
||||
return;
|
||||
@@ -188,7 +179,7 @@ class ContainerProvider extends ChangeNotifier {
|
||||
|
||||
Future<ContainerErr?> restart(String id) async => await run('restart $id');
|
||||
|
||||
Future<ContainerErr?> run(String cmd) async {
|
||||
Future<ContainerErr?> run(String cmd, {bool autoRefresh = true}) async {
|
||||
cmd = switch (type) {
|
||||
ContainerType.docker => 'docker $cmd',
|
||||
ContainerType.podman => 'podman $cmd',
|
||||
@@ -214,13 +205,13 @@ class ContainerProvider extends ChangeNotifier {
|
||||
message: errs.join('\n').trim(),
|
||||
);
|
||||
}
|
||||
await refresh();
|
||||
if (autoRefresh) await refresh();
|
||||
return null;
|
||||
}
|
||||
|
||||
/// wrap cmd with `docker host`
|
||||
String _wrap(String cmd) {
|
||||
final dockerHost = Stores.docker.fetch(hostId);
|
||||
final dockerHost = Stores.container.fetch(hostId);
|
||||
cmd = 'export LANG=en_US.UTF-8 && $cmd';
|
||||
final noDockerHost = dockerHost?.isEmpty ?? true;
|
||||
if (!noDockerHost) {
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
|
||||
class BuildData {
|
||||
static const String name = "ServerBox";
|
||||
static const int build = 761;
|
||||
static const int build = 762;
|
||||
static const String engine = "3.19.0";
|
||||
static const String buildAt = "2024-02-18 12:48:41";
|
||||
static const int modifications = 10;
|
||||
static const String buildAt = "2024-02-18 15:57:42";
|
||||
static const int modifications = 12;
|
||||
static const int script = 38;
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ import 'package:toolbox/locator.dart';
|
||||
abstract final class Stores {
|
||||
static final setting = locator<SettingStore>();
|
||||
static final server = locator<ServerStore>();
|
||||
static final docker = locator<DockerStore>();
|
||||
static final container = locator<ContainerStore>();
|
||||
static final history = locator<HistoryStore>();
|
||||
static final key = locator<PrivateKeyStore>();
|
||||
static final snippet = locator<SnippetStore>();
|
||||
@@ -18,7 +18,7 @@ abstract final class Stores {
|
||||
static final List<PersistentStore> all = [
|
||||
setting,
|
||||
server,
|
||||
docker,
|
||||
container,
|
||||
history,
|
||||
key,
|
||||
snippet,
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
import 'package:toolbox/core/extension/listx.dart';
|
||||
import 'package:toolbox/data/model/container/type.dart';
|
||||
import 'package:toolbox/data/res/store.dart';
|
||||
|
||||
import '../../core/persistant_store.dart';
|
||||
|
||||
const _keyConfig = 'providerConfig';
|
||||
|
||||
class DockerStore extends PersistentStore {
|
||||
DockerStore() : super('docker');
|
||||
class ContainerStore extends PersistentStore {
|
||||
ContainerStore() : super('docker');
|
||||
|
||||
String? fetch(String? id) {
|
||||
return box.get(id);
|
||||
@@ -16,17 +18,28 @@ class DockerStore extends PersistentStore {
|
||||
box.updateLastModified();
|
||||
}
|
||||
|
||||
ContainerType getType([String? id]) {
|
||||
final cfg = box.get(_keyConfig + (id ?? ''));
|
||||
if (cfg == null) {
|
||||
return ContainerType.docker;
|
||||
} else {
|
||||
return ContainerType.values.firstWhere((e) => e.toString() == cfg);
|
||||
ContainerType getType([String id = '']) {
|
||||
final cfg = box.get(_keyConfig + id);
|
||||
if (cfg != null) {
|
||||
final type =
|
||||
ContainerType.values.firstWhereOrNull((e) => e.toString() == cfg);
|
||||
if (type != null) return type;
|
||||
}
|
||||
|
||||
return defaultType;
|
||||
}
|
||||
|
||||
void setType(String? id, ContainerType type) {
|
||||
box.put(_keyConfig + (id ?? ''), type.toString());
|
||||
ContainerType get defaultType {
|
||||
if (Stores.setting.usePodman.fetch()) return ContainerType.podman;
|
||||
return ContainerType.docker;
|
||||
}
|
||||
|
||||
void setType(ContainerType type, [String id = '']) {
|
||||
if (type == defaultType) {
|
||||
box.delete(_keyConfig + id);
|
||||
} else {
|
||||
box.put(_keyConfig + id, type.toString());
|
||||
}
|
||||
box.updateLastModified();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -224,6 +224,12 @@ class SettingStore extends PersistentStore {
|
||||
].map((e) => e.index).toList(),
|
||||
);
|
||||
|
||||
/// Docker is more popular than podman, set to `false` to use docker
|
||||
late final usePodman = property('usePodman', false);
|
||||
|
||||
/// Try to use `sudo` to run docker command
|
||||
late final containerTrySudo = property('containerTrySudo', true);
|
||||
|
||||
// Never show these settings for users
|
||||
//
|
||||
// ------BEGIN------
|
||||
|
||||
Reference in New Issue
Block a user