Введение ¶
Ранее, я уже описывал мой опыт с ZSH здесь. Сейчас всё немного иначе, я полностью перешёл на Powerlevel10k.
Это очень красивый и удобный обвес, который просто ставится и настраивается на ходу.
Настройка p10k ¶
Настроить p10k можно очень просто, прямо на ходу, хоть по 10 раз на дню.
Установку самого p10k я зашил прямо в .zshrc, по этому, можно даже не следовать официальным инструкциям на сайте. Ну почти. Есть ещё рекомендованные шрифты, чтобы всё точно было красиво, описано вот здесь. Ниже, я записал и показал как выглядит настройка самого p10k. Вот только, в записи asciinema всё красивости квадратиками, не поддерживаются эти символы в записи, к сожалению. По этому, вот скриншот терминального окна.
В то время, как в записи, получилось не очень. Ну да ладно, хоть сами меню покажу.
Объяснение моего .zshrc ¶
Всё написанное далее это куски самого .zshrc, которые можно скачать в конце статьи. Для вашего удобства, продублирую ссылку ещё и здесь.
Установка p10k ¶
Выполнено это простым условием и прямым стягиванием из GitHub. Если у нас есть Git и ещё не стоит p10k - можем склонировать.
1
2
3
4
| if command -v git >/dev/null && [ ! -d ~/powerlevel10k ]; then
echo "info: installing p10k"
git clone --depth 1 --single-branch https://github.com/romkatv/powerlevel10k.git ~/powerlevel10k
fi
|
Плагины ¶
Плагины ставлю просто, тоже клонированием из GitHub. Добавил комментарии прямо в код для пояснения происходящего.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
| # if we have git installed
if command -v git >/dev/null; then
# and folder with plugins is absent
if [ ! -d /usr/share/zsh/plugins ]; then
# let's create it with sudo
sudo mkdir -p /usr/share/zsh/plugins
fi
# and jump in
cd /usr/share/zsh/plugins
# now, let's read every line between <<EOF and EOF lines below
while IFS= read -r REPO; do
# and for every line, which will be available in variable named REPO
# let's cut only last part of the url (ex: zsh-autosuggestions.git) and save to BASENAME var
BASENAME="$(basename "$REPO")"
# now, we will remove .git from the end of BASENAME and check either such folder exists
if [ ! -d "${BASENAME%.git}" ]; then
# if not, let's print an info message
echo "${REPO}: Cloning to $(pwd)/${BASENAME%.git}"
# and finally clone that plugin
sudo git clone --depth 1 --single-branch "$REPO"
fi
done <<EOF
https://github.com/zsh-users/zsh-history-substring-search.git
https://github.com/zsh-users/zsh-syntax-highlighting.git
https://github.com/zsh-users/zsh-autosuggestions.git
EOF
# after all plugins cloned, we cd back to the location we were
cd - >/dev/null
fi
# okay, now we assume that all plugins are cloned and we have to include them
# once again, for every hardcoded path to .zsh file
while IFS= read -r SOURCE; do
# we skip the plugin if it starts with '#' (commented out)
if echo "$SOURCE" | grep -qE '^#'; then
continue
elif [ -s "$SOURCE" ]; then
# if it is enabled, we just include it in current shell session with source command
source "$(realpath "$SOURCE")"
fi
done <<EOF
/usr/share/zsh/plugins/zsh-history-substring-search/zsh-history-substring-search.zsh
/usr/share/zsh/plugins/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh
/usr/share/zsh/plugins/zsh-autosuggestions/zsh-autosuggestions.zsh
EOF
|
Добавление путей в PATH ¶
Часто бывает, что дополнительные бинарники мы ставим в нестандартные папки. У меня, к примеру, ~/.local/bin используется для всяких kubectl, helm, k9s и другого. Вот тут мы для каждой папочки, если она конечно есть, выполняем проверку и включаем её в переменную PATH.
1
2
3
4
5
6
7
8
9
| while IFS= read -r P; do
if [ -d "$P" ]; then
export PATH="${P}:${PATH}"
fi
done <<EOF
${HOME}/.local/share/gem/ruby/3.0.0/bin
${HOME}/projects/stm32/gcc-arm-none-eabi-10.3-2021.10/bin
${HOME}/.local/bin
EOF
|
Алиасы ¶
Ну тут всё понятно, много всяких алиасов.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
| alias ..="cd .. && ls -lhA --color=auto"
alias d='sudo -E docker'
alias dc="docker-compose"
alias e="exit"
alias j="sudo journalctl"
alias l="ls -lh --color=always"
alias la="ls -lhA --color=always"
alias p="ping 8.8.8.8"
alias please='sudo'
alias reborn="sudo shutdown -r now"
alias s='sudo'
alias sctl="sudo systemctl"
alias svi="sudo vim"
alias svim="sudo vim"
alias t='terraform'
alias k="kubectl"
alias kd="kubectl describe"
alias kg="kubectl get"
alias ky="kubectl get -o yaml"
alias ke='kubectl exec -it'
alias vi="vim"
alias g="git"
alias b="sudo btrfs"
alias c="code ."
alias ansible-time="time ansible-playbook"
|
Git config ¶
К слову, у меня ж ещё есть и Git config. Ссылка тут или то же самое в конце страницы. Из интересного тут две команды.
git ps
- пушит ветку, а если её ещё нет, ловит сообщение из лога ошибки git-а и пушит с –set-upstreamgit dpush
(dummy push) - добавляет в коммит все файлы и папки, пишет стандартное сообщение к комиту и пушитgit cc
- просто делает коммит со стандартным сообщением
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| [alias]
co = checkout
a = add .
ci = commit
cc = commit -m 'Nothing special. Just regular commit.'
ps = ! sh -c 'git push >/tmp/git-ps 2>&1 || grep -- \"git push --set-upstream\" /tmp/git-ps | sh'
pt = push --tags
pts = ! sh -c 'git push && git push --tags'
pl = pull
st = status
br = branch
hist = log --pretty=format:'%h %ad | %s%d [%an]' --graph --date=short
type = cat-file -t
dump = cat-file -p
dpush = ! sh -c 'git add . && git commit -m \"Nothing special. Just regular commit.\"' && git push
|
KUBECONFIG ¶
Тут ищется стандартный kubeconfig для k3s или rke2 и прописывается в KUBECONFIG.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
| # if there is no file at the path that is already being set in KUBECONFIG var
if [ -z "$KUBECONFIG" ]; then
# for every filepath from the list below
while IFS= read -r K; do
# check if file exists and it is not empty
if [ -s "$K" ]; then
# change owner and group to current user
if ! stat -c '%u:%g' "$K" | grep -qF "$(id -u):$(id -g)"; then
sudo chown "${USER}:${USER}" "$K"
echo "info: chown $K"
fi
echo "info: selecting $K as kubeconfig"
# and select as default KUBECONFIG
export KUBECONFIG="$K"
fi
done << EOF
/etc/rancher/rke2/rke2.yaml
/etc/rancher/k3s/k3s.yaml
EOF
# last listed path wins
fi
|
Автоматическая загрузка утилит ¶
Тут, значится, происходит следующее: .zshrc сам следит за тем, чтобы у нас были установлены бинарники утилит, которые мы используем. Если утилиты нет вообще, он её качает, если нет - ничего не делает, но я вручную могу обновить k9s выполнив _update_k9s. Здесь ставятся такие вещи.
- k9s - подробнее в моей статье
- kubepug - утилита для проверки устаревших API в кластере перед обновлением версии самого Kubernetes
- kubecolor - обёртка над kubectl для разноцветного вывода
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
| _update_kubepug() {
mkdir -p ~/.local/bin
LOCATION="$(curl --connect-timeout 1 -sS https://github.com/rikatz/kubepug/releases/latest -D- | awk '/^location:/{print $2}')"
LATEST_VERSION="$(echo "$LOCATION" | awk -F/ '{print $NF}' | grep -oE '[0-9a-zA-Z_.-]+')"
if ! k9s version --short | grep -qF "$LATEST_VERSION"; then
printf "Updating kubepug to %s\n" "$LATEST_VERSION"
printf 'https://github.com/rikatz/kubepug/releases/download/%s/kubepug_linux_%s.tar.gz' \
"$LATEST_VERSION" "$(uname -p | sed 's/unknown/amd64/g' | tr -d '[[:space:]]')" | \
xargs curl -sSL | \
tar -xpzf - kubepug
install kubepug ~/.local/bin/kubepug -m 0755
rm -f kubepug
fi
}
if ! command -v kubepug &>/dev/null; then
_update_kubepug
fi
_update_k9s() {
mkdir -p ~/.local/bin
LOCATION="$(curl --connect-timeout 1 -sS https://github.com/derailed/k9s/releases/latest -D- | awk '/^location:/{print $2}')"
LATEST_VERSION="$(echo "$LOCATION" | awk -F/ '{print $NF}' | grep -oE '[0-9a-zA-Z_.-]+')"
if ! k9s version --short | grep -qF "$LATEST_VERSION"; then
printf "Updating k9s to %s\n" "$LATEST_VERSION"
printf 'https://github.com/derailed/k9s/releases/download/%s/k9s_Linux_%s.tar.gz' \
"$LATEST_VERSION" "$(uname -p | sed 's/unknown/x86_64/g' | tr -d '[[:space:]]')" | \
xargs curl -sSL | \
tar -xpzf - k9s
install k9s ~/.local/bin/k9s -m 0755
rm -f k9s
fi
}
if ! command -v k9s &>/dev/null; then
_update_k9s
fi
_update_kubecolor() {
mkdir -p ~/.local/bin
LOCATION="$(curl --connect-timeout 1 -sS https://github.com/hidetatz/kubecolor/releases/latest -D- | awk '/^location:/{print $2}')"
LATEST_VERSION="$(echo "$LOCATION" | awk -F/ '{print $NF}' | grep -oE '[0-9a-zA-Z_.-]+' | sed 's/^v//g')"
if ! kubecolor --kubecolor-version | grep -qF "$LATEST_VERSION"; then
printf "Updating kubecolor to %s\n" "$LATEST_VERSION"
printf 'https://github.com/hidetatz/kubecolor/releases/download/%s/kubecolor_%s_Linux_%s.tar.gz' \
"v$LATEST_VERSION" "$LATEST_VERSION" "$(uname -p | sed 's/unknown/x86_64/g' | tr -d '[[:space:]]')" | \
xargs curl -sSL | \
tar -xpzf - kubecolor
install kubecolor ~/.local/bin/kubecolor -m 0755
rm -f kubecolor
fi
}
if ! command -v kubecolor &>/dev/null; then
_update_kubecolor
alias kubectl="kubecolor"
typeset -g POWERLEVEL9K_KUBECONTEXT_SHOW_ON_COMMAND="${POWERLEVEL9K_KUBECONTEXT_SHOW_ON_COMMAND}|kubecolor"
fi
|
Так же, для ряда команд, если они такие есть, выполняется автоматическая подгрузка дополнений подсказки, чтобы zsh знал что подсказывать.
1
2
3
4
5
6
| ## Completions for 3-d party binaries
for COMMAND in kubectl helm k3d flux kubepug; do
if command -v "$COMMAND" >/dev/null; then
source <("$COMMAND" completion zsh)
fi
done
|
Раздельные окружения ¶
Вот тут самая хитрая и в то же время простая штука из моего арсенала. Самая ценная вещь в работе. Дело в том, что когда работаешь на разных проектах\окружениях, то самая страшная вещь, которую ты можешь сделать это что-то сломать. Так вот нет способа проще это сделать, чем забыть переключится на нужное окружение и применить что-то не туда куда думал.
Вот от этого как раз и спасает этот кусок кода.
1
2
3
| if [ -f env.sh ]; then
source ./env.sh
fi
|
Да всё так просто. А что собственно происходит? Дело в том, что zsh разово, при запуске, проверяет ту папку, в которой он запустился и если там есть файл с точным именем env.sh, то включает его в контекст. Объясняю.
Я использую Ranger для навигации по папкам из терминала. Допустим я работаю на проекте и у меня ещё блог есть. Создал вот такие папочки для проектов.
1
2
3
4
5
6
7
8
9
10
11
12
13
| .
├── MyBlog
│ ├── env.sh
│ └── kubeconfig.yaml
└── SuperWorkProject
├── development
│ ├── env.sh
│ └── kubeconfig.yaml
└── production
├── env.sh
└── kubeconfig.yaml
4 directories, 6 files
|
На боевом проекте у меня есть два окружения, везде Kubernetes, везде свои раздельные kubeconfig.yaml. Допустим мне нужно поработать на production. В его env.sh я запишу следующее.
1
2
3
4
5
6
7
8
| #!/usr/bin/env sh
export KUBECONFIG='~/projects/SuperWorkProject/production/kubeconfig.yaml'
export AWS_PROFILE='production'
pf() {
nohup sh -c 'kubectl get po -n monitoring -l app.kubernetes.io/name=grafana -o name | xargs -I{} kubectl port-forward {} 3000' 1>/dev/null &
}
|
Теперь, подключу открыв zsh в этой папке или просто через source ./env.sh
. Всё, теперь я точно уверен, что работаю с production. Кроме того, объявил себе функцию для port-forward.