1#!/usr/bin/env bash
2
3# Environment
4
5## Early-start global variables
6
7### Permutation
8
9_start="$(atfile.util.get_date "" "%s")" # 1
10_envvar_prefix="ATFILE" # 2
11_debug="$(atfile.util.get_envvar "${_envvar_prefix}_DEBUG" "$([[ $ATFILE_DEVEL == 1 ]] && echo 1 || echo 0)")" # 3
12_force_os="$(atfile.util.get_envvar "${_envvar_prefix}_FORCE_OS")" # 3
13
14### Combination
15
16_ci="$(atfile.util.get_ci)"
17_command="$1"
18_command_args=("${@:2}")
19_os="$(atfile.util.get_os)"
20_os_supported=0
21_is_piped=0
22_is_sourced=0
23_meta_author="{:meta_author:}"
24_meta_did="{:meta_did:}"
25_meta_repo="{:meta_repo:}"
26_meta_year="{:meta_year:}"
27_now="$(atfile.util.get_date)"
28_path_hook_post_start="$(atfile.util.get_envvar "${_envvar_prefix}_PATH_HOOK_POST_START")"
29_path_hook_pre_exit="$(atfile.util.get_envvar "${_envvar_prefix}_PATH_HOOK_PRE_EXIT")"
30_path_hook_pre_start="$(atfile.util.get_envvar "${_envvar_prefix}_PATH_HOOK_PRE_START")"
31_version="{:version:}"
32
33## "Hello, world!"
34
35atfile.say.debug "Reticulating splines..."
36atfile.util.source_hook "$_path_hook_pre_start"
37
38## Paths
39
40_path_home="$HOME"
41
42if [[ -n "$SUDO_USER" ]]; then
43 _path_home="$(eval echo "~$SUDO_USER")"
44fi
45
46_file_envvar="atfile.env"
47_path_blobs_tmp="/tmp"
48_path_cache="$_path_home/.cache"
49_path_envvar="$_path_home/.config"
50
51case $_os in
52 "haiku")
53 _path_blobs_tmp="/boot/system/cache/tmp"
54 _path_cache="$_path_home/config/cache"
55 _path_envvar="$_path_home/config/settings"
56 ;;
57 "linux-termux")
58 _path_blobs_tmp="$PREFIX/tmp"
59 ;;
60 "macos")
61 _path_envvar="$_path_home/Library/Application Support"
62 _path_blobs_tmp="/private/tmp"
63 ;;
64esac
65
66if [[ -n "$XDG_CONFIG_HOME" ]]; then
67 _path_envvar="$XDG_CONFIG_HOME"
68fi
69
70_path_blobs_tmp="$_path_blobs_tmp/at-blobs"
71_path_cache="$_path_cache/atfile"
72_path_envvar="$(atfile.util.get_envvar "${_envvar_prefix}_PATH_CONF" "$_path_envvar/$_file_envvar")"
73
74## OS detection
75
76atfile.say.debug "Detected OS: $_os"
77
78if [[ $_os != "unknown-"* ]] &&\
79 [[ $_os == "bsd" ]] ||\
80 [[ $_os == "haiku" ]] ||\
81 [[ $_os == "linux" ]] ||\
82 [[ $_os == "linux-mingw" ]] ||\
83 [[ $_os == "linux-termux" ]] ||\
84 [[ $_os == "macos" ]] ; then
85 _os_supported=1
86fi
87
88## CI detection
89
90[[ -n "$_ci" ]] && atfile.say.debug "Detected CI: $_ci"
91
92## Pipe detection
93
94if [ -p /dev/stdin ] ||\
95 [[ "$0" == "bash" || $0 == *"/bin/bash" ]]; then
96 _is_piped=1
97 atfile.say.debug "Piping: $0"
98fi
99
100## Source detection
101
102if [[ -n ${BASH_SOURCE[0]} ]]; then
103 if [[ "$0" != "${BASH_SOURCE[0]}" ]]; then
104 if [[ "$ATFILE_DEVEL" == 1 ]]; then
105 if [[ -n "$ATFILE_DEVEL_SOURCE" ]]; then
106 _is_sourced=1
107 atfile.say.debug "Sourcing: $ATFILE_DEVEL_SOURCE"
108 fi
109 else
110 _is_sourced=1
111 atfile.say.debug "Sourcing: ${BASH_SOURCE[0]}"
112 fi
113 fi
114fi
115
116# Installation
117
118if [[ $_is_piped == 1 ]] ||\
119 [[ "$1" == "install" ]]; then
120 atfile.util.source_hook "$_path_hook_post_start"
121
122 if [[ "$1" == "install" ]]; then
123 atfile.install "$2" "$3" "$4"
124 install_exit="$?"
125 else
126 atfile.install "$1" "$2" "$3"
127 install_exit="$?"
128 fi
129
130 atfile.util.source_hook "$_path_hook_pre_exit"
131 atfile.util.print_seconds_since_start_debug
132
133 exit $install_exit
134fi
135
136# Global variables
137
138## Reflection
139
140_prog="$(basename "$(atfile.util.get_realpath "$0")")"
141_prog_dir="$(dirname "$(atfile.util.get_realpath "$0")")"
142_prog_path="$(atfile.util.get_realpath "$0")"
143
144## Envvars
145
146### Fallbacks
147
148_max_list_fallback=100
149
150### Defaults
151
152_devel_dist_username_default="$_meta_did"
153_devel_enable_publish_default=0
154_disable_auth_check_default=0
155_disable_ni_exiftool_default=0
156_disable_ni_md5sum_default=0
157_disable_ni_mediainfo_default=0
158_disable_setup_dir_creation_default=0
159_disable_unsupported_os_warn_default=0
160_disable_update_checking_default=0
161_disable_update_command_default=0
162_enable_fingerprint_default=0
163_enable_update_git_clobber_default=0
164#_endpoint_appview_default="https://bsky.zio.blue"
165_endpoint_appview_default="https://api.bsky.app"
166#_endpoint_jetstream_default="wss://stream.zio.blue"
167_endpoint_jetstream_default="$(atfile.util.get_random_pbc_jetstream)"
168_endpoint_pdsls_default="https://pdsls.dev"
169_endpoint_plc_directory_default="https://plc.zio.blue"
170_endpoint_social_app_default="https://bsky.app"
171_fmt_blob_url_default="[server]/xrpc/com.atproto.sync.getBlob?did=[did]&cid=[cid]"
172_fmt_out_file_default="[key]__[name]"
173_enable_fingerprint_default=0
174_max_list_buffer=6
175_max_list_default=$(( $(atfile.util.get_term_rows) - _max_list_buffer ))
176_output_json_default=0
177
178### Set
179
180_devel_dist_password="$(atfile.util.get_envvar "${_envvar_prefix}_DEVEL_DIST_PASSWORD")"
181_devel_dist_username="$(atfile.util.get_envvar "${_envvar_prefix}_DEVEL_DIST_USERNAME" $_devel_dist_username_default)"
182_devel_enable_publish="$(atfile.util.get_envvar "${_envvar_prefix}_DEVEL_ENABLE_PUBLISH" $_devel_enable_publish_default)"
183_disable_auth_check="$(atfile.util.get_envvar "${_envvar_prefix}_DISABLE_AUTH_CHECK" "$_disable_auth_check_default")"
184_disable_ni_exiftool="$(atfile.util.get_envvar "${_envvar_prefix}_DISABLE_NI_EXIFTOOL" "$_disable_ni_exiftool_default")"
185_disable_ni_md5sum="$(atfile.util.get_envvar "${_envvar_prefix}_DISABLE_NI_MD5SUM" "$_disable_ni_md5sum_default")"
186_disable_ni_mediainfo="$(atfile.util.get_envvar "${_envvar_prefix}_DISABLE_NI_MEDIAINFO" "$_disable_ni_mediainfo_default")"
187_disable_setup_dir_creation="$(atfile.util.get_envvar "${_envvar_prefix}_DISABLE_SETUP_DIR_CREATION" "$_disable_setup_dir_creation_default")"
188_disable_unsupported_os_warn="$(atfile.util.get_envvar "${_envvar_prefix}_DISABLE_UNSUPPORTED_OS_WARN" "$_disable_unsupported_os_warn_default")"
189_disable_update_checking="$(atfile.util.get_envvar "${_envvar_prefix}_DISABLE_UPDATE_CHECKING" $_disable_update_checking_default)"
190_disable_update_command="$(atfile.util.get_envvar "${_envvar_prefix}_DISABLE_UPDATE_COMMAND" $_disable_update_command_default)"
191_enable_fingerprint="$(atfile.util.get_envvar "${_envvar_prefix}_ENABLE_FINGERPRINT" "$_enable_fingerprint_default")"
192_enable_update_git_clobber="$(atfile.util.get_envvar "${_envvar_prefix}_ENABLE_UPDATE_GIT_CLOBBER" "$_enable_update_git_clobber_default")"
193_endpoint_appview="$(atfile.util.get_envvar "${_envvar_prefix}_ENDPOINT_APPVIEW" "$_endpoint_appview_default")"
194_endpoint_jetstream="$(atfile.util.get_envvar "${_envvar_prefix}_ENDPOINT_JETSTREAM" "$_endpoint_jetstream_default")"
195_endpoint_pdsls="$(atfile.util.get_envvar "${_envvar_prefix}_ENDPOINT_PDSLS" "$_endpoint_pdsls_default")"
196_endpoint_plc_directory="$(atfile.util.get_envvar "${_envvar_prefix}_ENDPOINT_PLC_DIRECTORY" "$_endpoint_plc_directory_default")"
197_endpoint_social_app="$(atfile.util.get_envvar "${_envvar_prefix}_ENDPOINT_SOCIAL_APP" "$_endpoint_social_app_default")"
198_fmt_blob_url="$(atfile.util.get_envvar "${_envvar_prefix}_FMT_BLOB_URL" "$_fmt_blob_url_default")"
199_fmt_out_file="$(atfile.util.get_envvar "${_envvar_prefix}_FMT_OUT_FILE" "$_fmt_out_file_default")"
200_force_meta_author="$(atfile.util.get_envvar "${_envvar_prefix}_FORCE_META_AUTHOR")"
201_force_meta_did="$(atfile.util.get_envvar "${_envvar_prefix}_FORCE_META_DID")"
202_force_meta_repo="$(atfile.util.get_envvar "${_envvar_prefix}_FORCE_META_REPO")"
203_force_meta_year="$(atfile.util.get_envvar "${_envvar_prefix}_FORCE_META_YEAR")"
204_force_now="$(atfile.util.get_envvar "${_envvar_prefix}_FORCE_NOW")"
205_force_version="$(atfile.util.get_envvar "${_envvar_prefix}_FORCE_VERSION")"
206_max_list="$(atfile.util.get_envvar "${_envvar_prefix}_MAX_LIST" "$_max_list_default")"
207_output_json="$(atfile.util.get_envvar "${_envvar_prefix}_OUTPUT_JSON" "$_output_json_default")"
208_server="$(atfile.util.get_envvar "${_envvar_prefix}_ENDPOINT_PDS")"
209_password="$(atfile.util.get_envvar "${_envvar_prefix}_PASSWORD")"
210_test_desktop_uas="Mozilla/5.0 (X11; Linux x86_64; rv:128.0) Gecko/20100101 Firefox/128.0"
211_username="$(atfile.util.get_envvar "${_envvar_prefix}_USERNAME")"
212
213## Read-only
214
215_nsid_prefix="blue.zio"
216_nsid_lock="${_nsid_prefix}.atfile.lock"
217_nsid_meta="${_nsid_prefix}.atfile.meta"
218_nsid_upload="${_nsid_prefix}.atfile.upload"
219_endpoint_pdsls_name="PDSls"
220_endpoint_social_app_name="Bluesky"
221
222# Setup
223
224## Envvar correction
225
226### Overrides
227
228[[ -n $_force_meta_author ]] && \
229 _meta_author="$_force_meta_author" &&\
230 atfile.util.print_override_envvar_debug "Copyright Author" "_meta_author"
231[[ -n $_force_meta_did ]] && \
232 _meta_did="$_force_meta_did" &&\
233 _devel_dist_username="$(atfile.util.get_envvar "${_envvar_prefix}_DEVEL_DIST_USERNAME" "$_meta_did")" &&\
234 atfile.util.print_override_envvar_debug "DID" "_meta_did"
235[[ -n $_force_meta_repo ]] && \
236 _meta_repo="$_force_meta_repo" &&\
237 atfile.util.print_override_envvar_debug "Repo URL" "_meta_author"
238[[ -n $_force_meta_year ]] && \
239 _meta_year="$_force_meta_year" &&\
240 atfile.util.print_override_envvar_debug "Copyright Year" "_meta_year"
241[[ -n $_force_now ]] && \
242 _now="$_force_now" &&\
243 atfile.util.print_override_envvar_debug "Current Time" "_now"
244[[ -n $_force_os ]] &&\
245 _os="$_force_os" &&\
246 atfile.util.print_override_envvar_debug "OS" "_os"
247[[ -n $_force_version ]] && \
248 _version="$_force_version" &&\
249 atfile.util.print_override_envvar_debug "Version" "_version"
250
251if [[ $_endpoint_appview != "$_endpoint_appview_default" ]] &&\
252 [[ $_endpoint_social_app == "$_endpoint_social_app_default" ]]; then
253 case "$_endpoint_appview" in
254 "https://bsky.zeppelin.social") _endpoint_social_app="https://zeppelin.social" ;;
255 esac
256fi
257
258case "$_endpoint_social_app" in
259 "https://blacksky.community") _endpoint_social_app_name="Blacksky" ;;
260 "https://deer.social") _endpoint_social_app_name="Deer" ;;
261 "https://zeppelin.social") _endpoint_social_app_name="Zeppelin" ;;
262esac
263
264### Validation
265
266[[ $_output_json == 1 ]] && [[ $_max_list == "$_max_list_default" ]] &&\
267 atfile.say.debug "Setting ${_envvar_prefix}_MAX_LIST to $_max_list_fallback\n↳ ${_envvar_prefix}_OUTPUT_JSON set to 1" &&\
268 _max_list=$_max_list_fallback
269[[ $(( _max_list > _max_list_fallback )) == 1 ]] &&\
270 atfile.say.debug "Setting ${_envvar_prefix}_MAX_LIST to $_max_list_fallback\n↳ Maximum is $_max_list_fallback" &&\
271 _max_list=$_max_list_fallback
272
273## OS detection
274
275if [[ $_os_supported == 0 ]]; then
276 if [[ $_disable_unsupported_os_warn == 0 ]]; then
277 atfile.die "Unsupported OS (${_os//unknown-/})\n↳ Set ${_envvar_prefix}_DISABLE_UNSUPPORTED_OS_WARN=1 to ignore"
278 else
279 atfile.say.debug "Ignoring unsupported OS warning\n↳ ${_envvar_prefix}_DISABLE_UNSUPPORTED_OS_WARN set to '$_disable_unsupported_os_warn'"
280 fi
281fi
282
283## Program detection
284
285_prog_hint_jq="https://jqlang.github.io/jq"
286
287[[ "$_os" == "haiku" ]] && _prog_hint_jq="pkgman install jq"
288
289atfile.util.check_prog "curl" "https://curl.se"
290[[ $_os != "haiku" && $_os != "solaris" ]] && atfile.util.check_prog "file" "https://www.darwinsys.com/file"
291atfile.util.check_prog "jq" "$_prog_hint_jq"
292[[ $_disable_ni_md5sum == 0 ]] && atfile.util.check_prog "md5sum" "" "${_envvar_prefix}_DISABLE_NI_MD5SUM"
293#[[ $_os == "haiku" ]] && atfile.util.check_prog "perl"
294
295# Main
296
297## Command aliases
298
299if [[ $_is_sourced == 0 ]]; then
300 previous_command="$_command"
301
302 case "$_command" in
303 "release") _command="build" ;;
304 "open"|"print"|"c") _command="cat" ;;
305 "rm") _command="delete" ;;
306 "download"|"f"|"d") _command="fetch" ;;
307 "download-crypt"|"fc"|"dc") _command="fetch-crypt" ;;
308 "at") _command="handle" ;;
309 "--help"|"-h") _command="help" ;;
310 "get"|"i") _command="info" ;;
311 "ls") _command="list" ;;
312 "did") _command="resolve" ;;
313 "sb") _command="something-broke" ;;
314 "js") _command="stream" ;;
315 "ul"|"u") _command="upload" ;;
316 "--update"|"-U") _command="update" ;;
317 "ub") _command="upload-blob" ;;
318 "uc") _command="upload-crypt" ;;
319 "get-url"|"b") _command="url" ;;
320 "--version"|"-V") _command="version" ;;
321 esac
322
323 if [[ $previous_command != "$_command" ]]; then
324 atfile.say.debug "Using command '$_command' for '$previous_command'..."
325 fi
326fi
327
328## Defaults
329
330[[ $_is_sourced == 0 && -z $_command ]] && _command="help"
331
332if [[ "$_command" == "atfile:"* || "$_command" == "at:"* || "$_command" == "https:"* ]]; then
333 _command="handle"
334 _command_args=("$1")
335 atfile.say.debug "Handling '${_command_args[*]}'..."
336fi
337
338## Invoke
339
340atfile.util.source_hook "$_path_hook_post_start"
341
342if [[ $_is_sourced == 0 ]]; then
343 atfile.auth
344 atfile.invoke "$_command" "${_command_args[@]}"
345fi
346
347atfile.util.source_hook "$_path_hook_pre_exit"
348atfile.util.print_seconds_since_start_debug