diff --git a/CLAUDE.md b/CLAUDE.md index 5cddb7fd0..4be85fcc9 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -10,6 +10,42 @@ ## Project Overview Coolify is an open-source, self-hostable platform for deploying applications and managing servers - an alternative to Heroku/Netlify/Vercel. It's built with Laravel (PHP) and uses Docker for containerization. +## Git Worktree Shared Dependencies + +This repository uses git worktrees for parallel development with **automatic shared dependency setup** via Conductor. + +### How It Works + +The `conductor.json` setup script (`scripts/conductor-setup.sh`) automatically: +1. Creates symlinks from worktree's `node_modules` and `vendor` to the main repository's directories +2. All worktrees share the same dependencies from the main repository +3. This happens automatically when Conductor creates a new worktree + +### Benefits + +- **Save disk space**: Only one copy of dependencies across all worktrees +- **Faster setup**: No need to run `npm install` or `composer install` for each worktree +- **Consistent versions**: All worktrees use the same dependency versions +- **Auto-configured**: Handled by Conductor's setup script +- **Simple**: Uses the main repo's existing directories, no extra folders + +### Manual Setup (If Needed) + +If you need to set up symlinks manually or for non-Conductor worktrees: + +```bash +# From the worktree directory +rm -rf node_modules vendor +ln -sf ../../node_modules node_modules +ln -sf ../../vendor vendor +``` + +### Important Notes + +- Dependencies are shared from the main repository (`$CONDUCTOR_ROOT_PATH`) +- Run `npm install` or `composer install` from the main repo or any worktree to update all +- If different branches need different dependency versions, this won't work - remove symlinks and use separate directories + ## Development Commands ### Frontend Development diff --git a/scripts/conductor-setup.sh b/scripts/conductor-setup.sh index 7712f88be..a88b457fb 100755 --- a/scripts/conductor-setup.sh +++ b/scripts/conductor-setup.sh @@ -1 +1,97 @@ -cp $CONDUCTOR_ROOT_PATH/.env .env \ No newline at end of file +#!/bin/bash +set -e + +# Validate CONDUCTOR_ROOT_PATH is set and valid before any operations +if [ -z "$CONDUCTOR_ROOT_PATH" ]; then + echo "ERROR: CONDUCTOR_ROOT_PATH environment variable is not set" + echo "This script must be run by Conductor with CONDUCTOR_ROOT_PATH set to the main repository path" + exit 1 +fi + +if [ ! -d "$CONDUCTOR_ROOT_PATH" ]; then + echo "ERROR: CONDUCTOR_ROOT_PATH ($CONDUCTOR_ROOT_PATH) is not a valid directory" + exit 1 +fi + +# Copy .env file +cp "$CONDUCTOR_ROOT_PATH/.env" .env + +# Setup shared dependencies via symlinks to main repo +echo "Setting up shared node_modules and vendor directories..." + +# Ensure main repo has the directories +mkdir -p "$CONDUCTOR_ROOT_PATH/node_modules" +mkdir -p "$CONDUCTOR_ROOT_PATH/vendor" + +# Get current worktree path +WORKTREE_PATH=$(pwd) + +# Safety check 1: ensure WORKTREE_PATH is valid +if [ -z "$WORKTREE_PATH" ]; then + echo "ERROR: WORKTREE_PATH is empty" + exit 1 +fi + +# Safety check 2: CRITICAL FIRST - blacklist system directories +# This check runs BEFORE the positive check to prevent dangerous operations +# even if someone misconfigures CONDUCTOR_ROOT_PATH +case "$WORKTREE_PATH" in + /|/bin|/sbin|/usr|/usr/*|/etc|/etc/*|/var|/var/*|/System|/System/*|/Library|/Library/*|/Applications|/Applications/*|"$HOME") + echo "ERROR: WORKTREE_PATH ($WORKTREE_PATH) is in a dangerous system location" + exit 1 + ;; +esac + +# Safety check 3: positive check - verify we're under CONDUCTOR_ROOT_PATH +case "$WORKTREE_PATH" in + "$CONDUCTOR_ROOT_PATH"|"$CONDUCTOR_ROOT_PATH"/.conductor/*) + # Valid: either main repo or under .conductor/ + ;; + *) + echo "ERROR: WORKTREE_PATH ($WORKTREE_PATH) is not under CONDUCTOR_ROOT_PATH ($CONDUCTOR_ROOT_PATH)" + exit 1 + ;; +esac + +# Safety check 4: verify we're in a git repository +if [ ! -f ".git" ] && [ ! -d ".git" ]; then + echo "ERROR: Not in a git repository" + exit 1 +fi + +# Remove existing directories/symlinks if they exist +# For symlinks: use 'rm' without -r to remove the symlink itself (not following it) +# For directories: use 'rm -rf' to remove the directory and contents +if [ -L "node_modules" ]; then + # It's a symlink - remove it without following (no -r flag) + rm "$WORKTREE_PATH/node_modules" +elif [ -e "node_modules" ]; then + # It's a regular directory or file - safe to use -rf + rm -rf "$WORKTREE_PATH/node_modules" +fi + +if [ -L "vendor" ]; then + # It's a symlink - remove it without following (no -r flag) + rm "$WORKTREE_PATH/vendor" +elif [ -e "vendor" ]; then + # It's a regular directory or file - safe to use -rf + rm -rf "$WORKTREE_PATH/vendor" +fi + +# Calculate relative path from worktree to main repo +# Use bash-native approach: try realpath first (GNU coreutils), fallback to perl +if command -v realpath &> /dev/null && realpath --relative-to / / &> /dev/null 2>&1; then + # GNU coreutils realpath with --relative-to support + RELATIVE_PATH=$(realpath --relative-to="$WORKTREE_PATH" "$CONDUCTOR_ROOT_PATH") +else + # Fallback: use perl which is standard on macOS and most Unix systems + RELATIVE_PATH=$(perl -e 'use File::Spec; print File::Spec->abs2rel($ARGV[0], $ARGV[1])' "$CONDUCTOR_ROOT_PATH" "$WORKTREE_PATH") +fi + +# Create symlinks to main repo's node_modules and vendor +ln -sf "$RELATIVE_PATH/node_modules" node_modules +ln -sf "$RELATIVE_PATH/vendor" vendor + +echo "✓ Shared dependencies linked successfully" +echo " node_modules -> $RELATIVE_PATH/node_modules" +echo " vendor -> $RELATIVE_PATH/vendor" \ No newline at end of file