repositories / termux-janitor
termux-janitor
Interactive cleanup assistant for Termux: transparent, safe, confirmed disk reclamation.
owned by admin
tools/janitor/model.zig
Raw// Termux Janitor product registries layered onto the generic engine graph.
const std = @import("std");
const engine = @import("engine");
const profile = @import("profile");
pub const limit_count_max = 128;
pub const cli_option_count_max = 32;
pub const cli_exit_status_count_max = 16;
pub const android_package_count_max = 32;
pub const classification_value_count_max = 128;
pub const threshold_count_max = 16;
pub const limits_path = "spec/model/limits.zon";
pub const cli_path = "spec/model/cli.zon";
pub const android_packages_path = "spec/model/android_packages.zon";
pub const classification_path = "spec/model/classification.zon";
pub const thresholds_path = "spec/model/thresholds.zon";
pub const package_path = "build.zig.zon";
/// The complete repository model: the generic relationship graph plus the
/// product-domain registries owned by this repository alone.
pub const Model = struct {
graph: engine.model.Graph,
limits: []const Limit,
cli: Cli,
android_packages: []const AndroidPackage,
classification: Classification,
thresholds: []const Threshold,
package: Package,
pub fn load(allocator: std.mem.Allocator, io: std.Io) !Model {
return .{
.graph = try engine.model.Graph.load(allocator, io),
.limits = try engine.model.parseFile(
[]const Limit,
allocator,
io,
limits_path,
),
.cli = try engine.model.parseFile(
Cli,
allocator,
io,
cli_path,
),
.android_packages = try engine.model.parseFile(
[]const AndroidPackage,
allocator,
io,
android_packages_path,
),
.classification = try engine.model.parseFile(
Classification,
allocator,
io,
classification_path,
),
.thresholds = try engine.model.parseFile(
[]const Threshold,
allocator,
io,
thresholds_path,
),
.package = try loadPackage(allocator, io),
};
}
};
/// The package manifest owns the one canonical version required by
/// `spec/ARTIFACT.md`. Unknown manifest fields belong to the Zig toolchain, so
/// this parse ignores them instead of duplicating the manifest schema.
pub const Package = struct {
version: []const u8,
};
fn loadPackage(allocator: std.mem.Allocator, io: std.Io) !Package {
const bytes = try std.Io.Dir.cwd().readFileAlloc(
io,
package_path,
allocator,
.limited(engine.model.file_size_max),
);
const source = try allocator.dupeZ(u8, bytes);
return std.zon.parse.fromSliceAlloc(
Package,
allocator,
source,
null,
.{ .ignore_unknown_fields = true, .free_on_error = true },
);
}
comptime {
std.debug.assert(profile.suiteIsConcrete(.u));
}
pub const AndroidPackage = struct {
id: []const u8,
revision: u32,
identifier: []const u8,
role: AndroidPackageRole,
requirement: engine.model.RequirementReference,
};
pub const AndroidPackageRole = enum {
base,
add_on,
};
pub const Classification = struct {
source_basenames: ClassificationSet,
source_suffixes: ClassificationSet,
document_roots: ClassificationSet,
};
pub const ClassificationSet = struct {
revision: u32,
values: []const []const u8,
requirement: engine.model.RequirementReference,
};
pub const Threshold = struct {
id: []const u8,
revision: u32,
key: []const u8,
value: u64,
unit: ThresholdUnit,
requirement: engine.model.RequirementReference,
};
pub const ThresholdUnit = enum {
bytes,
seconds,
};
pub const Limit = struct {
id: []const u8,
category: LimitCategory,
label: []const u8,
value: LimitValue,
};
pub const LimitCategory = enum {
scan,
process,
queue,
terminal,
logging,
};
pub const LimitValue = union(enum) {
scalar: ScalarLimit,
dimensions: DimensionsLimit,
alternative: AlternativeLimit,
};
pub const ScalarLimit = struct {
value: u64,
unit: LimitUnit,
};
pub const DimensionsLimit = struct {
columns: u16,
rows: u16,
};
pub const AlternativeLimit = struct {
items: u32,
milliseconds: u32,
};
pub const LimitUnit = enum {
bytes,
cells,
components,
count,
milliseconds,
minutes,
seconds,
};
pub const Cli = struct {
executable: []const u8,
description: []const u8,
default_mode: []const u8,
long_options_only: bool,
option_terminator: bool,
operands_allowed: bool,
duplicate_options_allowed: bool,
unattended_cleanup: bool,
informational_stream: OutputStream,
usage_stream: OutputStream,
diagnostic_stream: OutputStream,
options: []const CliOption,
argument_rules: []const CliArgumentRule,
exit_statuses: []const CliExitStatus,
};
pub const OutputStream = enum {
stdout,
stderr,
};
pub const CliOption = struct {
id: []const u8,
spelling: []const u8,
argument: CliArgument,
summary: []const u8,
must_appear_alone: bool,
bypasses_startup: []const StartupSubsystem,
requires_terminal: bool,
};
pub const StartupSubsystem = enum {
configuration,
logging,
terminal_initialization,
scanning,
};
pub const CliArgument = enum {
none,
path,
};
pub const CliArgumentRule = struct {
option: []const u8,
argument: []const u8,
arity: u8,
syntax: ArgumentSyntax,
nonempty: bool,
relative_base: RelativeBase,
};
pub const ArgumentSyntax = enum {
separate,
};
pub const RelativeBase = enum {
initial_working_directory,
};
pub const CliExitStatus = struct {
id: []const u8,
code: u8,
condition: []const u8,
};