mirror of
https://github.com/RGBCube/nu_scripts
synced 2025-08-01 22:57:46 +00:00
refactor: ✨ (#418)
* refactor: ✨ move in one commit Eveything in modules should probably be changed to `exported` defs. The idea is to move everything first to keep proper history. * refactor: 📝 add modules readme (wip) * refactor: ✨ small move * refactor: 📝 changed nestring, updated modules readme * refactor: 📝 to document or not to document * fix: 🐛 themes replaced the template to use `main` and regenerated them from lemnos themes. * Revert "fix: 🐛 themes" This reverts commit 4918d3633c8d2d81950a0ed0cfd9eb84241bc886. * refactor: ✨ introduce sourced - Created a source `root` in which sourcable demos are stored. Some might get converted to modules later on. - Moved some files to bin too. * fix: 🐛 fehbg.nu * fix: 🐛 modules/after.nu * moved some other stuff around --------- Co-authored-by: Darren Schroeder <343840+fdncred@users.noreply.github.com>
This commit is contained in:
parent
382696cd21
commit
c47ccd42b8
128 changed files with 185 additions and 12 deletions
46
modules/network/remoting/README.md
Normal file
46
modules/network/remoting/README.md
Normal file
|
@ -0,0 +1,46 @@
|
|||
# Remoting
|
||||
This module provide convenient way to manage multiple remote clients.
|
||||
|
||||
## Prerequisites
|
||||
* Both `ssh` and `ssh script` require ssh to be installed on the host
|
||||
* `ssh script` requires nushell to be installed on the client
|
||||
* `ssh` can work both with and without nushell installed on the client however having it installed enables more sophisticated interaction between host and clients
|
||||
* `wake` requires wakeonlan to be installed on the host and clients to be configured to accept Wake on Lan magic packets
|
||||
|
||||
## `ssh` function
|
||||
This function serves as a wrapper around standard ssh command.
|
||||
|
||||
Function accepts following arguments:
|
||||
* name - Name of the client as specified in the config. This parameter is required (autocompletion enabled)
|
||||
* args - command to run on the client. If not provided ssh starts an interactive session with the client. If provided and specified client has nushell configured output will be returned as nushell table on the host allowing further parsing. If provided and specified client does not have nushell configured output will be passed back as is
|
||||
## `ssh script` function
|
||||
This function executes a nushell script on a client that has nushell configured.
|
||||
|
||||
Function accepts following arguments:
|
||||
* name - Name of the client as specified in the config. This parameter is required (autocompletion enabled)
|
||||
* script - Name of the script to be executed on the client. This parameter is required The script must be available in current scope in order to be used (autocompletion enabled)
|
||||
* args - Arguments to be passed to the script. Named parameters should be put in quotes to avoid parsing errors like this: `ssh script my-host my-script '--arg value'`
|
||||
|
||||
## `wake` function
|
||||
This function wakes specified clients via Wake on Lan.
|
||||
|
||||
Function accepts following arguments:
|
||||
* names - Name of clients to be woken up as specified in the config. (autocompletion enabled)
|
||||
|
||||
|
||||
## Config
|
||||
Client config is kept within (non-exported) `hosts` function as a list of records. Each record should contain following fields:
|
||||
|
||||
| Parameter | Is required? | Usage | Type |
|
||||
|-----------|----------------------------------------|------------------------------|--------|
|
||||
| name | Required | DNS name of the client | string |
|
||||
| domain | Either domain or IP must be specified | DNS domain of the client | string |
|
||||
| ip | Either domain or IP must be specified | IP address of the client | string |
|
||||
| username | Required | Username used for connection | string |
|
||||
| port | Required | SSH port | int |
|
||||
| mac | Required only for `wake` | MAC address of the client | string |
|
||||
| nu | Required | Whether nushell is installed | bool |
|
||||
|
||||
Example configuration records:
|
||||
* {name: 'host1', domain: 'nushell.sh', ip: '', username: 'username', port: 22, mac: 'AA:BB:CC:DD:EE;FF', nu: false}
|
||||
* {name: 'host2', domain: '', ip: '192.168.0.1', username: 'username', port: 2222, mac: '', nu: true}
|
98
modules/network/remoting/remoting.nu
Normal file
98
modules/network/remoting/remoting.nu
Normal file
|
@ -0,0 +1,98 @@
|
|||
# internal function that holds the host data. We could store it in a yaml file as well but that would require nushell to read it from disk every single time
|
||||
def hosts [] {
|
||||
[
|
||||
# Put your config here
|
||||
]
|
||||
}
|
||||
def "nu-complete wol" [] {
|
||||
hosts
|
||||
|where mac != ''
|
||||
|get name
|
||||
}
|
||||
|
||||
def "nu-complete nu" [] {
|
||||
hosts
|
||||
|where nu
|
||||
|get name
|
||||
}
|
||||
|
||||
def "nu-complete hosts" [] {
|
||||
hosts
|
||||
|get name
|
||||
}
|
||||
|
||||
def "nu-complete scripts" [] {
|
||||
$nu.scope.commands
|
||||
|where is_custom
|
||||
|get -i command
|
||||
}
|
||||
|
||||
# Returns ssh connection as url to be consumed by original ssh command
|
||||
def get-url [
|
||||
host: record
|
||||
] {
|
||||
if 'ip' in ($host|columns) {
|
||||
echo $"ssh://($host.username)@($host.ip):($host.port)"
|
||||
} else {
|
||||
echo $"ssh://($host.username)@($host.name).($host.domain):($host.port)"
|
||||
}
|
||||
}
|
||||
|
||||
# Connect over ssh to one of predefined hosts, execute nushell commands and parse them on the host
|
||||
export def ssh [
|
||||
hostname: string@"nu-complete hosts" # name of the host you want to connect to
|
||||
...args # commands you wish to run on the host
|
||||
] {
|
||||
let host = (hosts|where name == $hostname|get -i 0)
|
||||
if ($host.nu) {
|
||||
if ($args|length) > 0 {
|
||||
^ssh (get-url $host) (build-string ($args|str join ' ') '|to json -r')|from json
|
||||
} else {
|
||||
^ssh (get-url $host)
|
||||
}
|
||||
} else {
|
||||
^ssh (get-url $host) $args
|
||||
}
|
||||
}
|
||||
|
||||
# Connect over ssh to one of predefined hosts, execute nushell script with arguments passed from the host
|
||||
export def "ssh script" [
|
||||
hostname: string@"nu-complete nu" # name of the host you want to connect to
|
||||
script: string@"nu-complete scripts" # name of the script
|
||||
...args # arguments you wish to pass to the script in key=value format
|
||||
] {
|
||||
let span = (metadata $script).span
|
||||
if $script in ($nu.scope.commands|where is_custom|get command) {
|
||||
|
||||
let host = (hosts|where name == $hostname|get 0)
|
||||
let full_command = (build-string (view-source $script) '; ' $script ' ' ($args|str join ' ') '|to json -r')
|
||||
^ssh (get-url $host) ($full_command)|from json
|
||||
|
||||
} else {
|
||||
error make {
|
||||
msg: $"($script) is not a custom command, use regular ssh command instead"
|
||||
label: {
|
||||
text: "Not a custom command",
|
||||
start: $span.start,
|
||||
end: $span.end
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
# Turns on specified hosts using Wake on Lan
|
||||
export def wake [
|
||||
...names: string@"nu-complete wol" # list of host names to wake
|
||||
] {
|
||||
hosts
|
||||
|where name in $names
|
||||
|each {|host|
|
||||
if $host.mac != '' {
|
||||
echo $"Waking ($host.name)"
|
||||
wakeonlan $host.mac|ignore
|
||||
} else {
|
||||
error make {
|
||||
msg: $"($host.name) does not support Wake on Lan"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
4
modules/network/sockets/README.md
Normal file
4
modules/network/sockets/README.md
Normal file
|
@ -0,0 +1,4 @@
|
|||
The `sockets` command returns a table containing information on network sockets and the processes they belong to.
|
||||
It is basically a join of the tables produced by the `lsof` command, and the nushell `ps` command.
|
||||
|
||||
<img width="1486" alt="image" src="https://user-images.githubusercontent.com/52205/196287615-00e46f8e-06ed-45ce-8fe7-a5c5f38afaaa.png">
|
32
modules/network/sockets/sockets.nu
Normal file
32
modules/network/sockets/sockets.nu
Normal file
|
@ -0,0 +1,32 @@
|
|||
export def sockets [--abbreviate-java-class-paths (-j)] {
|
||||
let input = (^lsof +c 0xFFFF -i -n -P)
|
||||
let header = ($input | lines
|
||||
| take 1
|
||||
| each { str downcase | str replace ' name$' ' name state' })
|
||||
let body = ($input | lines
|
||||
| skip 1
|
||||
| each { str replace '([^)])$' '$1 (NONE)' | str replace ' \((.+)\)$' ' $1' })
|
||||
[$header] | append $body
|
||||
| to text
|
||||
| detect columns
|
||||
| upsert 'pid' { |r| $r.pid | into int }
|
||||
| rename -c ['name' 'connection']
|
||||
| reject 'command'
|
||||
| join-table (ps -l) 'pid' 'pid'
|
||||
| if $abbreviate_java_class_paths {
|
||||
upsert 'classpath' { |r| $r.command | java-cmd classpath }
|
||||
| upsert 'command' { |r| $r.command | java-cmd abbreviate-classpath }
|
||||
} else { $in }
|
||||
}
|
||||
|
||||
export def 'java-cmd classpath' [] {
|
||||
str replace '.* -classpath +(.+\.jar) +.*' '$1' | split row ':'
|
||||
}
|
||||
|
||||
export def 'java-cmd abbreviate-classpath' [] {
|
||||
str replace '[^ ]*\.jar' '*.jar'
|
||||
}
|
||||
|
||||
export def join-table [table: table, left_on: string, right_on: string] {
|
||||
into df | join ($table | into df) $left_on $right_on | into nu
|
||||
}
|
128
modules/network/ssh.nu
Normal file
128
modules/network/ssh.nu
Normal file
|
@ -0,0 +1,128 @@
|
|||
export def ensure-index [index path action] {
|
||||
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)
|
||||
do $action
|
||||
}
|
||||
}
|
||||
|
||||
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 '(?P<k>Host|HostName|User|Port|IdentityFile)\s+(?P<v>.+)'
|
||||
| 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 "ssh-hosts" [] {
|
||||
let cache = $'($env.HOME)/.cache/nu-complete/ssh.json'
|
||||
ensure-index $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 -f $cache
|
||||
}
|
||||
|
||||
cat $cache | from json
|
||||
}
|
||||
|
||||
def "nu-complete ssh" [] {
|
||||
let data = (ssh-hosts)
|
||||
$data.completion
|
||||
| each { |x|
|
||||
let uri = ($x.uri | fill -a l -w $data.max.uri -c ' ')
|
||||
let group = ($x.group | fill -a l -w $data.max.group -c ' ')
|
||||
let id = ($x.identfile | fill -a l -w $data.max.identfile -c ' ')
|
||||
{value: $x.value, description: $"\t($uri) ($group) ($id)" }
|
||||
}
|
||||
}
|
||||
|
||||
export extern main [
|
||||
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
|
||||
]
|
||||
|
||||
|
||||
def "nu-complete scp" [cmd: string, offset: int] {
|
||||
let argv = ($cmd | str substring ..$offset | split row ' ')
|
||||
let p = if ($argv | length) > 2 { $argv | get 2 } else { $argv | get 1 }
|
||||
let ssh = (ssh-hosts | get completion
|
||||
| each {|x| {value: $"($x.value):" description: $x.uri} }
|
||||
)
|
||||
let n = ($p | split row ':')
|
||||
if $"($n | get 0):" in ($ssh | get value) {
|
||||
^ssh ($n | get 0) $"sh -c 'ls -dp ($n | get 1)*'"
|
||||
| lines
|
||||
| each {|x| $"($n | get 0):($x)"}
|
||||
} else {
|
||||
let files = (do -i {
|
||||
ls -a $"($p)*"
|
||||
| each {|x| if $x.type == dir { $"($x.name)/"} else { $x.name }}
|
||||
})
|
||||
$files | append $ssh
|
||||
}
|
||||
}
|
||||
|
||||
export def scp [
|
||||
lhs: string@"nu-complete scp",
|
||||
rhs: string@"nu-complete scp"
|
||||
] {
|
||||
^scp -r $lhs $rhs
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue