Skip to content

Instantly share code, notes, and snippets.

@lbussy
Last active December 29, 2024 18:11
Show Gist options
  • Save lbussy/c2c7d6c41c8547fc7242fe7a7d98e660 to your computer and use it in GitHub Desktop.
Save lbussy/c2c7d6c41c8547fc7242fe7a7d98e660 to your computer and use it in GitHub Desktop.

Git Functions Documentation

Overview

This script interacts with Git repositories to perform various functions such as cloning, downloading files, and updating file ownership and permissions.

Usage

To use the script, run it as follows:

./git_functions.sh

The script automatically fetches repository data, downloads files from specified directories, and performs other Git-related operations.

Example usage:

./git_functions.sh

License

This script is distributed under the MIT License.

Author

Lee Bussy

Version

1.0

Functions

logI

@brief

Logs an informational message.

@details

This function formats and logs messages with an "[INFO ]" prefix. It removes extra spaces and trims leading/trailing spaces.

@param $1 The message to log.

@return None.

@example

logI "Repository cloned successfully"

logE

@brief

Logs an error message.

@details

This function formats and logs error messages with an "[ERROR]" prefix. It removes extra spaces and trims leading/trailing spaces.

@param $1 The error message to log.

@return None.

@example

logE "Failed to clone repository"

update_file

@brief

Updates ownership and permissions of a file.

@details

Changes the ownership of a file to match the owner of a specified home directory and adjusts file permissions based on its type (executable or non-executable).

@param $1 The file path to update.

@param $2 The root directory used to determine file ownership.

@throws Logs errors and returns non-zero if the file or directory is invalid or if ownership/permission updates fail.

@return Returns 0 on success, or 1 on failure.

@example

update_file "/path/to/file.sh" "/home/user"

download_file

@brief

Downloads a single file from a Git repository's raw URL.

@details

Fetches a file from the raw content URL of the repository and saves it to the specified local directory. Ensures the destination directory exists before downloading.

@param $1 The relative path of the file in the repository.

@param $2 The local destination directory where the file will be saved.

@throws Logs an error and returns non-zero if the file download fails.

@return None.

@example

download_file "path/to/file.txt" "/local/dir"

git_clone

@brief

Clones a GitHub repository to the specified local destination.

@details

This function clones the repository from the provided Git URL to the specified local destination directory.

@param None.

@global GIT_CLONE The base URL for cloning the GitHub repository.

@global USER_HOME The home directory of the user, used as the base for storing files.

@global REPO_NAME The name of the repository to clone.

@throws Logs an error and returns non-zero if the repository cloning fails.

@return None.

@example

git_clone

fetch_tree

@brief

Fetches the Git tree of a specified branch from a repository.

@details

Retrieves the SHA of the specified branch and then fetches the complete tree structure of the repository, allowing recursive access to all files and directories.

@param None.

@global GIT_API The base URL for the GitHub API, pointing to the repository.

@global REPO_BRANCH The branch name to fetch the tree from.

@throws Prints an error message and exits if the branch SHA cannot be fetched.

@return Outputs the JSON representation of the repository tree.

@example

fetch_tree

download_files_in_directories

@brief

Downloads files from specified directories in a repository.

@details

This function retrieves a repository tree, identifies files within specified directories, and downloads them to the local system.

@param $1 The target directory to update.

@global USER_HOME The home directory of the user, used as the base for storing files.

@global DIRECTORIES Array of directories in the repository to process.

@throws Exits the script with an error if the repository tree cannot be fetched.

@return Downloads files to the specified directory structure under $USER_HOME/apppop.

@example

download_files_in_directories

_main

@brief

Entry point to the script.

@details

This function calls the git_clone function to clone the repository into the specified destination directory.

@return None.

@example

_main

main

@brief

Main function of the script.

@details

This function is the script's entry point and invokes the _main function with arguments passed to it. It provides a way to handle script execution and allows for easier testing and debugging.

@param $@ The arguments passed to the script, which are forwarded to _main.

@return None.

@example

main "$@"

Exit Status

The script exits with the status of the last executed command. A status of 0 indicates success, while any non-zero status indicates an error.

#!/usr/bin/env bash
set -uo pipefail # Setting -e is far too much work here
IFS=$'\n\t'
set +o noclobber
# -----------------------------------------------------------------------------
# @file git_instructions.sh
# @brief This script interacts with Git repositories to perform various
# functions such as cloning, downloading files, and updating file
# ownership and permissions.
#
# @usage
# To use the script, run it as follows:
#
# ./git_functions.sh
#
# The script automatically fetches repository data, downloads files from
# specified directories, and performs other Git-related operations.
#
# Example usage:
# ./git_functions.sh
#
# @license
# This script is distributed under the MIT License.
#
# @author
# Lee Bussy
#
# @version
# 1.0
# -----------------------------------------------------------------------------
declare FALLBACK_SCRIPT_NAME="${FALLBACK_SCRIPT_NAME:-template.sh}"
declare REPO_ORG="${REPO_ORG:-lbussy}"
declare REPO_NAME="${REPO_NAME:-ap-popup}"
declare REPO_BRANCH="${REPO_BRANCH:-main}"
declare GIT_TAG="${GIT_TAG:-0.0.1}"
declare SEM_VER="${GIT_TAG:-0.0.1}"
declare LOCAL_REPO_DIR="${LOCAL_REPO_DIR:-}"
declare LOCAL_WWW_DIR="${LOCAL_WWW_DIR:-}"
declare LOCAL_SCRIPTS_DIR="${LOCAL_SCRIPTS_DIR:-}"
declare GIT_RAW="${GIT_RAW:-"https://raw.githubusercontent.com/$REPO_ORG/$REPO_NAME"}"
declare GIT_API="${GIT_API:-"https://api.github.com/repos/$REPO_ORG/$REPO_NAME"}"
declare GIT_CLONE="${GIT_CLONE:-"https://github.com/$REPO_ORG/$REPO_NAME.git"}"
declare USER_HOME
if [[ -n "${SUDO_USER-}" ]]; then
readonly USER_HOME=$(eval echo "~$SUDO_USER")
else
readonly USER_HOME="$HOME"
fi
readonly DIRECTORIES=("man" "scripts" "conf") # Relevant directories for download.
# -----------------------------------------------------------------------------
# @brief Logs an informational message.
# @details This function formats and logs messages with an "[INFO ]" prefix.
# It removes extra spaces and trims leading/trailing spaces.
#
# @param $1 The message to log.
#
# @return None.
#
# @example
# logI "Repository cloned successfully"
# -----------------------------------------------------------------------------
logI() {
local func_name="${FUNCNAME[0]}"
local caller_name="${FUNCNAME[1]}"
local caller_line="${BASH_LINENO[0]}"
local message
message="$*"
message="${message%"${message##*[![:space:]]}"}" # Trim leading spaces
message="${message#"${message%%[![:space:]]*}"}" # Trim trailing spaces
message=$(echo "$message" | sed 's/ */ /g') # Replace multiple spaces with a single space
echo "[INFO ] $message"
}
# -----------------------------------------------------------------------------
# @brief Logs an error message.
# @details This function formats and logs error messages with an "[ERROR]" prefix.
# It removes extra spaces and trims leading/trailing spaces.
#
# @param $1 The error message to log.
#
# @return None.
#
# @example
# logE "Failed to clone repository"
# -----------------------------------------------------------------------------
logE() {
local func_name="${FUNCNAME[0]}"
local caller_name="${FUNCNAME[1]}"
local caller_line="${BASH_LINENO[0]}"
local message
message="$*"
message="${message%"${message##*[![:space:]]}"}" # Trim leading spaces
message="${message#"${message%%[![:space:]]*}"}" # Trim trailing spaces
message=$(echo "$message" | sed 's/ */ /g') # Replace multiple spaces with a single space
echo "[ERROR] $message"
}
# -----------------------------------------------------------------------------
# @brief Updates ownership and permissions of a file.
# @details Changes the ownership of a file to match the owner of a specified home
# directory and adjusts file permissions based on its type (executable
# or non-executable).
#
# @param $1 The file path to update.
# @param $2 The root directory used to determine file ownership.
#
# @global None.
#
# @throws Logs errors and returns non-zero if the file or directory is invalid
# or if ownership/permission updates fail.
#
# @return Returns 0 on success, or 1 on failure.
#
# @example
# update_file "/path/to/file.sh" "/home/user"
# -----------------------------------------------------------------------------
update_file() {
local file="$1"
local home_root="$2"
if [[ -z "$file" || -z "$home_root" ]]; then
logE "Usage: update_file <file> <home_root>"
return 1
fi
if [[ ! -d "$home_root" ]]; then
logE "Home root '$home_root' is not a valid directory."
return 1
fi
if [[ ! -f "$file" ]]; then
logE "File '$file' does not exist."
return 1
fi
local owner
owner=$(stat -c '%U' "$home_root")
if [[ -z "$owner" ]]; then
logE "Unable to determine the owner of the home root."
return 1
fi
logI "Changing ownership of '$file' to '$owner'."
chown "$owner":"$owner" "$file" || {
logE "Failed to change ownership."
return 1
}
if [[ "$file" == *.sh ]]; then
logI "Setting permissions of '$file' to 700 (executable)."
chmod 700 "$file" || {
logE "Failed to set permissions to 700."
return 1
}
else
logI "Setting permissions of '$file' to 600."
chmod 600 "$file" || {
logE "Failed to set permissions to 600."
return 1
}
fi
logI "Ownership and permissions updated successfully for '$file'."
return 0
}
# -----------------------------------------------------------------------------
# @brief Downloads a single file from a Git repository's raw URL.
# @details Fetches a file from the raw content URL of the repository and saves
# it to the specified local directory. Ensures the destination
# directory exists before downloading.
#
# @param $1 The relative path of the file in the repository.
# @param $2 The local destination directory where the file will be saved.
#
# @global GIT_RAW The base URL for raw content access in the Git repository.
# @global REPO_BRANCH The branch name from which the file will be fetched.
#
# @throws Logs an error and returns non-zero if the file download fails.
#
# @return None. Downloads the file to the specified directory.
#
# @example
# download_file "path/to/file.txt" "/local/dir"
# -----------------------------------------------------------------------------
download_file() {
local file_path="$1"
local dest_dir="$2"
mkdir -p "$dest_dir"
local file_name
file_name=$(basename "$file_path")
file_name="${file_name//\'/}"
logI "Downloading from: $GIT_RAW/$REPO_BRANCH/$file_path to $dest_dir/$file_name"
wget -q -O "$dest_dir/$file_name" "$GIT_RAW/$REPO_BRANCH/$file_path" || {
logE "Failed to download file: $file_path to $dest_dir/$file_name"
return 1
}
local dest_file="$dest_dir/$file_name"
mv "$dest_file" "${dest_file//\'/}"
}
# -----------------------------------------------------------------------------
# @brief Clones a GitHub repository to the specified local destination.
# @details This function clones the repository from the provided Git URL to the
# specified local destination directory.
#
# @global GIT_CLONE The base URL for cloning the GitHub repository.
# @global USER_HOME The home directory of the user, used as the base for storing files.
# @global REPO_NAME The name of the repository to clone.
#
# @throws Logs an error and returns non-zero if the repository cloning fails.
#
# @return None. Clones the repository into the local destination.
#
# @example
# git_clone
# -----------------------------------------------------------------------------
git_clone() {
local dest_root="$USER_HOME/$REPO_NAME"
mkdir -p "$dest_root"
logI "Cloning repository from $GIT_CLONE to $dest_root"
git clone "$GIT_CLONE" "$dest_root" || {
logE "Failed to clone repository: $GIT_CLONE to $dest_root"
return 1
}
logI "Repository cloned successfully to $dest_root"
}
# -----------------------------------------------------------------------------
# @brief Fetches the Git tree of a specified branch from a repository.
# @details Retrieves the SHA of the specified branch and then fetches the
# complete tree structure of the repository, allowing recursive access
# to all files and directories.
#
# @global GIT_API The base URL for the GitHub API, pointing to the repository.
# @global REPO_BRANCH The branch name to fetch the tree from.
#
# @throws Prints an error message and exits if the branch SHA cannot be fetched.
#
# @return Outputs the JSON representation of the repository tree.
#
# @example
# fetch_tree
# -----------------------------------------------------------------------------
fetch_tree() {
local branch_sha
branch_sha=$(curl -s "$GIT_API/git/ref/heads/$REPO_BRANCH" | jq -r '.object.sha')
if [[ -z "$branch_sha" || "$branch_sha" == "null" ]]; then
logE "Failed to fetch branch SHA for branch: $REPO_BRANCH. Check repository details or API access."
return 1
fi
curl -s "$GIT_API/git/trees/$branch_sha?recursive=1"
}
# -----------------------------------------------------------------------------
# @brief Downloads files from specified directories in a repository.
# @details This function retrieves a repository tree, identifies files within
# specified directories, and downloads them to the local system.
#
# @param $1 The target directory to update.
#
# @global USER_HOME The home directory of the user, used as the base for storing files.
# @global DIRECTORIES Array of directories in the repository to process.
#
# @throws Exits the script with an error if the repository tree cannot be fetched.
#
# @return Downloads files to the specified directory structure under $USER_HOME/apppop.
#
# @example
# download_files_in_directories
# -----------------------------------------------------------------------------
download_files_in_directories() {
local dest_root="$USER_HOME/$REPO_NAME"
logI "Fetching repository tree."
local tree=$(fetch_tree)
if [[ $(printf "%s" "$tree" | jq '.tree | length') -eq 0 ]]; then
die 1 "Failed to fetch repository tree. Check repository details or ensure it is public."
fi
for dir in "${DIRECTORIES[@]}"; do
logI "Processing directory: $dir"
local files
files=$(printf "%s" "$tree" | jq -r --arg TARGET_DIR "$dir/" \
'.tree[] | select(.type=="blob" and (.path | startswith($TARGET_DIR))) | .path')
if [[ -z "$files" ]]; then
logI "No files found in directory: $dir"
continue
fi
local dest_dir="$dest_root/$dir"
mkdir -p "$dest_dir"
printf "%s\n" "$files" | while read -r file; do
logI "Downloading: $file"
download_file "$file" "$dest_dir"
done
logI "Files from $dir downloaded to: $dest_dir"
done
logI "Files saved in: $dest_root"
}
# -----------------------------------------------------------------------------
# @brief Entry point to the script.
# @details This function calls the `git_clone` function to clone the repository
# into the specified destination directory.
#
# @return None.
#
# @example
# _main
# -----------------------------------------------------------------------------
_main() {
git_clone
}
# -----------------------------------------------------------------------------
# @brief Main function of the script.
# @details This function is the script's entry point and invokes the `_main`
# function with arguments passed to it. It provides a way to handle
# script execution and allows for easier testing and debugging.
#
# @param $@ The arguments passed to the script, which are forwarded to `_main`.
#
# @return None.
#
# @example
# main "$@"
# -----------------------------------------------------------------------------
main() { _main "$@"; };
# Call the main function and exit.
main "$@"
exit $?
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment