|
| 1 | +#!/usr/bin/env bash |
| 2 | + |
| 3 | +# Check if the platform is Windows |
| 4 | +if [[ "$OSTYPE" == "msys" || "$OSTYPE" == "cygwin" ]]; then |
| 5 | + echo "Note: Dipin does not support Powershell or Cmd on Windows." |
| 6 | + echo "Please use Git BASH (https://gitforwindows.org/) or WSL (https://learn.microsoft.com/en-us/windows/wsl/install)." |
| 7 | +fi |
| 8 | + |
| 9 | +set -e |
| 10 | + |
| 11 | +BASE_DIR=${XDG_CONFIG_HOME:-$HOME} |
| 12 | +DIP_DIR=${DIP_DIR-"$BASE_DIR/.dip"} |
| 13 | +DIP_BIN_DIR="$DIP_DIR/bin" |
| 14 | + |
| 15 | +BINS=(dip) |
| 16 | + |
| 17 | +export RUSTFLAGS="-C target-cpu=native" |
| 18 | + |
| 19 | +main() { |
| 20 | + need_cmd git |
| 21 | + need_cmd curl |
| 22 | + |
| 23 | + while [[ $1 ]]; do |
| 24 | + case $1 in |
| 25 | + --) shift; break;; |
| 26 | + |
| 27 | + -r|--repo) shift; DIPIN_REPO=$1;; |
| 28 | + -b|--branch) shift; DIPIN_BRANCH=$1;; |
| 29 | + -t|--tag) shift; DIPIN_USER_TAG=$1;; |
| 30 | + -v|--version) shift; DIPIN_VERSION=$1;; |
| 31 | + -p|--path) shift; DIPIN_LOCAL_REPO=$1;; |
| 32 | + -P|--pr) shift; DIPIN_PR=$1;; |
| 33 | + -c|--commit) shift; DIPIN_COMMIT=$1;; |
| 34 | + -h|--help) |
| 35 | + usage |
| 36 | + exit 0 |
| 37 | + ;; |
| 38 | + *) |
| 39 | + warn "unknown option: $1" |
| 40 | + usage |
| 41 | + exit 1 |
| 42 | + esac; shift |
| 43 | + done |
| 44 | + |
| 45 | + if [ -n "$DIPIN_BRANCH" ] || [ -n "$DIPIN_USER_TAG" ] || [ -n "$DIPIN_PR" ] || [ -n "$DIPIN_COMMIT" ] || [ -n "$DIPIN_LOCAL_REPO" ] || [ -n "$DIPIN_REPO" ]; then |
| 46 | + if ! command -v rustc &> /dev/null; then |
| 47 | + err "Rust is required for building from source. Please install Rust from https://www.rust-lang.org/tools/install." |
| 48 | + fi |
| 49 | + fi |
| 50 | + |
| 51 | + REMOTE_OPTION=$(check_exclusive_options DIPIN_BRANCH DIPIN_USER_TAG DIPIN_PR) |
| 52 | + |
| 53 | + if [ -n "$REMOTE_OPTION" ]; then |
| 54 | + if [ "$REMOTE_OPTION" = "DIPIN_PR" ]; then |
| 55 | + say "Using $REMOTE_OPTION: $DIPIN_PR" |
| 56 | + DIPIN_BRANCH="refs/pull/$DIPIN_PR/head" |
| 57 | + else |
| 58 | + say "Using $REMOTE_OPTION: ${!REMOTE_OPTION}" |
| 59 | + fi |
| 60 | + fi |
| 61 | + |
| 62 | + # Installs dip from a local repository if --path parameter is provided |
| 63 | + if [[ -n "$DIPIN_LOCAL_REPO" ]]; then |
| 64 | + need_cmd cargo |
| 65 | + |
| 66 | + # Ignore branches/versions as we do not want to modify local git state |
| 67 | + if [ -n "$DIPIN_REPO" ] || [ -n "$DIPIN_BRANCH" ] || [ -n "$DIPIN_VERSION" ]; then |
| 68 | + warn "--branch, --version, and --repo arguments are ignored during local install" |
| 69 | + fi |
| 70 | + |
| 71 | + # Enter local repo and build |
| 72 | + say "installing from $DIPIN_LOCAL_REPO" |
| 73 | + cd "$DIPIN_LOCAL_REPO" |
| 74 | + ensure cargo build --release # need 4 speed |
| 75 | + |
| 76 | + for bin in "${BINS[@]}"; do |
| 77 | + # Remove prior installations if they exist |
| 78 | + rm -f "$DIP_BIN_DIR/$bin" |
| 79 | + # Symlink from local repo binaries to bin dir |
| 80 | + ensure ln -s "$PWD/target/release/$bin" "$DIP_BIN_DIR/$bin" |
| 81 | + done |
| 82 | + |
| 83 | + say "done" |
| 84 | + welcome_msg |
| 85 | + exit 0 |
| 86 | + fi |
| 87 | + |
| 88 | + DIPIN_REPO=${DIPIN_REPO-diptools/dip} |
| 89 | + |
| 90 | + # Store user specified version seperately. |
| 91 | + DIPIN_USER_VERSION=${DIPIN_VERSION} |
| 92 | + |
| 93 | + # Install by downloading binaries |
| 94 | + if [[ "$DIPIN_REPO" == "diptools/dip" && -z "$DIPIN_BRANCH" && -z "$DIPIN_COMMIT" ]]; then |
| 95 | + DIPIN_VERSION=${DIPIN_VERSION-stable} |
| 96 | + |
| 97 | + if [ -n "$DIPIN_USER_TAG" ]; then |
| 98 | + DIPIN_TAG=$DIPIN_USER_TAG |
| 99 | + DIPIN_VERSION=$DIPIN_USER_TAG |
| 100 | + else |
| 101 | + DIPIN_TAG=$DIPIN_VERSION |
| 102 | + fi |
| 103 | + |
| 104 | + # Normalize versions (handle channels, versions without v prefix |
| 105 | + if [[ "$DIPIN_VERSION" == "stable" ]]; then |
| 106 | + # Fetch the list of releases from the GitHub API and filter out `prerelease`` releases and `alpha`` releases |
| 107 | + DIPIN_TAG=$(curl -s "https://api.github.com/repos/${DIPIN_REPO}/releases" \ |
| 108 | + | grep -oE '"tag_name": "[^"]*"|"prerelease": (true|false)' \ |
| 109 | + | grep -B1 '"prerelease": false' \ |
| 110 | + | grep '"tag_name":' \ |
| 111 | + | grep -oE '"v[0-9]*\.[0-9]*\.[0-9]*"' \ |
| 112 | + | tr -d '"' \ |
| 113 | + | head -n 1) |
| 114 | + DIPIN_VERSION=$DIPIN_TAG |
| 115 | + elif [[ "$DIPIN_VERSION" == [[:digit:]]* ]]; then |
| 116 | + # Add v prefix |
| 117 | + DIPIN_VERSION="v${DIPIN_VERSION}" |
| 118 | + DIPIN_TAG="${DIPIN_VERSION}" |
| 119 | + fi |
| 120 | + |
| 121 | + say "installing dip (version ${DIPIN_VERSION}, tag ${DIPIN_TAG})" |
| 122 | + |
| 123 | + PLATFORM="$(uname -s)" |
| 124 | + EXT="tar.gz" |
| 125 | + case $PLATFORM in |
| 126 | + Linux) |
| 127 | + PLATFORM="linux" |
| 128 | + ;; |
| 129 | + Darwin) |
| 130 | + PLATFORM="darwin" |
| 131 | + ;; |
| 132 | + MINGW*) |
| 133 | + EXT="zip" |
| 134 | + PLATFORM="win32" |
| 135 | + ;; |
| 136 | + *) |
| 137 | + err "unsupported platform: $PLATFORM" |
| 138 | + ;; |
| 139 | + esac |
| 140 | + |
| 141 | + ARCHITECTURE="$(uname -m)" |
| 142 | + if [ "${ARCHITECTURE}" = "x86_64" ]; then |
| 143 | + # Redirect stderr to /dev/null to avoid printing errors if non Rosetta. |
| 144 | + if [ "$(sysctl -n sysctl.proc_translated 2>/dev/null)" = "1" ]; then |
| 145 | + ARCHITECTURE="arm64" # Rosetta. |
| 146 | + else |
| 147 | + ARCHITECTURE="amd64" # Intel. |
| 148 | + fi |
| 149 | + elif [ "${ARCHITECTURE}" = "arm64" ] ||[ "${ARCHITECTURE}" = "aarch64" ] ; then |
| 150 | + ARCHITECTURE="arm64" # Arm. |
| 151 | + else |
| 152 | + ARCHITECTURE="amd64" # Amd. |
| 153 | + fi |
| 154 | + |
| 155 | + # Compute the URL of the release tarball in the Dip repository. |
| 156 | + RELEASE_URL="https://github.com/${DIPIN_REPO}/releases/download/${DIPIN_TAG}/" |
| 157 | + BIN_ARCHIVE_URL="${RELEASE_URL}dip${DIPIN_VERSION}_${PLATFORM}_${ARCHITECTURE}.$EXT" |
| 158 | + |
| 159 | + # Check if the version mentioned by user exists in the Dip repository. |
| 160 | + if ! curl --output /dev/null --silent --head --fail "$BIN_ARCHIVE_URL"; then |
| 161 | + say "Version ${DIPIN_VERSION} does not match any release listed at https://github.com/diptools/dip/releases." |
| 162 | + say "Please specify a valid version, or omit -v to install the latest stable version automatically." |
| 163 | + err "Aborting installation." |
| 164 | + fi |
| 165 | + |
| 166 | + echo "$BIN_ARCHIVE_URL" |
| 167 | + |
| 168 | + # Display message only if version is not mentioned by user. |
| 169 | + if [ -z "$DIPIN_USER_VERSION" ] && [ -z "$DIPIN_USER_TAG" ]; then |
| 170 | + say "downloading latest dip" |
| 171 | + fi |
| 172 | + |
| 173 | + # Download and extract the binaries archive |
| 174 | + if [ "$PLATFORM" = "win32" ]; then |
| 175 | + tmp="$(mktemp -d 2>/dev/null || echo ".")/dip.zip" |
| 176 | + ensure download "$BIN_ARCHIVE_URL" "$tmp" |
| 177 | + ensure unzip "$tmp" -d "$DIP_BIN_DIR" |
| 178 | + rm -f "$tmp" |
| 179 | + else |
| 180 | + ensure download "$BIN_ARCHIVE_URL" | ensure tar -xzC "$DIP_BIN_DIR" |
| 181 | + fi |
| 182 | + |
| 183 | + for bin in "${BINS[@]}"; do |
| 184 | + bin_path="$DIP_BIN_DIR/$bin" |
| 185 | + |
| 186 | + # Print installed msg |
| 187 | + say "installed - $(ensure "$bin_path" --version)" |
| 188 | + |
| 189 | + # Check if the default path of the binary is not in DIP_BIN_DIR |
| 190 | + which_path="$(which "$bin")" |
| 191 | + if [ "$which_path" != "$bin_path" ]; then |
| 192 | + warn "" |
| 193 | + cat 1>&2 <<EOF |
| 194 | +There are multiple binaries with the name '$bin' present in your 'PATH'. |
| 195 | +This may be the result of installing '$bin' using another method, |
| 196 | +like Cargo or other package managers. |
| 197 | +You may need to run 'rm $which_path' or move '$DIP_BIN_DIR' |
| 198 | +in your 'PATH' to allow the newly installed version to take precedence! |
| 199 | +
|
| 200 | +EOF |
| 201 | + fi |
| 202 | + done |
| 203 | + |
| 204 | + # Extracting the scarb version from the output of 'sozo --version' |
| 205 | + scarb_version=$(echo "$(sozo --version)" | grep -o 'scarb: [0-9.]*' | cut -d ' ' -f 2) |
| 206 | + |
| 207 | + # Check if scarb is already installed |
| 208 | + if [ "$(scarb --version 2>/dev/null)" != "scarb $scarb_version" ]; then |
| 209 | + # Check if scarb is managed by asdf |
| 210 | + if command -v asdf &> /dev/null; then |
| 211 | + if asdf list | grep -q "scarb"; then |
| 212 | + # Check if default version is set |
| 213 | + if ! asdf current scarb &> /dev/null; then |
| 214 | + asdf global scarb $scarb_version |
| 215 | + fi |
| 216 | + else |
| 217 | + # Install scarb using asdf |
| 218 | + asdf plugin add scarb |
| 219 | + asdf install scarb $scarb_version |
| 220 | + fi |
| 221 | + else |
| 222 | + # Install scarb using the install script |
| 223 | + curl --proto '=https' --tlsv1.2 -sSf https://docs.swmansion.com/scarb/install.sh | sh -s -- -v $scarb_version |
| 224 | + fi |
| 225 | + fi |
| 226 | + |
| 227 | + say "done!" |
| 228 | + welcome_msg |
| 229 | + |
| 230 | + # Install by cloning the repo with the provided branch/tag |
| 231 | + else |
| 232 | + need_cmd cargo |
| 233 | + DIPIN_BRANCH=${DIPIN_BRANCH-main} |
| 234 | + REPO_PATH="$DIP_DIR/$DIPIN_REPO" |
| 235 | + |
| 236 | + # If repo path does not exist, grab the author from the repo, make a directory in .dip, cd to it and clone. |
| 237 | + if [ ! -d "$REPO_PATH" ]; then |
| 238 | + AUTHOR="$(echo "$DIPIN_REPO" | cut -d'/' -f1 -)" |
| 239 | + ensure mkdir -p "$DIP_DIR/$AUTHOR" |
| 240 | + cd "$DIP_DIR/$AUTHOR" |
| 241 | + ensure git clone "https://github.com/$DIPIN_REPO" |
| 242 | + fi |
| 243 | + |
| 244 | + # Force checkout, discarding any local changes |
| 245 | + cd "$REPO_PATH" |
| 246 | + ensure git fetch origin "${DIPIN_BRANCH}:remotes/origin/${DIPIN_BRANCH}" |
| 247 | + ensure git checkout "origin/${DIPIN_BRANCH}" |
| 248 | + |
| 249 | + # If set, checkout specific commit from branch |
| 250 | + if [ -n "$DIPIN_COMMIT" ]; then |
| 251 | + say "installing at commit $DIPIN_COMMIT" |
| 252 | + ensure git checkout "$DIPIN_COMMIT" |
| 253 | + fi |
| 254 | + |
| 255 | + for bin in "${BINS[@]}"; do |
| 256 | + # Build the repo and install the binaries locally to the .dip bin directory. |
| 257 | + # --root appends /bin to the directory it is given, so we pass DIP_DIR. |
| 258 | + ensure cargo install --path ./bin/$bin $bin --locked --force --root "$DIP_DIR" |
| 259 | + done |
| 260 | + |
| 261 | + say "done" |
| 262 | + welcome_msg |
| 263 | + fi |
| 264 | +} |
| 265 | + |
| 266 | +usage() { |
| 267 | + cat 1>&2 <<'EOF' |
| 268 | +The installer for Dip. |
| 269 | +
|
| 270 | +Update or revert to a specific Dip version with ease. |
| 271 | +
|
| 272 | +USAGE: |
| 273 | + dipin <OPTIONS> |
| 274 | +
|
| 275 | +OPTIONS: |
| 276 | + -h, --help Print help information |
| 277 | + -v, --version Install a specific version (e.g., `dipin --version nightly`) |
| 278 | + -b, --branch Install a specific branch (e.g., `dipin --branch release/0.1.0`) |
| 279 | + -P, --pr Install a specific Pull Request (e.g., `dipin --pr 1071`) |
| 280 | + -c, --commit Install a specific commit (e.g., `dipin -c 94bfdb2`) |
| 281 | + -r, --repo Install from a remote GitHub repo (uses default branch if no other options are set) (e.g., `dipin --repo JunichiSugiura/dip`) |
| 282 | + -p, --path Install a local repository (e.g., `dipin --path ./git/dip`) |
| 283 | +EOF |
| 284 | +} |
| 285 | + |
| 286 | +say() { |
| 287 | + printf "dipin: %s\n" "$1" |
| 288 | +} |
| 289 | + |
| 290 | +warn() { |
| 291 | + say "warning: ${1}" >&2 |
| 292 | +} |
| 293 | + |
| 294 | +err() { |
| 295 | + say "$1" >&2 |
| 296 | + exit 1 |
| 297 | +} |
| 298 | + |
| 299 | +need_cmd() { |
| 300 | + if ! check_cmd "$1"; then |
| 301 | + err "need '$1' (command not found)" |
| 302 | + fi |
| 303 | +} |
| 304 | + |
| 305 | +check_cmd() { |
| 306 | + command -v "$1" &>/dev/null |
| 307 | +} |
| 308 | + |
| 309 | +# Run a command that should never fail. If the command fails execution |
| 310 | +# will immediately terminate with an error showing the failing |
| 311 | +# command. |
| 312 | +ensure() { |
| 313 | + if ! "$@"; then err "command failed: $*"; fi |
| 314 | +} |
| 315 | + |
| 316 | +# Downloads $1 into $2 or stdout |
| 317 | +download() { |
| 318 | + if [ "$2" ]; then |
| 319 | + # output into $2 |
| 320 | + if check_cmd curl; then |
| 321 | + curl -#o "$2" -L "$1" |
| 322 | + else |
| 323 | + wget --show-progress -qO "$2" "$1" |
| 324 | + fi |
| 325 | + else |
| 326 | + # output to stdout |
| 327 | + if check_cmd curl; then |
| 328 | + curl -#L "$1" |
| 329 | + else |
| 330 | + wget --show-progress -qO- "$1" |
| 331 | + fi |
| 332 | + fi |
| 333 | +} |
| 334 | + |
| 335 | +# Function to check mutual exclusivity of options. |
| 336 | +check_exclusive_options() { |
| 337 | + local options=("$@") |
| 338 | + local count=0 |
| 339 | + local set_option="" |
| 340 | + |
| 341 | + for option in "${options[@]}"; do |
| 342 | + if [ -n "${!option}" ]; then |
| 343 | + ((count++)) |
| 344 | + set_option="$option" |
| 345 | + fi |
| 346 | + done |
| 347 | + |
| 348 | + if [ "$count" -gt 1 ]; then |
| 349 | + err "only one of ${options[*]} can be specified" |
| 350 | + elif [ "$count" -eq 1 ]; then |
| 351 | + echo "$set_option" |
| 352 | + fi |
| 353 | +} |
| 354 | + |
| 355 | +# Welcome message printed after having installed Dip. |
| 356 | +welcome_msg() { |
| 357 | + dip='\033[1;34m' |
| 358 | + title='\033[0;32m' |
| 359 | + emphasis='\033[0;34m' |
| 360 | + command='\033[0;31m' |
| 361 | + clear='\033[0m' |
| 362 | + |
| 363 | + printf " |
| 364 | +═════════════════════════════════════════════════════════════════════════ |
| 365 | + |
| 366 | +
|
| 367 | + ██████╗ ██╗██████╗ ████████╗ ██████╗ ██████╗ ██╗ ███████╗ |
| 368 | + ██╔══██╗██║██╔══██╗ ╚══██╔══╝██╔═══██╗██╔═══██╗██║ ██╔════╝ |
| 369 | + ██║ ██║██║██████╔╝ ██║ ██║ ██║██║ ██║██║ ███████╗ |
| 370 | + ██║ ██║██║██╔═══╝ ██║ ██║ ██║██║ ██║██║ ╚════██║ |
| 371 | + ██████╔╝██║██║ ██║ ╚██████╔╝╚██████╔╝███████╗███████║ |
| 372 | + ╚═════╝ ╚═╝╚═╝ ╚═╝ ╚═════╝ ╚═════╝ ╚══════╝╚══════╝ |
| 373 | + |
| 374 | +
|
| 375 | +
|
| 376 | + Repo : https://github.com/diptools/dip |
| 377 | + Book : https://dip.tools/ |
| 378 | + Chat : https://discord.gg/4R8AtxAxk3 |
| 379 | +
|
| 380 | +Congratulations on successfully installing ${dip}Dip${clear} ${DIPIN_VERSION}! 🥷 |
| 381 | +
|
| 382 | +For more info on how to get started, check out the Dip Getting Started Guide: https://dip.tools/getting-started/quick-start |
| 383 | +
|
| 384 | +═════════════════════════════════════════════════════════════════════════ |
| 385 | +
|
| 386 | +" |
| 387 | +} |
| 388 | + |
| 389 | +main "$@" || exit 1 |
| 390 | + |
0 commit comments