1mod commands;
2mod detect;
3mod execution;
4mod managed;
5#[cfg(test)]
6mod manifest;
7mod model;
8mod profile_commands;
9mod recovery;
10mod render;
11mod run_manifest;
12mod selection;
13
14#[cfg(test)]
15use model::SysInstalledRow;
16use model::{
17 LoadedSysPreset, ResolvedSelection, SysDetection, SysDetectionProbe, SysDriverKind, SysInstall,
18 SysItem, SysItemMode, SysItemOutcome, SysItemStatus, SysPackageProvider, SysUpdateRow,
19 SysUpgradeReport,
20};
21
22use anyhow::{Context, Result};
23
24pub use commands::{handle_info, handle_init, handle_list, handle_status};
25pub use detect::detect_os_id;
26pub use managed::{
27 handle_apply, handle_apply_approved, handle_uninstall, handle_uninstall_approved,
28 handle_upgrade_managed, handle_upgrade_managed_target, managed_updates,
29};
30pub(crate) use managed::{
31 handle_upgrade_managed_target_with_result_approved, handle_upgrade_managed_with_result_prepared,
32};
33pub use profile_commands::{
34 handle_profile_disable, handle_profile_disable_approved, handle_profile_enable,
35 handle_profile_enable_approved,
36};
37pub use recovery::handle_recover_approved;
38
39const SYS_TEMPLATE: &str = r#"# System bootstrap preset metadata for shine (schema v2).
40version = 2
41description = "My system bootstrap."
42default_profile = "recommended"
43
44[[items]]
45id = "my-tool"
46label = "My Tool"
47description = "Install and configure my tool."
48default = true
49detect = { kind = "command", command = "my-tool", version_args = ["--version"] }
50# Keep scripts inside this category. For Windows, use a .ps1 script instead.
51install = { kind = "script", path = "install/my-tool.sh" }
52
53[items.permissions]
54schema_version = 1
55filesystem = [{ access = ["execute"], base = "preset", path = "install/my-tool.sh" }]
56# Add reviewed command, network, administrator, environment, and system identities used by the script.
57
58[profiles.recommended]
59items = ["my-tool"]
60"#;
61
62pub async fn handle_init_template(force: bool) -> Result<()> {
63 let dir = std::env::current_dir().context("reading current directory")?;
64 let (path, overwritten) =
65 shine_core::init_template::write_shine_toml_template(&dir, force, SYS_TEMPLATE)?;
66 if overwritten {
67 println!("Updated sys preset template: {}", path.display());
68 } else {
69 println!("Created sys preset template: {}", path.display());
70 }
71 Ok(())
72}
73
74#[cfg(test)]
75mod tests {
76 use super::*;
77
78 #[test]
79 fn init_template_contains_valid_permission_declaration() {
80 let manifest = manifest::parse_and_validate_manifest(SYS_TEMPLATE).unwrap();
81
82 assert_eq!(manifest.items.len(), 1);
83 assert_eq!(
84 manifest.items[0]
85 .permissions
86 .as_ref()
87 .map(|permissions| permissions.schema_version),
88 Some(1)
89 );
90 }
91}