diff --git a/assets/linux/freebsd.png b/assets/linux/freebsd.png new file mode 100644 index 00000000..6d4a6298 Binary files /dev/null and b/assets/linux/freebsd.png differ diff --git a/assets/linux/rocky.png b/assets/linux/rocky.png new file mode 100644 index 00000000..4431d97e Binary files /dev/null and b/assets/linux/rocky.png differ diff --git a/lib/core/extension/stringx.dart b/lib/core/extension/stringx.dart index fdcd84d0..3237187d 100644 --- a/lib/core/extension/stringx.dart +++ b/lib/core/extension/stringx.dart @@ -2,26 +2,10 @@ import 'dart:convert'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import 'package:toolbox/data/model/distribution.dart'; extension StringX on String { int get i => int.parse(this); - Distribution get dist { - final lower = toLowerCase(); - for (var dist in debianDistList) { - if (lower.contains(dist)) { - return Distribution.debian; - } - } - for (var dist in rehlDistList) { - if (lower.contains(dist)) { - return Distribution.rehl; - } - } - return Distribution.unknown; - } - Uri get uri { return Uri.parse(this); } diff --git a/lib/data/model/apt/upgrade_pkg_info.dart b/lib/data/model/apt/upgrade_pkg_info.dart index 1a68087b..c42eda0f 100644 --- a/lib/data/model/apt/upgrade_pkg_info.dart +++ b/lib/data/model/apt/upgrade_pkg_info.dart @@ -1,8 +1,8 @@ -import 'package:toolbox/data/model/distribution.dart'; +import 'package:toolbox/data/model/server/dist.dart'; class UpgradePkgInfo { final String _raw; - final Distribution _dist; + final Dist _dist; late String package; late String nowVersion; @@ -11,12 +11,15 @@ class UpgradePkgInfo { UpgradePkgInfo(this._raw, this._dist) { switch (_dist) { - case Distribution.debian: - case Distribution.unknown: + case Dist.debian: + case Dist.ubuntu: _parseApt(); break; - case Distribution.rehl: + case Dist.centos: _parseYum(); + break; + default: + throw Exception('Unsupported dist: $_dist'); } } diff --git a/lib/data/model/distribution.dart b/lib/data/model/distribution.dart deleted file mode 100644 index 61e18443..00000000 --- a/lib/data/model/distribution.dart +++ /dev/null @@ -1,23 +0,0 @@ -enum Distribution { - unknown, - debian, - rehl, -} - -const debianDistList = [ - 'debian', - 'ubuntu', - 'linuxmint', - 'elementary', - 'raspbian', - 'armbian' -]; - -const rehlDistList = [ - 'redhat', - 'fedora', - 'centos', - 'scientificlinux', - 'rhel', - 'oraclelinux' -]; diff --git a/lib/data/model/server/dist.dart b/lib/data/model/server/dist.dart new file mode 100644 index 00000000..c9f80ad3 --- /dev/null +++ b/lib/data/model/server/dist.dart @@ -0,0 +1,30 @@ +enum Dist { + debian, + ubuntu, + centos, + fedora, + opensuse, + kali, + wrt, + armbian, + arch, + freebsd, + /// Rocky Linux + rocky; + + String? get iconPath { + return 'assets/linux/$name.png'; + } +} + +extension StringX on String { + Dist? get dist { + final lower = toLowerCase(); + for (final dist in Dist.values) { + if (lower.contains(dist.name)) { + return dist; + } + } + return null; + } +} diff --git a/lib/data/provider/apt.dart b/lib/data/provider/apt.dart index 7c58b968..58015c67 100644 --- a/lib/data/provider/apt.dart +++ b/lib/data/provider/apt.dart @@ -8,13 +8,16 @@ import 'package:toolbox/core/extension/stringx.dart'; import 'package:toolbox/core/extension/uint8list.dart'; import 'package:toolbox/core/provider_base.dart'; import 'package:toolbox/data/model/apt/upgrade_pkg_info.dart'; -import 'package:toolbox/data/model/distribution.dart'; +import 'package:toolbox/data/model/server/dist.dart'; + +enum _Type { apt, yum, dnf, zypper, pkg, pacman, opkg } class AptProvider extends BusyProvider { final logger = Logger('AptProvider'); SSHClient? client; - Distribution? dist; + Dist? dist; + _Type? type; Function()? onUpgrade; Function()? onUpdate; PwdRequestFunc? onPasswordRequest; @@ -31,7 +34,7 @@ class AptProvider extends BusyProvider { Future init( SSHClient client, - Distribution dist, + Dist? dist, Function() onUpgrade, Function() onUpdate, PwdRequestFunc onPasswordRequest, @@ -41,6 +44,37 @@ class AptProvider extends BusyProvider { this.onUpgrade = onUpgrade; this.onPasswordRequest = onPasswordRequest; whoami = user; + + switch (dist) { + case Dist.centos: + case Dist.rocky: + type = _Type.yum; + break; + case Dist.debian: + case Dist.ubuntu: + case Dist.kali: + case Dist.armbian: + type = _Type.apt; + break; + case Dist.fedora: + type = _Type.dnf; + break; + case Dist.opensuse: + type = _Type.zypper; + break; + case Dist.freebsd: + type = _Type.pkg; + break; + case Dist.wrt: + type = _Type.opkg; + break; + case Dist.arch: + type = _Type.pacman; + break; + case null: + error = 'Unsupported dist: $dist'; + break; + } } bool get isSU => whoami == 'root'; @@ -51,10 +85,10 @@ class AptProvider extends BusyProvider { isRequestingPwd = false; } - Future refreshInstalled() async { + Future refresh() async { final result = await _update(); try { - getUpgradeableList(result); + _parse(result); } catch (e) { error = '[Server Raw]:\n$result\n[App Error]:\n$e'; } finally { @@ -62,18 +96,18 @@ class AptProvider extends BusyProvider { } } - void getUpgradeableList(String? raw) { + void _parse(String? raw) { if (raw == null) return; var list = raw.split('\n'); - switch (dist) { - case Distribution.rehl: + switch (type) { + case _Type.yum: list = list.sublist(2); list.removeWhere((element) => element.isEmpty); final endLine = list.lastIndexWhere( (element) => element.contains('Obsoleting Packages')); list = list.sublist(0, endLine); break; - default: + case _Type.apt: // avoid other outputs // such as: [Could not chdir to home directory /home/test: No such file or directory, , WARNING: apt does not have a stable CLI interface. Use with caution in scripts., , Listing...] final idx = @@ -84,15 +118,18 @@ class AptProvider extends BusyProvider { } list = list.sublist(idx); list.removeWhere((element) => element.isEmpty); + break; + default: + return; } upgradeable = list.map((e) => UpgradePkgInfo(e, dist!)).toList(); } Future _update() async { - switch (dist) { - case Distribution.rehl: + switch (type) { + case _Type.yum: return await client?.run(_wrap('yum check-update')).string; - default: + case _Type.apt: await client!.exec( _wrap('apt update'), onStderr: _onPwd, @@ -105,19 +142,29 @@ class AptProvider extends BusyProvider { return await client ?.run('apt list --upgradeable'.withLangExport) .string; + default: + error = 'Unsupported dist: $dist'; + return null; } } Future upgrade() async { final upgradeCmd = () { - switch (dist) { - case Distribution.rehl: + switch (type) { + case _Type.yum: return 'yum upgrade -y'; - default: + case _Type.apt: return 'apt upgrade -y'; + default: + return null; } }(); + if (upgradeCmd == null) { + error = 'Unsupported dist: $dist'; + return; + } + await client!.exec( _wrap(upgradeCmd), onStderr: _onPwd, @@ -131,7 +178,7 @@ class AptProvider extends BusyProvider { ); upgradeLog = null; - refreshInstalled(); + refresh(); } Future _onPwd(String event, StreamSink stdin) async { diff --git a/lib/data/res/icon/common.dart b/lib/data/res/icon.dart similarity index 100% rename from lib/data/res/icon/common.dart rename to lib/data/res/icon.dart diff --git a/lib/data/res/icon/linux_icons.dart b/lib/data/res/icon/linux_icons.dart deleted file mode 100644 index 17b8ae5c..00000000 --- a/lib/data/res/icon/linux_icons.dart +++ /dev/null @@ -1,26 +0,0 @@ -final linuxIcons = LinuxIcons([ - 'ubuntu', - 'arch', - 'centos', - 'debian', - 'fedora', - 'opensuse', - 'kali', - 'wrt', - 'armbian' -]); - -class LinuxIcons { - List db; - - LinuxIcons(this.db); - - String? search(String sysVer) { - for (var item in db) { - if (sysVer.toLowerCase().contains(item)) { - return 'assets/linux/$item.png'; - } - } - return null; - } -} diff --git a/lib/view/page/apt.dart b/lib/view/page/apt.dart index e17bd317..0858a015 100644 --- a/lib/view/page/apt.dart +++ b/lib/view/page/apt.dart @@ -1,8 +1,8 @@ import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; -import 'package:toolbox/core/extension/stringx.dart'; import 'package:toolbox/core/utils.dart'; import 'package:toolbox/data/model/apt/upgrade_pkg_info.dart'; +import 'package:toolbox/data/model/server/dist.dart'; import 'package:toolbox/data/model/server/server_private_info.dart'; import 'package:toolbox/data/provider/apt.dart'; import 'package:toolbox/data/provider/server.dart'; @@ -68,7 +68,7 @@ class _AptManagePageState extends State onPwdRequest, widget.spi.user, ); - _aptProvider.refreshInstalled(); + _aptProvider.refresh(); } void onSubmitted() { diff --git a/lib/view/page/home.dart b/lib/view/page/home.dart index c9b029d1..22906591 100644 --- a/lib/view/page/home.dart +++ b/lib/view/page/home.dart @@ -11,7 +11,7 @@ import 'package:toolbox/data/provider/server.dart'; import 'package:toolbox/data/res/build_data.dart'; import 'package:toolbox/data/res/color.dart'; import 'package:toolbox/data/res/font_style.dart'; -import 'package:toolbox/data/res/icon/common.dart'; +import 'package:toolbox/data/res/icon.dart'; import 'package:toolbox/data/res/tab.dart'; import 'package:toolbox/data/res/url.dart'; import 'package:toolbox/data/store/setting.dart'; diff --git a/lib/view/page/server/detail.dart b/lib/view/page/server/detail.dart index 7b418256..a5684231 100644 --- a/lib/view/page/server/detail.dart +++ b/lib/view/page/server/detail.dart @@ -1,13 +1,13 @@ import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:toolbox/core/extension/numx.dart'; +import 'package:toolbox/data/model/server/dist.dart'; import 'package:toolbox/data/model/server/net_speed.dart'; import 'package:toolbox/data/model/server/server.dart'; import 'package:toolbox/data/model/server/server_status.dart'; import 'package:toolbox/data/provider/server.dart'; import 'package:toolbox/data/res/color.dart'; import 'package:toolbox/data/res/font_style.dart'; -import 'package:toolbox/data/res/icon/linux_icons.dart'; import 'package:toolbox/data/res/padding.dart'; import 'package:toolbox/generated/l10n.dart'; import 'package:toolbox/view/widget/round_rect_card.dart'; @@ -67,7 +67,7 @@ class _ServerDetailPageState extends State } Widget _buildLinuxIcon(String sysVer) { - final iconPath = linuxIcons.search(sysVer); + final iconPath = sysVer.dist?.iconPath; if (iconPath == null) return const SizedBox(); return ConstrainedBox( constraints: BoxConstraints(