Skip to content

Commit 3d5982f

Browse files
committed
fix(opencode.ai): Direct download.
1 parent f513f1a commit 3d5982f

File tree

2 files changed

+124
-199
lines changed

2 files changed

+124
-199
lines changed

src/opencode.ai/devcontainer-feature.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "opencode.ai",
33
"id": "opencode.ai",
4-
"version": "0.0.5",
4+
"version": "0.0.6",
55
"description": "Install \"opencode\" binary",
66
"documentationURL": "https://github.com/devcontainer-community/devcontainer-features/tree/main/src/opencode.ai",
77
"options": {

src/opencode.ai/install.sh

Lines changed: 123 additions & 198 deletions
Original file line numberDiff line numberDiff line change
@@ -1,207 +1,132 @@
1-
#!/usr/bin/env bash
2-
set -euo pipefail
3-
APP=opencode
4-
5-
RED='\033[0;31m'
6-
GREEN='\033[0;32m'
7-
YELLOW='\033[1;33m'
8-
ORANGE='\033[38;2;255;140;0m'
9-
NC='\033[0m' # No Color
10-
11-
requested_version=${VERSION:-}
12-
if [[ "$requested_version" == "latest" ]]; then
13-
requested_version=""
14-
fi
15-
16-
os=$(uname -s | tr '[:upper:]' '[:lower:]')
17-
if [[ "$os" == "darwin" ]]; then
18-
os="darwin"
19-
fi
20-
arch=$(uname -m)
21-
22-
if [[ "$arch" == "aarch64" ]]; then
23-
arch="arm64"
24-
elif [[ "$arch" == "x86_64" ]]; then
25-
arch="x64"
26-
fi
27-
28-
filename="$APP-$os-$arch.zip"
29-
30-
31-
case "$filename" in
32-
*"-linux-"*)
33-
[[ "$arch" == "x64" || "$arch" == "arm64" ]] || exit 1
34-
;;
35-
*"-darwin-"*)
36-
[[ "$arch" == "x64" || "$arch" == "arm64" ]] || exit 1
37-
;;
38-
*"-windows-"*)
39-
[[ "$arch" == "x64" ]] || exit 1
40-
;;
41-
*)
42-
echo -e "${RED}Unsupported OS/Arch: $os/$arch${NC}"
43-
exit 1
44-
;;
45-
esac
46-
47-
# Set installation directory based on whether script is run as root
48-
if [[ $EUID -eq 0 ]]; then
49-
INSTALL_DIR="/usr/local/bin"
50-
else
51-
INSTALL_DIR="$HOME/.opencode/bin"
52-
fi
53-
mkdir -p "$INSTALL_DIR"
54-
55-
if [ -z "$requested_version" ]; then
56-
url="https://github.com/sst/opencode/releases/latest/download/$filename"
57-
specific_version=$(curl -s https://api.github.com/repos/sst/opencode/releases/latest | awk -F'"' '/"tag_name": "/ {gsub(/^v/, "", $4); print $4}')
58-
59-
if [[ $? -ne 0 || -z "$specific_version" ]]; then
60-
echo -e "${RED}Failed to fetch version information${NC}"
61-
exit 1
1+
#!/bin/bash
2+
set -o errexit
3+
set -o pipefail
4+
set -o noclobber
5+
set -o nounset
6+
set -o allexport
7+
readonly githubRepository='sst/opencode'
8+
readonly binaryName='opencode'
9+
readonly versionArgument='--version'
10+
readonly downloadUrlTemplate='https://github.com/${githubRepository}/releases/download/v${version}/${name}-linux-${architecture}.zip'
11+
readonly binaryTargetFolder='/usr/local/bin'
12+
readonly name="${githubRepository##*/}"
13+
apt_get_update() {
14+
if [ "$(find /var/lib/apt/lists/* | wc -l)" = "0" ]; then
15+
echo "Running apt-get update..."
16+
apt-get update -y
17+
fi
18+
}
19+
apt_get_checkinstall() {
20+
if ! dpkg -s "$@" >/dev/null 2>&1; then
21+
apt_get_update
22+
DEBIAN_FRONTEND=noninteractive apt-get -y install --no-install-recommends --no-install-suggests --option 'Debug::pkgProblemResolver=true' --option 'Debug::pkgAcquire::Worker=1' "$@"
23+
fi
24+
}
25+
apt_get_cleanup() {
26+
apt-get clean
27+
rm -rf /var/lib/apt/lists/*
28+
}
29+
check_curl_envsubst_file_unzip_installed() {
30+
declare -a requiredAptPackagesMissing=()
31+
if ! [ -r '/etc/ssl/certs/ca-certificates.crt' ]; then
32+
requiredAptPackagesMissing+=('ca-certificates')
33+
fi
34+
if ! command -v curl >/dev/null 2>&1; then
35+
requiredAptPackagesMissing+=('curl')
36+
fi
37+
if ! command -v envsubst >/dev/null 2>&1; then
38+
requiredAptPackagesMissing+=('gettext-base')
39+
fi
40+
if ! command -v file >/dev/null 2>&1; then
41+
requiredAptPackagesMissing+=('file')
42+
fi
43+
if ! command -v unzip >/dev/null 2>&1; then
44+
requiredAptPackagesMissing+=('unzip')
45+
fi
46+
declare -i requiredAptPackagesMissingCount=${#requiredAptPackagesMissing[@]}
47+
if [ $requiredAptPackagesMissingCount -gt 0 ]; then
48+
apt_get_update
49+
apt_get_checkinstall "${requiredAptPackagesMissing[@]}"
50+
apt_get_cleanup
6251
fi
63-
else
64-
url="https://github.com/sst/opencode/releases/download/v${requested_version}/$filename"
65-
specific_version=$requested_version
66-
fi
67-
68-
print_message() {
69-
local level=$1
70-
local message=$2
71-
local color=""
72-
73-
case $level in
74-
info) color="${GREEN}" ;;
75-
warning) color="${YELLOW}" ;;
76-
error) color="${RED}" ;;
77-
esac
78-
79-
echo -e "${color}${message}${NC}"
8052
}
81-
82-
check_version() {
83-
if command -v opencode >/dev/null 2>&1; then
84-
opencode_path=$(which opencode)
85-
86-
87-
## TODO: check if version is installed
88-
# installed_version=$(opencode version)
89-
installed_version="0.0.1"
90-
installed_version=$(echo $installed_version | awk '{print $2}')
91-
92-
if [[ "$installed_version" != "$specific_version" ]]; then
93-
print_message info "Installed version: ${YELLOW}$installed_version."
94-
else
95-
print_message info "Version ${YELLOW}$specific_version${GREEN} already installed"
96-
exit 0
97-
fi
53+
curl_check_url() {
54+
local url=$1
55+
local status_code
56+
status_code=$(curl -s -o /dev/null -w '%{http_code}' "$url")
57+
if [ "$status_code" -ne 200 ] && [ "$status_code" -ne 302 ]; then
58+
echo "Failed to download '$url'. Status code: $status_code."
59+
return 1
9860
fi
9961
}
100-
101-
download_and_install() {
102-
print_message info "Downloading ${ORANGE}opencode ${GREEN}version: ${YELLOW}$specific_version ${GREEN}..."
103-
mkdir -p opencodetmp && cd opencodetmp
104-
curl -# -L -o "$filename" "$url"
105-
unzip -q "$filename"
106-
mv opencode "$INSTALL_DIR"
107-
cd .. && rm -rf opencodetmp
62+
curl_download_stdout() {
63+
local url=$1
64+
curl \
65+
--silent \
66+
--location \
67+
--output '-' \
68+
--connect-timeout 5 \
69+
"$url"
70+
}
71+
curl_download_unzip() {
72+
local url=$1
73+
local strip=$2
74+
local target=$3
75+
local bin_path=$4
76+
local temp_file=$(mktemp)
77+
curl_download_stdout "$url" > "$temp_file"
78+
unzip -j "$temp_file" "$bin_path" -d "$target"
79+
rm "$temp_file"
80+
}
81+
debian_get_arch() {
82+
echo "$(dpkg --print-architecture)"
83+
}
84+
echo_banner() {
85+
local text="$1"
86+
echo -e "\e[1m\e[97m\e[41m$text\e[0m"
10887
}
109-
110-
check_version
111-
download_and_install
112-
113-
# Skip PATH modification if installed to /usr/local/bin (already in PATH)
114-
if [[ "$INSTALL_DIR" == "/usr/local/bin" ]]; then
115-
print_message info "Binary installed to ${ORANGE}/usr/local/bin${GREEN} (already in \$PATH)"
116-
117-
if [ -n "${GITHUB_ACTIONS-}" ] && [ "${GITHUB_ACTIONS}" == "true" ]; then
118-
echo "$INSTALL_DIR" >> $GITHUB_PATH
119-
print_message info "Added $INSTALL_DIR to \$GITHUB_PATH"
88+
github_list_releases() {
89+
if [ -z "$1" ]; then
90+
echo "Usage: list_github_releases <owner/repo>"
91+
return 1
12092
fi
121-
122-
exit 0
123-
fi
124-
125-
add_to_path() {
126-
local config_file=$1
127-
local command=$2
128-
129-
if grep -Fxq "$command" "$config_file"; then
130-
print_message info "Command already exists in $config_file, skipping write."
131-
elif [[ -w $config_file ]]; then
132-
echo -e "\n# opencode" >> "$config_file"
133-
echo "$command" >> "$config_file"
134-
print_message info "Successfully added ${ORANGE}opencode ${GREEN}to \$PATH in $config_file"
135-
else
136-
print_message warning "Manually add the directory to $config_file (or similar):"
137-
print_message info " $command"
93+
local repo="$1"
94+
local url="https://api.github.com/repos/$repo/releases"
95+
curl -s "$url" | grep -Po '"tag_name": "\K.*?(?=")' | grep -E '^v?[0-9]+\.[0-9]+\.[0-9]+$' | sed 's/^v//'
96+
}
97+
github_get_latest_release() {
98+
if [ -z "$1" ]; then
99+
echo "Usage: get_latest_github_release <owner/repo>"
100+
return 1
138101
fi
102+
github_list_releases "$1" | head -n 1
139103
}
140-
141-
XDG_CONFIG_HOME=${XDG_CONFIG_HOME:-$HOME/.config}
142-
143-
current_shell=$(basename "$SHELL")
144-
case $current_shell in
145-
fish)
146-
config_files="$HOME/.config/fish/config.fish"
147-
;;
148-
zsh)
149-
config_files="$HOME/.zshrc $HOME/.zshenv $XDG_CONFIG_HOME/zsh/.zshrc $XDG_CONFIG_HOME/zsh/.zshenv"
150-
;;
151-
bash)
152-
config_files="$HOME/.bashrc $HOME/.bash_profile $HOME/.profile $XDG_CONFIG_HOME/bash/.bashrc $XDG_CONFIG_HOME/bash/.bash_profile"
153-
;;
154-
ash)
155-
config_files="$HOME/.ashrc $HOME/.profile /etc/profile"
156-
;;
157-
sh)
158-
config_files="$HOME/.ashrc $HOME/.profile /etc/profile"
159-
;;
160-
*)
161-
# Default case if none of the above matches
162-
config_files="$HOME/.bashrc $HOME/.bash_profile $XDG_CONFIG_HOME/bash/.bashrc $XDG_CONFIG_HOME/bash/.bash_profile"
163-
;;
164-
esac
165-
166-
config_file=""
167-
for file in $config_files; do
168-
if [[ -f $file ]]; then
169-
config_file=$file
170-
break
104+
utils_check_version() {
105+
local version=$1
106+
if ! [[ "${version:-}" =~ ^(latest|[0-9]+\.[0-9]+\.[0-9]+)$ ]]; then
107+
printf >&2 '=== [ERROR] Option "version" (value: "%s") is not "latest" or valid semantic version format "X.Y.Z" !\n' \
108+
"$version"
109+
exit 1
171110
fi
172-
done
173-
174-
if [[ -z $config_file ]]; then
175-
print_message error "No config file found for $current_shell. Checked files: ${config_files[@]}"
176-
exit 1
177-
fi
178-
179-
if [[ ":$PATH:" != *":$INSTALL_DIR:"* ]]; then
180-
case $current_shell in
181-
fish)
182-
add_to_path "$config_file" "fish_add_path $INSTALL_DIR"
183-
;;
184-
zsh)
185-
add_to_path "$config_file" "export PATH=$INSTALL_DIR:\$PATH"
186-
;;
187-
bash)
188-
add_to_path "$config_file" "export PATH=$INSTALL_DIR:\$PATH"
189-
;;
190-
ash)
191-
add_to_path "$config_file" "export PATH=$INSTALL_DIR:\$PATH"
192-
;;
193-
sh)
194-
add_to_path "$config_file" "export PATH=$INSTALL_DIR:\$PATH"
195-
;;
196-
*)
197-
export PATH=$INSTALL_DIR:$PATH
198-
print_message warning "Manually add the directory to $config_file (or similar):"
199-
print_message info " export PATH=$INSTALL_DIR:\$PATH"
200-
;;
201-
esac
202-
fi
203-
204-
if [ -n "${GITHUB_ACTIONS-}" ] && [ "${GITHUB_ACTIONS}" == "true" ]; then
205-
echo "$INSTALL_DIR" >> $GITHUB_PATH
206-
print_message info "Added $INSTALL_DIR to \$GITHUB_PATH"
207-
fi
111+
}
112+
install() {
113+
utils_check_version "$VERSION"
114+
check_curl_envsubst_file_unzip_installed
115+
readonly architecture="$(debian_get_arch)"
116+
readonly binaryTargetPathTemplate='${binaryTargetFolder}/${binaryName}'
117+
if [ "$VERSION" == 'latest' ] || [ -z "$VERSION" ]; then
118+
VERSION=$(github_get_latest_release "$githubRepository")
119+
fi
120+
readonly version="${VERSION:?}"
121+
readonly downloadUrl="$(echo -n "$downloadUrlTemplate" | envsubst)"
122+
curl_check_url "$downloadUrl"
123+
readonly binaryPathInArchive="$binaryName"
124+
readonly stripComponents="$(echo -n "$binaryPathInArchive" | awk -F'/' '{print NF-1}')"
125+
readonly binaryTargetPath="$(echo -n "$binaryTargetPathTemplate" | envsubst)"
126+
curl_download_unzip "$downloadUrl" "$stripComponents" "$binaryTargetFolder" "$binaryPathInArchive"
127+
chmod 755 "$binaryTargetPath"
128+
}
129+
echo_banner "devcontainer.community"
130+
echo "Installing $name..."
131+
install "$@"
132+
echo "(*) Done!"

0 commit comments

Comments
 (0)