diff --git a/sh/.shellcheckrc b/.shellcheckrc similarity index 100% rename from sh/.shellcheckrc rename to .shellcheckrc diff --git a/pyproject.toml b/pyproject.toml index 1d231ec..7a3d9c9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -18,7 +18,7 @@ dependencies = [] description = "Read Write eXecute" dynamic = ["version"] keywords = [] -license-files = { paths = ["license.md"] } +license-files = ["license.md"] name = "rwx" readme = "readme.md" requires-python = ">= 3.11" @@ -30,16 +30,3 @@ requires-python = ">= 3.11" [tool.hatch.version] path = "rwx/__init__.py" - -[tool.pydoclint] -allow-init-docstring = true -quiet = true -skip-checking-short-docstrings = false -style = "sphinx" - -[tool.ruff] -line-length = 80 - -[tool.ruff.lint] -ignore = ["COM812", "D203", "D213", "ISC001"] -select = ["ALL"] diff --git a/rwx/fs/__init__.py b/rwx/fs/__init__.py index 0772a8d..8a45288 100644 --- a/rwx/fs/__init__.py +++ b/rwx/fs/__init__.py @@ -2,9 +2,10 @@ import os import shutil -import tomllib from pathlib import Path +import tomllib + from rwx import ps CHARSET = "UTF-8" @@ -61,7 +62,7 @@ def get_path_mount(path: Path) -> Path: "stat", ("--format", "%m"), str(path), - ) + ), ) diff --git a/rwx/grub/__init__.py b/rwx/grub/__init__.py index 572b13e..aa208c3 100644 --- a/rwx/grub/__init__.py +++ b/rwx/grub/__init__.py @@ -1,5 +1,7 @@ """Wrap GRUB commands.""" +from __future__ import annotations + from rwx import cmd, ps cmd.need("grub-mkimage") diff --git a/rwx/ps/__init__.py b/rwx/ps/__init__.py index 82c9640..3bef50d 100644 --- a/rwx/ps/__init__.py +++ b/rwx/ps/__init__.py @@ -1,5 +1,7 @@ """Handle processes.""" +from __future__ import annotations + import subprocess from rwx import Object, txt @@ -43,7 +45,9 @@ def run(*items: str | tuple[str, ...]) -> subprocess.CompletedProcess: :rtype: subprocess.CompletedProcess """ return subprocess.run( - get_tuples_args(*items), capture_output=False, check=True + get_tuples_args(*items), + capture_output=False, + check=True, ) @@ -61,7 +65,8 @@ def run_line(*items: str | tuple[str, ...], charset: str = txt.CHARSET) -> str: def run_lines( - *items: str | tuple[str, ...], charset: str = txt.CHARSET + *items: str | tuple[str, ...], + charset: str = txt.CHARSET, ) -> list[str]: """Run and return output lines. @@ -72,7 +77,9 @@ def run_lines( :rtype: list[str] """ process = subprocess.run( - get_tuples_args(*items), capture_output=True, check=True + get_tuples_args(*items), + capture_output=True, + check=True, ) string = process.stdout.decode(charset) return string.rstrip().splitlines() diff --git a/sh/alias/git.sh b/sh/alias/git.sh index 6400092..cadd10b 100644 --- a/sh/alias/git.sh +++ b/sh/alias/git.sh @@ -1,4 +1,4 @@ -SH_GIT_LOG_FORMAT="\ +RWX_GIT_LOG_FORMAT="\ %C(auto)%h%d S %C(red)%GS A %C(green)%an %ae @@ -240,11 +240,12 @@ a__git_diff_word() { # fetch from the remote repository gf() { a__git_fetch "${@}"; } a__git_fetch() { - git \ - fetch \ - --tags \ - --verbose \ - "${@}" + rwx_gpg_agent_update && + git \ + fetch \ + --tags \ + --verbose \ + "${@}" } # fetch from remote repository and prune local orphan branches @@ -293,7 +294,7 @@ a__git_log() { log \ --abbrev=8 \ --abbrev-commit \ - --format="${SH_GIT_LOG_FORMAT}" \ + --format="${RWX_GIT_LOG_FORMAT}" \ --graph \ "${@}" } @@ -371,11 +372,12 @@ a__git_merge_tool() { # push to the remote repository gp() { a__git_push "${@}"; } a__git_push() { - git \ - push \ - --tags \ - --verbose \ - "${@}" + rwx_gpg_agent_update && + git \ + push \ + --tags \ + --verbose \ + "${@}" } # delete from the remote repository @@ -533,3 +535,14 @@ a__git_tag_delete() { --delete \ "${@}" } + +# update head ref +gurh() { a__git_update_ref_head "${@}"; } +a__git_update_ref_head() { + if [ -n "${2}" ]; then + git \ + update-ref \ + "refs/heads/${1}" \ + "${2}" + fi +} diff --git a/sh/alias/gpg.sh b/sh/alias/gpg.sh index 496b05e..eb19651 100644 --- a/sh/alias/gpg.sh +++ b/sh/alias/gpg.sh @@ -8,7 +8,5 @@ a__gpg_agent_kill() { # bind gpg agent to current tty gau() { a__gpg_agent_update "${@}"; } a__gpg_agent_update() { - gpg-connect-agent \ - updatestartuptty \ - /bye + rwx_gpg_agent_update } diff --git a/sh/cryptsetup.sh b/sh/cryptsetup.sh new file mode 100644 index 0000000..900083d --- /dev/null +++ b/sh/cryptsetup.sh @@ -0,0 +1,6 @@ +_rwx_cmd_cs() { rwx_crypt_setup "${@}"; } + +rwx_crypt_setup() { + local action="${1}" + echo "cs: ${action}" +} diff --git a/sh/ffmpeg.sh b/sh/ffmpeg.sh new file mode 100644 index 0000000..bcb3a62 --- /dev/null +++ b/sh/ffmpeg.sh @@ -0,0 +1,194 @@ +# ╭────────┬─────────┬───────╮ +# │ ffmpeg │ devices │ reset │ +# ╰────────┴─────────┴───────╯ + +_rwx_cmd_rwx_ffmpeg_devices_reset() { rwx_ffmpeg_devices_reset "${@}"; } +rwx_ffmpeg_devices_reset() { + local module="uvcvideo" + modprobe --remove "${module}" && + modprobe "${module}" +} + +# ╭────────┬────────┬─────────╮ +# │ ffmpeg │ device │ formats │ +# ╰────────┴────────┴─────────╯ + +rwx_ffmpeg_device_formats() { + local device="${1}" + [ -n "${device}" ] || device="/dev/video0" + ffmpeg \ + -f "v4l2" \ + -list_formats "all" \ + -i "${device}" +} + +# ╭────────┬───────╮ +# │ ffmpeg │ input │ +# ╰────────┴───────╯ + +rwx_ffmpeg_input_blue_yeti() { + local device="alsa_input.\ +usb-Generic_Blue_Microphones_2051BAB04XY8-00.analog-stereo" + set -- \ + -f "pulse" \ + -i "${device}" \ + -ac "2" \ + -ar "48000" + local argument + for argument in "${@}"; do echo "${argument}"; done +} + +rwx_ffmpeg_input_dell_precision() { + local device="alsa_input.\ +pci-0000_00_1f.3.analog-stereo" + set -- \ + -f "pulse" \ + -i "${device}" \ + -ac "2" \ + -ar "48000" + local argument + for argument in "${@}"; do echo "${argument}"; done +} + +rwx_ffmpeg_input_file() { + local file="${1}" + local from="${2}" + local to="${3}" + [ -n "${file}" ] || return + set -- \ + -i "${file}" + if [ -n "${to}" ]; then + set -- "${@}" \ + -ss "${from}" \ + -to "${to}" + fi + local argument + for argument in "${@}"; do echo "${argument}"; done +} + +rwx_ffmpeg_input_hdmi() { + local device="${1}" + [ -n "${device}" ] || device="/dev/video0" + set -- \ + -f "v4l2" \ + -video_size "1920x1080" \ + -framerate "60" \ + -input_format "yuyv422" \ + -i "${device}" + local argument + for argument in "${@}"; do echo "${argument}"; done +} + +# ╭────────┬────────╮ +# │ ffmpeg │ output │ +# ╰────────┴────────╯ + +rwx_ffmpeg_output_audio_fast() { + set -- \ + -codec:a "flac" \ + -compression_level "0" + local argument + for argument in "${@}"; do echo "${argument}"; done +} + +rwx_ffmpeg_output_audio_slow() { + set -- \ + -codec:a "libopus" \ + -b:a "128k" + local argument + for argument in "${@}"; do echo "${argument}"; done +} + +rwx_ffmpeg_output_file() { + local file="${1}" + [ -n "${file}" ] || return + set -- \ + -y "${file}" + local argument + for argument in "${@}"; do echo "${argument}"; done +} + +rwx_ffmpeg_output_video_fast() { + set -- \ + -codec:v "libx264" \ + -preset "ultrafast" \ + -crf "0" + local argument + for argument in "${@}"; do echo "${argument}"; done +} + +rwx_ffmpeg_output_video_slow() { + local crf="${1}" + local codec="${2}" + [ -n "${codec}" ] || codec="libx264" + if [ -z "${crm}" ]; then + case "${codec}" in + "libx264") crf="23" ;; + "libx265") crf="28" ;; + *) ;; + esac + fi + set -- \ + -codec:v "${codec}" \ + -preset "veryslow" \ + -crf "${crf}" \ + -movflags "+faststart" \ + -pix_fmt "yuv420p" + local argument + for argument in "${@}"; do echo "${argument}"; done +} + +# ╭────────┬────────╮ +# │ ffmpeg │ record │ +# ╰────────┴────────╯ + +rwx_ffmpeg_record_hdmi_precision() { + local file="${1}" + [ -n "${file}" ] || return + # LATER alternative + # shellcheck disable=SC2046,SC2312 + set -- \ + $(rwx_ffmpeg_input_hdmi) \ + $(rwx_ffmpeg_input_dell_precision) \ + $(rwx_ffmpeg_output_video_fast) \ + $(rwx_ffmpeg_output_audio_fast) \ + $(rwx_ffmpeg_output_file "${file}") + echo "${@}" + ffmpeg "${@}" +} + +rwx_ffmpeg_record_hdmi_yeti() { + local file="${1}" + [ -n "${file}" ] || return + # LATER alternative + # shellcheck disable=SC2046,SC2312 + set -- \ + $(rwx_ffmpeg_input_hdmi) \ + $(rwx_ffmpeg_input_blue_yeti) \ + $(rwx_ffmpeg_output_video_fast) \ + $(rwx_ffmpeg_output_audio_fast) \ + $(rwx_ffmpeg_output_file "${file}") + echo "${@}" + ffmpeg "${@}" +} + +# ╭────────┬────────╮ +# │ ffmpeg │ reduce │ +# ╰────────┴────────╯ + +rwx_ffmpeg_reduce() { + local input="${1}" + local output="${2}" + local from="${3}" + local to="${4}" + [ -n "${output}" ] || return + # LATER alternative + # shellcheck disable=SC2046,SC2312 + set -- \ + $(rwx_ffmpeg_input_file "${input}" "${from}" "${to}") \ + $(rwx_ffmpeg_output_video_slow) \ + $(rwx_ffmpeg_output_audio_slow) \ + $(rwx_ffmpeg_output_file "${output}") + echo "${@}" + ffmpeg "${@}" +} diff --git a/sh/gnome.sh b/sh/gnome.sh index 11831fb..b17a058 100644 --- a/sh/gnome.sh +++ b/sh/gnome.sh @@ -1,3 +1,27 @@ +# ╭───────┬────────────╮ +# │ gnome │ background │ +# ╰───────┴────────────╯ + +rwx_gnome_background_black() { + rwx_gnome_set_background "color-shading-type" "solid" + rwx_gnome_set_background "primary-color" "#000000" +} + +rwx_gnome_background_white() { + rwx_gnome_set_background "color-shading-type" "solid" + rwx_gnome_set_background "primary-color" "#ffffff" +} + +rwx_gnome_background_win3() { + rwx_gnome_set_background "color-shading-type" "vertical" + rwx_gnome_set_background "primary-color" "#000000" + rwx_gnome_set_background "secondary-color" "#0000ff" +} + +# ╭───────┬───────╮ +# │ gnome │ proxy │ +# ╰───────┴───────╯ + rwx_gnome_proxy() { local value case "${1}" in @@ -7,6 +31,29 @@ rwx_gnome_proxy() { gsettings set "org.gnome.system.proxy" "mode" "${value}" } +# ╭───────┬─────╮ +# │ gnome │ set │ +# ╰───────┴─────╯ + +rwx_gnome_set() { + local group="${1}" + local key="${2}" + local value="${3}" + [ -n "${value}" ] || return + gsettings set "${group}" "${key}" "${value}" +} + +rwx_gnome_set_background() { + local key="${1}" + local value="${2}" + [ -n "${value}" ] || return + rwx_gnome_set "org.gnome.desktop.background" "${key}" "${value}" +} + +# ╭───────┬────────────╮ +# │ gnome │ workspaces │ +# ╰───────┴────────────╯ + rwx_gnome_workspaces_primary() { local bool local group="org.gnome.mutter" diff --git a/sh/gpg.sh b/sh/gpg.sh index a2b7f50..b5ce07b 100644 --- a/sh/gpg.sh +++ b/sh/gpg.sh @@ -1,3 +1,10 @@ +# bind gpg agent to current tty +rwx_gpg_agent_update() { + gpg-connect-agent \ + updatestartuptty \ + /bye +} + rwx_gpg_ssh_auth_sock() { local user_id user_id=$(id --user) diff --git a/sh/lint/gitlint.sh b/sh/lint/gitlint.sh new file mode 100644 index 0000000..643333c --- /dev/null +++ b/sh/lint/gitlint.sh @@ -0,0 +1,6 @@ +rwx_gitlint() { + local path="${1}" + gitlint \ + --target "${path}" \ + "lint" +} diff --git a/sh/lint/lint.sh b/sh/lint/lint.sh new file mode 100644 index 0000000..365773f --- /dev/null +++ b/sh/lint/lint.sh @@ -0,0 +1,78 @@ +# lint code +rwx_lint() { + local path="${1}" + [ -n "${path}" ] || return 1 + rwx_lint_clean "${path}" + rwx_lint_tasks "${path}" + set \ + "python" \ + "shell" + local code + for code in "${@}"; do + rwx_log "" "${code}" + "rwx_lint_${code}" "${path}" + done + rwx_lint_clean "${path}" +} + +# clean +rwx_lint_clean() { + local path="${1}" + [ -n "${path}" ] || return 1 + rwx_log "" "clean" "" + py3clean "${path}" + set \ + "mypy" \ + "ruff" + local tool + for tool in "${@}"; do + rwx_remove "${path}/.${tool}_cache" + done +} + +# lint python code +rwx_lint_python() { + local path="${1}" + local action + set \ + "pylint" \ + "pydoclint" \ + "mypy" \ + "ruff" + for action in "${@}"; do + rwx_log "" "${action}" + "rwx_${action}" "${path}" + done +} + +# lint shell code +rwx_lint_shell() { + local path="${1}" + local action + set \ + "shellcheck" \ + "shfmt" + for action in "${@}"; do + rwx_log "" "${action}" + "rwx_${action}" "${path}" + done +} + +# lint code tasks +rwx_lint_tasks() { + local path="${1}" + local type + set \ + "LATER" \ + "TODO" \ + "FIXME" + for type in "${@}"; do + rwx_log "" "${type}" + grep \ + --after "1" \ + --directories "recurse" \ + --line-number \ + " ${type}" \ + "${path}" + done +} diff --git a/sh/lint/mypy.sh b/sh/lint/mypy.sh new file mode 100644 index 0000000..586d409 --- /dev/null +++ b/sh/lint/mypy.sh @@ -0,0 +1,4 @@ +rwx_mypy() { + local path="${1}" + mypy "${path}" +} diff --git a/sh/lint/pydoclint.sh b/sh/lint/pydoclint.sh new file mode 100644 index 0000000..d2eb72f --- /dev/null +++ b/sh/lint/pydoclint.sh @@ -0,0 +1,9 @@ +rwx_pydoclint() { + local path="${1}" + pydoclint \ + --allow-init-docstring True \ + --quiet \ + --skip-checking-short-docstrings False \ + --style "sphinx" \ + "${path}" +} diff --git a/sh/lint/pylint.sh b/sh/lint/pylint.sh new file mode 100644 index 0000000..52e1bd1 --- /dev/null +++ b/sh/lint/pylint.sh @@ -0,0 +1,6 @@ +rwx_pylint() { + local path="${1}" + pylint \ + --enable-all-extensions \ + "${path}/**/*.py" +} diff --git a/sh/lint/ruff.sh b/sh/lint/ruff.sh new file mode 100644 index 0000000..e15b701 --- /dev/null +++ b/sh/lint/ruff.sh @@ -0,0 +1,28 @@ +rwx_ruff() { + local path="${1}" + local action + set \ + "check" \ + "format" + for action in "${@}"; do + "rwx_ruff_${action}" "${path}" + done +} + +rwx_ruff_check() { + local path="${1}" + ruff check \ + --ignore "D203,D213" \ + --isolated \ + --select "ALL" \ + "${path}" +} + +rwx_ruff_format() { + local path="${1}" + ruff format \ + --diff \ + --isolated \ + --line-length "80" \ + "${path}" +} diff --git a/sh/lint/shellcheck.sh b/sh/lint/shellcheck.sh index f31b2b4..ac8c700 100644 --- a/sh/lint/shellcheck.sh +++ b/sh/lint/shellcheck.sh @@ -9,6 +9,12 @@ rwx_shellcheck() { echo ". \"${path}\"" >>"${file}" done rwx_ifs_unset + rwx_shellcheck_file "${file}" + rwx_remove "${file}" +} + +rwx_shellcheck_file() { + local file="${1}" shellcheck \ --check-sourced \ --enable "all" \ @@ -16,5 +22,13 @@ rwx_shellcheck() { --external-sources \ --shell "dash" \ "${file}" - rm "${file}" +} + +rwx_shellcheck_write() { + rwx_file_write ".shellcheckrc" "\ +disable=3043 +enable=all +external-sources=true +shell=sh +" } diff --git a/sh/lint/shfmt.sh b/sh/lint/shfmt.sh index 097de86..4d6e894 100644 --- a/sh/lint/shfmt.sh +++ b/sh/lint/shfmt.sh @@ -1,4 +1,4 @@ rwx_shfmt() { - local root="${1}" - shfmt --diff "${root}" + local path="${1}" + shfmt --diff "${path}" } diff --git a/sh/log.sh b/sh/log/log.sh similarity index 100% rename from sh/log.sh rename to sh/log/log.sh diff --git a/sh/log/step.sh b/sh/log/step.sh new file mode 100644 index 0000000..34a5c64 --- /dev/null +++ b/sh/log/step.sh @@ -0,0 +1,25 @@ +# ╭───────────────╮ +# │ __ = internal │ +# ╰───────────────╯ + +# __RWX_BAR_TOP +# __RWX_BAR_MIDDLE +# __RWX_BAR_BOTTOM + +# __RWX_STEP_LEVEL +# __RWX_STEP_level_INDEX +# __RWX_STEP_level_LABEL + +# ╭─────────────╮ +# │ _ = private │ +# ╰─────────────╯ + +_RWX_BOX_DOWN_AND_HORIZONTAL="┬" +_RWX_BOX_DOWN_AND_LEFT="╮" +_RWX_BOX_DOWN_AND_RIGHT="╭" +_RWX_BOX_HORIZONTAL="─" +_RWX_BOX_LEFT="╴" +_RWX_BOX_UP_AND_HORIZONTAL="┴" +_RWX_BOX_UP_AND_LEFT="╯" +_RWX_BOX_UP_AND_RIGHT="╰" +_RWX_BOX_VERTICAL="│" diff --git a/sh/main.sh b/sh/main.sh old mode 100644 new mode 100755 index 2b3508c..802418f --- a/sh/main.sh +++ b/sh/main.sh @@ -1,24 +1,35 @@ -# ╭───────────╮ -# │ constants │ -# ╰───────────╯ +#! /usr/bin/env sh + +# ╭──────┬───────────╮ +# │ main │ constants │ +# ╰──────┴───────────╯ RWX_MAIN_NAME="main.sh" RWX_SELF_NAME="rwx" -# ╭───────────╮ -# │ variables │ -# ╰───────────╯ +RWX_SELF_COMMAND="_${RWX_SELF_NAME}_cmd_" -RWX_ROOT_USER="${HOME}/${RWX_SELF_NAME}" +# ╭──────┬───────────╮ +# │ main │ variables │ +# ╰──────┴───────────╯ + +RWX_COMMAND_ARGUMENT="${0}" RWX_SHELL="$(cat "/proc/${$}/comm")" -RWX_SYSTEM_ROOT="/usr/local/lib" + +RWX_COMMAND_NAME="$(basename "${RWX_COMMAND_ARGUMENT}" | + sed "s|^-||")" +case "${RWX_COMMAND_NAME}" in +"bash" | "dash" | "sh") unset RWX_COMMAND_NAME ;; +*) ;; +esac +RWX_ROOT_SYSTEM="/usr/local/lib/${RWX_SELF_NAME}" +RWX_SELF_USER="${HOME}/${RWX_SELF_NAME}" RWX_MAIN_PATH="${RWX_ROOT_SYSTEM}/${RWX_MAIN_NAME}" -RWX_ROOT_SYSTEM="${RWX_SYSTEM_ROOT}/${RWX_SELF_NAME}" -# ╭──────╮ -# │ core │ -# ╰──────╯ +# ╭──────┬───────╮ +# │ main │ shell │ +# ╰──────┴───────╯ # test if active shell is in interactive mode rwx_shell_interactive() { @@ -29,7 +40,7 @@ rwx_shell_interactive() { } # ╭──────┬─────╮ -# │ core │ log │ +# │ main │ log │ # ╰──────┴─────╯ __rwx_log() { @@ -43,7 +54,7 @@ __rwx_log() { } # ╭──────┬──────╮ -# │ core │ find │ +# │ main │ find │ # ╰──────┴──────╯ # find directory’s files by extension @@ -70,7 +81,7 @@ rwx_find_shell() { } # ╭──────┬─────╮ -# │ core │ ifs │ +# │ main │ ifs │ # ╰──────┴─────╯ rwx_ifs_set() { @@ -85,20 +96,19 @@ rwx_ifs_unset() { } # ╭──────┬────────╮ -# │ core │ source │ +# │ main │ source │ # ╰──────┴────────╯ rwx_source() { local path="${1}" [ -d "${path}" ] || return 1 - local count module modules - modules="$(rwx_find_shell "${path}" "${RWX_MAIN_NAME}")" - rwx_ifs_set + local count module count=0 __rwx_log "" \ ". ${path}" - for module in ${modules}; do + rwx_ifs_set + for module in $(rwx_find_shell "${path}" "${RWX_MAIN_NAME}"); do count=$((count + 1)) __rwx_log "$(printf "%02d" "${count}") ${module%.sh}" module="${path}/${module}" @@ -108,9 +118,9 @@ rwx_source() { rwx_ifs_unset } -# ╭──────┬──────╮ -# │ core │ main │ -# ╰──────┴──────╯ +# ╭──────╮ +# │ main │ +# ╰──────╯ # run initial steps rwx_main() { @@ -120,20 +130,15 @@ rwx_main() { return 1 fi # user root - rwx_source "${RWX_ROOT_USER}" - # run interactive extras - if rwx_shell_interactive; then - # check format - rwx_log - rwx_shfmt "${RWX_ROOT_SYSTEM}" - # check syntax - rwx_log - rwx_shellcheck "${RWX_ROOT_SYSTEM}" - # help - rwx_log - rwx_self_help + rwx_source "${RWX_SELF_USER}" + # context / command + if [ -n "${RWX_COMMAND_NAME}" ]; then + "${RWX_SELF_COMMAND}${RWX_COMMAND_NAME}" "${@}" + # context / shell + else + rwx_self_init fi } # run main function -rwx_main +rwx_main "${@}" diff --git a/sh/python.sh b/sh/python.sh new file mode 100644 index 0000000..44ea181 --- /dev/null +++ b/sh/python.sh @@ -0,0 +1,14 @@ +# ╭────────╮ +# │ python │ +# ╰────────╯ + +# ╭────────┬──────╮ +# │ python │ venv │ +# ╰────────┴──────╯ + +rwx_python_venv() { + local path="${1}" + [ -d "${path}" ] || return 1 + export VIRTUAL_ENV="${path}" && \ + export PATH="${VIRTUAL_ENV}/bin:${PATH}" +} diff --git a/sh/rescue/hetzner.sh b/sh/rescue/hetzner.sh index 9d22847..24d6bd0 100644 --- a/sh/rescue/hetzner.sh +++ b/sh/rescue/hetzner.sh @@ -63,6 +63,8 @@ rwx_rescue_wipe_0_init_hetzner_8_8() { for device in "${@}"; do members="${members} ${device}2" done + # LATER alternative + # shellcheck disable=SC2086 rwx_fs_raid_create \ "boot" "00000000:00000000:00000000:00000002" ${members} # @@ -87,6 +89,8 @@ rwx_rescue_wipe_0_init_hetzner_8_8() { for device in "${@}"; do members="${members} ${device}1" done + # LATER alternative + # shellcheck disable=SC2086 rwx_fs_raid_create \ "crypt" "00000000:00000000:00000000:00000001" ${members} # encrypt diff --git a/sh/self.sh b/sh/self.sh index 4220366..732e9c2 100644 --- a/sh/self.sh +++ b/sh/self.sh @@ -1,4 +1,57 @@ -# get functions from file +# meta doc +rwx_doc() { + local name="${1}" + [ -n "${name}" ] || return + local doc line module + rwx_ifs_set + for module in $(rwx_find_shell "${RWX_ROOT_SYSTEM}"); do + while read -r line; do + case "${line}" in + "#"*) doc="${doc}${line}" ;; + "${name}() {") + echo "${doc}" + return + ;; + *) doc="" ;; + esac + done <"${RWX_ROOT_SYSTEM}/${module}" + done + rwx_ifs_unset +} + +# ╭──────┬───────╮ +# │ self │ check │ +# ╰──────┴───────╯ + +# check source code +rwx_self_check() { + # check format + rwx_log + rwx_shfmt "${RWX_ROOT_SYSTEM}" + # check syntax + rwx_log + rwx_shellcheck "${RWX_ROOT_SYSTEM}" +} + +# ╭──────┬──────────╮ +# │ self │ commands │ +# ╰──────┴──────────╯ + +# get commands from root +rwx_self_commands() { + grep \ + --directories "recurse" \ + --no-filename \ + "^${RWX_SELF_COMMAND}" "${RWX_ROOT_SYSTEM}" | + cut --delimiter "(" --fields 1 | + sed "s|^${RWX_SELF_COMMAND}||" +} + +# ╭──────┬───────────╮ +# │ self │ functions │ +# ╰──────┴───────────╯ + +# get functions from root rwx_self_functions() { grep \ --directories "recurse" \ @@ -7,6 +60,10 @@ rwx_self_functions() { cut --delimiter "(" --fields 1 } +# ╭──────┬──────╮ +# │ self │ help │ +# ╰──────┴──────╯ + # output help message rwx_self_help() { rwx_log \ @@ -14,3 +71,92 @@ rwx_self_help() { " a__… = aliases" \ " u__… = user" } + +# ╭──────┬──────╮ +# │ self │ init │ +# ╰──────┴──────╯ + +rwx_self_init() { + # run interactive extras + if rwx_shell_interactive; then + # help + rwx_log + rwx_self_help + fi +} + +# ╭──────┬─────────╮ +# │ self │ install │ +# ╰──────┴─────────╯ + +_rwx_cmd_rwx_install() { rwx_self_install "${@}"; } +rwx_self_install() { + local target="${1}" + local command file root + # code + if [ -n "${target}" ]; then + root="${target}${RWX_ROOT_SYSTEM}" + rwx_remove "${root}" + cp --recursive "${RWX_ROOT_SYSTEM}" "${root}" + fi + # commands + root="${target}/usr/local/bin" + for command in $(rwx_self_commands); do + file="${root}/${command}" + rwx_remove "${file}" + rwx_link "${file}" "${RWX_MAIN_PATH}" + done + # sh + file="${target}/etc/profile.d/${RWX_SELF_NAME}.sh" + rwx_remove "${file}" + rwx_file_write "${file}" "\ +export ENV=\"${RWX_MAIN_PATH}\" +" + # bash + file="${target}/etc/bash.bashrc" + rwx_remove "${file}" + rwx_link "${file}" "${RWX_MAIN_PATH}" +} + +# ╭──────┬────────╮ +# │ self │ subset │ +# ╰──────┴────────╯ + +rwx_self_subset() { + local argument path + for argument in "${@}"; do + path="${RWX_ROOT_SYSTEM}/${argument}" + if [ -d "${path}" ]; then + local file + for file in $(rwx_find_shell "${path}"); do + echo "${argument}/${file}" + done + elif [ -f "${path}" ]; then + echo "${argument}" + fi + done +} + +# ╭──────┬───────╮ +# │ self │ write │ +# ╰──────┴───────╯ + +rwx_self_write() { + local target="${1}" + if [ -n "${target}" ]; then + shift + local file text + text="#! /usr/bin/env sh +" + rwx_ifs_set + for file in $(rwx_self_subset "${@}"); do + text="${text} +$(cat "${RWX_ROOT_SYSTEM}/${file}") +" + done + rwx_ifs_unset + rwx_file_write "${target}" "${text}" + rwx_shfmt "${target}" + rwx_shellcheck_file "${target}" + fi +} diff --git a/sh/shell.sh b/sh/shell.sh index 561fcdd..7e56658 100644 --- a/sh/shell.sh +++ b/sh/shell.sh @@ -71,7 +71,7 @@ rwx_shell_prompt() { id="$(id --user)" local path="${PWD}" local user="${USER}" - local view="└ " + local view="╰ " # code if [ "${code}" -ne 0 ]; then view="${view}${RWX_COLOR_GREEN}" @@ -96,7 +96,7 @@ rwx_shell_prompt() { # new view="${view}\\n" # frame - view="${view}${RWX_COLOR_DEFAULT}┌ " + view="${view}${RWX_COLOR_DEFAULT}╭ " # user if [ "${id}" -eq 0 ]; then view="${view}${RWX_COLOR_GREEN}" @@ -114,12 +114,3 @@ rwx_shell_prompt() { # print printf "%b" "${view}" } - -rwx_shell_setup() { - # shell - echo "export ENV=\"${ENV}\"" >"/etc/profile.d/${RWX_SELF_NAME}.sh" - # bash - local file="/etc/bash.bashrc" - rm --force --recursive "${file}" - ln --symbolic "${ENV}" "${file}" -} diff --git a/sh/tmux.sh b/sh/tmux.sh new file mode 100644 index 0000000..d9813e1 --- /dev/null +++ b/sh/tmux.sh @@ -0,0 +1,264 @@ +# ╭──────┬───────╮ +# │ tmux │ setup │ +# ╰──────┴───────╯ + +rwx_tmux_setup() { + local file + file="${HOME}/.tmux.conf" + rwx_file_write "${file}" "\ +# ╭────────╮ +# │ option │ +# ╰────────╯ + +# empty name for windows +set-option -g automatic-rename-format '#{pane_current_command}' +set-option -g automatic-rename on + +# first index number +set-option -g base-index 1 + +# display duration +set-option -g display-time 1536 + +# extend history limit +set-option -g history-limit 1048576 + +# style for messages +set-option -g message-style bg=red,fg=white + +# activity monitoring +set-window-option -g monitor-activity on + +# silence monitoring +set-window-option -g monitor-silence 0 + +# enable mouse actions +set-option -g mouse on + +# prefix with ^B or F12 +set-option -g prefix C-b +set-option -g prefix2 F12 + +# renumber windows after closing one +set-option -g renumber-windows on + +# enable title +set-option -g set-titles on + +# set title to working directory +set-option -g set-titles-string '\ +#{session_name}\ + - \ +#{window_index}∕#{session_windows} #{window_name}\ + - \ +#{pane_index}∕#{window_panes} #{pane_current_command}\ +' + +# ╭────────┬──────╮ +# │ option │ pane │ +# ╰────────┴──────╯ + +# first index number +set-option -g pane-base-index 1 + +# ╭────────┬──────┬────────╮ +# │ option │ pane │ border │ +# ╰────────┴──────┴────────╯ + +# active style +set-option -g pane-active-border-style fg=green + +# regular style +set-option -g pane-border-style fg=blue + +# ╭────────┬────────╮ +# │ option │ status │ +# ╰────────┴────────╯ + +# status lines +set-option -g status 3 + +# background color +set-option -g status-bg '#0D0D0D' + +# foreground color +set-option -g status-fg white + +# line 1 +set-option -g status-format[0] '\ +#{W:\ +#[bg=##202020] #[bg=##303030]\ +#{?window_zoomed_flag,#[fg=magenta][, }\ +#[fg=yellow]#{window_index}\ +#{?window_zoomed_flag,#[fg=magenta]], }\ + \ +#{?window_active,#[fg=green],\ +#{?window_activity_flag,#[fg=red],#[fg=blue]}}\ +#{window_name}\ +#[bg=##303030] #[bg=##202020] \ +#[bg=default] \ +}\ +#[align=right]\ +#[bg=##202020] #[bg=##303030] \ +#[fg=yellow]%H:%M:%S\ +#[bg=##303030] #[bg=##202020]\ +#{?client_prefix,#[fg=green]p, }\ +' + +# line 2 +set-option -g status-format[1] '\ +#{S:\ +#[bg=##202020] #[bg=##303030] \ +#{?session_many_attached,#[fg=red],\ +#{?session_attached,#[fg=magenta],#[fg=blue]}}\ +#{session_name}\ +#[bg=##303030] #[bg=##202020] \ +#[bg=default] \ +}\ +#[fg=yellow]→ #[fg=green]#{session_name} \ +#[align=right]\ +#[bg=##202020] #[bg=##303030] \ +#[fg=yellow]%Y-%m-%d\ +#[bg=##303030] #[bg=##202020] \ +' + +# line 3 +set-option -g status-format[2] '\ +#[fg=cyan]#{pane_current_path}\ +#[align=right]\ +#[bg=##202020] #[bg=##303030] \ +#[fg=yellow]#{host}\ +#[bg=##303030] #[bg=##202020] \ +' + +# line 4 +set-option -g status-format[3] '\ +#{P:\ +#[bg=##202020] #[bg=##303030] \ +#[fg=yellow]#{pane_index}\ + \ +#{?pane_active,#[fg=green],#[fg=blue]}\ +#{pane_current_command}\ +#[bg=##303030] #[bg=##202020] \ +#[bg=default] \ +}\ +#[align=right]\ +#[bg=##202020] #[bg=##303030] \ +#{?uid,#[fg=green],#[fg=red]}\ +#{user}\ +#[bg=##303030] #[bg=##202020] \ +' + +# line 5 +set-option -g status-format[4] '\ +#{P:\ +#[bg=##202020] #[bg=##303030] \ +#[fg=yellow]#{pane_index}\ + \ +#{?pane_active,#[fg=green],#[fg=blue]}\ +#{pane_width}×#{pane_height}\ +#[bg=##303030] #[bg=##202020] \ +#[bg=default] \ +}\ +#[align=right]\ +#[bg=##202020] #[bg=##303030] \ +#[fg=green]#{window_width}×#{window_height}\ +#[bg=##303030] #[bg=##202020] \ +' + +# refresh period +set-option -g status-interval 1 + +# bar location +set-option -g status-position bottom + +# ╭─────╮ +# │ key │ +# ╰─────╯ + +# detach client +bind-key -n F6 detach-client + +# new window +bind-key -n F2 new-window + +# select pane +bind-key -n C-S-Down select-pane -D +bind-key -n C-S-Left select-pane -L +bind-key -n C-S-Right select-pane -R +bind-key -n C-S-Up select-pane -U + +# status lines +bind-key -n C-F10 set-option -g status off +bind-key -n C-F1 set-option -g status on +bind-key -n C-F2 set-option -g status 2 +bind-key -n C-F3 set-option -g status 3 +bind-key -n C-F4 set-option -g status 4 +bind-key -n C-F5 set-option -g status 5 + +# switch session +bind-key -n M-Down switch-client -n +bind-key -n M-Up switch-client -p + +# switch window +bind-key -n M-Left previous-window +bind-key -n M-Right next-window + +# ╭─────┬────────╮ +# │ key │ prefix │ +# ╰─────┴────────╯ + +# rename +bind-key C-s command-prompt { rename-session '%%' } +bind-key C-w command-prompt { rename-window '%%' } + +# split window +bind-key h split-window -h +bind-key v split-window -v + +# toggle mouse +bind-key t set-option -g mouse \\; display-message 'mouse = #{mouse}' + +# reload configuration +bind-key r source-file ${file} \\; display-message 'source-file ${file}' + +# swap window +bind-key M-Left swap-window -t -1 +bind-key M-Right swap-window -t +1 + +# ╭─────────────╮ +# │ default │ +# ╭───────────┬─────────┼─────┬───────┤ +# │ -n │ F12 │ -n │ C-b │ +# ╭───────────────────┼───────────┼─────────┼─────┼───────┤ +# │ command-prompt │ │ │ │ : │ +# │ copy-mode │ │ │ │ PPage │ +# │ detach-client │ │ │ │ d │ +# │ new-session │ │ │ │ │ +# │ new-window │ F2 │ │ │ c │ +# │ next-window │ M-Right │ │ │ n │ +# │ previous-window │ M-Left │ │ │ p │ +# │ rename-session │ │ C-s │ │ │ +# │ rename-window │ │ C-w │ │ │ +# │ resize-pane -Z │ │ │ │ z │ +# │ select-pane -D │ C-S-Down │ │ │ │ +# │ select-pane -L │ C-S-Left │ │ │ │ +# │ select-pane -R │ C-S-Right │ │ │ │ +# │ select-pane -U │ C-S-Up │ │ │ │ +# │ set -g mouse │ │ t │ │ │ +# │ set -g status off │ C-F10 │ │ │ │ +# │ set -g status on │ C-F1 │ │ │ │ +# │ set -g status 2 │ C-F2 │ │ │ │ +# │ set -g status 3 │ C-F3 │ │ │ │ +# │ set -g status 4 │ C-F4 │ │ │ │ +# │ set -g status 5 │ C-F5 │ │ │ │ +# │ source-file │ │ r │ │ │ +# │ split-window -h │ │ h │ │ % │ +# │ split-window -v │ │ v │ │ \" │ +# │ swap-window -t -1 │ │ M-Left │ │ │ +# │ swap-window -t +1 │ │ M-Right │ │ │ +# │ switch-client -n │ M-Down │ │ │ │ +# │ switch-client -p │ M-Up │ │ │ │ +# ╰───────────────────┴───────────┴─────────┴─────┴───────╯ +" +} diff --git a/sh/util.sh b/sh/util.sh index 7d9cc3f..cbcd67a 100644 --- a/sh/util.sh +++ b/sh/util.sh @@ -1,3 +1,35 @@ +rwx_file_append() { + local file="${1}" + local text="${2}" + if [ -n "${file}" ]; then + printf "%s" "${text}" >>"${file}" + fi +} + +rwx_file_empty() { + local file="${1}" + if [ -n "${file}" ]; then + rwx_file_write "${file}" "" + fi +} + +rwx_file_write() { + local file="${1}" + local text="${2}" + if [ -n "${file}" ]; then + printf "%s" "${text}" >"${file}" + fi +} + +rwx_link() { + local link="${1}" + local target="${2}" + ln \ + --symbolic \ + "${target}" \ + "${link}" +} + rwx_list_block_devices() { lsblk \ --noempty \ @@ -28,6 +60,13 @@ rwx_read_secret() { unset secret } +rwx_remove() { + rm \ + --force \ + --recursive \ + "${@}" +} + rwx_warn_wipe() { local tmp rwx_list_block_devices