Skip to content

Instantly share code, notes, and snippets.

@nilium
Last active January 6, 2019 05:15
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nilium/9ece98f861474c8dc6acc948518299a5 to your computer and use it in GitHub Desktop.
Save nilium/9ece98f861474c8dc6acc948518299a5 to your computer and use it in GitHub Desktop.
Short script to upload a file to a GCS bucket and print its public URL
#!/usr/bin/env bash
prog="$(basename "$0")"
## Defaults
# : ${FUP_BUCKET:=YOUR-BUCKET}
# : ${FUP_URL_PREFIX:=https://CUSTOM-URL/}
: ${FUP_PAR_UPLOAD_THRESHOLD:=100M}
: ${FUP_URL_PREFIX:=https://storage.googleapis.com/${FUP_BUCKET}/}
## Support functions
usage() {
cat <<EOF
Usage: ${prog} [OPTIONS] [--] [FILE...]
Upload a file to a Google Cloud Storage bucket with a SHA2 base64
directory prefix. If file is '-' (or /dev/stdin), or no file is given,
fup will read stdin to a temporary file and upload it as a 'stdin' file.
You can set the FUP_BUCKET and FUP_SHASUM environment variables to
declare a default bucket (-b) and shasum program (-c). FUP_SHASUM
defaults to the first available of shasum, sha224sum, or sha3-224sum.
Other environment variables are listed in the options below.
Options:
-b <BUCKET> Set the bucket to copy files to. Can have a path prefix.
Required if FUP_BUCKET is not set. May not contain
a trailing slash.
-c <PROG> Program command-line for computing a checksum from a file.
Must output one line in shasum format.
Defaults to a sha224sum program if FUP_SHASUM is not set.
-t <THR> Sets the parallel upload threshold used by gsutil.
Defaults to 100M if FUP_PAR_UPLOAD_THRESHOLD is not set.
-u <URL> Set the URL prefix printed by $prog.
Defaults to the Google storage bucket's URL if
FUP_URL_PREFIX is not set.
-p Copy file URL(s) to clipboard.
-P Do not copy file URL(s) to clipboard (default).
Overrides previous uses of -p.
-v Emit gsutil progress output.
-V Do not emit gsuitl progress output (default).
Overrides previous uses of -v.
-h, --help Print this usage text.
EOF
exit 2
}
FATAL() {
local ec="$1"
shift
echo 'ERR' "$@" 1>&2
exit "$ec"
}
bsum() {
if ! sum="$($FUP_SHASUM "$@")"; then
return 1
fi
echo -n "$sum" |
awk '{print $1}' |
xxd -r -p | base64 |
tr /+ _- | tr -d = |
sed -e 's/^\(.\)\(.\)/\1\/\2\//'
}
upload() {
local desc="$1"
local file="${desc%%:*}"
local istmp=0
# Special case standard input
if [[ "$file" = - ]] || [[ "$file" = /dev/stdin ]]; then
istmp=1
if ! file="$(mktemp)"; then
FATAL 1 "Cannot create temporary file for standard input"
fi
cat > "$file"
desc=stdin
fi
if [[ ! -f "$file" ]]; then
FATAL 1 "Cannot upload non-file: $file"
fi
local name="$(basename "${desc#*:}")"
if ! sum="$(bsum "$file" | awk '{print $1}')"; then
FATAL 1 "Unable to get the checksum of $name"
fi
local path="${sum}/$name"
local gspath="gs://$FUP_BUCKET/$path"
if ! gsutil $quiet -o "GSUtil:parallel_composite_upload_threshold=$FUP_PAR_UPLOAD_THRESHOLD" cp -- "$file" "$gspath" 1>&2; then
FATAL 1 "Unable to upload $name"
fi
if ! gsutil $quiet acl ch -u AllUsers:R "$gspath" 1>&2; then
if [[ "$istemp" = 1 ]] && [[ -f "$file" ]]; then
rm "$file"
fi
FATAL 1 "Unable to set ACL on $gspath to publicly readable"
fi
if [[ "$istemp" = 1 ]] && [[ -f "$file" ]]; then
rm "$file"
fi
printf '%s%s%s' "$FUP_URL_PREFIX" "$path"
}
## Main
if [[ -z "$(command -v gsutil)" ]]; then
FATAL 1 $'gsutil not found in PATH. Please install the Google Cloud SDK:\n\n\thttps://cloud.google.com/sdk/install'
fi
tmpout=/dev/null
pasteprefix=
paste=0
quiet=-q
while [ $# -gt 0 ]; do
case "$1" in
-b) FUP_BUCKET="$2"; shift;;
-b=*) FUP_BUCKET="${1#-b=}";;
-b?*) FUP_BUCKET="${1#-b}";;
-c) FUP_SHASUM="$2"; shift;;
-c=*) FUP_SHASUM="${1#-c=}";;
-c?*) FUP_SHASUM="${1#-c}";;
-t) FUP_PAR_UPLOAD_THRESHOLD="$2"; shift;;
-t=*) FUP_PAR_UPLOAD_THRESHOLD="${1#-t=}";;
-t?*) FUP_PAR_UPLOAD_THRESHOLD="${1#-t}";;
-u) FUP_URL_PREFIX="$2"; shift;;
-u=*) FUP_URL_PREFIX="${1#-u=}";;
-u?*) FUP_URL_PREFIX="${1#-u}";;
# Toggles
-p) paste=1;;
-P) paste=0;;
-v) quiet=;;
-V) quiet=-q;;
-h|--help) usage;;
--) shift; break;;
*) break;;
esac
shift
done
if [[ -z "$FUP_BUCKET" ]]; then
FATAL 2 'FUP_BUCKET is not set -- it must be set to a GCS bucket name'
elif [[ "$FUP_BUCKET" = */ ]]; then
FATAL 2 'FUP_BUCKET may not contain a trailing slash'
fi
# Set default shasum
if [ -z "$FUP_SHASUM" ]; then
if [ -n "$(command -v sha224sum)" ]; then
FUP_SHASUM='sha224sum'
elif [ -n "$(command -v gsha224sum)" ]; then
FUP_SHASUM='gsha224sum'
elif [ -n "$(command -v shasum)" ]; then
FUP_SHASUM='shasum -a224'
elif [ -n "$(command -v sha3-224sum)" ]; then
# Just because we want something with some length here
FUP_SHASUM=sha3-224sum
else
FATAL 1 'None of sha224sum, shasum, nor sha3-224sum are available'
fi
fi
if [[ $# -eq 0 ]]; then
set -- -
fi
if [[ "$1" = -p ]]; then
shift
paste=1
fi
if [[ $paste -eq 1 ]]; then
if ! tmpout="$(mktemp)"; then
FATAL 1 "Cannot create temporary URLs file"
fi
trap 'rm "$tmpout"' EXIT
fi
for file; do
if ! url="$(upload "$file")"; then
FATAL 1 "Upload failed: $file"
fi
echo "$url"
if [[ $paste -eq 1 ]]; then
printf "%s%s" "$pasteprefix" "$url" >>"$tmpout"
pasteprefix=$'\n'
fi
done
if [[ $paste -eq 1 ]]; then
# TODO: Add checks for x11 clipboard managers
<"$tmpout" pbcopy
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment