rpm-ostree/ostree only retain a couple of deployments, so there's no durable record of what's been layered since the stock image. Add a local history DB (lib/history/) keyed on the ostree deployment checksum, with a parent pointer forming a tree, plus named "current" and "last_known_safe" pointers. Reconciling against live `rpm-ostree status --json` on every launch means the history stays correct even across manual rpm-ostree/bootc changes made outside this app: any booted checksum we don't recognize gets recorded as a "detected" node rather than silently ignored. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
55 lines
1.6 KiB
Dart
55 lines
1.6 KiB
Dart
import 'package:flutter/material.dart';
|
|
|
|
import 'confirmation_marker.dart';
|
|
import 'confirmation_page.dart';
|
|
import 'history/history_service.dart';
|
|
import 'wizard_page.dart';
|
|
|
|
void main() {
|
|
runApp(const LayerWizardApp());
|
|
}
|
|
|
|
class LayerWizardApp extends StatelessWidget {
|
|
const LayerWizardApp({super.key});
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return MaterialApp(
|
|
title: 'Layer Wizard',
|
|
theme: ThemeData(colorSchemeSeed: Colors.teal, useMaterial3: true),
|
|
home: const _StartupRouter(),
|
|
);
|
|
}
|
|
}
|
|
|
|
/// Checks for a pending post-reboot confirmation before deciding which
|
|
/// screen to show first.
|
|
class _StartupRouter extends StatelessWidget {
|
|
const _StartupRouter();
|
|
|
|
/// Reconciles our layer history against the live `rpm-ostree status`
|
|
/// before anything else — catches rollbacks, reboots into our own
|
|
/// installs, and any manual changes made outside the app — then checks
|
|
/// for a pending post-reboot confirmation.
|
|
Future<PendingConfirmation?> _startup() async {
|
|
await HistoryService.instance.reconcile();
|
|
return ConfirmationMarker.read();
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return FutureBuilder<PendingConfirmation?>(
|
|
future: _startup(),
|
|
builder: (context, snapshot) {
|
|
if (snapshot.connectionState != ConnectionState.done) {
|
|
return const Scaffold(body: Center(child: CircularProgressIndicator()));
|
|
}
|
|
final pending = snapshot.data;
|
|
if (pending != null) {
|
|
return ConfirmationPage(pending: pending);
|
|
}
|
|
return const WizardHomePage();
|
|
},
|
|
);
|
|
}
|
|
}
|