refactor + ui
This commit is contained in:
parent
7f0fd2c45b
commit
a3da9fb9ac
6 changed files with 318 additions and 62 deletions
84
installs/full.toml
Normal file
84
installs/full.toml
Normal file
|
@ -0,0 +1,84 @@
|
|||
# Full Install Template
|
||||
|
||||
# Drive Selection for Install
|
||||
[drive]
|
||||
# Device node for the EFI boot filesystem
|
||||
boot = "/dev/null"
|
||||
|
||||
# Device node for the root filesystem
|
||||
root = "/dev/null"
|
||||
|
||||
# Root filesystem encryption passphrase
|
||||
# If this option is set the root filesystem will be encrypted with LUKS
|
||||
encryption = "password"
|
||||
|
||||
# General configuration
|
||||
[general]
|
||||
# Preset
|
||||
mode = "Desktop"
|
||||
|
||||
# System Locale
|
||||
locale = "de_DE.UTF-8"
|
||||
|
||||
# Keymap
|
||||
keyboard_layout = "de"
|
||||
keyboard_variant = "mac"
|
||||
|
||||
# Timezone
|
||||
timezone = "Europe/Berlin"
|
||||
|
||||
# Hostname
|
||||
hostname = "navos"
|
||||
|
||||
[pkg]
|
||||
# Additional packages
|
||||
pkg = [
|
||||
"nano",
|
||||
"micro"
|
||||
]
|
||||
|
||||
# Enable virtualization
|
||||
virtualization = true
|
||||
|
||||
# Enable docker
|
||||
docker = true
|
||||
|
||||
# User configuration
|
||||
# The `[[user]]` directive can be repeated to create multiple users.
|
||||
[[user]]
|
||||
# Username
|
||||
name = "testuser"
|
||||
|
||||
# User password
|
||||
password = "testpass"
|
||||
|
||||
# Allow user to use `doas` as root
|
||||
doas_root= true
|
||||
|
||||
# SSH Configuration
|
||||
# If `[ssh]` is set, openssh will be installed and enabled.
|
||||
[ssh]
|
||||
# Config file for sshd
|
||||
# This file will be copied to the new system
|
||||
sshd_config = "/etc/ssh/sshd_config"
|
||||
|
||||
# Install a SSH keys
|
||||
# To set multiple keys, repeat the `[[ssh.key]]` directive.
|
||||
# Every key will be installed in the users respective `authorized_keys` file.
|
||||
[[ssh.key]]
|
||||
# The SSH Key
|
||||
key = "ssh-rsa ... user@host"
|
||||
|
||||
# The users allowed to login with this key
|
||||
users = ["testuser", "root"]
|
||||
|
||||
# Ollama Configuration
|
||||
# If `[ai]` is set, ollama will be installed and enabled.
|
||||
[ai]
|
||||
# Install with CUDA supports
|
||||
gpu = true
|
||||
|
||||
# Pull LLMs
|
||||
models = [
|
||||
"llama3.1:8b"
|
||||
]
|
|
@ -1,57 +0,0 @@
|
|||
# Drive Selection for Install
|
||||
[drive]
|
||||
boot = "/dev/null"
|
||||
root = "/dev/null"
|
||||
|
||||
# Use LUKS encryption on root drive
|
||||
encryption = "password"
|
||||
|
||||
[general]
|
||||
# Preset
|
||||
mode = "Desktop"
|
||||
|
||||
# System Locale
|
||||
locale = "de_DE.UTF-8"
|
||||
|
||||
# Keymap
|
||||
keyboard_layout = "de"
|
||||
keyboard_variant = "mac"
|
||||
|
||||
# Timezone
|
||||
timezone = "Europe/Berlin"
|
||||
|
||||
# Hostname
|
||||
hostname = "navos"
|
||||
|
||||
[pkg]
|
||||
# Additional packages
|
||||
pkg = [
|
||||
"nano",
|
||||
"micro"
|
||||
]
|
||||
|
||||
# Enable virtualization
|
||||
virtualization = true
|
||||
|
||||
# Enable docker
|
||||
docker = true
|
||||
|
||||
[[user]]
|
||||
# Username
|
||||
name = "testuser"
|
||||
|
||||
# User password
|
||||
password = "testpass"
|
||||
|
||||
# Allow user to use doas as root
|
||||
doas_root= true
|
||||
|
||||
# SSH Configuration
|
||||
[ssh]
|
||||
# Config file for sshd
|
||||
sshd_config = "/etc/ssh/sshd_config"
|
||||
|
||||
# Install a SSH key for the user as `authorized_keys`
|
||||
[[ssh.key]]
|
||||
key = "ssh-rsa ... user@host"
|
||||
users = ["testuser", "root"]
|
|
@ -1,3 +1,5 @@
|
|||
use std::fmt::Display;
|
||||
|
||||
use serde::Deserialize;
|
||||
|
||||
/// Declarative install configuration
|
||||
|
@ -26,7 +28,7 @@ pub struct OllamaConfig {
|
|||
#[derive(Debug, Deserialize)]
|
||||
pub struct SSHConfig {
|
||||
pub sshd_config: Option<String>,
|
||||
pub key: Vec<SSHKey>,
|
||||
pub key: Option<Vec<SSHKey>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
|
@ -90,3 +92,16 @@ pub enum InstallMode {
|
|||
// TODO : Evaluate
|
||||
Kiosk,
|
||||
}
|
||||
|
||||
impl Display for InstallMode {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
InstallMode::Base => f.write_str("Base")?,
|
||||
InstallMode::Desktop => f.write_str("Desktop")?,
|
||||
InstallMode::Server => f.write_str("Server")?,
|
||||
InstallMode::Kiosk => f.write_str("Kiosk")?,
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@ pub fn setup_ssh(conf: Option<SSHConfig>) {
|
|||
install_file("/mnt/etc/ssh/sshd_config", &content, 0o644);
|
||||
}
|
||||
|
||||
for key in &conf.key {
|
||||
for key in &conf.key.unwrap_or_default() {
|
||||
for user in &key.users {
|
||||
let path = if user == "root" {
|
||||
std::fs::create_dir_all("/root/.ssh").unwrap();
|
||||
|
|
|
@ -8,9 +8,11 @@ mod create_iso;
|
|||
mod install;
|
||||
mod linux;
|
||||
mod pkg;
|
||||
mod print;
|
||||
use create_iso::create_iso;
|
||||
use install::install;
|
||||
use linux::is_root;
|
||||
use print::print_config;
|
||||
use yansi::{Color, Paint};
|
||||
|
||||
fn print_status(msg: &str) {
|
||||
|
@ -97,9 +99,8 @@ fn main() {
|
|||
}
|
||||
};
|
||||
|
||||
// TODO : Show config
|
||||
println!("Config: {conf:?}");
|
||||
print!("\nDo you want to proceed with this configuration? (yes/no) ");
|
||||
print_config(&conf);
|
||||
print!("Do you want to proceed with this configuration? (yes/no) ");
|
||||
|
||||
let mut input = String::new();
|
||||
std::io::stdout().flush().expect("Error flushing stdout.");
|
||||
|
|
213
src/print.rs
Normal file
213
src/print.rs
Normal file
|
@ -0,0 +1,213 @@
|
|||
use yansi::{Color, Paint};
|
||||
|
||||
use crate::config::InstallConfig;
|
||||
|
||||
pub fn print_config(conf: &InstallConfig) {
|
||||
println!("🚀 Install Configuration:");
|
||||
|
||||
let mut root_info = Tree::new();
|
||||
|
||||
let mut drive_info = Tree::new();
|
||||
drive_info.add_str(format!(
|
||||
"💾 {} {}",
|
||||
conf.drive.boot.paint(Color::Red),
|
||||
"[EFI]".paint(Color::Blue)
|
||||
));
|
||||
drive_info.add_str(format!(
|
||||
"{} {} {}",
|
||||
if conf.drive.encryption.is_some() {
|
||||
"🔒"
|
||||
} else {
|
||||
"💾"
|
||||
},
|
||||
conf.drive.root.paint(Color::Red),
|
||||
"[ROOT]".paint(Color::Blue)
|
||||
));
|
||||
|
||||
root_info.add_tree("💾 Drive Selection", drive_info);
|
||||
|
||||
let mut general_info = Tree::new();
|
||||
|
||||
general_info.add_str(format!(
|
||||
"💎 {} {}",
|
||||
"Mode:".paint(Color::Yellow),
|
||||
conf.general.mode
|
||||
));
|
||||
general_info.add_str(format!(
|
||||
"🖥️ {} {}",
|
||||
"Hostname:".paint(Color::Yellow),
|
||||
conf.general.hostname
|
||||
));
|
||||
general_info.add_str(format!(
|
||||
"⌨️ {} {} {}",
|
||||
"Keyboard:".paint(Color::Yellow),
|
||||
conf.general.keyboard_layout,
|
||||
conf.general
|
||||
.keyboard_variant
|
||||
.as_ref()
|
||||
.unwrap_or(&String::new())
|
||||
));
|
||||
general_info.add_str(format!(
|
||||
"🌍 {} {}",
|
||||
"Locale:".paint(Color::Yellow),
|
||||
conf.general.locale
|
||||
));
|
||||
general_info.add_str(format!(
|
||||
"⌛ {} {}",
|
||||
"Timezone:".paint(Color::Yellow),
|
||||
conf.general.timezone
|
||||
));
|
||||
|
||||
root_info.add_tree("🔨 General", general_info);
|
||||
|
||||
let mut pkg_info = Tree::new();
|
||||
|
||||
if conf.pkg.docker {
|
||||
pkg_info.add_str(format!("🐳 Docker {}", "✔️".paint(Color::Green)));
|
||||
}
|
||||
|
||||
if conf.pkg.virtualization {
|
||||
pkg_info.add_str(format!("🎃 Virtualization {}", "✔️".paint(Color::Green)));
|
||||
}
|
||||
|
||||
if !conf.pkg.pkg.is_empty() {
|
||||
pkg_info.add_str(format!(
|
||||
"📦 Additional packages: {}",
|
||||
conf.pkg.pkg.join(" ")
|
||||
));
|
||||
}
|
||||
|
||||
root_info.add_tree("📦 Packages", pkg_info);
|
||||
|
||||
let mut users_info = Tree::new();
|
||||
|
||||
for user in &conf.user {
|
||||
users_info.add_str(format!(
|
||||
"👤 {} {}",
|
||||
user.name,
|
||||
if user.doas_root { "🔑" } else { "" }
|
||||
));
|
||||
}
|
||||
|
||||
root_info.add_tree("🧛 Users", users_info);
|
||||
|
||||
if let Some(ssh_conf) = &conf.ssh {
|
||||
let mut ssh_info = Tree::new();
|
||||
|
||||
if let Some(sshd_conf) = &ssh_conf.sshd_config {
|
||||
ssh_info.add_str(format!("📖 Installing {sshd_conf} as sshd_config"));
|
||||
}
|
||||
|
||||
if let Some(keys) = &ssh_conf.key {
|
||||
for key in keys {
|
||||
let key_origin = key.key.split(" ").nth(2).unwrap_or_default();
|
||||
|
||||
ssh_info.add_str(format!(
|
||||
"🔑 Key {} for {}",
|
||||
key_origin.paint(Color::Blue),
|
||||
key.users.join(", ").paint(Color::Yellow)
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
root_info.add_tree("🌐 SSH", ssh_info);
|
||||
}
|
||||
|
||||
if let Some(ai_conf) = &conf.ai {
|
||||
let mut ai_info = Tree::new();
|
||||
|
||||
if ai_conf.gpu {
|
||||
ai_info.add_str(format!("🟩 Use CUDA {}", "✔️".paint(Color::Green)));
|
||||
}
|
||||
|
||||
if let Some(models) = &ai_conf.models {
|
||||
ai_info.add_str(format!("⬇️ Pull Models: {}", models.join(", ")));
|
||||
}
|
||||
|
||||
root_info.add_tree("🦙 Ollama", ai_info);
|
||||
}
|
||||
|
||||
println!("{}", root_info.render(0));
|
||||
}
|
||||
|
||||
pub struct Tree {
|
||||
elements: Vec<TreeEntry>,
|
||||
}
|
||||
|
||||
pub enum TreeEntry {
|
||||
Tree(String, Tree),
|
||||
Str(String),
|
||||
}
|
||||
|
||||
impl Tree {
|
||||
pub fn new() -> Self {
|
||||
Self { elements: vec![] }
|
||||
}
|
||||
|
||||
pub fn add_tree(&mut self, key: &str, item: Tree) {
|
||||
self.elements.push(TreeEntry::Tree(key.to_string(), item));
|
||||
}
|
||||
|
||||
pub fn add_str(&mut self, item: String) {
|
||||
self.elements.push(TreeEntry::Str(item));
|
||||
}
|
||||
|
||||
pub fn render(&self, depth: i32) -> String {
|
||||
const DEPTH_INCREASE: i32 = 3;
|
||||
|
||||
let mut ret = String::new();
|
||||
|
||||
let len = self.elements.len();
|
||||
|
||||
for (index, val) in self.elements.iter().enumerate() {
|
||||
let padding = pad_with_bars(depth, DEPTH_INCREASE);
|
||||
|
||||
let path_repr = if (index + 1) == len {
|
||||
if matches!(val, TreeEntry::Tree(_, _)) {
|
||||
"├─"
|
||||
} else {
|
||||
"└─"
|
||||
}
|
||||
} else {
|
||||
"├─"
|
||||
};
|
||||
|
||||
match val {
|
||||
TreeEntry::Tree(key, tree) => {
|
||||
if !tree.elements.is_empty() {
|
||||
ret.push_str(&format!("{padding}{path_repr} {key}\n"));
|
||||
ret.push_str(&tree.render(depth + DEPTH_INCREASE))
|
||||
}
|
||||
}
|
||||
TreeEntry::Str(str) => {
|
||||
ret.push_str(&format!("{padding}{path_repr} {str}\n"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ret
|
||||
}
|
||||
}
|
||||
|
||||
pub fn pad_with_bars(n: i32, depth_inc: i32) -> String {
|
||||
let amount = n / depth_inc;
|
||||
|
||||
let mut ret = String::new();
|
||||
|
||||
if amount >= 1 {
|
||||
ret.push_str("│");
|
||||
}
|
||||
|
||||
ret.push_str(&pad(n - amount));
|
||||
ret
|
||||
}
|
||||
|
||||
pub fn pad(n: i32) -> String {
|
||||
let mut ret = String::new();
|
||||
|
||||
for _ in 0..n {
|
||||
ret.push_str(" ");
|
||||
}
|
||||
|
||||
ret
|
||||
}
|
Loading…
Add table
Reference in a new issue