Compare commits

..

16 Commits

Author SHA1 Message Date
MangoPig
1e2515a21a Fedora Fix 2026-05-31 20:48:18 +01:00
MangoPig
5e7031d700 Fedora Setup 2026-05-29 15:57:17 +01:00
MangoPig
ad39f07b34 Accept pnpm 2026-05-25 16:41:54 +01:00
MangoPig
689a2dc079 R Script Fix 2026-05-05 11:18:52 +01:00
MangoPig
87fb89a6b7 Azure 2025-12-11 04:55:40 +00:00
MangoPig
d41626190d Adding curl too 2025-12-09 03:31:07 +00:00
MangoPig
f359bb68eb Add Ninja to base 2025-12-09 03:29:57 +00:00
MangoPig
69f7a5d4d5 Password no interactive 2025-12-06 10:10:29 +00:00
MangoPig
b0db2dfaf6 Adding a base setup 2025-12-06 10:01:13 +00:00
MangoPig
7743665917 Cpp 2025-12-06 09:27:49 +00:00
MangoPig
3ba98e21ad Changing Location 2025-12-05 19:49:08 +00:00
MangoPig
28027b31ab Fix 2025-12-05 19:27:06 +00:00
MangoPig
75ffecbfb6 Add clean and stow to setup 2025-12-05 19:25:37 +00:00
MangoPig
d3830840c2 Forgot parts of it 2025-12-05 19:10:41 +00:00
MangoPig
ece7ac7a0b Old Package Detection 2025-12-05 19:09:46 +00:00
MangoPig
cf670488ac Python 2025-12-05 19:01:00 +00:00
35 changed files with 803 additions and 2601 deletions

View File

@@ -16,7 +16,7 @@ alias grep="grep --color=auto"
alias src="source ~/.zshrc && echo '🔄 Reloaded .zshrc'"
# alias cat="bat"
alias cat="bat"
alias fd="fd"
alias tree="eza --icons -T --git-ignore"

3
.zsh_secrets.example Normal file
View File

@@ -0,0 +1,3 @@
# .zsh_secrets
export TESTING_SECRET="HELLO THIS IS WORKING"

31
.zshenv Normal file
View File

@@ -0,0 +1,31 @@
# ENV File
export GOGC=500
# CodeGraphContext defaults
export CGC_RUNTIME_DB_TYPE=kuzudb
export KUZUDB_PATH="$HOME/.codegraphcontext/kuzudb"
export PATH=/home/mangopig/.opencode/bin:$PATH
export OPENCHAMBER_HOST=0.0.0.0
export AZURE_COGNITIVE_SERVICES_RESOURCE_NAME="$AZURE_URL"
export VAULT_ADDR="http://192.168.30.53:8200"
export OPENCHAMBER_UI_PASSWORD="$VM_SUDO_PASS"
export AZURE_RESOURCE_NAME="$AZURE_URL"
export PLANNOTATOR_PORT=9999
# OpenCode Secrets
export TAOBAO_API_KEY="sk-BCjuuzYOkaR0L1lBpcqP4N9VWnIh6XoVWghltVjBvk5GQneL"
export AZURE_OPENAI_API_KEY="6ebJTnqeDNv66eoYUmKscjb9bOmR1gE7vRcBnH9zLFnFT1Dy6a6XJQQJ99CBACfhMk5XJ3w3AAAAACOGDFaj"
export FOUNDRY_ANTHROPIC_API_KEY="$AZURE_OPENAI_API_KEY"
export CHROMA_OPENAI_API_KEY="$AZURE_OPENAI_API_KEY"
export OUTLINE_MOKU_TOKEN="ol_api_jZbStf5YaAxWlfT5fE79xgKPKW82cfUn8NaSK9"
export OUTLINE_MOKU_AUTHORIZATION="Bearer $OUTLINE_MOKU_TOKEN"
export DOKPLOY_API_KEY="CkiyeXRRImWOKeVkFAAfdoBjwHmbXoSKXNRWFwnhjKlhHnTkxBfVZDpvmXYAWgbQ"
export N8N_AUTH="725ce955821a3f92c9e85d428cd157a890c6209f254a8d31edca41ddc4b8a324"
export CONTEXT7_API_KEY="ctx7sk-3c4a0f0a-f9c4-4d45-a2a1-765f5dfa33ba"
export GITEA_ACCESS_TOKEN="51bd8f571def772ed54a3e8317189abaa7d5a1e5"
export NETDATA_TOKEN="67e9f974-be37-4bbd-9d1e-4541613fa119"
export OBSIDIAN_API_KEY="360159f3b5b72953b3dd28ebd8e24215117e67478a7333bcc6c0e43a4bfc3720"

76
.zshrc Normal file
View File

@@ -0,0 +1,76 @@
# .zshrc
# Zsh Configuration
export ZSH="$HOME/.oh-my-zsh"
PROMPT="%B%~%b :: "
RPROMPT="%n@%m"
# Plugins
plugins=(git zsh-syntax-highlighting zsh-autosuggestions sudo rclone rust nvm golang conda pyenv)
source $ZSH/oh-my-zsh.sh
# Programming Languages Root
export PROG_DIR="$HOME/.programming"
# Go and GVM (Black Box)
export GVM_ROOT="$PROG_DIR/go"
[[ -s "$GVM_ROOT/scripts/gvm" ]] && source "$GVM_ROOT/scripts/gvm"
# Node and NVM (Lazy Load)
export NVM_DIR="$PROG_DIR/node"
nvm_load() {
echo "💤 Waking up NVM..."
unset -f nvm node npm npx
[ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh"
"$@"
}
nvm() { nvm_load "nvm" "$@"; }
node() { nvm_load "node" "$@"; }
npm() { nvm_load "npm" "$@"; }
npx() { nvm_load "npx" "$@"; }
# Rust and Cargo
export RUSTUP_HOME="$PROG_DIR/rust/multirust"
export CARGO_HOME="$PROG_DIR/rust/cargo"
# Python (Pyenv + Miniconda)
export PYENV_ROOT="$PROG_DIR/python/pyenv"
export PATH="$PYENV_ROOT/bin:$PATH"
if command -v pyenv 1>/dev/null 2>&1; then
eval "$(pyenv init -)"
fi
if command -v conda >/dev/null 2>&1; then
CONDA_BASE=$(conda info --base)
[ -f "$CONDA_BASE/etc/profile.d/conda.sh" ] && source "$CONDA_BASE/etc/profile.d/conda.sh"
fi
# R and Rig
export RIG_HOME="$PROG_DIR/r"
if [ -d "$RIG_HOME/bin" ]; then
export PATH="$RIG_HOME/bin:$PATH"
fi
# Zoxide
eval "$(zoxide init --cmd cd zsh)"
# Source Aliases & Secrets
[ -f ~/.zsh_aliases ] && source ~/.zsh_aliases
[ -f ~/.zsh_secrets ] && source ~/.zsh_secrets
# Add to PATH
export PATH="$HOME/.local/bin:$CARGO_HOME/bin:$PATH"
export PATH="$GOPATH/bin:$PATH"
# opencode
if ! pgrep -f "openchamber.*7891" > /dev/null; then
openchamber --port 7891 >/dev/null 2>&1
fi
# direnv
eval "$(direnv hook zsh)"

View File

@@ -1,45 +0,0 @@
{
"nvim": {
"owner": "neovim",
"repo": "neovim",
"version": "v0.11.5",
"linux": {
"x86_64": {
"asset": "nvim-linux-x86_64.tar.gz",
"binary": "nvim-linux-x86_64/bin/nvim"
},
"aarch64": {
"asset": "nvim-linux-arm64.tar.gz",
"binary": "nvim-linux-arm64/bin/nvim"
}
},
"macos": {
"x86_64": {
"asset": "nvim-macos-x86_64.tar.gz",
"binary": "nvim-macos-x86_64/bin/nvim"
},
"aarch64": {
"asset": "nvim-macos-arm64.tar.gz",
"binary": "nvim-macos-arm64/bin/nvim"
}
}
},
"eza": {
"owner": "eza-community",
"repo": "eza",
"version": "v0.23.4",
"linux": {
"x86_64": {
"asset": "eza_x86_64-unknown-linux-gnu.tar.gz",
"binary": "eza"
},
"aarch64": {
"asset": "eza_aarch64-unknown-linux-gnu.tar.gz",
"binary": "eza"
}
},
"macos": {
"formula": "eza"
}
}
}

View File

@@ -1,22 +0,0 @@
project_root := justfile_directory()
bin_script_dir := project_root + "/Scripts/bin"
# Install all pinned repo-managed binaries into ~/.local/bin.
install-all:
bash '{{bin_script_dir}}/install.sh' --all
# Install one pinned repo-managed binary into ~/.local/bin.
install tool:
bash '{{bin_script_dir}}/install.sh' '{{tool}}'
# Update the pinned version for a binary. If no version is given, open an fzf selector when available.
update tool version='':
bash '{{bin_script_dir}}/update.sh' '{{tool}}' '{{version}}'
# List available releases for a supported binary.
list tool:
bash '{{bin_script_dir}}/update.sh' --list '{{tool}}'
# Print the currently pinned versions.
show:
cat '{{project_root}}/Bins/versions.json'

View File

@@ -1,20 +0,0 @@
project_root := justfile_directory()
scripts_dir := project_root + "/Scripts"
node:
bash '{{scripts_dir}}/node.sh'
go:
bash '{{scripts_dir}}/go.sh'
rust:
bash '{{scripts_dir}}/rust.sh'
python:
bash '{{scripts_dir}}/python.sh'
r:
bash '{{scripts_dir}}/r.sh'
cpp:
bash '{{scripts_dir}}/cpp.sh'

View File

@@ -1,23 +0,0 @@
project_root := justfile_directory()
scripts_dir := project_root + "/Scripts"
# Run the full setup flow.
all:
bash '{{scripts_dir}}/setup.sh'
# Install the base system layer only.
base:
bash '{{scripts_dir}}/base.sh'
# Stow shell files into $HOME.
stow:
bash '{{scripts_dir}}/setup.sh' --stow-only
# Remove stowed shell files from $HOME.
clean:
stow --dir='{{project_root}}' -D Zsh --target="$HOME"
# Pull latest changes and rerun setup.
update:
git -C '{{project_root}}' pull origin main
just --justfile '{{project_root}}/Justfile' setup all

View File

@@ -1,59 +0,0 @@
set shell := ["bash", "-cu"]
project_root := justfile_directory()
scripts_dir := project_root + "/Scripts"
bin_script_dir := scripts_dir + "/bin"
help:
@printf '%s\n' \
'Dot-Zsh commands:' \
'' \
' just setup all # full setup flow' \
' just setup base # base layer only' \
' just setup stow # stow Zsh files into $HOME' \
' just setup clean # remove stowed Zsh files from $HOME' \
' just setup update # git pull + full setup' \
'' \
' just lang node # install Node tooling' \
' just lang go # install Go tooling' \
' just lang rust # install Rust tooling' \
' just lang python # install Python tooling' \
' just lang r # install R tooling' \
' just lang cpp # install C/C++ tooling' \
'' \
' just bin install-all # install all pinned binaries' \
' just bin install nvim # install one pinned binary' \
' just bin update nvim # update pinned version for a binary' \
' just bin list nvim # list available releases' \
' just bin show # print current pinned versions'
setup action='all':
case '{{action}}' in \
all) bash '{{scripts_dir}}/setup.sh' ;; \
base) bash '{{scripts_dir}}/base.sh' ;; \
stow) bash '{{scripts_dir}}/setup.sh' --stow-only ;; \
clean) stow --dir='{{project_root}}' -D Zsh --target="$HOME" ;; \
update) git -C '{{project_root}}' pull origin main && just --justfile '{{project_root}}/Justfile' setup all ;; \
*) printf 'Unknown setup action: %s\n' '{{action}}' >&2; exit 1 ;; \
esac
lang tool:
case '{{tool}}' in \
node) bash '{{scripts_dir}}/node.sh' ;; \
go) bash '{{scripts_dir}}/go.sh' ;; \
rust) bash '{{scripts_dir}}/rust.sh' ;; \
python) bash '{{scripts_dir}}/python.sh' ;; \
r) bash '{{scripts_dir}}/r.sh' ;; \
cpp) bash '{{scripts_dir}}/cpp.sh' ;; \
*) printf 'Unknown language target: %s\n' '{{tool}}' >&2; exit 1 ;; \
esac
bin action='show' tool='' version='':
case '{{action}}' in \
install-all) bash '{{bin_script_dir}}/install.sh' --all ;; \
install) [ -n '{{tool}}' ] || { printf 'bin install requires a tool name\n' >&2; exit 1; }; bash '{{bin_script_dir}}/install.sh' '{{tool}}' ;; \
update) [ -n '{{tool}}' ] || { printf 'bin update requires a tool name\n' >&2; exit 1; }; bash '{{bin_script_dir}}/update.sh' '{{tool}}' '{{version}}' ;; \
list) [ -n '{{tool}}' ] || { printf 'bin list requires a tool name\n' >&2; exit 1; }; bash '{{bin_script_dir}}/update.sh' --list '{{tool}}' ;; \
show) cat '{{project_root}}/Bins/versions.json' ;; \
*) printf 'Unknown bin action: %s\n' '{{action}}' >&2; exit 1 ;; \
esac

View File

@@ -1,11 +1,96 @@
# Makefile
SCRIPTS_DIR := ./Scripts
REBOOT_MARKER := .setup-reboot-required
# Default target
all: setup
all: stow
# Bootstrap entrypoint for first-run setup.
# This intentionally keeps Make lightweight: base packages, then restow dotfiles.
# Full Setup
setup:
bash $(SCRIPTS_DIR)/setup.sh --bootstrap-only
@set -e; \
rm -f $(REBOOT_MARKER); \
bash ./scripts/base.sh; \
if [ -f $(REBOOT_MARKER) ]; then \
rm -f $(REBOOT_MARKER); \
echo "Package layering finished. Reboot, then rerun make setup."; \
exit 0; \
fi; \
bash ./scripts/node.sh; \
bash ./scripts/go.sh; \
bash ./scripts/rust.sh; \
bash ./scripts/python.sh; \
if [ -f $(REBOOT_MARKER) ]; then \
rm -f $(REBOOT_MARKER); \
echo "Package layering finished. Reboot, then rerun make setup."; \
exit 0; \
fi; \
bash ./scripts/r.sh; \
if [ -f $(REBOOT_MARKER) ]; then \
rm -f $(REBOOT_MARKER); \
echo "Package layering finished. Reboot, then rerun make setup."; \
exit 0; \
fi; \
$(MAKE) clean; \
$(MAKE) stow; \
echo "Full setup completed."
base:
bash ./scripts/base.sh
@echo "Base setup completed."
# Just stow the dotfiles
stow:
stow . --target=$$HOME --ignore=".git" --ignore=".gitignore" --ignore="README.md" --ignore=".zsh_secrets" --ignore=".zsh_secrets.example" --ignore="LICENSE" --ignore="Makefile" --ignore="bin" --ignore="scripts"
@echo "Dotfiles linked."
# Clean old files and links
clean:
stow -D . --target=$$HOME
@echo "Links removed."
# Pull Git Updates
update:
git pull origin main
$(MAKE) setup
# Language Setups
node:
bash ./scripts/node.sh
go:
bash ./scripts/go.sh
rust:
bash ./scripts/rust.sh
python:
bash ./scripts/python.sh
r:
bash ./scripts/r.sh
cpp:
bash ./scripts/cpp.sh
storagebox:
bash ./scripts/storagebox.sh
# Docker Tests
test-ubuntu:
@echo "Ubuntu Test"
docker run -it --rm -e TERM=xterm-256color -v $(PWD):/root/dotfiles ubuntu:latest \
bash -c "export DEBIAN_FRONTEND=noninteractive && \
apt-get update && \
apt-get install -y sudo git make curl && \
cd /root/dotfiles && \
make setup"
test-arch:
@echo "Spawning Arch Container..."
docker run -it --rm -e TERM=xterm-256color -v $(PWD):/root/dotfiles archlinux:latest \
bash -c "pacman -Sy --noconfirm base-devel git make sudo && cd /root/dotfiles && make setup"
test-fedora:
@echo "Spawning Fedora Container..."
docker run -it --rm -e TERM=xterm-256color -v $(PWD):/root/dotfiles fedora:latest \
bash -c "dnf install -y git make sudo curl which passwd procps-ng && cd /root/dotfiles && make setup"

337
README.md
View File

@@ -1,337 +0,0 @@
# Dot-Zsh
Personal cross-platform shell and workstation bootstrap for:
- Arch Linux
- Ubuntu / Debian-family Linux
- Fedora
- macOS
- WSL
The repo is built around a small bootstrap path and a fuller `just`-based workflow.
---
## Layout
```text
.
├── Bins/ # Pinned binary versions (nvim, eza, ...)
├── Commands/ # just modules
├── Scripts/ # install/setup scripts
├── Zsh/ # stowed shell files
├── Justfile # main just entrypoint
└── Makefile # lightweight bootstrap entrypoint
```
### Key folders
#### `Zsh/`
Stowed into `$HOME`.
- `.zshrc`
- `.zshenv`
- `.zsh_aliases`
- `.zsh_prompt`
- `.zsh_completion`
- `.zsh_secrets`
- `.zsh_secrets.example`
#### `Scripts/`
Main install logic.
- `base.sh` — system/base packages and common tools
- `setup.sh` — full setup flow
- `node.sh`, `go.sh`, `rust.sh`, `python.sh`, `r.sh`, `cpp.sh`
- `bin/install.sh` — install pinned repo-managed binaries
- `bin/update.sh` — update pinned binary versions
#### `Commands/`
Modular `just` commands.
- `Commands/Setup/mod.just`
- `Commands/Lang/mod.just`
- `Commands/Bin/mod.just`
#### `Bins/`
`versions.json` is the source of truth for pinned binary versions and per-platform asset mappings.
---
## Core workflow
### Bootstrap only
Use `make setup` when you want the lightweight bootstrap path:
```bash
make setup
```
This currently does:
1. run `Scripts/base.sh`
2. remove old `Zsh` stow links
3. stow `Zsh/` into `$HOME`
It is intentionally small.
### Full setup
Use `just setup all` for the full machine setup:
```bash
just setup all
```
This runs the full flow in `Scripts/setup.sh`:
1. base system setup
2. node / pnpm / yarn / bun
3. go / gvm
4. rust
5. python / pyenv / miniforge
6. r
7. secret-file reconciliation
8. backup of conflicting unmanaged dotfiles
9. stow `Zsh/`
### Other useful commands
```bash
just setup base
just setup stow
just setup clean
just setup update
just lang node
just lang go
just lang rust
just lang python
just lang r
just lang cpp
just bin show
just bin install-all
just bin install nvim
just bin list nvim
just bin update nvim
```
If `fzf` is available, `just bin update <tool>` can use interactive selection.
---
## Secrets model
This repo now treats shell secrets as repo-managed local dotfiles instead of tracked plaintext config.
### Source of truth
```text
Zsh/.zsh_secrets
```
That file is intended to be stowed to:
```text
$HOME/.zsh_secrets
```
### Important notes
- `.zsh_secrets` is ignored by git
- `.zsh_secrets.example` exists as a template/reference
- setup tries to reconcile an existing `$HOME/.zsh_secrets` safely
- if conflicting unmanaged dotfiles already exist, setup backs them up before stowing
Backup location:
```text
~/.dotzsh-pre-stow-backup/<timestamp>/
```
---
## Binary management
This repo no longer stores shipped binaries in git.
Instead:
- pinned versions live in `Bins/versions.json`
- installs go into `~/.local/bin`
- updates happen through `just bin update <tool>`
Current managed binaries include:
- `nvim`
- `eza`
Platform behavior:
- Linux: install from pinned release assets
- macOS: install from pinned asset when supported, or use Homebrew formula fallback when configured
---
## Shell behavior
### Prompt
Prompt logic lives in:
```text
Zsh/.zsh_prompt
```
It adds:
- git branch
- git dirty/clean indicator
- conda / direnv context
- repo-scoped project markers
- language version hints
- separator rule between prompts
### Completion
Completion logic lives in:
```text
Zsh/.zsh_completion
```
It adds:
- custom first-word command completion
- recently used commands shown first
- used commands visually marked with `*`
- wrapper completion bindings for lazy-loaded tools like `gvm`, `conda`, `go`, `node`, `npm`, and `npx`
### Lazy loading
Several language managers are intentionally lazy-loaded to keep shell startup lighter.
Examples:
- `nvm`
- `gvm`
- `pyenv`
- `conda`
`openchamber` auto-start is restricted to WSL sessions.
---
## Install size
Measured practical installed footprint on Linux is roughly:
- Ubuntu: about `1.96 GB`
- Arch: about `1.84 GB`
- Fedora: about `1.77 GB`
So the setup is best thought of as:
```text
~1.8 GB to ~2.0 GB total
```
### Largest components
Measured Ubuntu component breakdown:
- Rust: about `1.5 GB`
- Python: about `1.1 GB`
- Go: about `635 MB`
- Node: about `235 MB`
- `~/.local`: about `128 MB`
- R wrapper/user area under `~/.programming/r`: very small (`~20 KB` in that measurement)
Important nuance:
- `~/.programming/r` is intentionally small because it mainly holds wrappers and user-library location
- the actual R runtime may still come from the distro package manager or Rig, depending on platform
- so not all R-related disk usage appears under `~/.programming/r`
### Measured paths
Representative measured path sizes from Linux test runs:
```text
Ubuntu
~/.programming ~3.17 GB
~/.local ~133 MB
/usr/local ~13 MB
Arch
~/.programming ~3.17 GB
~/.local ~133 MB
Fedora
~/.programming ~3.17 GB
~/.local ~133 MB
```
Those path totals are larger than the final container image delta because some space is shared/overlapping across package layers and installed tooling.
---
## Notes by platform
### Linux
- full setup has been exercised in container tests on Ubuntu, Arch, and Fedora x86_64
### macOS
- supports Homebrew-based package install flow
- uses `/bin/zsh` for shell-change target
- handles existing dotfiles and secret symlink reconciliation more carefully
### WSL
- WSL-specific logic is used where needed
- `openchamber` is only auto-started in WSL
---
## First-run recommendation
If you are starting clean:
```bash
make setup
just setup all
```
If you only want shell files re-linked:
```bash
just setup clean
just setup stow
```
If you only want to refresh pinned binaries:
```bash
just bin install-all
```
---
## Current philosophy
This repo aims to be:
- owned rather than magical
- reproducible rather than ad hoc
- modular rather than one giant dotfile blob
- explicit about pinned binaries and local secrets
It is not trying to be the smallest possible install. It is trying to be a repeatable personal workstation setup.

View File

@@ -1,439 +0,0 @@
#!/bin/bash
# Path: Scripts/base.sh
set -e
BLUE='\033[1;34m'
YELLOW='\033[1;33m'
GREEN='\033[1;32m'
RED='\033[1;31m'
NC='\033[0m'
DOTFILES_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
REPO_ROOT="$(dirname "$DOTFILES_DIR")"
source "$DOTFILES_DIR/lib/distro.sh"
OH_MY_ZSH_REPO="https://github.com/ohmyzsh/ohmyzsh.git"
OH_MY_ZSH_COMMIT="b26b5002633e865b70e17933536fe4dc99127898"
ZSH_SYNTAX_HIGHLIGHTING_REPO="https://github.com/zsh-users/zsh-syntax-highlighting.git"
ZSH_SYNTAX_HIGHLIGHTING_COMMIT="5eb677bb0fa9a3e60f0eff031dc13926e093df92"
ZSH_AUTOSUGGESTIONS_REPO="https://github.com/zsh-users/zsh-autosuggestions.git"
ZSH_AUTOSUGGESTIONS_COMMIT="85919cd1ffa7d2d5412f6d3fe437ebdbeeec4fc5"
RCLONE_VERSION="v1.74.2"
EARTHLY_VERSION="v0.8.16"
clone_pinned_repo() {
local repo_url="$1"
local destination="$2"
local commit="$3"
local label="$4"
if [ -d "$destination" ]; then
echo -e "${GREEN} LOG: $label already present.${NC}"
return 0
fi
echo -e "${BLUE} LOG:${YELLOW} Installing $label at pinned commit ${commit:0:12}...${NC}"
git clone "$repo_url" "$destination"
git -C "$destination" checkout "$commit"
if [ "$(git -C "$destination" rev-parse HEAD)" != "$commit" ]; then
echo -e "${RED} ERROR: Failed to pin $label to expected commit $commit${NC}"
exit 1
fi
}
install_debian_docker_from_repo() {
local docker_repo_os="$OS"
local docker_codename="${VERSION_CODENAME:-}"
local dpkg_arch
if [[ "$docker_repo_os" != "ubuntu" && "$docker_repo_os" != "debian" ]]; then
docker_repo_os="ubuntu"
fi
if [ -z "$docker_codename" ] && command -v lsb_release >/dev/null 2>&1; then
docker_codename="$(lsb_release -cs)"
fi
if [ -z "$docker_codename" ]; then
echo -e "${RED} ERROR: Unable to determine Debian/Ubuntu codename for Docker repository setup.${NC}"
exit 1
fi
dpkg_arch="$(dpkg --print-architecture)"
sudo apt-get remove -y docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc >/dev/null 2>&1 || true
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL "https://download.docker.com/linux/${docker_repo_os}/gpg" | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg
echo "deb [arch=${dpkg_arch} signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/${docker_repo_os} ${docker_codename} stable" |
sudo tee /etc/apt/sources.list.d/docker.list >/dev/null
sudo apt-get update
sudo DEBIAN_FRONTEND=noninteractive apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
sudo systemctl enable --now docker
}
download_and_verify_release_asset() {
local asset_url="$1"
local checksum_url="$2"
local asset_name="$3"
local destination_path="$4"
local checksum_file
local expected_checksum
local actual_checksum
checksum_file="$(mktemp)"
curl -fLsS "$asset_url" -o "$destination_path"
curl -fLsS "$checksum_url" -o "$checksum_file"
expected_checksum="$(awk -v asset="$asset_name" '$2 == asset { print $1; exit }' "$checksum_file")"
if [ -z "$expected_checksum" ]; then
rm -f "$checksum_file"
echo -e "${RED} ERROR: Could not find checksum for $asset_name in $checksum_url${NC}"
exit 1
fi
actual_checksum="$(sha256sum "$destination_path" | awk '{print $1}')"
if [ "$actual_checksum" != "$expected_checksum" ]; then
rm -f "$checksum_file"
echo -e "${RED} ERROR: Checksum verification failed for $asset_name${NC}"
exit 1
fi
rm -f "$checksum_file"
}
ensure_git_credential_helper() {
local helper_value="$1"
local existing_helpers=""
existing_helpers=$(git config --global --get-all credential.helper 2>/dev/null || true)
if printf '%s\n' "$existing_helpers" | grep -Fx -- "$helper_value" >/dev/null 2>&1; then
return 0
fi
git config --global --add credential.helper "$helper_value"
}
echo -e "${BLUE} LOG:${YELLOW} Initializing Base System Layer...${NC}"
# Confirm Architecture
ARCH=$(uname -m)
if [ "$ARCH" != "x86_64" ] && [ "$ARCH" != "aarch64" ] && [ "$ARCH" != "arm64" ]; then
echo -e "${RED} ERROR: Unsupported architecture: $ARCH${NC}"
exit 1
fi
is_wsl() {
[ -f /proc/version ] && grep -qEi "(Microsoft|WSL)" /proc/version
}
# Package Installation
PACKAGES=(
curl wget git sudo
rsync
zsh tmux
unzip tar gzip
build-essential
openssl
python bison mercurial
ripgrep fd bat fzf jq
btop httpie gnupg
zoxide stow direnv
bind nmap socat tcpdump net-tools
strace gdb hexyl
ninja-build libcurl4-openssl-dev
just
)
FINAL_PACKAGES=()
for pkg in "${PACKAGES[@]}"; do
case "$pkg" in
"build-essential")
if is_arch_family; then
FINAL_PACKAGES+=(base-devel)
elif is_debian_family; then
FINAL_PACKAGES+=(build-essential)
elif is_fedora_family; then
FINAL_PACKAGES+=(gcc gcc-c++ make patch)
elif is_macos; then
:
fi
continue
;;
"python")
if is_arch_family; then
FINAL_PACKAGES+=(python)
elif is_debian_family; then
FINAL_PACKAGES+=(python3 python3-pip python3-venv)
elif is_fedora_family; then
FINAL_PACKAGES+=(python3 python3-pip)
elif is_macos; then
FINAL_PACKAGES+=(python)
fi
continue
;;
"fd")
if is_arch_family; then
FINAL_PACKAGES+=(fd)
elif is_debian_family || is_fedora_family; then
FINAL_PACKAGES+=(fd-find)
fi
continue
;;
"bat")
FINAL_PACKAGES+=(bat)
continue
;;
"openssl")
if is_arch_family; then
FINAL_PACKAGES+=(openssl)
elif is_debian_family; then
FINAL_PACKAGES+=(libssl-dev)
elif is_fedora_family; then
FINAL_PACKAGES+=(openssl openssl-devel)
elif is_macos; then
FINAL_PACKAGES+=(openssl@3)
fi
continue
;;
"bind")
if is_arch_family; then
FINAL_PACKAGES+=(bind)
elif is_debian_family; then
FINAL_PACKAGES+=(dnsutils)
elif is_fedora_family; then
FINAL_PACKAGES+=(bind-utils)
elif is_macos; then
FINAL_PACKAGES+=(bind)
fi
continue
;;
"ninja-build")
if is_arch_family; then
FINAL_PACKAGES+=(ninja)
elif is_debian_family || is_fedora_family; then
FINAL_PACKAGES+=(ninja-build)
elif is_macos; then
FINAL_PACKAGES+=(ninja)
fi
continue
;;
"libcurl4-openssl-dev")
if is_arch_family; then
FINAL_PACKAGES+=(curl)
elif is_debian_family; then
FINAL_PACKAGES+=(libcurl4-openssl-dev)
elif is_fedora_family; then
FINAL_PACKAGES+=(libcurl-devel)
elif is_macos; then
FINAL_PACKAGES+=(curl)
fi
continue
;;
"gnupg")
if is_fedora_family; then
FINAL_PACKAGES+=(gnupg2)
elif is_macos; then
FINAL_PACKAGES+=(gnupg)
else
FINAL_PACKAGES+=(gnupg)
fi
continue
;;
*)
esac
FINAL_PACKAGES+=("$pkg")
done
if is_debian_family; then
FINAL_PACKAGES+=(ca-certificates bsdmainutils pkg-config cmake)
fi
if is_fedora_family; then
FINAL_PACKAGES+=(ca-certificates pkgconf-pkg-config cmake)
FINAL_PACKAGES+=(R-core gcc-gfortran bzip2 bzip2-devel readline-devel sqlite sqlite-devel tk-devel libffi-devel xz xz-devel ncurses-devel zlib-devel findutils llvm)
fi
if is_macos; then
FINAL_PACKAGES=(
curl wget git zsh tmux unzip
python bison mercurial
ripgrep fd bat fzf jq
btop httpie gnupg
zoxide stow direnv
bind nmap socat
hexyl ninja just
)
fi
echo -e "${BLUE} LOG:${YELLOW} Installing: ${NC}${FINAL_PACKAGES[*]}"
install_status=0
install_packages "${FINAL_PACKAGES[@]}" || install_status=$?
if [ "$install_status" -eq 42 ]; then
exit 0
elif [ "$install_status" -ne 0 ]; then
exit "$install_status"
fi
if is_debian_family || is_fedora_family; then
echo -e "${BLUE} LOG:${YELLOW} Fixing fd/bat binary names when needed...${NC}"
[ -f /usr/bin/fdfind ] && sudo ln -sf /usr/bin/fdfind /usr/local/bin/fd
[ -f /usr/bin/batcat ] && sudo ln -sf /usr/bin/batcat /usr/local/bin/bat
fi
# Installing pinned repo-managed CLI binaries
bash "$REPO_ROOT/Scripts/bin/install.sh" --all
if ! command -v rclone &> /dev/null; then
echo -e "${BLUE} LOG:${YELLOW} Installing Rclone CLI...${NC}"
if is_macos; then
brew install rclone
else
case "$ARCH" in
x86_64)
RCLONE_ARCH="amd64"
;;
aarch64|arm64)
RCLONE_ARCH="arm64"
;;
esac
TEMP_DIR="$(mktemp -d)"
RCLONE_ZIP="$TEMP_DIR/rclone.zip"
RCLONE_ASSET="rclone-${RCLONE_VERSION}-linux-${RCLONE_ARCH}.zip"
RCLONE_ASSET_URL="https://github.com/rclone/rclone/releases/download/${RCLONE_VERSION}/${RCLONE_ASSET}"
RCLONE_CHECKSUM_URL="https://github.com/rclone/rclone/releases/download/${RCLONE_VERSION}/SHA256SUMS"
download_and_verify_release_asset "$RCLONE_ASSET_URL" "$RCLONE_CHECKSUM_URL" "$RCLONE_ASSET" "$RCLONE_ZIP"
unzip -q "$RCLONE_ZIP" -d "$TEMP_DIR"
install -m 755 "$TEMP_DIR"/rclone-${RCLONE_VERSION}-linux-"${RCLONE_ARCH}"/rclone "$HOME/.local/bin/rclone"
rm -rf "$TEMP_DIR"
fi
fi
if ! command -v earthly &> /dev/null; then
echo -e "${BLUE} LOG:${YELLOW} Installing Earthly CLI...${NC}"
if is_macos; then
brew install earthly
else
case "$ARCH" in
x86_64)
EARTHLY_ARCH="amd64"
;;
aarch64|arm64)
EARTHLY_ARCH="arm64"
;;
esac
EARTHLY_ASSET="earthly-linux-${EARTHLY_ARCH}"
EARTHLY_ASSET_URL="https://github.com/earthly/earthly/releases/download/${EARTHLY_VERSION}/${EARTHLY_ASSET}"
EARTHLY_CHECKSUM_URL="https://github.com/earthly/earthly/releases/download/${EARTHLY_VERSION}/checksum.asc"
download_and_verify_release_asset "$EARTHLY_ASSET_URL" "$EARTHLY_CHECKSUM_URL" "$EARTHLY_ASSET" "$HOME/.local/bin/earthly"
chmod +x "$HOME/.local/bin/earthly"
fi
fi
# Docker Installation
if command -v docker &> /dev/null; then
echo -e "${GREEN} LOG: Docker is already installed.${NC}"
else
if is_wsl; then
echo -e "${RED} LOG: WSL Detected! Skipping Native Docker.${NC}"
echo -e "${RED} >>> Please install Docker Desktop on Windows.${NC}"
elif is_macos; then
echo -e "${YELLOW} NOTE:${NC} Docker is not installed. Please install Docker Desktop for macOS manually."
else
echo -e "${BLUE} LOG:${YELLOW} Installing Native Docker...${NC}"
if is_arch_family; then
sudo pacman -S --noconfirm --needed docker docker-compose
sudo systemctl enable --now docker
elif is_debian_family; then
install_debian_docker_from_repo
elif is_fedora_family; then
if is_atomic_fedora; then
echo -e "${YELLOW} NOTE:${NC} Skipping native Docker auto-install on rpm-ostree systems."
echo -e "${YELLOW} NOTE:${NC} After reboot, install your preferred container runtime separately if needed."
else
sudo dnf install -y moby-engine docker-compose
sudo systemctl enable --now docker
fi
fi
# Add user to group
if command -v getent >/dev/null 2>&1 && getent group docker >/dev/null 2>&1; then
sudo usermod -aG docker $(whoami)
fi
fi
fi
# 4. Zsh & Configuration
if [ ! -d "$HOME/.oh-my-zsh" ]; then
clone_pinned_repo "$OH_MY_ZSH_REPO" "$HOME/.oh-my-zsh" "$OH_MY_ZSH_COMMIT" "Oh My Zsh"
fi
# Plugins
ZSH_CUSTOM="${ZSH_CUSTOM:-$HOME/.oh-my-zsh/custom}"
mkdir -p "$ZSH_CUSTOM/plugins"
[ ! -d "$ZSH_CUSTOM/plugins/zsh-syntax-highlighting" ] && clone_pinned_repo "$ZSH_SYNTAX_HIGHLIGHTING_REPO" "$ZSH_CUSTOM/plugins/zsh-syntax-highlighting" "$ZSH_SYNTAX_HIGHLIGHTING_COMMIT" "zsh-syntax-highlighting"
[ ! -d "$ZSH_CUSTOM/plugins/zsh-autosuggestions" ] && clone_pinned_repo "$ZSH_AUTOSUGGESTIONS_REPO" "$ZSH_CUSTOM/plugins/zsh-autosuggestions" "$ZSH_AUTOSUGGESTIONS_COMMIT" "zsh-autosuggestions"
# 5. Git Credentials (WSL Bridge)
if is_wsl; then
GCM_WIN="/mnt/c/Program Files/Git/mingw64/bin/git-credential-manager.exe"
[ -f "$GCM_WIN" ] && ensure_git_credential_helper "! \"$GCM_WIN\""
else
ensure_git_credential_helper 'cache --timeout=43200'
fi
# 6. Cleanup & Secrets
rm -f "$HOME/.zshrc" "$HOME/.zsh_aliases"
mkdir -p "$REPO_ROOT/Zsh"
[ -e "$REPO_ROOT/Zsh/.zsh_secrets" ] || : > "$REPO_ROOT/Zsh/.zsh_secrets"
# 7. Set Shell
TARGET_SHELL="$(command -v zsh)"
CURRENT_LOGIN_SHELL=""
if is_macos && [ -x /bin/zsh ]; then
TARGET_SHELL="/bin/zsh"
fi
if command -v getent >/dev/null 2>&1; then
CURRENT_LOGIN_SHELL="$(getent passwd "$(whoami)" | cut -d: -f7)"
elif is_macos && command -v dscl >/dev/null 2>&1; then
CURRENT_LOGIN_SHELL="$(dscl . -read "/Users/$(whoami)" UserShell 2>/dev/null | awk '{print $2}')"
fi
if [ "$CURRENT_LOGIN_SHELL" != "$TARGET_SHELL" ]; then
if [ ! -t 0 ]; then
echo -e "${YELLOW} NOTE:${NC} Non-interactive session detected. Skipping login shell change to $TARGET_SHELL."
echo -e "${YELLOW} NOTE:${NC} Run 'chsh -s $TARGET_SHELL' manually later if you want zsh as your login shell."
elif is_macos && command -v chsh >/dev/null 2>&1; then
chsh -s "$TARGET_SHELL"
elif command -v chsh >/dev/null 2>&1; then
sudo chsh -s "$TARGET_SHELL" "$(whoami)"
elif command -v usermod >/dev/null 2>&1; then
sudo usermod -s "$TARGET_SHELL" "$(whoami)"
else
echo -e "${YELLOW} NOTE:${NC} Could not find chsh/usermod. Please change your login shell to $TARGET_SHELL manually."
fi
fi
echo -e "${GREEN} LOG: Base System Setup Complete.${NC}"

View File

@@ -1,145 +0,0 @@
#!/bin/bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(dirname "$(dirname "$SCRIPT_DIR")")"
MANIFEST="$REPO_ROOT/Bins/versions.json"
TARGET_DIR="$HOME/.local/bin"
ensure_deps() {
local missing=()
for cmd in jq curl tar; do
if ! command -v "$cmd" >/dev/null 2>&1; then
missing+=("$cmd")
fi
done
if [ "${#missing[@]}" -gt 0 ]; then
printf 'Missing required commands: %s\n' "${missing[*]}" >&2
exit 1
fi
}
detect_platform() {
case "$(uname -s)" in
Linux) printf 'linux\n' ;;
Darwin) printf 'macos\n' ;;
*)
printf 'Unsupported operating system: %s\n' "$(uname -s)" >&2
exit 1
;;
esac
}
detect_arch() {
case "$(uname -m)" in
x86_64) printf 'x86_64\n' ;;
aarch64|arm64) printf 'aarch64\n' ;;
*)
printf 'Unsupported architecture: %s\n' "$(uname -m)" >&2
exit 1
;;
esac
}
install_tool() {
local tool="$1"
local platform arch version owner repo asset binary_rel formula url tmp_dir archive_path extracted_path target_path installed_path formula_prefix
platform="$(detect_platform)"
arch="$(detect_arch)"
if ! jq -e --arg tool "$tool" '.[$tool]' "$MANIFEST" >/dev/null; then
printf 'Unsupported tool: %s\n' "$tool" >&2
exit 1
fi
version="$(jq -r --arg tool "$tool" '.[$tool].version' "$MANIFEST")"
owner="$(jq -r --arg tool "$tool" '.[$tool].owner' "$MANIFEST")"
repo="$(jq -r --arg tool "$tool" '.[$tool].repo' "$MANIFEST")"
formula="$(jq -r --arg tool "$tool" --arg platform "$platform" '.[$tool][$platform].formula // empty' "$MANIFEST")"
if [ -n "$formula" ]; then
if ! command -v brew >/dev/null 2>&1; then
printf 'Homebrew is required to install %s on macOS\n' "$tool" >&2
exit 1
fi
if ! brew list --formula "$formula" >/dev/null 2>&1; then
printf 'Installing %s via Homebrew formula %s\n' "$tool" "$formula"
brew install "$formula"
else
printf '%s already installed via Homebrew\n' "$tool"
fi
formula_prefix="$(brew --prefix "$formula" 2>/dev/null || true)"
if [ -n "$formula_prefix" ] && [ -x "$formula_prefix/bin/$tool" ]; then
installed_path="$formula_prefix/bin/$tool"
else
installed_path="$(command -v "$tool" || true)"
fi
if [ -z "$installed_path" ]; then
printf 'Installed formula %s but %s is not on PATH\n' "$formula" "$tool" >&2
exit 1
fi
mkdir -p "$TARGET_DIR"
target_path="$TARGET_DIR/$tool"
ln -sf "$installed_path" "$target_path"
printf 'Linked %s -> %s\n' "$target_path" "$installed_path"
return 0
fi
asset="$(jq -r --arg tool "$tool" --arg platform "$platform" --arg arch "$arch" '.[$tool][$platform][$arch].asset // empty' "$MANIFEST")"
binary_rel="$(jq -r --arg tool "$tool" --arg platform "$platform" --arg arch "$arch" '.[$tool][$platform][$arch].binary // empty' "$MANIFEST")"
if [ -z "$asset" ] || [ -z "$binary_rel" ]; then
printf 'No %s asset mapping for %s on %s\n' "$platform" "$tool" "$arch" >&2
exit 1
fi
mkdir -p "$TARGET_DIR"
tmp_dir="$(mktemp -d)"
archive_path="$tmp_dir/$asset"
url="https://github.com/$owner/$repo/releases/download/$version/$asset"
printf 'Installing %s %s\n' "$tool" "$version"
curl -fL "$url" -o "$archive_path"
tar -xzf "$archive_path" -C "$tmp_dir"
extracted_path="$tmp_dir/$binary_rel"
if [ ! -f "$extracted_path" ]; then
printf 'Expected binary not found after extraction: %s\n' "$binary_rel" >&2
rm -rf "$tmp_dir"
exit 1
fi
target_path="$TARGET_DIR/$tool"
install -m 755 "$extracted_path" "$target_path"
rm -rf "$tmp_dir"
printf 'Installed %s -> %s\n' "$tool" "$target_path"
}
main() {
ensure_deps
if [ "${1:-}" = "--all" ]; then
while IFS= read -r tool; do
install_tool "$tool"
done < <(jq -r 'keys[]' "$MANIFEST")
exit 0
fi
if [ -z "${1:-}" ]; then
printf 'Usage: %s [--all|tool]\n' "$0" >&2
exit 1
fi
install_tool "$1"
}
main "$@"

View File

@@ -1,135 +0,0 @@
#!/bin/bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(dirname "$(dirname "$SCRIPT_DIR")")"
MANIFEST="$REPO_ROOT/Bins/versions.json"
ensure_deps() {
local missing=()
for cmd in jq curl python3; do
if ! command -v "$cmd" >/dev/null 2>&1; then
missing+=("$cmd")
fi
done
if [ "${#missing[@]}" -gt 0 ]; then
printf 'Missing required commands: %s\n' "${missing[*]}" >&2
exit 1
fi
}
github_api() {
local path="$1"
local auth_args=()
if [ -n "${GITHUB_TOKEN:-}" ]; then
auth_args=(-H "Authorization: Bearer $GITHUB_TOKEN")
fi
curl -fsSL \
-H "Accept: application/vnd.github+json" \
"${auth_args[@]}" \
"https://api.github.com${path}"
}
list_versions() {
local tool="$1" owner repo
if ! jq -e --arg tool "$tool" '.[$tool]' "$MANIFEST" >/dev/null; then
printf 'Unsupported tool: %s\n' "$tool" >&2
exit 1
fi
owner="$(jq -r --arg tool "$tool" '.[$tool].owner' "$MANIFEST")"
repo="$(jq -r --arg tool "$tool" '.[$tool].repo' "$MANIFEST")"
github_api "/repos/$owner/$repo/releases?per_page=100" | jq -r '.[].tag_name'
}
select_version() {
local tool="$1"
local versions
versions="$(list_versions "$tool")"
if [ -z "$versions" ]; then
printf 'No releases found for %s\n' "$tool" >&2
exit 1
fi
if command -v fzf >/dev/null 2>&1; then
printf '%s\n' "$versions" | fzf --prompt="Select ${tool} version > " --height=20 --reverse
else
printf '%s\n' "$versions" | sed -n '1,20p' >&2
printf 'fzf is not installed, so pass a version explicitly.\n' >&2
exit 1
fi
}
update_version() {
local tool="$1" version="$2"
local tmp_file
if [ -z "$version" ]; then
printf 'No version selected for %s\n' "$tool" >&2
exit 1
fi
tmp_file="$(mktemp)"
python3 - "$MANIFEST" "$tool" "$version" "$tmp_file" <<'PY'
import json
import pathlib
import sys
manifest_path = pathlib.Path(sys.argv[1])
tool = sys.argv[2]
version = sys.argv[3]
tmp_path = pathlib.Path(sys.argv[4])
data = json.loads(manifest_path.read_text())
if tool not in data:
raise SystemExit(f"Unsupported tool: {tool}")
data[tool]["version"] = version
tmp_path.write_text(json.dumps(data, indent=2) + "\n")
PY
mv "$tmp_file" "$MANIFEST"
printf 'Pinned %s to %s\n' "$tool" "$version"
}
main() {
local mode="update" tool version
ensure_deps
if [ "${1:-}" = "--list" ]; then
mode="list"
shift
fi
tool="${1:-}"
version="${2:-}"
if [ -z "$tool" ]; then
printf 'Usage: %s [--list] tool [version]\n' "$0" >&2
exit 1
fi
case "$mode" in
list)
list_versions "$tool"
;;
update)
if [ -z "$version" ]; then
version="$(select_version "$tool")"
fi
update_version "$tool" "$version"
;;
esac
}
main "$@"

View File

@@ -1,172 +0,0 @@
#!/bin/bash
# Path: Scripts/go.sh
set -e
BLUE='\033[1;34m'
YELLOW='\033[1;33m'
GREEN='\033[1;32m'
RED='\033[1;31m'
NC='\033[0m'
export GVM_ROOT="$HOME/.programming/go"
BOOTSTRAP_GO="$GVM_ROOT/bootstrap"
GO_BOOTSTRAP_VERSION="1.20.5"
OS_NAME="$(uname -s)"
ARCH="$(uname -m)"
case "$ARCH" in
x86_64)
GO_BOOTSTRAP_ARCH="amd64"
;;
aarch64|arm64)
GO_BOOTSTRAP_ARCH="arm64"
;;
*)
echo -e "${RED} ERROR:${NC} Unsupported architecture for Go bootstrap: $ARCH"
exit 1
;;
esac
case "$OS_NAME" in
Linux)
GO_BOOTSTRAP_OS="linux"
;;
Darwin)
GO_BOOTSTRAP_OS="darwin"
;;
*)
echo -e "${RED} ERROR:${NC} Unsupported operating system for Go bootstrap: $OS_NAME"
exit 1
;;
esac
GO_BOOTSTRAP_FILENAME="go${GO_BOOTSTRAP_VERSION}.${GO_BOOTSTRAP_OS}-${GO_BOOTSTRAP_ARCH}.tar.gz"
GO_BOOTSTRAP_URL="https://go.dev/dl/${GO_BOOTSTRAP_FILENAME}"
GO_RELEASE_METADATA_URL="https://go.dev/dl/?mode=json&include=all"
sha256_file() {
local file_path="$1"
if command -v sha256sum >/dev/null 2>&1; then
sha256sum "$file_path" | awk '{print $1}'
elif command -v shasum >/dev/null 2>&1; then
shasum -a 256 "$file_path" | awk '{print $1}'
else
echo -e "${RED} ERROR:${NC} No SHA256 tool found (need sha256sum or shasum)."
exit 1
fi
}
get_go_release_sha256() {
python3 - "$GO_RELEASE_METADATA_URL" "$GO_BOOTSTRAP_FILENAME" <<'PY'
import json
import sys
import urllib.request
metadata_url = sys.argv[1]
target_filename = sys.argv[2]
with urllib.request.urlopen(metadata_url, timeout=30) as response:
releases = json.load(response)
for release in releases:
for file_info in release.get("files", []):
if file_info.get("filename") == target_filename:
print(file_info.get("sha256", ""))
raise SystemExit(0)
raise SystemExit(1)
PY
}
download_and_verify_go_bootstrap() {
local destination_path="$1"
local expected_sha256=""
local actual_sha256=""
local temp_tarball=""
temp_tarball="$(mktemp "${TMPDIR:-/tmp}/go-bootstrap.XXXXXX")"
cleanup_go_bootstrap_download() {
rm -f "$temp_tarball"
}
trap cleanup_go_bootstrap_download RETURN
echo -e "${BLUE} LOG:${YELLOW} Downloading pinned Bootstrap Go ${GO_BOOTSTRAP_VERSION}...${NC}"
curl -fsSL "$GO_BOOTSTRAP_URL" -o "$temp_tarball"
expected_sha256="$(get_go_release_sha256)"
if [ -z "$expected_sha256" ]; then
echo -e "${RED} ERROR:${NC} Could not find official SHA256 for ${GO_BOOTSTRAP_FILENAME}."
exit 1
fi
actual_sha256="$(sha256_file "$temp_tarball")"
if [ "$actual_sha256" != "$expected_sha256" ]; then
echo -e "${RED} ERROR:${NC} Bootstrap Go checksum mismatch for ${GO_BOOTSTRAP_FILENAME}."
echo -e "${RED} ERROR:${NC} Expected: ${expected_sha256}"
echo -e "${RED} ERROR:${NC} Actual: ${actual_sha256}"
exit 1
fi
tar -C "$destination_path" -xzf "$temp_tarball" --strip-components=1
}
echo -e "${BLUE} LOG:${YELLOW} Setting up Go and GVM in ${GVM_ROOT}...${NC}"
if [ ! -d "$GVM_ROOT/scripts" ]; then
echo -e "${BLUE} LOG:${YELLOW} Cloning GVM...${NC}"
git clone https://github.com/moovweb/gvm.git "$GVM_ROOT"
rm -rf "$GVM_ROOT/.git"
echo -e "${BLUE} LOG:${YELLOW} Configuring GVM scripts...${NC}"
cp "$GVM_ROOT/scripts/gvm-default" "$GVM_ROOT/scripts/gvm"
python3 - "$GVM_ROOT/scripts/gvm" "$GVM_ROOT" <<'PY'
from pathlib import Path
import sys
path = Path(sys.argv[1])
root = sys.argv[2]
text = path.read_text()
path.write_text(text.replace('GVM_ROOT="$HOME/.gvm"', f'GVM_ROOT="{root}"', 1))
PY
echo -e "${GREEN} SUCCESS:${NC} GVM cloned and configured."
else
echo -e "${GREEN} SKIP:${NC} GVM already installed."
fi
if [ ! -d "$BOOTSTRAP_GO" ]; then
mkdir -p "$BOOTSTRAP_GO"
download_and_verify_go_bootstrap "$BOOTSTRAP_GO"
echo -e "${GREEN} SUCCESS:${NC} Bootstrap Go installed."
else
echo -e "${GREEN} SKIP:${NC} Bootstrap Go already exists."
fi
export PATH="$BOOTSTRAP_GO/bin:$PATH"
export GOROOT_BOOTSTRAP="$BOOTSTRAP_GO"
set +e
source "$GVM_ROOT/scripts/gvm"
set -e
if ! command -v gvm &> /dev/null; then
echo -e "${RED} ERROR:${NC} GVM failed to load."
exit 1
fi
TARGET_VER="go1.24.11"
if ! gvm list | grep -q "$TARGET_VER"; then
echo -e "${BLUE} LOG:${YELLOW} Installing ${TARGET_VER}...${NC}"
gvm install "$TARGET_VER" --prefer-binary
fi
gvm use "$TARGET_VER" --default
echo -e "${GREEN} SUCCESS:${NC} Go setup completed."

View File

@@ -1,220 +0,0 @@
#!/bin/bash
# Path: Scripts/r.sh
set -e
BLUE='\033[1;34m'
YELLOW='\033[1;33m'
GREEN='\033[1;32m'
RED='\033[1;31m'
NC='\033[0m'
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
source "$SCRIPT_DIR/lib/distro.sh"
PROG_DIR="$HOME/.programming"
R_ROOT="$PROG_DIR/r"
R_BIN_DIR="$R_ROOT/bin"
R_LIB_DIR="$R_ROOT/library"
mkdir -p "$R_BIN_DIR" "$R_LIB_DIR"
write_r_wrapper() {
local target_name="$1"
local command_body="$2"
cat > "$R_BIN_DIR/$target_name" <<EOF
#!/bin/bash
set -e
export R_LIBS_USER="$R_LIB_DIR"
$command_body "\$@"
EOF
chmod +x "$R_BIN_DIR/$target_name"
}
resolve_non_wrapper_command() {
local target_name="$1"
local original_path="$PATH"
local filtered_parts=()
local filtered_path=""
local resolved_path=""
local part
IFS=':' read -r -a filtered_parts <<< "$PATH"
local kept_parts=()
for part in "${filtered_parts[@]}"; do
if [ -n "$part" ] && [ "$part" != "$R_BIN_DIR" ]; then
kept_parts+=("$part")
fi
done
filtered_path=$(IFS=:; printf '%s' "${kept_parts[*]}")
resolved_path=$(PATH="$filtered_path" command -v "$target_name" 2>/dev/null || true)
PATH="$original_path"
if [ -z "$resolved_path" ]; then
echo -e "${RED} ERROR:${NC} Could not resolve system command for $target_name outside $R_BIN_DIR"
exit 1
fi
printf '%s\n' "$resolved_path"
}
echo -e "${BLUE} LOG:${YELLOW} Detecting R installation strategy for $OS...${NC}"
if is_arch_family; then
echo -e "${BLUE} LOG:${YELLOW} Arch Linux detected. Using system R (Pacman)...${NC}"
# Install R + Build Tools
install_status=0
install_packages r gcc-fortran curl tar || install_status=$?
if [ "$install_status" -eq 42 ]; then
exit 0
elif [ "$install_status" -ne 0 ]; then
exit "$install_status"
fi
echo -e "${GREEN} SUCCESS:${NC} R installed via Pacman."
R_BIN="R"
SYSTEM_R_BIN="$(resolve_non_wrapper_command R)"
SYSTEM_RSCRIPT_BIN="$(resolve_non_wrapper_command Rscript)"
write_r_wrapper "R" "exec \"$SYSTEM_R_BIN\""
write_r_wrapper "Rscript" "exec \"$SYSTEM_RSCRIPT_BIN\""
elif is_debian_family; then
echo -e "${BLUE} LOG:${YELLOW} Installing Debian build dependencies...${NC}"
install_status=0
install_packages gfortran curl tar ca-certificates || install_status=$?
if [ "$install_status" -eq 42 ]; then
exit 0
elif [ "$install_status" -ne 0 ]; then
exit "$install_status"
fi
if ! command -v rig >/dev/null 2>&1; then
echo -e "${BLUE} LOG:${YELLOW} Installing Rig for Debian/Ubuntu...${NC}"
DEB_ARCH=$(dpkg --print-architecture)
case "$DEB_ARCH" in
amd64|arm64)
;;
*)
echo -e "${RED} ERROR:${NC} Unsupported Debian architecture for Rig: $DEB_ARCH"
exit 1
;;
esac
LATEST_REL_DATA=$(curl -fsSL https://api.github.com/repos/r-lib/rig/releases/latest)
RIG_URL=$(echo "$LATEST_REL_DATA" | grep -o "https://[^\"]*r-rig_[^\"]*_${DEB_ARCH}\.deb" | head -n 1)
if [ -z "$RIG_URL" ]; then
echo -e "${RED} ERROR:${NC} Could not find Rig .deb download URL for architecture: $DEB_ARCH"
exit 1
fi
TEMP_DEB=$(mktemp --suffix=.deb)
curl -fLsS "$RIG_URL" -o "$TEMP_DEB"
sudo apt-get install -y "$TEMP_DEB"
rm -f "$TEMP_DEB"
fi
TARGET_VER="release"
if ! rig list | grep -q "release"; then
echo -e "${BLUE} LOG:${YELLOW} Installing R (${TARGET_VER})...${NC}"
sudo rig add "$TARGET_VER" --without-cran-mirror
sudo rig default "$TARGET_VER"
fi
R_BIN="R"
SYSTEM_R_BIN="$(resolve_non_wrapper_command R)"
SYSTEM_RSCRIPT_BIN="$(resolve_non_wrapper_command Rscript)"
write_r_wrapper "R" "exec \"$SYSTEM_R_BIN\""
write_r_wrapper "Rscript" "exec \"$SYSTEM_RSCRIPT_BIN\""
elif is_fedora_family; then
echo -e "${BLUE} LOG:${YELLOW} Fedora detected. Using system R...${NC}"
install_status=0
install_packages R-core R-core-devel gcc-gfortran curl tar || install_status=$?
if [ "$install_status" -eq 42 ]; then
exit 0
elif [ "$install_status" -ne 0 ]; then
exit "$install_status"
fi
R_BIN="R"
SYSTEM_R_BIN="$(resolve_non_wrapper_command R)"
SYSTEM_RSCRIPT_BIN="$(resolve_non_wrapper_command Rscript)"
write_r_wrapper "R" "exec \"$SYSTEM_R_BIN\""
write_r_wrapper "Rscript" "exec \"$SYSTEM_RSCRIPT_BIN\""
elif is_macos; then
echo -e "${BLUE} LOG:${YELLOW} macOS detected. Using Homebrew R...${NC}"
install_status=0
install_packages r || install_status=$?
if [ "$install_status" -ne 0 ]; then
exit "$install_status"
fi
R_BIN="R"
SYSTEM_R_BIN="$(resolve_non_wrapper_command R)"
SYSTEM_RSCRIPT_BIN="$(resolve_non_wrapper_command Rscript)"
write_r_wrapper "R" "exec \"$SYSTEM_R_BIN\""
write_r_wrapper "Rscript" "exec \"$SYSTEM_RSCRIPT_BIN\""
else
echo -e "${RED} ERROR:${NC} Unsupported OS: $OS"
exit 1
fi
export R_LIBS_USER="$R_LIB_DIR"
if compgen -G "$R_LIB_DIR/00LOCK*" >/dev/null 2>&1; then
echo -e "${RED} ERROR:${NC} Detected existing R package lock(s) in $R_LIB_DIR"
find "$R_LIB_DIR" -maxdepth 1 -type d -name '00LOCK*' -print | sed 's/^/ - /'
echo -e "${YELLOW} LOG:${NC} This usually means a previous R package install was interrupted."
echo -e "${YELLOW} LOG:${NC} Remove the stale lock directory/directories above, then rerun the command."
exit 1
fi
echo -e "${BLUE} LOG:${YELLOW} Installing 'renv' package in the user R library...${NC}"
echo -e "${BLUE} LOG:${YELLOW} R user library: $R_LIB_DIR${NC}"
echo -e "${BLUE} LOG:${YELLOW} R executable: $R_BIN_DIR/Rscript${NC}"
"$R_BIN_DIR/Rscript" --vanilla - <<'EOF'
user_lib <- path.expand(Sys.getenv("R_LIBS_USER", unset = "~/.programming/r/library"))
dir.create(user_lib, recursive = TRUE, showWarnings = FALSE)
.libPaths(c(user_lib, .libPaths()))
cat("R user library:", user_lib, "\n")
cat("R library paths:", paste(.libPaths(), collapse = " | "), "\n")
if (requireNamespace("renv", quietly = TRUE)) {
cat("renv is already installed.\n")
quit(save = "no", status = 0)
}
cat("Installing renv from CRAN...\n")
install.packages(
"renv",
lib = user_lib,
repos = "https://cloud.r-project.org",
quiet = FALSE
)
cat("Verifying renv installation...\n")
if (!requireNamespace("renv", quietly = TRUE)) {
stop("renv install finished but the package is still unavailable.")
}
cat("renv installation verified.\n")
EOF
echo -e "${GREEN} SUCCESS:${NC} R setup completed."

View File

@@ -1,165 +0,0 @@
#!/bin/bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(dirname "$SCRIPT_DIR")"
REBOOT_MARKER="$REPO_ROOT/.setup-reboot-required"
REPO_SECRET_FILE="$REPO_ROOT/Zsh/.zsh_secrets"
HOME_SECRET_FILE="$HOME/.zsh_secrets"
BACKUP_ROOT="$HOME/.dotzsh-pre-stow-backup"
handle_reboot_marker() {
if [ -f "$REBOOT_MARKER" ]; then
rm -f "$REBOOT_MARKER"
echo "Package layering finished. Reboot, then rerun the same command."
exit 0
fi
}
sync_repo_managed_secret_file() {
local home_secret_resolved repo_secret_resolved
mkdir -p "$(dirname "$REPO_SECRET_FILE")"
if [ -L "$HOME_SECRET_FILE" ]; then
home_secret_resolved="$(python3 -c 'import os,sys; print(os.path.realpath(sys.argv[1]))' "$HOME_SECRET_FILE")"
repo_secret_resolved="$(python3 -c 'import os,sys; print(os.path.realpath(sys.argv[1]))' "$REPO_SECRET_FILE")"
if [ "$home_secret_resolved" = "$repo_secret_resolved" ]; then
return 0
fi
if [ -f "$home_secret_resolved" ]; then
if [ ! -f "$REPO_SECRET_FILE" ] || [ ! -s "$REPO_SECRET_FILE" ]; then
cp "$home_secret_resolved" "$REPO_SECRET_FILE"
rm -f "$HOME_SECRET_FILE"
return 0
fi
if cmp -s "$home_secret_resolved" "$REPO_SECRET_FILE"; then
rm -f "$HOME_SECRET_FILE"
return 0
fi
fi
echo "Conflict: $HOME_SECRET_FILE points to a different secret file than $REPO_SECRET_FILE."
echo "Please merge them manually, then rerun the command."
exit 1
fi
if [ -f "$HOME_SECRET_FILE" ]; then
if [ ! -f "$REPO_SECRET_FILE" ] || [ ! -s "$REPO_SECRET_FILE" ]; then
mv "$HOME_SECRET_FILE" "$REPO_SECRET_FILE"
return 0
fi
if cmp -s "$HOME_SECRET_FILE" "$REPO_SECRET_FILE"; then
rm -f "$HOME_SECRET_FILE"
return 0
fi
echo "Conflict: both $HOME_SECRET_FILE and $REPO_SECRET_FILE exist with different contents."
echo "Please merge them manually, then rerun the command."
exit 1
fi
touch "$REPO_SECRET_FILE"
}
backup_conflicting_home_files() {
local backup_dir backed_up_any=0 source_file filename target_file target_resolved source_resolved
backup_dir="$BACKUP_ROOT/$(date +%Y%m%d-%H%M%S)"
while IFS= read -r source_file; do
filename="$(basename "$source_file")"
target_file="$HOME/$filename"
if [ -L "$target_file" ]; then
target_resolved="$(python3 -c 'import os,sys; print(os.path.realpath(sys.argv[1]))' "$target_file")"
source_resolved="$(python3 -c 'import os,sys; print(os.path.realpath(sys.argv[1]))' "$source_file")"
if [ "$target_resolved" = "$source_resolved" ]; then
continue
fi
mkdir -p "$backup_dir"
mv "$target_file" "$backup_dir/$filename"
echo "Backed up existing linked $target_file -> $backup_dir/$filename"
backed_up_any=1
elif [ -e "$target_file" ]; then
mkdir -p "$backup_dir"
mv "$target_file" "$backup_dir/$filename"
echo "Backed up existing $target_file -> $backup_dir/$filename"
backed_up_any=1
fi
done < <(find "$REPO_ROOT/Zsh" -mindepth 1 -maxdepth 1 -type f -name '.*' ! -name '.zsh_secrets')
if [ "$backed_up_any" -eq 1 ]; then
echo "Existing unmanaged dotfiles were backed up before stowing."
fi
}
stow_dotfiles() {
echo "Preparing repo-managed secrets for stow..."
sync_repo_managed_secret_file
echo "Checking for conflicting home dotfiles before stow..."
backup_conflicting_home_files
echo "Cleaning existing Zsh stow links..."
stow --dir="$REPO_ROOT" -D Zsh --target="$HOME" 2>/dev/null || true
echo "Stowing Zsh dotfiles..."
stow --dir="$REPO_ROOT" Zsh --target="$HOME"
echo "Zsh dotfiles stowed."
}
bootstrap_only() {
rm -f "$REBOOT_MARKER"
bash "$SCRIPT_DIR/base.sh"
handle_reboot_marker
stow_dotfiles
echo "Bootstrap setup completed."
}
full_setup() {
rm -f "$REBOOT_MARKER"
bash "$SCRIPT_DIR/base.sh"
handle_reboot_marker
bash "$SCRIPT_DIR/node.sh"
bash "$SCRIPT_DIR/go.sh"
bash "$SCRIPT_DIR/rust.sh"
bash "$SCRIPT_DIR/python.sh"
handle_reboot_marker
bash "$SCRIPT_DIR/r.sh"
handle_reboot_marker
stow_dotfiles
echo "Full setup completed."
}
case "${1:-}" in
--bootstrap-only)
bootstrap_only
;;
--stow-only)
stow_dotfiles
;;
"")
full_setup
;;
*)
echo "Usage: $0 [--bootstrap-only|--stow-only]"
exit 1
;;
esac

View File

@@ -1,185 +0,0 @@
# Completion behavior and wrapper bindings
autoload -Uz add-zsh-hook
if ! whence -w compdef >/dev/null 2>&1; then
autoload -Uz compinit
if [ -n "${ZSH_COMPDUMP:-}" ]; then
mkdir -p "${ZSH_COMPDUMP:h}"
if [ -f "$ZSH_COMPDUMP" ]; then
compinit -C -d "$ZSH_COMPDUMP" >/dev/null 2>&1
else
compinit -i -d "$ZSH_COMPDUMP" >/dev/null 2>&1
fi
else
compinit -i >/dev/null 2>&1
fi
fi
zmodload zsh/complist 2>/dev/null || true
zstyle ':completion:*' menu select
zstyle ':completion:*' verbose yes
zstyle ':completion:*' list-grouped yes
zstyle ':completion:*' use-cache yes
zstyle ':completion:*:descriptions' format '%F{240}%B%d%b%f'
typeset -ga DOTZSH_USED_COMMANDS
typeset -ga DOTZSH_ALL_COMMANDS
typeset -gA DOTZSH_USED_COMMAND_MAP
typeset -gA DOTZSH_ALL_COMMAND_MAP
typeset -g DOTZSH_USED_COMMANDS_INITIALIZED=0
typeset -g DOTZSH_ALL_COMMANDS_INITIALIZED=0
typeset -g DOTZSH_USED_COMMAND_LIMIT=120
_dotzsh_parse_history_line() {
local raw_line="$1"
local parsed_line="$raw_line"
case "$parsed_line" in
': '*';'*)
parsed_line="${parsed_line#*;}"
;;
esac
print -r -- "$parsed_line"
}
_dotzsh_extract_command_name() {
local line="$(_dotzsh_parse_history_line "$1")"
local command_name=""
local -a parts=()
local index=1
[ -n "$line" ] || return 1
[[ "$line" == '#'* ]] && return 1
parts=(${(z)line})
[ "${#parts[@]}" -gt 0 ] || return 1
while [ "$index" -le "${#parts[@]}" ]; do
command_name="${parts[$index]}"
case "$command_name" in
sudo|time|command|builtin|noglob|env)
((index++))
continue
;;
*=*)
((index++))
continue
;;
esac
break
done
[ -n "$command_name" ] || return 1
[[ "$command_name" == _* ]] && return 1
[[ "$command_name" =~ '^[A-Za-z0-9][A-Za-z0-9+._-]*$' ]] || return 1
print -r -- "$command_name"
}
_dotzsh_remember_command() {
local command_name="$1"
[ -n "$command_name" ] || return 0
DOTZSH_USED_COMMANDS=(${DOTZSH_USED_COMMANDS:#$command_name})
DOTZSH_USED_COMMANDS=("$command_name" "${DOTZSH_USED_COMMANDS[@]}")
DOTZSH_USED_COMMAND_MAP[$command_name]=1
}
_dotzsh_initialize_used_commands() {
local history_file="${HISTFILE:-$HOME/.zsh_history}"
local line=""
local command_name=""
[ "$DOTZSH_USED_COMMANDS_INITIALIZED" -eq 0 ] || return 0
DOTZSH_USED_COMMANDS=()
DOTZSH_USED_COMMAND_MAP=()
while IFS= read -r line; do
command_name="$(_dotzsh_extract_command_name "$line")" || continue
[[ -n ${DOTZSH_USED_COMMAND_MAP[$command_name]:-} ]] && continue
DOTZSH_USED_COMMANDS+=("$command_name")
DOTZSH_USED_COMMAND_MAP[$command_name]=1
[ "${#DOTZSH_USED_COMMANDS[@]}" -lt "$DOTZSH_USED_COMMAND_LIMIT" ] || break
done < <(
if [ -r "$history_file" ]; then
tac "$history_file" 2>/dev/null || tail -r "$history_file" 2>/dev/null || cat "$history_file"
else
fc -lnr 1 2>/dev/null
fi
)
DOTZSH_USED_COMMANDS_INITIALIZED=1
}
_dotzsh_initialize_all_commands() {
local command_name=""
[ "$DOTZSH_ALL_COMMANDS_INITIALIZED" -eq 0 ] || return 0
DOTZSH_ALL_COMMANDS=()
DOTZSH_ALL_COMMAND_MAP=()
for command_name in ${(k)aliases} ${(k)builtins} ${(k)commands} ${(k)functions}; do
[ -n "$command_name" ] || continue
[[ "$command_name" == _* ]] && continue
[[ -n ${DOTZSH_ALL_COMMAND_MAP[$command_name]:-} ]] && continue
DOTZSH_ALL_COMMANDS+=("$command_name")
DOTZSH_ALL_COMMAND_MAP[$command_name]=1
done
DOTZSH_ALL_COMMANDS_INITIALIZED=1
}
_dotzsh_record_command() {
local command_name=""
command_name="$(_dotzsh_extract_command_name "$1")" || return 0
_dotzsh_remember_command "$command_name"
}
_dotzsh_command_menu() {
local command_name=""
local -a other_commands=()
local -a filtered_used_commands=()
local -a used_display=()
local current_prefix="$PREFIX"
_dotzsh_initialize_used_commands
_dotzsh_initialize_all_commands
for command_name in "${DOTZSH_USED_COMMANDS[@]}"; do
[[ -n ${DOTZSH_ALL_COMMAND_MAP[$command_name]:-} ]] || continue
[ -z "$current_prefix" ] || [[ "$command_name" == ${~current_prefix}* ]] || continue
filtered_used_commands+=("$command_name")
used_display+=("* $command_name")
done
for command_name in "${DOTZSH_ALL_COMMANDS[@]}"; do
[[ -n ${DOTZSH_USED_COMMAND_MAP[$command_name]:-} ]] && continue
[ -z "$current_prefix" ] || [[ "$command_name" == ${~current_prefix}* ]] || continue
other_commands+=("$command_name")
done
[ "${#filtered_used_commands[@]}" -eq 0 ] || compadd -Q -U -o nosort -d used_display -- "${filtered_used_commands[@]}"
[ "${#other_commands[@]}" -eq 0 ] || compadd -Q -U -o nosort -- "${other_commands[@]}"
[ "${#filtered_used_commands[@]}" -gt 0 ] || [ "${#other_commands[@]}" -gt 0 ]
}
compdef _dotzsh_command_menu -command-
add-zsh-hook preexec _dotzsh_record_command
autoload -Uz _gvm _conda _go _node _npm _npx 2>/dev/null
compdef _gvm gvm
compdef _go go gofmt
compdef _conda conda
compdef _node node
compdef _npm npm
compdef _npx npx

View File

@@ -1,285 +0,0 @@
# Prompt styling and context
autoload -Uz add-zsh-hook vcs_info
zstyle ':vcs_info:*' enable git
zstyle ':vcs_info:git:*' formats ' %b'
typeset -g PROMPT_SHOW_SPACER=0
typeset -gA PROMPT_PROJECT_MATCH_CACHE
typeset -gA PROMPT_VERSION_CACHE
typeset -gA PROMPT_SEPARATOR_CACHE
typeset -g PROMPT_FIRST_RENDER=1
typeset -g PROMPT_PROJECT_ROOT_CACHE_PWD=''
typeset -g PROMPT_PROJECT_ROOT_CACHE=''
prompt_preexec() {
case "$1" in
clear|clear\ *|reset|reset\ *)
PROMPT_SHOW_SPACER=0
;;
*)
PROMPT_SHOW_SPACER=1
;;
esac
}
get_command_version() {
local command_name="$1"
local binary_path=""
local raw_version=""
if [[ -n ${PROMPT_VERSION_CACHE[$command_name]+x} ]]; then
print -r -- "${PROMPT_VERSION_CACHE[$command_name]}"
return 0
fi
binary_path="$(whence -p "$command_name" 2>/dev/null || true)"
if ! [ -n "$binary_path" ] || ! [ -x "$binary_path" ]; then
PROMPT_VERSION_CACHE[$command_name]=""
return 0
fi
case "$command_name" in
python)
raw_version="$($binary_path --version 2>&1 || true)"
raw_version="${raw_version#Python }"
;;
node)
raw_version="$($binary_path -v 2>/dev/null || true)"
raw_version="${raw_version#v}"
;;
go)
raw_version="$($binary_path version 2>/dev/null || true)"
raw_version="${raw_version#go version go}"
raw_version="${raw_version%% *}"
;;
rustc)
raw_version="$($binary_path -V 2>/dev/null || true)"
raw_version="${raw_version#rustc }"
raw_version="${raw_version%% *}"
;;
*)
PROMPT_VERSION_CACHE[$command_name]=""
return 0
;;
esac
[ -n "$raw_version" ] || {
PROMPT_VERSION_CACHE[$command_name]=""
return 0
}
PROMPT_VERSION_CACHE[$command_name]="$raw_version"
print -r -- "$raw_version"
}
get_project_root() {
if [ "$PROMPT_PROJECT_ROOT_CACHE_PWD" = "$PWD" ] && [ -n "$PROMPT_PROJECT_ROOT_CACHE" ]; then
print -r -- "$PROMPT_PROJECT_ROOT_CACHE"
return 0
fi
PROMPT_PROJECT_ROOT_CACHE_PWD="$PWD"
PROMPT_PROJECT_ROOT_CACHE="$(command git rev-parse --show-toplevel 2>/dev/null || print -r -- "$PWD")"
print -r -- "$PROMPT_PROJECT_ROOT_CACHE"
}
project_has_pattern() {
local project_root=""
local cache_key=""
local pattern
local matches=()
project_root="$(get_project_root)"
cache_key="${project_root}::${(j:|:)@}"
if [[ -n ${PROMPT_PROJECT_MATCH_CACHE[$cache_key]+x} ]]; then
[[ ${PROMPT_PROJECT_MATCH_CACHE[$cache_key]} == 1 ]]
return
fi
for pattern in "$@"; do
matches=("${project_root}"/${~pattern}(N))
if [ "${#matches[@]}" -gt 0 ]; then
PROMPT_PROJECT_MATCH_CACHE[$cache_key]=1
return 0
fi
done
PROMPT_PROJECT_MATCH_CACHE[$cache_key]=0
return 1
}
build_git_status_segment() {
local git_status_output=""
local line=""
local staged=0
local unstaged=0
local untracked=0
local status_parts=()
command git rev-parse --is-inside-work-tree >/dev/null 2>&1 || return 0
git_status_output="$(command git status --porcelain 2>/dev/null || true)"
if [ -z "$git_status_output" ]; then
print -r -- "%F{green}✓ clean%f"
return 0
fi
while IFS= read -r line; do
[ -n "$line" ] || continue
if [ "${line:0:2}" = "??" ]; then
((untracked++))
continue
fi
[ "${line:0:1}" = " " ] || ((staged++))
[ "${line:1:1}" = " " ] || ((unstaged++))
done <<< "$git_status_output"
[ "$staged" -eq 0 ] || status_parts+=("+$staged")
[ "$unstaged" -eq 0 ] || status_parts+=("~$unstaged")
[ "$untracked" -eq 0 ] || status_parts+=("?$untracked")
if [ "${#status_parts[@]}" -eq 0 ]; then
print -r -- "%F{green}✓ clean%f"
else
print -r -- "%F{yellow}${(j: :)status_parts}%f"
fi
}
build_prompt_separator_line() {
local last_status="$1"
local line_width="${COLUMNS:-80}"
local cache_key="${line_width}:${last_status}"
local separator_line=""
local color_prefix=""
local color_suffix=""
local i=0
if [[ -n ${PROMPT_SEPARATOR_CACHE[$cache_key]+x} ]]; then
print -r -- "${PROMPT_SEPARATOR_CACHE[$cache_key]}"
return 0
fi
if [ "$line_width" -lt 1 ]; then
line_width=1
fi
if [ "$last_status" -ne 0 ]; then
color_prefix="%F{red}"
color_suffix="%f"
fi
while [ "$i" -lt "$line_width" ]; do
separator_line+="─"
((i++))
done
PROMPT_SEPARATOR_CACHE[$cache_key]="${color_prefix}${separator_line}${color_suffix}"
print -r -- "${PROMPT_SEPARATOR_CACHE[$cache_key]}"
}
build_prompt() {
local last_status=$?
local git_segment=""
local git_status_segment=""
local env_segment=""
local project_symbols=()
local tool_versions=()
local python_version=""
local node_version=""
local go_version=""
local rust_version=""
local context_line=""
local newline=$'\n'
local prompt_spacer=""
local separator="::"
if [ "$last_status" -ne 0 ]; then
separator="%F{red}::%f"
fi
if [ "$PROMPT_FIRST_RENDER" -eq 1 ]; then
PROMPT_FIRST_RENDER=0
PROMPT="%B%~%b ${separator} "
RPROMPT="%n@%m"
return 0
fi
vcs_info
git_segment="${vcs_info_msg_0_}"
git_status_segment="$(build_git_status_segment)"
if [ -n "${CONDA_DEFAULT_ENV:-}" ]; then
env_segment=" ${CONDA_DEFAULT_ENV}"
elif [ -n "${DIRENV_DIR:-}" ] || [ -n "${DIRENV_FILE:-}" ]; then
env_segment=" direnv"
fi
if project_has_pattern '**/docker-compose*.yml' '**/docker-compose*.yaml' '**/compose*.yml' '**/compose*.yaml'; then
project_symbols+=("%F{blue}%f")
fi
if project_has_pattern '**/Makefile' '**/makefile' '**/GNUmakefile' '**/Justfile' '**/justfile' '**/.justfile'; then
project_symbols+=("%F{yellow}%f")
fi
if project_has_pattern '**/pyproject.toml' '**/requirements.txt' '**/.python-version' '**/setup.py'; then
python_version="$(get_command_version python)"
[ -z "$python_version" ] || tool_versions+=("%F{magenta} ${python_version}%f")
fi
if project_has_pattern '**/package.json' '**/.nvmrc' '**/pnpm-workspace.yaml' '**/yarn.lock' '**/package-lock.json' '**/bun.lock' '**/bun.lockb'; then
node_version="$(get_command_version node)"
[ -z "$node_version" ] || tool_versions+=("%F{green} ${node_version}%f")
fi
if project_has_pattern '**/go.mod' '**/go.work'; then
go_version="$(get_command_version go)"
[ -z "$go_version" ] || tool_versions+=("%F{cyan} ${go_version}%f")
fi
if project_has_pattern '**/Cargo.toml' '**/Cargo.lock' '**/rust-toolchain.toml' '**/rust-toolchain'; then
rust_version="$(get_command_version rustc)"
[ -z "$rust_version" ] || tool_versions+=("%F{yellow} ${rust_version}%f")
fi
if [ -n "$git_segment" ]; then
context_line="%F{cyan}${git_segment}%f"
[ -z "$git_status_segment" ] || context_line+=" ${git_status_segment}"
fi
if [ -n "$env_segment" ]; then
[ -z "$context_line" ] || context_line+=" %F{240}·%f "
context_line+="%F{green}${env_segment}%f"
fi
if [ "${#project_symbols[@]}" -gt 0 ]; then
[ -z "$context_line" ] || context_line+=" %F{240}·%f "
context_line+="${(j: :)project_symbols}"
fi
if [ "${#tool_versions[@]}" -gt 0 ]; then
[ -z "$context_line" ] || context_line+=" %F{240}·%f "
context_line+="${(j: :)tool_versions}"
fi
if [ -n "$context_line" ]; then
context_line+="${newline}"
fi
if [ "$PROMPT_SHOW_SPACER" -eq 1 ]; then
prompt_spacer="$(build_prompt_separator_line "$last_status")${newline}"
fi
PROMPT="${prompt_spacer}${context_line}%B%~%b ${separator} "
RPROMPT="%n@%m"
}
add-zsh-hook preexec prompt_preexec
add-zsh-hook precmd build_prompt
build_prompt

View File

@@ -1,26 +0,0 @@
# ~/.zsh_secrets
#
# Copy this file to ~/.zsh_secrets and fill in real values locally.
# Do not commit real secrets.
# Core local values
export AZURE_URL=""
export VM_SUDO_PASS=""
# API keys and tokens
export TAOBAO_API_KEY=""
export AZURE_OPENAI_API_KEY=""
export OUTLINE_MOKU_TOKEN=""
export DOKPLOY_API_KEY=""
export N8N_AUTH=""
export CONTEXT7_API_KEY=""
export GITEA_ACCESS_TOKEN=""
export NETDATA_TOKEN=""
export OBSIDIAN_API_KEY=""
export GITHUB_TOKEN=""
export OPEN_ROUTER_API_KEY=""
# Optional overrides
# export VAULT_ADDR="http://192.168.30.53:8200"
# export OPENCHAMBER_HOST="0.0.0.0"
# export PLANNOTATOR_PORT="9999"

View File

@@ -1,29 +0,0 @@
# ENV File
# Load machine-local secrets before defining any derived environment variables.
[ -f "$HOME/.zsh_secrets" ] && source "$HOME/.zsh_secrets"
export GOGC=500
export R_ROOT="$HOME/.programming/r"
export R_LIBS_USER="$R_ROOT/library"
# CodeGraphContext defaults
export CGC_RUNTIME_DB_TYPE=kuzudb
export KUZUDB_PATH="$HOME/.codegraphcontext/kuzudb"
if [ -d "$HOME/.local/share/cgc-venv/bin" ]; then
export PATH="$HOME/.local/share/cgc-venv/bin:$PATH"
fi
export PATH="$HOME/.opencode/bin:$PATH"
export OPENCHAMBER_HOST="${OPENCHAMBER_HOST:-0.0.0.0}"
export VAULT_ADDR="${VAULT_ADDR:-http://192.168.30.53:8200}"
export PLANNOTATOR_PORT="${PLANNOTATOR_PORT:-9999}"
# Derived environment variables that may depend on machine-local secrets.
[ -n "${AZURE_URL:-}" ] && export AZURE_COGNITIVE_SERVICES_RESOURCE_NAME="$AZURE_URL"
[ -n "${AZURE_URL:-}" ] && export AZURE_RESOURCE_NAME="$AZURE_URL"
[ -n "${VM_SUDO_PASS:-}" ] && export OPENCHAMBER_UI_PASSWORD="$VM_SUDO_PASS"
[ -n "${AZURE_OPENAI_API_KEY:-}" ] && export FOUNDRY_ANTHROPIC_API_KEY="$AZURE_OPENAI_API_KEY"
[ -n "${AZURE_OPENAI_API_KEY:-}" ] && export CHROMA_OPENAI_API_KEY="$AZURE_OPENAI_API_KEY"
[ -n "${OUTLINE_MOKU_TOKEN:-}" ] && export OUTLINE_MOKU_AUTHORIZATION="Bearer $OUTLINE_MOKU_TOKEN"

View File

@@ -1,235 +0,0 @@
# .zshrc
# Zsh Configuration
export ZSH="$HOME/.oh-my-zsh"
export ZSH_CACHE_DIR="${XDG_CACHE_HOME:-$HOME/.cache}/oh-my-zsh"
export ZSH_COMPDUMP="${ZSH_CACHE_DIR}/.zcompdump-${HOST}-${ZSH_VERSION}"
mkdir -p "$ZSH_CACHE_DIR"
mkdir -p "$ZSH_CACHE_DIR/completions"
export DOTZSH_GIT_PLUGIN="$ZSH/plugins/git/git.plugin.zsh"
export DOTZSH_SUDO_PLUGIN="$ZSH/plugins/sudo/sudo.plugin.zsh"
export DOTZSH_RCLONE_PLUGIN="$ZSH/plugins/rclone/rclone.plugin.zsh"
export DOTZSH_AUTOSUGGESTIONS_PLUGIN="$ZSH/custom/plugins/zsh-autosuggestions/zsh-autosuggestions.zsh"
export DOTZSH_SYNTAX_HIGHLIGHTING_PLUGIN="$ZSH/custom/plugins/zsh-syntax-highlighting/zsh-syntax-highlighting.plugin.zsh"
export DOTZSH_HISTORY_SUBSTRING_SEARCH_PLUGIN="$ZSH/plugins/history-substring-search/history-substring-search.plugin.zsh"
# Programming Languages Root
export PROG_DIR="$HOME/.programming"
# History
export HISTFILE="$HOME/.zsh_history"
export HISTSIZE=10000
export SAVEHIST=10000
setopt APPEND_HISTORY
setopt SHARE_HISTORY
setopt EXTENDED_HISTORY
setopt HIST_EXPIRE_DUPS_FIRST
setopt HIST_IGNORE_ALL_DUPS
setopt HIST_IGNORE_SPACE
setopt HIST_FIND_NO_DUPS
setopt HIST_REDUCE_BLANKS
setopt HIST_SAVE_NO_DUPS
typeset -gA DOTZSH_MISSING_TOOL_WARNED
dotzsh_warn_missing_tool_once() {
local tool_key="$1"
local tool_label="$2"
local setup_hint="$3"
if [[ -n "${DOTZSH_MISSING_TOOL_WARNED[$tool_key]:-}" ]]; then
return 0
fi
DOTZSH_MISSING_TOOL_WARNED[$tool_key]=1
print -u2 -- "$tool_label is not installed on this system."
print -u2 -- "Run: $setup_hint"
print -u2 -- "Or: just setup all"
}
# Go and GVM (Black Box)
export GOPATH="$PROG_DIR/go"
export GVM_ROOT="$GOPATH"
gvm_load() {
local requested_command="$1"
unset -f gvm go gofmt
if [[ ! -s "$GVM_ROOT/scripts/gvm" ]]; then
dotzsh_warn_missing_tool_once "go" "Go / GVM" "just lang go"
return 127
fi
source "$GVM_ROOT/scripts/gvm"
if ! command -v "$requested_command" >/dev/null 2>&1; then
dotzsh_warn_missing_tool_once "go" "Go / GVM" "just lang go"
return 127
fi
"$@"
}
gvm() { gvm_load gvm "$@"; }
go() { gvm_load go "$@"; }
gofmt() { gvm_load gofmt "$@"; }
# Node and NVM (Lazy Load)
export NVM_DIR="$PROG_DIR/node"
nvm_load() {
local requested_command="$1"
unset -f nvm node npm npx
if [[ ! -s "$NVM_DIR/nvm.sh" ]]; then
dotzsh_warn_missing_tool_once "node" "Node / NVM" "just lang node"
return 127
fi
. "$NVM_DIR/nvm.sh"
if ! command -v "$requested_command" >/dev/null 2>&1; then
dotzsh_warn_missing_tool_once "node" "Node / NVM" "just lang node"
return 127
fi
"$@"
}
nvm() { nvm_load "nvm" "$@"; }
node() { nvm_load "node" "$@"; }
npm() { nvm_load "npm" "$@"; }
npx() { nvm_load "npx" "$@"; }
# Rust and Cargo
export RUSTUP_HOME="$PROG_DIR/rust/multirust"
export CARGO_HOME="$PROG_DIR/rust/cargo"
# Python (Pyenv + Miniconda)
export PYENV_ROOT="$PROG_DIR/python/pyenv"
export PATH="$PYENV_ROOT/bin:$PYENV_ROOT/shims:$PATH"
export CONDA_ROOT="$PYENV_ROOT/versions/miniforge3-latest"
pyenv_load() {
unset -f pyenv
if ! command -v pyenv >/dev/null 2>&1; then
dotzsh_warn_missing_tool_once "python" "Pyenv / Python" "just lang python"
return 127
fi
eval "$(command pyenv init -)"
if ! command -v pyenv >/dev/null 2>&1; then
dotzsh_warn_missing_tool_once "python" "Pyenv / Python" "just lang python"
return 127
fi
pyenv "$@"
}
pyenv() { pyenv_load "$@"; }
conda_load() {
local requested_command="$1"
unset -f conda mamba
if [[ ! -f "$CONDA_ROOT/etc/profile.d/conda.sh" ]]; then
dotzsh_warn_missing_tool_once "python" "Conda / Mamba" "just lang python"
return 127
fi
source "$CONDA_ROOT/etc/profile.d/conda.sh"
if ! command -v "$requested_command" >/dev/null 2>&1; then
dotzsh_warn_missing_tool_once "python" "Conda / Mamba" "just lang python"
return 127
fi
"$@"
}
conda() { conda_load conda "$@"; }
mamba() { conda_load mamba "$@"; }
# R and Rig
export RIG_HOME="$PROG_DIR/r"
if [ -d "$RIG_HOME/bin" ]; then
export PATH="$RIG_HOME/bin:$PATH"
fi
if [ -n "${WSL_DISTRO_NAME:-}" ] || [ -n "${WSL_INTEROP:-}" ]; then
typeset -gr DOTZSH_IS_WSL=1
elif [ -r /proc/sys/kernel/osrelease ] && grep -qiE '(microsoft|wsl)' /proc/sys/kernel/osrelease 2>/dev/null; then
typeset -gr DOTZSH_IS_WSL=1
else
typeset -gr DOTZSH_IS_WSL=0
fi
# Zoxide
if command -v zoxide >/dev/null 2>&1; then
eval "$(zoxide init --cmd cd zsh)"
fi
# Source Aliases & Secrets
[ -f ~/.zsh_aliases ] && source ~/.zsh_aliases
[ -f ~/.zsh_secrets ] && source ~/.zsh_secrets
# Add to PATH
export PATH="$HOME/.local/bin:$CARGO_HOME/bin:$GOPATH/bin:$PATH"
# opencode
if [ "$DOTZSH_IS_WSL" -eq 1 ] && command -v openchamber >/dev/null 2>&1 && ! pgrep -f "openchamber.*7891" >/dev/null 2>&1; then
openchamber --port 7891 >/dev/null 2>&1 &!
fi
# direnv
if command -v direnv >/dev/null 2>&1; then
eval "$(direnv hook zsh)"
fi
# Completion Styling
[ -f ~/.zsh_completion ] && source ~/.zsh_completion
# Plugin Scripts (lighter than loading full Oh My Zsh)
[ -f "$DOTZSH_GIT_PLUGIN" ] && source "$DOTZSH_GIT_PLUGIN"
[ -f "$DOTZSH_SUDO_PLUGIN" ] && source "$DOTZSH_SUDO_PLUGIN"
[ -f "$DOTZSH_RCLONE_PLUGIN" ] && source "$DOTZSH_RCLONE_PLUGIN"
# Prompt Styling
[ -f ~/.zsh_prompt ] && source ~/.zsh_prompt
# Interactive Enhancements
[ -f "$DOTZSH_HISTORY_SUBSTRING_SEARCH_PLUGIN" ] && source "$DOTZSH_HISTORY_SUBSTRING_SEARCH_PLUGIN"
[ -f "$DOTZSH_AUTOSUGGESTIONS_PLUGIN" ] && source "$DOTZSH_AUTOSUGGESTIONS_PLUGIN"
[ -f "$DOTZSH_SYNTAX_HIGHLIGHTING_PLUGIN" ] && source "$DOTZSH_SYNTAX_HIGHLIGHTING_PLUGIN"
export HISTORY_SUBSTRING_SEARCH_PREFIXED=1
# History keybindings
bindkey '^[[A' history-substring-search-up
bindkey '^[OA' history-substring-search-up
bindkey '^[[B' history-substring-search-down
bindkey '^[OB' history-substring-search-down
# bun
export BUN_INSTALL="$PROG_DIR/node/bun"
case ":$PATH:" in
*":$BUN_INSTALL/bin:"*) ;;
*) export PATH="$BUN_INSTALL/bin:$PATH" ;;
esac
# pnpm
export PNPM_HOME="$PROG_DIR/node/pnpm"
case ":$PATH:" in
*":$PNPM_HOME:"*) ;;
*) export PATH="$PNPM_HOME:$PATH" ;;
esac
# pnpm end

BIN
bin/eza Normal file

Binary file not shown.

BIN
bin/nvim Normal file

Binary file not shown.

22
scripts/azure.sh Normal file
View File

@@ -0,0 +1,22 @@
#!/bin/bash
# Path: scripts/azure.sh
echo "Checking disks..."
lsblk | grep nvme
sudo mkfs.xfs -f /dev/nvme0n1
sudo mkdir -p /mnt/nvme
sudo mount /dev/nvme0n1 /mnt/nvme
sudo chown -R $USER:$USER /mnt/nvme
echo "NVMe mounted at /mnt/nvme"
df -h /mnt/nvme
# rclone sync -P --transfers=16 hetzner-box:models/Qwen3-30B-A3B-Instruct-2507 /mnt/nvme/Qwen3-30B-A3B-Instruct-2507
# rclone sync -P --transfers=16 /mnt/nvme/Qwen3-70B-Instruct-2024-12-04 hetzner-box:models/Qwen3-70B-Instruct-2024-12-04

269
scripts/base.sh Executable file
View File

@@ -0,0 +1,269 @@
#!/bin/bash
# Path: scripts/base.sh
set -e
BLUE='\033[1;34m'
YELLOW='\033[1;33m'
GREEN='\033[1;32m'
RED='\033[1;31m'
NC='\033[0m'
DOTFILES_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
REPO_ROOT="$(dirname "$DOTFILES_DIR")"
source "$DOTFILES_DIR/lib/distro.sh"
echo -e "${BLUE} LOG:${YELLOW} Initializing Base System Layer...${NC}"
# Confirm Architecture
ARCH=$(uname -m)
if [ "$ARCH" != "x86_64" ] && [ "$ARCH" != "aarch64" ]; then
echo -e "${RED} ERROR: Unsupported architecture: $ARCH${NC}"
exit 1
fi
# Package Installation
PACKAGES=(
curl wget git sudo
zsh tmux
unzip tar gzip
build-essential
openssl
python bison mercurial
ripgrep fd bat fzf jq
btop httpie gnupg
zoxide stow direnv
bind nmap socat tcpdump net-tools
strace gdb hexyl
ninja-build libcurl4-openssl-dev
just
)
FINAL_PACKAGES=()
for pkg in "${PACKAGES[@]}"; do
case "$pkg" in
"build-essential")
if is_arch_family; then
FINAL_PACKAGES+=(base-devel)
elif is_debian_family; then
FINAL_PACKAGES+=(build-essential)
elif is_fedora_family; then
FINAL_PACKAGES+=(gcc gcc-c++ make patch)
fi
continue
;;
"python")
if is_arch_family; then
FINAL_PACKAGES+=(python)
elif is_debian_family; then
FINAL_PACKAGES+=(python3 python3-pip python3-venv)
elif is_fedora_family; then
FINAL_PACKAGES+=(python3 python3-pip)
fi
continue
;;
"fd")
if is_arch_family; then
FINAL_PACKAGES+=(fd)
elif is_debian_family || is_fedora_family; then
FINAL_PACKAGES+=(fd-find)
fi
continue
;;
"bat")
FINAL_PACKAGES+=(bat)
continue
;;
"openssl")
if is_arch_family; then
FINAL_PACKAGES+=(openssl)
elif is_debian_family; then
FINAL_PACKAGES+=(libssl-dev)
elif is_fedora_family; then
FINAL_PACKAGES+=(openssl openssl-devel)
fi
continue
;;
"bind")
if is_arch_family; then
FINAL_PACKAGES+=(bind)
elif is_debian_family; then
FINAL_PACKAGES+=(dnsutils)
elif is_fedora_family; then
FINAL_PACKAGES+=(bind-utils)
fi
continue
;;
"ninja-build")
if is_arch_family; then
FINAL_PACKAGES+=(ninja)
elif is_debian_family || is_fedora_family; then
FINAL_PACKAGES+=(ninja-build)
fi
continue
;;
"libcurl4-openssl-dev")
if is_arch_family; then
FINAL_PACKAGES+=(curl)
elif is_debian_family; then
FINAL_PACKAGES+=(libcurl4-openssl-dev)
elif is_fedora_family; then
FINAL_PACKAGES+=(libcurl-devel)
fi
continue
;;
"gnupg")
if is_fedora_family; then
FINAL_PACKAGES+=(gnupg2)
else
FINAL_PACKAGES+=(gnupg)
fi
continue
;;
*)
esac
FINAL_PACKAGES+=("$pkg")
done
if is_debian_family; then
FINAL_PACKAGES+=(ca-certificates bsdmainutils pkg-config cmake)
fi
if is_fedora_family; then
FINAL_PACKAGES+=(ca-certificates pkgconf-pkg-config cmake)
FINAL_PACKAGES+=(R-core gcc-gfortran bzip2 bzip2-devel readline-devel sqlite sqlite-devel tk-devel libffi-devel xz xz-devel ncurses-devel zlib-devel findutils llvm)
fi
echo -e "${BLUE} LOG:${YELLOW} Installing: ${NC}${FINAL_PACKAGES[*]}"
install_status=0
install_packages "${FINAL_PACKAGES[@]}" || install_status=$?
if [ "$install_status" -eq 42 ]; then
exit 0
elif [ "$install_status" -ne 0 ]; then
exit "$install_status"
fi
if is_debian_family || is_fedora_family; then
echo -e "${BLUE} LOG:${YELLOW} Fixing fd/bat binary names when needed...${NC}"
[ -f /usr/bin/fdfind ] && sudo ln -sf /usr/bin/fdfind /usr/local/bin/fd
[ -f /usr/bin/batcat ] && sudo ln -sf /usr/bin/batcat /usr/local/bin/bat
fi
# Moving Pre-Built bin to .local/bin
mkdir -p "$HOME/.local/bin"
cp -f "$REPO_ROOT/bin/"* "$HOME/.local/bin/"
chmod +x "$HOME/.local/bin/"*
if ! command -v rclone &> /dev/null; then
echo -e "${BLUE} LOG:${YELLOW} Installing Rclone CLI...${NC}"
case "$ARCH" in
x86_64)
RCLONE_ARCH="amd64"
;;
aarch64)
RCLONE_ARCH="arm64"
;;
esac
TEMP_DIR="$(mktemp -d)"
RCLONE_ZIP="$TEMP_DIR/rclone.zip"
curl -fLsS "https://downloads.rclone.org/rclone-current-linux-${RCLONE_ARCH}.zip" -o "$RCLONE_ZIP"
unzip -q "$RCLONE_ZIP" -d "$TEMP_DIR"
install -m 755 "$TEMP_DIR"/rclone-*-linux-"${RCLONE_ARCH}"/rclone "$HOME/.local/bin/rclone"
rm -rf "$TEMP_DIR"
fi
if ! command -v earthly &> /dev/null; then
echo -e "${BLUE} LOG:${YELLOW} Installing Earthly CLI...${NC}"
case "$ARCH" in
x86_64)
EARTHLY_ARCH="amd64"
;;
aarch64)
EARTHLY_ARCH="arm64"
;;
esac
curl -fLsS "https://github.com/earthly/earthly/releases/latest/download/earthly-linux-${EARTHLY_ARCH}" \
-o "$HOME/.local/bin/earthly"
chmod +x "$HOME/.local/bin/earthly"
fi
# Docker Installation
if command -v docker &> /dev/null; then
echo -e "${GREEN} LOG: Docker is already installed.${NC}"
else
if grep -qEi "(Microsoft|WSL)" /proc/version &> /dev/null; then
echo -e "${RED} LOG: WSL Detected! Skipping Native Docker.${NC}"
echo -e "${RED} >>> Please install Docker Desktop on Windows.${NC}"
else
echo -e "${BLUE} LOG:${YELLOW} Installing Native Docker...${NC}"
if is_arch_family; then
sudo pacman -S --noconfirm --needed docker docker-compose
sudo systemctl enable --now docker
elif is_debian_family; then
curl -fsSL https://get.docker.com | sh
elif is_fedora_family; then
if is_atomic_fedora; then
echo -e "${YELLOW} NOTE:${NC} Skipping native Docker auto-install on rpm-ostree systems."
echo -e "${YELLOW} NOTE:${NC} After reboot, install your preferred container runtime separately if needed."
else
sudo dnf install -y moby-engine docker-compose
sudo systemctl enable --now docker
fi
fi
# Add user to group
if getent group docker >/dev/null 2>&1; then
sudo usermod -aG docker $(whoami)
fi
fi
fi
# 4. Zsh & Configuration
if [ ! -d "$HOME/.oh-my-zsh" ]; then
echo -e "${BLUE} LOG:${YELLOW} Installing Oh My Zsh...${NC}"
sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)" "" --unattended
fi
# Plugins
ZSH_CUSTOM="${ZSH_CUSTOM:-$HOME/.oh-my-zsh/custom}"
mkdir -p "$ZSH_CUSTOM/plugins"
[ ! -d "$ZSH_CUSTOM/plugins/zsh-syntax-highlighting" ] && git clone https://github.com/zsh-users/zsh-syntax-highlighting.git "$ZSH_CUSTOM/plugins/zsh-syntax-highlighting"
[ ! -d "$ZSH_CUSTOM/plugins/zsh-autosuggestions" ] && git clone https://github.com/zsh-users/zsh-autosuggestions "$ZSH_CUSTOM/plugins/zsh-autosuggestions"
# 5. Git Credentials (WSL Bridge)
if grep -qEi "(Microsoft|WSL)" /proc/version &> /dev/null; then
GCM_WIN="/mnt/c/Program Files/Git/mingw64/bin/git-credential-manager.exe"
[ -f "$GCM_WIN" ] && git config --global credential.helper "! \"$GCM_WIN\""
else
git config --global credential.helper 'cache --timeout=43200'
fi
# 6. Cleanup & Secrets
rm -f "$HOME/.zshrc" "$HOME/.zsh_aliases"
touch "$HOME/.zsh_secrets"
# 7. Set Shell
TARGET_SHELL="$(command -v zsh)"
CURRENT_LOGIN_SHELL="$(getent passwd "$(whoami)" | cut -d: -f7)"
if [ "$CURRENT_LOGIN_SHELL" != "$TARGET_SHELL" ]; then
if command -v chsh >/dev/null 2>&1; then
sudo chsh -s "$TARGET_SHELL" "$(whoami)"
elif command -v usermod >/dev/null 2>&1; then
sudo usermod -s "$TARGET_SHELL" "$(whoami)"
else
echo -e "${YELLOW} NOTE:${NC} Could not find chsh/usermod. Please change your login shell to $TARGET_SHELL manually."
fi
fi
echo -e "${GREEN} LOG: Base System Setup Complete.${NC}"

View File

@@ -1,6 +1,6 @@
#!/bin/bash
# Path: Scripts/cpp.sh
# Path: scripts/cpp.sh
set -e

80
scripts/go.sh Normal file
View File

@@ -0,0 +1,80 @@
#!/bin/bash
# Path: scripts/go.sh
set -e
BLUE='\033[1;34m'
YELLOW='\033[1;33m'
GREEN='\033[1;32m'
RED='\033[1;31m'
NC='\033[0m'
export GVM_ROOT="$HOME/.programming/go"
BOOTSTRAP_GO="$GVM_ROOT/bootstrap"
ARCH="$(uname -m)"
case "$ARCH" in
x86_64)
GO_BOOTSTRAP_ARCH="amd64"
;;
aarch64)
GO_BOOTSTRAP_ARCH="arm64"
;;
*)
echo -e "${RED} ERROR:${NC} Unsupported architecture for Go bootstrap: $ARCH"
exit 1
;;
esac
echo -e "${BLUE} LOG:${YELLOW} Setting up Go and GVM in ${GVM_ROOT}...${NC}"
if [ ! -d "$GVM_ROOT/scripts" ]; then
echo -e "${BLUE} LOG:${YELLOW} Cloning GVM...${NC}"
git clone https://github.com/moovweb/gvm.git "$GVM_ROOT"
rm -rf "$GVM_ROOT/.git"
echo -e "${BLUE} LOG:${YELLOW} Configuring GVM scripts...${NC}"
cp "$GVM_ROOT/scripts/gvm-default" "$GVM_ROOT/scripts/gvm"
sed -i "s|^GVM_ROOT=.*|GVM_ROOT=\"$GVM_ROOT\"|" "$GVM_ROOT/scripts/gvm"
echo -e "${GREEN} SUCCESS:${NC} GVM cloned and configured."
else
echo -e "${GREEN} SKIP:${NC} GVM already installed."
fi
if [ ! -d "$BOOTSTRAP_GO" ]; then
echo -e "${BLUE} LOG:${YELLOW} Downloading Bootstrap Go...${NC}"
mkdir -p "$BOOTSTRAP_GO"
wget -q "https://go.dev/dl/go1.20.5.linux-${GO_BOOTSTRAP_ARCH}.tar.gz" -O /tmp/go-bootstrap.tar.gz
tar -C "$BOOTSTRAP_GO" -xzf /tmp/go-bootstrap.tar.gz --strip-components=1
rm /tmp/go-bootstrap.tar.gz
echo -e "${GREEN} SUCCESS:${NC} Bootstrap Go installed."
else
echo -e "${GREEN} SKIP:${NC} Bootstrap Go already exists."
fi
export PATH="$BOOTSTRAP_GO/bin:$PATH"
export GOROOT_BOOTSTRAP="$BOOTSTRAP_GO"
set +e
source "$GVM_ROOT/scripts/gvm"
set -e
if ! command -v gvm &> /dev/null; then
echo -e "${RED} ERROR:${NC} GVM failed to load."
exit 1
fi
TARGET_VER="go1.24.11"
if ! gvm list | grep -q "$TARGET_VER"; then
echo -e "${BLUE} LOG:${YELLOW} Installing ${TARGET_VER}...${NC}"
gvm install "$TARGET_VER" --prefer-binary
fi
gvm use "$TARGET_VER" --default
echo -e "${GREEN} SUCCESS:${NC} Go setup completed."

View File

@@ -10,11 +10,8 @@ if [ -f /etc/os-release ]; then
. /etc/os-release
OS="${ID}"
OS_LIKE="${ID_LIKE:-}"
elif [ "$(uname -s)" = "Darwin" ]; then
OS="macos"
OS_LIKE="darwin"
else
echo "Unable to detect operating system: /etc/os-release not found and host is not macOS."
echo "Unable to detect operating system: /etc/os-release not found."
return 1 2>/dev/null || exit 1
fi
@@ -30,10 +27,6 @@ is_fedora_family() {
[[ "$OS" == "fedora" || "$OS" == "bazzite" || " $OS_LIKE " == *" fedora "* || " $OS_LIKE " == *" rhel "* ]]
}
is_macos() {
[[ "$OS" == "macos" ]]
}
is_atomic_fedora() {
is_fedora_family && command -v rpm-ostree >/dev/null 2>&1 && [ -f /run/ostree-booted ]
}
@@ -133,22 +126,6 @@ install_packages() {
return 0
fi
if is_macos; then
if ! command -v brew >/dev/null 2>&1; then
echo "Homebrew is required on macOS. Install it from https://brew.sh first."
return 1
fi
local pkg
for pkg in "${packages[@]}"; do
if brew list --formula "$pkg" >/dev/null 2>&1; then
continue
fi
brew install "$pkg"
done
return 0
fi
echo "Unsupported OS: $OS"
return 1
}

View File

@@ -1,6 +1,6 @@
#!/bin/bash
# Path: Scripts/node.sh
# Path: scripts/node.sh
set -e
@@ -11,7 +11,6 @@ NC='\033[0m'
export NVM_DIR="$HOME/.programming/node"
export COREPACK_ENABLE_DOWNLOAD_PROMPT=0
export BUN_INSTALL="$NVM_DIR/bun"
echo -e "${BLUE} LOG:${YELLOW} Setting up Node.js (NVM) in ${NVM_DIR}...${NC}"
@@ -32,22 +31,8 @@ if command -v nvm &> /dev/null; then
corepack enable
echo -e "${BLUE} LOG:${YELLOW} Preparing pnpm and yarn...${NC}"
corepack prepare pnpm@latest --activate
corepack prepare yarn@stable --activate
if [ ! -x "$BUN_INSTALL/bin/bun" ]; then
echo -e "${BLUE} LOG:${YELLOW} Installing Bun to ${BUN_INSTALL}...${NC}"
curl -fsSL https://bun.sh/install | bash
else
echo -e "${BLUE} LOG:${YELLOW} Bun already installed at ${BUN_INSTALL}.${NC}"
fi
export PATH="$BUN_INSTALL/bin:$PATH"
echo -e "${GREEN} LOG: Node setup complete. $(node -v)${NC}"
echo -e "${GREEN} LOG: Package Managers: pnpm $(pnpm -v), yarn $(yarn -v), bun $(bun -v)${NC}"
echo -e "${GREEN} LOG: Package Managers: pnpm $(pnpm -v), yarn $(yarn -v)${NC}"
else
echo -e "${RED} ERROR: NVM failed to load from $NVM_DIR${NC}"
exit 1

8
Scripts/provision.sh → scripts/provision.sh Normal file → Executable file
View File

@@ -1,6 +1,6 @@
#!/bin/bash
# Path: Scripts/provision.sh
# Path: scripts/provision.sh
set -e
@@ -36,11 +36,11 @@ fi
echo -e "${YELLOW}LOG: Updating system and installing base tools...${NC}"
if is_arch_family; then
pacman -Sy --noconfirm git make curl rsync zsh sudo
pacman -Sy --noconfirm git make curl zsh sudo
SUDO_GROUP="wheel"
elif is_debian_family; then
apt-get update
apt-get install -y git make curl rsync sudo zsh
apt-get install -y git make curl sudo zsh
SUDO_GROUP="sudo"
elif is_fedora_family; then
if is_atomic_fedora; then
@@ -49,7 +49,7 @@ elif is_fedora_family; then
exit 1
fi
dnf install -y git make curl rsync sudo zsh
dnf install -y git make curl sudo zsh
SUDO_GROUP="wheel"
else
echo -e "${RED}Unsupported OS: $OS${NC}"

View File

@@ -1,6 +1,6 @@
#!/bin/bash
# Path: Scripts/python.sh
# Path: scripts/python.sh
set -e
BLUE='\033[1;34m'
@@ -22,9 +22,6 @@ elif is_debian_family; then
elif is_fedora_family; then
echo -e "${BLUE} LOG:${YELLOW} Installing Fedora build dependencies...${NC}"
PYTHON_BUILD_DEPS=(make gcc gcc-c++ patch zlib-devel bzip2 bzip2-devel readline-devel sqlite sqlite-devel openssl-devel tk-devel libffi-devel xz xz-devel ncurses-devel findutils git)
elif is_macos; then
echo -e "${BLUE} LOG:${YELLOW} Installing macOS build dependencies...${NC}"
PYTHON_BUILD_DEPS=(openssl@3 readline sqlite xz tcl-tk bzip2 zlib pkg-config git)
else
echo -e "${RED} ERROR:${NC} Unsupported OS: $OS"
exit 1

103
scripts/r.sh Normal file
View File

@@ -0,0 +1,103 @@
#!/bin/bash
# Path: scripts/r.sh
set -e
BLUE='\033[1;34m'
YELLOW='\033[1;33m'
GREEN='\033[1;32m'
RED='\033[1;31m'
NC='\033[0m'
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
source "$SCRIPT_DIR/lib/distro.sh"
echo -e "${BLUE} LOG:${YELLOW} Detecting R installation strategy for $OS...${NC}"
if is_arch_family; then
echo -e "${BLUE} LOG:${YELLOW} Arch Linux detected. Using system R (Pacman)...${NC}"
# Install R + Build Tools
install_status=0
install_packages r gcc-fortran curl tar || install_status=$?
if [ "$install_status" -eq 42 ]; then
exit 0
elif [ "$install_status" -ne 0 ]; then
exit "$install_status"
fi
echo -e "${GREEN} SUCCESS:${NC} R installed via Pacman."
R_BIN="R"
elif is_debian_family; then
echo -e "${BLUE} LOG:${YELLOW} Installing Debian build dependencies...${NC}"
install_status=0
install_packages gfortran curl tar ca-certificates || install_status=$?
if [ "$install_status" -eq 42 ]; then
exit 0
elif [ "$install_status" -ne 0 ]; then
exit "$install_status"
fi
if ! command -v rig >/dev/null 2>&1; then
echo -e "${BLUE} LOG:${YELLOW} Installing Rig for Debian/Ubuntu...${NC}"
DEB_ARCH=$(dpkg --print-architecture)
case "$DEB_ARCH" in
amd64|arm64)
;;
*)
echo -e "${RED} ERROR:${NC} Unsupported Debian architecture for Rig: $DEB_ARCH"
exit 1
;;
esac
LATEST_REL_DATA=$(curl -fsSL https://api.github.com/repos/r-lib/rig/releases/latest)
RIG_URL=$(echo "$LATEST_REL_DATA" | grep -o "https://[^\"]*r-rig_[^\"]*_${DEB_ARCH}\.deb" | head -n 1)
if [ -z "$RIG_URL" ]; then
echo -e "${RED} ERROR:${NC} Could not find Rig .deb download URL for architecture: $DEB_ARCH"
exit 1
fi
TEMP_DEB=$(mktemp --suffix=.deb)
curl -fLsS "$RIG_URL" -o "$TEMP_DEB"
sudo apt-get install -y "$TEMP_DEB"
rm -f "$TEMP_DEB"
fi
TARGET_VER="release"
if ! rig list | grep -q "release"; then
echo -e "${BLUE} LOG:${YELLOW} Installing R (${TARGET_VER})...${NC}"
sudo rig add "$TARGET_VER" --without-cran-mirror
sudo rig default "$TARGET_VER"
fi
R_BIN="rig run"
elif is_fedora_family; then
echo -e "${BLUE} LOG:${YELLOW} Fedora detected. Using system R...${NC}"
install_status=0
install_packages R-core gcc-gfortran curl tar || install_status=$?
if [ "$install_status" -eq 42 ]; then
exit 0
elif [ "$install_status" -ne 0 ]; then
exit "$install_status"
fi
R_BIN="R"
else
echo -e "${RED} ERROR:${NC} Unsupported OS: $OS"
exit 1
fi
echo -e "${BLUE} LOG:${YELLOW} Installing 'renv' package in the user R library...${NC}"
$R_BIN -e 'user_lib <- path.expand(Sys.getenv("R_LIBS_USER", unset = "~/R/library")); dir.create(user_lib, recursive = TRUE, showWarnings = FALSE); .libPaths(c(user_lib, .libPaths())); if (!require("renv", quietly=TRUE)) install.packages("renv", lib = user_lib, repos = "https://cloud.r-project.org")'
echo -e "${GREEN} SUCCESS:${NC} R setup completed."

View File

@@ -1,6 +1,6 @@
#!/bin/bash
# Path: Scripts/rust.sh
# Path: scripts/rust.sh
set -e

116
scripts/storagebox.sh Normal file
View File

@@ -0,0 +1,116 @@
#!/bin/bash
set -e
# Colors
BLUE='\033[1;34m'
YELLOW='\033[1;33m'
GREEN='\033[1;32m'
RED='\033[1;31m'
NC='\033[0m'
SECRETS_FILE="$HOME/.zsh_secrets"
REMOTE_NAME="hetzner-box"
# Dependency Check
if ! command -v rclone &> /dev/null; then
echo -e "${RED}Error: rclone is not installed.${NC}"
exit 1
fi
# Load Secrets
if [ -f "$SECRETS_FILE" ]; then
source "$SECRETS_FILE"
fi
# Configure Remote (If missing)
if ! rclone listremotes | grep -q "^${REMOTE_NAME}:$"; then
echo -e "${BLUE}Configuration missing. Starting setup...${NC}"
if [ -z "$HETZNER_USER" ]; then
DEFAULT_USER="u513875"
read -p "Enter Username [$DEFAULT_USER]: " INPUT_USER
HETZNER_USER="${INPUT_USER:-$DEFAULT_USER}"
fi
if [ -z "$HETZNER_HOST" ]; then
DEFAULT_HOST="${HETZNER_USER}.your-storagebox.de"
read -p "Enter Host [$DEFAULT_HOST]: " INPUT_HOST
HETZNER_HOST="${INPUT_HOST:-$DEFAULT_HOST}"
fi
if [ -z "$HETZNER_PASS" ]; then
echo -e "${YELLOW}Note: Passwords are obscured in config, but saving to secrets file uses plain text.${NC}"
read -s -p "Enter Password: " HETZNER_PASS
echo ""
fi
# Save to secrets
if ! grep -q "HETZNER_USER" "$SECRETS_FILE" 2>/dev/null; then
echo -e "${BLUE}Saving credentials to $SECRETS_FILE...${NC}"
{
echo ""
echo "# Hetzner Storage Box"
echo "export HETZNER_USER=\"$HETZNER_USER\""
echo "export HETZNER_HOST=\"$HETZNER_HOST\""
echo "export HETZNER_PASS=\"$HETZNER_PASS\""
} >> "$SECRETS_FILE"
fi
OBSCURED_PASS=$(rclone obscure "$HETZNER_PASS")
rclone config create "$REMOTE_NAME" sftp \
host "$HETZNER_HOST" \
user "$HETZNER_USER" \
pass "$OBSCURED_PASS" \
port 23 \
--non-interactive
echo -e "${GREEN}Configuration created!${NC}"
fi
# Interactive Menu
echo -e "${BLUE}--- Hetzner Storage Box Manager ---${NC}"
echo "1) List files (ls)"
echo "2) Upload (Copy LOCAL -> REMOTE)"
echo "3) Download (Copy REMOTE -> LOCAL)"
echo "q) Quit"
read -p "Select option: " OPTION
case $OPTION in
1)
read -p "Enter depth [1]: " INPUT_DEPTH
DEPTH="${INPUT_DEPTH:-1}"
echo -e "${BLUE}Listing files on Hetzner...${NC}"
rclone ls "${REMOTE_NAME}:" --max-depth "$DEPTH"
;;
2)
read -p "Enter local folder/file to upload: " LOCAL_PATH
LOCAL_PATH=${LOCAL_PATH%/}
read -p "Enter remote destination folder (e.g. Backup): " REMOTE_FOLDER
REMOTE_FOLDER=${REMOTE_FOLDER#/}
REMOTE_FOLDER=${REMOTE_FOLDER%/}
echo -e "${YELLOW}Uploading '$LOCAL_PATH' to '${REMOTE_NAME}:$REMOTE_FOLDER'...${NC}"
rclone copy "$LOCAL_PATH" "${REMOTE_NAME}:$REMOTE_FOLDER" -P
;;
3)
echo -e "${BLUE}Contents of Root:${NC}"
rclone lsd "${REMOTE_NAME}:"
read -p "Enter remote path to download (e.g. models/Test): " REMOTE_PATH
REMOTE_PATH=${REMOTE_PATH#/}
read -p "Enter local destination folder: " LOCAL_DEST
mkdir -p "$LOCAL_DEST"
echo -e "${YELLOW}Downloading '${REMOTE_NAME}:$REMOTE_PATH' to '$LOCAL_DEST'...${NC}"
rclone copy "${REMOTE_NAME}:$REMOTE_PATH" "$LOCAL_DEST" -P
;;
q)
exit 0
;;
*)
echo "Invalid option"
;;
esac