Skip to content

added install script #71

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Mar 4, 2025
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,11 @@ Spaces are sovereign Bitcoin identities. They leverage the existing infrastructu

## Quick Start

Check out the [documentation](https://docs.spacesprotocol.org)
Install the latest version:
```bash
curl -sSf https://raw.githubusercontent.com/spacesprotocol/spaces/main/install.sh | sudo sh
```


## Development setup on testnet4

Expand Down Expand Up @@ -75,4 +79,4 @@ spaced --chain testnet4 --bitcoin-rpc-user testnet4 --bitcoin-rpc-password testn

## License

Spaces is released under the terms of the MIT license. See LICENSE for more information or see https://opensource.org/licenses/MIT.
Spaces is released under the terms of the MIT license. See LICENSE for more information or see https://opensource.org/licenses/MIT.
263 changes: 263 additions & 0 deletions install.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,263 @@
#!/usr/bin/env sh
set -eu
(set -o pipefail 2>/dev/null) && set -o pipefail

help() {
cat <<'EOF'
Install spaces binaries (spaced and space-cli) from GitHub releases.

USAGE:
install.sh [options]

FLAGS:
-h, --help Display this message
-f, --force Force overwriting existing binaries
-v, --verbose Show detailed output

OPTIONS:
--tag VERSION Specific version to install (e.g., 0.0.6a), defaults to latest release
--to LOCATION Where to install the binaries (default: auto-detected based on OS)
For macOS: ~/.local/bin if exists, else ~/bin
For Linux: ~/.local/bin

NOTES:
The script will automatically choose an appropriate user-writable location.
The chosen directory will be added to your PATH if needed.
EOF
}

say() {
echo "install: $*" >&2
}

err() {
if [ -n "${td-}" ]; then
rm -rf "$td"
fi
say "error: $*"
say "run './install.sh --help' to see available options"
exit 1
}

need() {
if ! command -v "$1" > /dev/null 2>&1; then
err "need $1 (command not found)"
fi
}

add_to_path() {
local install_dir="$1"
local shell_rc
local reload_needed=false

# Detect shell configuration file
if [ -n "${ZSH_VERSION-}" ]; then
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

$ZSH_VERSION is only set when you're actually running zsh as your interactive shell but the script executes in sh/bash env. Maybe use $SHELL (returns /bin/zsh for me) or just check if its macos.

shell_rc="$HOME/.zshrc"
shell_type="zsh"
else
shell_type="bash"
shell_rc="$HOME/.bashrc"
[ "$(uname -s)" = "Darwin" ] && shell_rc="$HOME/.bash_profile"
fi

if ! echo "$PATH" | tr ':' '\n' | grep -Fq "$install_dir"; then
say "Adding $install_dir to PATH in $shell_rc"
echo "export PATH=\"$install_dir:\$PATH\"" >> "$shell_rc"
reload_needed=true
fi

# Return whether reload is needed
[ "$reload_needed" = true ] && echo "reload" || echo "noreload"
}

determine_install_dir() {
local os="$1"
local specified_dir="$2"
local install_dir

if [ -n "$specified_dir" ]; then
install_dir="$specified_dir"
else
case "$os" in
darwin)
if [ -d "$HOME/.local/bin" ]; then
install_dir="$HOME/.local/bin"
else
install_dir="$HOME/bin"
fi
;;
linux)
install_dir="$HOME/.local/bin"
;;
*)
err "unsupported operating system: $os"
;;
esac
fi

# Create directory if it doesn't exist
if [ ! -d "$install_dir" ]; then
mkdir -p "$install_dir" || err "failed to create $install_dir"
fi

echo "$install_dir"
}

download() {
url="$1"
output="$2"
if command -v curl > /dev/null; then
if [ "$output" = "-" ]; then
curl --proto =https --tlsv1.2 -sSfL "$url"
else
curl --proto =https --tlsv1.2 -sSfL "$url" -o "$output"
fi
else
wget --https-only --secure-protocol=TLSv1_2 --quiet "$url" -O "$output"
fi
}

# Initialize default values
force=false
verbose=false
dest=""
tag=""
td=""

# Process command line arguments
while test $# -gt 0; do
case $1 in
--force | -f)
force=true
;;
--help | -h)
help
exit 0
;;
--verbose | -v)
verbose=true
;;
--tag)
tag="$2"
shift
;;
--to)
dest="$2"
shift
;;
*)
say "error: unrecognized argument '$1'"
help
exit 1
;;
esac
shift
done

# Check for required commands
command -v curl > /dev/null 2>&1 || command -v wget > /dev/null 2>&1 || err "need wget or curl"
need mktemp
need tar

# Detect OS and architecture
os=$(uname -s | tr '[:upper:]' '[:lower:]')
arch=$(uname -m)

# Map architecture to match release files
case "$arch" in
x86_64) arch="x86_64" ;;
aarch64|arm64) arch="arm64" ;;
*) err "unsupported architecture: $arch" ;;
esac

# Determine installation directory
dest=$(determine_install_dir "$os" "$dest")
[ "$verbose" = true ] && say "installing to: $dest"

# Get latest version if not specified
if [ -z "$tag" ]; then
[ "$verbose" = true ] && say "fetching latest release version..."
api_response=$(download "https://api.github.com/repos/spacesprotocol/spaces/releases/latest" - || echo "failed")
if [ "$api_response" = "failed" ]; then
err "could not fetch release information from GitHub"
fi

tag=$(echo "$api_response" | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/')
if [ -z "$tag" ]; then
err "no releases found in the repository"
fi
fi

# Standardize tag format
tag_without_v="${tag#v}" # Remove 'v' prefix if present
check_tag="v$tag_without_v" # Add 'v' prefix for consistency

# Verify the tag exists
[ "$verbose" = true ] && say "verifying tag $check_tag exists..."
api_response=$(download "https://api.github.com/repos/spacesprotocol/spaces/releases/tags/$check_tag" - || echo "failed")
if [ "$api_response" = "failed" ] || echo "$api_response" | grep -q "Not Found"; then
err "release tag '$check_tag' not found"
fi

[ -z "$tag_without_v" ] && err "could not determine version to install"

[ "$verbose" = true ] && say "installing spaces version $check_tag"

# Create temporary directory
td=$(mktemp -d || mktemp -d -t tmp)
trap 'rm -rf "$td"' EXIT

# Construct download URL
download_url="https://github.com/spacesprotocol/spaces/releases/download/$check_tag/spaces-$check_tag-${os}-${arch}.tar.gz"

[ "$verbose" = true ] && say "downloading from: $download_url"

# Download and extract
download "$download_url" "$td/spaces.tar.gz" || err "download failed"
tar xzf "$td/spaces.tar.gz" -C "$td" || err "failed to extract archive"

# Install binaries
for binary in spaced space-cli; do
if [ -f "$dest/$binary" ] && [ "$force" = false ]; then
err "Found existing spaces executables at $dest. Use --force flag to overwrite"
fi

binary_path="$dest/$binary"
if ! find "$td" -type f -name "$binary" -exec cp {} "$binary_path" \; ; then
err "failed to copy $binary to $dest (permission denied)"
fi

if ! chmod 755 "$binary_path"; then
err "failed to set permissions on $binary (permission denied)"
fi

[ "$verbose" = true ] && say "installed $binary to $binary_path"
done

# Verify installation
for binary in spaced space-cli; do
if ! [ -x "$dest/$binary" ]; then
err "installation verification failed for $binary"
fi
done

# Add to PATH if needed and get reload status
reload_status=$(add_to_path "$dest")

# Final instructions
say "Successfully installed spaces $check_tag to $dest"

# Reload shell if needed
if [ "$reload_status" = "reload" ]; then
if [ -n "${ZSH_VERSION-}" ]; then
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same

exec zsh
else
exec bash
fi
fi

# Show versions if verbose
if [ "$verbose" = true ]; then
say "installed version:"
"$dest/spaced" --version
fi
Loading