theamify-cli 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,135 @@
1
+ #!/usr/bin/env bash
2
+ # -----------------------------------------------------------------------------
3
+ # lib/utils.sh - Utility Functions (ORIGINAL / BUGGY, for reproduction)
4
+ # -----------------------------------------------------------------------------
5
+
6
+ require_root() {
7
+ local cmd="${1:-this command}"
8
+ if [[ "${EUID}" -ne 0 ]]; then
9
+ print_error "Root privileges required."
10
+ print_step "Try: sudo ${cmd}"
11
+ exit 1
12
+ fi
13
+ }
14
+
15
+ confirm() {
16
+ local msg="${1:-Are you sure?}"
17
+ [[ "${OPT_YES:-false}" == "true" ]] && return 0
18
+ echo -ne " ${C_PROMPT}${msg} [y/N]${RESET} "
19
+ read -r ans
20
+ [[ "${ans}" =~ ^[Yy]$ ]]
21
+ }
22
+
23
+ check_deps_required() {
24
+ local ok=true
25
+ command -v git &>/dev/null || {
26
+ print_error "Missing required dependency: git"
27
+ print_step "Install: sudo apt install git"
28
+ ok=false
29
+ }
30
+ if ! command -v wget &>/dev/null && ! command -v curl &>/dev/null; then
31
+ print_error "Need wget or curl for downloading."
32
+ print_step "Install: sudo apt install wget"
33
+ ok=false
34
+ fi
35
+ [[ "${ok}" == "true" ]] || exit 1
36
+ }
37
+
38
+ git_clone() {
39
+ local url="${1}" dest="${2}"
40
+ local args=("--depth=1" "--recurse-submodules" "--quiet")
41
+ if [[ "${OPT_VERBOSE:-false}" == "true" ]]; then
42
+ args=("--depth=1" "--recurse-submodules")
43
+ fi
44
+ # GIT_TERMINAL_PROMPT=0: if the repo is missing/private/renamed, git
45
+ # normally falls back to an interactive username/password prompt over
46
+ # HTTPS instead of failing - which hangs a non-interactive batch run
47
+ # (theamify get --all) forever waiting on stdin. With this set, git
48
+ # fails fast instead.
49
+ # >&2 (not 2>&1): git_clone() is called from inside get_repo(), whose
50
+ # own stdout is captured via $(...) to obtain the repo path. Anything
51
+ # git writes to fd1 here would silently become part of that captured
52
+ # string, so we always send it to the terminal directly instead.
53
+ if ! GIT_TERMINAL_PROMPT=0 git clone "${args[@]}" "${url}" "${dest}" >&2; then
54
+ print_error "git clone failed for: ${url}"
55
+ return 1
56
+ fi
57
+ }
58
+
59
+ repo_url_to_id() {
60
+ local url="${1}"
61
+ echo "${url}" \
62
+ | sed 's|https://github\.com/||;s|https://gitlab\.com/||' \
63
+ | sed 's|/|__|g' \
64
+ | sed 's|\.git$||' \
65
+ | sed 's|[^a-zA-Z0-9_-]|_|g'
66
+ }
67
+
68
+ get_repo() {
69
+ local url="${1}"
70
+ local force="${2:-false}"
71
+
72
+ local repo_id
73
+ repo_id="$(repo_url_to_id "${url}")"
74
+ local repo_path="${REPO_CACHE_DIR}/${repo_id}"
75
+
76
+ mkdir -p "${REPO_CACHE_DIR}"
77
+
78
+ if [[ -d "${repo_path}" && "${force}" != "true" ]]; then
79
+ log_verbose "Using cached repo: ${repo_id}"
80
+ echo "${repo_path}"
81
+ return 0
82
+ fi
83
+
84
+ [[ -d "${repo_path}" ]] && rm -rf "${repo_path}"
85
+
86
+ # This function's stdout is captured by callers via $(...) to get
87
+ # repo_path back - only the final `echo "${repo_path}"` below may ever
88
+ # touch fd1. Every status message in between is sent to stderr (>&2)
89
+ # explicitly so it prints to the terminal instead of getting silently
90
+ # appended to the returned path.
91
+ print_step "Cloning: ${url}" >&2
92
+ spinner_start "Downloading"
93
+ if git_clone "${url}" "${repo_path}"; then
94
+ spinner_stop
95
+ print_success "Repository cloned." >&2
96
+ else
97
+ spinner_stop
98
+ print_error "Clone failed: ${url}"
99
+ return 1
100
+ fi
101
+
102
+ echo "${repo_path}"
103
+ }
104
+
105
+ find_theme_txt() {
106
+ local dir="${1}"
107
+ [[ -f "${dir}/theme.txt" ]] && echo "${dir}/theme.txt" && return 0
108
+ local found
109
+ found="$(find "${dir}" -maxdepth 3 -name "theme.txt" -type f 2>/dev/null | sort | head -1 || true)"
110
+ [[ -n "${found}" ]] && echo "${found}" && return 0
111
+ return 1
112
+ }
113
+
114
+ open_url() {
115
+ local url="${1}"
116
+ if command -v xdg-open &>/dev/null; then
117
+ xdg-open "${url}" &>/dev/null & disown
118
+ elif command -v sensible-browser &>/dev/null; then
119
+ sensible-browser "${url}" &>/dev/null & disown
120
+ elif command -v firefox &>/dev/null; then
121
+ firefox "${url}" &>/dev/null & disown
122
+ elif command -v chromium-browser &>/dev/null; then
123
+ chromium-browser "${url}" &>/dev/null & disown
124
+ else
125
+ print_warning "No browser found. Open manually: ${url}"
126
+ return 1
127
+ fi
128
+ print_info "Opened in browser."
129
+ }
130
+
131
+ log_verbose() {
132
+ [[ "${OPT_VERBOSE:-false}" == "true" ]] && print_dim " [verbose] ${*}" >&2 || true
133
+ }
134
+
135
+ inc() { eval "${1}=$(( ${!1} + 1 ))"; }