4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | ❯ Salt
5 |
6 | Fast and simple task management from the CLI.
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 | DEV Post | YouTube Video | VSCode Extension
20 |
21 |
22 |
23 |
24 | ## Install
25 |
26 | Windows: [Scoop](https://scoop.sh)
27 |
28 | ```
29 | scoop bucket add cone https://github.com/Milo123459/cone
30 | scoop install cone/salt
31 | ```
32 |
33 | MacOS: [Brew](https://brew.sh)
34 |
35 | ```
36 | brew tap eternalmoon1234/brew
37 | brew install salt
38 | ```
39 |
40 | Linux:
41 |
42 | ```
43 | curl -fsSL https://raw.githubusercontent.com/Milo123459/salt/master/install.sh | bash
44 | ```
45 |
46 | Litreally anything (Rust needed):
47 |
48 | ```
49 | cargo install salt
50 | ```
51 |
52 | ## Concepts
53 |
54 | You have a node, and a task.
55 |
56 | Think of it like a tree with apples. The tree is the node, the apples are the tasks. They just live under specific trees.
57 |
58 | *just for context, apple = task, tree = node`*
59 |
60 | ## Future ideas
61 |
62 | - Stats (ie, which node you use the most)
63 | - GitHub issue sync
64 | - Sync across multiple devices
65 |
66 | ## How to use
67 |
68 | Pretty simple:
69 |
70 | Run `salt action` to see all commands.
71 |
72 | Or, run `salt node action` to see all node sub-commands.
73 |
--------------------------------------------------------------------------------
/assets/salt.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Milo123459/salt/55953b5a6cdf2335bb88c905a94adc42c7613c4d/assets/salt.png
--------------------------------------------------------------------------------
/assets/salt.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/install.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | # Adapted from starships install file
4 | # shellcheck disable=SC2039
5 |
6 | help_text="# Options
7 | #
8 | # -V, --verbose
9 | # Enable verbose output for the installer
10 | #
11 | # -f, -y, --force, --yes
12 | # Skip the confirmation prompt during installation
13 | #
14 | # -p, --platform
15 | # Override the platform identified by the installer
16 | #
17 | # -b, --bin-dir
18 | # Override the bin installation directory
19 | #
20 | # -a, --arch
21 | # Override the architecture identified by the installer
22 | #
23 | # -B, --base-url
24 | # Override the base URL used for downloading releases
25 | # -r, --remove
26 | # Uninstall salt
27 | # -h, --help
28 | # Get some help
29 | #
30 | "
31 |
32 | set -eu
33 | printf '\n'
34 |
35 | BOLD="$(tput bold 2>/dev/null || printf '')"
36 | GREY="$(tput setaf 0 2>/dev/null || printf '')"
37 | UNDERLINE="$(tput smul 2>/dev/null || printf '')"
38 | RED="$(tput setaf 1 2>/dev/null || printf '')"
39 | GREEN="$(tput setaf 2 2>/dev/null || printf '')"
40 | YELLOW="$(tput setaf 3 2>/dev/null || printf '')"
41 | BLUE="$(tput setaf 4 2>/dev/null || printf '')"
42 | MAGENTA="$(tput setaf 5 2>/dev/null || printf '')"
43 | NO_COLOR="$(tput sgr0 2>/dev/null || printf '')"
44 |
45 | SUPPORTED_TARGETS="x86_64-unknown-linux-gnu x86_64-unknown-linux-musl \
46 | i686-unknown-linux-musl aarch64-unknown-linux-musl \
47 | arm-unknown-linux-musleabihf x86_64-apple-darwin \
48 | aarch64-apple-darwin x86_64-pc-windows-msvc \
49 | i686-pc-windows-msvc aarch64-pc-windows-msvc \
50 | x86_64-unknown-freebsd"
51 |
52 | info() {
53 | printf '%s\n' "${BOLD}${GREY}>${NO_COLOR} $*"
54 | }
55 |
56 | warn() {
57 | printf '%s\n' "${YELLOW}! $*${NO_COLOR}"
58 | }
59 |
60 | error() {
61 | printf '%s\n' "${RED}x $*${NO_COLOR}" >&2
62 | }
63 |
64 | completed() {
65 | printf '%s\n' "${GREEN}✓${NO_COLOR} $*"
66 | }
67 |
68 | has() {
69 | command -v "$1" 1>/dev/null 2>&1
70 | }
71 |
72 | # Gets path to a temporary file, even if
73 | get_tmpfile() {
74 | local suffix
75 | suffix="$1"
76 | if has mktemp; then
77 | printf "%s%s.%s.%s" "$(mktemp)" "-salt" "${RANDOM}" "${suffix}"
78 | else
79 | # No really good options here--let's pick a default + hope
80 | printf "/tmp/salt.%s" "${suffix}"
81 | fi
82 | }
83 |
84 | # Test if a location is writeable by trying to write to it. Windows does not let
85 | # you test writeability other than by writing: https://stackoverflow.com/q/1999988
86 | test_writeable() {
87 | local path
88 | path="${1:-}/test.txt"
89 | if touch "${path}" 2>/dev/null; then
90 | rm "${path}"
91 | return 0
92 | else
93 | return 1
94 | fi
95 | }
96 |
97 | download() {
98 | file="$1"
99 | url="$2"
100 | touch "$file"
101 | printf "%s" "$file"
102 |
103 | if has curl; then
104 | cmd="curl --fail --silent --location --output $file $url"
105 | elif has wget; then
106 | cmd="wget --quiet --output-document=$file $url"
107 | elif has fetch; then
108 | cmd="fetch --quiet --output=$file $url"
109 | else
110 | error "No HTTP download program (curl, wget, fetch) found, exiting…"
111 | return 1
112 | fi
113 |
114 | $cmd && return 0 || rc=$?
115 |
116 | error "Command failed (exit code $rc): ${BLUE}${cmd}${NO_COLOR}"
117 | printf "\n" >&2
118 | info "This is likely due to salt not yet supporting your configuration."
119 | info "If you would like to see a build for your configuration,"
120 | info "please create an issue requesting a build for ${MAGENTA}${TARGET}${NO_COLOR}:"
121 | info "${BOLD}${UNDERLINE}https://github.com/Milo123459/salt/issues/new/${NO_COLOR}"
122 | return $rc
123 | }
124 |
125 | unpack() {
126 | local archive=$1
127 | local bin_dir=$2
128 | local sudo=${3-}
129 |
130 | case "$archive" in
131 | *.tar.gz)
132 | flags=$(test -n "${VERBOSE-}" && echo "-v" || echo "")
133 | ${sudo} tar "${flags}" -xzf "${archive}" -C "${bin_dir}"
134 | return 0
135 | ;;
136 | *.zip)
137 | flags=$(test -z "${VERBOSE-}" && echo "-qq" || echo "")
138 | UNZIP="${flags}" ${sudo} unzip "${archive}" -d "${bin_dir}"
139 | return 0
140 | ;;
141 | esac
142 |
143 | error "Unknown package extension."
144 | printf "\n"
145 | info "This almost certainly results from a bug in this script--please file a"
146 | info "bug report at https://github.com/Milo123459/salt/issues"
147 | return 1
148 | }
149 |
150 | elevate_priv() {
151 | if ! has sudo; then
152 | error 'Could not find the command "sudo", needed to get permissions for install.'
153 | info "If you are on Windows, please run your shell as an administrator, then"
154 | info "rerun this script. Otherwise, please run this script as root, or install"
155 | info "sudo."
156 | exit 1
157 | fi
158 | if ! sudo -v; then
159 | error "Superuser not granted, aborting installation"
160 | exit 1
161 | fi
162 | }
163 |
164 | install() {
165 | local msg
166 | local sudo
167 | local archive
168 | local ext="$1"
169 |
170 | if test_writeable "${BIN_DIR}"; then
171 | sudo=""
172 | msg="Installing salt, please wait…"
173 | else
174 | warn "Escalated permissions are required to install to ${BIN_DIR}"
175 | elevate_priv
176 | sudo="sudo"
177 | msg="Installing salt as root, please wait…"
178 | fi
179 | info "$msg"
180 |
181 | archive=$(get_tmpfile "$ext")
182 |
183 | # download to the temp file
184 | download "${archive}" "${URL}"
185 |
186 | # unpack the temp file to the bin dir, using sudo if required
187 | unpack "${archive}" "${BIN_DIR}" "${sudo}"
188 |
189 | # remove tempfile
190 |
191 | rm "${archive}"
192 | }
193 |
194 | # Currently supporting:
195 | # - win (Git Bash)
196 | # - darwin
197 | # - linux
198 | # - linux_musl (Alpine)
199 | # - freebsd
200 | detect_platform() {
201 | local platform
202 | platform="$(uname -s | tr '[:upper:]' '[:lower:]')"
203 |
204 | case "${platform}" in
205 | msys_nt*) platform="pc-windows-msvc" ;;
206 | cygwin_nt*) platform="pc-windows-msvc";;
207 | # mingw is Git-Bash
208 | mingw*) platform="pc-windows-msvc" ;;
209 | # use the statically compiled musl bins on linux to avoid linking issues.
210 | linux) platform="unknown-linux-musl" ;;
211 | darwin) platform="apple-darwin" ;;
212 | freebsd) platform="unknown-freebsd" ;;
213 | esac
214 |
215 | printf '%s' "${platform}"
216 | }
217 |
218 | # Currently supporting:
219 | # - x86_64
220 | # - i386
221 | detect_arch() {
222 | local arch
223 | arch="$(uname -m | tr '[:upper:]' '[:lower:]')"
224 |
225 | case "${arch}" in
226 | amd64) arch="x86_64" ;;
227 | armv*) arch="arm" ;;
228 | arm64) arch="aarch64" ;;
229 | esac
230 |
231 | # `uname -m` in some cases mis-reports 32-bit OS as 64-bit, so double check
232 | if [ "${arch}" = "x86_64" ] && [ "$(getconf LONG_BIT)" -eq 32 ]; then
233 | arch=i686
234 | elif [ "${arch}" = "aarch64" ] && [ "$(getconf LONG_BIT)" -eq 32 ]; then
235 | arch=arm
236 | fi
237 |
238 | printf '%s' "${arch}"
239 | }
240 |
241 | detect_target() {
242 | local arch="$1"
243 | local platform="$2"
244 | local target="$arch-$platform"
245 |
246 | if [ "${target}" = "arm-unknown-linux-musl" ]; then
247 | target="${target}eabihf"
248 | fi
249 |
250 | printf '%s' "${target}"
251 | }
252 |
253 |
254 | confirm() {
255 | if [ -z "${FORCE-}" ]; then
256 | printf "%s " "${MAGENTA}?${NO_COLOR} $* ${BOLD}[y/N]${NO_COLOR}"
257 | set +e
258 | read -r yn &2
318 | info "If you would like to see a build for your configuration,"
319 | info "please create an issue requesting a build for ${MAGENTA}${target}${NO_COLOR}:"
320 | info "${BOLD}${UNDERLINE}https://github.com/Milo123459/salt/issues/new/${NO_COLOR}"
321 | printf "\n"
322 | exit 1
323 | fi
324 | }
325 | UNINSTALL=0
326 | HELP=0
327 | CARGOTOML="$(curl -fsSL https://raw.githubusercontent.com/Milo123459/salt/master/Cargo.toml)"
328 | ALL_VERSIONS="$(sed -n 's/.*version = "\([^"]*\)".*/\1/p' <<< "$CARGOTOML")"
329 | IFS=$'\n' read -r -a VERSION <<< "$ALL_VERSIONS"
330 | # defaults
331 | if [ -z "${PLATFORM-}" ]; then
332 | PLATFORM="$(detect_platform)"
333 | fi
334 |
335 | if [ -z "${BIN_DIR-}" ]; then
336 | BIN_DIR=/usr/local/bin
337 | fi
338 |
339 | if [ -z "${ARCH-}" ]; then
340 | ARCH="$(detect_arch)"
341 | fi
342 |
343 | if [ -z "${BASE_URL-}" ]; then
344 | BASE_URL="https://github.com/Milo123459/salt/releases"
345 | fi
346 |
347 | # parse argv variables
348 | while [ "$#" -gt 0 ]; do
349 | case "$1" in
350 | -p | --platform)
351 | PLATFORM="$2"
352 | shift 2
353 | ;;
354 | -b | --bin-dir)
355 | BIN_DIR="$2"
356 | shift 2
357 | ;;
358 | -a | --arch)
359 | ARCH="$2"
360 | shift 2
361 | ;;
362 | -B | --base-url)
363 | BASE_URL="$2"
364 | shift 2
365 | ;;
366 |
367 | -V | --verbose)
368 | VERBOSE=1
369 | shift 1
370 | ;;
371 | -f | -y | --force | --yes)
372 | FORCE=1
373 | shift 1
374 | ;;
375 | -r | --remove | --uninstall)
376 | UNINSTALL=1
377 | shift 1
378 | ;;
379 | -h | --help)
380 | HELP=1
381 | shift 1
382 | ;;
383 | -p=* | --platform=*)
384 | PLATFORM="${1#*=}"
385 | shift 1
386 | ;;
387 | -b=* | --bin-dir=*)
388 | BIN_DIR="${1#*=}"
389 | shift 1
390 | ;;
391 | -a=* | --arch=*)
392 | ARCH="${1#*=}"
393 | shift 1
394 | ;;
395 | -B=* | --base-url=*)
396 | BASE_URL="${1#*=}"
397 | shift 1
398 | ;;
399 | -V=* | --verbose=*)
400 | VERBOSE="${1#*=}"
401 | shift 1
402 | ;;
403 | -f=* | -y=* | --force=* | --yes=*)
404 | FORCE="${1#*=}"
405 | shift 1
406 | ;;
407 |
408 | *)
409 | error "Unknown option: $1"
410 | exit 1
411 | ;;
412 | esac
413 | done
414 | if [ $UNINSTALL == 1 ]; then
415 | confirm "Are you sure you want to uninstall salt?"
416 |
417 | msg=""
418 | sudo=""
419 |
420 | info "REMOVING salt"
421 |
422 | if test_writeable "$(dirname "$(which salt)")"; then
423 | sudo=""
424 | msg="Removing salt, please wait…"
425 | else
426 | warn "Escalated permissions are required to install to ${BIN_DIR}"
427 | elevate_priv
428 | sudo="sudo"
429 | msg="Removing salt as root, please wait…"
430 | fi
431 |
432 | info "$msg"
433 | ${sudo} rm "$(which salt)"
434 | ${sudo} rm /tmp/salt
435 |
436 | info "Removed salt"
437 | exit 0
438 |
439 | fi
440 | if [ $HELP == 1 ]; then
441 | echo "${help_text}"
442 | exit 0
443 | fi
444 | TARGET="$(detect_target "${ARCH}" "${PLATFORM}")"
445 |
446 | is_build_available "${ARCH}" "${PLATFORM}" "${TARGET}"
447 |
448 | printf " %s\n" "${UNDERLINE}Configuration${NO_COLOR}"
449 | info "${BOLD}Bin directory${NO_COLOR}: ${GREEN}${BIN_DIR}${NO_COLOR}"
450 | info "${BOLD}Platform${NO_COLOR}: ${GREEN}${PLATFORM}${NO_COLOR}"
451 | info "${BOLD}Arch${NO_COLOR}: ${GREEN}${ARCH}${NO_COLOR}"
452 | info "${BOLD}Version${NO_COLOR}: ${GREEN}${VERSION[0]}${NO_COLOR}"
453 |
454 | # non-empty VERBOSE enables verbose untarring
455 | if [ -n "${VERBOSE-}" ]; then
456 | VERBOSE=v
457 | info "${BOLD}Verbose${NO_COLOR}: yes"
458 | else
459 | VERBOSE=
460 | fi
461 |
462 | printf '\n'
463 |
464 | EXT=tar.gz
465 | if [ "${PLATFORM}" = "pc-windows-msvc" ]; then
466 | EXT=zip
467 | fi
468 |
469 | URL="${BASE_URL}/latest/download/salt-${TARGET}.${EXT}"
470 | info "Tarball URL: ${UNDERLINE}${BLUE}${URL}${NO_COLOR}"
471 | confirm "Install salt ${GREEN}${VERSION[0]}${NO_COLOR} to ${BOLD}${GREEN}${BIN_DIR}${NO_COLOR}?"
472 | check_bin_dir "${BIN_DIR}"
473 |
474 | install "${EXT}"
475 | completed "salt installed"
--------------------------------------------------------------------------------
/rustfmt.toml:
--------------------------------------------------------------------------------
1 | reorder_imports = true
2 | reorder_modules = true
3 | use_field_init_shorthand = true
4 | hard_tabs = true
--------------------------------------------------------------------------------
/src/args.rs:
--------------------------------------------------------------------------------
1 | use serde::{Deserialize, Serialize};
2 | use structopt::StructOpt;
3 |
4 | #[derive(Serialize, Deserialize, Debug, StructOpt, PartialEq, Clone)]
5 | pub struct Arguments {
6 | /// type of action. run the `action` / `actions` action to see available actions.
7 | pub action: String,
8 |
9 | /// arguments to action
10 | pub arguments: Vec,
11 |
12 | /// todo node name
13 | #[structopt(long, short, default_value = "Default")]
14 | pub node: String,
15 |
16 | /// display done tasks (only applies on certain commands)
17 | #[structopt(long, short)]
18 | pub(crate) checked: Option