This commit is contained in:
JMARyA 2025-05-14 12:43:32 +02:00
parent 31110447da
commit 5f56b7fb77
Signed by: jmarya
GPG key ID: 901B2ADDF27C2263
23 changed files with 555 additions and 352 deletions

219
Cargo.lock generated
View file

@ -3,53 +3,35 @@
version = 4
[[package]]
name = "anstream"
version = "0.6.18"
name = "argh"
version = "0.1.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b"
checksum = "34ff18325c8a36b82f992e533ece1ec9f9a9db446bd1c14d4f936bac88fcd240"
dependencies = [
"anstyle",
"anstyle-parse",
"anstyle-query",
"anstyle-wincon",
"colorchoice",
"is_terminal_polyfill",
"utf8parse",
"argh_derive",
"argh_shared",
"rust-fuzzy-search",
]
[[package]]
name = "anstyle"
version = "1.0.10"
name = "argh_derive"
version = "0.1.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9"
[[package]]
name = "anstyle-parse"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9"
checksum = "adb7b2b83a50d329d5d8ccc620f5c7064028828538bdf5646acd60dc1f767803"
dependencies = [
"utf8parse",
"argh_shared",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "anstyle-query"
version = "1.1.2"
name = "argh_shared"
version = "0.1.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c"
checksum = "a464143cc82dedcdc3928737445362466b7674b5db4e2eb8e869846d6d84f4f6"
dependencies = [
"windows-sys",
]
[[package]]
name = "anstyle-wincon"
version = "3.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e"
dependencies = [
"anstyle",
"once_cell",
"windows-sys",
"serde",
]
[[package]]
@ -70,39 +52,6 @@ version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
[[package]]
name = "clap"
version = "4.5.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6088f3ae8c3608d19260cd7445411865a485688711b78b5be70d78cd96136f83"
dependencies = [
"clap_builder",
]
[[package]]
name = "clap_builder"
version = "4.5.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22a7ef7f676155edfb82daa97f99441f3ebf4a58d5e32f295a56259f1b6facc8"
dependencies = [
"anstream",
"anstyle",
"clap_lex",
"strsim",
]
[[package]]
name = "clap_lex"
version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6"
[[package]]
name = "colorchoice"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990"
[[package]]
name = "equivalent"
version = "1.0.2"
@ -115,6 +64,12 @@ version = "0.15.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289"
[[package]]
name = "heck"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
[[package]]
name = "indexmap"
version = "2.8.0"
@ -125,12 +80,6 @@ dependencies = [
"hashbrown",
]
[[package]]
name = "is_terminal_polyfill"
version = "1.70.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
[[package]]
name = "itoa"
version = "1.0.15"
@ -153,10 +102,11 @@ checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
name = "navinstall"
version = "0.1.0"
dependencies = [
"clap",
"argh",
"nix",
"serde",
"serde_json",
"strum",
"toml",
"yansi",
]
@ -173,12 +123,6 @@ dependencies = [
"libc",
]
[[package]]
name = "once_cell"
version = "1.21.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d75b0bedcc4fe52caa0e03d9f1151a323e4aa5e2d78ba3580400cd3c9e2bc4bc"
[[package]]
name = "proc-macro2"
version = "1.0.94"
@ -197,6 +141,18 @@ dependencies = [
"proc-macro2",
]
[[package]]
name = "rust-fuzzy-search"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a157657054ffe556d8858504af8a672a054a6e0bd9e8ee531059100c0fa11bb2"
[[package]]
name = "rustversion"
version = "1.0.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2"
[[package]]
name = "ryu"
version = "1.0.20"
@ -245,10 +201,26 @@ dependencies = [
]
[[package]]
name = "strsim"
version = "0.11.1"
name = "strum"
version = "0.27.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
checksum = "f64def088c51c9510a8579e3c5d67c65349dcf755e5479ad3d010aa6454e2c32"
dependencies = [
"strum_macros",
]
[[package]]
name = "strum_macros"
version = "0.27.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c77a8c5abcaf0f9ce05d62342b7d298c346515365c36b673df4ebe3ced01fde8"
dependencies = [
"heck",
"proc-macro2",
"quote",
"rustversion",
"syn",
]
[[package]]
name = "syn"
@ -301,85 +273,6 @@ version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
[[package]]
name = "utf8parse"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
[[package]]
name = "windows-sys"
version = "0.59.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
dependencies = [
"windows-targets",
]
[[package]]
name = "windows-targets"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_gnullvm",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
[[package]]
name = "windows_aarch64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
[[package]]
name = "windows_i686_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
[[package]]
name = "windows_i686_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
[[package]]
name = "windows_i686_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
[[package]]
name = "windows_x86_64_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
[[package]]
name = "windows_x86_64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
[[package]]
name = "winnow"
version = "0.7.4"

View file

@ -8,9 +8,10 @@ name = "navinstall"
path = "src/main.rs"
[dependencies]
clap = { version = "4.5.23", features = ["cargo"] }
argh = "0.1.13"
nix = { version = "0.29.0", features = ["user"] }
serde = { version = "1.0.216", features = ["derive"] }
serde_json = "1.0.135"
strum = { version = "0.27.1", features = ["derive", "strum_macros"] }
toml = "0.8.19"
yansi = "1.0.1"

View file

@ -1,41 +1,108 @@
use clap::{ArgAction, arg, command};
use argh::FromArgs;
pub fn get_args() -> clap::ArgMatches {
command!()
.about("navOS Installer")
.subcommand(
command!("create-iso")
.about("Create a new installation medium ISO")
.arg(arg!(--without_gui "Create ISO with just terminal"))
.arg(arg!(--no_tmp "Create ISO on disk"))
.arg(arg!(--kb_layout <LAYOUT> "Create ISO with this keyboard layout"))
.arg(arg!(--kb_variant <VARIANT> "Create ISO with this keyboard layout variant"))
.arg(arg!(--user <USER> "Change the system user"))
.arg(arg!(--pass <PASS> "Change the system users password"))
.arg(arg!(--uid <UID> "Change the system users UID"))
.arg(arg!(--unit <UNIT> "Include a systemd unit").action(ArgAction::Append))
.arg(arg!(--install <CONFIG> "Create ISO which automatically installs <CONFIG> upon boot."))
)
.subcommand(
command!()
.name("install")
.about("Install a system according to configuration")
.arg(arg!(-f --force "Install without confirming config"))
.arg(arg!([config] "Config file").required(true)),
)
.subcommand(
command!()
.name("create-tar")
.arg(arg!([dir] "root fs dir").required(true))
.about("Create a container tar image"),
)
.subcommand(
command!()
.name("create-img")
.about("Create an install on a disk image for VMs or embedded devices")
.arg(arg!(--gpt "Use modern disk format"))
.arg(arg!([config] "Config file").required(true))
.arg(arg!([image] "Image file").required(true))
)
.get_matches()
use crate::fx::Features;
#[derive(FromArgs)]
/// navOS Installer
pub struct NavinstallArgs {
#[argh(subcommand)]
pub cmd: NavinstallCommands,
}
#[derive(FromArgs)]
#[argh(subcommand)]
pub enum NavinstallCommands {
CreateISO(CreateISOCommand),
Install(InstallCommand),
CreateTar(CreateTarCommand),
CreateImage(CreateImageCommand),
Feature(FeatureCommand),
}
#[derive(FromArgs)]
#[argh(subcommand, name = "create-iso")]
/// Create a new installation medium ISO
pub struct CreateISOCommand {
#[argh(switch)]
/// create ISO with just terminal
pub without_gui: bool,
#[argh(switch)]
/// create ISO on disk
pub no_tmp: bool,
#[argh(option)]
/// create ISO with this keyboard layout
pub kb_layout: Option<String>,
#[argh(option)]
/// create ISO with this keyboard layout variant
pub kb_variant: Option<String>,
#[argh(option)]
/// change the system user
pub user: Option<String>,
#[argh(option)]
/// change the system users password
pub pass: Option<String>,
#[argh(option)]
/// change the system user UID
pub uid: Option<u16>,
#[argh(option)]
/// include a systemd unit
pub unit: Vec<String>,
#[argh(option)]
/// create ISO which automatically installs <CONFIG> upon boot.
pub install: Option<String>,
}
#[derive(FromArgs)]
#[argh(subcommand, name = "install")]
/// Install a system according to configuration
pub struct InstallCommand {
#[argh(switch, short = 'f')]
/// install without confirming config
pub force: bool,
#[argh(positional)]
/// config file
pub config: String,
}
#[derive(FromArgs)]
#[argh(subcommand, name = "create-tar")]
/// Create a container rootfs
pub struct CreateTarCommand {
#[argh(positional)]
/// rootfs dir
pub dir: String,
}
#[derive(FromArgs)]
#[argh(subcommand, name = "create-img")]
/// Create an install on a disk image for VMs or embedded devices
pub struct CreateImageCommand {
#[argh(switch)]
/// use modern disk format
pub gpt: bool,
#[argh(positional)]
/// config file
pub config: String,
#[argh(positional)]
/// image file
pub image: String,
}
#[derive(FromArgs)]
#[argh(subcommand, name = "fx")]
/// Enable or disable features
pub struct FeatureCommand {
#[argh(subcommand)]
pub cmd: Features,
}

View file

@ -123,8 +123,10 @@ pub struct GeneralConfig {
pub secure_boot: Option<bool>,
}
#[derive(Debug, Clone, Deserialize)]
#[derive(Debug, Clone, Deserialize, Default)]
pub enum GPUVendor {
#[default]
NONE,
AMD,
NVIDIA,
INTEL,

View file

@ -5,7 +5,7 @@ use yansi::{Color, Paint};
use crate::{expect_yes, install::uncomment_tag, linux::is_root, linux::run_command, print_status};
/// Build the `kxkbrc` file for the given `layout` and `variant
pub fn build_kxkbrc(layout: &str, variant: Option<&str>) -> String {
pub fn build_kxkbrc(layout: &str, variant: Option<String>) -> String {
let mut res = String::from("[Layout]\nUse=true\n");
res.push_str(&format!("LayoutList={layout}\n"));
if let Some(variant) = variant {
@ -19,10 +19,10 @@ pub fn create_iso(
without_gui: bool,
no_tmp: bool,
kb_layout: &str,
kb_variant: Option<&str>,
kb_variant: Option<String>,
user: Option<(String, String, u16)>,
systemd_units: Vec<String>,
install: Option<&String>,
install: Option<String>,
) {
if !is_root() {
eprintln!("Error: You need root to create an ISO");

View file

@ -1,5 +1,12 @@
use argh::FromArgs;
use crate::{linux::systemd_service_enable, pkg::install_pkgs, print_status};
#[derive(FromArgs)]
#[argh(subcommand, name = "bluetooth")]
/// Enable Bluetooth support
pub struct BluetoothFeature {}
/// Enable Bluetooth
pub fn setup_bluetooth() {
print_status("Setting up Bluetooth");

32
src/fx/docker.rs Normal file
View file

@ -0,0 +1,32 @@
use argh::FromArgs;
use crate::{
linux::{arch_chroot, systemd_service_enable},
pkg::install_pkgs,
print_status,
};
#[derive(FromArgs)]
#[argh(subcommand, name = "docker")]
/// Enable docker
pub struct DockerFeature {
#[argh(positional)]
/// assign user to docker group
pub user: Vec<String>,
}
/// Setup docker on the system
pub fn setup_docker(conf: &[String]) {
print_status("Setting up Docker");
install_pkgs(&["docker", "docker-compose"]);
systemd_service_enable("docker.service");
for user in conf {
arch_chroot(
&vec!["usermod", "-a", "-G", "docker", user.as_str()],
None,
false,
);
}
}

View file

@ -1,9 +1,20 @@
use argh::FromArgs;
use crate::{
linux::{arch_chroot, systemd_service_enable},
pkg::install_pkgs,
print_status,
};
#[derive(FromArgs)]
#[argh(subcommand, name = "firewall")]
/// Install firewall
pub struct FirewallFeature {
#[argh(switch)]
/// allow SSH
pub ssh: bool,
}
/// Setup UFW
pub fn setup_firewall(ssh: bool) {
print_status("Enabling firewall");

View file

@ -1,5 +1,16 @@
use argh::FromArgs;
use crate::{config::GPUVendor, pkg::install_pkgs};
#[derive(FromArgs)]
#[argh(subcommand, name = "gpu")]
/// Install GPU drivers
pub struct GPUFeature {
#[argh(positional)]
/// GPU vendor
pub vendor: String,
}
/// Setup GPU video drivers
pub fn setup_video_drivers(vendor: &GPUVendor) {
match vendor {
@ -24,5 +35,6 @@ pub fn setup_video_drivers(vendor: &GPUVendor) {
"lib32-vulkan-intel",
]);
}
GPUVendor::NONE => {}
}
}

73
src/fx/mod.rs Normal file
View file

@ -0,0 +1,73 @@
use argh::FromArgs;
use bluetooth::BluetoothFeature;
use docker::DockerFeature;
use firewall::FirewallFeature;
use gpu::GPUFeature;
use ollama::OllamaFeature;
use ssh::SSHFeature;
use virt::{VirtFeature, VirtGuestFeature};
use zram::ZramFeature;
pub mod bluetooth;
pub mod docker;
pub mod firewall;
pub mod gpu;
pub mod ollama;
pub mod ssh;
pub mod virt;
pub mod zram;
pub struct OptionSet {
values: Vec<(String, String)>,
}
impl OptionSet {
pub fn new(values: Vec<String>) -> Self {
Self {
values: values
.into_iter()
.map(|x| {
let s = x.split_once('=').unwrap();
(s.0.to_owned(), s.1.to_owned())
})
.collect(),
}
}
pub fn get(&self, key: &str) -> Option<&String> {
self.values.iter().find(|x| x.0 == key).map(|x| &x.1)
}
pub fn get_many(&self, key: &str) -> Vec<String> {
self.values
.iter()
.filter_map(|x| if x.0 == key { Some(x.1.clone()) } else { None })
.collect()
}
pub fn get_flag(&self, key: &str) -> Option<bool> {
if let Some(val) = self.get(key) {
if val == "true" || val == "1" {
return Some(true);
} else {
return Some(false);
}
}
None
}
}
#[derive(FromArgs)]
#[argh(subcommand)]
pub enum Features {
Bluetooth(BluetoothFeature),
GPU(GPUFeature),
Docker(DockerFeature),
Firewall(FirewallFeature),
Ollama(OllamaFeature),
SSH(SSHFeature),
Virt(VirtFeature),
VirtGuest(VirtGuestFeature),
Zram(ZramFeature),
}

View file

@ -1,5 +1,7 @@
use std::time::Duration;
use argh::FromArgs;
use crate::{
config::OllamaConfig,
linux::{arch_chroot, systemd_service_enable},
@ -7,6 +9,28 @@ use crate::{
print_status,
};
#[derive(FromArgs)]
#[argh(subcommand, name = "ollama")]
/// Enable ollama AI
pub struct OllamaFeature {
#[argh(option)]
/// pull model
pub model: Vec<String>,
#[argh(switch)]
/// enable CUDA
pub gpu: bool,
}
impl OllamaFeature {
pub fn into_config(self) -> OllamaConfig {
OllamaConfig {
models: Some(self.model),
gpu: self.gpu,
}
}
}
/// Setup Ollama AI Service
pub fn setup_ollama(conf: &OllamaConfig) {
if conf.gpu {

View file

@ -1,11 +1,50 @@
use argh::FromArgs;
use crate::{
config::SSHConfig,
config::{SSHConfig, SSHKey},
linux::{install_file, systemd_service_enable},
pkg::install_pkgs,
print_status,
};
use std::io::Write;
#[derive(FromArgs)]
#[argh(subcommand, name = "ssh")]
/// Enable SSH
pub struct SSHFeature {
#[argh(option)]
/// copy sshd config
pub sshd: Option<String>,
#[argh(option)]
/// add SSH key in the format 'user1,user2:key'
pub key: Vec<String>,
}
impl SSHFeature {
pub fn into_config(self) -> SSHConfig {
SSHConfig {
sshd_config: self.sshd,
key: Some(
self.key
.into_iter()
.map(|x| {
let (users, key) = x.split_once(':').unwrap();
let users: Vec<_> = users
.split(',')
.map(std::string::ToString::to_string)
.collect();
SSHKey {
key: key.to_string(),
users: users,
}
})
.collect(),
),
}
}
}
/// Setup SSH on the system
///
/// This should be done after `setup_users()` to ensure that the users directories exist.

63
src/fx/virt.rs Normal file
View file

@ -0,0 +1,63 @@
use argh::FromArgs;
use crate::{
linux::{arch_chroot, run_command_noerr, systemd_service_enable},
pkg::install_pkgs,
print_status,
};
#[derive(FromArgs)]
#[argh(subcommand, name = "virt-guest")]
/// Install VM guest utils
pub struct VirtGuestFeature {}
#[derive(FromArgs)]
#[argh(subcommand, name = "virt")]
/// Enable virtualization
pub struct VirtFeature {
#[argh(switch)]
/// enable virt-manager GUI
pub gui: bool,
#[argh(option)]
/// add user to libvirt group
pub user: Vec<String>,
}
pub fn setup_virtualization(conf: &VirtFeature) {
install_pkgs(&["libvirt", "swtpm", "qemu-base"]);
if conf.gui {
install_pkgs(&["virt-manager"]);
}
systemd_service_enable("libvirtd.service");
for user in &conf.user {
arch_chroot(
&vec!["usermod", "-a", "-G", "libvirt", user.as_str()],
None,
false,
);
}
}
pub fn setup_vm_guest() {
print_status("Detected KVM. Installing utils");
install_pkgs(&["qemu-guest-agent", "spice-vdagent"]);
systemd_service_enable("qemu-guest-agent.service");
systemd_service_enable("spice-vdagentd.service");
}
/// Setup guest utils if running inside a VM
pub fn try_setup_vm_guest() {
let res = run_command_noerr(&["systemd-detect-virt", "--vm"], None, false);
let is_vm = res.0.trim();
match is_vm {
"qemu" | "kvm" => {
setup_vm_guest();
}
_ => {}
}
}

View file

@ -1,9 +1,16 @@
use argh::FromArgs;
use crate::{
linux::{install_file, systemd_service_enable},
pkg::install_pkgs,
print_status,
};
#[derive(FromArgs)]
#[argh(subcommand, name = "zram")]
/// Enable ZRAM
pub struct ZramFeature {}
/// Setup the ZRAM feature
pub fn setup_zram() {
install_pkgs(&["zram-generator"]);

View file

@ -1,24 +0,0 @@
use crate::{
config::UserConfig,
linux::{arch_chroot, systemd_service_enable},
pkg::install_pkgs,
print_status,
};
/// Setup docker on the system
pub fn setup_docker(conf: &[UserConfig]) {
print_status("Setting up Docker");
install_pkgs(&["docker", "docker-compose"]);
systemd_service_enable("docker.service");
for user in conf {
if user.docker.unwrap_or_default() {
arch_chroot(
&vec!["usermod", "-a", "-G", "docker", user.name.as_str()],
None,
false,
);
}
}
}

View file

@ -2,7 +2,7 @@
use crate::{
config::GeneralConfig,
linux::{arch_chroot, install_file, run_command, systemd_service_enable},
linux::{arch_chroot, install_file, run_command},
print_status,
};

View file

@ -6,44 +6,36 @@
// DRIVE SELECTION
use bluetooth::setup_bluetooth;
use crate::config::InstallMode;
use crate::fx::docker::setup_docker;
use crate::fx::firewall::setup_firewall;
use crate::fx::gpu::setup_video_drivers;
use crate::fx::ollama::setup_ollama;
use crate::fx::ssh::setup_ssh;
use crate::fx::virt::{VirtFeature, setup_virtualization, try_setup_vm_guest};
use crate::fx::zram::setup_zram;
use boot::setup_bootloader;
use desktop::setup_desktop;
use docker::setup_docker;
use drives::{format_drives, mount_drives, setup_fstrim};
use firewall::setup_firewall;
use firmware::{setup_fwupd, setup_microcode};
use first_boot::{first_boot_values, genfstab};
use gpu::setup_video_drivers;
use kernel::setup_mkinitcpio;
use navos::setup_navos;
use ollama::setup_ollama;
use security::{has_secure_boot, setup_secure_boot, setup_tpm_unlock};
use skel::setup_skel;
use ssh::setup_ssh;
use user::setup_users;
use virt::{setup_virtualization, setup_vm};
use yansi::{Color, Paint};
use zram::setup_zram;
pub mod bluetooth;
pub mod boot;
pub mod desktop;
pub mod docker;
pub mod drives;
pub mod firewall;
pub mod firmware;
pub mod first_boot;
pub mod gpu;
pub mod kernel;
pub mod navos;
pub mod ollama;
pub mod security;
pub mod skel;
pub mod ssh;
pub mod user;
pub mod virt;
pub mod zram;
// TODO : error handling
// TODO : Power profile daemon
@ -51,6 +43,7 @@ pub mod zram;
use crate::{
config::{InstallConfig, WlanConfig},
fx::bluetooth::setup_bluetooth,
linux::run_command,
pkg::{self, install_pkgs, pacstrap_at, setup_kernel},
print_status,
@ -209,7 +202,25 @@ pub fn install_mnt(conf: InstallConfig, bare: bool) {
// Applications
if conf.pkg.virtualization.unwrap_or_default() {
setup_virtualization(&conf);
setup_virtualization(&VirtFeature {
gui: matches!(conf.general.mode, InstallMode::Desktop),
user: conf
.user
.as_ref()
.map(|users| {
users
.into_iter()
.filter_map(|x| {
if x.virtualization.unwrap_or_default() {
Some(x.name.clone())
} else {
None
}
})
.collect::<Vec<_>>()
})
.unwrap_or_default(),
});
}
if conf.pkg.docker.unwrap_or_default() {
@ -219,7 +230,17 @@ pub fn install_mnt(conf: InstallConfig, bare: bool) {
Vec::new()
};
setup_docker(&user_conf);
let docker_users: Vec<_> = user_conf
.iter()
.filter_map(|x| {
if x.docker.unwrap_or_default() {
Some(x.name.clone())
} else {
None
}
})
.collect();
setup_docker(&docker_users);
}
if let Some(ai) = conf.ai {
@ -237,7 +258,7 @@ pub fn install_mnt(conf: InstallConfig, bare: bool) {
// System
setup_zram();
setup_vm();
try_setup_vm_guest();
if let Some(gpu_vendor) = &conf.general.gpu_driver {
setup_video_drivers(gpu_vendor);
}

View file

@ -5,10 +5,7 @@ pub fn setup_skel(conf: &GeneralConfig) {
std::fs::create_dir_all("/mnt/etc/skel/.config").unwrap();
install_file(
"/mnt/etc/skel/.config/kxkbrc",
&build_kxkbrc(
conf.keyboard_layout.as_str(),
conf.keyboard_variant.as_ref().map(|x| x.as_str()),
),
&build_kxkbrc(conf.keyboard_layout.as_str(), conf.keyboard_variant.clone()),
0o644,
);
}

View file

@ -1,48 +0,0 @@
use crate::{
config::{InstallConfig, InstallMode},
linux::{arch_chroot, run_command_noerr, systemd_service_enable},
pkg::install_pkgs,
print_status,
};
pub fn setup_virtualization(conf: &InstallConfig) {
let user_conf = if let Some(user_conf) = &conf.user {
user_conf.clone()
} else {
Vec::new()
};
install_pkgs(&["libvirt", "swtpm", "qemu-base"]);
if matches!(conf.general.mode, InstallMode::Desktop) {
install_pkgs(&["virt-manager"]);
}
systemd_service_enable("libvirtd.service");
for user in user_conf {
if user.virtualization.unwrap_or_default() {
arch_chroot(
&vec!["usermod", "-a", "-G", "libvirt", user.name.as_str()],
None,
false,
);
}
}
}
/// Setup guest utils if running inside a VM
pub fn setup_vm() {
let res = run_command_noerr(&["systemd-detect-virt", "--vm"], None, false);
let is_vm = res.0.trim();
match is_vm {
"qemu" | "kvm" => {
print_status("Detected KVM. Installing utils");
install_pkgs(&["qemu-guest-agent", "spice-vdagent"]);
systemd_service_enable("qemu-guest-agent.service");
systemd_service_enable("spice-vdagentd.service");
}
_ => {}
}
}

View file

@ -1,6 +1,7 @@
pub mod args;
pub mod config;
pub mod create_iso;
pub mod fx;
pub mod install;
pub mod linux;
pub mod pkg;

View file

@ -1,4 +1,12 @@
use navinstall::config::InstallConfig;
use navinstall::fx::bluetooth::setup_bluetooth;
use navinstall::fx::docker::setup_docker;
use navinstall::fx::firewall::setup_firewall;
use navinstall::fx::gpu::setup_video_drivers;
use navinstall::fx::ollama::setup_ollama;
use navinstall::fx::ssh::setup_ssh;
use navinstall::fx::virt::{setup_virtualization, setup_vm_guest};
use navinstall::fx::zram::setup_zram;
use navinstall::install::navos::setup_navos;
use navinstall::install::{
drives::setup_disk_image, install, install_mnt, security::ensure_secure_boot,
@ -24,69 +32,40 @@ fn main() {
.paint(Color::Yellow)
);
let args = navinstall::args::get_args();
let args: navinstall::args::NavinstallArgs = argh::from_env();
match args.subcommand() {
Some(("create-iso", iso_args)) => {
let without_gui = iso_args.get_flag("without_gui");
let no_tmp = iso_args.get_flag("no_tmp");
match args.cmd {
navinstall::args::NavinstallCommands::CreateISO(create_isocommand) => {
let kb_layout_default = "us".to_string();
let kb_layout: &String = iso_args.get_one("kb_layout").unwrap_or(&kb_layout_default);
let kb_variant: Option<&str> =
iso_args.get_one("kb_variant").map(|x: &String| x.as_str());
let auto_install_config: Option<&String> = iso_args.get_one("install");
let kb_layout = create_isocommand.kb_layout.unwrap_or(kb_layout_default);
let user: Option<&String> = iso_args.get_one("user");
let pass: Option<&String> = iso_args.get_one("pass");
let uid: Option<&String> = iso_args.get_one("uid");
let user = if user.is_some() && pass.is_some() {
let user = if create_isocommand.user.is_some() && create_isocommand.pass.is_some() {
Some((
user.unwrap().to_string(),
pass.unwrap().to_string(),
uid.map(|x| x.parse().unwrap()).unwrap_or(1000),
create_isocommand.user.unwrap().to_string(),
create_isocommand.pass.unwrap().to_string(),
create_isocommand.uid.unwrap_or(1000),
))
} else {
None
};
let units: Vec<_> = iso_args.get_many("unit").unwrap_or_default().collect();
create_iso(
without_gui,
no_tmp,
kb_layout,
kb_variant,
create_isocommand.without_gui,
create_isocommand.no_tmp,
&kb_layout,
create_isocommand.kb_variant,
user,
units.into_iter().map(|x: &String| x.to_string()).collect(),
auto_install_config,
create_isocommand.unit,
create_isocommand.install,
);
std::process::exit(0);
}
Some(("create-tar", tar_options)) => {
ensure_root();
let dir: &String = tar_options.get_one("dir").unwrap();
print_status("Pacstrapping root fs");
pacstrap_at(&dir, &[]);
setup_navos(dir.as_str());
}
Some(("create-img", install_args)) => {
let config_file: &String = install_args.get_one("config").unwrap();
let conf = read_conf(config_file);
let img_file: &String = install_args.get_one("image").unwrap();
let gpt = install_args.get_flag("gpt");
setup_disk_image(img_file.as_str(), gpt);
install_mnt(conf, false);
}
Some(("install", install_args)) => {
navinstall::args::NavinstallCommands::Install(install_command) => {
ensure_root();
let config_file: &String = install_args.get_one("config").unwrap();
let force = install_args.get_flag("force");
let conf = read_conf(config_file);
let conf = read_conf(&install_command.config);
if !force {
if !install_command.force {
print_config(&conf);
print!("Do you want to proceed with this configuration? (yes/no) ");
expect_yes();
@ -99,7 +78,53 @@ fn main() {
// Run the
install(conf, true);
}
_ => {}
navinstall::args::NavinstallCommands::CreateTar(create_tar_command) => {
ensure_root();
print_status("Pacstrapping root fs");
pacstrap_at(&create_tar_command.dir, &[]);
setup_navos(&create_tar_command.dir.as_str());
}
navinstall::args::NavinstallCommands::CreateImage(create_image_command) => {
let conf = read_conf(&create_image_command.config);
setup_disk_image(
&create_image_command.image.as_str(),
create_image_command.gpt,
);
install_mnt(conf, false);
}
navinstall::args::NavinstallCommands::Feature(feature_command) => {
match feature_command.cmd {
navinstall::fx::Features::Bluetooth(_) => setup_bluetooth(),
navinstall::fx::Features::GPU(gpufeature) => {
let vendor = match gpufeature.vendor.to_lowercase().as_str() {
"amd" => navinstall::config::GPUVendor::AMD,
"intel" => navinstall::config::GPUVendor::INTEL,
"nvidia" => navinstall::config::GPUVendor::NVIDIA,
_ => {
println!("{} is no GPU vendor", gpufeature.vendor);
std::process::exit(1);
}
};
setup_video_drivers(&vendor);
}
navinstall::fx::Features::Docker(docker_feature) => {
setup_docker(&docker_feature.user);
}
navinstall::fx::Features::Firewall(firewall_feature) => {
setup_firewall(firewall_feature.ssh)
}
navinstall::fx::Features::Ollama(ollama_feature) => {
setup_ollama(&ollama_feature.into_config())
}
navinstall::fx::Features::SSH(sshfeature) => {
setup_ssh(&Some(sshfeature.into_config()))
}
navinstall::fx::Features::Virt(virt_feature) => setup_virtualization(&virt_feature),
navinstall::fx::Features::VirtGuest(_) => setup_vm_guest(),
navinstall::fx::Features::Zram(_) => setup_zram(),
}
}
}
}

View file

@ -47,7 +47,6 @@ pub fn setup_kernel(kernel: Option<String>) {
/// Initial system pacstrap
pub fn pacstrap_at(dir: &str, pkg: &[String]) {
// TODO : rearrange pkgs + minify
let mut cmd: Vec<&str> = vec!["pacstrap", "-K", dir, "base"];
#[cfg(target_arch = "aarch64")]

View file

@ -79,6 +79,7 @@ pub fn print_config(conf: &InstallConfig) {
crate::config::GPUVendor::NVIDIA => {
general_info.add_str(format!("🟩 NVIDIA GPU {}", "✔️".paint(Color::Green)))
}
crate::config::GPUVendor::NONE => {}
}
}
if conf.general.firewall.unwrap_or(true) {