fix: Detect broken Paru linked against old libalpm and repair via official repo/makepkg
This commit is contained in:
@@ -282,18 +282,6 @@ class CatalogService {
|
|||||||
rating: 4.95,
|
rating: 4.95,
|
||||||
votes: 1256,
|
votes: 1256,
|
||||||
),
|
),
|
||||||
CatalogApp(
|
|
||||||
id: 'paru-bin',
|
|
||||||
name: 'Paru (Binary)',
|
|
||||||
summary: 'Прекомпилированная бинарная версия AUR-хелпера Paru для быстрой установки без сборки.',
|
|
||||||
category: 'Утилиты',
|
|
||||||
backend: BackendType.aur,
|
|
||||||
iconUrl: _knownIconUrls['paru-bin'],
|
|
||||||
fallbackIcon: CupertinoIcons.flame_fill,
|
|
||||||
accentColor: const Color(0xFFFF9500),
|
|
||||||
rating: 4.9,
|
|
||||||
votes: 324,
|
|
||||||
),
|
|
||||||
CatalogApp(
|
CatalogApp(
|
||||||
id: 'com.usebottles.bottles',
|
id: 'com.usebottles.bottles',
|
||||||
name: 'Bottles',
|
name: 'Bottles',
|
||||||
|
|||||||
@@ -9,12 +9,16 @@ class SystemComponentStatus {
|
|||||||
final bool hasFlathub;
|
final bool hasFlathub;
|
||||||
final bool hasParu;
|
final bool hasParu;
|
||||||
final bool hasYay;
|
final bool hasYay;
|
||||||
|
final bool isParuBroken;
|
||||||
|
final String? paruBrokenReason;
|
||||||
|
|
||||||
const SystemComponentStatus({
|
const SystemComponentStatus({
|
||||||
required this.hasFlatpak,
|
required this.hasFlatpak,
|
||||||
required this.hasFlathub,
|
required this.hasFlathub,
|
||||||
required this.hasParu,
|
required this.hasParu,
|
||||||
required this.hasYay,
|
required this.hasYay,
|
||||||
|
this.isParuBroken = false,
|
||||||
|
this.paruBrokenReason,
|
||||||
});
|
});
|
||||||
|
|
||||||
bool get hasAurHelper => hasParu || hasYay;
|
bool get hasAurHelper => hasParu || hasYay;
|
||||||
@@ -27,6 +31,8 @@ class ComponentInstallerService {
|
|||||||
bool hasFlathub = false;
|
bool hasFlathub = false;
|
||||||
bool hasParu = false;
|
bool hasParu = false;
|
||||||
bool hasYay = false;
|
bool hasYay = false;
|
||||||
|
bool isParuBroken = false;
|
||||||
|
String? paruBrokenReason;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final res = await Process.run('which', ['flatpak']);
|
final res = await Process.run('which', ['flatpak']);
|
||||||
@@ -41,8 +47,17 @@ class ComponentInstallerService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
final whichRes = await Process.run('which', ['paru']);
|
||||||
|
final hasParuBinary = whichRes.exitCode == 0 && whichRes.stdout.toString().trim().isNotEmpty;
|
||||||
|
|
||||||
final res = await Process.run('paru', ['--version']);
|
final res = await Process.run('paru', ['--version']);
|
||||||
hasParu = res.exitCode == 0 && res.stdout.toString().toLowerCase().contains('paru');
|
if (res.exitCode == 0 && res.stdout.toString().toLowerCase().contains('paru')) {
|
||||||
|
hasParu = true;
|
||||||
|
} else if (hasParuBinary) {
|
||||||
|
isParuBroken = true;
|
||||||
|
final err = res.stderr.toString().trim();
|
||||||
|
paruBrokenReason = err.isNotEmpty ? err : 'Несовместимость библиотек libalpm';
|
||||||
|
}
|
||||||
} catch (_) {}
|
} catch (_) {}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -55,72 +70,53 @@ class ComponentInstallerService {
|
|||||||
hasFlathub: hasFlathub,
|
hasFlathub: hasFlathub,
|
||||||
hasParu: hasParu,
|
hasParu: hasParu,
|
||||||
hasYay: hasYay,
|
hasYay: hasYay,
|
||||||
|
isParuBroken: isParuBroken,
|
||||||
|
paruBrokenReason: paruBrokenReason,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Установка Flatpak и подключение репозитория Flathub
|
/// Установка Flatpak и подключение репозитория Flathub
|
||||||
static Stream<String> installFlatpak(String? password) async* {
|
static Stream<String> installFlatpak(String? password) async* {
|
||||||
yield '🚀 [Flatpak] Проверка и установка пакета flatpak через pacman...';
|
yield '🚀 [Flatpak] Начинаем установку Flatpak...';
|
||||||
|
|
||||||
// 1. Установка flatpak
|
// 1. Установка пакета flatpak через pacman
|
||||||
final proc = await AdminService.runPrivileged(
|
yield '📦 [Flatpak] Установка системного пакета flatpak...';
|
||||||
|
final pacmanProc = await AdminService.runPrivileged(
|
||||||
password,
|
password,
|
||||||
'pacman',
|
'pacman',
|
||||||
['-S', '--needed', '--noconfirm', 'flatpak'],
|
['-S', '--needed', '--noconfirm', 'flatpak'],
|
||||||
);
|
);
|
||||||
|
|
||||||
final controller = StreamController<String>();
|
final controller = StreamController<String>();
|
||||||
proc.stdout.transform(utf8.decoder).transform(const LineSplitter()).listen(
|
pacmanProc.stdout.transform(utf8.decoder).transform(const LineSplitter()).listen((l) => controller.add(l));
|
||||||
(line) => controller.add(line),
|
pacmanProc.stderr.transform(utf8.decoder).transform(const LineSplitter()).listen((l) => controller.add(l));
|
||||||
onError: (e) => controller.add('ERR: $e'),
|
pacmanProc.exitCode.then((_) => Future.delayed(const Duration(milliseconds: 50), () => controller.close()));
|
||||||
);
|
|
||||||
proc.stderr.transform(utf8.decoder).transform(const LineSplitter()).listen(
|
|
||||||
(line) => controller.add('STDERR: $line'),
|
|
||||||
onError: (e) => controller.add('ERR: $e'),
|
|
||||||
);
|
|
||||||
|
|
||||||
proc.exitCode.then((_) {
|
|
||||||
Future.delayed(const Duration(milliseconds: 60), () {
|
|
||||||
if (!controller.isClosed) controller.close();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
await for (final line in controller.stream) {
|
await for (final line in controller.stream) {
|
||||||
yield line;
|
yield line;
|
||||||
}
|
}
|
||||||
|
|
||||||
final code = await proc.exitCode;
|
final pacmanExit = await pacmanProc.exitCode;
|
||||||
if (code != 0) {
|
if (pacmanExit != 0) {
|
||||||
yield '❌ [Flatpak] Ошибка установки пакета flatpak (код $code).';
|
yield '❌ [Flatpak] Ошибка установки pacman (код $pacmanExit)';
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
yield '✅ [Flatpak] Пакет flatpak успешно установлен в систему.';
|
yield '✅ [Flatpak] Пакет flatpak установлен!';
|
||||||
yield '🌐 [Flathub] Подключение официального репозитория Flathub...';
|
|
||||||
|
|
||||||
// 2. Добавление репозитория Flathub
|
// 2. Подключение Flathub
|
||||||
try {
|
yield '🌐 [Flathub] Подключение репозитория Flathub...';
|
||||||
final remoteProc = await Process.run('flatpak', [
|
final flathubRes = await Process.run('flatpak', [
|
||||||
'remote-add',
|
'remote-add',
|
||||||
'--if-not-exists',
|
'--if-not-exists',
|
||||||
'flathub',
|
'flathub',
|
||||||
'https://dl.flathub.org/repo/flathub.flatpakrepo',
|
'https://dl.flathub.org/repo/flathub.flatpakrepo',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
if (remoteProc.exitCode == 0) {
|
if (flathubRes.exitCode == 0) {
|
||||||
yield '✅ [Flathub] Репозиторий Flathub успешно подключен!';
|
yield '✅ [Flathub] Репозиторий Flathub успешно добавлен!';
|
||||||
} else {
|
} else {
|
||||||
// Попытка с правами суперпользователя
|
yield '⚠️ [Flathub] Сообщение: ${flathubRes.stderr.toString().trim()}';
|
||||||
final rootRemote = await AdminService.runPrivileged(
|
|
||||||
password,
|
|
||||||
'flatpak',
|
|
||||||
['remote-add', '--if-not-exists', 'flathub', 'https://dl.flathub.org/repo/flathub.flatpakrepo'],
|
|
||||||
);
|
|
||||||
await rootRemote.exitCode;
|
|
||||||
yield '✅ [Flathub] Репозиторий Flathub подключен системно!';
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
yield '⚠️ [Flathub] Предупреждение при подключении репозитория: $e';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
yield '🎉 [Успех] Интеграция Flatpak & Flathub полностью готова!';
|
yield '🎉 [Успех] Интеграция Flatpak & Flathub полностью готова!';
|
||||||
@@ -128,15 +124,59 @@ class ComponentInstallerService {
|
|||||||
|
|
||||||
/// Установка AUR-хелпера Paru (Rust)
|
/// Установка AUR-хелпера Paru (Rust)
|
||||||
static Stream<String> installParu(String? password) async* {
|
static Stream<String> installParu(String? password) async* {
|
||||||
yield '🚀 [Paru] Начинаем установку Paru (AUR Helper на Rust)...';
|
yield '🚀 [Paru] Начинаем установку / восстановление Paru (AUR Helper на Rust)...';
|
||||||
|
|
||||||
// Если уже есть yay, ставим paru-bin через него
|
// 1. Проверяем наличие paru в официальных/дистрибутивных репозиториях pacman (EndeavourOS, Chaotic-AUR и т.д.)
|
||||||
|
bool inPacman = false;
|
||||||
|
try {
|
||||||
|
final chk = await Process.run('pacman', ['-Si', 'paru']);
|
||||||
|
inPacman = chk.exitCode == 0;
|
||||||
|
} catch (_) {}
|
||||||
|
|
||||||
|
if (inPacman) {
|
||||||
|
yield '📦 [Paru] Обнаружен нативный пакет paru в репозитории системы! Устанавливаем через pacman...';
|
||||||
|
try {
|
||||||
|
final pacmanProc = await AdminService.runPrivileged(
|
||||||
|
password,
|
||||||
|
'pacman',
|
||||||
|
['-S', '--noconfirm', 'paru'],
|
||||||
|
);
|
||||||
|
|
||||||
|
final controller = StreamController<String>();
|
||||||
|
pacmanProc.stdout.transform(utf8.decoder).transform(const LineSplitter()).listen((l) => controller.add(l));
|
||||||
|
pacmanProc.stderr.transform(utf8.decoder).transform(const LineSplitter()).listen((l) => controller.add(l));
|
||||||
|
pacmanProc.exitCode.then((_) => Future.delayed(const Duration(milliseconds: 50), () => controller.close()));
|
||||||
|
|
||||||
|
await for (final line in controller.stream) {
|
||||||
|
yield line;
|
||||||
|
}
|
||||||
|
|
||||||
|
final exitCode = await pacmanProc.exitCode;
|
||||||
|
if (exitCode == 0) {
|
||||||
|
final verify = await Process.run('paru', ['--version']);
|
||||||
|
if (verify.exitCode == 0) {
|
||||||
|
AurService.resetCache();
|
||||||
|
yield '🎉 [Paru] Paru успешно установлен и проверен (${verify.stdout.toString().trim()})!';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
yield '⚠️ [Paru] Установка через pacman не сработала (код $exitCode), переходим к сборке...';
|
||||||
|
} catch (e) {
|
||||||
|
yield '⚠️ [Paru] Ошибка pacman: $e';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Если есть рабочий yay, собираем нативный paru через yay (НЕ paru-bin!)
|
||||||
final status = await checkComponents();
|
final status = await checkComponents();
|
||||||
if (status.hasYay) {
|
if (status.hasYay) {
|
||||||
yield '📦 [Paru] Обнаружен yay! Устанавливаем paru-bin через yay...';
|
yield '📦 [Paru] Обнаружен yay! Сборка и установка нативного paru через yay...';
|
||||||
|
if (password != null && password.isNotEmpty) {
|
||||||
|
await AdminService.verifyPassword(password);
|
||||||
|
}
|
||||||
|
|
||||||
final proc = await Process.start(
|
final proc = await Process.start(
|
||||||
'yay',
|
'yay',
|
||||||
['-S', '--noconfirm', 'paru-bin'],
|
['-S', '--noconfirm', 'paru'],
|
||||||
environment: {'LC_ALL': 'C'},
|
environment: {'LC_ALL': 'C'},
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -162,38 +202,22 @@ class ComponentInstallerService {
|
|||||||
|
|
||||||
final exitCode = await proc.exitCode;
|
final exitCode = await proc.exitCode;
|
||||||
if (exitCode == 0) {
|
if (exitCode == 0) {
|
||||||
AurService.resetCache();
|
final verify = await Process.run('paru', ['--version']);
|
||||||
yield '🎉 [Paru] Paru успешно установлен и готов к работе!';
|
if (verify.exitCode == 0) {
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
yield '⚠️ [Paru] Не удалось установить через yay (код $exitCode), пробуем сборку из исходников paru...';
|
|
||||||
final procSrc = await Process.start(
|
|
||||||
'yay',
|
|
||||||
['-S', '--noconfirm', 'paru'],
|
|
||||||
environment: {'LC_ALL': 'C'},
|
|
||||||
);
|
|
||||||
final srcCtrl = StreamController<String>();
|
|
||||||
procSrc.stdout.transform(utf8.decoder).transform(const LineSplitter()).listen((l) => srcCtrl.add(l));
|
|
||||||
procSrc.stderr.transform(utf8.decoder).transform(const LineSplitter()).listen((l) => srcCtrl.add(l));
|
|
||||||
procSrc.exitCode.then((_) => Future.delayed(const Duration(milliseconds: 50), () => srcCtrl.close()));
|
|
||||||
await for (final l in srcCtrl.stream) {
|
|
||||||
yield l;
|
|
||||||
}
|
|
||||||
final srcExit = await procSrc.exitCode;
|
|
||||||
if (srcExit == 0) {
|
|
||||||
AurService.resetCache();
|
AurService.resetCache();
|
||||||
yield '🎉 [Paru] Paru успешно скомпилирован и установлен!';
|
yield '🎉 [Paru] Paru успешно скомпилирован и готов к работе (${verify.stdout.toString().trim()})!';
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
yield '⚠️ [Paru] Установка через yay завершилась с кодом $exitCode, пробуем makepkg...';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ручная установка paru-bin через makepkg
|
// 3. Ручная сборка исходников paru через makepkg
|
||||||
yield '🛠️ [Paru] Проверка базовых инструментов сборки (base-devel, git)...';
|
yield '🛠️ [Paru] Проверка базовых инструментов сборки (base-devel, git, cargo)...';
|
||||||
final pacmanProc = await AdminService.runPrivileged(
|
final pacmanProc = await AdminService.runPrivileged(
|
||||||
password,
|
password,
|
||||||
'pacman',
|
'pacman',
|
||||||
['-S', '--needed', '--noconfirm', 'base-devel', 'git'],
|
['-S', '--needed', '--noconfirm', 'base-devel', 'git', 'cargo'],
|
||||||
);
|
);
|
||||||
await pacmanProc.exitCode;
|
await pacmanProc.exitCode;
|
||||||
|
|
||||||
@@ -205,12 +229,12 @@ class ComponentInstallerService {
|
|||||||
Directory? tempDir;
|
Directory? tempDir;
|
||||||
try {
|
try {
|
||||||
tempDir = Directory.systemTemp.createTempSync('forge_paru_install_');
|
tempDir = Directory.systemTemp.createTempSync('forge_paru_install_');
|
||||||
yield '📥 [Paru] Клонирование paru-bin из AUR...';
|
yield '📥 [Paru] Клонирование исходников paru из AUR...';
|
||||||
|
|
||||||
final cloneRes = await Process.run('git', [
|
final cloneRes = await Process.run('git', [
|
||||||
'clone',
|
'clone',
|
||||||
'https://aur.archlinux.org/paru-bin.git',
|
'https://aur.archlinux.org/paru.git',
|
||||||
'${tempDir.path}/paru-bin',
|
'${tempDir.path}/paru',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
if (cloneRes.exitCode != 0) {
|
if (cloneRes.exitCode != 0) {
|
||||||
@@ -218,11 +242,11 @@ class ComponentInstallerService {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
yield '⚙️ [Paru] Сборка и установка пакета (makepkg -si)...';
|
yield '⚙️ [Paru] Сборка и установка пакета через makepkg -si...';
|
||||||
final makepkgProc = await Process.start(
|
final makepkgProc = await Process.start(
|
||||||
'makepkg',
|
'makepkg',
|
||||||
['-si', '--noconfirm'],
|
['-si', '--noconfirm'],
|
||||||
workingDirectory: '${tempDir.path}/paru-bin',
|
workingDirectory: '${tempDir.path}/paru',
|
||||||
environment: {'LC_ALL': 'C'},
|
environment: {'LC_ALL': 'C'},
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -248,7 +272,13 @@ class ComponentInstallerService {
|
|||||||
|
|
||||||
final exitCode = await makepkgProc.exitCode;
|
final exitCode = await makepkgProc.exitCode;
|
||||||
if (exitCode == 0) {
|
if (exitCode == 0) {
|
||||||
yield '🎉 [Paru] Paru успешно собран и установлен в систему!';
|
final verify = await Process.run('paru', ['--version']);
|
||||||
|
if (verify.exitCode == 0) {
|
||||||
|
AurService.resetCache();
|
||||||
|
yield '🎉 [Paru] Paru успешно собран и установлен в систему!';
|
||||||
|
} else {
|
||||||
|
yield '❌ [Paru] Пакет установлен, но не может запуститься: ${verify.stderr}';
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
yield '❌ [Paru] makepkg завершился с кодом ошибки $exitCode.';
|
yield '❌ [Paru] makepkg завершился с кодом ошибки $exitCode.';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -438,28 +438,41 @@ class _SettingsScreenState extends State<SettingsScreen> {
|
|||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: (_componentStatus?.hasParu ?? false)
|
color: (_componentStatus?.hasParu ?? false)
|
||||||
? CupertinoColors.systemGreen.withValues(alpha: 0.15)
|
? CupertinoColors.systemGreen.withValues(alpha: 0.15)
|
||||||
: CupertinoColors.systemGrey.withValues(alpha: 0.15),
|
: ((_componentStatus?.isParuBroken ?? false)
|
||||||
|
? CupertinoColors.systemRed.withValues(alpha: 0.15)
|
||||||
|
: CupertinoColors.systemGrey.withValues(alpha: 0.15)),
|
||||||
borderRadius: BorderRadius.circular(4),
|
borderRadius: BorderRadius.circular(4),
|
||||||
),
|
),
|
||||||
child: Text(
|
child: Text(
|
||||||
(_componentStatus?.hasParu ?? false)
|
(_componentStatus?.hasParu ?? false)
|
||||||
? 'Paru активен'
|
? 'Paru активен'
|
||||||
: ((_componentStatus?.hasYay ?? false) ? 'Обнаружен yay' : 'Отсутствует'),
|
: ((_componentStatus?.isParuBroken ?? false)
|
||||||
|
? 'Повреждён (libalpm)'
|
||||||
|
: ((_componentStatus?.hasYay ?? false) ? 'Обнаружен yay' : 'Отсутствует')),
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 10.5,
|
fontSize: 10.5,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
color: (_componentStatus?.hasParu ?? false)
|
color: (_componentStatus?.hasParu ?? false)
|
||||||
? CupertinoColors.systemGreen
|
? CupertinoColors.systemGreen
|
||||||
: CupertinoColors.systemGrey,
|
: ((_componentStatus?.isParuBroken ?? false)
|
||||||
|
? CupertinoColors.systemRed
|
||||||
|
: CupertinoColors.systemGrey),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
const SizedBox(height: 2),
|
const SizedBox(height: 2),
|
||||||
const Text(
|
Text(
|
||||||
'Сверхбыстрый сборщик пакетов из Arch User Repository',
|
(_componentStatus?.isParuBroken ?? false)
|
||||||
style: TextStyle(fontSize: 12, color: CupertinoColors.systemGrey),
|
? '⚠️ Paru поврежден (несовместимость libalpm в Arch). Нажмите «Исправить».'
|
||||||
|
: 'Сверхбыстрый сборщик пакетов из Arch User Repository',
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 12,
|
||||||
|
color: (_componentStatus?.isParuBroken ?? false)
|
||||||
|
? CupertinoColors.systemRed
|
||||||
|
: CupertinoColors.systemGrey,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@@ -471,7 +484,9 @@ class _SettingsScreenState extends State<SettingsScreen> {
|
|||||||
await SetupWizardDialog.show(context);
|
await SetupWizardDialog.show(context);
|
||||||
_loadSettings();
|
_loadSettings();
|
||||||
},
|
},
|
||||||
child: Text((_componentStatus?.hasParu ?? false) ? 'Переустановить' : 'Установить Paru'),
|
child: Text((_componentStatus?.hasParu ?? false)
|
||||||
|
? 'Переустановить'
|
||||||
|
: ((_componentStatus?.isParuBroken ?? false) ? 'Исправить Paru' : 'Установить Paru')),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -256,16 +256,22 @@ class _SetupWizardDialogState extends State<SetupWizardDialog> {
|
|||||||
icon: CupertinoIcons.flame_fill,
|
icon: CupertinoIcons.flame_fill,
|
||||||
iconColor: const Color(0xFFFF9500),
|
iconColor: const Color(0xFFFF9500),
|
||||||
title: 'AUR и Paru (Rust AUR Helper)',
|
title: 'AUR и Paru (Rust AUR Helper)',
|
||||||
subtitle: 'Сборка пакетов сообщества из Arch User Repository с максимальной скоростью',
|
subtitle: (_status?.isParuBroken ?? false)
|
||||||
|
? '⚠️ Paru поврежден: не запускается из-за смены libalpm в Arch. Нажмите «Исправить»'
|
||||||
|
: 'Сборка пакетов сообщества из Arch User Repository с максимальной скоростью',
|
||||||
statusText: (_status?.hasParu ?? false)
|
statusText: (_status?.hasParu ?? false)
|
||||||
? 'Paru установлен (активен)'
|
? 'Paru установлен (активен)'
|
||||||
: ((_status?.hasYay ?? false) ? 'Обнаружен yay (Paru не установлен)' : 'AUR-хелпер отсутствует'),
|
: ((_status?.isParuBroken ?? false)
|
||||||
isInstalled: (_status?.hasParu ?? false) || (_status?.hasYay ?? false),
|
? 'Повреждён (libalpm)'
|
||||||
|
: ((_status?.hasYay ?? false) ? 'Обнаружен yay (Paru не установлен)' : 'AUR-хелпер отсутствует')),
|
||||||
|
isInstalled: _status?.hasParu ?? false,
|
||||||
actionButton: PushButton(
|
actionButton: PushButton(
|
||||||
controlSize: ControlSize.small,
|
controlSize: ControlSize.small,
|
||||||
secondary: _status?.hasParu ?? false,
|
secondary: _status?.hasParu ?? false,
|
||||||
onPressed: _isInstalling ? null : _installParu,
|
onPressed: _isInstalling ? null : _installParu,
|
||||||
child: Text((_status?.hasParu ?? false) ? 'Переустановить Paru' : 'Установить Paru'),
|
child: Text((_status?.hasParu ?? false)
|
||||||
|
? 'Переустановить Paru'
|
||||||
|
: ((_status?.isParuBroken ?? false) ? 'Исправить Paru' : 'Установить Paru')),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user