bulk: syncr
This commit is contained in:
parent
f0e039461c
commit
344e1693bd
55 changed files with 1838 additions and 796 deletions
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
.data/
|
||||
target/
|
12
README.md
12
README.md
|
@ -1,12 +0,0 @@
|
|||
# Raine's Dotfiles
|
||||
|
||||
## Crates
|
||||
Everything is a crate.
|
||||
If something is distro specific you should follow the following naming scheme:
|
||||
`crate.<DISTRO>.sh`
|
||||
|
||||
## Using it
|
||||
Just use the script tbh
|
||||
```sh
|
||||
curl -L https://via.ixvd.net/sh | sh
|
||||
```
|
|
@ -1,12 +0,0 @@
|
|||
super_apply() {
|
||||
pacman -Syyu --noconfirm
|
||||
pacman -S --needed --noconfirm sudo reflector
|
||||
if ! grep -q "Reflector" /etc/pacman.d/mirrorlist; then
|
||||
cp /etc/pacman.d/mirrorlist /etc/pacman.d/mirrorlist.bak
|
||||
reflector -c NL -f 10 --threads 4 --save /etc/pacman.d/mirrorlist
|
||||
else
|
||||
echo "err: reflector already executed -- skipping..."
|
||||
fi
|
||||
|
||||
cp files/pacman.conf /etc/pacman.conf
|
||||
}
|
|
@ -1,5 +0,0 @@
|
|||
super_apply() {
|
||||
apt update -y
|
||||
apt install -y netselect-apt sudo
|
||||
netselect-apt
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
#!/bin/sh
|
||||
|
||||
describe="Install stuff on the system!"
|
||||
scripts="@distro @self"
|
||||
|
||||
super_apply() {
|
||||
if [ -f /usr/lib/security/pam_wheel.so ] && ! grep -q "# pam_wheel.so added" /etc/pam.d/su; then
|
||||
echo "auth sufficient pam_wheel.so trust use_uid" > /etc/pam.d/su
|
||||
echo "# pam_wheel.so added" > /etc/pam.d/su
|
||||
fi
|
||||
}
|
|
@ -1,31 +0,0 @@
|
|||
[options]
|
||||
HoldPkg = pacman glibc yay
|
||||
Architecture = auto
|
||||
|
||||
Color
|
||||
CheckSpace
|
||||
ParallelDownloads = 5
|
||||
|
||||
SigLevel = Required DatabaseOptional
|
||||
LocalFileSigLevel = Optional
|
||||
|
||||
#[testing]
|
||||
#Include = /etc/pacman.d/mirrorlist
|
||||
|
||||
[core]
|
||||
Include = /etc/pacman.d/mirrorlist
|
||||
|
||||
[extra]
|
||||
Include = /etc/pacman.d/mirrorlist
|
||||
|
||||
#[community-testing]
|
||||
#Include = /etc/pacman.d/mirrorlist
|
||||
|
||||
[community]
|
||||
Include = /etc/pacman.d/mirrorlist
|
||||
|
||||
#[multilib-testing]
|
||||
#Include = /etc/pacman.d/mirrorlist
|
||||
|
||||
[multilib]
|
||||
Include = /etc/pacman.d/mirrorlist
|
|
@ -1,18 +0,0 @@
|
|||
#!/bin/sh
|
||||
|
||||
describe="setup ssh"
|
||||
|
||||
apply() {
|
||||
[ -e "$HOME/.ssh/authorized_keys" ] || ln files/authorized_keys $HOME/.ssh/authorized_keys
|
||||
[ -e "$HOME/.ssh/config" ] || ln files/config $HOME/.ssh/config
|
||||
if ! [ -f "$HOME/.ssh/id_rsa" ]; then
|
||||
echo "Creating new ssh key for this device..."
|
||||
ssh-keygen -f $HOME/.ssh/id_rsa -p "" -q
|
||||
echo "Adding key to authorized_keys..."
|
||||
cat $HOME/.ssh/id_rsa.pub > $HOME/.ssh/authorized_keys
|
||||
fi
|
||||
}
|
||||
|
||||
undo() {
|
||||
echo "Undoing ssh keys is not supported, please do this manually."
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCeNQfnbyyF3sht43vH5BcXDPca8nWu6bKPVGvAlWBOq4Av8ME2IQgwVe9nJ05r73ZY02/Vdqc01a8wyK5Hmw0XlPL0Cn6wc9QoiscOvq5lMUK87S2tr3EVLGkgl8o7nmVuWgLewyojiORjM02P1PZEiFhKPXVEQFxU0dFz9QtpAdm0u78Xn2HTukHpXSv44R3XDDMFZ3Ek/XRuS6J9dZVxGkgCLQhK8kpfbxuiYxaRC7MHgGlYuxjLuZ6P4i+V+SSSShfCGdm6U9bgeIAwftN6a8Pc9+OsBeZGSUrGjZjRlD35q0a7fbpoS8pKTfbwgf/ijYeu3JmAQUlY+H959mIpg4H9XOgRrKVJSYwx5/BGuhmWgVy6HIYpXCQfEbLE7QDmwC2C430KzAH6jCcrRNyurIUCuO4iq9dwoQTzboMccOK79S2Z+1B5fYgS3BZgaiTUBSME2G2FriM6utgleiBnvFu/p7oH2I8ZHL/aVcSWAw0gbzsr7ADywAuiDNZk18c= strix@ryuk
|
|
@ -1,22 +0,0 @@
|
|||
## neb servers
|
||||
|
||||
# hydrogen red helix
|
||||
Host H
|
||||
Hostname hydrogen.red.helix.saluco.nl
|
||||
|
||||
# argon red helix
|
||||
Host A
|
||||
Hostname argon.red.helix.saluco.nl
|
||||
|
||||
# iron red sphere
|
||||
Host I
|
||||
Hostname iron.red.sphere.saluco.nl
|
||||
|
||||
## utility servers
|
||||
Host git
|
||||
Hostname git.saluco.nl
|
||||
User git
|
||||
|
||||
Host github
|
||||
Hostname github.com
|
||||
User git
|
|
@ -1,11 +0,0 @@
|
|||
#!/bin/sh
|
||||
|
||||
pkgs="i3 i3lock i3status libpulse brightnessctl xss-lock dex maim dmenu gnome-keyring feh picom"
|
||||
|
||||
super_apply() {
|
||||
pacman -S --needed --noconfirm $pkgs
|
||||
}
|
||||
|
||||
super_undo() {
|
||||
pacman -R --noconfirm $pkgs
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
#!/bin/sh
|
||||
|
||||
pkgs="i3 i3lock i3status libpulse-mainloop-glib brightnessctl xss-lock dex maim dmenu gnome-keyring feh picom"
|
||||
|
||||
super_apply() {
|
||||
apt install -y $pkgs
|
||||
}
|
||||
|
||||
super_undo() {
|
||||
apt remove -y $pkgs
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
#!/bin/sh
|
||||
|
||||
describe="Installs i3"
|
||||
scripts="@distro @self"
|
||||
|
||||
apply() {
|
||||
[ -d "$HOME/.config/i3" ] || mkdir -p $HOME/.config/i3
|
||||
[ -d "$HOME/.config/i3status" ] || mkdir -p $HOME/.config/i3status
|
||||
[ -e "$HOME/.config/i3/config" ] || ln files/config $HOME/.config/i3/config
|
||||
[ -e "$HOME/.config/i3status/config" ] || ln files/status_config $HOME/.config/i3status/config
|
||||
[ -e "$HOME/.config/picom.conf" ] || ln files/picom.conf $HOME/.config/picom.conf
|
||||
}
|
||||
|
||||
undo() {
|
||||
rm $HOME/.config/i3/config
|
||||
rm $HOME/.config/i3status/config
|
||||
}
|
||||
|
||||
super_apply() {
|
||||
[ -d "/etc/X11/xorg.conf.d" ] || mkdir -p /etc/X11/xorg.conf.d/
|
||||
cp files/40-proper-touchpad.conf /etc/X11/xorg.conf.d/40-proper-touchpad.conf
|
||||
}
|
||||
|
||||
super_undo() {
|
||||
rm /etc/X11/xorg.conf.d/40-proper-touchpad.conf
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
#!/bin/sh
|
||||
|
||||
pkgs="i3 i3lock i3status pulseaudio-devel brightnessctl xss-lock dex maim dmenu gnome-keyring feh picom"
|
||||
|
||||
super_apply() {
|
||||
xbps-install -y $pkgs
|
||||
}
|
||||
|
||||
super_undo() {
|
||||
xbps-remove -y $pkgs
|
||||
}
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
Section "InputClass"
|
||||
Identifier "libinput touchpad catchall"
|
||||
MatchIsTouchpad "on"
|
||||
MatchDevicePath "/dev/input/event*"
|
||||
Driver "libinput"
|
||||
Option "NaturalScrolling" "True"
|
||||
Option "Tapping" "on"
|
||||
EndSection
|
|
@ -1,206 +0,0 @@
|
|||
#######################
|
||||
## Raine's i3 config ##
|
||||
## Mar 22, 2023 ##
|
||||
## mutation: 1m ##
|
||||
#######################
|
||||
|
||||
## Mostly similar to i3's config yet differs
|
||||
|
||||
# Useful variables:
|
||||
# This section probably gets changed a lot
|
||||
# ---
|
||||
set $terminal alacritty
|
||||
set $screen_lock i3lock -c "#111111" --nofork
|
||||
set $appmenu i3-dmenu-desktop
|
||||
|
||||
set $screenshot maim -s | xclip -selection clipboard -t image/png
|
||||
|
||||
set $font pango:monospace 8
|
||||
|
||||
# Startup Applications:
|
||||
# Things that will startup when starting i3.
|
||||
# ---
|
||||
exec_always --no-startup-id dex --autostart --environment i3
|
||||
exec_always --no-startup-id nm-applet
|
||||
exec_always --no-startup-id xss-lock --transfer-sleep-lock -- $screen_lock
|
||||
exec_always --no-startup-id gnome-keyring-daemon --start --components=ssh,secrets,pkcs11
|
||||
exec_always --no-startup-id feh --bg-fill ~/Pictures/wallpaper.jpg
|
||||
exec_always --no-startup-id picom
|
||||
|
||||
# Gaps & Borders:
|
||||
# ---
|
||||
gaps inner 10
|
||||
smart_gaps on
|
||||
|
||||
default_border pixel 1
|
||||
hide_edge_borders smart_no_gaps
|
||||
|
||||
# Extra variables:
|
||||
# Only need changing for very specific installations.
|
||||
# ---
|
||||
set $audio_volume_up XF86AudioRaiseVolume
|
||||
set $audio_volume_down XF86AudioLowerVolume
|
||||
set $audio_mute XF86AudioMute
|
||||
set $audio_mute_mic XF86AudioMicMute
|
||||
|
||||
set $brightness_up XF86MonBrightnessUp
|
||||
set $brightness_down XF86MonBrightnessDown
|
||||
|
||||
set $ws_1 "1:main"
|
||||
set $ws_2 "2:term"
|
||||
set $ws_3 "3:docs"
|
||||
set $ws_4 "4:mail"
|
||||
set $ws_5 "5"
|
||||
set $ws_6 "6"
|
||||
set $ws_7 "7"
|
||||
set $ws_8 "8"
|
||||
set $ws_9 "9:bg"
|
||||
set $ws_10 "10:misc"
|
||||
|
||||
set $meta_refresh_statusbar killall -SIGUSR1 i3status
|
||||
bar {
|
||||
strip_workspace_numbers yes
|
||||
status_command i3status
|
||||
}
|
||||
|
||||
# END OF CONFIG
|
||||
|
||||
set $mod Mod4
|
||||
set $alt Mod1
|
||||
|
||||
# Customization
|
||||
|
||||
# class border backgr. text indic. child_border
|
||||
client.focused #81A1C1 #81A1C1 #ffffff #D8DEE9
|
||||
client.focused_inactive #2E3440 #2E3440 #88C0D0 #454948
|
||||
client.unfocused #2E3440 #2E3440 #88C0D0 #454948
|
||||
client.urgent #D08770 #3B4252 #ffffff #268BD2
|
||||
client.placeholder #000000 #0c0c0c #ffffff #000000
|
||||
client.background #3B4252
|
||||
|
||||
# Generic
|
||||
floating_modifier $mod
|
||||
tiling_drag modifier titlebar
|
||||
font $font
|
||||
|
||||
# Open a terminal
|
||||
bindsym $mod+Return exec $terminal
|
||||
|
||||
# Kill current window
|
||||
bindsym $mod+$alt+q kill
|
||||
|
||||
# Open app menu
|
||||
bindsym $mod+d exec --no-startup-id $appmenu
|
||||
|
||||
# Lock screen
|
||||
bindsym $mod+l exec --no-startup-id $screen_lock
|
||||
|
||||
# Screenshots
|
||||
bindsym Print exec --no-startup-id $screenshot
|
||||
|
||||
# Audio
|
||||
bindsym $audio_volume_up exec --no-startup-id pactl set-sink-volume @DEFAULT_SINK@ +10% && $meta_refresh_statusbar
|
||||
bindsym $audio_volume_down exec --no-startup-id pactl set-sink-volume @DEFAULT_SINK@ -10% && $meta_refresh_statusbar
|
||||
bindsym $audio_mute exec --no-startup-id pactl set-sink-mute @DEFAULT_SINK@ toggle && $meta_refresh_statusbar
|
||||
bindsym $audio_mute_mic exec --no-startup-id pactl set-source-mute @DEFAULT_SOURCE@ toggle && $meta_refresh_statusbar
|
||||
|
||||
# Brightness
|
||||
bindsym $brightness_up exec --no-startup-id brightnessctl set +5% && $meta_refresh_statusbar
|
||||
bindsym $brightness_down exec --no-startup-id brightnessctl set 5%- && $meta_refresh_statusbar
|
||||
|
||||
# Change focused window
|
||||
bindsym $mod+Up focus up
|
||||
bindsym $mod+Down focus down
|
||||
bindsym $mod+Left focus left
|
||||
bindsym $mod+Right focus right
|
||||
|
||||
# Move focused window
|
||||
bindsym $mod+Shift+Up move up
|
||||
bindsym $mod+Shift+Down move down
|
||||
bindsym $mod+Shift+Left move left
|
||||
bindsym $mod+Shift+Right move right
|
||||
|
||||
# Splits
|
||||
bindsym $mod+Shift+h split h
|
||||
bindsym $mod+Shift+v split v
|
||||
|
||||
# Change container layout
|
||||
bindsym $mod+Shift+s layout stacking
|
||||
bindsym $mod+Shift+t layout tabbed
|
||||
bindsym $mod+Shift+d layout toggle split
|
||||
|
||||
# Make current window fullscreen
|
||||
bindsym $mod+Shift+f fullscreen toggle
|
||||
|
||||
# Floating stuff
|
||||
bindsym $mod+space focus mode_toggle
|
||||
bindsym $mod+Shift+space floating toggle
|
||||
|
||||
# Scratchpad
|
||||
bindsym $mod+Shift+minus move scratchpad
|
||||
bindsym $mod+minus scratchpad show
|
||||
|
||||
# Switch to workspace
|
||||
bindsym $mod+1 workspace $ws_1
|
||||
bindsym $mod+2 workspace $ws_2
|
||||
bindsym $mod+3 workspace $ws_3
|
||||
bindsym $mod+4 workspace $ws_4
|
||||
bindsym $mod+5 workspace $ws_5
|
||||
bindsym $mod+6 workspace $ws_6
|
||||
bindsym $mod+7 workspace $ws_7
|
||||
bindsym $mod+8 workspace $ws_8
|
||||
bindsym $mod+9 workspace $ws_9
|
||||
bindsym $mod+0 workspace $ws_10
|
||||
|
||||
# Move focused container to workspace
|
||||
bindsym $mod+Shift+1 move container to workspace $ws_1
|
||||
bindsym $mod+Shift+2 move container to workspace $ws_2
|
||||
bindsym $mod+Shift+3 move container to workspace $ws_3
|
||||
bindsym $mod+Shift+4 move container to workspace $ws_4
|
||||
bindsym $mod+Shift+5 move container to workspace $ws_5
|
||||
bindsym $mod+Shift+6 move container to workspace $ws_6
|
||||
bindsym $mod+Shift+7 move container to workspace $ws_7
|
||||
bindsym $mod+Shift+8 move container to workspace $ws_8
|
||||
bindsym $mod+Shift+9 move container to workspace $ws_9
|
||||
bindsym $mod+Shift+0 move container to workspace $ws_10
|
||||
|
||||
# Move through workspaces
|
||||
bindsym $mod+$alt+Left workspace prev
|
||||
bindsym $mod+$alt+Right workspace next
|
||||
|
||||
# WM stuff
|
||||
# reload i3 config
|
||||
bindsym $mod+$alt+c reload
|
||||
# restart i3
|
||||
bindsym $mod+$alt+r restart
|
||||
# exit i3
|
||||
bindsym $mod+Shift+e exec "i3-nagbar -t warning -m 'Exit i3?' -B 'Yes, exit i3' 'i3-msg exit'"
|
||||
|
||||
# Modes
|
||||
bindsym $mod+r mode resize
|
||||
mode "resize" {
|
||||
bindsym $nav_left resize shrink width 10 px or 10 ppt
|
||||
bindsym $nav_down resize grow height 10 px or 10 ppt
|
||||
bindsym $nav_up resize shrink height 10 px or 10 ppt
|
||||
bindsym $nav_right resize grow width 10 px or 10 ppt
|
||||
bindsym Left resize shrink width 10 px or 10 ppt
|
||||
bindsym Down resize grow height 10 px or 10 ppt
|
||||
bindsym Up resize shrink height 10 px or 10 ppt
|
||||
bindsym Right resize grow width 10 px or 10 ppt
|
||||
|
||||
bindsym Return mode "default"
|
||||
bindsym Escape mode "default"
|
||||
bindsym $mod+r mode "default"
|
||||
}
|
||||
|
||||
bindsym $mod+s mode "session"
|
||||
mode "session" {
|
||||
bindsym l exec --no-startup-id $lock, mode "default"
|
||||
bindsym e exec --no-startup-id i3-msg exit, mode "default"
|
||||
bindsym Shift+r exec --no-startup-id systemctl reboot, mode "default"
|
||||
bindsym Shift+s exec --no-startup-id systemctl poweroff -i, mode "default"
|
||||
|
||||
bindsym Return mode "default"
|
||||
bindsym Escape mode "default"
|
||||
bindsym $mod+s mode "default"
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
inactive-opacity = 0.75;
|
||||
|
||||
blur: {
|
||||
method = "box";
|
||||
size = 10;
|
||||
background = false;
|
||||
background-frame = false;
|
||||
background-fixed = false;
|
||||
}
|
|
@ -1,57 +0,0 @@
|
|||
general {
|
||||
output_format = "i3bar"
|
||||
colors = true
|
||||
interval = 5
|
||||
}
|
||||
|
||||
order += "ipv6"
|
||||
order += "wireless wlp58s0"
|
||||
order += "battery 0"
|
||||
order += "disk /"
|
||||
order += "memory"
|
||||
order += "load"
|
||||
order += "tztime local"
|
||||
|
||||
wireless wlp58s0 {
|
||||
format_up = "W: (%quality at %essid, %bitrate) %ip"
|
||||
format_down = "W: down"
|
||||
}
|
||||
|
||||
battery 0 {
|
||||
format = "%status %percentage %remaining %emptytime"
|
||||
format_down = "No battery"
|
||||
status_chr = "⚡ CHR"
|
||||
status_bat = "🔋 BAT"
|
||||
status_unk = "? UNK"
|
||||
status_full = "☻ FULL"
|
||||
path = "/sys/class/power_supply/BAT%d/uevent"
|
||||
low_threshold = 10
|
||||
}
|
||||
|
||||
tztime local {
|
||||
format = "%Y-%m-%d %H:%M:%S"
|
||||
hide_if_equals_localtime = false
|
||||
}
|
||||
|
||||
tztime berlin {
|
||||
format = "%Y-%m-%d %H:%M:%S %Z"
|
||||
timezone = "Europe/Berlin"
|
||||
}
|
||||
|
||||
load {
|
||||
format = "%5min"
|
||||
}
|
||||
|
||||
memory {
|
||||
format = "%used"
|
||||
threshold_degraded = "10%"
|
||||
format_degraded = "MEMORY: %free"
|
||||
}
|
||||
|
||||
disk "/" {
|
||||
format = "%free"
|
||||
}
|
||||
|
||||
read_file uptime {
|
||||
path = "/proc/uptime"
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
super_apply() {
|
||||
pacman -S --needed --noconfirm zsh
|
||||
}
|
||||
|
||||
super_undo() {
|
||||
pacman -R --noconfirm zsh
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
super_apply() {
|
||||
apt install -y zsh
|
||||
}
|
||||
|
||||
super_undo() {
|
||||
apt remove -y zsh
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
super_apply() {
|
||||
apt install -y zsh
|
||||
}
|
||||
|
||||
super_undo() {
|
||||
apt remove -y zsh
|
||||
}
|
|
@ -1,31 +0,0 @@
|
|||
#!/bin/sh
|
||||
|
||||
describe="Install zsh and oh-my-zsh!"
|
||||
scripts="@distro @self"
|
||||
|
||||
super_apply() {
|
||||
usermod $USER --shell /bin/zsh
|
||||
}
|
||||
|
||||
super_undo() {
|
||||
usermod $USER --shell /bin/bash
|
||||
}
|
||||
|
||||
apply() {
|
||||
if [ ! -d "$HOME/.oh-my-zsh" ]; then
|
||||
sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)" "" --unattended
|
||||
|
||||
PL_DIR=${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-autosuggestions
|
||||
[ -d "$PL_DIR" ] || git clone https://github.com/zsh-users/zsh-autosuggestions $PL_DIR
|
||||
PL_DIR=${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-syntax-highlighting
|
||||
[ -d "$PL_DIR" ] || git clone https://github.com/zsh-users/zsh-syntax-highlighting.git $PL_DIR
|
||||
fi
|
||||
|
||||
[ -f "$HOME/.zshrc" ] && unlink $HOME/.zshrc
|
||||
[ -e "$HOME/.zshrc" ] || ln files/.zshrc $HOME/.zshrc
|
||||
}
|
||||
|
||||
undo() {
|
||||
unlink $HOME/.zshrc
|
||||
rm -rf $HOME/.oh-my-zsh
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
#!/bin/sh
|
||||
|
||||
super_apply() {
|
||||
xbps-install -y zsh
|
||||
}
|
||||
|
||||
super_undo() {
|
||||
xbps-remove -y zsh
|
||||
}
|
||||
|
|
@ -1,44 +0,0 @@
|
|||
#!/bin/zsh
|
||||
|
||||
# Raine's .zshrc
|
||||
|
||||
if [ "$PROFILEINC" = "1" ]; then
|
||||
. ~/.profile
|
||||
fi
|
||||
|
||||
export EDITOR=vim
|
||||
export GPG_TTY=$(tty)
|
||||
export PATH="$PATH:$HOME/.yarn/bin:$HOME/.config/yarn/global/node_modules/.bin:$HOME/.local/bin"
|
||||
|
||||
# oh-my-zsh init
|
||||
if [ -f "$HOME/.oh-my-zsh/oh-my-zsh.sh" ]; then
|
||||
export ZSH="$HOME/.oh-my-zsh"
|
||||
ZSH_THEME="afowler"
|
||||
plugins=(git docker docker-compose node zsh-autosuggestions zsh-syntax-highlighting zsh-cargo-completion)
|
||||
source $ZSH/oh-my-zsh.sh
|
||||
else
|
||||
echo "oh-my-zsh not detected :("
|
||||
PS1="$(whoami)@${HOSTNAME:-$(hostname)} $ "
|
||||
fi
|
||||
|
||||
update_dotfiles() {
|
||||
cd $HOME/.dotfiles
|
||||
git pull
|
||||
cd - &> /dev/null
|
||||
}
|
||||
|
||||
container() {
|
||||
docker run \
|
||||
-ti \
|
||||
--rm \
|
||||
--name tmp-$(id -u)-$(openssl rand -hex 8) \
|
||||
--network ${CONTAINER_NETWORK:-internal} \
|
||||
alpine \
|
||||
ash
|
||||
}
|
||||
|
||||
[ -f "$HOME/.config/i3/shortcuts-i3.sh" ] && . ~/.config/i3/shortcuts-i3.sh
|
||||
|
||||
alias q="exit"
|
||||
alias vim="nvim"
|
||||
alias vi="nvim"
|
|
@ -1,7 +0,0 @@
|
|||
super_apply() {
|
||||
pacman -S --needed --noconfirm neovim
|
||||
}
|
||||
|
||||
super_undo() {
|
||||
echo "we never uninstall vim -_-"
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
super_apply() {
|
||||
apt install -y neovim
|
||||
}
|
||||
|
||||
super_undo() {
|
||||
echo "we never uninstall vim -_-"
|
||||
}
|
|
@ -1,15 +0,0 @@
|
|||
#!/bin/sh
|
||||
|
||||
describe="Install vim and it's stuff"
|
||||
scripts="@distro @self"
|
||||
|
||||
apply() {
|
||||
[ -d "$HOME/.config/nvim" ] || mkdir -p "$HOME/.config/nvim"
|
||||
[ -e "$HOME/.config/nvim/init.vim" ] || ln files/init.vim $HOME/.config/nvim/init.vim
|
||||
[ -e "$HOME/.ideavimrc" ] || ln files/.ideavimrc $HOME/.ideavimrc
|
||||
}
|
||||
|
||||
undo() {
|
||||
unlink $HOME/.config/nvim/init.vim
|
||||
unlink $HOME/.ideavimrc
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
super_apply() {
|
||||
xbps-install -y neovim
|
||||
}
|
||||
|
||||
super_undo() {
|
||||
echo "we never uninstall vim -_-"
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
source ~/.vimrc
|
||||
|
||||
set scrolloff=5
|
||||
set incsearch
|
||||
|
||||
map Q gq
|
||||
|
||||
Plug 'machakann/vim-highlightedyank'
|
||||
Plug 'tpope/vim-commentary'
|
||||
Plug 'wellle/targets.vim'
|
|
@ -1,27 +0,0 @@
|
|||
" vim preferences
|
||||
set number
|
||||
set relativenumber
|
||||
syntax on
|
||||
|
||||
" No arrow keys
|
||||
noremap <Up> <Nop>
|
||||
noremap <Down> <Nop>
|
||||
noremap <Left> <Nop>
|
||||
noremap <Right> <Nop>
|
||||
|
||||
" ensure vim-plug
|
||||
let data_dir = has('nvim') ? stdpath('data') . '/site' : '~/.vim'
|
||||
if empty(glob(data_dir . '/autoload/plug.vim'))
|
||||
silent execute '!curl -fLo '.data_dir.'/autoload/plug.vim --create-dirs https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim'
|
||||
autocmd VimEnter * PlugInstall --sync | source $MYVIMRC
|
||||
endif
|
||||
|
||||
call plug#begin()
|
||||
|
||||
Plug 'ThePrimeagen/vim-be-good'
|
||||
Plug 'machakann/vim-highlightedyank'
|
||||
Plug 'tpope/vim-commentary'
|
||||
Plug 'wellle/targets.vim'
|
||||
Plug 'vim-scripts/loremipsum'
|
||||
|
||||
call plug#end()
|
|
@ -1,7 +0,0 @@
|
|||
super_apply() {
|
||||
pacman -S --needed --noconfirm alacritty
|
||||
}
|
||||
|
||||
super_undo() {
|
||||
pacman -R --noconfirm alacritty
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
super_apply() {
|
||||
apt install -y alacritty
|
||||
}
|
||||
|
||||
super_undo() {
|
||||
apt remove -y alacritty
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
#!/bin/sh
|
||||
|
||||
describe="Installs alacritty and configs"
|
||||
scripts="@distro @self"
|
||||
|
||||
apply() {
|
||||
[ -d "$HOME/.config/alacritty" ] || mkdir -p $HOME/.config/alacritty
|
||||
[ -e "$HOME/.config/alacritty/alacritty.yml" ] || ln files/alacritty.yml $HOME/.config/alacritty/alacritty.yml
|
||||
}
|
||||
|
||||
undo() {
|
||||
unlink $HOME/.config/alacritty/alacritty.yml
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
super_apply() {
|
||||
xbps-install -y alacritty
|
||||
}
|
||||
|
||||
super_undo() {
|
||||
xbps-remove -y alacritty
|
||||
}
|
|
@ -1,6 +0,0 @@
|
|||
cursor:
|
||||
style:
|
||||
shape: 'Block'
|
||||
blinking: 'On'
|
||||
blink_interval: 500
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
#!/bin/sh
|
||||
|
||||
describe="Setup git"
|
||||
scripts="@distro @self"
|
||||
|
||||
apply() {
|
||||
git config --global user.name Strix
|
||||
git config --global user.email strix@saluco.nl
|
||||
}
|
23
crates/common/crate.toml
Normal file
23
crates/common/crate.toml
Normal file
|
@ -0,0 +1,23 @@
|
|||
name = "common"
|
||||
description = "Common set of utilities"
|
||||
|
||||
[pkgs]
|
||||
openssh-server = {}
|
||||
openssh-client = {}
|
||||
git = {}
|
||||
netselect = { distros = ["debian", "ubuntu"] }
|
||||
reflector = { distros = ["arch"] }
|
||||
|
||||
[actions]
|
||||
setup_ssh = ["sh", "./scripts/%"]
|
||||
reflector = { args = ["sh", "./scripts/setup_pm/%"], distro = ["arch"] }
|
||||
netselect = { args = [
|
||||
"sh",
|
||||
"./scripts/setup_pm/%",
|
||||
], distro = [
|
||||
"debian",
|
||||
"ubuntu",
|
||||
] }
|
||||
|
||||
[super_actions]
|
||||
pam_wheel = ["sh", "./scripts/%"]
|
4
crates/common/scripts/pam_wheel.sh
Normal file
4
crates/common/scripts/pam_wheel.sh
Normal file
|
@ -0,0 +1,4 @@
|
|||
if [ -f /usr/lib/security/pam_wheel.so ] && ! grep -q "# pam_wheel.so added" /etc/pam.d/su; then
|
||||
echo "auth sufficient pam_wheel.so trust use_uid" > /etc/pam.d/su
|
||||
echo "# pam_wheel.so added" > /etc/pam.d/su
|
||||
fi
|
89
dot
89
dot
|
@ -1,89 +0,0 @@
|
|||
#!/bin/sh
|
||||
|
||||
ask=0
|
||||
|
||||
is_function() {
|
||||
type "$1" 2>/dev/null | sed "s/$1//" | grep -qwi function
|
||||
}
|
||||
|
||||
curr_distro() {
|
||||
cat /etc/os-release | grep -G "^ID=" | sed 's/ID=//'
|
||||
}
|
||||
|
||||
include() {
|
||||
[ -f "$1" ] || return 1
|
||||
. $1
|
||||
return 0
|
||||
}
|
||||
|
||||
func() {
|
||||
if is_function $(echo "super_$2"); then
|
||||
[ "${DO_SUDO:-yes}" = "yes" ] || return 0
|
||||
ecmd=". $1 && super_$2"
|
||||
[ "$(id -u)" = "0" ] && sh -c "$ecmd" || sudo sh -c "$ecmd"
|
||||
unset ecmd
|
||||
fi
|
||||
is_function $2 && $2
|
||||
}
|
||||
|
||||
# only run this *in crate dir*
|
||||
run_crate() {
|
||||
enabled=1
|
||||
include ./crate.sh || exit 1
|
||||
if [ -n "$describe" ]; then
|
||||
echo "desc($(basename $PWD)): $describe"
|
||||
fi
|
||||
if [ $enabled -ne 1 ]; then
|
||||
return
|
||||
fi
|
||||
cmd=$1
|
||||
scripts=${scripts:-"@self @distro"}
|
||||
for s in $scripts; do
|
||||
echo "exec($(basename $PWD)): $s/$cmd"
|
||||
case $s in
|
||||
@self)
|
||||
func ./crate.sh $cmd
|
||||
;;
|
||||
@distro)
|
||||
unset -f super_$cmd
|
||||
unset -f $cmd
|
||||
include ./crate.$(curr_distro).sh
|
||||
func ./crate.$(curr_distro).sh $cmd
|
||||
unset -f super_$cmd
|
||||
unset -f $cmd
|
||||
include ./crate.sh
|
||||
;;
|
||||
*)
|
||||
sh $s
|
||||
;;
|
||||
esac
|
||||
done
|
||||
}
|
||||
|
||||
echo "# details:"
|
||||
echo "# user: $USER (${UID:-$(id -u)})"
|
||||
echo "# groups: $(groups)"
|
||||
echo "# distro: $(curr_distro)"
|
||||
|
||||
cmd=$1
|
||||
if [ -z "$cmd" ]; then
|
||||
echo "usage: $0 <command> [...args]"
|
||||
exit 1
|
||||
else
|
||||
shift
|
||||
fi
|
||||
|
||||
for c in ${@:-$(ls crates)}; do
|
||||
[ -d crates/*$c ] || exit 1
|
||||
cd crates/*$c
|
||||
case $cmd in
|
||||
a | apply)
|
||||
run_crate apply
|
||||
;;
|
||||
u | undo)
|
||||
run_crate undo
|
||||
;;
|
||||
*) exit 1 ;;
|
||||
esac
|
||||
cd ../..
|
||||
done
|
|
@ -1,14 +0,0 @@
|
|||
#!/bin/sh
|
||||
|
||||
# this script is meant to be ran when .dotfiles is not present.
|
||||
#
|
||||
# example:
|
||||
# curl https://git.saluco.nl/strix/dotfiles/raw/branch/main/remote_script.sh | sh
|
||||
|
||||
set -e
|
||||
|
||||
HOME=${HOME:-/home/${USER:-$(whomai)}}
|
||||
|
||||
[ -d "$HOME/.dotfiles" ] || git clone https://git.saluco.nl/strix/dotfiles $HOME/.dotfiles
|
||||
cd $HOME/.dotfiles
|
||||
./dot a
|
|
@ -1,13 +0,0 @@
|
|||
#!/bin/sh
|
||||
|
||||
set -e
|
||||
|
||||
echo "Downloading newest package..."
|
||||
curl -Lo /tmp/discord.deb "https://discord.com/api/download?platform=linux&format=deb"
|
||||
cd /tmp
|
||||
echo "Extracting package..."
|
||||
xdeb discord.deb
|
||||
echo "Installing package..."
|
||||
sudo xbps-install -R /tmp/binpkgs discord
|
||||
rm -rf /tmp/binpkgs
|
||||
cd -
|
1149
sync-runner/Cargo.lock
generated
Normal file
1149
sync-runner/Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load diff
20
sync-runner/Cargo.toml
Normal file
20
sync-runner/Cargo.toml
Normal file
|
@ -0,0 +1,20 @@
|
|||
[package]
|
||||
name = "sync-runner"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
clap = { version = "4.5.29", features = ["derive"] }
|
||||
colored = "3.0.0"
|
||||
execute = "0.2.13"
|
||||
fern = "0.7.1"
|
||||
git2 = "0.20.0"
|
||||
glob = "0.3.2"
|
||||
hex = "0.4.3"
|
||||
lazy_static = "1.5.0"
|
||||
log = "0.4.26"
|
||||
regex = "1.11.1"
|
||||
serde = { version = "1.0.218", features = ["serde_derive"] }
|
||||
sha2 = "0.10.8"
|
||||
shellexpand = "3.1.0"
|
||||
toml = "0.8.20"
|
11
sync-runner/package_manager.list
Normal file
11
sync-runner/package_manager.list
Normal file
|
@ -0,0 +1,11 @@
|
|||
install(pacman): pacman -Sy %args
|
||||
uninstall(pacman): pacman -Rn %args
|
||||
|
||||
install(apt): apt install %args
|
||||
uninstall(apt): apt remove %args
|
||||
|
||||
install(dnf): dnf install %args
|
||||
uninstall(dnf): dnf remove %args
|
||||
|
||||
install(yum): yum install %args
|
||||
uninstall(yum): yum remove %args
|
10
sync-runner/src/action.rs
Normal file
10
sync-runner/src/action.rs
Normal file
|
@ -0,0 +1,10 @@
|
|||
use clap::Parser;
|
||||
|
||||
#[derive(Parser, Debug)]
|
||||
pub enum Action {
|
||||
/// Sync your device with dotfiles repository
|
||||
Sync {
|
||||
#[arg(short, long)]
|
||||
config_path: Option<String>,
|
||||
},
|
||||
}
|
7
sync-runner/src/cfg/daemon.rs
Normal file
7
sync-runner/src/cfg/daemon.rs
Normal file
|
@ -0,0 +1,7 @@
|
|||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct Daemon {
|
||||
/// interval in minutes
|
||||
pub interval: u64,
|
||||
}
|
15
sync-runner/src/cfg/mod.rs
Normal file
15
sync-runner/src/cfg/mod.rs
Normal file
|
@ -0,0 +1,15 @@
|
|||
|
||||
#![allow(unused)]
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
mod daemon;
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct Config {
|
||||
pub title: String,
|
||||
pub daemon: daemon::Daemon,
|
||||
pub source: HashMap<String, crate::source::Source>
|
||||
}
|
34
sync-runner/src/crates/mod.rs
Normal file
34
sync-runner/src/crates/mod.rs
Normal file
|
@ -0,0 +1,34 @@
|
|||
use std::collections::HashMap;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
mod pm;
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct Package {
|
||||
name: String,
|
||||
}
|
||||
|
||||
impl Package {
|
||||
pub fn install(&self) {
|
||||
todo!()
|
||||
}
|
||||
|
||||
pub fn uninstall(&self) {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct CrateAction {
|
||||
pub name: String,
|
||||
pub command: String,
|
||||
pub args: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct Crate {
|
||||
pub pkgs: HashMap<String, Package>,
|
||||
pub actions: HashMap<String, CrateAction>,
|
||||
pub super_actions: HashMap<String, CrateAction>,
|
||||
}
|
90
sync-runner/src/crates/pm.rs
Normal file
90
sync-runner/src/crates/pm.rs
Normal file
|
@ -0,0 +1,90 @@
|
|||
use lazy_static::lazy_static;
|
||||
use regex::Regex;
|
||||
use std::{process::Command, str::FromStr};
|
||||
|
||||
const pm_cfg: &str = include_str!("../../package_manager.list");
|
||||
|
||||
/// regex: `(?<pm>[a-z]+)>(?<action>(?:un)?install+): (?<command>.*)`
|
||||
/// example: pacman>install: pacman -Sy %args
|
||||
|
||||
lazy_static! {
|
||||
static ref PM_REGEX: Regex =
|
||||
Regex::new(r"(?P<pm>[a-z]+)>(?P<action>(?:un)?install+): (?P<command>.*)").unwrap();
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct PackageManager {
|
||||
name: String,
|
||||
command: String,
|
||||
args: Vec<String>,
|
||||
}
|
||||
|
||||
impl PackageManager {
|
||||
fn new(name: &str, command: &str, args: Vec<String>) -> Self {
|
||||
Self {
|
||||
name: name.to_string(),
|
||||
command: command.to_string(),
|
||||
args,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn install(&self, packages: Vec<String>) -> Result<(), Vec<String>> {
|
||||
Command::new(&self.command)
|
||||
.args(&self.args)
|
||||
.args(packages)
|
||||
.spawn()
|
||||
.expect("err");
|
||||
Ok(())
|
||||
}
|
||||
pub fn uninstall(&self, packages: Vec<String>) -> Result<(), Vec<String>> {
|
||||
todo!();
|
||||
}
|
||||
}
|
||||
impl FromStr for PackageManager {
|
||||
type Err = String;
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
let caps = PM_REGEX.captures(s).ok_or("invalid package manager")?;
|
||||
let name = caps.name("pm").ok_or("invalid package manager")?.as_str();
|
||||
let command = caps
|
||||
.name("command")
|
||||
.ok_or("invalid package manager")?
|
||||
.as_str();
|
||||
let args = caps
|
||||
.name("args")
|
||||
.ok_or("invalid package manager")?
|
||||
.as_str()
|
||||
.split_whitespace()
|
||||
.map(|s| s.to_string())
|
||||
.collect();
|
||||
Ok(Self::new(name, command, args))
|
||||
}
|
||||
}
|
||||
#[derive(Debug)]
|
||||
struct Package {
|
||||
name: String,
|
||||
}
|
||||
impl FromStr for Package {
|
||||
type Err = String;
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
let caps = PM_REGEX.captures(s).ok_or("invalid package")?;
|
||||
let name = caps.name("name").ok_or("invalid package")?.as_str();
|
||||
Ok(Self::new(name))
|
||||
}
|
||||
}
|
||||
|
||||
impl Package {
|
||||
fn new(name: &str) -> Self {
|
||||
Self {
|
||||
name: name.to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn package_managers() -> Vec<PackageManager> {
|
||||
pm_cfg
|
||||
.lines()
|
||||
.map(|s| s.to_string())
|
||||
.map(|s| s.parse::<PackageManager>())
|
||||
.collect::<Result<Vec<PackageManager>, String>>()
|
||||
.expect("invalid package manager")
|
||||
}
|
64
sync-runner/src/logging.rs
Normal file
64
sync-runner/src/logging.rs
Normal file
|
@ -0,0 +1,64 @@
|
|||
use std::env;
|
||||
|
||||
use colored::Colorize;
|
||||
use fern::Dispatch;
|
||||
use log::{Record, SetLoggerError};
|
||||
|
||||
fn format_regular<S: Into<String>>(log: S, record: &Record) -> String {
|
||||
let log = log.into();
|
||||
let line_prefix = |line: String, extend: bool| {
|
||||
let prefix = if extend {
|
||||
match record.level() {
|
||||
log::Level::Trace => " ]".bright_blue(),
|
||||
log::Level::Debug => " ?".green(),
|
||||
log::Level::Info => " >".blue(),
|
||||
log::Level::Warn => " #".yellow(),
|
||||
log::Level::Error => " !".red(),
|
||||
}.to_string()
|
||||
} else {
|
||||
match record.level() {
|
||||
log::Level::Trace => "[TRACE]".bright_blue().italic(),
|
||||
log::Level::Debug => "??".green(),
|
||||
log::Level::Info => "=>".blue(),
|
||||
log::Level::Warn => "##".yellow(),
|
||||
log::Level::Error => "!!".red().bold()
|
||||
}.to_string()
|
||||
};
|
||||
return format!("{} {}", prefix, line);
|
||||
};
|
||||
|
||||
let mut lines = log.lines().peekable();
|
||||
let mut output = match lines.peek() {
|
||||
Some(_line) => line_prefix(lines.next().unwrap().to_string(), false),
|
||||
None => return "".to_string(),
|
||||
};
|
||||
|
||||
for line in lines {
|
||||
output.push_str(&*format!("\n{}", line_prefix(line.to_string(), true)));
|
||||
}
|
||||
|
||||
output
|
||||
}
|
||||
|
||||
pub fn setup_logger() -> Result<(), SetLoggerError> {
|
||||
Dispatch::new()
|
||||
.format(|out, message, record| {
|
||||
match record.metadata().target() {
|
||||
// command output logging
|
||||
"command:stdout" => out.finish(format_args!("{} {}", ">>".cyan(), message.to_string())),
|
||||
"command:stderr" => out.finish(format_args!("{} {}", ">>".red(), message.to_string())),
|
||||
// this target means, it's an item and not a log.
|
||||
"item" => out.finish(format_args!("{} {}", "*".blue(), message.to_string())),
|
||||
// default logging
|
||||
_ => out.finish(format_args!("{}", format_regular(message.to_string(), record))),
|
||||
}
|
||||
})
|
||||
.level(
|
||||
env::var("SYNCR_LOG_LEVEL")
|
||||
.unwrap_or_else(|_| "info".to_string())
|
||||
.parse()
|
||||
.unwrap_or(log::LevelFilter::Info),
|
||||
)
|
||||
.chain(std::io::stdout())
|
||||
.apply()
|
||||
}
|
77
sync-runner/src/main.rs
Normal file
77
sync-runner/src/main.rs
Normal file
|
@ -0,0 +1,77 @@
|
|||
use std::{
|
||||
env::set_current_dir,
|
||||
fs::{exists, read_to_string, File},
|
||||
path::{absolute, Path},
|
||||
process::{exit, Stdio},
|
||||
};
|
||||
|
||||
use action::Action;
|
||||
use cfg::Config;
|
||||
use clap::Parser;
|
||||
use colored::Colorize;
|
||||
use execute::{command_args, Execute};
|
||||
use log::{debug, error, info, trace, warn};
|
||||
use prelude::abspath;
|
||||
|
||||
mod action;
|
||||
mod cfg;
|
||||
mod crates;
|
||||
mod logging;
|
||||
mod prelude;
|
||||
mod source;
|
||||
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
logging::setup_logger()?;
|
||||
|
||||
let git_sha1 = String::from_utf8(
|
||||
command_args!("git", "rev-parse", "HEAD")
|
||||
.stdout(Stdio::piped())
|
||||
.execute_output()?
|
||||
.stdout,
|
||||
)?;
|
||||
|
||||
let action = Action::parse();
|
||||
match action {
|
||||
Action::Sync { config_path } => {
|
||||
trace!("fetching config dir... {config_path:?}");
|
||||
if let Some(config_path) = abspath(&config_path.unwrap_or("~/.syncr".into())) {
|
||||
trace!("setting config dir as cwd... {config_path}");
|
||||
set_current_dir(config_path)?;
|
||||
}
|
||||
let config =
|
||||
toml::from_str::<Config>(&read_to_string(abspath("./syncr.toml").unwrap())?)?;
|
||||
info!("syncing \"{}\"...", config.title.bold());
|
||||
|
||||
info!("updating sources...");
|
||||
let mut available_sources = vec![];
|
||||
for (name, source) in &config.source {
|
||||
debug!("checking {name}...");
|
||||
if !source.available() {
|
||||
warn!("source \"{name}\" unavailable.");
|
||||
} else {
|
||||
info!("source \"{name}\" available!");
|
||||
available_sources.push(source);
|
||||
}
|
||||
}
|
||||
|
||||
if available_sources.len() == 0 {
|
||||
error!("{}", "sync impossible; no sources.".bold());
|
||||
exit(1);
|
||||
}
|
||||
|
||||
let oldpwd = absolute(".")?;
|
||||
for source in available_sources {
|
||||
// cd to source dir
|
||||
source.go_to_dir()?;
|
||||
for c in source.get_crates()? {
|
||||
info!("{} pkgs", c.pkgs.len())
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
println!("{action:#?}");
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
5
sync-runner/src/prelude.rs
Normal file
5
sync-runner/src/prelude.rs
Normal file
|
@ -0,0 +1,5 @@
|
|||
pub fn abspath(p: &str) -> Option<String> {
|
||||
let exp_path = shellexpand::full(p).ok()?;
|
||||
let can_path = std::fs::canonicalize(exp_path.as_ref()).ok()?;
|
||||
can_path.into_os_string().into_string().ok()
|
||||
}
|
241
sync-runner/src/source/git.rs
Normal file
241
sync-runner/src/source/git.rs
Normal file
|
@ -0,0 +1,241 @@
|
|||
use std::{
|
||||
env::current_dir, fs::{self, create_dir_all, exists}, io::Write, path::{Path, PathBuf}
|
||||
};
|
||||
|
||||
use git2::Repository;
|
||||
use log::{debug, info, trace, warn};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use sha2::{Digest, Sha256, Sha512};
|
||||
|
||||
use crate::prelude::abspath;
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct Git {
|
||||
pub url: String,
|
||||
#[serde(default = "default_branch")]
|
||||
pub branch: String,
|
||||
}
|
||||
|
||||
fn default_branch() -> String {
|
||||
"main".to_string()
|
||||
}
|
||||
|
||||
impl Git {
|
||||
fn url_hash(&self) -> String {
|
||||
let mut hasher = Sha256::new();
|
||||
hasher.update(&self.url);
|
||||
let hash = hasher.finalize();
|
||||
hex::encode(hash)
|
||||
}
|
||||
|
||||
fn branch_hash(&self) -> String {
|
||||
let mut hasher = Sha256::new();
|
||||
hasher.update(&self.url);
|
||||
let hash = hasher.finalize();
|
||||
hex::encode(hash)
|
||||
}
|
||||
|
||||
pub fn repository_path_str(&self) -> String {
|
||||
format!(".data/git/{}{}", self.url_hash(), self.branch_hash())
|
||||
}
|
||||
|
||||
pub fn repository_path(&self) -> Result<PathBuf, std::io::Error> {
|
||||
fs::canonicalize(self.repository_path_str())
|
||||
}
|
||||
|
||||
pub fn exists_on_fs(&self) -> bool {
|
||||
self.repository_path().is_ok()
|
||||
}
|
||||
|
||||
pub fn clone_repository(&self) -> Result<Repository, git2::Error> {
|
||||
Repository::clone_recurse(&self.url, Path::new(&self.repository_path_str()))
|
||||
}
|
||||
|
||||
pub fn repository(&self) -> Result<Repository, git2::Error> {
|
||||
if !self.exists_on_fs() {
|
||||
create_dir_all(self.repository_path_str()).unwrap();
|
||||
}
|
||||
match Repository::open(self.repository_path().unwrap()) {
|
||||
Ok(r) => Ok(r),
|
||||
Err(_) => self.clone_repository(),
|
||||
}
|
||||
}
|
||||
|
||||
fn up_to_date(&self) -> Result<bool, Box<dyn std::error::Error>>{
|
||||
debug!("checking repo up to date...");
|
||||
let repo = self.repository()?;
|
||||
let mut remote = repo.find_remote("origin")?;
|
||||
|
||||
// Fetch latest references from remote
|
||||
remote.fetch(&[self.branch.clone()], None, None)?;
|
||||
|
||||
let fetch_head = repo.refname_to_id(&format!("refs/remotes/origin/{}", self.branch))?;
|
||||
let local_head = repo.refname_to_id(&format!("refs/heads/{}", self.branch))?;
|
||||
|
||||
|
||||
Ok(fetch_head == local_head)
|
||||
}
|
||||
|
||||
pub fn update(&self) -> Result<bool, Box<dyn std::error::Error>> {
|
||||
if self.up_to_date()? {
|
||||
return Ok(true);
|
||||
}
|
||||
debug!("updating repository...");
|
||||
let repository = self.repository()?;
|
||||
let mut remote = repository.find_remote("origin")?;
|
||||
let mut cb = git2::RemoteCallbacks::new();
|
||||
|
||||
cb.transfer_progress(|stats| {
|
||||
if stats.received_objects() == stats.total_objects() {
|
||||
print!(
|
||||
"resolving deltas {}/{}\r",
|
||||
stats.indexed_deltas(),
|
||||
stats.total_deltas()
|
||||
);
|
||||
} else if stats.total_objects() > 0 {
|
||||
print!(
|
||||
"received {}/{} objects ({}) in {} bytes\r",
|
||||
stats.received_objects(),
|
||||
stats.total_objects(),
|
||||
stats.indexed_objects(),
|
||||
stats.received_bytes()
|
||||
);
|
||||
}
|
||||
std::io::stdout().flush().unwrap();
|
||||
true
|
||||
});
|
||||
|
||||
let mut fo = git2::FetchOptions::new();
|
||||
fo.remote_callbacks(cb);
|
||||
// Always fetch all tags.
|
||||
// Perform a download and also update tips
|
||||
fo.download_tags(git2::AutotagOption::All);
|
||||
info!("fetching {}...", remote.name().unwrap());
|
||||
remote.fetch(&[self.branch.clone()], Some(&mut fo), None)?;
|
||||
|
||||
let fetch_head = repository.find_reference("FETCH_HEAD")?;
|
||||
|
||||
do_merge(
|
||||
&repository,
|
||||
&self.branch,
|
||||
repository.reference_to_annotated_commit(&fetch_head)?,
|
||||
)?;
|
||||
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
pub fn ensure(&self) -> Result<&Self, Box<dyn std::error::Error>> {
|
||||
if self.exists_on_fs() {
|
||||
self.update();
|
||||
} else {
|
||||
self.clone_repository()?;
|
||||
}
|
||||
Ok(self)
|
||||
}
|
||||
}
|
||||
|
||||
fn do_merge<'a>(
|
||||
repo: &'a Repository,
|
||||
remote_branch: &str,
|
||||
fetch_commit: git2::AnnotatedCommit<'a>,
|
||||
) -> Result<(), git2::Error> {
|
||||
// 1. do a merge analysis
|
||||
let analysis = repo.merge_analysis(&[&fetch_commit])?;
|
||||
|
||||
// 2. Do the appopriate merge
|
||||
if analysis.0.is_fast_forward() {
|
||||
info!("doing a fast forward...");
|
||||
// do a fast forward
|
||||
let refname = format!("refs/heads/{}", remote_branch);
|
||||
match repo.find_reference(&refname) {
|
||||
Ok(mut r) => {
|
||||
fast_forward(repo, &mut r, &fetch_commit)?;
|
||||
}
|
||||
Err(_) => {
|
||||
// The branch doesn't exist so just set the reference to the
|
||||
// commit directly. Usually this is because you are pulling
|
||||
// into an empty repository.
|
||||
repo.reference(
|
||||
&refname,
|
||||
fetch_commit.id(),
|
||||
true,
|
||||
&format!("Setting {} to {}", remote_branch, fetch_commit.id()),
|
||||
)?;
|
||||
repo.set_head(&refname)?;
|
||||
repo.checkout_head(Some(
|
||||
git2::build::CheckoutBuilder::default()
|
||||
.allow_conflicts(true)
|
||||
.conflict_style_merge(true)
|
||||
.force(),
|
||||
))?;
|
||||
}
|
||||
};
|
||||
} else if analysis.0.is_normal() {
|
||||
// do a normal merge
|
||||
let head_commit = repo.reference_to_annotated_commit(&repo.head()?)?;
|
||||
normal_merge(&repo, &head_commit, &fetch_commit)?;
|
||||
} else {
|
||||
info!("nothing to do...");
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn fast_forward(
|
||||
repo: &Repository,
|
||||
lb: &mut git2::Reference,
|
||||
rc: &git2::AnnotatedCommit,
|
||||
) -> Result<(), git2::Error> {
|
||||
let name = match lb.name() {
|
||||
Some(s) => s.to_string(),
|
||||
None => String::from_utf8_lossy(lb.name_bytes()).to_string(),
|
||||
};
|
||||
let msg = format!("fast-forward: setting {} to id: {}", name, rc.id());
|
||||
info!("{}", msg);
|
||||
lb.set_target(rc.id(), &msg)?;
|
||||
repo.set_head(&name)?;
|
||||
repo.checkout_head(Some(
|
||||
git2::build::CheckoutBuilder::default()
|
||||
// For some reason the force is required to make the working directory actually get updated
|
||||
// I suspect we should be adding some logic to handle dirty working directory states
|
||||
// but this is just an example so maybe not.
|
||||
.force(),
|
||||
))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn normal_merge(
|
||||
repo: &Repository,
|
||||
local: &git2::AnnotatedCommit,
|
||||
remote: &git2::AnnotatedCommit,
|
||||
) -> Result<(), git2::Error> {
|
||||
let local_tree = repo.find_commit(local.id())?.tree()?;
|
||||
let remote_tree = repo.find_commit(remote.id())?.tree()?;
|
||||
let ancestor = repo
|
||||
.find_commit(repo.merge_base(local.id(), remote.id())?)?
|
||||
.tree()?;
|
||||
let mut idx = repo.merge_trees(&ancestor, &local_tree, &remote_tree, None)?;
|
||||
|
||||
if idx.has_conflicts() {
|
||||
warn!("merge conficts detected...");
|
||||
repo.checkout_index(Some(&mut idx), None)?;
|
||||
return Ok(());
|
||||
}
|
||||
let result_tree = repo.find_tree(idx.write_tree_to(repo)?)?;
|
||||
// now create the merge commit
|
||||
let msg = format!("Merge: {} into {}", remote.id(), local.id());
|
||||
let sig = repo.signature()?;
|
||||
let local_commit = repo.find_commit(local.id())?;
|
||||
let remote_commit = repo.find_commit(remote.id())?;
|
||||
// Do our merge commit and set current branch head to that commit.
|
||||
let _merge_commit = repo.commit(
|
||||
Some("HEAD"),
|
||||
&sig,
|
||||
&sig,
|
||||
&msg,
|
||||
&result_tree,
|
||||
&[&local_commit, &remote_commit],
|
||||
)?;
|
||||
// Set working tree to match head.
|
||||
repo.checkout_head(None)?;
|
||||
Ok(())
|
||||
}
|
68
sync-runner/src/source/mod.rs
Normal file
68
sync-runner/src/source/mod.rs
Normal file
|
@ -0,0 +1,68 @@
|
|||
use std::{env::{current_dir, set_current_dir}, fs::{create_dir_all, read_to_string}, path::PathBuf};
|
||||
|
||||
use log::{debug, info, trace};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{crates::Crate, prelude::abspath};
|
||||
|
||||
pub mod git;
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
#[serde(default)]
|
||||
pub struct Source {
|
||||
interval: u64,
|
||||
git: Option<git::Git>,
|
||||
}
|
||||
|
||||
impl Default for Source {
|
||||
fn default() -> Self {
|
||||
Source {
|
||||
interval: 60,
|
||||
git: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Source {
|
||||
pub fn available(&self) -> bool {
|
||||
if let Some(git) = &self.git {
|
||||
trace!("checking git...");
|
||||
return git.ensure().is_ok();
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
pub fn go_to_dir(&self) -> Result<(), Box<dyn std::error::Error>> {
|
||||
if let Some(git) = &self.git {
|
||||
if PathBuf::from(git.repository_path_str()) == current_dir()? {
|
||||
return Ok(())
|
||||
}
|
||||
let dir = git.ensure()?.repository_path()?;
|
||||
trace!("setting git dir as cwd... ({}@{}, {})", git.url, git.branch, dir.display());
|
||||
set_current_dir(dir)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn get_crates(&self) -> Result<Vec<Crate>, Box<dyn std::error::Error>> {
|
||||
let mut crates = vec![];
|
||||
if let Some(git) = &self.git {
|
||||
trace!("getting crates from git...");
|
||||
debug!("{}", current_dir()?.display());
|
||||
|
||||
// get crates (read dir, crates/*/crate.toml)
|
||||
for crate_file in glob::glob("crates/*/crate.toml").expect("err") {
|
||||
debug!("{crate_file:#?}");
|
||||
match crate_file {
|
||||
Ok(cd) =>{
|
||||
debug!("{}", cd.display());
|
||||
crates.push(toml::from_str(&read_to_string(cd)?)?)
|
||||
},
|
||||
_ => continue
|
||||
}
|
||||
}
|
||||
}
|
||||
debug!("{:#?}", crates);
|
||||
Ok(crates)
|
||||
}
|
||||
}
|
1
sync.sh
Normal file
1
sync.sh
Normal file
|
@ -0,0 +1 @@
|
|||
node sync-runner/index.js
|
17
syncr.toml
Normal file
17
syncr.toml
Normal file
|
@ -0,0 +1,17 @@
|
|||
title = "strix's syncr config"
|
||||
|
||||
[daemon]
|
||||
# interval
|
||||
# discription: how often to check for new updates, this is the default for syncs
|
||||
# you can define a custom interval for specific sources
|
||||
# unit = minutes
|
||||
interval = 60
|
||||
|
||||
[source.personal.git] # default is the uid
|
||||
url = "https://git.saluco.nl/strix/dotfiles.git"
|
||||
crate_dir = "./crates" # default
|
||||
cfg_toml = "./syncr.toml" # default
|
||||
|
||||
[source.work.git]
|
||||
url = "https://git.saluco.nl/dotfiles.git"
|
||||
branch = "work"
|
Loading…
Reference in a new issue