Compare commits
3 commits
4ad01219db
...
40a1498c6f
Author | SHA1 | Date | |
---|---|---|---|
40a1498c6f | |||
a3da9fb9ac | |||
7f0fd2c45b |
11 changed files with 414 additions and 83 deletions
87
installs/full.toml
Normal file
87
installs/full.toml
Normal file
|
@ -0,0 +1,87 @@
|
||||||
|
# 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"
|
||||||
|
|
||||||
|
# Root password
|
||||||
|
root_password = "root"
|
||||||
|
|
||||||
|
[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"
|
||||||
|
]
|
38
installs/min.toml
Normal file
38
installs/min.toml
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
# Minimal 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 = "Base"
|
||||||
|
|
||||||
|
# System Locale
|
||||||
|
locale = "de_DE.UTF-8"
|
||||||
|
|
||||||
|
# Keymap
|
||||||
|
keyboard_layout = "de"
|
||||||
|
keyboard_variant = "mac"
|
||||||
|
|
||||||
|
# Timezone
|
||||||
|
timezone = "Europe/Berlin"
|
||||||
|
|
||||||
|
# Hostname
|
||||||
|
hostname = "navos_min"
|
||||||
|
|
||||||
|
# Root password
|
||||||
|
root_password = "root"
|
||||||
|
|
||||||
|
[pkg]
|
||||||
|
# Additional packages
|
||||||
|
pkg = []
|
|
@ -1,56 +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
|
|
||||||
keymap = "de-latin1"
|
|
||||||
|
|
||||||
# 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;
|
use serde::Deserialize;
|
||||||
|
|
||||||
/// Declarative install configuration
|
/// Declarative install configuration
|
||||||
|
@ -10,7 +12,7 @@ pub struct InstallConfig {
|
||||||
/// Package Configuration
|
/// Package Configuration
|
||||||
pub pkg: PackageConfig,
|
pub pkg: PackageConfig,
|
||||||
/// User Configuration
|
/// User Configuration
|
||||||
pub user: Vec<UserConfig>,
|
pub user: Option<Vec<UserConfig>>,
|
||||||
/// SSH Configuration
|
/// SSH Configuration
|
||||||
pub ssh: Option<SSHConfig>,
|
pub ssh: Option<SSHConfig>,
|
||||||
/// Ollama AI Config
|
/// Ollama AI Config
|
||||||
|
@ -26,7 +28,7 @@ pub struct OllamaConfig {
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
pub struct SSHConfig {
|
pub struct SSHConfig {
|
||||||
pub sshd_config: Option<String>,
|
pub sshd_config: Option<String>,
|
||||||
pub key: Vec<SSHKey>,
|
pub key: Option<Vec<SSHKey>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
|
@ -47,9 +49,9 @@ pub struct PackageConfig {
|
||||||
/// Packages to install
|
/// Packages to install
|
||||||
pub pkg: Vec<String>,
|
pub pkg: Vec<String>,
|
||||||
/// Enable libvirt
|
/// Enable libvirt
|
||||||
pub virtualization: bool,
|
pub virtualization: Option<bool>,
|
||||||
/// Enable docker
|
/// Enable docker
|
||||||
pub docker: bool,
|
pub docker: Option<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
|
@ -68,12 +70,16 @@ pub struct GeneralConfig {
|
||||||
pub mode: InstallMode,
|
pub mode: InstallMode,
|
||||||
/// System locale
|
/// System locale
|
||||||
pub locale: String,
|
pub locale: String,
|
||||||
/// Keymap
|
/// Keyboard Layout
|
||||||
pub keymap: String,
|
pub keyboard_layout: String,
|
||||||
|
/// Keyboard Variant
|
||||||
|
pub keyboard_variant: Option<String>,
|
||||||
/// Timezone
|
/// Timezone
|
||||||
pub timezone: String,
|
pub timezone: String,
|
||||||
/// Hostname
|
/// Hostname
|
||||||
pub hostname: String,
|
pub hostname: String,
|
||||||
|
// Root password
|
||||||
|
pub root_password: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
|
@ -88,3 +94,16 @@ pub enum InstallMode {
|
||||||
// TODO : Evaluate
|
// TODO : Evaluate
|
||||||
Kiosk,
|
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(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ use crate::{
|
||||||
print_status,
|
print_status,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::uncomment_first_value_of;
|
use super::{uncomment_first_value_of, user::change_passwd};
|
||||||
|
|
||||||
/// Generate the `/etc/fstab` file
|
/// Generate the `/etc/fstab` file
|
||||||
pub fn genfstab() {
|
pub fn genfstab() {
|
||||||
|
@ -38,11 +38,7 @@ pub fn first_boot_values(conf: &GeneralConfig) {
|
||||||
|
|
||||||
// Keymap
|
// Keymap
|
||||||
print_status("Writing /etc/vconsole.conf");
|
print_status("Writing /etc/vconsole.conf");
|
||||||
std::fs::write(
|
std::fs::write("/mnt/etc/vconsole.conf", build_vconsole_conf(conf)).unwrap();
|
||||||
"/mnt/etc/vconsole.conf",
|
|
||||||
format!("KEYMAP=\"{}\"", conf.keymap),
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
// Hostname
|
// Hostname
|
||||||
print_status("Writing /etc/hostname");
|
print_status("Writing /etc/hostname");
|
||||||
|
@ -55,5 +51,20 @@ pub fn first_boot_values(conf: &GeneralConfig) {
|
||||||
|
|
||||||
arch_chroot(&["hwclock", "--systohc"], None, false);
|
arch_chroot(&["hwclock", "--systohc"], None, false);
|
||||||
|
|
||||||
|
if let Some(root_pw) = &conf.root_password {
|
||||||
|
change_passwd("root", root_pw);
|
||||||
|
}
|
||||||
|
|
||||||
systemd_service_enable("NetworkManager.service");
|
systemd_service_enable("NetworkManager.service");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn build_vconsole_conf(conf: &GeneralConfig) -> String {
|
||||||
|
let mut ret = format!("KEYMAP={}\n", conf.keyboard_layout);
|
||||||
|
ret.push_str(&format!("XBKLAYOUT={}\n", conf.keyboard_layout));
|
||||||
|
|
||||||
|
if let Some(variant) = &conf.keyboard_variant {
|
||||||
|
ret.push_str(&format!("XKBMODEL={variant}\n"));
|
||||||
|
}
|
||||||
|
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
|
|
@ -88,7 +88,7 @@ pub fn install(conf: InstallConfig) {
|
||||||
// System Setup
|
// System Setup
|
||||||
first_boot_values(&conf.general);
|
first_boot_values(&conf.general);
|
||||||
setup_skel(&conf.general);
|
setup_skel(&conf.general);
|
||||||
setup_users(&conf.user);
|
setup_users(&conf.user.unwrap_or_default());
|
||||||
|
|
||||||
setup_ssh(conf.ssh);
|
setup_ssh(conf.ssh);
|
||||||
|
|
||||||
|
@ -118,11 +118,11 @@ pub fn install(conf: InstallConfig) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if conf.pkg.virtualization {
|
if conf.pkg.virtualization.unwrap_or_default() {
|
||||||
// TODO : Enable virtualization
|
// TODO : Enable virtualization
|
||||||
}
|
}
|
||||||
|
|
||||||
if conf.pkg.docker {
|
if conf.pkg.docker.unwrap_or_default() {
|
||||||
// TODO : Enable docker
|
// TODO : Enable docker
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,14 @@
|
||||||
use crate::config::GeneralConfig;
|
use crate::{config::GeneralConfig, create_iso::build_kxkbrc, linux::install_file, print_status};
|
||||||
|
|
||||||
pub fn setup_skel(conf: &GeneralConfig) {
|
pub fn setup_skel(conf: &GeneralConfig) {
|
||||||
// TODO : Implement
|
print_status("Setting user config");
|
||||||
unimplemented!()
|
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()),
|
||||||
|
),
|
||||||
|
0o644,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@ pub fn setup_ssh(conf: Option<SSHConfig>) {
|
||||||
install_file("/mnt/etc/ssh/sshd_config", &content, 0o644);
|
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 {
|
for user in &key.users {
|
||||||
let path = if user == "root" {
|
let path = if user == "root" {
|
||||||
std::fs::create_dir_all("/root/.ssh").unwrap();
|
std::fs::create_dir_all("/root/.ssh").unwrap();
|
||||||
|
|
|
@ -4,6 +4,10 @@ use crate::{
|
||||||
print_status,
|
print_status,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub fn change_passwd(user: &str, pw: &str) {
|
||||||
|
arch_chroot(&["passwd", user], Some(&format!("{}\n{}\n", pw, pw)), false);
|
||||||
|
}
|
||||||
|
|
||||||
/// Setup the users of the system
|
/// Setup the users of the system
|
||||||
pub fn setup_users(conf: &[UserConfig]) {
|
pub fn setup_users(conf: &[UserConfig]) {
|
||||||
let mut doas_conf = String::new();
|
let mut doas_conf = String::new();
|
||||||
|
@ -11,11 +15,7 @@ pub fn setup_users(conf: &[UserConfig]) {
|
||||||
for user in conf {
|
for user in conf {
|
||||||
arch_chroot(&["useradd", "-m", &user.name], None, false);
|
arch_chroot(&["useradd", "-m", &user.name], None, false);
|
||||||
|
|
||||||
arch_chroot(
|
change_passwd(&user.name, &user.password);
|
||||||
&["passwd", &user.name],
|
|
||||||
Some(&format!("{}\n{}\n", user.password, user.password)),
|
|
||||||
false,
|
|
||||||
);
|
|
||||||
|
|
||||||
if user.doas_root {
|
if user.doas_root {
|
||||||
print_status(&format!("Allowing root doas for {}", user.name));
|
print_status(&format!("Allowing root doas for {}", user.name));
|
||||||
|
|
|
@ -8,9 +8,11 @@ mod create_iso;
|
||||||
mod install;
|
mod install;
|
||||||
mod linux;
|
mod linux;
|
||||||
mod pkg;
|
mod pkg;
|
||||||
|
mod print;
|
||||||
use create_iso::create_iso;
|
use create_iso::create_iso;
|
||||||
use install::install;
|
use install::install;
|
||||||
use linux::is_root;
|
use linux::is_root;
|
||||||
|
use print::print_config;
|
||||||
use yansi::{Color, Paint};
|
use yansi::{Color, Paint};
|
||||||
|
|
||||||
fn print_status(msg: &str) {
|
fn print_status(msg: &str) {
|
||||||
|
@ -97,9 +99,8 @@ fn main() {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO : Show config
|
print_config(&conf);
|
||||||
println!("Config: {conf:?}");
|
print!("Do you want to proceed with this configuration? (yes/no) ");
|
||||||
print!("\nDo you want to proceed with this configuration? (yes/no) ");
|
|
||||||
|
|
||||||
let mut input = String::new();
|
let mut input = String::new();
|
||||||
std::io::stdout().flush().expect("Error flushing stdout.");
|
std::io::stdout().flush().expect("Error flushing stdout.");
|
||||||
|
|
223
src/print.rs
Normal file
223
src/print.rs
Normal file
|
@ -0,0 +1,223 @@
|
||||||
|
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
|
||||||
|
));
|
||||||
|
if conf.general.root_password.is_some() {
|
||||||
|
general_info.add_str(format!(
|
||||||
|
"🔑 {} {}",
|
||||||
|
"Root Password".paint(Color::Yellow),
|
||||||
|
"✔️".paint(Color::Green)
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
root_info.add_tree("🔨 General", general_info);
|
||||||
|
|
||||||
|
let mut pkg_info = Tree::new();
|
||||||
|
|
||||||
|
if conf.pkg.docker.unwrap_or_default() {
|
||||||
|
pkg_info.add_str(format!("🐳 Docker {}", "✔️".paint(Color::Green)));
|
||||||
|
}
|
||||||
|
|
||||||
|
if conf.pkg.virtualization.unwrap_or_default() {
|
||||||
|
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();
|
||||||
|
|
||||||
|
let empty = Vec::new();
|
||||||
|
let user_conf = conf.user.as_ref().unwrap_or(&empty);
|
||||||
|
|
||||||
|
for user in user_conf {
|
||||||
|
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
Add a link
Reference in a new issue