diff --git a/noble/geoscripting-gui.yml b/noble/geoscripting-gui.yml index afd3a5e..e4271e9 100644 --- a/noble/geoscripting-gui.yml +++ b/noble/geoscripting-gui.yml @@ -6,9 +6,18 @@ become: yes vars: rstudio_version: 2025.05.1-513 - rstudio_branch: jammy + rstudio_branch: "{{ ubuntu_codename | default('jammy') }}" + arch: "{{ system_arch | default('amd64') }}" + tasks: + - name: Display system information + debug: + msg: + - "Installing on {{ arch }} architecture" + - "Using Ubuntu codename: {{ rstudio_branch }}" + - "RStudio version: {{ rstudio_version + ' (stable)' if arch == 'amd64' else 'Latest daily build' }} ({{ arch }})" + - name: Gather package facts package_facts: manager: apt @@ -26,6 +35,7 @@ - git-cola - oxygen-icon-theme - rkward + - cmake - name: Make sure local applications path exists file: @@ -37,9 +47,24 @@ src: ../common/git-gui.desktop dest: /usr/local/share/applications/git-gui.desktop - - name: Install RStudio desktop + - name: Get latest RStudio daily build info for ARM64 + uri: + url: https://dailies.rstudio.com/rstudio/latest/index.json + method: GET + return_content: yes + register: rstudio_daily_info + when: arch == "arm64" + + - name: Install RStudio desktop (AMD64 - stable release) apt: - deb: https://download1.rstudio.org/electron/{{ rstudio_branch }}/amd64/rstudio-{{ rstudio_version }}-amd64.deb + deb: https://download1.rstudio.org/electron/{{ rstudio_branch }}/{{ arch }}/rstudio-{{ rstudio_version }}-{{ arch }}.deb + when: arch == "amd64" + + - name: Install RStudio desktop (ARM64 - daily build) + apt: + deb: "{{ (rstudio_daily_info.content | from_json).products.electron.platforms[rstudio_branch + '-arm64'].link }}" + when: arch == "arm64" + - name: Fix RStudio sandbox permissions ansible.builtin.file: @@ -54,11 +79,15 @@ force: true - - name: Install Google Earth + - name: Install Google Earth (AMD64) apt: deb: https://dl.google.com/dl/earth/client/current/google-earth-stable_current_amd64.deb - when: '"google-earth-pro-stable" not in ansible_facts.packages' + when: '"google-earth-pro-stable" not in ansible_facts.packages and arch == "amd64"' + - name: Skip Google Earth installation on ARM64 + debug: + msg: "Google Earth is not available for ARM64 architecture, skipping installation" + when: arch == "arm64" - name: Add VSCode repo key ansible.builtin.get_url: @@ -69,7 +98,7 @@ - name: Add VSCode repository apt_repository: - repo: "deb [arch=amd64] https://packages.microsoft.com/repos/vscode stable main" + repo: "deb [arch={{ arch }}] https://packages.microsoft.com/repos/vscode stable main" filename: vscode - name: Install VSCode diff --git a/noble/install.sh b/noble/install.sh old mode 100644 new mode 100755 index 5ce756e..ef72366 --- a/noble/install.sh +++ b/noble/install.sh @@ -1,3 +1,53 @@ -#!/bin/sh -bash ./install-common.sh -ansible-playbook -K --connection=local -i 127.0.0.1, geoscripting-gui.yml +#!/bin/bash + +# Detect system architecture +ARCH=$(uname -m) +case $ARCH in + x86_64) + SYSTEM_ARCH="amd64" + echo "✓ Detected system architecture: AMD64 (x86_64)" + ;; + aarch64) + SYSTEM_ARCH="arm64" + echo "✓ Detected system architecture: ARM64 (aarch64)" + ;; + *) + echo "⚠ Warning: Unsupported architecture detected: $ARCH" + echo "This installation script supports AMD64 and ARM64 architectures only." + exit 1 + ;; +esac + +# Detect Ubuntu version +if [ -f /etc/os-release ]; then + . /etc/os-release + if [ "$ID" = "ubuntu" ]; then + echo "✓ Detected Ubuntu version: $VERSION ($VERSION_CODENAME)" + UBUNTU_VERSION=$VERSION_ID + UBUNTU_CODENAME=$VERSION_CODENAME + else + echo "⚠ Warning: This script is designed for Ubuntu systems." + echo "Detected OS: $PRETTY_NAME" + echo "Proceeding anyway, but some packages may not be available..." + fi +else + echo "⚠ Warning: Could not detect OS version. /etc/os-release not found." + echo "Assuming Ubuntu and proceeding..." +fi + +echo "" +echo "Starting installation with the following configuration:" +echo "- Architecture: $SYSTEM_ARCH" +echo "- Ubuntu Version: ${VERSION:-Unknown}" +echo "- Ubuntu Codename: ${VERSION_CODENAME:-Unknown}" +echo "" + +# Check if install-common.sh exists before trying to run it +if [ -f "./install-common.sh" ]; then + bash ./install-common.sh +else + echo "Note: install-common.sh not found, skipping..." +fi + +# Run ansible playbook with architecture variable +ansible-playbook -K --connection=local -i 127.0.0.1, geoscripting-gui.yml --extra-vars "system_arch=$SYSTEM_ARCH ubuntu_codename=${UBUNTU_CODENAME:-jammy}" diff --git a/noble/scripts/update_rstudio_version.py b/noble/scripts/update_rstudio_version.py new file mode 100755 index 0000000..fc57289 --- /dev/null +++ b/noble/scripts/update_rstudio_version.py @@ -0,0 +1,175 @@ +#!/usr/bin/env python3 +""" +RStudio Version Updater +Checks for the latest stable RStudio version and updates the Ansible playbook if needed. +""" + +import re +import sys +import os +import subprocess + +# Try to import requests, install if missing +try: + import requests +except ImportError: + print("📦 Installing required Python package: requests") + try: + subprocess.check_call([sys.executable, "-m", "pip", "install", "requests"]) + import requests + print("✅ Successfully installed requests") + except Exception as e: + print(f"❌ Failed to install requests: {e}") + print("Please install it manually: python3 -m pip install requests") + sys.exit(1) + +def get_latest_stable_version(): + """Fetch the latest stable RStudio version from the official download page.""" + try: + response = requests.get('https://posit.co/download/rstudio-desktop/', timeout=10) + response.raise_for_status() + content = response.text + + # Pattern for Ubuntu DEB files: rstudio-VERSION-amd64.deb + deb_pattern = r'rstudio-([0-9]+\.[0-9]+\.[0-9]+-[0-9]+)-amd64\.deb' + matches = re.findall(deb_pattern, content) + + if matches: + # Get unique versions and return the latest + versions = list(set(matches)) + latest_version = sorted(versions, reverse=True)[0] + return latest_version + else: + print("⚠ No version patterns found on the download page") + return None + + except Exception as e: + print(f"❌ Error fetching latest version: {e}") + return None + +def get_current_version_from_playbook(playbook_path): + """Extract the current RStudio version from the Ansible playbook.""" + try: + with open(playbook_path, 'r') as f: + content = f.read() + + # Look for rstudio_version: VERSION pattern + version_pattern = r'rstudio_version:\s*([0-9]+\.[0-9]+\.[0-9]+-[0-9]+)' + match = re.search(version_pattern, content) + + if match: + return match.group(1) + else: + print("⚠ Could not find rstudio_version in playbook") + return None + + except Exception as e: + print(f"❌ Error reading playbook: {e}") + return None + +def update_playbook_version(playbook_path, old_version, new_version): + """Update the RStudio version in the Ansible playbook.""" + try: + with open(playbook_path, 'r') as f: + content = f.read() + + # Replace the version + old_line = f"rstudio_version: {old_version}" + new_line = f"rstudio_version: {new_version}" + updated_content = content.replace(old_line, new_line) + + if updated_content != content: + # Create backup + backup_path = f"{playbook_path}.backup" + with open(backup_path, 'w') as f: + f.write(content) + print(f"📁 Created backup: {backup_path}") + + # Write updated version + with open(playbook_path, 'w') as f: + f.write(updated_content) + print(f"✅ Updated {playbook_path}") + return True + else: + print("⚠ No changes made to playbook") + return False + + except Exception as e: + print(f"❌ Error updating playbook: {e}") + return False + +def verify_version_accessibility(version): + """Verify that the new version is accessible via download URL.""" + test_url = f"https://download1.rstudio.org/electron/jammy/amd64/rstudio-{version}-amd64.deb" + + try: + response = requests.head(test_url, timeout=10) + if response.status_code == 200: + size = response.headers.get('content-length', 'Unknown') + if size != 'Unknown': + size_mb = round(int(size) / (1024*1024), 1) + print(f"✅ Version {version} verified: {size_mb} MB") + else: + print(f"✅ Version {version} verified") + return True + else: + print(f"❌ Version {version} not accessible: HTTP {response.status_code}") + return False + except Exception as e: + print(f"❌ Error verifying version {version}: {e}") + return False + +def main(): + # Look for playbook in parent directory + script_dir = os.path.dirname(os.path.abspath(__file__)) + playbook_path = os.path.join(os.path.dirname(script_dir), "geoscripting-gui.yml") + + if not os.path.exists(playbook_path): + print(f"❌ Playbook not found: {playbook_path}") + print("Please ensure geoscripting-gui.yml exists in the parent directory.") + sys.exit(1) + + print("RStudio Version Checker") + print("=" * 30) + + # Get current version from playbook + current_version = get_current_version_from_playbook(playbook_path) + if not current_version: + sys.exit(1) + + print(f"Current version in playbook: {current_version}") + + # Get latest stable version + latest_version = get_latest_stable_version() + if not latest_version: + sys.exit(1) + + print(f"Latest stable version: {latest_version}") + + # Compare versions + if current_version == latest_version: + print("✅ Playbook is up to date!") + sys.exit(0) + + print(f"🔄 Update available: {current_version} → {latest_version}") + + # Verify new version is accessible + if not verify_version_accessibility(latest_version): + print("❌ Cannot update to inaccessible version") + sys.exit(1) + + # Ask for confirmation + response = input(f"Update playbook to version {latest_version}? [y/N]: ").strip().lower() + + if response in ['y', 'yes']: + if update_playbook_version(playbook_path, current_version, latest_version): + print("🎉 Update completed successfully!") + print(f"Updated from {current_version} to {latest_version}") + else: + print("❌ Update failed") + sys.exit(1) + else: + print("Update cancelled") + +if __name__ == "__main__": + main() diff --git a/noble/scripts/update_rstudio_version_builtin.py b/noble/scripts/update_rstudio_version_builtin.py new file mode 100755 index 0000000..6bb684c --- /dev/null +++ b/noble/scripts/update_rstudio_version_builtin.py @@ -0,0 +1,165 @@ +#!/usr/bin/env python3 +""" +RStudio Version Updater (No External Dependencies) +Checks for the latest stable RStudio version using only built-in Pytho if response in ['y', 'yes']: + if update_playbook_version(playbook_path, current_version, latest_version): + print("🎉 Update completed successfully!") + print(f"Updated from {current_version} to {latest_version}")braries. +""" + +import urllib.request +import urllib.error +import re +import sys +import os + +def get_latest_stable_version(): + """Fetch the latest stable RStudio version from the official download page.""" + try: + with urllib.request.urlopen('https://posit.co/download/rstudio-desktop/', timeout=10) as response: + content = response.read().decode('utf-8') + + # Pattern for Ubuntu DEB files: rstudio-VERSION-amd64.deb + deb_pattern = r'rstudio-([0-9]+\.[0-9]+\.[0-9]+-[0-9]+)-amd64\.deb' + matches = re.findall(deb_pattern, content) + + if matches: + # Get unique versions and return the latest + versions = list(set(matches)) + latest_version = sorted(versions, reverse=True)[0] + return latest_version + else: + print("⚠ No version patterns found on the download page") + return None + + except Exception as e: + print(f"❌ Error fetching latest version: {e}") + return None + +def get_current_version_from_playbook(playbook_path): + """Extract the current RStudio version from the Ansible playbook.""" + try: + with open(playbook_path, 'r') as f: + content = f.read() + + # Look for rstudio_version: VERSION pattern + version_pattern = r'rstudio_version:\s*([0-9]+\.[0-9]+\.[0-9]+-[0-9]+)' + match = re.search(version_pattern, content) + + if match: + return match.group(1) + else: + print("⚠ Could not find rstudio_version in playbook") + return None + + except Exception as e: + print(f"❌ Error reading playbook: {e}") + return None + +def update_playbook_version(playbook_path, old_version, new_version): + """Update the RStudio version in the Ansible playbook.""" + try: + with open(playbook_path, 'r') as f: + content = f.read() + + # Replace the version + old_line = f"rstudio_version: {old_version}" + new_line = f"rstudio_version: {new_version}" + updated_content = content.replace(old_line, new_line) + + if updated_content != content: + # Create backup + backup_path = f"{playbook_path}.backup" + with open(backup_path, 'w') as f: + f.write(content) + print(f"📁 Created backup: {backup_path}") + + # Write updated version + with open(playbook_path, 'w') as f: + f.write(updated_content) + print(f"✅ Updated {playbook_path}") + return True + else: + print("⚠ No changes made to playbook") + return False + + except Exception as e: + print(f"❌ Error updating playbook: {e}") + return False + +def verify_version_accessibility(version): + """Verify that the new version is accessible via download URL.""" + test_url = f"https://download1.rstudio.org/electron/jammy/amd64/rstudio-{version}-amd64.deb" + + try: + req = urllib.request.Request(test_url, method='HEAD') + with urllib.request.urlopen(req, timeout=10) as response: + if response.getcode() == 200: + size = response.headers.get('content-length', 'Unknown') + if size != 'Unknown': + size_mb = round(int(size) / (1024*1024), 1) + print(f"✅ Version {version} verified: {size_mb} MB") + else: + print(f"✅ Version {version} verified") + return True + else: + print(f"❌ Version {version} not accessible: HTTP {response.getcode()}") + return False + except Exception as e: + print(f"❌ Error verifying version {version}: {e}") + return False + +def main(): + # Look for playbook in parent directory + script_dir = os.path.dirname(os.path.abspath(__file__)) + playbook_path = os.path.join(os.path.dirname(script_dir), "geoscripting-gui.yml") + + if not os.path.exists(playbook_path): + print(f"❌ Playbook not found: {playbook_path}") + print("Please ensure geoscripting-gui.yml exists in the parent directory.") + sys.exit(1) + + print("RStudio Version Checker (Built-in Libraries)") + print("=" * 45) + + # Get current version from playbook + current_version = get_current_version_from_playbook(playbook_path) + if not current_version: + sys.exit(1) + + print(f"Current version in playbook: {current_version}") + + # Get latest stable version + latest_version = get_latest_stable_version() + if not latest_version: + sys.exit(1) + + print(f"Latest stable version: {latest_version}") + + # Compare versions + if current_version == latest_version: + print("✅ Playbook is up to date!") + sys.exit(0) + + print(f"🔄 Update available: {current_version} → {latest_version}") + + # Verify new version is accessible + if not verify_version_accessibility(latest_version): + print("❌ Cannot update to inaccessible version") + sys.exit(1) + + # Ask for confirmation + response = input(f"Update playbook to version {latest_version}? [y/N]: ").strip().lower() + + if response in ['y', 'yes']: + if update_playbook_version(playbook_path, current_version, latest_version): + print("🎉 Update completed successfully!") + print(f"Updated from {current_version} to {latest_version}") + else: + print("❌ Update failed") + sys.exit(1) + else: + print("Update cancelled") + +if __name__ == "__main__": + main() \ No newline at end of file