diff --git a/.devcontainer/vscode-init/extensions-to-install.txt b/.devcontainer/vscode-init/extensions-to-install.txt index 08d66b1..e2ca3e6 100644 --- a/.devcontainer/vscode-init/extensions-to-install.txt +++ b/.devcontainer/vscode-init/extensions-to-install.txt @@ -2,7 +2,7 @@ # These extensions will be enabled for all users of the devcontainer. # One extension ID per line. charliermarsh.ruff -Continue.continue +#Continue.continue DavidAnson.vscode-markdownlint eamodio.gitlens # The marimo extension has been removed from the marketplace whilst it is being rewritten. @@ -12,7 +12,7 @@ ms-ossdata.vscode-pgsql --pre-release ms-python.black-formatter ms-toolsai.datawrangler ms-toolsai.jupyter -openai.chatgpt +#openai.chatgpt REditorSupport.r REditorSupport.r-syntax yzhang.markdown-all-in-one \ No newline at end of file diff --git a/.github/workflows/build-devcontainer.yml b/.github/workflows/build-devcontainer.yml index 6c47636..64798ac 100644 --- a/.github/workflows/build-devcontainer.yml +++ b/.github/workflows/build-devcontainer.yml @@ -126,42 +126,56 @@ jobs: echo "=== Dev container validation completed! ===" + # Free up disk space before security scan to prevent "no space left on device" errors + - name: Free Disk Space + run: | + echo "=== Disk space before cleanup ===" + df -h + echo "=== Removing unnecessary files ===" + sudo rm -rf /usr/share/dotnet + sudo rm -rf /usr/local/lib/android + sudo rm -rf /opt/ghc + sudo rm -rf /opt/hostedtoolcache/CodeQL + sudo apt-get clean + echo "=== Disk space after cleanup ===" + df -h + # Using the custom Trivy Security Scan action from this repository - # - name: Security Scan - # id: security-scan - # uses: smartdatafoundry/trivy-security-scan@v1.0.0 - # with: - # image-ref: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} - # registry: ${{ env.REGISTRY }} - # severity: 'CRITICAL,HIGH' - # detailed-severity: 'CRITICAL,HIGH,MEDIUM,LOW' - # ignore-unfixed: 'true' - # exit-code: '0' - # artifact-name: 'security-scan-results' - # artifact-retention-days: '30' - # github-token: ${{ secrets.GITHUB_TOKEN }} - # post-pr-comment: 'true' + - name: Security Scan + id: security-scan + uses: smartdatafoundry/trivy-security-scan@v1.0.0 + with: + image-ref: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + registry: ${{ env.REGISTRY }} + severity: 'CRITICAL,HIGH' + detailed-severity: 'CRITICAL,HIGH,MEDIUM,LOW' + ignore-unfixed: 'true' + exit-code: '0' + artifact-name: 'security-scan-results' + artifact-retention-days: '30' + github-token: ${{ secrets.GITHUB_TOKEN }} + post-pr-comment: 'true' - # # Optional: Handle scan results programmatically - # - name: Process scan results - # run: | - # echo "Security scan status: ${{ steps.security-scan.outputs.scan-status }}" - # echo "Vulnerabilities found: ${{ steps.security-scan.outputs.vulnerability-count }}" - # echo "Artifact ID: ${{ steps.security-scan.outputs.artifact-id }}" + # Optional: Handle scan results programmatically + - name: Process scan results + run: | + echo "Security scan status: ${{ steps.security-scan.outputs.scan-status }}" + echo "Vulnerabilities found: ${{ steps.security-scan.outputs.vulnerability-count }}" + echo "Artifact ID: ${{ steps.security-scan.outputs.artifact-id }}" - # # You can add custom logic here based on the scan results - # if [ "${{ steps.security-scan.outputs.scan-status }}" = "vulnerabilities_found" ]; then - # echo "⚠️ Security vulnerabilities detected!" - # echo "Consider reviewing the security report before deploying." + # You can add custom logic here based on the scan results + if [ "${{ steps.security-scan.outputs.scan-status }}" = "vulnerabilities_found" ]; then + echo "⚠️ Security vulnerabilities detected!" + echo "Consider reviewing the security report before deploying." - # # Optionally, you could fail the build for critical vulnerabilities: - # # if [ "${{ steps.security-scan.outputs.vulnerability-count }}" -gt "10" ]; then - # # echo "❌ Too many vulnerabilities found (> 10), failing build" - # # exit 1 - # # fi - # else - # echo "✅ No critical or high severity vulnerabilities found!" - # fi + # Optionally, you could fail the build for critical vulnerabilities: + # if [ "${{ steps.security-scan.outputs.vulnerability-count }}" -gt "10" ]; then + # echo "❌ Too many vulnerabilities found (> 10), failing build" + # exit 1 + # fi + else + echo "✅ No critical or high severity vulnerabilities found!" + fi - name: Container info if: success() diff --git a/DEVCONTAINER.md b/DEVCONTAINER.md index 3ad38a9..ca72529 100644 --- a/DEVCONTAINER.md +++ b/DEVCONTAINER.md @@ -1,6 +1,6 @@ # Dev Container for Python & R Development -This repository contains a development container configuration optimized for Python (and first-class R) development, along with automated workflows to build and publish the container image to GitHub Container Registry (GHCR). For high-level usage see `README.md`; this document focuses on implementation details. +This repository contains a development container configuration optimised for Python (and first-class R) development, along with automated workflows to build and publish the container image to GitHub Container Registry (GHCR). For high-level usage see [`README.md`](README.md); this document focuses on implementation details. ## 📦 Published Container @@ -74,13 +74,69 @@ This dev container includes: * **Quarto**: Latest (document publishing) * **Marimo**: Alternative interactive notebook/presentation tool * **VS Code Server**: Pre-installed (pin via tag families) -* **VS Code Extensions**: Curated list (see `.devcontainer/vscode-init/extensions-to-install.txt`) +* **VS Code Extensions**: Curated list (see [`.devcontainer/vscode-init/extensions-to-install.txt`](.devcontainer/vscode-init/extensions-to-install.txt)) +* **User Setup Scripts**: Automated deployment and management tools + +### User Setup Scripts + +The container includes scripts in [`/workspace/scripts/`](scripts/) to simplify deployment and management: + +#### [`scripts/devcontainerctl`](scripts/devcontainerctl) +A comprehensive container lifecycle management script that provides: + +**Features:** +- Automatic image updates with VS Code tag alignment +- Container lifecycle management (start, stop, restart, remove) +- Status monitoring +- Automatic home directory and `/safedata` mounting +- Proxy configuration inheritance +- Background update notifications + +**Commands:** +- `start` - Pull latest image matching your VS Code version and start container +- `stop` - Stop the running container +- `restart` - Restart the container +- `status` - Show current container status +- `sync` - Update to latest matching image (used by cron) +- `update` - Stop, update, and restart with new image +- `remove` - Stop and remove the container + +**Usage:** +```bash +devcontainerctl start # Start with auto-detected VS Code version +devcontainerctl start vscode-abc123 # Start with specific tag +devcontainerctl status # Check status +devcontainerctl sync # Update image (used by daily cron) +``` + +#### [`scripts/setup.sh`](scripts/setup.sh) +One-time setup script that configures your environment: + +**What it does:** +- Creates `~/bin` directory if needed +- Creates symlink to `devcontainerctl` in `~/bin` +- Adds `~/bin` to PATH in `~/.bashrc` +- Configures daily cron job (8:00 AM) to sync images + +**Usage:** +```bash +# Extract scripts from container first +podman run --rm -v $HOME:$HOME -w $HOME \ + ghcr.io/smartdatafoundry/devcontainer:latest \ + cp -r /workspace/scripts $HOME/devcontainer-scripts + +# Run setup +cd $HOME/devcontainer-scripts +./setup.sh +``` + +After setup, the `devcontainerctl` command will be available system-wide, and your devcontainer image will automatically stay up-to-date. ## 🔄 Automated Builds The container is built using GitHub Actions with controlled publishing: -### Build Workflow (`build-devcontainer.yml`) +### Build Workflow ([`build-devcontainer.yml`](.github/workflows/build-devcontainer.yml)) - **PR Triggers**: Pull requests automatically build test images (`pr-` tags) using default VS Code Server commit - **Manual Dispatch**: Production builds require manual trigger with VS Code Server commit hash - **Required Input**: VS Code Server commit hash for reproducible builds @@ -105,7 +161,7 @@ export VSCODE_COMMIT=0f0d87fa9e96c856c5212fc86db137ac0d783365 devcontainer build --workspace-folder . ``` -This keeps maintenance simple: update the default by editing a single line in `Dockerfile` with support for overrides when needed via workflow inputs. +This keeps maintenance simple: update the default by editing a single line in [`Dockerfile`](.devcontainer/Dockerfile) with support for overrides when needed via workflow inputs. ## 📁 Repository Structure @@ -122,6 +178,9 @@ This keeps maintenance simple: update the default by editing a single line in `D ├── .github/workflows/ │ ├── build-devcontainer.yml # Build and publish workflow │ └── build-publish-container.yml +├── scripts/ # User deployment scripts +│ ├── devcontainerctl # Container management script +│ └── setup.sh # One-time setup script ├── assets/ # Documentation assets ├── docs/ # Additional documentation ├── DEVCONTAINER.md # Detailed documentation @@ -134,7 +193,7 @@ This keeps maintenance simple: update the default by editing a single line in `D To customize this dev container for your needs: 1. Fork this repository -2. Modify `.devcontainer/devcontainer.json`: +2. Modify [`.devcontainer/devcontainer.json`](.devcontainer/devcontainer.json): - Add/remove features - Update VS Code extensions - Change base image or configuration @@ -142,6 +201,7 @@ To customize this dev container for your needs: 4. Push changes - the container will be built automatically ## 🏗️ Local Development + ## 🔄 Automated Build Process The container images are built and published automatically using GitHub Actions with intelligent tagging: @@ -185,7 +245,7 @@ devcontainer exec --workspace-folder . bash 1. Fork the repository 2. Create a feature branch -3. Make your changes to `.devcontainer/devcontainer.json` +3. Make your changes to [`.devcontainer/devcontainer.json`](.devcontainer/devcontainer.json) 4. Test locally using the devcontainer CLI 5. Submit a pull request diff --git a/README.md b/README.md index 8ea8c95..4723adc 100644 --- a/README.md +++ b/README.md @@ -55,11 +55,44 @@ Add this to your `.devcontainer/devcontainer.json`: ### Using in SDF Trusted Research Environment -See the **[SDF TRE Setup Guide](SDF_TRE_SETUP.md)** for: -* Manual Dev Containers extension install & extraction -* Podman configuration -* Proxy / network specifics -* Troubleshooting in constrained environments +#### Quick Setup with Included Scripts (Recommended) + +The devcontainer includes setup scripts for easy deployment in the SDF TRE: + +```bash +# 1. Pull the container image +ces-pull a a ghcr.io/smartdatafoundry/devcontainer:latest + +# 2. Extract the setup scripts +podman run --rm -v $HOME:$HOME -w $HOME \ + ghcr.io/smartdatafoundry/devcontainer:latest \ + cp -r /workspace/scripts $HOME/devcontainer-scripts + +# 3. Run the setup script (one-time setup) +cd $HOME/devcontainer-scripts +./setup.sh + +# 4. Start your devcontainer +devcontainerctl start +``` + +The setup script will: +- Create a symlink to `devcontainerctl` in `~/bin` +- Add `~/bin` to your PATH +- Configure a daily cron job to keep the image updated + +Available `devcontainerctl` commands: +- `devcontainerctl start` - Pull latest image and start container +- `devcontainerctl stop` - Stop the container +- `devcontainerctl restart` - Restart the container +- `devcontainerctl status` - Check container status +- `devcontainerctl sync` - Update the container image +- `devcontainerctl update` - Update and restart with new image +- `devcontainerctl remove` - Stop and remove the container + +#### Manual Setup + +For detailed manual setup instructions, see the **[SDF TRE Setup Guide](SDF_TRE_SETUP.md)**. ### Using This Repository Directly @@ -71,9 +104,10 @@ See the **[SDF TRE Setup Guide](SDF_TRE_SETUP.md)** for: | Topic | Reference | |-------|-----------| -| SDF TRE usage | `SDF_TRE_SETUP.md` | -| Full container internals | `DEVCONTAINER.md` | -| Reusable publish workflow | `docs/BUILD_PUBLISH_CONTAINER.md` | +| SDF TRE usage | [`SDF_TRE_SETUP.md`](SDF_TRE_SETUP.md) | +| Full container internals | [`DEVCONTAINER.md`](DEVCONTAINER.md) | +| Setup scripts | [`scripts/`](scripts/) directory | +| Reusable publish workflow | [`docs/BUILD_PUBLISH_CONTAINER.md`](docs/BUILD_PUBLISH_CONTAINER.md) | | Dev Container Specification | https://containers.dev | ## 🛠️ What's Included @@ -85,6 +119,7 @@ See the **[SDF TRE Setup Guide](SDF_TRE_SETUP.md)** for: - **Shell**: Zsh with Oh My Zsh (via common-utils feature) - **Quarto**: Document publishing platform (latest version) - **Marimo**: Markdown presentation tool, alternative to Jupyter Notebooks +- **User Setup Scripts**: Automated deployment and management tools ([`scripts/`](scripts/)) - **VS Code Extensions (curated)**: - Continue (AI assistant) - Black (Python formatting) @@ -92,7 +127,7 @@ See the **[SDF TRE Setup Guide](SDF_TRE_SETUP.md)** for: - Marimo - Markdown All in One - Rainbow CSV - - (See `.devcontainer/vscode-init/extensions-to-install.txt` for authoritative list) + - (See [`.devcontainer/vscode-init/extensions-to-install.txt`](.devcontainer/vscode-init/extensions-to-install.txt) for authoritative list) - **VS Code Server**: Pre-installed for immediate development ## 📊 R Language Support @@ -112,20 +147,20 @@ This dev container includes comprehensive R language support through the [Rocker ## ⚙️ VS Code Server -Pre-installed. Pin a version using the tag families described above or via build arg `VSCODE_COMMIT`. For environment-specific considerations (e.g. TRE) see `SDF_TRE_SETUP.md`. +Pre-installed. Pin a version using the tag families described above or via build arg `VSCODE_COMMIT`. For environment-specific considerations (e.g. TRE) see [`SDF_TRE_SETUP.md`](SDF_TRE_SETUP.md). ## Adding New Extensions To add new VS Code extensions to the container, follow these steps: -1. Open the appropriate file in `.devcontainer/vscode-init/`: - - `extensions-to-install.txt` for extensions to install directly - - `extensions-to-download.txt` for extensions that need to be downloaded +1. Open the appropriate file in [`.devcontainer/vscode-init/`](.devcontainer/vscode-init/): + - [`extensions-to-install.txt`](.devcontainer/vscode-init/extensions-to-install.txt) for extensions to install directly + - [`extensions-to-download.txt`](.devcontainer/vscode-init/extensions-to-download.txt) for extensions that you want to be downloaded 2. Add the identifier of the desired extension in the format `publisher.extensionName` on a new line. 3. Save the changes to the extension file. 4. Commit and push the changes to your repository to trigger the build workflow with the updated extensions ## 🔄 Automated Builds & Tag Strategy -Workflow: `.github/workflows/build-devcontainer.yml` +Workflow: [`.github/workflows/build-devcontainer.yml`](.github/workflows/build-devcontainer.yml) Triggers: * Pull Requests touching devcontainer/workflow files → build + `pr-` tag @@ -149,7 +184,7 @@ Tag usage quick reference: | Pin VS Code Server only | `vscode-` | | Full reproducibility | `vscode--` | -Reusable generic Docker workflow documentation: see `docs/BUILD_PUBLISH_CONTAINER.md`. +Reusable generic Docker workflow documentation: see [`docs/BUILD_PUBLISH_CONTAINER.md`](docs/BUILD_PUBLISH_CONTAINER.md). --- ## 🤝 Contributing & License diff --git a/SDF_TRE_SETUP.md b/SDF_TRE_SETUP.md index 4dbee9c..556625b 100644 --- a/SDF_TRE_SETUP.md +++ b/SDF_TRE_SETUP.md @@ -4,7 +4,32 @@ This guide provides step-by-step instructions for setting up and using dev conta ## Quick Start -The quick start is for users familiar with the TRE and using Dev Containers. If you haven't done this setup before, please read the rest of this document instead of the quick start. +### Automated Setup (Recommended) + +For users who want the fastest setup with automatic updates: + +```bash +# 1. Pull the devcontainer image +ces-pull a a ghcr.io/smartdatafoundry/devcontainer:latest + +# 2. Extract the setup scripts +podman run --rm -v $HOME:$HOME -w $HOME \ + ghcr.io/smartdatafoundry/devcontainer:latest \ + cp -r /workspace/scripts $HOME/devcontainer-scripts + +# 3. Run the one-time setup +cd $HOME/devcontainer-scripts +./setup.sh + +# 4. Start your devcontainer +devcontainerctl start +``` + +See the "Using the Setup Scripts" section below for details. + +### Manual Setup + +For users who prefer manual control or are setting this up for the first time: 1. Pull the devcontainer image 2. Extract and install the [Dev Containers extension](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers) @@ -17,6 +42,68 @@ The quick start is for users familiar with the TRE and using Dev Containers. If 7. Wait for container to start 8. Do your work +See the sections below for detailed instructions. + +## Using the Setup Scripts (Recommended) + +The devcontainer includes scripts that automate deployment and management in the TRE environment. + +### One-Time Setup + +After extracting the scripts (see Quick Start above), run the setup script: + +```bash +cd $HOME/devcontainer-scripts +./setup.sh +``` + +This script will: +- Create `~/bin` directory if it doesn't exist +- Create a symlink to `devcontainerctl` in `~/bin` +- Add `~/bin` to your PATH (in `~/.bashrc`) +- Configure a daily cron job (8:00 AM) to keep your image updated + +After running the setup, either restart your terminal or run: +```bash +source ~/.bashrc +``` + +### Daily Usage + +Once setup is complete, you can use the `devcontainerctl` command: + +```bash +# Start your devcontainer (pulls latest matching image if needed) +devcontainerctl start + +# Check status +devcontainerctl status + +# Stop the container +devcontainerctl stop + +# Restart the container +devcontainerctl restart + +# Update to latest image and restart +devcontainerctl update + +# Remove the container completely +devcontainerctl remove +``` + +### Automatic Features + +The setup provides several automatic features: + +1. **Daily Updates**: A cron job runs at 8:00 AM daily to sync your container image with the latest version matching your VS Code installation + +2. **VS Code Tag Alignment**: The `devcontainerctl start` command automatically detects your installed VS Code version and pulls the matching container image tag (e.g., `vscode-abc1234`) + +3. **Automatic Mounting**: Your home directory and `/safedata` are automatically mounted when the container starts + +4. **Proxy Configuration**: HTTP proxy settings are inherited from your environment automatically + ## Prerequisites Verify you have access to `ces-pull` and Podman within your TRE workspace. @@ -147,7 +234,7 @@ This approach leverages container technology directly while maintaining the abil The container ships with VS Code Server pre-installed. To ensure reproducibility or to match an existing TRE host version, specify the commit hash: 1. Check your TRE VS Code version via _Help > About_ -2. The VS Code commit value is declared in the `Dockerfile` and can be overriden via workflow inputs. +2. The VS Code commit value is declared in the [`Dockerfile`](.devcontainer/Dockerfile) and can be overridden via workflow inputs. ## Troubleshooting @@ -174,6 +261,20 @@ If you experience network-related delays: - Ensure your proxy settings are correctly configured in the `runArgs` (HTTP_PROXY and HTTPS_PROXY are essential) - File system responsiveness may vary depending on TRE network conditions +### Script Issues + +If `devcontainerctl` command is not found: + +- Ensure you've run the setup script: `./setup.sh` +- Check that `~/bin` is in your PATH: `echo $PATH` +- Try restarting your terminal or running: `source ~/.bashrc` + +If cron job is not running: + +- Verify it's configured: `crontab -l` +- Check cron logs for errors +- Manually test the sync command: `devcontainerctl sync` + ## Support For any other issues: diff --git a/scripts/devcontainerctl b/scripts/devcontainerctl new file mode 100755 index 0000000..1161366 --- /dev/null +++ b/scripts/devcontainerctl @@ -0,0 +1,134 @@ +#!/bin/bash + +# Colors for output +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +RED='\033[0;31m' +NC='\033[0m' # No Color + +VSCODE_TAG="${2:-vscode-$(code --version | sed -n '2p' | cut -c1-7)}" +CONTAINER_NAME="devcontainer" + +show_usage() { + echo "Combined script to start or stop the devcontainer" + echo "Usage: devcontainerctl [start | stop | restart | remove | shell | status | sync] VSCODE_TAG" +} + +get_latest_devcontainer() { + local rc="${1:-false}" + + # print a message after 30 seconds if the pull is still ongoing + ( + sleep 30 + echo -e "\n${YELLOW}Updates can take some time, please be patient...${NC}\n" + ) & + background_pid=$! + trap "kill $background_pid 2>/dev/null" RETURN + + # Always attempt to install the aligned devcontainer + echo "Checking for devcontainer updates..." + if [ "$rc" = "true" ]; then + ces-pull sdf-build-git $GITHUB_TOKEN ghcr.io/smartdatafoundry/devcontainer:$VSCODE_TAG \ + | sed "s/$GITHUB_TOKEN/********/g" + podman tag ghcr.io/smartdatafoundry/devcontainer:$VSCODE_TAG \ + ghcr.io/smartdatafoundry/devcontainer:latest + else + ces-pull a a ghcr.io/smartdatafoundry/devcontainer:$VSCODE_TAG + podman tag ghcr.io/smartdatafoundry/devcontainer:$VSCODE_TAG \ + ghcr.io/smartdatafoundry/devcontainer:latest + fi +} + +start() { + echo "Starting devcontainer..." + + get_latest_devcontainer + + # Stop and remove any existing containers with these names + podman stop $CONTAINER_NAME 2>/dev/null + podman rm $CONTAINER_NAME 2>/dev/null + + # Start devcontainer + podman run -d \ + --name devcontainer \ + --restart unless-stopped \ + -e http_proxy \ + -v /safedata:/safedata \ + -v $HOME:$HOME \ + -w $HOME \ + ghcr.io/smartdatafoundry/devcontainer:$VSCODE_TAG sleep infinity + + echo "devcontainer service started. Check status with '$0 status'" +} + +stop() { + echo "Stopping devcontainer service..." + podman stop $CONTAINER_NAME 2>/dev/null + echo "devcontainer stopped." +} + +remove() { + echo "Stopping and removing devcontainer service..." + podman stop $CONTAINER_NAME 2>/dev/null + podman rm $CONTAINER_NAME 2>/dev/null + echo "devcontainer stopped and removed." +} + +shell() { + echo "Opening shell in devcontainer..." + podman exec -it $CONTAINER_NAME /bin/bash +} + +show_status() { + echo "devcontainer Service Status:" + echo "===========================" + status=$(podman ps -a --filter "name=$CONTAINER_NAME" --format "{{.Status}}" 2>/dev/null) + if [ -n "$status" ]; then + echo "$CONTAINER_NAME: $status" + else + echo "$CONTAINER_NAME: Not found" + fi +} + +update() { + echo "Updating devcontainer image..." + remove + start # Restarts the container with the updated image automatically + echo "devcontainer replaced with updated image." +} + +# Main script logic +case "${1:-}" in + start) + start + ;; + stop) + stop + ;; + restart) + stop + start + ;; + status) + show_status + ;; + remove) + remove + ;; + shell) + shell + ;; + sync) + get_latest_devcontainer + ;; + sync-rc) + get_latest_devcontainer true + ;; + update) + update + ;; + *) + show_usage + exit 1 + ;; +esac diff --git a/scripts/setup.sh b/scripts/setup.sh new file mode 100644 index 0000000..9319da2 --- /dev/null +++ b/scripts/setup.sh @@ -0,0 +1,83 @@ +#!/bin/bash + +set -e + +# Colors for output +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +RED='\033[0;31m' +NC='\033[0m' # No Color + +echo -e "${GREEN}DevContainer Setup Script${NC}" +echo "================================" + +# Define paths +SCRIPT_DIR="$(dirname "$(readlink -f "$0")")" +SCRIPT_SOURCE="$SCRIPT_DIR/devcontainerctl" +SYMLINK_TARGET="$HOME/bin/devcontainerctl" +CRON_COMMAND="0 8 * * * $SYMLINK_TARGET sync" + +# Check if source script exists +if [ ! -f "$SCRIPT_SOURCE" ]; then + echo -e "${RED}Error: Source script not found at $SCRIPT_SOURCE${NC}" + exit 1 +fi + +# Create ~/bin directory if it doesn't exist +if [ ! -d "$HOME/bin" ]; then + echo -e "${YELLOW}Creating $HOME/bin directory...${NC}" + mkdir -p "$HOME/bin" +fi + +# Create symlink +if [ -L "$SYMLINK_TARGET" ]; then + echo -e "${YELLOW}Symlink already exists at $SYMLINK_TARGET${NC}" + echo "Removing old symlink..." + rm "$SYMLINK_TARGET" +fi + +echo -e "${GREEN}Creating symlink: $SYMLINK_TARGET -> $SCRIPT_SOURCE${NC}" +ln -s "$SCRIPT_SOURCE" "$SYMLINK_TARGET" + +# Make sure the source script is executable +if [ ! -x "$SCRIPT_SOURCE" ]; then + echo -e "${YELLOW}Warning: $SCRIPT_SOURCE is not executable${NC}" + echo "You may need to run: sudo chmod +x $SCRIPT_SOURCE" +fi + +# Add ~/bin to PATH if not already present +if [[ ":$PATH:" != *":$HOME/bin:"* ]]; then + echo -e "${YELLOW}Adding $HOME/bin to PATH in ~/.bashrc${NC}" + echo '' >> "$HOME/.bashrc" + echo '# Added by devcontainer setup' >> "$HOME/.bashrc" + echo 'export PATH="$HOME/bin:$PATH"' >> "$HOME/.bashrc" + echo -e "${GREEN}Please run: source ~/.bashrc${NC}" +fi + +# Configure cron job +echo -e "${GREEN}Configuring cron job...${NC}" + +# Check if cron job already exists +if crontab -l 2>/dev/null | grep -q "devcontainerctl sync"; then + echo -e "${YELLOW}Cron job already exists. Removing old entry...${NC}" + crontab -l 2>/dev/null | grep -v "devcontainerctl sync" | crontab - +fi + +# Add new cron job +(crontab -l 2>/dev/null; echo "$CRON_COMMAND") | crontab - + +echo -e "${GREEN}Cron job added successfully!${NC}" +echo "Schedule: Daily at 8:00 AM" +echo "Command: $CRON_COMMAND" + +# Verify installation +echo "" +echo "================================" +echo -e "${GREEN}Setup Complete!${NC}" +echo "" +echo "Verification:" +echo " Symlink: $(ls -la $SYMLINK_TARGET 2>/dev/null || echo 'Not found')" +echo " Cron job:" +crontab -l | grep "devcontainerctl sync" || echo " Not found" +echo "" +echo -e "${YELLOW}Note: You may need to restart your shell or run 'source ~/.bashrc'${NC}" \ No newline at end of file