feat: add --dry-run flag (#6)
* feat: add --dry-run flag to all commands * feat: update copy-go with single copy.Replace * refactor: make Config interface * chore(config): cleanup unused * feat: add config demo (1/?) * chore: better naming for cfg * refactor: move to pkg config * refactor: use data for store configs * refactor: split real and demo config * feat: make use of dry run flag Co-authored-by: Tran Hau <ngtranhau@gmail.com>main
parent
ecafc5b74d
commit
4fa12066d0
|
@ -1,13 +0,0 @@
|
||||||
import:
|
|
||||||
- ~/.config/alacritty/one-dark.yml
|
|
||||||
|
|
||||||
font:
|
|
||||||
normal:
|
|
||||||
family: Cascadia Code
|
|
||||||
style: Regular
|
|
||||||
|
|
||||||
bold:
|
|
||||||
family: Cascadia Code
|
|
||||||
style: Bold
|
|
||||||
|
|
||||||
size: 12
|
|
|
@ -1,21 +0,0 @@
|
||||||
# https://github.com/alacritty/alacritty/wiki/Color-schemes
|
|
||||||
# Colors (One Dark)
|
|
||||||
colors:
|
|
||||||
primary:
|
|
||||||
background: "#282c34"
|
|
||||||
foreground: "#abb2bf"
|
|
||||||
cursor:
|
|
||||||
text: CellBackground
|
|
||||||
cursor: "#528bff"
|
|
||||||
selection:
|
|
||||||
text: CellForeground
|
|
||||||
background: "#3e4451"
|
|
||||||
normal:
|
|
||||||
black: "#5c6370"
|
|
||||||
red: "#e06c75"
|
|
||||||
green: "#98c379"
|
|
||||||
yellow: "#e5c07b"
|
|
||||||
blue: "#61afef"
|
|
||||||
magenta: "#c678dd"
|
|
||||||
cyan: "#56b6c2"
|
|
||||||
white: "#828997"
|
|
|
@ -1,3 +0,0 @@
|
||||||
--theme="TwoDark"
|
|
||||||
|
|
||||||
--style="plain"
|
|
|
@ -1,88 +0,0 @@
|
||||||
{
|
|
||||||
"apps": {
|
|
||||||
"nvim": {
|
|
||||||
"files": [
|
|
||||||
{
|
|
||||||
"internal": "config/nvim/init.vim",
|
|
||||||
"external": "~/.config/nvim/init.vim"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"vim": {
|
|
||||||
"files": [
|
|
||||||
{
|
|
||||||
"internal": "config/vim/vimrc",
|
|
||||||
"external": "~/.vimrc"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"bat": {
|
|
||||||
"dirs": [
|
|
||||||
{
|
|
||||||
"internal": "config/bat",
|
|
||||||
"external": "~/.config/bat"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"tmux": {
|
|
||||||
"files": [
|
|
||||||
{
|
|
||||||
"internal": "config/tmux/tmux.conf",
|
|
||||||
"external": "~/.tmux.conf"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"alacritty": {
|
|
||||||
"files": [
|
|
||||||
{
|
|
||||||
"internal": "config/alacritty/alacritty.yml",
|
|
||||||
"external": "~/.config/alacritty/alacritty.yml"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internal": "config/alacritty/one-dark.yml",
|
|
||||||
"external": "~/.config/alacritty/one-dark.yml"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"i3": {
|
|
||||||
"files": [
|
|
||||||
{
|
|
||||||
"internal": "config/i3/config",
|
|
||||||
"external": "~/.config/i3/config"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"i3status": {
|
|
||||||
"files": [
|
|
||||||
{
|
|
||||||
"internal": "config/i3status/config",
|
|
||||||
"external": "~/.config/i3status/config"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"rofi": {
|
|
||||||
"files": [
|
|
||||||
{
|
|
||||||
"internal": "config/rofi/config.rasi",
|
|
||||||
"external": "~/.config/rofi/config.rasi"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"xinit": {
|
|
||||||
"files": [
|
|
||||||
{
|
|
||||||
"internal": "config/xinit/xinitrc",
|
|
||||||
"external": "~/.xinitrc"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"redshift": {
|
|
||||||
"files": [
|
|
||||||
{
|
|
||||||
"internal": "config/redshift/redshift.conf",
|
|
||||||
"external": "~/.config/redshift/redshift.conf"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
139
config/i3/config
139
config/i3/config
|
@ -1,139 +0,0 @@
|
||||||
# https://i3wm.org/docs/userguide.html
|
|
||||||
|
|
||||||
set $mod Mod4
|
|
||||||
|
|
||||||
font pango:Cascadia Code 12
|
|
||||||
|
|
||||||
# feh
|
|
||||||
# https://wiki.archlinux.org/index.php/Feh
|
|
||||||
exec --no-startup-id feh --no-fehbg --bg-fill --randomize /usr/share/backgrounds/archlinux/*
|
|
||||||
|
|
||||||
# redshift
|
|
||||||
# https://wiki.archlinux.org/index.php/Redshift
|
|
||||||
exec --no-startup-id redshift-gtk
|
|
||||||
|
|
||||||
# fcitx
|
|
||||||
# https://wiki.archlinux.org/index.php/fcitx
|
|
||||||
exec --no-startup-id fcitx
|
|
||||||
|
|
||||||
# i3lock
|
|
||||||
bindsym $mod+l exec --no-startup-id i3lock -e -c 000000
|
|
||||||
|
|
||||||
# adjust volume
|
|
||||||
set $refresh_i3status killall -SIGUSR1 i3status
|
|
||||||
bindsym XF86AudioRaiseVolume exec --no-startup-id pactl set-sink-volume @DEFAULT_SINK@ +5% && $refresh_i3status
|
|
||||||
bindsym XF86AudioLowerVolume exec --no-startup-id pactl set-sink-volume @DEFAULT_SINK@ -5% && $refresh_i3status
|
|
||||||
bindsym XF86AudioMute exec --no-startup-id pactl set-sink-mute @DEFAULT_SINK@ toggle && $refresh_i3status
|
|
||||||
bindsym XF86AudioMicMute exec --no-startup-id pactl set-source-mute @DEFAULT_SOURCE@ toggle && $refresh_i3status
|
|
||||||
|
|
||||||
# adjust brightness
|
|
||||||
bindsym XF86MonBrightnessUp exec --no-startup-id xbacklight -inc 10
|
|
||||||
bindsym XF86MonBrightnessDown exec --no-startup-id xbacklight -dec 10
|
|
||||||
|
|
||||||
# use Mouse+$mod to move floating windows
|
|
||||||
floating_modifier $mod
|
|
||||||
|
|
||||||
# start a terminal
|
|
||||||
bindsym $mod+Return exec i3-sensible-terminal
|
|
||||||
|
|
||||||
# kill focused window
|
|
||||||
bindsym $mod+Shift+q kill
|
|
||||||
|
|
||||||
# rofi (a program launcher)
|
|
||||||
# https://wiki.archlinux.org/index.php/Rofi
|
|
||||||
bindsym $mod+d exec "rofi -combi-modi window,drun -show combi"
|
|
||||||
|
|
||||||
# change focus
|
|
||||||
bindsym $mod+Left focus left
|
|
||||||
bindsym $mod+Down focus down
|
|
||||||
bindsym $mod+Up focus up
|
|
||||||
bindsym $mod+Right focus right
|
|
||||||
|
|
||||||
# move focused window
|
|
||||||
bindsym $mod+Shift+Left move left
|
|
||||||
bindsym $mod+Shift+Down move down
|
|
||||||
bindsym $mod+Shift+Up move up
|
|
||||||
bindsym $mod+Shift+Right move right
|
|
||||||
|
|
||||||
# split in horizontal orientation
|
|
||||||
bindsym $mod+h split h
|
|
||||||
|
|
||||||
# split in vertical orientation
|
|
||||||
bindsym $mod+v split v
|
|
||||||
|
|
||||||
# enter fullscreen mode
|
|
||||||
bindsym $mod+f fullscreen toggle
|
|
||||||
|
|
||||||
# change container layout (stacked, tabbed, toggle split)
|
|
||||||
bindsym $mod+s layout stacking
|
|
||||||
bindsym $mod+w layout tabbed
|
|
||||||
bindsym $mod+e layout toggle split
|
|
||||||
|
|
||||||
# toggle tiling / floating
|
|
||||||
bindsym $mod+Shift+space floating toggle
|
|
||||||
|
|
||||||
# change focus between tiling / floating windows
|
|
||||||
bindsym $mod+space focus mode_toggle
|
|
||||||
|
|
||||||
# focus the parent container
|
|
||||||
bindsym $mod+a focus parent
|
|
||||||
|
|
||||||
# workspace
|
|
||||||
set $ws1 "1"
|
|
||||||
set $ws2 "2"
|
|
||||||
set $ws3 "3"
|
|
||||||
set $ws4 "4"
|
|
||||||
set $ws5 "5"
|
|
||||||
set $ws6 "6"
|
|
||||||
set $ws7 "7"
|
|
||||||
set $ws8 "8"
|
|
||||||
set $ws9 "9"
|
|
||||||
set $ws10 "10"
|
|
||||||
|
|
||||||
# switch to workspace
|
|
||||||
bindsym $mod+1 workspace number $ws1
|
|
||||||
bindsym $mod+2 workspace number $ws2
|
|
||||||
bindsym $mod+3 workspace number $ws3
|
|
||||||
bindsym $mod+4 workspace number $ws4
|
|
||||||
bindsym $mod+5 workspace number $ws5
|
|
||||||
bindsym $mod+6 workspace number $ws6
|
|
||||||
bindsym $mod+7 workspace number $ws7
|
|
||||||
bindsym $mod+8 workspace number $ws8
|
|
||||||
bindsym $mod+9 workspace number $ws9
|
|
||||||
bindsym $mod+0 workspace number $ws10
|
|
||||||
|
|
||||||
# move focused container to workspace
|
|
||||||
bindsym $mod+Shift+1 move container to workspace number $ws1
|
|
||||||
bindsym $mod+Shift+2 move container to workspace number $ws2
|
|
||||||
bindsym $mod+Shift+3 move container to workspace number $ws3
|
|
||||||
bindsym $mod+Shift+4 move container to workspace number $ws4
|
|
||||||
bindsym $mod+Shift+5 move container to workspace number $ws5
|
|
||||||
bindsym $mod+Shift+6 move container to workspace number $ws6
|
|
||||||
bindsym $mod+Shift+7 move container to workspace number $ws7
|
|
||||||
bindsym $mod+Shift+8 move container to workspace number $ws8
|
|
||||||
bindsym $mod+Shift+9 move container to workspace number $ws9
|
|
||||||
bindsym $mod+Shift+0 move container to workspace number $ws10
|
|
||||||
|
|
||||||
bindsym $mod+Shift+c reload
|
|
||||||
bindsym $mod+Shift+r restart
|
|
||||||
bindsym $mod+Shift+e exec "i3-nagbar -t warning -f 'pango:Cascadia Code 12' -m 'Do you want to exit i3?' -B 'Yes, exit i3' 'i3-msg exit'"
|
|
||||||
|
|
||||||
# resize window
|
|
||||||
mode "resize" {
|
|
||||||
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+r mode "resize"
|
|
||||||
|
|
||||||
# use i3status
|
|
||||||
bar {
|
|
||||||
position top
|
|
||||||
status_command i3status
|
|
||||||
}
|
|
|
@ -1,39 +0,0 @@
|
||||||
general {
|
|
||||||
interval = 5
|
|
||||||
|
|
||||||
# https://github.com/joshdick/onedark.vim
|
|
||||||
colors = true
|
|
||||||
color_good = "#98C379"
|
|
||||||
color_degraded = "#E5C07B"
|
|
||||||
color_bad = "#E06C75"
|
|
||||||
}
|
|
||||||
|
|
||||||
order += "wireless _first_"
|
|
||||||
order += "ethernet _first_"
|
|
||||||
order += "battery all"
|
|
||||||
order += "volume master"
|
|
||||||
order += "tztime local"
|
|
||||||
|
|
||||||
wireless _first_ {
|
|
||||||
format_up = "Wifi: %essid"
|
|
||||||
format_down = "Wifi: down"
|
|
||||||
}
|
|
||||||
|
|
||||||
ethernet _first_ {
|
|
||||||
format_up = "Ethernet: %ip (%speed)"
|
|
||||||
format_down = "Ethernet: down"
|
|
||||||
}
|
|
||||||
|
|
||||||
battery all {
|
|
||||||
format = "%status %percentage %remaining"
|
|
||||||
}
|
|
||||||
|
|
||||||
volume master {
|
|
||||||
format = "Sound: %volume"
|
|
||||||
format_muted = "Sound: muted (%volume)"
|
|
||||||
device = "pulse"
|
|
||||||
}
|
|
||||||
|
|
||||||
tztime local {
|
|
||||||
format = "%Y-%m-%d %H:%M:%S"
|
|
||||||
}
|
|
|
@ -1,7 +0,0 @@
|
||||||
[redshift]
|
|
||||||
location-provider=manual
|
|
||||||
|
|
||||||
[manual]
|
|
||||||
; Ho Chi Minh, Vietnam
|
|
||||||
lat=10.8188
|
|
||||||
lon=106.65186
|
|
|
@ -1,4 +0,0 @@
|
||||||
configuration {
|
|
||||||
modi: "window,drun,combi";
|
|
||||||
font: "Cascadia Code 12";
|
|
||||||
}
|
|
|
@ -1,19 +0,0 @@
|
||||||
# https://github.com/tmux/tmux/wiki/FAQ
|
|
||||||
|
|
||||||
# Switch panes using Alt without prefix
|
|
||||||
bind -n M-Left select-pane -L
|
|
||||||
bind -n M-Right select-pane -R
|
|
||||||
bind -n M-Up select-pane -U
|
|
||||||
bind -n M-Down select-pane -D
|
|
||||||
|
|
||||||
# Color
|
|
||||||
set -g default-terminal "tmux-256color"
|
|
||||||
|
|
||||||
# https://github.com/tmux-plugins/tpm
|
|
||||||
# List of plugins
|
|
||||||
set -g @plugin 'tmux-plugins/tpm'
|
|
||||||
set -g @plugin 'tmux-plugins/tmux-sensible'
|
|
||||||
set -g @plugin 'tmux-plugins/tmux-pain-control'
|
|
||||||
|
|
||||||
# Initialize TMUX plugin manager
|
|
||||||
run '~/.tmux/plugins/tpm/tpm'
|
|
|
@ -1,52 +0,0 @@
|
||||||
set breakindent
|
|
||||||
set completeopt=menuone,noinsert,noselect
|
|
||||||
set noswapfile
|
|
||||||
set number
|
|
||||||
set relativenumber
|
|
||||||
set scrolloff=4
|
|
||||||
set virtualedit=block
|
|
||||||
set whichwrap=<,>,[,]
|
|
||||||
|
|
||||||
" True color
|
|
||||||
" https://gist.github.com/XVilka/8346728
|
|
||||||
if (empty($TMUX))
|
|
||||||
if (has('termguicolors'))
|
|
||||||
set termguicolors
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
|
|
||||||
" Disable cursor styling
|
|
||||||
set guicursor=
|
|
||||||
|
|
||||||
" Install xclip or xsel
|
|
||||||
set clipboard+=unnamedplus
|
|
||||||
|
|
||||||
" FZF
|
|
||||||
set rtp+=~/.fzf
|
|
||||||
|
|
||||||
" Plugins config
|
|
||||||
let g:go_fmt_command='gopls'
|
|
||||||
let g:go_gopls_gofumpt=1
|
|
||||||
let g:go_version_warning=0
|
|
||||||
let g:lightline={'colorscheme':'onedark'}
|
|
||||||
|
|
||||||
" vim-plug
|
|
||||||
" https://github.com/junegunn/vim-plug
|
|
||||||
call plug#begin()
|
|
||||||
|
|
||||||
" Should use
|
|
||||||
Plug 'sheerun/vim-polyglot'
|
|
||||||
Plug 'preservim/nerdtree'
|
|
||||||
Plug 'machakann/vim-sandwich'
|
|
||||||
Plug 'itchyny/lightline.vim'
|
|
||||||
|
|
||||||
" Colorschemes
|
|
||||||
Plug 'joshdick/onedark.vim'
|
|
||||||
|
|
||||||
" Languages
|
|
||||||
Plug 'fatih/vim-go', {'tag': '*'}
|
|
||||||
|
|
||||||
call plug#end()
|
|
||||||
|
|
||||||
set background=dark
|
|
||||||
colorscheme onedark
|
|
|
@ -1,7 +0,0 @@
|
||||||
# https://wiki.archlinux.org/index.php/fcitx
|
|
||||||
export GTK_IM_MODULE=fcitx
|
|
||||||
export QT_IM_MODULE=fcitx
|
|
||||||
export XMODIFIERS=@im=fcitx
|
|
||||||
|
|
||||||
# https://wiki.archlinux.org/index.php/i3
|
|
||||||
exec i3
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
{
|
||||||
|
"apps": {
|
||||||
|
"nvim": {
|
||||||
|
"files": [
|
||||||
|
{
|
||||||
|
"internal": "config/nvim/init.vim",
|
||||||
|
"external": "~/.config/nvim/init.vim"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
62
file.go
62
file.go
|
@ -1,62 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"os/user"
|
|
||||||
"path/filepath"
|
|
||||||
|
|
||||||
copier "github.com/haunt98/copy-go"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
homeSymbol = '~'
|
|
||||||
)
|
|
||||||
|
|
||||||
type copyFn func(from, to string) error
|
|
||||||
|
|
||||||
func replaceFile(from, to string) error {
|
|
||||||
return replace(from, to, copier.CopyFile)
|
|
||||||
}
|
|
||||||
|
|
||||||
func replaceDir(from, to string) error {
|
|
||||||
return replace(from, to, copier.CopyDir)
|
|
||||||
}
|
|
||||||
|
|
||||||
func replace(from, to string, fn copyFn) error {
|
|
||||||
newFrom, err := replaceHomeSymbol(from)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to replace home symbol %s: %w", from, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
newTo, err := replaceHomeSymbol(to)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to replace home symbol %s: %w", to, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := os.RemoveAll(newTo); err != nil {
|
|
||||||
return fmt.Errorf("failed to remove %s: %w", newTo, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := fn(newFrom, newTo); err != nil {
|
|
||||||
return fmt.Errorf("failed to copy from %s to %s: %w", newFrom, newTo, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// replace ~
|
|
||||||
// https://stackoverflow.com/a/17609894
|
|
||||||
func replaceHomeSymbol(path string) (string, error) {
|
|
||||||
if path == "" || path[0] != homeSymbol {
|
|
||||||
return path, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
currentUser, err := user.Current()
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
newPath := filepath.Join(currentUser.HomeDir, path[1:])
|
|
||||||
return newPath, nil
|
|
||||||
}
|
|
2
go.mod
2
go.mod
|
@ -5,7 +5,7 @@ go 1.16
|
||||||
require (
|
require (
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.0 // indirect
|
github.com/cpuguy83/go-md2man/v2 v2.0.0 // indirect
|
||||||
github.com/haunt98/color v0.1.0
|
github.com/haunt98/color v0.1.0
|
||||||
github.com/haunt98/copy-go v0.4.0
|
github.com/haunt98/copy-go v0.5.0
|
||||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||||
github.com/urfave/cli/v2 v2.3.0
|
github.com/urfave/cli/v2 v2.3.0
|
||||||
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57 // indirect
|
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57 // indirect
|
||||||
|
|
4
go.sum
4
go.sum
|
@ -6,8 +6,8 @@ github.com/fatih/color v1.10.0 h1:s36xzo75JdqLaaWoiEHk767eHiwo0598uUxyfiPkDsg=
|
||||||
github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM=
|
github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM=
|
||||||
github.com/haunt98/color v0.1.0 h1:qfP5oNI3aoUC8T+bH/JNVAg79ljyhTGpgfqSKWhkiQQ=
|
github.com/haunt98/color v0.1.0 h1:qfP5oNI3aoUC8T+bH/JNVAg79ljyhTGpgfqSKWhkiQQ=
|
||||||
github.com/haunt98/color v0.1.0/go.mod h1:V4BPVUSuiOItuVZHRHUTkpxO7OYQiP0DSgIWMpC/2qs=
|
github.com/haunt98/color v0.1.0/go.mod h1:V4BPVUSuiOItuVZHRHUTkpxO7OYQiP0DSgIWMpC/2qs=
|
||||||
github.com/haunt98/copy-go v0.4.0 h1:ts47dExLyIWWrnLQmVc475Af3/LO111zeB58waSe02A=
|
github.com/haunt98/copy-go v0.5.0 h1:8yy7Dx47BBtlHIFIXxcCIECZRoQB/JSgLN9yunqtLAQ=
|
||||||
github.com/haunt98/copy-go v0.4.0/go.mod h1:cK1mRlW7QXPHhe5YI1VtL/U4OjUbRLAtZnO/oucrwRI=
|
github.com/haunt98/copy-go v0.5.0/go.mod h1:cK1mRlW7QXPHhe5YI1VtL/U4OjUbRLAtZnO/oucrwRI=
|
||||||
github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8=
|
github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8=
|
||||||
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||||
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
|
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
|
||||||
|
|
61
main.go
61
main.go
|
@ -7,6 +7,7 @@ import (
|
||||||
"runtime"
|
"runtime"
|
||||||
|
|
||||||
"github.com/haunt98/color"
|
"github.com/haunt98/color"
|
||||||
|
"github.com/haunt98/dotfiles/pkg/config"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -16,6 +17,7 @@ const (
|
||||||
|
|
||||||
// flags
|
// flags
|
||||||
verboseFlag = "verbose"
|
verboseFlag = "verbose"
|
||||||
|
dryRunFlag = "dry-run"
|
||||||
|
|
||||||
// commands
|
// commands
|
||||||
installCommand = "install"
|
installCommand = "install"
|
||||||
|
@ -24,6 +26,7 @@ const (
|
||||||
|
|
||||||
// usages
|
// usages
|
||||||
verboseUsage = "show what is going on"
|
verboseUsage = "show what is going on"
|
||||||
|
dryRunUsage = "demo mode without actually changing anything"
|
||||||
installUsage = "install user configs from dotfiles"
|
installUsage = "install user configs from dotfiles"
|
||||||
updateUsage = "update dotfiles from user configs"
|
updateUsage = "update dotfiles from user configs"
|
||||||
cleanUsage = "clean unused dotfiles"
|
cleanUsage = "clean unused dotfiles"
|
||||||
|
@ -66,6 +69,10 @@ func main() {
|
||||||
Name: verboseFlag,
|
Name: verboseFlag,
|
||||||
Usage: verboseUsage,
|
Usage: verboseUsage,
|
||||||
},
|
},
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: dryRunFlag,
|
||||||
|
Usage: dryRunUsage,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
Action: a.RunInstall,
|
Action: a.RunInstall,
|
||||||
},
|
},
|
||||||
|
@ -73,13 +80,33 @@ func main() {
|
||||||
Name: updateCommand,
|
Name: updateCommand,
|
||||||
Aliases: updateAliases,
|
Aliases: updateAliases,
|
||||||
Usage: updateUsage,
|
Usage: updateUsage,
|
||||||
Action: a.RunUpdate,
|
Flags: []cli.Flag{
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: verboseFlag,
|
||||||
|
Usage: verboseUsage,
|
||||||
|
},
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: dryRunFlag,
|
||||||
|
Usage: dryRunUsage,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Action: a.RunUpdate,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: cleanCommand,
|
Name: cleanCommand,
|
||||||
Aliases: cleanAliases,
|
Aliases: cleanAliases,
|
||||||
Usage: cleanUsage,
|
Usage: cleanUsage,
|
||||||
Action: a.RunClean,
|
Flags: []cli.Flag{
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: verboseFlag,
|
||||||
|
Usage: verboseUsage,
|
||||||
|
},
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: dryRunFlag,
|
||||||
|
Usage: dryRunUsage,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Action: a.RunClean,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Action: a.RunHelp,
|
Action: a.RunHelp,
|
||||||
|
@ -93,6 +120,7 @@ func main() {
|
||||||
type action struct {
|
type action struct {
|
||||||
flags struct {
|
flags struct {
|
||||||
verbose bool
|
verbose bool
|
||||||
|
dryRun bool
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -105,11 +133,10 @@ func (a *action) RunInstall(c *cli.Context) error {
|
||||||
a.getFlags(c)
|
a.getFlags(c)
|
||||||
a.log("start %s\n", installCommand)
|
a.log("start %s\n", installCommand)
|
||||||
|
|
||||||
cfg, err := LoadConfig(currentDir)
|
cfg, err := a.loadConfig()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to load config: %w", err)
|
return err
|
||||||
}
|
}
|
||||||
a.log("config %+v\n", cfg)
|
|
||||||
|
|
||||||
if err := cfg.Install(); err != nil {
|
if err := cfg.Install(); err != nil {
|
||||||
return fmt.Errorf("failed to install config: %w", err)
|
return fmt.Errorf("failed to install config: %w", err)
|
||||||
|
@ -122,11 +149,10 @@ func (a *action) RunUpdate(c *cli.Context) error {
|
||||||
a.getFlags(c)
|
a.getFlags(c)
|
||||||
a.log("start %s\n", updateCommand)
|
a.log("start %s\n", updateCommand)
|
||||||
|
|
||||||
cfg, err := LoadConfig(currentDir)
|
cfg, err := a.loadConfig()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to load config: %w", err)
|
return err
|
||||||
}
|
}
|
||||||
a.log("config %+v\n", cfg)
|
|
||||||
|
|
||||||
if err := cfg.Update(); err != nil {
|
if err := cfg.Update(); err != nil {
|
||||||
return fmt.Errorf("failed to update config: %w", err)
|
return fmt.Errorf("failed to update config: %w", err)
|
||||||
|
@ -139,11 +165,10 @@ func (a *action) RunClean(c *cli.Context) error {
|
||||||
a.getFlags(c)
|
a.getFlags(c)
|
||||||
a.log("start %s\n", cleanCommand)
|
a.log("start %s\n", cleanCommand)
|
||||||
|
|
||||||
cfg, err := LoadConfig(currentDir)
|
cfg, err := a.loadConfig()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to load config: %w", err)
|
return err
|
||||||
}
|
}
|
||||||
a.log("config %+v\n", cfg)
|
|
||||||
|
|
||||||
if err := cfg.Clean(); err != nil {
|
if err := cfg.Clean(); err != nil {
|
||||||
return fmt.Errorf("failed to clean config: %w", err)
|
return fmt.Errorf("failed to clean config: %w", err)
|
||||||
|
@ -152,8 +177,22 @@ func (a *action) RunClean(c *cli.Context) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *action) loadConfig() (config.Config, error) {
|
||||||
|
cfgReal, cfgDemo, err := config.LoadConfig(currentDir)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to load config: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if a.flags.dryRun {
|
||||||
|
return cfgDemo, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return cfgReal, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (a *action) getFlags(c *cli.Context) {
|
func (a *action) getFlags(c *cli.Context) {
|
||||||
a.flags.verbose = c.Bool(verboseFlag)
|
a.flags.verbose = c.Bool(verboseFlag)
|
||||||
|
a.flags.dryRun = c.Bool(dryRunFlag)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *action) log(format string, v ...interface{}) {
|
func (a *action) log(format string, v ...interface{}) {
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
package config
|
||||||
|
|
||||||
|
type Config interface {
|
||||||
|
Install() error
|
||||||
|
Update() error
|
||||||
|
Clean() error
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
package config
|
||||||
|
|
||||||
|
type configDemo struct {
|
||||||
|
configApps
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ Config = (*configDemo)(nil)
|
||||||
|
|
||||||
|
func (cd *configDemo) Install() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cd *configDemo) Update() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cd *configDemo) Clean() error {
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package main
|
package config
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
@ -6,18 +6,26 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
|
"github.com/haunt98/copy-go"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
configDirPath = "config"
|
configDirPath = "data"
|
||||||
configFile = "config.json"
|
configFile = "data.json"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Config struct {
|
type config struct {
|
||||||
// Read from file
|
configApps
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ Config = (*config)(nil)
|
||||||
|
|
||||||
|
type configApps struct {
|
||||||
Apps map[string]App `json:"apps"`
|
Apps map[string]App `json:"apps"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Read from file
|
||||||
type App struct {
|
type App struct {
|
||||||
Files []Path `json:"files"`
|
Files []Path `json:"files"`
|
||||||
Dirs []Path `json:"dirs"`
|
Dirs []Path `json:"dirs"`
|
||||||
|
@ -28,39 +36,45 @@ type Path struct {
|
||||||
External string `json:"external"`
|
External string `json:"external"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load config from file
|
// LoadConfig return config, configDemo
|
||||||
func LoadConfig(path string) (result Config, err error) {
|
func LoadConfig(path string) (*config, *configDemo, error) {
|
||||||
configPath := getConfigPath(path)
|
configPath := getConfigPath(path)
|
||||||
bytes, err := os.ReadFile(configPath)
|
bytes, err := os.ReadFile(configPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, os.ErrNotExist) {
|
if errors.Is(err, os.ErrNotExist) {
|
||||||
err = fmt.Errorf("file not exist %s: %w", configPath, err)
|
return nil, nil, fmt.Errorf("file not exist %s: %w", configPath, err)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
err = fmt.Errorf("failed to read file%s: %w", configPath, err)
|
return nil, nil, fmt.Errorf("failed to read file%s: %w", configPath, err)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = json.Unmarshal(bytes, &result); err != nil {
|
var cfgApps configApps
|
||||||
err = fmt.Errorf("failed to unmarshal: %w", err)
|
if err = json.Unmarshal(bytes, &cfgApps); err != nil {
|
||||||
return
|
return nil, nil, fmt.Errorf("failed to unmarshal: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
cfg := config{
|
||||||
|
configApps: cfgApps,
|
||||||
|
}
|
||||||
|
|
||||||
|
cfgDemo := configDemo{
|
||||||
|
configApps: cfgApps,
|
||||||
|
}
|
||||||
|
|
||||||
|
return &cfg, &cfgDemo, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// internal -> external
|
// internal -> external
|
||||||
func (c *Config) Install() error {
|
func (c *config) Install() error {
|
||||||
for _, app := range c.Apps {
|
for _, app := range c.Apps {
|
||||||
for _, file := range app.Files {
|
for _, file := range app.Files {
|
||||||
if err := replaceFile(file.Internal, file.External); err != nil {
|
if err := copy.Replace(file.Internal, file.External); err != nil {
|
||||||
return fmt.Errorf("failed to remove and copy from %s to %s: %w", file.Internal, file.External, err)
|
return fmt.Errorf("failed to remove and copy from %s to %s: %w", file.Internal, file.External, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, dir := range app.Dirs {
|
for _, dir := range app.Dirs {
|
||||||
if err := replaceDir(dir.Internal, dir.External); err != nil {
|
if err := copy.Replace(dir.Internal, dir.External); err != nil {
|
||||||
return fmt.Errorf("failed to remove and copy from %s to %s: %w", dir.Internal, dir.External, err)
|
return fmt.Errorf("failed to remove and copy from %s to %s: %w", dir.Internal, dir.External, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -70,16 +84,16 @@ func (c *Config) Install() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// external -> internal
|
// external -> internal
|
||||||
func (c *Config) Update() error {
|
func (c *config) Update() error {
|
||||||
for _, app := range c.Apps {
|
for _, app := range c.Apps {
|
||||||
for _, file := range app.Files {
|
for _, file := range app.Files {
|
||||||
if err := replaceFile(file.External, file.Internal); err != nil {
|
if err := copy.Replace(file.External, file.Internal); err != nil {
|
||||||
return fmt.Errorf("failed to remove and copy from %s to %s: %w", file.External, file.Internal, err)
|
return fmt.Errorf("failed to remove and copy from %s to %s: %w", file.External, file.Internal, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, dir := range app.Dirs {
|
for _, dir := range app.Dirs {
|
||||||
if err := replaceDir(dir.External, dir.Internal); err != nil {
|
if err := copy.Replace(dir.External, dir.Internal); err != nil {
|
||||||
return fmt.Errorf("failed to remove and copy from %s to %s: %w", dir.External, dir.Internal, err)
|
return fmt.Errorf("failed to remove and copy from %s to %s: %w", dir.External, dir.Internal, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -88,7 +102,7 @@ func (c *Config) Update() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Config) Clean() error {
|
func (c *config) Clean() error {
|
||||||
files, err := os.ReadDir(configDirPath)
|
files, err := os.ReadDir(configDirPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to read dir %s: %w", configDirPath, err)
|
return fmt.Errorf("failed to read dir %s: %w", configDirPath, err)
|
Loading…
Reference in New Issue