From c9ecd3251b78423a4c95fe001f01144d6f4ca0a8 Mon Sep 17 00:00:00 2001 From: Randall Winkhart Date: Sun, 28 Sep 2025 01:45:11 -0400 Subject: [PATCH] Initial code commit --- README.md | 11 + applications.go | 127 +++++++++ configurations.go | 639 +++++++++++++++++++++++++++++++++++++++++++++ cosmic.go | 45 ++++ go.mod | 10 + go.sum | 6 + main.go | 44 ++++ removals.go | 48 ++++ system.go | 158 +++++++++++ universalTweaks.go | 28 ++ utilities.go | 53 ++++ 11 files changed, 1169 insertions(+) create mode 100644 README.md create mode 100644 applications.go create mode 100644 configurations.go create mode 100644 cosmic.go create mode 100644 go.mod create mode 100644 go.sum create mode 100644 main.go create mode 100644 removals.go create mode 100644 system.go create mode 100644 universalTweaks.go create mode 100644 utilities.go diff --git a/README.md b/README.md new file mode 100644 index 0000000..16b1d58 --- /dev/null +++ b/README.md @@ -0,0 +1,11 @@ +# CachyOS Post-Install Helper +This is a simple utility meant to address what I personally dislike about the base CachyOS installation. + +## Usage +Begin by installing CachyOS via the standard GUI installer. You may desire to uncheck the installation of `cachyos-zsh-config` and `firefox`. Please use systemd-boot. + +As soon as the system is installed and booted, run this utility as root and follow the prompts! That's it. + +If using to configure Cosmic DE, I recommend running this utility from a raw TTY without Cosmic running. + +A reboot is recommended if applying system tweaks. diff --git a/applications.go b/applications.go new file mode 100644 index 0000000..7a4dc36 --- /dev/null +++ b/applications.go @@ -0,0 +1,127 @@ +package main + +import ( + "os/exec" + + "github.com/rwinkhart/go-boilerplate/front" + "github.com/rwinkhart/go-boilerplate/other" +) + +func applications() { + for { + var doAll bool + choice := front.InputMenuGen("Application to install:", []string{"back", "all", "pamac-aur (replaces octopi)", "yay-bin (replaces paru)", "htop (replaces btop)", "neovim (replaces vi+vim+nano+micro)", "virt-manager (also installs qemu-desktop+libvirt)", "librewolf-bin", "zed", "steam"}) + switch choice { + case 1: + return + case 2: + doAll = true + fallthrough + case 3: + cmd := exec.Command("pacman", "-S", "pamac-aur", "--noconfirm") + err := cmd.Run() + if err != nil { + other.PrintError("Failed to perform application installation", 1) + } + cmd = exec.Command("pacman", "-Rcns", "octopi", "--noconfirm") + err = cmd.Run() + if err != nil { + other.PrintError("Failed to perform application removal", 1) + } + + if !doAll { + break + } + fallthrough + case 4: + cmd := exec.Command("pacman", "-S", "yay-bin", "--noconfirm") + err := cmd.Run() + if err != nil { + other.PrintError("Failed to perform application installation", 1) + } + cmd = exec.Command("pacman", "-Rcns", "paru", "--noconfirm") + err = cmd.Run() + if err != nil { + other.PrintError("Failed to perform application removal", 1) + } + + if !doAll { + break + } + fallthrough + case 5: + cmd := exec.Command("pacman", "-S", "htop", "--noconfirm") + err := cmd.Run() + if err != nil { + other.PrintError("Failed to perform application installation", 1) + } + cmd = exec.Command("pacman", "-Rcns", "btop", "--noconfirm") + err = cmd.Run() + if err != nil { + other.PrintError("Failed to perform application removal", 1) + } + + if !doAll { + break + } + fallthrough + case 6: + cmd := exec.Command("pacman", "-S", "neovim", "--noconfirm") + err := cmd.Run() + if err != nil { + other.PrintError("Failed to perform application installation", 1) + } + cmd = exec.Command("pacman", "-Rcns", "vi", "vim", "nano", "micro", "--noconfirm") + err = cmd.Run() + if err != nil { + other.PrintError("Failed to perform application removals", 1) + } + + if !doAll { + break + } + fallthrough + case 7: + cmd := exec.Command("pacman", "-S", "virt-manager", "qemu-desktop", "libvirt", "--noconfirm") + err := cmd.Run() + if err != nil { + other.PrintError("Failed to perform application installations", 1) + } + manageService("enable", "libvirtd.service") + manageService("start", "libvirtd.service") + + if !doAll { + break + } + fallthrough + case 8: + cmd := exec.Command("pacman", "-S", "librewolf-bin", "--noconfirm") + err := cmd.Run() + if err != nil { + other.PrintError("Failed to perform application installation", 1) + } + + if !doAll { + break + } + fallthrough + case 9: + cmd := exec.Command("pacman", "-S", "zed", "--noconfirm") + err := cmd.Run() + if err != nil { + other.PrintError("Failed to perform application installation", 1) + } + + if !doAll { + break + } + fallthrough + case 10: + cmd := exec.Command("pacman", "-S", "steam", "--noconfirm") + err := cmd.Run() + if err != nil { + other.PrintError("Failed to perform application installation", 1) + } + } + } +} diff --git a/configurations.go b/configurations.go new file mode 100644 index 0000000..7499857 --- /dev/null +++ b/configurations.go @@ -0,0 +1,639 @@ +package main + +import ( + "os" + "os/exec" + + "github.com/rwinkhart/go-boilerplate/front" + "github.com/rwinkhart/go-boilerplate/other" +) + +func configurations() { + for { + var doAll bool + choice := front.InputMenuGen("Custom config:", []string{"back", "all", "shell profile", "zshrc", "neovim", "zed", "makepkg", "pacman"}) + switch choice { + case 1: + return + case 2: + doAll = true + fallthrough + case 3: + cmd := exec.Command("pacman", "-S", "wayland-protocols", "--noconfirm") + err := cmd.Run() + if err != nil { + other.PrintError("Failed to install wayland-protocols", 1) + } + writeFile("/home/"+getUsername()+"/.profile", shellProfile, getUsername(), 0644) + + if !doAll { + break + } + fallthrough + case 4: + writeFile("/home/"+getUsername()+"/.zshrc", zshrc, getUsername(), 0644) + + if !doAll { + break + } + fallthrough + case 5: + writeFile("/etc/xdg/nvim/sysinit.vim", sysinitVim, "root", 0644) + + if !doAll { + break + } + fallthrough + case 6: + err := os.Mkdir("/home/"+getUsername()+"/.config/zed", 0755) + if err != nil { + other.PrintError("Failed to create zed config directory", 1) + } + writeFile("/home/"+getUsername()+"/.config/zed/settings.json", zed, getUsername(), 0600) + + if !doAll { + break + } + fallthrough + case 7: + writeFile("/etc/makepkg.conf", makepkg, "root", 0644) + + if !doAll { + break + } + fallthrough + case 8: + cmd := exec.Command("pacman", "-S", "pacman-contrib", "--noconfirm") + err := cmd.Run() + if err != nil { + other.PrintError("Failed to install pacman-contrib", 1) + } + writeFile("/etc/pacman.conf", pacman, "root", 0644) + writeFile("/etc/pacman.d/hooks/paccache-clean.hook", pacmanHookClean, "root", 0644) + writeFile("/etc/pacman.d/hooks/nvidia.hook", pacmanHookNvidia, "root", 0644) + } + } +} + +const shellProfile = `#!/bin/sh + +# WAYLAND ENV +export WAYLAND_PROTOCOLS_DATADIR="/usr/share/wayland-protocols" +export ELECTRON_OZONE_PLATFORM_HINT=auto + +# XDG BASE ENV +export XDG_DATA_HOME="$HOME"/.local/share +export XDG_CONFIG_HOME="$HOME"/.config +export XDG_STATE_HOME="$HOME"/.local/state +export XDG_CACHE_HOME="$HOME"/.cache + +# DOTFILE MANAGEMENT +export CUDA_CACHE_PATH="$XDG_CACHE_HOME"/nv +export GTK2_RC_FILES="$XDG_CONFIG_HOME"/gtk-2.0/gtkrc +export LESSHISTFILE="$XDG_CACHE_HOME"/less/history +export WINEPREFIX="$XDG_DATA_HOME"/wine +export ANDROID_USER_HOME="$XDG_DATA_HOME"/android +export _JAVA_OPTIONS=-Djava.util.prefs.userRoot="$XDG_CONFIG_HOME"/java +export CARGO_HOME="$XDG_DATA_HOME"/cargo +export RUSTUP_HOME="$XDG_DATA_HOME"/rustup + +# GO SETTINGS +export GOPATH="$XDG_DATA_HOME"/go +export CGO_ENABLED=1 +export GOFLAGS='-trimpath "-ldflags=-s -w" -buildvcs=false' +export GOAMD64=v3 + +# PROTON SETTINGS +export PROTON_USE_NTSYNC=1 +export PROTON_ENABLE_WAYLAND=1 +#export WAYLANDDRV_PRIMARY_MONITOR=DP-3 +#export FSR4_UPGRADE=1 + +# MISC SETTINGS +export EDITOR=nvim +export BUILDDIR=/tmp/makepkg` + +const zshrc = `# Shell settings +HISTFILE="$XDG_CACHE_HOME"/zsh-histfile +HISTSIZE=2500 +SAVEHIST=2000 +setopt INC_APPEND_HISTORY +setopt HIST_EXPIRE_DUPS_FIRST +setopt HIST_FIND_NO_DUPS +unsetopt beep +bindkey -e +zstyle :compinstall filename "/home/$USER/.zshrc" +autoload -Uz compinit +compinit -d "$XDG_CACHE_HOME"/zcompdump +PS1='%F{yellow}%?%F{cyan}|%n%f@%F{cyan}%m:%f%1~%f%F{cyan}|%#%f ' +source /usr/share/zsh/plugins/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh +source /usr/share/zsh/plugins/zsh-autosuggestions/zsh-autosuggestions.zsh +bindkey '^[[H' beginning-of-line +bindkey '^[[F' end-of-line +bindkey '^[[3~' delete-char + +# Text art on clear/new shell +art_cat='%F{#fe8019}/\_,_/\ +\ 0 0 /%f' +art_dog=' %F{#d79921}/___/ +| 6.6 |%f' +art_bear='%F{#d65d0e}() () +(o.o)%f' +art_snail=' %F{#689d6a}|_/ +/o o\%f' +art_bunny=' %F{#d5c4a1}/_/ +|^.^|' +art_jellyfish='%F{#83a598}<===> +//|\\%f' +art_school=' %F{#fe8019}<°))>< %F{#fabd2f}><(((.> +%F{#8ec07c}><(((°> %F{#d3869b}><((((°>%f' +art_array=("$art_cat" "$art_dog" "$art_bear" "$art_snail" "$art_bunny" "$art_jellyfish" "$art_school") +print -Pr "$art_array[$((RANDOM%7+1))]" +function term_clear() { + clear + print -Pr "$art_array[$((RANDOM%7+1))]" + print -Pn $PS1 +} +zle -N zsh-redraw term_clear +bindkey "^L" zsh-redraw + +# Stock aliases +alias ls='ls --color=auto' +alias grep='grep --color=auto' +alias fastfetch='fastfetch -c neofetch' +alias unmv='setopt shwordsplit && lastCmdSplit=(${(@s/ /)$(fc -ln -1)}) && newCmd="mv ${lastCmdSplit[3]} ${lastCmdSplit[2]}" && $newCmd && unsetopt shwordsplit' +alias orphans='doas pacman -Rcns $(pacman -Qqdt)' +alias powersave='doas /usr/local/bin/powerset.sh powersave' +alias performance='doas /usr/local/bin/powerset.sh performance' +alias schedutil='doas /usr/local/bin/powerset.sh schedutil' +alias poweroff='doas /usr/bin/poweroff' +alias reboot='doas /usr/bin/reboot'` + +const sysinitVim = `" rwinkhart/cachyos-postinstall-helper 09/28/2025 + +" ensure correct basic settings +set fileencoding=utf-8 + +" show line numbers +set number + +" enable basic spellchecking +set spell + +" set keybinds (home/end, delete w/o copy) +noremap +imap +noremap +imap +nnoremap x "_x +nnoremap "_x + +" expand all tabs and indents to 4 spaces +set tabstop=4 +set shiftwidth=4 +set expandtab +autocmd FileType go,html,php,css set noexpandtab + +" set default clipboard register to system clipboard +set clipboard=unnamedplus + +" enable visually indented text wrapping +set wrap +set breakindent +set showbreak=→ + +" do not auto-break lines unless they are 1000+ characters long +set textwidth=1000 + +" do not create automatic backups of any sort +set nobackup +set nowritebackup + +" default to case insensitive search unless a capital is typed +set ignorecase +set smartcase + +" tell vim to remember certain things when exited +" '10 : marks will be remembered for up to 10 previously edited files +" "100 : will save up to 100 lines for each register +" :20 : up to 20 lines of command-line history will be remembered +" % : saves and restores the buffer list +" n... : where to save the viminfo files +set viminfo='10,\"100,:20,%,n~/.local/share/nviminfo + +" restores cursor position in recently opened files +function! ResCur() + if line("'\"") <= line("$")` + + "\nnormal! g`" + `" + return 1 + endif +endfunction + +augroup resCur + autocmd! + autocmd BufWinEnter * call ResCur() +augroup END` + +const zed = `{ + // rwinkhart/cachyos-postinstall-helper 09/28/2025 + + // AI Settings + "telemetry": { + "metrics": false, + "diagnostics": false + }, + "edit_predictions": { + "mode": "subtle", + "enabled_in_text_threads": false + }, + "show_edit_predictions": true, + "agent": { + "default_profile": "ask", + "default_model": { + "provider": "copilot_chat", + "model": "claude-sonnet-4" + } + }, + "features": { + "edit_prediction_provider": "copilot" + }, + // General Settings + "minimap": { + "show": "always" + }, + "icon_theme": "JetBrains New UI Icons (Dark)", + "middle_click_paste": false, + "base_keymap": "VSCode", + "autosave": "off", + "theme": "Gruvbox Dark", + "ui_font_size": 14, + "buffer_font_size": 18, + "auto_update": false, + "terminal": { + "shell": { + "program": "zsh" + } + }, + "tab_size": 4, + "preferred_line_length": 120, + "git": { + "inline_blame": { + "enabled": false + } + }, + // Language-specific Settings + "languages": { + "Python": { + "soft_wrap": "preferred_line_length" + }, + "Go": { + "hard_tabs": true + }, + "JavaScript": { + "format_on_save": "off" + }, + "CSS": { + "format_on_save": "off" + } + }, + // De-clutter UI + "tab_bar": { + "show_nav_history_buttons": false + }, + "search": { + "button": false + }, + "title_bar": { + "show_branch_name": false + }, + "notification_panel": { + "button": false + }, + "collaboration_panel": { + "button": false + }, + "git_panel": { + "button": false + } +}` + +const makepkg = `#!/hint/bash +# +# /etc/makepkg.conf - rwinkhart/cachyos-postinstall-helper 09/28/2025 +# + +######################################################################### +# SOURCE ACQUISITION +######################################################################### +# +#-- The download utilities that makepkg should use to acquire sources +# Format: 'protocol::agent' +DLAGENTS=('file::/usr/bin/curl -qgC - -o %o %u' + 'ftp::/usr/bin/curl -qgfC - --ftp-pasv --retry 3 --retry-delay 3 -o %o %u' + 'http::/usr/bin/curl -qgb "" -fLC - --retry 3 --retry-delay 3 -o %o %u' + 'https::/usr/bin/curl -qgb "" -fLC - --retry 3 --retry-delay 3 -o %o %u' + 'rsync::/usr/bin/rsync --no-motd -z %u %o' + 'scp::/usr/bin/scp -C %u %o') + +# Other common tools: +# /usr/bin/snarf +# /usr/bin/lftpget -c +# /usr/bin/wget + +#-- The package required by makepkg to download VCS sources +# Format: 'protocol::package' +VCSCLIENTS=('bzr::breezy' + 'fossil::fossil' + 'git::git' + 'hg::mercurial' + 'svn::subversion') + +######################################################################### +# ARCHITECTURE, COMPILE FLAGS +######################################################################### +# +CARCH="x86_64" +CHOST="x86_64-pc-linux-gnu" + +#-- Compiler and Linker Flags +#CPPFLAGS="" +CFLAGS="-march=native -mtune=native -O3 -pipe -fno-plt -fexceptions \ + -Wp,-D_FORTIFY_SOURCE=3 -Wformat -Werror=format-security \ + -fstack-clash-protection -fcf-protection \ + -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer" +CXXFLAGS="$CFLAGS -Wp,-D_GLIBCXX_ASSERTIONS" +LDFLAGS="-Wl,-O3 -Wl,--sort-common -Wl,--as-needed -Wl,-z,relro -Wl,-z,now \ + -Wl,-z,pack-relative-relocs" +LTOFLAGS="-flto=auto" +#-- Make Flags: change this for DistCC/SMP systems +MAKEFLAGS="-j$(nproc)" +NINJAFLAGS="-j$(nproc)" +#-- Debugging flags +DEBUG_CFLAGS="-g" +DEBUG_CXXFLAGS="$DEBUG_CFLAGS" + +######################################################################### +# BUILD ENVIRONMENT +######################################################################### +# +# Makepkg defaults: BUILDENV=(!distcc !color !ccache check !sign) +# A negated environment option will do the opposite of the comments below. +# +#-- distcc: Use the Distributed C/C++/ObjC compiler +#-- color: Colorize output messages +#-- ccache: Use ccache to cache compilation +#-- check: Run the check() function if present in the PKGBUILD +#-- sign: Generate PGP signature file +# +BUILDENV=(!distcc color !ccache check !sign) +# +#-- If using DistCC, your MAKEFLAGS will also need modification. In addition, +#-- specify a space-delimited list of hosts running in the DistCC cluster. +#DISTCC_HOSTS="" +# +#-- Specify a directory for package building. +#BUILDDIR=/tmp/makepkg + +######################################################################### +# GLOBAL PACKAGE OPTIONS +# These are default values for the options=() settings +######################################################################### +# +# Makepkg defaults: OPTIONS=(!strip docs libtool staticlibs emptydirs !zipman !purge !debug !lto !autodeps) +# A negated option will do the opposite of the comments below. +# +#-- strip: Strip symbols from binaries/libraries +#-- docs: Save doc directories specified by DOC_DIRS +#-- libtool: Leave libtool (.la) files in packages +#-- staticlibs: Leave static library (.a) files in packages +#-- emptydirs: Leave empty directories in packages +#-- zipman: Compress manual (man and info) pages in MAN_DIRS with gzip +#-- purge: Remove files specified by PURGE_TARGETS +#-- debug: Add debugging flags as specified in DEBUG_* variables +#-- lto: Add compile flags for building with link time optimization +#-- autodeps: Automatically add depends/provides +# +OPTIONS=(strip docs !libtool !staticlibs emptydirs zipman purge !debug lto) + +#-- File integrity checks to use. Valid: md5, sha1, sha224, sha256, sha384, sha512, b2 +INTEGRITY_CHECK=(sha256) +#-- Options to be used when stripping binaries. See "man strip" for details. +STRIP_BINARIES="--strip-all" +#-- Options to be used when stripping shared libraries. See "man strip" for details. +STRIP_SHARED="--strip-unneeded" +#-- Options to be used when stripping static libraries. See "man strip" for details. +STRIP_STATIC="--strip-debug" +#-- Manual (man and info) directories to compress (if zipman is specified) +MAN_DIRS=({usr{,/local}{,/share},opt/*}/{man,info}) +#-- Doc directories to remove (if !docs is specified) +DOC_DIRS=(usr/{,local/}{,share/}{doc,gtk-doc} opt/*/{doc,gtk-doc}) +#-- Files to be removed from all packages (if purge is specified) +PURGE_TARGETS=(usr/{,share}/info/dir .packlist *.pod) +#-- Directory to store source code in for debug packages +DBGSRCDIR="/usr/src/debug" +#-- Prefix and directories for library autodeps +LIB_DIRS=('lib:usr/lib' 'lib32:usr/lib32') + +######################################################################### +# PACKAGE OUTPUT +######################################################################### +# +# Default: put built package and cached source in build directory +# +#-- Destination: specify a fixed directory where all packages will be placed +#PKGDEST=/home/packages +#-- Source cache: specify a fixed directory where source files will be cached +#SRCDEST=/home/sources +#-- Source packages: specify a fixed directory where all src packages will be placed +#SRCPKGDEST=/home/srcpackages +#-- Log files: specify a fixed directory where all log files will be placed +#LOGDEST=/home/makepkglogs +#-- Packager: name/email of the person or organization building packages +#PACKAGER="John Doe " +#-- Specify a key to use for package signing +#GPGKEY="" + +######################################################################### +# COMPRESSION DEFAULTS +######################################################################### +# +COMPRESSGZ=(gzip -c -f -n) +COMPRESSBZ2=(bzip2 -c -f) +COMPRESSXZ=(xz -c -z -e6 --threads=0 -) +COMPRESSZST=(zstd -c -z -q --threads=0 -) +COMPRESSLRZ=(lrzip -q) +COMPRESSLZO=(lzop -q) +COMPRESSZ=(compress -c -f) +COMPRESSLZ4=(lz4 -q) +COMPRESSLZ=(lzip -c -f) + +######################################################################### +# EXTENSION DEFAULTS +######################################################################### +# +PKGEXT='.pkg.tar.xz' +SRCEXT='.src.tar.gz' + +######################################################################### +# OTHER +######################################################################### +# +#-- Command used to run pacman as root, instead of trying sudo and su +PACMAN_AUTH=(doas)` + +const makepkgRS = `#!/hint/bash +# +# /etc/makepkg.conf.d/rust.conf - rwinkhart/cachyos-postinstall-helper 09/28/2025 +# + +######################################################################### +# RUST LANGUAGE SUPPORT +######################################################################### + +# Flags used for the Rust compiler, similar in spirit to CFLAGS. Read +# linkman:rustc[1] for more details on the available flags. +RUSTFLAGS="-Cforce-frame-pointers=yes -C opt-level=3 -C target-cpu=native" + +# Additional compiler flags appended to "RUSTFLAGS" for use in debugging. +# Read linkman:rustc[1] for more details on the available flags. +DEBUG_RUSTFLAGS="-C debuginfo=2"` + +const pacman = `# /etc/pacman.conf - rwinkhart/cachyos-postinstall-helper 09/28/2025 + +# See the pacman.conf(5) manpage for option and repository directives + +# GENERAL OPTIONS +[options] +# The following paths are commented out with their default values listed. +# If you wish to use different paths, uncomment and update the paths. +#RootDir = / +#DBPath = /var/lib/pacman/ +#CacheDir = /var/cache/pacman/pkg/ +#LogFile = /var/log/pacman.log +#GPGDir = /etc/pacman.d/gnupg/ +#HookDir = /etc/pacman.d/hooks/ +HoldPkg = pacman glibc +#XferCommand = /usr/bin/curl -L -C - -f -o %o %u +#XferCommand = /usr/bin/wget --passive-ftp -c -O %o %u +#CleanMethod = KeepInstalled +#UseDelta = 0.7 +Architecture = auto + +# Pacman won't upgrade packages listed in IgnorePkg and members of IgnoreGroup +#IgnorePkg = +#IgnoreGroup = + +#NoUpgrade = +#NoExtract = + +# Misc options +#UseSyslog +Color +ILoveCandy +#NoProgressBar +CheckSpace +#VerbosePkgLists +DisableDownloadTimeout +ParallelDownloads = 10 +DownloadUser = alpm +#DisableSandbox + +# By default, pacman accepts packages signed by keys that its local keyring +# trusts (see pacman-key and its man page), as well as unsigned packages. +SigLevel = Required DatabaseOptional +LocalFileSigLevel = Optional +#RemoteFileSigLevel = Required + +# NOTE: You must run "pacman-key --init" before first using pacman; the local +# keyring can then be populated with the keys of all official Arch Linux +# packagers with "pacman-key --populate archlinux". + +# +# REPOSITORIES +# - can be defined here or included from another file +# - pacman will search repositories in the order defined here +# - local/custom mirrors can be added here or in separate files +# - repositories listed first will take precedence when packages +# have identical names, regardless of version number +# - URLs will have $repo replaced by the name of the current repo +# - URLs will have $arch replaced by the name of the architecture +# +# Repository entries are of the format: +# [repo-name] +# Server = ServerName +# Include = IncludePath +# +# The header [repo-name] is crucial - it must be present and +# uncommented to enable the repo. +# + +# cachyos repos +[cachyos-v3] +Include = /etc/pacman.d/cachyos-v3-mirrorlist + +[cachyos-core-v3] +Include = /etc/pacman.d/cachyos-v3-mirrorlist + +[cachyos-extra-v3] +Include = /etc/pacman.d/cachyos-v3-mirrorlist + +[cachyos] +Include = /etc/pacman.d/cachyos-mirrorlist + +# The testing repositories are disabled by default. To enable, uncomment the +# repo name header and Include lines. You can add preferred servers immediately +# after the header, and they will be used before the default mirrors. + +#[core-testing] +#Include = /etc/pacman.d/mirrorlist + +[core] +Include = /etc/pacman.d/mirrorlist + +#[extra-testing] +#Include = /etc/pacman.d/mirrorlist + +[extra] +Include = /etc/pacman.d/mirrorlist + +# If you want to run 32 bit applications on your x86_64 system, +# enable the multilib repositories as required here. + +#[multilib-testing] +#Include = /etc/pacman.d/mirrorlist + +[multilib] +Include = /etc/pacman.d/mirrorlist + +# An example of a custom package repository. See the pacman manpage for +# tips on creating your own repositories. +#[custom] +#SigLevel = Optional TrustAll +#Server = file:///home/custompkgs` + +const pacmanHookClean = `[Trigger] +Operation = Remove +Operation = Install +Operation = Upgrade +Type = Package +Target = * + +[Action] +Description = Keep the last cache and the currently installed. +When = PostTransaction +Exec = /usr/bin/paccache -rvk2` + +const pacmanHookNvidia = `[Trigger] +Operation=Install +Operation=Upgrade +Operation=Remove +Type=Package +Target=nvidia-open +Target=linux-cachyos + +[Action] +Description=Update Nvidia module in initcpio +Depends=mkinitcpio +When=PostTransaction +NeedsTargets +Exec=/bin/sh -c 'while read -r trg; do case $trg in linux) exit 0; esac; done; /usr/bin/mkinitcpio -P'` diff --git a/cosmic.go b/cosmic.go new file mode 100644 index 0000000..438d9e6 --- /dev/null +++ b/cosmic.go @@ -0,0 +1,45 @@ +package main + +import ( + "os/exec" + + "github.com/rwinkhart/go-boilerplate/other" +) + +func cosmic() { + version := "/v1/" + filenamesToValues := map[string]string{ + "AppList" + version + "enable_drag_source": "true", + "AppList" + version + "favorites": "[\n com.system76.CosmicFiles\n]", + "Comp" + version + "autotile_behavior": "PerWorkspace", + "Comp" + version + "cursor_follows_focus": "false", + "Comp" + version + "focus_follows_cursor": "true", + "Comp" + version + "input_default": "(\n state: Enabled,\n acceleration: Some((\n profile: Some(Flat),\n speed: 0.0,\n )),\n)", + "Comp" + version + "workspaces": "(\n workspace_mode: Global,\n workspace_layout: Vertical,\n)", + "Panel" + version + "entries": "[\n \"Panel\",\n]", + "Panel.Panel" + version + "anchor_gap": "true", + "Panel.Panel" + version + "border_radius": "10", + "Panel.Panel" + version + "exclusive_zone": "true", + "Panel.Panel" + version + "expand_to_edges": "false", + "Panel.Panel" + version + "opacity": "0.75", + "Panel.Panel" + version + "plugins_center": "Some([])", + "Panel.Panel" + version + "plugins_wings": "Some(([\n \"com.system76.CosmicAppList\",\n], [\n \"com.system76.CosmicAppletStatusArea\",\n \"com.system76.CosmicAppletTiling\",\n \"com.system76.CosmicAppletAudio\",\n \"com.system76.CosmicAppletBluetooth\",\n \"com.system76.CosmicAppletNetwork\",\n \"com.system76.CosmicAppletBattery\",\n \"com.system76.CosmicAppletNotifications\",\n \"com.system76.CosmicAppletPower\",\n \"com.system76.CosmicAppletTime\",\n]))", + "Panel.Panel" + version + "size": "XS", + "Tk" + version + "show_maximize": "false"} + + for key, value := range filenamesToValues { + filePath := "/home/" + getUsername() + "/.config/" + key + writeFile(filePath, value, getUsername(), 0755) + } + + // Replace SDDM with cosmic-greeter + writeFile("/etc/greetd/config.toml", "[terminal]\nvt = 1\n\n[default_session]\ncommand = \"cosmic-comp /bin/cosmic-greeter\"\nuser = \"cosmic-greeter\"", "root", 0644) + manageService("stop", "sddm.service") + manageService("disable", "sddm.service") + manageService("enable", "greetd.service") + cmd := exec.Command("pacman", "-Rcns", "sddm", "--noconfirm") + err := cmd.Run() + if err != nil { + other.PrintError("Failed to remove SDDM", 1) + } +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..cee071b --- /dev/null +++ b/go.mod @@ -0,0 +1,10 @@ +module cachy-post + +go 1.25.1 + +require github.com/rwinkhart/go-boilerplate v0.1.0 + +require ( + golang.org/x/sys v0.33.0 // indirect + golang.org/x/term v0.32.0 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..eeff877 --- /dev/null +++ b/go.sum @@ -0,0 +1,6 @@ +github.com/rwinkhart/go-boilerplate v0.1.0 h1:EzlVj6R7Bxtl79Nl7R5zRcg6s+Cf2FAqGIzR4giWTQg= +github.com/rwinkhart/go-boilerplate v0.1.0/go.mod h1:cnzIF45I0FCOvE4YIB+26pLCUx2kWyY2llKYZruNaRY= +golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= +golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/term v0.32.0 h1:DR4lr0TjUs3epypdhTOkMmuF5CDFJ/8pOnbzMZPQ7bg= +golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ= diff --git a/main.go b/main.go new file mode 100644 index 0000000..61457b4 --- /dev/null +++ b/main.go @@ -0,0 +1,44 @@ +package main + +import ( + "os/user" + + "github.com/rwinkhart/go-boilerplate/front" + "github.com/rwinkhart/go-boilerplate/other" +) + +var username string + +// TODO add mode to perform EVERYTHING +func main() { + userInfo, err := user.Current() + if err != nil { + other.PrintError("Failed to get current user", 1) + } + if userInfo.Uid != "0" { + other.PrintError("This utility must be run as root", 1) + } + + for { + choice := front.InputMenuGen("Option:", []string{"universal tweaks", "system tweaks", "removals", "applications", "configuration", "cosmic"}) + switch choice { + case 1: + universalTweaks() + case 2: + system() + case 3: + removals() + // TODO remove config/data + case 4: + applications() + // TODO remove config/data for replacements + case 5: + configurations() + case 6: + cosmic() + // TODO keyboard shortcuts for screenshot/sticky window/terminal + // TODO window decoration position (not yet implemented?) + // TODO link CachyOS wallpapers? + } + } +} diff --git a/removals.go b/removals.go new file mode 100644 index 0000000..7f9fa4d --- /dev/null +++ b/removals.go @@ -0,0 +1,48 @@ +package main + +import ( + "os/exec" + + "github.com/rwinkhart/go-boilerplate/front" + "github.com/rwinkhart/go-boilerplate/other" +) + +func removals() { + for { + var doAll bool + choice := front.InputMenuGen("Application to remove:", []string{"back", "all", "alacritty", "pavucontrol", "bash", "linux-cachyos-lts", "ufw", "modemmanager"}) + var target string + switch choice { + case 1: + return + case 2: + cmd := exec.Command("pacman", "-Rcns", "back", "alacritty", "pavucontrol", "bash", "linux-cachyos-lts", "ufw", "modemmanager", "--noconfirm") + err := cmd.Run() + if err != nil { + other.PrintError("Failed to perform application removals", 1) + } + doAll = true + case 3: + target = "alacritty" + case 4: + target = "pavucontrol" + case 5: + target = "bash" + case 6: + target = "linux-cachyos-lts" + case 7: + target = "ufw" + manageService("stop", "ufw.service") + manageService("disable", "ufw.service") + case 8: + target = "modemmanager" + } + if !doAll { + cmd := exec.Command("pacman", "-Rcns", target, "--noconfirm") + err := cmd.Run() + if err != nil { + other.PrintError("Failed to remove "+target, 1) + } + } + } +} diff --git a/system.go b/system.go new file mode 100644 index 0000000..eed9ae3 --- /dev/null +++ b/system.go @@ -0,0 +1,158 @@ +package main + +import ( + "bufio" + "os" + "os/exec" + "strings" + + "github.com/rwinkhart/go-boilerplate/front" + "github.com/rwinkhart/go-boilerplate/other" +) + +func system() { + for { + var doAll bool + choice := front.InputMenuGen("Tweak:", []string{"back", "all", "replace sudo with doas", "enable ipv6 privacy extensions", "enable ext4 fast_commit", "enable SysRq reboots", "disable kernel security mitigations", "unlock amdgpu tuning", "enable amd_pstate in passive mode (recommended for zenver2)"}) + switch choice { + case 1: + return + case 2: + doAll = true + fallthrough + case 3: + writeFile("/etc/doas.conf", "permit persist keepenv :wheel as root", "root", 0644) + writeFile("/tmp/PKGBUILD", `# Maintainer: Arch Linux Team +# Contributor: Levente Polyak + +pkgname=base-devel +pkgver=1 +pkgrel=2 +pkgdesc='Basic tools to build Arch Linux packages' +url='https://www.archlinux.org' +arch=('any') +license=('GPL') +options=('!debug') +depends=( + archlinux-keyring + autoconf + automake + binutils + bison + debugedit + fakeroot + file + findutils + flex + gawk + gcc + gettext + grep + groff + gzip + libtool + m4 + make + pacman + pacman-contrib + patch + pkgconf + sed + opendoas + texinfo + which +) + +# vim: ts=2 sw=2 et: +`, "nobody", 0777) + cmd := exec.Command("sudo", "-u", "nobody", "makepkg", "-si", "--dir", "/tmp") + err := cmd.Run() + if err != nil { + other.PrintError("Failed to build+install custom base-devel", 1) + } + cmd = exec.Command("pacman", "-S", "opendoas", "--noconfirm") + err = cmd.Run() + if err != nil { + other.PrintError("Failed to install opendoas", 1) + } + cmd = exec.Command("pacman", "-R", "sudo", "--noconfirm") + err = cmd.Run() + if err != nil { + other.PrintError("Failed to remove sudo", 1) + } + + if !doAll { + break + } + fallthrough + case 4: + nics, err := os.ReadDir("/sys/class/net") + if err != nil { + other.PrintError("Failed to retrieve NICs", 1) + } + var sysctlConf strings.Builder + sysctlConf.WriteString("net.ipv6.conf.all.use_tempaddr = 2\nnet.ipv6.conf.default.use_tempaddr = 2") + for _, nic := range nics { + sysctlConf.WriteString("\nnet.ipv6.conf." + nic.Name() + "use_tempaddr = 2") + } + writeFile("/etc/sysctl.d/40-ipv6-priv-ext.conf", sysctlConf.String(), "root", 0644) + + if !doAll { + break + } + fallthrough + case 5: + cmd := exec.Command("tune2fs", "-O", "fast_commit", front.Input("/dev/driveparition:")) + err := cmd.Run() + if err != nil { + other.PrintError("Failed to enable fast_commit", 1) + } + + if !doAll { + break + } + fallthrough + case 6: + writeFile("/etc/sysctl.d/35-sysrq.conf", "kernel.sysrq = 244", "root", 0644) + + if !doAll { + break + } + fallthrough + case 7: + addKernelParams([]string{"mitigations=off"}) + + if !doAll { + break + } + fallthrough + case 8: + addKernelParams([]string{"amdgpu.ppfeaturemask=0xffffffff"}) + + if !doAll { + break + } + fallthrough + case 9: + addKernelParams([]string{"amd_pstate=passive"}) + } + } +} + +func addKernelParams(newParameters []string) { + f, err := os.Open("/boot/loader/entries/linux-cachyos.conf") + if err != nil { + other.PrintError("Failed to open systemd-boot entry", 1) + } + fScanner := bufio.NewScanner(f) + fScanner.Split(bufio.ScanLines) + var parameters []string + for i := 0; fScanner.Scan(); i++ { + if i == 1 { + parameters = strings.Split(fScanner.Text(), " ")[2:] + break + } + } + parameters = append(parameters, newParameters...) + writeFile("/boot/loader/entries/linux-cachyos.conf", "title Linux Cachyos\noptions root=UUID=e2ff600b-0202-4620-bed3-54d7a58414f8 "+strings.Join(parameters, " ")+"\nlinux /vmlinuz-linux-cachyos\ninitrd /initramfs-linux-cachyos.img", "root", 0700) +} diff --git a/universalTweaks.go b/universalTweaks.go new file mode 100644 index 0000000..dece272 --- /dev/null +++ b/universalTweaks.go @@ -0,0 +1,28 @@ +package main + +import ( + "os" + "os/exec" + + "github.com/rwinkhart/go-boilerplate/other" +) + +func universalTweaks() { + // Lock root account + cmd := exec.Command("usermod", "--delete", "root") + cmd.Run() + cmd = exec.Command("usermod", "--lock", "root") + cmd.Run() + + // Add user to uucp group for non-root serial console usage + cmd = exec.Command("usermod", "-aG", "uucp", getUsername()) + cmd.Run() + + // Force disable kernel watchdog (kernel parameters should do this as well) + f, err := os.Create("/etc/modprobe.d/blacklist.conf") + if err != nil { + other.PrintError("Failed to create /etc/modprobe.d/blacklist.conf", 1) + } + f.WriteString("#Disable kernel watchdog\nblacklist iTCO_wdt") + f.Close() +} diff --git a/utilities.go b/utilities.go new file mode 100644 index 0000000..059a098 --- /dev/null +++ b/utilities.go @@ -0,0 +1,53 @@ +package main + +import ( + "os" + "os/exec" + "os/user" + "strconv" + + "github.com/rwinkhart/go-boilerplate/front" + "github.com/rwinkhart/go-boilerplate/other" +) + +func manageService(action, service string) { + cmd := exec.Command("systemctl", "daemon-reload") + err := cmd.Run() + if err != nil { + other.PrintError("Failed to perform daemon-reload", 1) + } + cmd = exec.Command("systemctl", action, service) + err = cmd.Run() + if err != nil { + other.PrintError("Failed to "+action+" "+service, 1) + } +} + +func writeFile(path, data, owner string, perms os.FileMode) { + err := os.WriteFile(path, []byte(data), perms) + if err != nil { + other.PrintError("Failed to write to "+path, 1) + } + if owner != "root" { + userInfo, err := user.Lookup(owner) + if err != nil { + other.PrintError("Failed to lookup UID for "+owner, 1) + } + uid, err := strconv.Atoi(userInfo.Uid) + if err != nil { + other.PrintError("Failed to convert UID to integer", 1) + } + err = os.Chown(path, uid, uid) + if err != nil { + other.PrintError("Failed to set ownership of "+path, 1) + } + } +} + +func getUsername() string { + if username == "" { + username = front.Input("Non-root username:") + } + localUsername := username + return localUsername +}