Last active
December 4, 2025 10:52
-
-
Save Vitexus/7d27f958cb0309c505917bea49ff12d8 to your computer and use it in GitHub Desktop.
A powerful Bash script that automates PHP development workflow by replacing Composer-installed vendor dependencies with symbolic links to local development versions.
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 | |
| # Development Symlink Manager | |
| # Automaticky nahrazuje Composer závislosti symlinky na lokální vývojové verze | |
| # Autor: GitHub Copilot pro VitexSoftware | |
| # Datum: $(date +"%Y-%m-%d") | |
| set -e | |
| # Barvy pro výstup | |
| RED='\033[0;31m' | |
| GREEN='\033[0;32m' | |
| YELLOW='\033[1;33m' | |
| BLUE='\033[0;34m' | |
| NC='\033[0m' # No Color | |
| # Funkce pro logování | |
| log_info() { | |
| echo -e "${BLUE}[INFO]${NC} $1" | |
| } | |
| log_success() { | |
| echo -e "${GREEN}[SUCCESS]${NC} $1" | |
| } | |
| log_warning() { | |
| echo -e "${YELLOW}[WARNING]${NC} $1" | |
| } | |
| log_error() { | |
| echo -e "${RED}[ERROR]${NC} $1" | |
| } | |
| # Asociativní pole pro ukládání nalezených PHP knihoven | |
| declare -A php_libraries | |
| declare -A php_projects | |
| # Základní adresář (pokud není zadán, použije se aktuální) | |
| BASE_DIR="${1:-$(pwd)}" | |
| # Funkce pro doplnění chybějící vlastnosti "type" do composer.json | |
| add_missing_type_property() { | |
| local composer_file="$1" | |
| local package_type="${2:-library}" | |
| # Zkontrolujeme, jestli soubor má vlastnost "type" | |
| local current_type=$(jq -r '.type // empty' "$composer_file" 2>/dev/null) | |
| if [[ -z "$current_type" || "$current_type" == "null" ]]; then | |
| log_warning "Soubor $composer_file nemá definovanou vlastnost 'type', doplňuji jako '$package_type'" | |
| # Vytvoříme backup původního souboru | |
| cp "$composer_file" "$composer_file.bak" | |
| # Přidáme vlastnost "type" pomocí jq | |
| local temp_file=$(mktemp) | |
| if jq ". + {\"type\": \"$package_type\"}" "$composer_file" > "$temp_file" && mv "$temp_file" "$composer_file"; then | |
| log_success "Vlastnost 'type': '$package_type' byla úspěšně přidána do $composer_file" | |
| return 0 | |
| else | |
| log_error "Nepodařilo se přidat vlastnost 'type' do $composer_file" | |
| # Obnovíme původní soubor při chybě | |
| mv "$composer_file.bak" "$composer_file" | |
| rm -f "$temp_file" | |
| return 1 | |
| fi | |
| fi | |
| return 0 | |
| } | |
| # Verbose režim | |
| VERBOSE=true | |
| log_info "Začínám skenování z adresáře: $BASE_DIR" | |
| # Fáze 1: Nalezení všech PHP knihoven | |
| log_info "=== FÁZE 1: Hledání PHP knihoven ===" | |
| find_php_libraries() { | |
| local search_dir="$1" | |
| # Hledáme adresáře s composer.json, ale VYLUČUJEME vendor složky a debian složky | |
| while IFS= read -r -d '' composer_file; do | |
| # Ignorujeme soubory v cestách obsahujících '/debian/' - ty jsou pro balíčkování | |
| if [[ "$composer_file" == *"/debian/"* ]]; then | |
| continue | |
| fi | |
| local dir=$(dirname "$composer_file") | |
| # Přeskočíme soubory ve vendor složkách | |
| if [[ "$dir" == *"/vendor/"* ]]; then | |
| continue | |
| fi | |
| # Kontrola, jestli je to PHP knihovna (má composer.json a src/ nebo lib/ nebo obsahuje "type": "library") | |
| if [[ -f "$composer_file" ]]; then | |
| # Získání názvu balíčku z composer.json | |
| local package_name=$(jq -r '.name // empty' "$composer_file" 2>/dev/null) | |
| local package_type=$(jq -r '.type // empty' "$composer_file" 2>/dev/null) | |
| if [[ -n "$package_name" ]]; then | |
| # Zlepšená klasifikace knižníc | |
| local has_autoload has_bin | |
| jq -e 'has("autoload")' "$composer_file" >/dev/null 2>&1 && has_autoload="true" || has_autoload="false" | |
| jq -e 'has("bin")' "$composer_file" >/dev/null 2>&1 && has_bin="true" || has_bin="false" | |
| # Pokud je to knihovna bez typu, doplníme "type": "library" | |
| if [[ "$has_autoload" == "true" && "$has_bin" == "false" && (-z "$package_type" || "$package_type" == "null") ]]; then | |
| add_missing_type_property "$composer_file" "library" | |
| # Načteme typ znovu po případné změně | |
| package_type=$(jq -r '.type // empty' "$composer_file" 2>/dev/null) | |
| fi | |
| # Klasifikace ako knižnica ak: | |
| # 1. Explicitne označená ako library, ALEBO | |
| # 2. Má autoload konfiguráciu a žiadne bin skripty (typický vzor knižnice) | |
| if [[ "$package_type" == "library" ]] || [[ "$has_autoload" == "true" && "$has_bin" == "false" && ("$package_type" == "" || "$package_type" == "null") ]]; then | |
| php_libraries["$package_name"]="$dir" | |
| log_success "Nalezena PHP knihovna: $package_name v $dir (type: $package_type, autoload: $has_autoload)" | |
| else | |
| # Vše ostatní považujeme za projekt | |
| php_projects["$package_name"]="$dir" | |
| log_info "Nalezen PHP projekt: $package_name v $dir (type: $package_type, autoload: $has_autoload, bin: $has_bin)" | |
| fi | |
| fi | |
| fi | |
| done < <(find "$search_dir" -name "composer.json" -type f -not -path "*/vendor/*" -print0) | |
| } | |
| find_php_libraries "$BASE_DIR" | |
| log_info "Nalezeno ${#php_libraries[@]} PHP knihoven a ${#php_projects[@]} PHP projektů" | |
| if [[ ${#php_libraries[@]} -eq 0 ]]; then | |
| log_warning "Nebyly nalezeny žádné PHP knihovny. Ukončujem." | |
| exit 0 | |
| fi | |
| echo | |
| log_info "=== NALEZENÉ PHP KNIHOVNY ===" | |
| for package in "${!php_libraries[@]}"; do | |
| echo " $package -> ${php_libraries[$package]}" | |
| done | |
| echo | |
| log_info "=== NALEZENÉ PHP PROJEKTY ===" | |
| for package in "${!php_projects[@]}"; do | |
| echo " $package -> ${php_projects[$package]}" | |
| done | |
| # Fáze 2: Aktualizace projektů a vytvoření symlinkků | |
| echo | |
| log_info "=== FÁZE 2: Aktualizace projektů a vytváření symlinkků ===" | |
| process_php_projects() { | |
| for project_name in "${!php_projects[@]}"; do | |
| local project_dir="${php_projects[$project_name]}" | |
| log_info "Zpracovávám projekt: $project_name v $project_dir" | |
| # Kontrola existence composer.json | |
| if [[ ! -f "$project_dir/composer.json" ]]; then | |
| log_warning "Soubor composer.json nenalezen v $project_dir, přeskakujem" | |
| continue | |
| fi | |
| # Přesun do adresáře projektu | |
| cd "$project_dir" | |
| # Spuštění composer update | |
| log_info "Spouštím composer update v $project_dir" | |
| if composer update --no-interaction --optimize-autoloader; then | |
| log_success "Composer update dokončen úspěšně" | |
| else | |
| log_error "Composer update selhal v $project_dir" | |
| continue | |
| fi | |
| # Kontrola existence vendor adresáře | |
| if [[ ! -d "$project_dir/vendor" ]]; then | |
| log_warning "Vendor adresář nenalezen v $project_dir, přeskakujem symlink vytváření" | |
| continue | |
| fi | |
| # Procházení vendor adresáře a hledání závislostí k nahrazení | |
| log_info "Hledám závislosti k nahrazení symlinky..." | |
| # Procházíme celý vendor adresář a hledáme shody s našimi knihovnami | |
| if [[ -d "$project_dir/vendor" ]]; then | |
| # Nastavíme IFS a použijeme for cyklus namiesto while s pipe (aby sme sa vyhli subshell problému) | |
| local -a vendor_packages=() | |
| while IFS= read -r -d '' vendor_package_dir; do | |
| vendor_packages+=("$vendor_package_dir") | |
| done < <(find "$project_dir/vendor" -mindepth 2 -maxdepth 2 -type d -print0) | |
| for vendor_package_dir in "${vendor_packages[@]}"; do | |
| # Získáme relativní cestu od vendor/ (např. "vitexsoftware/ease-core") | |
| local relative_path=${vendor_package_dir#$project_dir/vendor/} | |
| log_info "Kontrolujem závislost: $relative_path" | |
| # Debug: Zobrazíme dostupné knihovny | |
| if [[ ${#php_libraries[@]} -eq 0 ]]; then | |
| log_warning "Pole php_libraries je prázdne!" | |
| else | |
| log_info "Dostupných knihoven: ${#php_libraries[@]}" | |
| fi | |
| # Hledáme přímou shodu podle názvu balíčku z composer.json | |
| if [[ -n "${php_libraries[$relative_path]}" ]]; then | |
| local found_library="$relative_path" | |
| local found_path="${php_libraries[$relative_path]}" | |
| log_success "Nalezena závislost $relative_path -> $found_library na $found_path" | |
| # Ověření, že zdrojový adresář existuje | |
| if [[ -d "$found_path" ]]; then | |
| # Odstranení původního vendor adresáře | |
| log_info "Odstraňujem původní adresář: $vendor_package_dir" | |
| rm -rf "$vendor_package_dir" | |
| # Vytvoření symlinku | |
| log_info "Vytvářím symlink: $vendor_package_dir -> $found_path" | |
| if ln -sf "$found_path" "$vendor_package_dir"; then | |
| log_success "Symlink vytvořen úspěšně: $relative_path -> $found_library" | |
| else | |
| log_error "Nepodařilo se vytvořit symlink pro $relative_path" | |
| fi | |
| else | |
| log_warning "Zdrojový adresář $found_path neexistuje, přeskakujem $relative_path" | |
| fi | |
| else | |
| log_info "Závislost $relative_path nenalezena v knihovnách (přeskakujem)" | |
| fi | |
| done | |
| else | |
| log_warning "Vendor adresář nenalezen v $project_dir" | |
| fi | |
| echo "----------------------------------------" | |
| done | |
| } | |
| # Potvrzení od uživatele před provedením změn | |
| echo | |
| log_warning "POZOR: Tento skript provede následující akce:" | |
| echo "1. Spustí 'composer update' ve všech nalezených PHP projektech" | |
| echo "2. Nahradí instalované závislosti symlinky na lokální vývojové verze" | |
| echo "3. Pro obnovení původního stavu stačí spustit 'composer update' v projektu" | |
| echo | |
| read -p "Chcete pokračovat? [y/N]: " -n 1 -r | |
| echo | |
| if [[ ! $REPLY =~ ^[Yy]$ ]]; then | |
| log_info "Operace zrušena uživatelem" | |
| exit 0 | |
| fi | |
| # Spuštění zpracování | |
| process_php_projects | |
| # Návrat do původního adresáře | |
| cd "$BASE_DIR" | |
| echo | |
| log_success "=== DOKONČENO ===" | |
| log_info "Všechny PHP projekty byly zpracovány" | |
| log_info "Nyní můžete vyvíjet s nejnovějšími verzemi závislostí" | |
| echo | |
| log_info "=== SHRNUTÍ ===" | |
| echo "Nalezeno knihoven: ${#php_libraries[@]}" | |
| echo "Zpracováno projektů: ${#php_projects[@]}" | |
| echo | |
| log_info "=== POZNÁMKA ===" | |
| log_info "Pro obnovení původního stavu jednoduše spusťte 'composer update' v projektových adresářích" | |
| log_info "Composer automaticky obnoví původní závislosti podle composer.lock souboru" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment