#!/usr/bin/env bash CODE_DIR="~/Code" eval expanded_code_dir="$CODE_DIR" mkdir -p "$expanded_code_dir" # API URL API_URL="https://lab.mrflos.pw/?api/forms/5/entries" echo "Fetching repository information from $API_URL..." json_data=$(curl -s "$API_URL") if [ $? -ne 0 ]; then echo "Error: Failed to fetch data from the API at $API_URL." exit 1 fi if [ -z "$json_data" ]; then echo "Error: Fetched JSON data is empty from $API_URL." exit 1 fi # Get all top-level keys (repository entry names) from the JSON # The `keys_unsorted[]` jq function extracts all keys as an array. # `jq -r '. | keys_unsorted[]'` prints each key on a new line. repo_keys=$(echo "$json_data" | jq -r '. | keys_unsorted[]') if [ $? -ne 0 ] || [ -z "$repo_keys" ]; then echo "Error: Could not extract repository keys from JSON or JSON is not in the expected format (object)." echo "Fetched JSON data (first 500 chars): $(echo "$json_data" | head -c 500)" exit 1 fi echo "Found repository keys to process:" echo "$repo_keys" echo "---" # Loop through each repository key while IFS= read -r REPO_KEY; do if [ -z "$REPO_KEY" ]; then continue # Skip empty lines if any fi echo "" echo "Processing repository entry: $REPO_KEY" echo "--------------------------------------------------" # Use jq to parse repository URL and branch for the current REPO_KEY repo_url=$(echo "$json_data" | jq -r --arg key "$REPO_KEY" '.[$key].bf_repo_git') branch_name=$(echo "$json_data" | jq -r --arg key "$REPO_KEY" '.[$key].bf_branch') # Validate that repo_url and branch_name were found and are not null or empty if [ "$repo_url" == "null" ] || [ -z "$repo_url" ]; then echo "Error: Could not parse bf_repo_git for key '$REPO_KEY'. Skipping this entry." echo " JSON for this key (bf_repo_git): $(echo "$json_data" | jq --arg key "$REPO_KEY" '.[$key].bf_repo_git')" continue fi if [ "$branch_name" == "null" ] || [ -z "$branch_name" ]; then echo "Error: Could not parse bf_branch for key '$REPO_KEY'. Skipping this entry." echo " JSON for this key (bf_branch): $(echo "$json_data" | jq --arg key "$REPO_KEY" '.[$key].bf_branch')" continue fi echo " Repository URL: $repo_url" echo " Branch: $branch_name" # Extract repository name from the URL to use as the folder name. repo_folder_name=$(basename "$repo_url" .git) # Define the full path to the local repository local_repo_path="$expanded_code_dir/$repo_folder_name" echo " Local repository path: $local_repo_path" # Check if the repository directory exists if [ ! -d "$local_repo_path" ]; then echo " Repository folder '$repo_folder_name' does not exist locally. Cloning..." # Try to clone the specific branch directly git clone --branch "$branch_name" "$repo_url" "$local_repo_path" clone_status=$? if [ $clone_status -ne 0 ]; then echo " Warning: Initial clone with branch '$branch_name' failed. Trying to clone default branch then checkout..." # If specific branch clone fails, clone default and then try to checkout the branch git clone "$repo_url" "$local_repo_path" if [ $? -ne 0 ]; then echo " Error: Git clone (default branch) failed for $repo_url. Skipping this repository." continue fi cd "$local_repo_path" || { echo " Error: Failed to cd into '$local_repo_path' after clone. Skipping."; continue; } echo " Checking out branch '$branch_name'..." git checkout "$branch_name" if [ $? -ne 0 ]; then echo " Warning: Failed to checkout branch '$branch_name' after cloning. The branch might not exist remotely or there was another issue." echo " Staying on default branch: $(git rev-parse --abbrev-ref HEAD)" else echo " Successfully checked out branch '$branch_name'." fi else cd "$local_repo_path" || { echo " Error: Failed to cd into '$local_repo_path' after clone. Skipping."; continue; } echo " Successfully cloned and on branch '$branch_name'." fi else echo " Repository folder '$repo_folder_name' already exists. Fetching and updating..." cd "$local_repo_path" || { echo " Error: Failed to cd into existing '$local_repo_path'. Skipping."; continue; } echo " Current directory: $(pwd)" echo " Currently on branch: $(git rev-parse --abbrev-ref HEAD)" # Stash any local changes before switching branches or pulling echo " Stashing local changes if any..." git stash push -m "autostash_before_update_$(date +%s)_$REPO_KEY" > /dev/null 2>&1 echo " Fetching all remotes and pruning..." git fetch --all --prune if [ $? -ne 0 ]; then echo " Error: Git fetch failed for $repo_folder_name. Attempting to restore stash." git stash pop > /dev/null 2>&1 # Attempt to restore stashed changes continue # Skip to the next repository fi current_branch_in_repo=$(git rev-parse --abbrev-ref HEAD) # Check if the desired branch exists locally or remotely if ! git show-ref --verify --quiet refs/heads/"$branch_name" && ! git show-ref --verify --quiet refs/remotes/origin/"$branch_name"; then echo " Warning: Branch '$branch_name' not found locally or on remote 'origin' for $repo_folder_name. Staying on branch '$current_branch_in_repo'." # If the target branch doesn't exist at all, pull the current one. if [ "$current_branch_in_repo" != "HEAD" ]; then # Ensure it's not a detached HEAD echo " Pulling latest changes for current branch '$current_branch_in_repo'..." git pull origin "$current_branch_in_repo" if [ $? -ne 0 ]; then echo " Error: Git pull failed for branch '$current_branch_in_repo' in $repo_folder_name. Attempting to restore stash." fi else echo " Warning: Repository is in a detached HEAD state. Cannot pull without a specific branch." fi else # Desired branch exists either locally or remotely. Try to switch and pull. if [ "$current_branch_in_repo" != "$branch_name" ]; then echo " Switching to branch '$branch_name'..." git checkout "$branch_name" if [ $? -ne 0 ]; then # If checkout fails (e.g., local branch exists but no remote tracking, or new branch from remote failed) # Try to create it from remote if it exists there if git show-ref --verify --quiet refs/remotes/origin/"$branch_name"; then echo " Attempting to checkout '$branch_name' tracking 'origin/$branch_name'..." git checkout -b "$branch_name" "origin/$branch_name" if [ $? -ne 0 ]; then echo " Error: Could not switch to or create branch '$branch_name'. Pulling current branch '$current_branch_in_repo'." if [ "$current_branch_in_repo" != "HEAD" ]; then git pull origin "$current_branch_in_repo" fi else echo " Successfully on branch '$branch_name'. Pulling..." git pull fi else echo " Error: Could not switch to branch '$branch_name'. Pulling current branch '$current_branch_in_repo'." if [ "$current_branch_in_repo" != "HEAD" ]; then git pull origin "$current_branch_in_repo" fi fi else echo " Successfully on branch '$branch_name'. Pulling..." git pull fi else echo " Already on branch '$branch_name'. Pulling..." git pull fi if [ $? -ne 0 ] && [ "$(git rev-parse --abbrev-ref HEAD)" == "$branch_name" ]; then # Check if pull failed on the target branch echo " Error: Git pull failed for branch '$branch_name' in $repo_folder_name. Attempting to restore stash." fi fi # Attempt to reapply stashed changes echo " Attempting to reapply stashed changes..." if ! git stash pop > /dev/null 2>&1; then # Check if there was anything to pop stash_count=$(git stash list | wc -l) if [ "$stash_count" -gt 0 ]; then echo " Warning: Could not automatically reapply stashed changes for $repo_folder_name. You may have a stash entry to resolve manually (git stash list)." else echo " No stashed changes to reapply." fi else echo " Stashed changes (if any) reapplied successfully." fi fi echo " Process for '$REPO_KEY' completed." echo "--------------------------------------------------" # Return to the main code directory to avoid issues with relative paths in the loop cd "$expanded_code_dir" || { echo "FATAL: Could not cd back to $expanded_code_dir. Exiting."; exit 1; } done <<< "$repo_keys" echo "" echo "All repositories processed."