1
Fork 0
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:
Mel Massadian 2023-04-26 00:56:25 +02:00 committed by GitHub
parent 382696cd21
commit c47ccd42b8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
128 changed files with 185 additions and 12 deletions

View 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}

View 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"
}
}
}
}

View 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">

View 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
View 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
}