diff --git a/docker/docker.nu b/docker/docker.nu new file mode 100644 index 0000000..75a98ce --- /dev/null +++ b/docker/docker.nu @@ -0,0 +1,315 @@ +alias docker = podman + +export def dp [] { + # docker ps --all --no-trunc --format='{{json .}}' | jq + docker ps -a --format '{"id":"{{.ID}}", "image": "{{.Image}}", "name":"{{.Names}}", "cmd":"{{.Command}}", "port":"{{.Ports}}", "status":"{{.Status}}", "created":"{{.Created}}"}' + | lines + | each {|x| + let r = ($x | from json) + let t = ($r.created | str substring ',32' | into datetime ) - 8hr + $r | upsert created $t + } +} + +export def di [] { + docker images + | from ssv -a + | rename repo tag id created size + | upsert size { |i| $i.size | into filesize } +} + +def "nu-complete docker ps" [] { + docker ps + | from ssv -a + | each {|x| {description: $x.NAMES value: $x.'CONTAINER ID'}} +} + +def "nu-complete docker container" [] { + docker ps + | from ssv -a + | each {|x| {description: $x.'CONTAINER ID' value: $x.NAMES}} +} + +def "nu-complete docker all container" [] { + docker ps -a + | from ssv -a + | each {|x| {description: $x.'CONTAINER ID' value: $x.NAMES}} +} + +def "nu-complete docker images" [] { + docker images + | from ssv + | each {|x| $"($x.REPOSITORY):($x.TAG)"} +} + +export def dl [ctn: string@"nu-complete docker container"] { + docker logs -f $ctn +} + +export def da [ + ctn: string@"nu-complete docker container" + ...args +] { + if ($args|is-empty) { + docker exec -it $ctn /bin/sh -c "[ -e /bin/zsh ] && /bin/zsh || [ -e /bin/bash ] && /bin/bash || /bin/sh" + } else { + docker exec -it $ctn $args + } +} + +export def dcp [ + lhs: string@"nu-complete docker container", + rhs: string@"nu-complete docker container" +] { + docker cp $lhs $rhs +} + +export def dcr [ctn: string@"nu-complete docker all container"] { + docker container rm -f $ctn +} + +export def dis [img: string@"nu-complete docker images"] { + docker inspect $img +} + +export def dh [img: string@"nu-complete docker images"] { + docker history --no-trunc $img | from ssv -a +} + +export def dsv [...img: string@"nu-complete docker images"] { + docker save $img +} + +export alias dld = podman load + +export def dsp [] { + docker system prune -f +} + +export alias dspall = podman system prune --all --force --volumes + +export def drmi [img: string@"nu-complete docker images"] { + docker rmi $img +} + +export def dt [from: string@"nu-complete docker images" to: string] { + docker tag $from $to +} + +export def dps [img: string@"nu-complete docker images"] { + docker push $img +} + +export alias dpl = podman pull + +### volume +export def dvl [] { + docker volume ls | from ssv -a +} + +def "nu-complete docker volume" [] { + dvl | get name +} + +export def dvc [name: string] { + docker volume create +} + +export def dvi [name: string@"nu-complete docker volume"] { + docker volume inspect $name +} + +export def dvr [...name: string@"nu-complete docker volume"] { + docker volume rm $name +} + +### run +def "nu-complete docker run vol" [] { + [ + $"($env.PWD):/world" + $"($env.PWD):/app" + $"($env.PWD):/srv" + $"($env.HOME)/.config/nvim:/etc/nvim" + ] +} + +def "nu-complete docker run port" [ctx: string, pos: int] { + [ + $"(port 8080):80" + $"(port 2222):22" + $"(port 3000):3000" + $"(port 5000):5000" + $"(port 8000):8000" + $"(port 9000):9000" + ] +} + +def "nu-complete docker run sshkey" [ctx: string, pos: int] { + (do { cd ~/.ssh; ls **/*.pub } | get name) +} + +def "nu-complete docker run proxy" [] { + let hostaddr = do -i {hostname -I | split row ' ' | get 0} + [$"http://($hostaddr):7890" $"http://localhost:7890"] +} + +export def dr [ + --debug(-x): bool + --appimage: bool + --netadmin(-n): bool + --proxy: string@"nu-complete docker run proxy" # proxy + --ssh(-s): string@"nu-complete docker run sshkey" # specify ssh key + --sshuser: string=root # default root + --cache(-c): string # cache + --vol(-v): string@"nu-complete docker run vol" # volume + --port(-p): any # { 8080: 80 } + --envs(-e): any # { FOO: BAR } + --daemon(-d): bool + --attach(-a): string@"nu-complete docker container" # attach + --entrypoint: string # entrypoint + --dry-run: bool + --with-x: bool + img: string@"nu-complete docker images" # image + ...cmd # command args +] { + let entrypoint = if ($entrypoint|is-empty) { [] } else { [--entrypoint $entrypoint] } + let daemon = if $daemon { [-d] } else { [--rm -it] } + let mnt = if ($vol|is-empty) { [] } else { [-v $vol] } + let envs = if ($envs|is-empty) { [] } else { $envs | transpose k v | each {|x| $"-e ($x.k)=($x.v)"} } + let port = if ($port|is-empty) { [] } else { $port | transpose k v | each {|x|[-p $"($x.k):($x.v)"]} | flatten } + let debug = if $debug { [--cap-add=SYS_ADMIN --cap-add=SYS_PTRACE --security-opt seccomp=unconfined] } else { [] } + #let appimage = if $appimage { [--device /dev/fuse --security-opt apparmor:unconfined] } else { [] } + let appimage = if $appimage { [--device /dev/fuse] } else { [] } + let netadmin = if $netadmin { [--cap-add=NET_ADMIN --device /dev/net/tun] } else { [] } + let clip = if $with_x { [-e DISPLAY -v /tmp/.X11-unix:/tmp/.X11-unix] } else { [] } + let ssh = if ($ssh|is-empty) { [] } else { + let sshkey = (cat ([~/.ssh $ssh] | path join) | split row ' ' | get 1) + [-e $"ed25519_($sshuser)=($sshkey)"] + } + let proxy = if ($proxy|is-empty) { [] } else { + [-e $"http_proxy=($proxy)" -e $"https_proxy=($proxy)"] + } + let attach = if ($attach|is-empty) { [] } else { + let c = $"container:($attach)" + [--uts $c --ipc $c --pid $c --network $c] + } + let cache = if ($cache|is-empty) { [] } else { [-v $cache] } + let args = ([$entrypoint $attach $daemon $envs $ssh $proxy $debug $appimage $netadmin $clip $mnt $port $cache] | flatten) + let name = $"($img | split row '/' | last | str replace ':' '-')_(date now | date format %m%d%H%M)" + if $dry_run { + echo $"docker run --name ($name) ($args|str join ' ') ($img) ($cmd | flatten)" + } else { + docker run --name $name $args $img ($cmd | flatten) + } +} + +def "nu-complete docker dev env" [] { + [ io io:rs io:hs io:jpl io:go ng ng:pg ] +} + + +export def dx [ + --dry-run(-v): bool + --mount-cache: bool + --attach(-a): string@"nu-complete docker container" # attach + --proxy: string@"nu-complete docker run proxy" # proxy + dx: string@"nu-complete docker images" # image + --envs(-e): any # { FOO: BAR } + --port(-p): any # { 8080: 80 } # todo: multiple specify parameters(-p 8080:80 -p 8181:81) + ...cmd # command args +] { + let __dx_cache = { + hs: 'stack:/opt/stack' + rs: 'cargo:/opt/cargo' + go: 'gopkg:/opt/gopkg' + ng: 'ng:/srv' + pg: 'pg:/var/lib/postgresql/data' + } + let c = do -i {$__dx_cache | transpose k v | where {|x| $dx | str contains $x.k} | get v.0} + let c = if ($c|is-empty) { '' } else if $mount_cache { + let c = ( $c + | split row ':' + | each -n {|x| if $x.index == 1 { $"/cache($x.item)" } else { $x.item } } + | str join ':' + ) + $"($env.HOME)/.cache/($c)" + } else { + $"($env.HOME)/.cache/($c)" + } + let proxy = if ($proxy|is-empty) { [] } else { [--proxy $proxy] } + if $dry_run { + print $"cache: ($c)" + dr --dry-run --attach $attach --port $port --envs $envs --cache $c -v $"($env.PWD):/world" --debug --proxy $proxy --ssh id_ed25519.pub $dx $cmd + } else { + dr --attach $attach --port $port --envs $envs --cache $c -v $"($env.PWD):/world" --debug --proxy $proxy --ssh id_ed25519.pub $dx $cmd + } +} + + +def "nu-complete registry list" [cmd: string, offset: int] { + let cmd = ($cmd | split row ' ') + let url = do -i { $cmd | get 2 } + let reg = do -i { $cmd | get 3 } + let tag = do -i { $cmd | get 4 } + if ($reg|is-empty) { + if (do -i { $env.REGISTRY_TOKEN } | is-empty) { + fetch $"($url)/v2/_catalog" + } else { + fetch -H [authorization $"Basic ($env.REGISTRY_TOKEN)"] $"($url)/v2/_catalog" + } + | get repositories + } else if ($tag|is-empty) { + if (do -i { $env.REGISTRY_TOKEN } | is-empty) { + fetch $"($url)/v2/($reg)/tags/list" + } else { + fetch -H [authorization $"Basic ($env.REGISTRY_TOKEN)"] $"($url)/v2/($reg)/tags/list" + } + | get tags + } +} + +### docker registry list +export def "registry list" [ + url: string + reg: string@"nu-complete registry list" +] { + if (do -i { $env.REGISTRY_TOKEN } | is-empty) { + fetch $"($url)/v2/($reg)/tags/list" + } else { + fetch -H [authorization $"Basic ($env.REGISTRY_TOKEN)"] $"($url)/v2/($reg)/tags/list" + } + | get tags +} + +### buildah + +export def "bud img" [] { + buildah images + | from ssv -a + | rename repo tag id created size + | upsert size { |i| $i.size | into filesize } +} + +export def "bud ls" [] { + buildah list + | from ssv -a + | rename id builder image-id image container +} + +export def "bud ps" [] { + buildah ps + | from ssv -a + | rename id builder image-id image container +} + +def "nu-complete bud ps" [] { + bud ps + | select 'CONTAINER ID' "CONTAINER NAME" + | rename value description +} + +export def "bud rm" [ + id: string@"nu-complete bud ps" +] { + buildah rm $id +} diff --git a/git/git.nu b/git/git.nu new file mode 100644 index 0000000..6b6a947 --- /dev/null +++ b/git/git.nu @@ -0,0 +1,234 @@ +export def _git_stat [n] { + do -i { + git log -n $n --pretty=»¦«%h --stat + | lines + | reduce -f { c: '', r: [] } {|it, acc| + if ($it | str starts-with '»¦«') { + $acc | upsert c ($it | str substring '6,') + } else if ($it | find -r '[0-9]+ file.+change' | is-empty) { + $acc + } else { + let x = ( + $it + | split row ',' + | each {|x| $x + | str trim + | parse -r "(?P[0-9]+) (?P.+)" + | get 0 + } + | reduce -f {sha: $acc.c file:0 ins:0 del:0} {|i,a| + let col = if ($i.col | str starts-with 'file') { + 'file' + } else { + $i.col | str substring ',3' + } + let num = ($i.num | into int) + $a | upsert $col $num + } + ) + $acc | upsert r ($acc.r | append $x) + } + } + | get r + } +} + +export def _git_log [v num] { + let stat = if $v { + _git_stat $num + } else { {} } + let r = do -i { + git log -n $num --pretty=%h»¦«%s»¦«%aN»¦«%aE»¦«%aD + | lines + | split column "»¦«" sha message author email date + | each {|x| ($x| upsert date ($x.date | into datetime))} + } + if $v { + $r | merge { $stat } | reverse + } else { + $r | reverse + } +} + +def "nu-complete git log" [] { + git log -n 32 --pretty=%h»¦«%s + | lines + | split column "»¦«" value description +} + +export def glg [ + commit?: string@"nu-complete git log" + --verbose(-v):bool + --num(-n):int=32 +] { + if ($commit|is-empty) { + _git_log $verbose $num + } else { + git log --stat -p -n 1 $commit + } +} + +export def glgv [ + commit?: string@"nu-complete git log" + --num(-n):int=32 +] { + if ($commit|is-empty) { + _git_log true $num + } else { + git log --stat -p -n 1 $commit + } +} + +export def gpp! [] { + git add --all + git commit -v -a --no-edit --amend + git push --force +} + +export def gha [] { + git log --pretty=%h»¦«%aN»¦«%s»¦«%aD + | lines + | split column "»¦«" sha1 committer desc merged_at + | histogram committer merger + | sort-by merger + | reverse +} + +export def gsq [] { + git reflog expire --all --expire=now + git gc --prune=now --aggressive +} + +def "nu-complete git branches" [] { + ^git branch | lines | each { |line| $line | str replace '[\*\+] ' '' | str trim } +} + +def "nu-complete git remotes" [] { + ^git remote | lines | each { |line| $line | str trim } +} + +export def gm [branch:string@"nu-complete git branches"] { + git merge $branch +} + +extern "git reset" [ + sha?:string@"nu-complete git log" + --hard:bool +] + +export alias gp = git push +export alias gpf! = git push --force +export alias gl = git pull +export alias ga = git add +export alias gaa = git add --all +export alias gapa = git add --patch +export alias gau = git add --update +export alias gav = git add --verbose +export alias gap = git apply +export alias gapt = git apply --3way + +export alias gb = git branch +export alias gba = git branch -a +export alias gbd = git branch -d +export alias gbda = 'git branch --no-color --merged | command grep -vE "^(\+|\*|\s*($(git_main_branch)|development|develop|devel|dev)\s*$)" | command xargs -n 1 git branch -d' +export alias gbD = git branch -D +export alias gbl = git blame -b -w +export alias gbnm = git branch --no-merged +export alias gbr = git branch --remote +export alias gbs = git bisect +export alias gbsb = git bisect bad +export alias gbsg = git bisect good +export alias gbsr = git bisect reset +export alias gbss = git bisect start + +export alias gc = git commit -v +export alias gc! = git commit -v --amend +export alias gcn! = git commit -v --no-edit --amend +export alias gca = git commit -v -a +export alias gca! = git commit -v -a --amend +export alias gcan! = git commit -v -a --no-edit --amend +export alias gcans! = git commit -v -a -s --no-edit --amend +export alias gcam = git commit -a -m +export alias gcsm = git commit -s -m +export alias gcb = ^git checkout -b +export alias gcf = git config --list +export alias gcl = git clone --recurse-submodules +export alias gclean = git clean -id +# export alias gpristine = git reset --hard && git clean -dffx +export alias gcm = git checkout (git_main_branch) +export alias gcd = git checkout develop +export alias gcmsg = git commit -m +export alias gco = git checkout +export alias gcount = git shortlog -sn +export alias gcp = git cherry-pick +export alias gcpa = git cherry-pick --abort +export alias gcpc = git cherry-pick --continue +export alias gcs = git commit -S + +export alias gd = git diff +export alias gdca = git diff --cached +export alias gdcw = git diff --cached --word-diff +export alias gdct = git describe --tags (git rev-list --tags --max-count=1) +export alias gds = git diff --staged +export alias gdt = git diff-tree --no-commit-id --name-only -r +export alias gdw = git diff --word-diff + +export alias gr = git remote +export alias gra = git remote add +export alias grb = git rebase +export alias grba = git rebase --abort +export alias grbc = git rebase --continue +export alias grbd = git rebase develop +export alias grbi = git rebase -i +export alias grbm = git rebase (git_main_branch) +export alias grbo = git rebase --onto +export alias grbs = git rebase --skip +export alias grev = git revert +export alias grh = git reset +export alias grhh = git reset --hard +export alias groh = git reset origin/$(git_current_branch) --hard +export alias grm = git rm +export alias grmc = git rm --cached +export alias grmv = git remote rename +export alias grrm = git remote remove +export alias grs = git restore +export alias grset = git remote set-url +export alias grss = git restore --source +export alias grst = git restore --staged +export alias grt = cd "$(git rev-parse --show-toplevel || echo .)" +# export alias gru = git reset -- +export alias grup = git remote update +export alias grv = git remote -v + +export alias gsb = git status -sb +export alias gsd = git svn dcommit +export alias gsh = git show +export alias gsi = git submodule init +export alias gsps = git show --pretty=short --show-signature +export alias gsr = git svn rebase +export alias gss = git status -s +export alias gs = git status + + +export alias gstaa = git stash apply +export alias gstc = git stash clear +export alias gstd = git stash drop +export alias gstl = git stash list +export alias gstp = git stash pop +export alias gsts = git stash show --text +export alias gstu = gsta --include-untracked +export alias gstall = git stash --all +export alias gsu = git submodule update +export alias gsw = git switch +export alias gswc = git switch -c + +export alias gts = git tag -s + +export alias gunignore = git update-index --no-assume-unchanged +export alias gup = git pull --rebase +export alias gupv = git pull --rebase -v +export alias gupa = git pull --rebase --autostash +export alias gupav = git pull --rebase --autostash -v +export alias glum = git pull upstream (git_main_branch) + +# cat ($nu.config-path | path dirname | path join 'scripts' | path join 'a.nu' ) diff --git a/just/just.nu b/just/just.nu new file mode 100644 index 0000000..f3788d7 --- /dev/null +++ b/just/just.nu @@ -0,0 +1,37 @@ +export def run [...x: any] { + let script = $"($env.PWD)/.nu" + nu $script ...$x +} + +export def "nu-complete just recipes" [] { + ^just --unstable --unsorted --dump --dump-format json + | from json + | get recipes + | transpose k v + | each {|x| + { + value: $x.k, + description: ( $x.v.parameters + | each {|y| $y.name} + | str join ' ' + ) + } + } +} + +export def "nu-complete just args" [context: string, offset: int] { + let r = ($context | split row ' ') + ^just --unstable -u --dump --dump-format json + | from json + | get recipes + | get ($r.1) + | get body + | each {|x| {description: ($x | get 0) }} + | prepend '' + +} + +export extern "just" [ + recipes?: string@"nu-complete just recipes" + ...args: any@"nu-complete just args" +] diff --git a/kubernetes/kubernetes.nu b/kubernetes/kubernetes.nu new file mode 100644 index 0000000..a151e0e --- /dev/null +++ b/kubernetes/kubernetes.nu @@ -0,0 +1,518 @@ +export def 'filter index' [...idx] { + reduce -f [] -n {|it, acc| + if $it.index not-in ($idx|flatten) { + $acc.item | append $it.item + } else { + $acc.item + } + } +} + +export def "parse cmd" [] { + $in + | split row ' ' + | reduce -f { args: [], sw: '' } {|it, acc| + if ($acc.sw|is-empty) { + if ($it|str starts-with '-') { + $acc | upsert sw $it + } else { + let args = ($acc.args | append $it) + $acc | upsert args $args + } + } else { + if ($it|str starts-with '-') { + $acc + | upsert $acc.sw true + | upsert sw $it + } else { + $acc | upsert $acc.sw $it | upsert sw '' + } + } + } + | reject sw +} + +export def index-need-update [index path] { + let ts = do -i { ls $path | sort-by modified | reverse | get 0.modified } + if ($ts | is-empty) { return false } + let tc = do -i { ls $index | get 0.modified } + if not (($index | path exists) and ($ts < $tc)) { + mkdir (dirname $index) + return true + } + return false +} + +export def 'str max-length' [] { + $in | reduce -f 0 {|x, a| + if ($x|is-empty) { return $a } + let l = ($x | str length) + if $l > $a { $l } else { $a } + } +} + +##### +export-env { + let-env KUBERNETES_SCHEMA_URL = $"file:///($env.HOME)/.config/kubernetes-json-schema/all.json" +} + + +### file +export def kaf [p: path] { + kubectl apply -f $p +} + +export def kdf [p: path] { + kubectl diff -f $p +} + +export def kdelf [p: path] { + kubectl delete -f $p +} + +export def kak [p: path] { + kubectl apply -k $p +} + +export def kdk [p: path] { + kubectl diff -k $p +} + +export def kdelk [p: path] { + kubectl delete -k $p +} + +export def kk [p: path] { + kubectl kustomize $p +} + +### ctx +export def "kube-config" [] { + let file = if 'KUBECONFIG' in (env).name { $env.KUBECONFIG } else { $"($env.HOME)/.kube/config" } + { path: $file, data: (cat $file | from yaml)} +} + +def "nu-complete kube ctx" [] { + let k = (kube-config) + let cache = $'($env.HOME)/.cache/nu-complete/k8s/(basename $k.path).json' + if index-need-update $cache $k.path { + let clusters = ($k.data | get clusters | select name cluster.server) + let data = ( $k.data + | get contexts + | reduce -f {completion:[], mx_ns: 0, mx_cl: 0} {|x, a| + let ns = (if ('namespace' in ($x.context|columns)) { $x.context.namespace } else { '' }) + let max_ns = ($ns | str length) + let cluster = ($"($x.context.user)@($clusters | where name == $x.context.cluster | get cluster_server.0)") + let max_cl = ($cluster | str length) + $a + | upsert mx_ns (if $max_ns > $a.mx_ns { $max_ns } else $a.mx_ns) + | upsert mx_cl (if $max_cl > $a.mx_cl { $max_cl } else $a.mx_cl) + | upsert completion ($a.completion | append {value: $x.name, ns: $ns, cluster: $cluster}) + }) + {completion: $data.completion, max: {ns: $data.mx_ns, cluster: $data.mx_cl}} | save $cache + } + + let data = (cat $cache | from json) + $data.completion | each {|x| + let ns = ($x.ns | str rpad -l $data.max.ns -c ' ') + let cl = ($x.cluster | str lpad -l $data.max.cluster -c ' ') + {value: $x.value, description: $"\t($ns) ($cl)"} + } +} + +def "nu-complete kube ns" [] { + kubectl get namespaces + | from ssv -a + | each {|x| + {value: $x.NAME, description: $"($x.AGE)\t($x.STATUS)"} + } +} + +export def kcc [ctx: string@"nu-complete kube ctx"] { + kubectl config use-context $ctx +} + +export def kn [ns: string@"nu-complete kube ns"] { + kubectl config set-context --current $"--namespace=($ns)" +} + +export def 'kconf import' [name: string, path: string] { + let k = (kube-config) + let d = $k.data + let i = (cat $path | from yaml) + let c = [{ + name: $name, + context: { + cluster: $name, + namespace: default, + user: $name + } + }] + $d + | upsert clusters ($d.clusters | append ($i.clusters.0 | upsert name $name)) + | upsert users ($d.users | append ($i.users.0 | upsert name $name)) + | upsert contexts ($d.contexts | append $c) + | to yaml +} + +export def 'kconf export' [name: string@"nu-complete kube ctx"] { + let d = (kube-config).data + let ctx = ($d | get contexts | where name == $name | get 0) + let user = ($d | get users | where name == $ctx.context.user) + let cluster = ($d | get clusters | where name == $ctx.context.cluster) + { + apiVersion: 'v1', + current-context: $ctx.name, + kind: Config, + clusters: $cluster, + preferences: {}, + contexts: [$ctx], + users: $user, + } | to yaml +} + +export def-env kcconf [name: string@"nu-complete kube ctx"] { + let dist = $"($env.HOME)/.kube/config.d" + mkdir $dist + kconf export $name | save -r $"($dist)/($name)" + let-env KUBECONFIG = $"($dist)/($name)" +} + +### common +def "nu-complete kube def" [] { + [ + pod deployment svc endpoints + configmap secret event + namespace node pv pvc ingress + job cronjob daemonset statefulset + clusterrole clusterrolebinding role serviceaccount rolebinding + ] | append (kubectl get crd | from ssv -a | get NAME) +} + +def "nu-complete kube res" [context: string, offset: int] { + let ctx = ($context | parse cmd) + let def = ($ctx | get args | get 1) + let ns = do -i { $ctx | get '-n' } + let ns = if ($ns|is-empty) { [] } else { [-n $ns] } + kubectl get $ns $def | from ssv -a | get NAME +} + +export def kg [ + r: string@"nu-complete kube def" + -n: string@"nu-complete kube ns" + --all (-A):bool +] { + let n = if $all { + [-A] + } else if ($n | is-empty) { + [] + } else { + [-n $n] + } + #let h = ($d | columns | str kebab-case) + #$d | rename ...$h + kubectl get $n $r | from ssv -a +} + +export def kc [ + r: string@"nu-complete kube def" + -n: string@"nu-complete kube ns" + name:string +] { + let n = if ($n|is-empty) { [] } else { [-n $n] } + kubectl create $n $r $name +} + +export def ky [ + r: string@"nu-complete kube def" + i: string@"nu-complete kube res" + -n: string@"nu-complete kube ns" +] { + let n = if ($n|is-empty) { [] } else { [-n $n] } + kubectl get $n -o yaml $r $i +} + +export def kd [ + r: string@"nu-complete kube def" + i: string@"nu-complete kube res" + -n: string@"nu-complete kube ns" +] { + let n = if ($n|is-empty) { [] } else { [-n $n] } + kubectl describe $n $r $i +} + +export def ke [ + r: string@"nu-complete kube def" + i: string@"nu-complete kube res" + -n: string@"nu-complete kube ns" +] { + let n = if ($n|is-empty) { [] } else { [-n $n] } + kubectl edit $n $r $i +} + +export def kdel [ + r: string@"nu-complete kube def" + i: string@"nu-complete kube res" + -n: string@"nu-complete kube ns" + --force(-f): bool +] { + let n = if ($n|is-empty) { [] } else { [-n $n] } + let f = if $force { [--grace-period=0 --force] } else { [] } + kubectl delete $n $f $r $i +} + + +### node +export def kgno [] { + kubectl get nodes -o wide | from ssv -a + | rename name status roles age version internal-ip external-ip os kernel runtime +} + +### pods +def "nu-complete kube pods" [context: string, offset: int] { + let ctx = ($context | parse cmd) + let ns = do -i { $ctx | get '-n' } + let ns = if ($ns|is-empty) { [] } else { [-n $ns] } + kubectl get $ns pods | from ssv -a | get NAME +} + +def "nu-complete kube ctns" [context: string, offset: int] { + let ctx = ($context | parse cmd) + let ns = do -i { $ctx | get '-n' } + let ns = if ($ns|is-empty) { [] } else { [-n $ns] } + let ctn = do -i { $ctx | get '-c' } + let ctn = if ($ctn|is-empty) { [] } else { [-c $ctn] } + let pod = ($ctx | get args.1) + kubectl get $ns pod $pod -o jsonpath={.spec.containers[*].name} | split row ' ' +} + +export def kgpl [] { + kubectl get pods -o json + | from json + | get items + | each {|x| + let rs = $x.status.containerStatuses.0.restartCount + { + namespace: $x.metadata.namespace, + name: $x.metadata.name, + status: $x.status.phase, + restarts: ($rs | split row ' '| get 0 | into int), + age: ($x.status.startTime | into datetime) + }} +} + +export def kgpa [] { + kubectl get pods -o wide -A | from ssv -a + | rename namespace name ready status restarts age ip node + | each {|x| ($x| upsert restarts ($x.restarts|split row ' '| get 0 | into int)) } + | reject 'NOMINATED NODE' 'READINESS GATES' +} + +export def kgp [-n: string@"nu-complete kube ns"] { + let n = if ($n|is-empty) { [] } else { [-n $n] } + kubectl get pods $n -o wide | from ssv -a + | rename name ready status restarts age ip node + | each {|x| ($x| upsert restarts ($x.restarts|split row ' '| get 0 | into int)) } + | reject 'NOMINATED NODE' 'READINESS GATES' +} + +export def kgpw [] { + kubectl get pods --watch +} + +export def kep [-n: string@"nu-complete kube ns", pod: string@"nu-complete kube pods"] { + let n = if ($n|is-empty) { [] } else { [-n $n] } + kubectl edit pod $n $pod +} + +export def kdp [-n: string@"nu-complete kube ns", pod: string@"nu-complete kube pods"] { + let n = if ($n|is-empty) { [] } else { [-n $n] } + kubectl describe pod $n $pod +} + +export def ka [ + pod: string@"nu-complete kube pods" + -n: string@"nu-complete kube ns" + --container(-c): string@"nu-complete kube ctns" + ...args +] { + let n = if ($n|is-empty) { [] } else { [-n $n] } + let c = if ($container|is-empty) { [] } else { [-c $container] } + kubectl exec $n -it $pod $c -- (if ($args|is-empty) { 'bash' } else { $args }) +} + +export def kl [ + pod: string@"nu-complete kube pods" + --namespace(-n): string@"nu-complete kube ns" + --container(-c): string@"nu-complete kube ctns" +] { + let n = if ($namespace|is-empty) { [] } else { [-n $namespace] } + let c = if ($container|is-empty) { [] } else { [-c $container] } + kubectl logs $n $pod $c +} + +export def klf [ + pod: string@"nu-complete kube pods" + --namespace(-n): string@"nu-complete kube ns" + --container(-c): string@"nu-complete kube ctns" +] { + let n = if ($namespace|is-empty) { [] } else { [-n $namespace] } + let c = if ($container|is-empty) { [] } else { [-c $container] } + kubectl logs $n -f $pod $c +} + +def "nu-complete port forward type" [] { + [pod svc] +} +export def kpf [ + res: string@"nu-complete port forward type" + target: string@"nu-complete kube res" + -n: string@"nu-complete kube ns" + port: string ### reflect port num +] { + let n = if ($n|is-empty) { [] } else { [-n $n] } + kubectl port-forward $n $"($res)/($target)" $port +} + +export def kcp [ + lhs: string@"nu-complete kube pods" + rhs: string@"nu-complete kube pods" + -n: string@"nu-complete kube ns" +] { + let n = if ($n|is-empty) { [] } else { [-n $n] } + kubectl cp $n $lhs $rhs +} + +### service +def "nu-complete kube service" [context: string, offset: int] { + let ctx = ($context | parse cmd) + let ns = do -i { $ctx | get '-n' } + let ns = if ($ns|is-empty) { [] } else { [-n $ns] } + kubectl get $ns services | from ssv -a | get NAME +} + +export def kgs [-n: string@"nu-complete kube ns"] { + let n = if ($n|is-empty) { [] } else { [-n $n] } + kubectl get $n services | from ssv -a + | rename name type cluster-ip external-ip ports age selector +} + +export def kes [svc: string@"nu-complete kube service", -n: string@"nu-complete kube ns"] { + let n = if ($n|is-empty) { [] } else { [-n $n] } + kubectl edit $n service $svc +} + +export def kdels [svc: string@"nu-complete kube service", -n: string@"nu-complete kube ns"] { + let n = if ($n|is-empty) { [] } else { [-n $n] } + kubectl delete $n service $svc +} + +### deployments +def "nu-complete kube deployments" [context: string, offset: int] { + let ctx = ($context | parse cmd) + let ns = do -i { $ctx | get '-n' } + let ns = if ($ns|is-empty) { [] } else { [-n $ns] } + kubectl get $ns deployments | from ssv -a | get NAME +} + +export def kgd [-n: string@"nu-complete kube ns"] { + let n = if ($n|is-empty) { [] } else { [-n $n] } + kubectl get $n deployments -o wide | from ssv -a + | rename name ready up-to-date available age containers images selector + | reject selector +} + +export def ked [d: string@"nu-complete kube deployments", -n: string@"nu-complete kube ns"] { + let n = if ($n|is-empty) { [] } else { [-n $n] } + kubectl edit $n deployments $d +} + +def "nu-complete num9" [] { [1 2 3] } +export def ksd [ + d: string@"nu-complete kube deployments" + num: int@"nu-complete num9" + -n: string@"nu-complete kube ns" +] { + if $num > 9 { + "too large" + } else { + let n = if ($n|is-empty) { [] } else { [-n $n] } + kubectl scale $n deployments $d --replicas $num + } +} + +export alias krsd = kubectl rollout status deployment +export alias kgrs = kubectl get rs +export def krh [-n: string@"nu-complete kube ns", --revision (-v): int, dpl: string@"nu-complete kube deployments"] { + let n = if ($n|is-empty) { [] } else { [-n $n] } + let v = if ($revision|is-empty) { [] } else { [ $"--revision=($revision)" ] } + kubectl $n rollout history $"deployment/($dpl)" $v +} +export def kru [-n: string@"nu-complete kube ns", --revision (-v): int, dpl: string@"nu-complete kube deployments"] { + let n = if ($n|is-empty) { [] } else { [-n $n] } + let v = if ($revision|is-empty) { [] } else { [ $"--to-revision=($revision)" ] } + kubectl $n rollout undo $"deployment/($dpl)" $v +} +export alias ksss = kubectl scale statefulset +export alias krsss = kubectl rollout status statefulset + +### kubecto top pod +export def ktp [-n: string@"nu-complete kube ns"] { + let n = if ($n|is-empty) { [] } else { [-n $n] } + kubectl top pod $n | from ssv -a | rename name cpu mem + | each {|x| { + name: $x.name + cpu: ($x.cpu| str substring ',-1' | into decimal) + mem: ($x.mem | str substring ',-2' | into decimal) + } } +} + +export def ktpa [] { + kubectl top pod -A | from ssv -a | rename namespace name cpu mem + | each {|x| { + namespace: $x.namespace + name: $x.name + cpu: ($x.cpu| str substring ',-1' | into decimal) + mem: ($x.mem | str substring ',-2' | into decimal) + } } +} + +### kube top node +export def ktn [] { + kubectl top node | from ssv -a | rename name cpu pcpu mem pmem + | each {|x| { + name: $x.name + cpu: ($x.cpu| str substring ',-1' | into decimal) + cpu%: (($x.pcpu| str substring ',-1' | into decimal) / 100) + mem: ($x.mem | str substring ',-2' | into decimal) + mem%: (($x.pmem | str substring ',-1' | into decimal) / 100) + } } +} + +### +export def "kclean evicted" [] { + kubectl get pods -A + | from ssv -a + | where STATUS == Evicted + | each { |x| kdel pod -n $x.NAMESPACE $x.NAME } +} + +### fixme: +export def "kclean stucked ns" [ns: string] { + kubectl get namespace $ns -o json \ + | tr -d "\n" + | sed 's/\"finalizers\": \[[^]]\+\]/\"finalizers\": []/' \ + | kubectl replace --raw /api/v1/namespaces/$1/finalize -f - +} + +export alias "kclean finalizer" = kubectl patch -p '{\"metadata\":{\"finalizers\":null}}' + +export alias "kadm renew" = kubeadm alpha certs renew all + +### cert-manager +export def kgcert [] { + kubectl get certificates -o wide | from ssv | rename certificates + kubectl get certificaterequests -o wide | from ssv | rename certificaterequests + kubectl get order.acme -o wide | from ssv | rename order.acme + kubectl get challenges.acme -o wide | from ssv | rename challenges.acme +} diff --git a/nvim/nvim.nu b/nvim/nvim.nu new file mode 100644 index 0000000..b406fef --- /dev/null +++ b/nvim/nvim.nu @@ -0,0 +1,102 @@ +def nvim_tcd [] { + [ + {|before, after| + if 'NVIM' in (env).name { + nvim --headless --noplugin --server $env.NVIM --remote-send $"lua HookPwdChanged\('($after)', '($before)')" + } + } + ] +} + +export-env { + let-env config = ( $env.config | upsert hooks.env_change.PWD { |config| + let o = ($config | get -i hooks.env_change.PWD) + let val = (nvim_tcd) + if $o == $nothing { + $val + } else { + $o | append $val + } + }) +} + +def edit [action file] { + if 'NVIM' in (env).name { + let af = ($file | each {|f| + if ($f|str substring ',1') in ['/', '~'] { + $f + } else { + $"($env.PWD)/($f)" + } + }) + let cmd = $"($action) ($af|str join ' ')" + nvim --headless --noplugin --server $env.NVIM --remote-send $cmd + } else { + nvim $file + } +} + +export def tcd [path?: string] { + let after = if ($path|is-empty) { + $env.PWD + } else { + $path + } + nvim --headless --noplugin --server $env.NVIM --remote-send $"lua HookPwdChanged\('($after)', '($env.PWD)')" +} + +export def e [...file: string] { + if ($file|is-empty) { + nvim + } else { + edit vsplit $file + } +} + +export def c [...file: string] { + if ($file|is-empty) { + nvim + } else { + edit split $file + } +} + +export def v [...file: string] { + if ($file|is-empty) { + nvim + } else { + edit vsplit $file + } +} + +export def x [...file: string] { + if ($file|is-empty) { + nvim + } else { + edit tabnew $file + } +} + +export def drop [] { + if 'NVIM' in (env).name { + let c = $in + let temp = (mktemp -t nuvim.XXXXXXXX|str trim) + $c | save $temp + nvim --headless --noplugin --server $env.NVIM --remote-send $"lua ReadTempDrop\('($temp)')" + } else { + echo $in + } +} + +export def nvim_lua [...expr: string] { + if 'NVIM' in (env).name { + nvim --headless --noplugin --server $env.NVIM --remote-send $'lua vim.g.remote_expr_lua = ($expr|str join " ")' + do -i { nvim --headless --noplugin --server $env.NVIM --remote-expr 'g:remote_expr_lua' } | complete | get stderr + } else { + echo "not found nvim instance" + } +} + +export def opwd [] { + nvim_lua 'OppositePwd()' +} diff --git a/ssh/ssh.nu b/ssh/ssh.nu new file mode 100644 index 0000000..c98f52d --- /dev/null +++ b/ssh/ssh.nu @@ -0,0 +1,98 @@ +export def index-need-update [index path] { + let ts = do -i { ls $path | sort-by modified | reverse | get 0.modified } + if ($ts | is-empty) { return false } + let tc = do -i { ls $index | get 0.modified } + if not (($index | path exists) and ($ts < $tc)) { + mkdir (dirname $index) + return true + } + return false +} + +export def 'str max-length' [] { + $in | reduce -f 0 {|x, a| + if ($x|is-empty) { return $a } + let l = ($x | str length) + if $l > $a { $l } else { $a } + } +} + +def "nu-complete ssh host" [] { + rg -LNI '^Host [a-z0-9_\-\.]+' ~/.ssh | lines | each {|x| $x | split row ' '| get 1} +} + +export def parse-ssh-file [group] { + $in + | parse -r '(?PHost|HostName|User|Port|IdentityFile)\s+(?P.+)' + | append { k: Host, v: null} + | reduce -f { rst: [], item: {Host: null} } {|it, acc| + if $it.k == 'Host' { + $acc | upsert rst ($acc.rst | append $acc.item) + | upsert item { Host : $it.v, HostName: null, Port: null, User: null, IdentityFile: null, Group: $group } + } else { + $acc | upsert item ($acc.item | upsert $it.k $it.v) + } + } + | get rst + | where {|x| not (($x.Host | is-empty) or $x.Host =~ '\*')} +} + +export def ssh-list [] { + rg -L -l 'Host' ~/.ssh + | lines + | each {|x| cat $x | parse-ssh-file $x} + | flatten +} + +def fmt-group [p] { + $p | str replace $"($env.HOME)/.ssh/" '' +} + +def "nu-complete ssh" [] { + let cache = $'($env.HOME)/.cache/nu-complete/ssh.json' + if index-need-update $cache ~/.ssh/**/* { + let data = (ssh-list | each {|x| + let uri = $"($x.User)@($x.HostName):($x.Port)" + { + value: $x.Host, + uri: $uri, + group: $"(fmt-group $x.Group)", + identfile: $"($x.IdentityFile)", + } + }) + + let max = { + value: ($data.value | str max-length), + uri: ($data.uri | str max-length), + group: ($data.group | str max-length), + identfile: ($data.identfile | str max-length), + } + + {max: $max, completion: $data} | save $cache + } + + let data = (cat $cache | from json) + + $data.completion + | each { |x| + let uri = ($x.uri | str lpad -l $data.max.uri -c ' ') + let group = ($x.group | str rpad -l $data.max.group -c ' ') + let id = ($x.identfile | str rpad -l $data.max.identfile -c ' ') + {value: $x.value, description: $"\t($uri) ($group) ($id)" } + } +} + +export extern ssh [ + host: string@"nu-complete ssh" # host + ...cmd # cmd + -v # verbose + -i: string # key + -p: int # port + -N # n + -T # t + -L # l + -R # r + -D # d + -J: string # j + -W: string # w +]