Skip to content
Closed
Show file tree
Hide file tree
Changes from all 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
61 changes: 61 additions & 0 deletions .github/workflows/installerv2-ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
name: InstallerV2 CI

on:
pull_request_target:
branches: [ main ]
workflow_dispatch:

jobs:
build-and-smoke:
runs-on: macos-latest
steps:
- name: Checkout base (for context)
uses: actions/checkout@v4

- name: Checkout PR head
if: github.event_name == 'pull_request_target'
uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.sha }}
path: pr_head

- name: Show workspace files (debug)
run: |
echo "pwd=$(pwd)"
ls -la
echo "PR head tree:" && ls -la pr_head || true

- name: Build universal installer
shell: bash
run: |
if [[ -d pr_head ]]; then cd pr_head; fi
test -f InstallerV2/build/create-universal-installer.sh || { echo "InstallerV2 build script missing"; ls -la InstallerV2 || true; exit 1; }
bash InstallerV2/build/create-universal-installer.sh
ls -la dist

- name: Smoke test (CLI, dry-run)
shell: bash
env:
CI: true
DTU_ANALYTICS_ENABLED: "0"
run: |
if [[ -d pr_head ]]; then cd pr_head; fi
./dist/dtu-installer.sh --cli --dry-run

- name: Smoke test (GUI, dry-run)
shell: bash
env:
CI: true
DTU_ANALYTICS_ENABLED: "0"
run: |
if [[ -d pr_head ]]; then cd pr_head; fi
./dist/dtu-installer.sh --gui --dry-run

- name: Direct run via repo entry (CLI, dry-run)
shell: bash
env:
CI: true
DTU_ANALYTICS_ENABLED: "0"
run: |
if [[ -d pr_head ]]; then cd pr_head; fi
./InstallerV2/install.sh --cli --dry-run
52 changes: 52 additions & 0 deletions .github/workflows/installerv2-pr.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
name: InstallerV2 PR

on:
pull_request:
branches: [ main ]
paths:
- 'InstallerV2/**'
- '.github/workflows/installerv2-pr.yml'
workflow_dispatch:

jobs:
build-and-smoke:
runs-on: macos-latest
steps:
- name: Checkout PR head
uses: actions/checkout@v4

- name: Show workspace files (debug)
run: |
echo "pwd=$(pwd)"
ls -la

- name: Build universal installer
shell: bash
run: |
bash InstallerV2/build/create-universal-installer.sh
ls -la dist

- name: Smoke test (CLI, dry-run)
shell: bash
env:
CI: true
DTU_ANALYTICS_ENABLED: "0"
run: |
./dist/dtu-installer.sh --cli --dry-run

- name: Smoke test (GUI, dry-run)
shell: bash
env:
CI: true
DTU_ANALYTICS_ENABLED: "0"
run: |
./dist/dtu-installer.sh --gui --dry-run

- name: Direct run via repo entry (CLI, dry-run)
shell: bash
env:
CI: true
DTU_ANALYTICS_ENABLED: "0"
run: |
./InstallerV2/install.sh --cli --dry-run

13 changes: 12 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,23 @@ __pycache__/
*.so
.Python
build/
!InstallerV2/
!InstallerV2/build/
!InstallerV2/build/create-universal-installer.sh
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
!InstallerV2/lib/
!InstallerV2/lib/logging.sh
!InstallerV2/lib/config.sh
!InstallerV2/lib/platform.sh
!InstallerV2/lib/telemetry.sh
!InstallerV2/lib/ui-cli.sh
!InstallerV2/lib/ui-gui.sh
!InstallerV2/lib/core.sh
lib64/
parts/
sdist/
Expand Down Expand Up @@ -106,4 +117,4 @@ docs/_build/

# Application specific
*.dmg
*.app
*.app
49 changes: 49 additions & 0 deletions InstallerV2/build/create-universal-installer.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#!/usr/bin/env bash
set -euo pipefail

ROOT_DIR="$(cd "$(dirname "$0")/.." && pwd)"
DIST_DIR="$ROOT_DIR/../dist"
OUT="$DIST_DIR/dtu-installer.sh"

mkdir -p "$DIST_DIR"

# Simple concatenation build: create a single script that sources embedded parts.
# For now we just stitch files in a deterministic order; network downloads remain external.

{
echo "#!/usr/bin/env bash"
echo "set -euo pipefail"
echo "# Generated universal installer"
echo "EMBEDDED=1"
echo "ROOT_DIR=\"\$(cd \"\$(dirname \"\${BASH_SOURCE[0]}\")\" && pwd)\""

echo "# --- logging ---"
cat "$ROOT_DIR/lib/logging.sh"
echo "# --- config ---"
cat "$ROOT_DIR/lib/config.sh"
echo "# --- platform ---"
cat "$ROOT_DIR/lib/platform.sh"
echo "# --- telemetry ---"
cat "$ROOT_DIR/lib/telemetry.sh"
echo "# --- ui cli ---"
cat "$ROOT_DIR/lib/ui-cli.sh"
echo "# --- ui gui ---"
cat "$ROOT_DIR/lib/ui-gui.sh"

echo "# --- phases ---"
cat "$ROOT_DIR/phases/pre_install.sh"
cat "$ROOT_DIR/phases/post_install.sh"

echo "# --- components ---"
cat "$ROOT_DIR/components/python.sh"
cat "$ROOT_DIR/components/vscode.sh"
cat "$ROOT_DIR/components/packages.sh"

echo "# --- core ---"
cat "$ROOT_DIR/lib/core.sh"
echo 'main_core "$@"'
} > "$OUT"

chmod +x "$OUT"
echo "Built: $OUT"

41 changes: 41 additions & 0 deletions InstallerV2/components/packages.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#!/usr/bin/env bash

packages_precheck() {
local pybin="$HOME/miniforge3/bin/python3"
if [[ ! -x "$pybin" ]]; then
ui_info "Packages precheck: Miniforge Python not found; packages will be installed when Python is ready."
return 0
fi

local tmpf
tmpf=$(mktemp)
cat > "$tmpf" <<'PY'
import importlib, sys
missing = []
for p in sys.argv[1:]:
try:
importlib.import_module(p)
except Exception:
missing.append(p)
if missing:
print("MISSING:"+",".join(missing))
sys.exit(1)
print("OK")
PY
if "$pybin" "$tmpf" "${DTU_PACKAGES[@]}" >/dev/null 2>&1; then
ui_info "Required packages already installed. Skipping."
rm -f "$tmpf"
return 1
fi
rm -f "$tmpf"
ui_info "Some required packages missing. Will install."
return 0
}

packages_install() {
local conda_bin="$HOME/miniforge3/bin/conda"
[[ -x "$conda_bin" ]] || die "Conda not found; cannot install packages"
announce "Installing required packages via conda-forge"
"$conda_bin" install -y -c conda-forge "${DTU_PACKAGES[@]}"
}

42 changes: 42 additions & 0 deletions InstallerV2/components/python.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#!/usr/bin/env bash

python_is_installed() {
[[ -x "$HOME/miniforge3/bin/python3" ]]
}

python_precheck() {
if python_is_installed; then
ui_info "Python (Miniforge) already installed. Skipping."
return 1
fi
ui_info "Python (Miniforge) not found. Will install."
return 0
}

python_install() {
local url installer prefix
url="$(miniforge_url_for_arch)"
installer="/tmp/miniforge-installer.sh"
prefix="$HOME/miniforge3"

announce "Downloading Miniforge: $url"
curl -fsSL "$url" -o "$installer"

announce "Installing Miniforge to $prefix"
bash "$installer" -b -p "$prefix"

local conda_bin
conda_bin="$prefix/bin/conda"
[[ -x "$conda_bin" ]] || die "Conda not found after Miniforge install"

announce "Configuring conda channels"
"$conda_bin" config --set channel_priority strict || true
"$conda_bin" config --remove channels defaults || true
"$conda_bin" config --add channels conda-forge || true

announce "Ensuring Python ${DTU_PYTHON_VERSION}"
"$conda_bin" install -y "python=${DTU_PYTHON_VERSION}"

ui_info "Miniforge installed at $prefix"
}

74 changes: 74 additions & 0 deletions InstallerV2/components/vscode.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
#!/usr/bin/env bash

vscode_is_installed() {
if command -v code >/dev/null 2>&1; then return 0; fi
if [[ -d "/Applications/Visual Studio Code.app" ]] || [[ -d "$HOME/Applications/Visual Studio Code.app" ]]; then return 0; fi
return 1
}

_resolve_code_bin() {
if command -v code >/dev/null 2>&1; then
command -v code
return 0
fi
if [[ -x "/Applications/Visual Studio Code.app/Contents/Resources/app/bin/code" ]]; then
echo "/Applications/Visual Studio Code.app/Contents/Resources/app/bin/code"
return 0
fi
if [[ -x "$HOME/Applications/Visual Studio Code.app/Contents/Resources/app/bin/code" ]]; then
echo "$HOME/Applications/Visual Studio Code.app/Contents/Resources/app/bin/code"
return 0
fi
return 1
}

vscode_precheck() {
if vscode_is_installed; then
ui_info "VS Code already installed. Skipping."
return 1
fi
ui_info "VS Code not found. Will install."
return 0
}

vscode_install() {
announce "Installing Visual Studio Code"
local target_app="/Applications"
if [[ ! -w "$target_app" ]]; then
target_app="$HOME/Applications"
mkdir -p "$target_app"
fi

if command -v brew >/dev/null 2>&1; then
announce "Using Homebrew to install VS Code"
brew install --cask visual-studio-code || true
else
announce "Downloading VS Code (no Homebrew detected)"
local url zip tmp
url="https://update.code.visualstudio.com/latest/darwin/universal/stable"
tmp=$(mktemp -d)
zip="$tmp/vscode.zip"
curl -fsSL "$url" -o "$zip"
(cd "$tmp" && unzip -q "$zip")
# Expect "Visual Studio Code.app" folder
if [[ -d "$tmp/Visual Studio Code.app" ]]; then
rm -rf "$target_app/Visual Studio Code.app"
mv "$tmp/Visual Studio Code.app" "$target_app/"
else
warn "VS Code archive did not contain expected app bundle"
fi
rm -rf "$tmp"
fi

# Try to install extensions
local codebin
if codebin=$(_resolve_code_bin); then
for ext in "${VSCODE_EXTENSIONS[@]}"; do
"$codebin" --install-extension "$ext" || true
done
ui_info "Installed VS Code extensions."
else
warn "VS Code CLI not found; could not install extensions automatically."
fi
}

22 changes: 22 additions & 0 deletions InstallerV2/install.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#!/usr/bin/env bash
set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
ROOT_DIR="$SCRIPT_DIR"

source "$ROOT_DIR/lib/logging.sh"
source "$ROOT_DIR/lib/config.sh"
source "$ROOT_DIR/lib/platform.sh"
source "$ROOT_DIR/lib/telemetry.sh"

source "$ROOT_DIR/phases/pre_install.sh"
source "$ROOT_DIR/phases/post_install.sh"

source "$ROOT_DIR/components/python.sh"
source "$ROOT_DIR/components/vscode.sh"
source "$ROOT_DIR/components/packages.sh"

source "$ROOT_DIR/lib/core.sh"

main_core "$@"

16 changes: 16 additions & 0 deletions InstallerV2/lib/config.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#!/usr/bin/env bash

# User-facing flags (parsed in core):
# --cli | --gui | --dry-run | --no-analytics | --prefix=PATH

# Defaults align with existing MacOS/config.sh but isolated here for V2.
DTU_PYTHON_VERSION=${DTU_PYTHON_VERSION:-"3.12"}
DTU_PACKAGES=("dtumathtools" "pandas" "scipy" "statsmodels" "uncertainties")
VSCODE_EXTENSIONS=("ms-python.python" "ms-toolsai.jupyter" "tomoki1207.pdf")

MINIFORGE_BASE_URL=${MINIFORGE_BASE_URL:-"https://github.com/conda-forge/miniforge/releases/latest/download/Miniforge3-MacOSX"}
INSTALL_PREFIX=${INSTALL_PREFIX:-"$HOME"}

# Analytics
DTU_ANALYTICS_ENABLED=${DTU_ANALYTICS_ENABLED:-"1"}

Loading
Loading