-
-
Save gadenbuie/7bb14b245a45e08173e54bc75ec38790 to your computer and use it in GitHub Desktop.
Script for updating to latest RStudio daily build
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/bin/bash | |
| # | |
| # Installs the latest RStudio daily desktop build for OSX/macOS and Ubuntu(amd64) | |
| # | |
| # https://support.rstudio.com/hc/en-us/articles/203842428-Getting-the-newest-RStudio-builds | |
| # | |
| # Source: https://gist.github.com/gadenbuie/7bb14b245a45e08173e54bc75ec38790 | |
| set -e | |
| # ============================================================================== | |
| # Color and formatting setup (respects NO_COLOR) | |
| # ============================================================================== | |
| setup_colors() { | |
| if [[ -z "${NO_COLOR:-}" && -t 1 ]]; then | |
| BOLD='\033[1m' | |
| DIM='\033[2m' | |
| RESET='\033[0m' | |
| GREEN='\033[32m' | |
| BLUE='\033[34m' | |
| YELLOW='\033[33m' | |
| CYAN='\033[36m' | |
| RED='\033[31m' | |
| else | |
| BOLD='' | |
| DIM='' | |
| RESET='' | |
| GREEN='' | |
| BLUE='' | |
| YELLOW='' | |
| CYAN='' | |
| RED='' | |
| fi | |
| } | |
| setup_colors | |
| # ============================================================================== | |
| # Output helpers | |
| # ============================================================================== | |
| header() { | |
| echo "" | |
| echo -e "${BOLD}${BLUE}▶ ${1}${RESET}" | |
| } | |
| info() { | |
| echo -e " ${DIM}ℹ${RESET} ${1}" | |
| } | |
| success() { | |
| echo -e " ${GREEN}✔${RESET} ${1}" | |
| } | |
| warn() { | |
| echo -e " ${YELLOW}!${RESET} ${1}" | |
| } | |
| error() { | |
| echo -e " ${RED}✘${RESET} ${1}" | |
| } | |
| step() { | |
| echo -e " ${CYAN}●${RESET} ${1}" | |
| } | |
| clear_last_line() { | |
| if [[ -z "${NO_COLOR:-}" && -t 1 ]]; then | |
| echo -en "\033[A\033[2K\r" | |
| fi | |
| } | |
| step_done() { | |
| clear_last_line | |
| success "$1" | |
| } | |
| step_fail() { | |
| clear_last_line | |
| error "$1" | |
| } | |
| run_cmd() { | |
| if [[ "$VERBOSE" == true ]]; then | |
| "$@" | |
| else | |
| "$@" > /dev/null 2>&1 | |
| fi | |
| } | |
| # ============================================================================== | |
| # Help | |
| # ============================================================================== | |
| help() { | |
| echo -e "${BOLD}Usage:${RESET} update-rstudio-daily [command] [options]" | |
| echo "" | |
| echo "Installs the latest RStudio daily or hourly desktop build." | |
| echo "" | |
| echo -e "${BOLD}Commands:${RESET}" | |
| echo " install Install the latest build (default)" | |
| echo " info Show available builds for your platform" | |
| echo "" | |
| echo -e "${BOLD}Options:${RESET}" | |
| echo " --hourly Use hourly builds instead of daily" | |
| echo " -v, --verbose Show command output" | |
| echo " -h, --help Show this help message" | |
| echo "" | |
| echo -e "${BOLD}Supported platforms:${RESET}" | |
| echo " - macOS" | |
| echo " - Ubuntu Linux (jammy/22.04)" | |
| } | |
| # ============================================================================== | |
| # Parse arguments | |
| # ============================================================================== | |
| VERBOSE=false | |
| HOURLY=false | |
| COMMAND="install" | |
| while [[ $# -gt 0 ]]; do | |
| case $1 in | |
| info|install) | |
| COMMAND="$1" | |
| shift | |
| ;; | |
| --hourly) | |
| HOURLY=true | |
| shift | |
| ;; | |
| -v|--verbose) | |
| VERBOSE=true | |
| shift | |
| ;; | |
| -h|--help) | |
| help | |
| exit 0 | |
| ;; | |
| -*) | |
| warn "Unknown option: $1" | |
| echo "" | |
| help | |
| exit 1 | |
| ;; | |
| *) | |
| warn "Unexpected argument: $1" | |
| echo "" | |
| help | |
| exit 1 | |
| ;; | |
| esac | |
| done | |
| # ============================================================================== | |
| # Build index helpers | |
| # ============================================================================== | |
| DAILY_INDEX_URL="https://dailies.rstudio.com/rstudio/latest/index.json" | |
| # Get the branch slug (e.g., "Globemaster Allium" -> "globemaster-allium") | |
| get_branch_slug() { | |
| local json=$1 | |
| echo "$json" | jq -r '.branch' | tr '[:upper:]' '[:lower:]' | tr ' ' '-' | |
| } | |
| # Fetch the build index JSON (daily or hourly) | |
| fetch_index_json() { | |
| local daily_json | |
| daily_json=$(curl -s "${DAILY_INDEX_URL}") | |
| if [[ "$HOURLY" == true ]]; then | |
| local slug | |
| slug=$(get_branch_slug "$daily_json") | |
| curl -s "https://dailies.rstudio.com/rstudio-hourly/${slug}/index.json" | |
| else | |
| echo "$daily_json" | |
| fi | |
| } | |
| # Extract platform info from index JSON | |
| # Daily structure: .products.electron.platforms.<key> | |
| # Hourly structure: .electron.platforms.<key> | |
| get_platform_info() { | |
| local json=$1 | |
| local platform_key=$2 | |
| if [[ "$HOURLY" == true ]]; then | |
| echo "$json" | jq -r ".electron.platforms.${platform_key}" | |
| else | |
| echo "$json" | jq -r ".products.electron.platforms.${platform_key}" | |
| fi | |
| } | |
| # List all electron platform keys from the index JSON | |
| get_platform_keys() { | |
| local json=$1 | |
| if [[ "$HOURLY" == true ]]; then | |
| echo "$json" | jq -r '.electron.platforms // {} | keys[]' | |
| else | |
| echo "$json" | jq -r '.products.electron.platforms // {} | keys[]' | |
| fi | |
| } | |
| build_label() { | |
| if [[ "$HOURLY" == true ]]; then | |
| echo "hourly" | |
| else | |
| echo "daily" | |
| fi | |
| } | |
| # ============================================================================== | |
| # List available builds | |
| # ============================================================================== | |
| list_builds() { | |
| local label | |
| label=$(build_label) | |
| header "Fetching RStudio ${label} build info" | |
| step "Checking available builds..." | |
| local json | |
| json=$(fetch_index_json) | |
| step_done "Fetched build index" | |
| local platform_filter | |
| if [[ $(uname -s) = "Darwin" ]]; then | |
| platform_filter="macos" | |
| elif [[ -f /etc/issue ]] && grep -q Ubuntu /etc/issue; then | |
| platform_filter="jammy\|noble" | |
| else | |
| error "Unsupported platform" | |
| exit 1 | |
| fi | |
| echo "" | |
| printf " ${BOLD}%-24s %-28s %-12s %s${RESET}\n" "PLATFORM" "VERSION" "DATE" "ARCH" | |
| local keys | |
| keys=$(get_platform_keys "$json") | |
| local found=false | |
| while IFS= read -r key; do | |
| # Skip xcopy (installer-less) variants | |
| [[ "$key" == *-xcopy ]] && continue | |
| # Filter to current OS platforms | |
| echo "$key" | grep -q "$platform_filter" || continue | |
| local info | |
| info=$(get_platform_info "$json" "$key") | |
| local version date arch | |
| version=$(echo "$info" | jq -r '.version // "-"') | |
| date=$(echo "$info" | jq -r '.date // "-"' | cut -d' ' -f1) | |
| arch=$(echo "$info" | jq -r '.architecture // "-"') | |
| printf " %-24s %-28s %-12s %s\n" "$key" "$version" "$date" "$arch" | |
| found=true | |
| done <<< "$keys" | |
| if [[ "$found" == false ]]; then | |
| warn "No builds found for your platform" | |
| fi | |
| echo "" | |
| } | |
| # ============================================================================== | |
| # RStudio process management | |
| # ============================================================================== | |
| # Check if RStudio is currently running | |
| is_rstudio_running() { | |
| local platform=$1 | |
| if [ "$platform" = "macos" ]; then | |
| pgrep -x "RStudio" > /dev/null | |
| else | |
| pgrep -i rstudio > /dev/null | |
| fi | |
| } | |
| # Send quit signal to RStudio | |
| quit_rstudio() { | |
| local platform=$1 | |
| if [ "$platform" = "macos" ]; then | |
| osascript -e 'quit app "RStudio"' > /dev/null 2>&1 | |
| else | |
| pkill -TERM -i rstudio | |
| fi | |
| } | |
| # Wait for RStudio process to end | |
| wait_for_rstudio_quit() { | |
| local platform=$1 | |
| local max_wait=30 | |
| for _ in $(seq 1 $max_wait); do | |
| if ! is_rstudio_running "$platform"; then | |
| return 0 | |
| fi | |
| sleep 1 | |
| done | |
| return 1 | |
| } | |
| # Main function to ensure RStudio is not running before update | |
| ensure_rstudio_not_running() { | |
| local platform=$1 | |
| if ! is_rstudio_running "$platform"; then | |
| return 0 | |
| fi | |
| echo "" | |
| warn "RStudio is currently running" | |
| echo -en " Do you want to quit RStudio to proceed? ${DIM}(y/n)${RESET} " | |
| read -n 1 -r | |
| echo "" | |
| if [[ ! $REPLY =~ ^[Yy]$ ]]; then | |
| info "Update cancelled" | |
| exit 0 | |
| fi | |
| step "Quitting RStudio gracefully..." | |
| quit_rstudio "$platform" | |
| if wait_for_rstudio_quit "$platform"; then | |
| step_done "RStudio has quit" | |
| else | |
| step_fail "RStudio is still running (may have unsaved work)" | |
| info "Please quit RStudio manually and run this script again" | |
| exit 1 | |
| fi | |
| } | |
| # ============================================================================== | |
| # macOS installation | |
| # ============================================================================== | |
| install_macos_daily() { | |
| local label | |
| label=$(build_label) | |
| header "Fetching RStudio ${label} build info" | |
| info "Source: dailies.rstudio.com" | |
| step "Checking latest version" | |
| local index_json | |
| index_json=$(fetch_index_json) | |
| local platform_info | |
| platform_info=$(get_platform_info "$index_json" "macos") | |
| RELEASE_URL=$(echo "$platform_info" | jq -r '.link') | |
| if [ "${RELEASE_URL}" == "" ] || [ "${RELEASE_URL}" == "null" ]; then | |
| step_fail "Could not extract ${label} build URL from JSON" | |
| exit 1 | |
| fi | |
| step_done "Found latest build" | |
| cd /tmp | |
| TARGET=$(basename "${RELEASE_URL}") | |
| # Volume name mirrors the DMG filename without extension. | |
| VOLUME_NAME=$(basename "${TARGET}" .dmg) | |
| VOLUME_MOUNT="/Volumes/${VOLUME_NAME}" | |
| header "Downloading ${VOLUME_NAME}" | |
| info "URL: ${RELEASE_URL}" | |
| step "Downloading DMG..." | |
| if [[ "$VERBOSE" == true ]]; then | |
| curl -L -o "${TARGET}" "${RELEASE_URL}" | |
| else | |
| curl -sL -o "${TARGET}" "${RELEASE_URL}" | |
| fi | |
| step_done "Download complete" | |
| header "Installing RStudio" | |
| ensure_rstudio_not_running "macos" | |
| step "Mounting disk image" | |
| run_cmd hdiutil attach -quiet "${TARGET}" | |
| step_done "Mounted" | |
| step "Removing previous installation" | |
| rm -rf /Applications/RStudio.app | |
| step_done "Removed old version" | |
| step "Copying to /Applications" | |
| run_cmd cp -R "${VOLUME_MOUNT}/RStudio.app" /Applications | |
| step_done "Installed" | |
| step "Cleaning up" | |
| run_cmd hdiutil detach -quiet "${VOLUME_MOUNT}" | |
| rm "${TARGET}" | |
| step_done "Cleaned up" | |
| header "Done" | |
| success "Installed ${VOLUME_NAME} to /Applications" | |
| echo "" | |
| } | |
| # ============================================================================== | |
| # Ubuntu installation | |
| # ============================================================================== | |
| install_ubuntu_daily() { | |
| local label | |
| label=$(build_label) | |
| header "Fetching RStudio ${label} build info" | |
| info "Source: dailies.rstudio.com" | |
| step "Checking latest version" | |
| local index_json | |
| index_json=$(fetch_index_json) | |
| local platform_info | |
| platform_info=$(get_platform_info "$index_json" "jammy") | |
| URL=$(echo "$platform_info" | jq -r '.link') | |
| if [ "${URL}" == "" ] || [ "${URL}" == "null" ]; then | |
| step_fail "Could not extract ${label} build URL from JSON" | |
| exit 1 | |
| fi | |
| step_done "Found latest build" | |
| PACKAGE=$(basename "${URL}") | |
| TARGET="/tmp/${PACKAGE}" | |
| # If previous file exists (from previous partial download, for example), | |
| # remove it. | |
| if [[ -f "${TARGET}" ]]; then | |
| step "Removing existing package file" | |
| rm "${TARGET}" | |
| fi | |
| header "Downloading ${PACKAGE}" | |
| info "URL: ${URL}" | |
| step "Downloading package..." | |
| if [ -x /usr/bin/curl ] ; then | |
| if [[ "$VERBOSE" == true ]]; then | |
| curl -L -o "${TARGET}" "${URL}" | |
| else | |
| curl -sL -o "${TARGET}" "${URL}" | |
| fi | |
| elif [ -x /usr/bin/wget ] ; then | |
| if [[ "$VERBOSE" == true ]]; then | |
| wget -O "${TARGET}" "${URL}" | |
| else | |
| wget -q -O "${TARGET}" "${URL}" | |
| fi | |
| else | |
| step_fail "Cannot find 'curl' or 'wget'" | |
| exit 1 | |
| fi | |
| step_done "Download complete" | |
| header "Installing RStudio" | |
| ensure_rstudio_not_running "ubuntu" | |
| LAUNCH="" | |
| if [[ $(whoami) != "root" ]]; then | |
| LAUNCH="sudo" | |
| info "Sudo required for installation" | |
| fi | |
| step "Installing package with dpkg" | |
| if [[ "$VERBOSE" == true ]]; then | |
| ${LAUNCH} dpkg -i "${TARGET}" | |
| else | |
| ${LAUNCH} dpkg -i "${TARGET}" > /dev/null 2>&1 | |
| fi | |
| step_done "Installed" | |
| step "Cleaning up" | |
| rm "${TARGET}" | |
| step_done "Cleaned up" | |
| header "Done" | |
| success "Installed ${PACKAGE}" | |
| echo "" | |
| } | |
| # ============================================================================== | |
| # Main | |
| # ============================================================================== | |
| if [[ "$COMMAND" == "info" ]]; then | |
| list_builds | |
| elif [[ $(uname -s) = "Darwin" ]]; then | |
| install_macos_daily | |
| elif [[ -f /etc/issue ]] && grep -q Ubuntu /etc/issue ; then | |
| install_ubuntu_daily | |
| else | |
| error "Unsupported platform" | |
| info "This script only works on macOS and Ubuntu Linux" | |
| exit 1 | |
| fi |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment