mirror of
https://github.com/mod-playerbots/azerothcore-wotlk.git
synced 2025-11-29 17:38:24 +08:00
feat(config): add support for excluding modules during installation and updates (#22793)
This commit is contained in:
@@ -9,6 +9,10 @@ This directory contains the module management system for AzerothCore, providing
|
|||||||
- **Custom Directory Naming**: Prevent conflicts with custom directory names
|
- **Custom Directory Naming**: Prevent conflicts with custom directory names
|
||||||
- **Duplicate Prevention**: Smart detection and prevention of duplicate installations
|
- **Duplicate Prevention**: Smart detection and prevention of duplicate installations
|
||||||
- **Multi-Host Support**: GitHub, GitLab, and other Git hosts
|
- **Multi-Host Support**: GitHub, GitLab, and other Git hosts
|
||||||
|
- **Module Exclusion**: Support for excluding modules via environment variable
|
||||||
|
- **Interactive Menu System**: Easy-to-use menu interface for module management
|
||||||
|
- **Colored Output**: Enhanced terminal output with color support (respects NO_COLOR)
|
||||||
|
- **Flat Directory Structure**: Uses flat module installation (no owner subfolders)
|
||||||
|
|
||||||
## 📁 File Structure
|
## 📁 File Structure
|
||||||
|
|
||||||
@@ -100,10 +104,33 @@ repo[:dirname][@branch[:commit]]
|
|||||||
# Search with multiple terms
|
# Search with multiple terms
|
||||||
./acore.sh module search auction house
|
./acore.sh module search auction house
|
||||||
|
|
||||||
# Show all available modules
|
# Search with input prompt
|
||||||
./acore.sh module search
|
./acore.sh module search
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Listing Installed Modules
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# List all installed modules
|
||||||
|
./acore.sh module list
|
||||||
|
```
|
||||||
|
|
||||||
|
### Interactive Menu
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Start interactive menu system
|
||||||
|
./acore.sh module
|
||||||
|
|
||||||
|
# Menu options:
|
||||||
|
# s - Search for available modules
|
||||||
|
# i - Install one or more modules
|
||||||
|
# u - Update installed modules
|
||||||
|
# r - Remove installed modules
|
||||||
|
# l - List installed modules
|
||||||
|
# h - Show detailed help
|
||||||
|
# q - Close this menu
|
||||||
|
```
|
||||||
|
|
||||||
## 🔍 Cross-Format Recognition
|
## 🔍 Cross-Format Recognition
|
||||||
|
|
||||||
The system intelligently recognizes the same module across different specification formats:
|
The system intelligently recognizes the same module across different specification formats:
|
||||||
@@ -129,13 +156,55 @@ The system prevents common conflicts:
|
|||||||
```bash
|
```bash
|
||||||
# If 'mod-transmog' directory already exists:
|
# If 'mod-transmog' directory already exists:
|
||||||
$ ./acore.sh module install mod-transmog:mod-transmog
|
$ ./acore.sh module install mod-transmog:mod-transmog
|
||||||
Error: Directory 'mod-transmog' already exists.
|
|
||||||
Possible solutions:
|
Possible solutions:
|
||||||
1. Use a different directory name: mod-transmog:my-custom-name
|
1. Use a different directory name: mod-transmog:my-custom-name
|
||||||
2. Remove the existing directory first
|
2. Remove the existing directory first
|
||||||
3. Use the update command if this is the same module
|
3. Use the update command if this is the same module
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Duplicate Module Prevention
|
||||||
|
The system uses intelligent owner/name matching to prevent installing the same module multiple times, even when specified in different formats.
|
||||||
|
|
||||||
|
## 🚫 Module Exclusion
|
||||||
|
|
||||||
|
You can exclude modules from installation using the `MODULES_EXCLUDE_LIST` environment variable:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Exclude specific modules (space-separated)
|
||||||
|
export MODULES_EXCLUDE_LIST="mod-test-module azerothcore/mod-dev-only"
|
||||||
|
./acore.sh module install --all # Will skip excluded modules
|
||||||
|
|
||||||
|
# Supports cross-format matching
|
||||||
|
export MODULES_EXCLUDE_LIST="https://github.com/azerothcore/mod-transmog.git"
|
||||||
|
./acore.sh module install mod-transmog # Will be skipped as excluded
|
||||||
|
```
|
||||||
|
|
||||||
|
The exclusion system:
|
||||||
|
- Uses the same cross-format recognition as other module operations
|
||||||
|
- Works with all installation methods (`install`, `install --all`)
|
||||||
|
- Provides clear feedback when modules are skipped
|
||||||
|
- Supports URLs, owner/name format, and simple names
|
||||||
|
|
||||||
|
## 🎨 Color Support
|
||||||
|
|
||||||
|
The module manager provides enhanced terminal output with colors:
|
||||||
|
|
||||||
|
- **Info**: Cyan text for informational messages
|
||||||
|
- **Success**: Green text for successful operations
|
||||||
|
- **Warning**: Yellow text for warnings
|
||||||
|
- **Error**: Red text for errors
|
||||||
|
- **Headers**: Bold cyan text for section headers
|
||||||
|
|
||||||
|
Color support is automatically disabled when:
|
||||||
|
- Output is not to a terminal (piped/redirected)
|
||||||
|
- `NO_COLOR` environment variable is set
|
||||||
|
- Terminal doesn't support colors
|
||||||
|
|
||||||
|
You can force color output with:
|
||||||
|
```bash
|
||||||
|
export FORCE_COLOR=1
|
||||||
|
```
|
||||||
|
|
||||||
## 🔄 Integration
|
## 🔄 Integration
|
||||||
|
|
||||||
### Including in Scripts
|
### Including in Scripts
|
||||||
@@ -165,24 +234,78 @@ azerothcore/mod-transmog master abc123def456
|
|||||||
https://github.com/custom/mod-custom.git develop def456abc789
|
https://github.com/custom/mod-custom.git develop def456abc789
|
||||||
mod-eluna:custom-eluna-dir main 789abc123def
|
mod-eluna:custom-eluna-dir main 789abc123def
|
||||||
```
|
```
|
||||||
|
|
||||||
|
The list maintains:
|
||||||
|
- **Alphabetical ordering** by normalized owner/name for consistency
|
||||||
|
- **Original format preservation** of how modules were specified
|
||||||
|
- **Automatic deduplication** across different specification formats
|
||||||
|
- **Custom directory tracking** when specified
|
||||||
|
|
||||||
## 🔧 Configuration
|
## 🔧 Configuration
|
||||||
|
|
||||||
### Environment Variables
|
### Environment Variables
|
||||||
- `MODULES_LIST_FILE`: Override default modules list path
|
|
||||||
- `J_PATH_MODULES`: Modules installation directory
|
| Variable | Description | Default |
|
||||||
- `AC_PATH_ROOT`: AzerothCore root path
|
|----------|-------------|---------|
|
||||||
|
| `MODULES_LIST_FILE` | Override default modules list path | `$AC_PATH_ROOT/conf/modules.list` |
|
||||||
|
| `MODULES_EXCLUDE_LIST` | Space-separated list of modules to exclude | - |
|
||||||
|
| `J_PATH_MODULES` | Modules installation directory | `$AC_PATH_ROOT/modules` |
|
||||||
|
| `AC_PATH_ROOT` | AzerothCore root path | - |
|
||||||
|
| `NO_COLOR` | Disable colored output | - |
|
||||||
|
| `FORCE_COLOR` | Force colored output even when not TTY | - |
|
||||||
|
|
||||||
### Default Paths
|
### Default Paths
|
||||||
- Modules list: `$AC_PATH_ROOT/conf/modules.list`
|
- **Modules list**: `$AC_PATH_ROOT/conf/modules.list`
|
||||||
|
- **Installation directory**: `$J_PATH_MODULES` (flat structure, no owner subfolders)
|
||||||
|
|
||||||
|
## 🏗️ Architecture
|
||||||
|
|
||||||
|
### Core Functions
|
||||||
|
|
||||||
|
| Function | Purpose |
|
||||||
|
|----------|---------|
|
||||||
|
| `inst_module()` | Main dispatcher and interactive menu |
|
||||||
|
| `inst_parse_module_spec()` | Parse advanced module syntax |
|
||||||
|
| `inst_extract_owner_name()` | Normalize modules for cross-format recognition |
|
||||||
|
| `inst_mod_list_*()` | Module list management (read/write/update) |
|
||||||
|
| `inst_module_*()` | Module operations (install/update/remove/search) |
|
||||||
|
|
||||||
|
### Key Features
|
||||||
|
|
||||||
|
- **Flat Directory Structure**: All modules install directly under `modules/` without owner subdirectories
|
||||||
|
- **Smart Conflict Detection**: Prevents directory name conflicts with helpful suggestions
|
||||||
|
- **Cross-Platform Compatibility**: Works on Linux, macOS, and Windows (Git Bash)
|
||||||
|
- **Version Compatibility**: Checks `acore-module.json` for AzerothCore version compatibility
|
||||||
|
- **Git Integration**: Uses Joiner system for Git repository management
|
||||||
|
|
||||||
|
### Debug Mode
|
||||||
|
|
||||||
|
For debugging module operations, you can examine the generated commands:
|
||||||
|
```bash
|
||||||
|
# Check what Joiner commands would be executed
|
||||||
|
tail -f /tmp/joiner_called.txt # In test environments
|
||||||
|
```
|
||||||
|
|
||||||
## 🤝 Contributing
|
## 🤝 Contributing
|
||||||
|
|
||||||
When modifying the module manager:
|
When modifying the module manager:
|
||||||
|
|
||||||
1. Maintain backwards compatibility
|
1. **Maintain backwards compatibility** with existing module list format
|
||||||
2. Update tests in `test_module_commands.bats`
|
2. **Update tests** in `test_module_commands.bats` for new functionality
|
||||||
3. Update this documentation
|
3. **Update this documentation** for any new features or changes
|
||||||
4. Test cross-format recognition thoroughly
|
4. **Test cross-format recognition** thoroughly across all supported formats
|
||||||
5. Ensure helpful error messages
|
5. **Ensure helpful error messages** for common user mistakes
|
||||||
|
6. **Test exclusion functionality** with various module specification formats
|
||||||
|
7. **Verify color output** works correctly in different terminal environments
|
||||||
|
|
||||||
|
### Testing Guidelines
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Run all module-related tests
|
||||||
|
cd apps/installer
|
||||||
|
bats test/test_module_commands.bats
|
||||||
|
|
||||||
|
# Test with different environments
|
||||||
|
NO_COLOR=1 ./acore.sh module list
|
||||||
|
FORCE_COLOR=1 ./acore.sh module help
|
||||||
|
```
|
||||||
|
|||||||
@@ -28,6 +28,49 @@ source "$CURRENT_PATH/../../../bash_shared/includes.sh"
|
|||||||
source "$CURRENT_PATH/../includes.sh"
|
source "$CURRENT_PATH/../includes.sh"
|
||||||
source "$AC_PATH_APPS/bash_shared/menu_system.sh"
|
source "$AC_PATH_APPS/bash_shared/menu_system.sh"
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
# Color support (disabled when not a TTY or NO_COLOR is set)
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
if [ -t 1 ] && [ -z "${NO_COLOR:-}" ]; then
|
||||||
|
if command -v tput >/dev/null 2>&1; then
|
||||||
|
_ac_cols=$(tput colors 2>/dev/null || echo 0)
|
||||||
|
else
|
||||||
|
_ac_cols=0
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
_ac_cols=0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "${FORCE_COLOR:-}" != "" ] || [ "${_ac_cols}" -ge 8 ]; then
|
||||||
|
C_RESET='\033[0m'
|
||||||
|
C_BOLD='\033[1m'
|
||||||
|
C_DIM='\033[2m'
|
||||||
|
C_RED='\033[31m'
|
||||||
|
C_GREEN='\033[32m'
|
||||||
|
C_YELLOW='\033[33m'
|
||||||
|
C_BLUE='\033[34m'
|
||||||
|
C_MAGENTA='\033[35m'
|
||||||
|
C_CYAN='\033[36m'
|
||||||
|
else
|
||||||
|
C_RESET=''
|
||||||
|
C_BOLD=''
|
||||||
|
C_DIM=''
|
||||||
|
C_RED=''
|
||||||
|
C_GREEN=''
|
||||||
|
C_YELLOW=''
|
||||||
|
C_BLUE=''
|
||||||
|
C_MAGENTA=''
|
||||||
|
C_CYAN=''
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Simple helpers for consistent colored output
|
||||||
|
function print_info() { printf "%b\n" "${C_CYAN}$*${C_RESET}"; }
|
||||||
|
function print_warn() { printf "%b\n" "${C_YELLOW}$*${C_RESET}"; }
|
||||||
|
function print_error() { printf "%b\n" "${C_RED}$*${C_RESET}"; }
|
||||||
|
function print_success() { printf "%b\n" "${C_GREEN}$*${C_RESET}"; }
|
||||||
|
function print_skip() { printf "%b\n" "${C_BLUE}$*${C_RESET}"; }
|
||||||
|
function print_header() { printf "%b\n" "${C_BOLD}${C_CYAN}$*${C_RESET}"; }
|
||||||
|
|
||||||
# Module management menu definition
|
# Module management menu definition
|
||||||
# Format: "key|short|description"
|
# Format: "key|short|description"
|
||||||
module_menu_items=(
|
module_menu_items=(
|
||||||
@@ -65,11 +108,11 @@ function handle_module_command() {
|
|||||||
inst_module_help
|
inst_module_help
|
||||||
;;
|
;;
|
||||||
"quit")
|
"quit")
|
||||||
echo "Exiting module manager..."
|
print_info "Exiting module manager..."
|
||||||
return 0
|
return 0
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
echo "Invalid option. Use 'help' to see available commands."
|
print_error "Invalid option. Use 'help' to see available commands."
|
||||||
return 1
|
return 1
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
@@ -77,7 +120,7 @@ function handle_module_command() {
|
|||||||
|
|
||||||
# Show detailed module help
|
# Show detailed module help
|
||||||
function inst_module_help() {
|
function inst_module_help() {
|
||||||
echo "AzerothCore Module Manager Help"
|
print_header "AzerothCore Module Manager Help"
|
||||||
echo "==============================="
|
echo "==============================="
|
||||||
echo ""
|
echo ""
|
||||||
echo "Usage:"
|
echo "Usage:"
|
||||||
@@ -106,20 +149,20 @@ function inst_module_help() {
|
|||||||
|
|
||||||
# List installed modules
|
# List installed modules
|
||||||
function inst_module_list() {
|
function inst_module_list() {
|
||||||
echo "Installed Modules:"
|
print_header "Installed Modules"
|
||||||
echo "=================="
|
echo "=================="
|
||||||
local count=0
|
local count=0
|
||||||
while read -r repo_ref branch commit; do
|
while read -r repo_ref branch commit; do
|
||||||
[[ -z "$repo_ref" ]] && continue
|
[[ -z "$repo_ref" ]] && continue
|
||||||
count=$((count + 1))
|
count=$((count + 1))
|
||||||
echo " $count. $repo_ref ($branch)"
|
printf " %s. %b (%s)%b\n" "$count" "${C_GREEN}${repo_ref}" "${branch}" "${C_RESET}"
|
||||||
if [[ "$commit" != "-" ]]; then
|
if [[ "$commit" != "-" ]]; then
|
||||||
echo " Commit: $commit"
|
printf " %bCommit:%b %s\n" "${C_DIM}" "${C_RESET}" "$commit"
|
||||||
fi
|
fi
|
||||||
done < <(inst_mod_list_read)
|
done < <(inst_mod_list_read)
|
||||||
|
|
||||||
if [[ $count -eq 0 ]]; then
|
if [[ $count -eq 0 ]]; then
|
||||||
echo " No modules installed."
|
print_warn " No modules installed."
|
||||||
fi
|
fi
|
||||||
echo ""
|
echo ""
|
||||||
}
|
}
|
||||||
@@ -160,8 +203,7 @@ function inst_module() {
|
|||||||
inst_module_list "${args[@]}"
|
inst_module_list "${args[@]}"
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
echo "Unknown module command: $cmd"
|
print_error "Unknown module command: $cmd. Use 'help' to see available commands."
|
||||||
echo "Use 'help' to see available commands."
|
|
||||||
return 1
|
return 1
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
@@ -188,20 +230,72 @@ function inst_parse_module_spec() {
|
|||||||
|
|
||||||
# Parse the new syntax: repo[:dirname][@branch[:commit]]
|
# Parse the new syntax: repo[:dirname][@branch[:commit]]
|
||||||
|
|
||||||
# First, extract custom directory name if present (format: repo:dirname@branch)
|
# First, check if this is a URL (contains :// or starts with git@)
|
||||||
|
local is_url=0
|
||||||
|
if [[ "$spec" =~ :// ]] || [[ "$spec" =~ ^git@ ]]; then
|
||||||
|
is_url=1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Parse directory and branch differently for URLs vs simple names
|
||||||
local repo_with_branch="$spec"
|
local repo_with_branch="$spec"
|
||||||
if [[ "$spec" =~ ^([^@:]+):([^@:]+)(@.*)?$ ]]; then
|
if [[ $is_url -eq 1 ]]; then
|
||||||
repo_with_branch="${BASH_REMATCH[1]}${BASH_REMATCH[3]}"
|
# For URLs, look for :dirname pattern, but be careful about ports
|
||||||
dirname="${BASH_REMATCH[2]}"
|
# Strategy: only match :dirname if it's clearly after the repository path
|
||||||
|
|
||||||
|
# Look for :dirname patterns at the end, but not if it looks like a port
|
||||||
|
if [[ "$spec" =~ ^(.*\.git):([^@/:]+)(@.*)?$ ]]; then
|
||||||
|
# Repo ending with .git:dirname
|
||||||
|
repo_with_branch="${BASH_REMATCH[1]}${BASH_REMATCH[3]}"
|
||||||
|
dirname="${BASH_REMATCH[2]}"
|
||||||
|
elif [[ "$spec" =~ ^(.*://[^/]+/[^:]*[^0-9]):([^@/:]+)(@.*)?$ ]]; then
|
||||||
|
# URL with path ending in non-digit:dirname (avoid matching ports)
|
||||||
|
repo_with_branch="${BASH_REMATCH[1]}${BASH_REMATCH[3]}"
|
||||||
|
dirname="${BASH_REMATCH[2]}"
|
||||||
|
fi
|
||||||
|
# If no custom dirname found, repo_with_branch remains the original spec
|
||||||
|
else
|
||||||
|
# For simple names, use the original logic
|
||||||
|
if [[ "$spec" =~ ^([^@:]+):([^@:]+)(@.*)?$ ]]; then
|
||||||
|
repo_with_branch="${BASH_REMATCH[1]}${BASH_REMATCH[3]}"
|
||||||
|
dirname="${BASH_REMATCH[2]}"
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Now parse branch and commit from the repo part
|
# Now parse branch and commit from the repo part
|
||||||
if [[ "$repo_with_branch" =~ ^([^@]+)@([^:]+)(:(.+))?$ ]]; then
|
# Be careful not to confuse URL @ with branch @
|
||||||
repo_part="${BASH_REMATCH[1]}"
|
if [[ "$repo_with_branch" =~ :// ]]; then
|
||||||
branch="${BASH_REMATCH[2]}"
|
# For URLs, look for @ after the authority part
|
||||||
commit="${BASH_REMATCH[4]:-}"
|
if [[ "$repo_with_branch" =~ ^[^/]*//[^/]+/.*@([^:]+)(:(.+))?$ ]]; then
|
||||||
|
# @ found in path part - treat as branch
|
||||||
|
repo_part="${repo_with_branch%@*}"
|
||||||
|
branch="${BASH_REMATCH[1]}"
|
||||||
|
commit="${BASH_REMATCH[3]:-}"
|
||||||
|
elif [[ "$repo_with_branch" =~ ^([^@]*@[^/]+/.*)@([^:]+)(:(.+))?$ ]]; then
|
||||||
|
# @ found after URL authority @ - treat as branch
|
||||||
|
repo_part="${BASH_REMATCH[1]}"
|
||||||
|
branch="${BASH_REMATCH[2]}"
|
||||||
|
commit="${BASH_REMATCH[4]:-}"
|
||||||
|
else
|
||||||
|
repo_part="$repo_with_branch"
|
||||||
|
fi
|
||||||
|
elif [[ "$repo_with_branch" =~ ^git@ ]]; then
|
||||||
|
# Git SSH format - look for @ after the initial git@host: part
|
||||||
|
if [[ "$repo_with_branch" =~ ^git@[^:]+:.*@([^:]+)(:(.+))?$ ]]; then
|
||||||
|
repo_part="${repo_with_branch%@*}"
|
||||||
|
branch="${BASH_REMATCH[1]}"
|
||||||
|
commit="${BASH_REMATCH[3]:-}"
|
||||||
|
else
|
||||||
|
repo_part="$repo_with_branch"
|
||||||
|
fi
|
||||||
else
|
else
|
||||||
repo_part="$repo_with_branch"
|
# Non-URL format - use original logic
|
||||||
|
if [[ "$repo_with_branch" =~ ^([^@]+)@([^:]+)(:(.+))?$ ]]; then
|
||||||
|
repo_part="${BASH_REMATCH[1]}"
|
||||||
|
branch="${BASH_REMATCH[2]}"
|
||||||
|
commit="${BASH_REMATCH[4]:-}"
|
||||||
|
else
|
||||||
|
repo_part="$repo_with_branch"
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Normalize repo reference and extract owner/name.
|
# Normalize repo reference and extract owner/name.
|
||||||
@@ -210,10 +304,39 @@ function inst_parse_module_spec() {
|
|||||||
|
|
||||||
# If repo_ref is a URL, extract owner/name from path when possible
|
# If repo_ref is a URL, extract owner/name from path when possible
|
||||||
if [[ "$repo_ref" =~ :// ]] || [[ "$repo_ref" =~ ^git@ ]]; then
|
if [[ "$repo_ref" =~ :// ]] || [[ "$repo_ref" =~ ^git@ ]]; then
|
||||||
# Extract owner/name (last two path components)
|
# Handle various URL formats
|
||||||
owner_repo=$(echo "$repo_ref" | sed -E 's#(git@[^:]+:|https?://[^/]+/|ssh://[^/]+/)?(.*?)(\.git)?$#\2#')
|
local path_part=""
|
||||||
owner="$(echo "$owner_repo" | awk -F'/' '{print $(NF-1)}')"
|
if [[ "$repo_ref" =~ ^https?://[^/]+:?[0-9]*/(.+)$ ]]; then
|
||||||
name="$(echo "$owner_repo" | awk -F'/' '{print $NF}' | sed -E 's/\.git$//')"
|
# HTTPS URL (with or without port)
|
||||||
|
path_part="${BASH_REMATCH[1]}"
|
||||||
|
elif [[ "$repo_ref" =~ ^ssh://.*@[^/]+:?[0-9]*/(.+)$ ]]; then
|
||||||
|
# SSH URL with user@host:port/path format
|
||||||
|
path_part="${BASH_REMATCH[1]}"
|
||||||
|
elif [[ "$repo_ref" =~ ^ssh://[^@/]+:?[0-9]*/(.+)$ ]]; then
|
||||||
|
# SSH URL with host:port/path format (no user@)
|
||||||
|
path_part="${BASH_REMATCH[1]}"
|
||||||
|
elif [[ "$repo_ref" =~ ^git@[^:]+:(.+)$ ]]; then
|
||||||
|
# Git SSH format (git@host:path)
|
||||||
|
path_part="${BASH_REMATCH[1]}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Extract owner/name from path
|
||||||
|
if [[ -n "$path_part" ]]; then
|
||||||
|
# Remove .git suffix and any :dirname suffix
|
||||||
|
path_part="${path_part%.git}"
|
||||||
|
path_part="${path_part%:*}"
|
||||||
|
|
||||||
|
if [[ "$path_part" == *"/"* ]]; then
|
||||||
|
owner="$(echo "$path_part" | awk -F'/' '{print $(NF-1)}')"
|
||||||
|
name="$(echo "$path_part" | awk -F'/' '{print $NF}')"
|
||||||
|
else
|
||||||
|
owner="unknown"
|
||||||
|
name="$path_part"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
owner="unknown"
|
||||||
|
name="unknown"
|
||||||
|
fi
|
||||||
else
|
else
|
||||||
owner_repo="$repo_ref"
|
owner_repo="$repo_ref"
|
||||||
if [[ "$owner_repo" == *"/"* ]]; then
|
if [[ "$owner_repo" == *"/"* ]]; then
|
||||||
@@ -266,21 +389,28 @@ function inst_extract_owner_name {
|
|||||||
base_ref="${repo_ref%%:*}"
|
base_ref="${repo_ref%%:*}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ "$base_ref" =~ ^https?://github\.com/([^/]+)/([^/]+)(\.git)?(/.*)?$ ]]; then
|
# Handle various URL formats with possible ports
|
||||||
# HTTPS URL format - check this first before owner/name pattern
|
if [[ "$base_ref" =~ ^https?://[^/]+:?[0-9]*/([^/]+)/([^/?]+) ]]; then
|
||||||
|
# HTTPS URL format (with or without port) - matches github.com, gitlab.com, custom hosts
|
||||||
|
local owner="${BASH_REMATCH[1]}"
|
||||||
local name="${BASH_REMATCH[2]}"
|
local name="${BASH_REMATCH[2]}"
|
||||||
name="${name%.git}" # Remove .git suffix if present
|
name="${name%:*}" # Remove any :dirname suffix first
|
||||||
echo "${BASH_REMATCH[1]}/$name"
|
name="${name%.git}" # Then remove .git suffix if present
|
||||||
elif [[ "$base_ref" =~ ^https?://gitlab\.com/([^/]+)/([^/]+)(\.git)?(/.*)?$ ]]; then
|
echo "$owner/$name"
|
||||||
# GitLab URL format
|
elif [[ "$base_ref" =~ ^ssh://[^/]+:?[0-9]*/([^/]+)/([^/?]+) ]]; then
|
||||||
|
# SSH URL format (with or without port)
|
||||||
|
local owner="${BASH_REMATCH[1]}"
|
||||||
local name="${BASH_REMATCH[2]}"
|
local name="${BASH_REMATCH[2]}"
|
||||||
name="${name%.git}" # Remove .git suffix if present
|
name="${name%:*}" # Remove any :dirname suffix first
|
||||||
echo "${BASH_REMATCH[1]}/$name"
|
name="${name%.git}" # Then remove .git suffix if present
|
||||||
elif [[ "$base_ref" =~ ^git@github\.com:([^/]+)/([^/]+)(\.git)?$ ]]; then
|
echo "$owner/$name"
|
||||||
# SSH URL format
|
elif [[ "$base_ref" =~ ^git@[^:]+:([^/]+)/([^/?]+) ]]; then
|
||||||
|
# Git SSH format (git@host:owner/repo)
|
||||||
|
local owner="${BASH_REMATCH[1]}"
|
||||||
local name="${BASH_REMATCH[2]}"
|
local name="${BASH_REMATCH[2]}"
|
||||||
name="${name%.git}" # Remove .git suffix if present
|
name="${name%:*}" # Remove any :dirname suffix first
|
||||||
echo "${BASH_REMATCH[1]}/$name"
|
name="${name%.git}" # Then remove .git suffix if present
|
||||||
|
echo "$owner/$name"
|
||||||
elif [[ "$base_ref" =~ ^[^/]+/[^/]+$ ]]; then
|
elif [[ "$base_ref" =~ ^[^/]+/[^/]+$ ]]; then
|
||||||
# Format: owner/name (check after URL patterns)
|
# Format: owner/name (check after URL patterns)
|
||||||
echo "$base_ref"
|
echo "$base_ref"
|
||||||
@@ -330,6 +460,40 @@ function inst_mod_list_read() {
|
|||||||
done < "$file"
|
done < "$file"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Check whether a module spec matches the exclusion list.
|
||||||
|
# - Reads space/newline separated items from env var MODULES_EXCLUDE_LIST
|
||||||
|
# - Supports cross-format matching via inst_extract_owner_name
|
||||||
|
# Returns 0 if excluded, 1 otherwise.
|
||||||
|
function inst_mod_is_excluded() {
|
||||||
|
local spec="$1"
|
||||||
|
local target_owner_name
|
||||||
|
target_owner_name=$(inst_extract_owner_name "$spec")
|
||||||
|
|
||||||
|
# No exclusions configured
|
||||||
|
if [[ -z "${MODULES_EXCLUDE_LIST:-}" ]]; then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Split on default IFS (space, tab, newline)
|
||||||
|
local items=()
|
||||||
|
# Use mapfile to split MODULES_EXCLUDE_LIST on newlines; fallback to space if no newlines
|
||||||
|
if [[ "${MODULES_EXCLUDE_LIST}" == *$'\n'* ]]; then
|
||||||
|
mapfile -t items <<< "${MODULES_EXCLUDE_LIST}"
|
||||||
|
else
|
||||||
|
read -r -a items <<< "${MODULES_EXCLUDE_LIST}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
local it it_owner
|
||||||
|
for it in "${items[@]}"; do
|
||||||
|
[[ -z "$it" ]] && continue
|
||||||
|
it_owner=$(inst_extract_owner_name "$it")
|
||||||
|
if [[ "$it_owner" == "$target_owner_name" ]]; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
# Add or update an entry in the list: repo_ref branch commit
|
# Add or update an entry in the list: repo_ref branch commit
|
||||||
# Removes any existing entries with the same owner/name to avoid duplicates
|
# Removes any existing entries with the same owner/name to avoid duplicates
|
||||||
function inst_mod_list_upsert() {
|
function inst_mod_list_upsert() {
|
||||||
@@ -448,12 +612,12 @@ function inst_check_module_conflict {
|
|||||||
local repo_ref="$2"
|
local repo_ref="$2"
|
||||||
|
|
||||||
if [ -d "$J_PATH_MODULES/$dirname" ]; then
|
if [ -d "$J_PATH_MODULES/$dirname" ]; then
|
||||||
echo "Error: Directory '$dirname' already exists."
|
print_error "Error: Directory '$dirname' already exists."
|
||||||
echo "Possible solutions:"
|
print_warn "Possible solutions:"
|
||||||
echo " 1. Use a different directory name: $repo_ref:my-custom-name"
|
echo " 1. Use a different directory name: $repo_ref:my-custom-name"
|
||||||
echo " 2. Remove the existing directory first"
|
echo " 2. Remove the existing directory first"
|
||||||
echo " 3. Use the update command if this is the same module"
|
echo " 3. Use the update command if this is the same module"
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
@@ -511,7 +675,7 @@ function inst_module_search {
|
|||||||
|
|
||||||
local CATALOG_URL="https://www.azerothcore.org/data/catalogue.json"
|
local CATALOG_URL="https://www.azerothcore.org/data/catalogue.json"
|
||||||
|
|
||||||
echo "Searching ${terms[*]}..."
|
print_header "Searching ${terms[*]}..."
|
||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
# Build candidate list from catalogue (full_name = owner/repo)
|
# Build candidate list from catalogue (full_name = owner/repo)
|
||||||
@@ -567,9 +731,9 @@ function inst_module_search {
|
|||||||
read v b < <(inst_getVersionBranch "https://raw.githubusercontent.com/${mod_full}/master/acore-module.json")
|
read v b < <(inst_getVersionBranch "https://raw.githubusercontent.com/${mod_full}/master/acore-module.json")
|
||||||
|
|
||||||
if [[ "$b" != "none" ]]; then
|
if [[ "$b" != "none" ]]; then
|
||||||
echo "-> $mod (tested with AC version: $v)"
|
printf "%b -> %b (tested with AC version: %s)%b\n" "" "${C_GREEN}${mod}${C_RESET}" "$v" ""
|
||||||
else
|
else
|
||||||
echo "-> $mod (NOTE: The module latest tested AC revision is Unknown)"
|
printf "%b -> %b %b(NOTE: The module latest tested AC revision is Unknown)%b\n" "" "${C_GREEN}${mod}${C_RESET}" "${C_YELLOW}" "${C_RESET}"
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
@@ -590,7 +754,7 @@ function inst_module_install {
|
|||||||
|
|
||||||
local modules=("$@")
|
local modules=("$@")
|
||||||
|
|
||||||
echo "Installing modules: ${modules[*]}"
|
print_header "Installing modules: ${modules[*]}"
|
||||||
|
|
||||||
if $use_all; then
|
if $use_all; then
|
||||||
# Install all modules from the list (respecting recorded branch and commit).
|
# Install all modules from the list (respecting recorded branch and commit).
|
||||||
@@ -602,14 +766,18 @@ function inst_module_install {
|
|||||||
local dup_error=0
|
local dup_error=0
|
||||||
while read -r repo_ref branch commit; do
|
while read -r repo_ref branch commit; do
|
||||||
[ -z "$repo_ref" ] && continue
|
[ -z "$repo_ref" ] && continue
|
||||||
|
# Skip excluded modules when checking duplicates
|
||||||
|
if inst_mod_is_excluded "$repo_ref"; then
|
||||||
|
continue
|
||||||
|
fi
|
||||||
parsed_output=$(inst_parse_module_spec "$repo_ref")
|
parsed_output=$(inst_parse_module_spec "$repo_ref")
|
||||||
IFS=' ' read -r _ owner modname _ _ url dirname <<< "$parsed_output"
|
IFS=' ' read -r _ owner modname _ _ url dirname <<< "$parsed_output"
|
||||||
# dirname defaults to repo name; flat install path uses dirname only
|
# dirname defaults to repo name; flat install path uses dirname only
|
||||||
if [[ -n "${_seen[$dirname]:-}" ]]; then
|
if [[ -n "${_seen[$dirname]:-}" ]]; then
|
||||||
echo "Error: duplicate module target directory '$dirname' detected in modules.list:"
|
print_error "Error: duplicate module target directory '$dirname' detected in modules.list:"
|
||||||
echo " - ${_first[$dirname]}"
|
echo " - ${_first[$dirname]}"
|
||||||
echo " - ${repo_ref}"
|
echo " - ${repo_ref}"
|
||||||
echo "Use a custom folder name to disambiguate, e.g.: ${repo_ref}:$dirname-alt"
|
print_warn "Use a custom folder name to disambiguate, e.g.: ${repo_ref}:$dirname-alt"
|
||||||
dup_error=1
|
dup_error=1
|
||||||
else
|
else
|
||||||
_seen[$dirname]=1
|
_seen[$dirname]=1
|
||||||
@@ -623,11 +791,16 @@ function inst_module_install {
|
|||||||
# Second pass: install in flat modules directory (no owner subfolders)
|
# Second pass: install in flat modules directory (no owner subfolders)
|
||||||
while read -r repo_ref branch commit; do
|
while read -r repo_ref branch commit; do
|
||||||
[ -z "$repo_ref" ] && continue
|
[ -z "$repo_ref" ] && continue
|
||||||
|
# Skip excluded entries during installation
|
||||||
|
if inst_mod_is_excluded "$repo_ref"; then
|
||||||
|
print_warn "[$repo_ref] Excluded by MODULES_EXCLUDE_LIST (skipping)."
|
||||||
|
continue
|
||||||
|
fi
|
||||||
parsed_output=$(inst_parse_module_spec "$repo_ref")
|
parsed_output=$(inst_parse_module_spec "$repo_ref")
|
||||||
IFS=' ' read -r _ owner modname _ _ url dirname <<< "$parsed_output"
|
IFS=' ' read -r _ owner modname _ _ url dirname <<< "$parsed_output"
|
||||||
|
|
||||||
if [ -d "$J_PATH_MODULES/$dirname" ]; then
|
if [ -d "$J_PATH_MODULES/$dirname" ]; then
|
||||||
echo "[$repo_ref] Already installed (skipping)."
|
print_skip "[$repo_ref] Already installed (skipping)."
|
||||||
continue
|
continue
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -642,9 +815,9 @@ function inst_module_install {
|
|||||||
local curCommit
|
local curCommit
|
||||||
curCommit=$(git -C "$J_PATH_MODULES/$dirname" rev-parse HEAD 2>/dev/null || echo "")
|
curCommit=$(git -C "$J_PATH_MODULES/$dirname" rev-parse HEAD 2>/dev/null || echo "")
|
||||||
inst_mod_list_upsert "$repo_ref" "$branch" "$curCommit"
|
inst_mod_list_upsert "$repo_ref" "$branch" "$curCommit"
|
||||||
echo "[$repo_ref] Installed."
|
print_success "[$repo_ref] Installed."
|
||||||
else
|
else
|
||||||
echo "[$repo_ref] Install failed."
|
print_error "[$repo_ref] Install failed."
|
||||||
exit 1;
|
exit 1;
|
||||||
fi
|
fi
|
||||||
done < <(inst_mod_list_read)
|
done < <(inst_mod_list_read)
|
||||||
@@ -663,7 +836,7 @@ function inst_module_install {
|
|||||||
# Check if module is already installed (by owner/name matching)
|
# Check if module is already installed (by owner/name matching)
|
||||||
existing_repo_ref=$(inst_mod_is_installed "$spec" || true)
|
existing_repo_ref=$(inst_mod_is_installed "$spec" || true)
|
||||||
if [ -n "$existing_repo_ref" ]; then
|
if [ -n "$existing_repo_ref" ]; then
|
||||||
echo "[$spec] Already installed as [$existing_repo_ref] (skipping)."
|
print_skip "[$spec] Already installed as [$existing_repo_ref] (skipping)."
|
||||||
continue
|
continue
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -689,14 +862,14 @@ function inst_module_install {
|
|||||||
fi
|
fi
|
||||||
if [[ "$v" == "none" || "$v" == "not-defined" || "$b" == "none" ]]; then
|
if [[ "$v" == "none" || "$v" == "not-defined" || "$b" == "none" ]]; then
|
||||||
def="$(inst_get_default_branch "$repo_ref")"
|
def="$(inst_get_default_branch "$repo_ref")"
|
||||||
echo "Warning: $repo_ref has no compatible acore-module.json; installing from branch '$def' (latest commit)."
|
print_warn "Warning: $repo_ref has no compatible acore-module.json; installing from branch '$def' (latest commit)."
|
||||||
b="$def"
|
b="$def"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Use flat directory structure with custom directory name
|
# Use flat directory structure with custom directory name
|
||||||
if [ -d "$J_PATH_MODULES/$dirname" ]; then
|
if [ -d "$J_PATH_MODULES/$dirname" ]; then
|
||||||
echo "[$repo_ref] Already installed (skipping)."
|
print_skip "[$repo_ref] Already installed (skipping)."
|
||||||
curCommit=$(git -C "$J_PATH_MODULES/$dirname" rev-parse HEAD 2>/dev/null || echo "")
|
curCommit=$(git -C "$J_PATH_MODULES/$dirname" rev-parse HEAD 2>/dev/null || echo "")
|
||||||
inst_mod_list_upsert "$repo_ref" "$b" "$curCommit"
|
inst_mod_list_upsert "$repo_ref" "$b" "$curCommit"
|
||||||
continue
|
continue
|
||||||
@@ -709,14 +882,14 @@ function inst_module_install {
|
|||||||
if git -C "$J_PATH_MODULES/$dirname" rev-parse --verify "$override_commit" >/dev/null 2>&1; then
|
if git -C "$J_PATH_MODULES/$dirname" rev-parse --verify "$override_commit" >/dev/null 2>&1; then
|
||||||
git -C "$J_PATH_MODULES/$dirname" checkout --quiet "$override_commit"
|
git -C "$J_PATH_MODULES/$dirname" checkout --quiet "$override_commit"
|
||||||
else
|
else
|
||||||
echo "[$repo_ref] Warning: provided commit '$override_commit' not found; staying on branch '$b' HEAD."
|
print_warn "[$repo_ref] provided commit '$override_commit' not found; staying on branch '$b' HEAD."
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
curCommit=$(git -C "$J_PATH_MODULES/$dirname" rev-parse HEAD 2>/dev/null || echo "")
|
curCommit=$(git -C "$J_PATH_MODULES/$dirname" rev-parse HEAD 2>/dev/null || echo "")
|
||||||
inst_mod_list_upsert "$repo_ref" "$b" "$curCommit"
|
inst_mod_list_upsert "$repo_ref" "$b" "$curCommit"
|
||||||
echo "[$repo_ref] Installed in '$dirname'. Please re-run compiling and db assembly."
|
print_success "[$repo_ref] Installed in '$dirname'. Please re-run compiling and db assembly."
|
||||||
else
|
else
|
||||||
echo "[$repo_ref] Install failed or module not found"
|
print_error "[$repo_ref] Install failed or module not found"
|
||||||
exit 1;
|
exit 1;
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
@@ -748,21 +921,26 @@ function inst_module_update {
|
|||||||
local line repo_ref branch commit newCommit owner modname url dirname
|
local line repo_ref branch commit newCommit owner modname url dirname
|
||||||
while read -r repo_ref branch commit; do
|
while read -r repo_ref branch commit; do
|
||||||
[ -z "$repo_ref" ] && continue
|
[ -z "$repo_ref" ] && continue
|
||||||
|
# Skip excluded modules during update --all
|
||||||
|
if inst_mod_is_excluded "$repo_ref"; then
|
||||||
|
print_warn "[$repo_ref] Excluded by MODULES_EXCLUDE_LIST (skipping)."
|
||||||
|
continue
|
||||||
|
fi
|
||||||
parsed_output=$(inst_parse_module_spec "$repo_ref")
|
parsed_output=$(inst_parse_module_spec "$repo_ref")
|
||||||
IFS=' ' read -r _ owner modname _ _ url dirname <<< "$parsed_output"
|
IFS=' ' read -r _ owner modname _ _ url dirname <<< "$parsed_output"
|
||||||
|
|
||||||
dirname="${dirname:-$modname}"
|
dirname="${dirname:-$modname}"
|
||||||
if [ ! -d "$J_PATH_MODULES/$dirname/" ]; then
|
if [ ! -d "$J_PATH_MODULES/$dirname/" ]; then
|
||||||
echo "[$repo_ref] Not installed locally, skipping."
|
print_skip "[$repo_ref] Not installed locally, skipping."
|
||||||
continue
|
continue
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if Joiner:upd_repo "$url" "$dirname" "$branch" ""; then
|
if Joiner:upd_repo "$url" "$dirname" "$branch" ""; then
|
||||||
newCommit=$(git -C "$J_PATH_MODULES/$dirname" rev-parse HEAD 2>/dev/null || echo "")
|
newCommit=$(git -C "$J_PATH_MODULES/$dirname" rev-parse HEAD 2>/dev/null || echo "")
|
||||||
inst_mod_list_upsert "$repo_ref" "$branch" "$newCommit"
|
inst_mod_list_upsert "$repo_ref" "$branch" "$newCommit"
|
||||||
echo "[$repo_ref] Updated to latest commit on '$branch'."
|
print_success "[$repo_ref] Updated to latest commit on '$branch'."
|
||||||
else
|
else
|
||||||
echo "[$repo_ref] Cannot update"
|
print_error "[$repo_ref] Cannot update"
|
||||||
fi
|
fi
|
||||||
done < <(inst_mod_list_read)
|
done < <(inst_mod_list_read)
|
||||||
else
|
else
|
||||||
@@ -793,11 +971,11 @@ function inst_module_update {
|
|||||||
fi
|
fi
|
||||||
if [[ "$v" == "none" || "$v" == "not-defined" || "$b" == "none" ]]; then
|
if [[ "$v" == "none" || "$v" == "not-defined" || "$b" == "none" ]]; then
|
||||||
if branch=$(git -C "$J_PATH_MODULES/$dirname" rev-parse --abbrev-ref HEAD 2>/dev/null); then
|
if branch=$(git -C "$J_PATH_MODULES/$dirname" rev-parse --abbrev-ref HEAD 2>/dev/null); then
|
||||||
echo "Warning: $repo_ref has no compatible acore-module.json; updating current branch '$branch'."
|
print_warn "Warning: $repo_ref has no compatible acore-module.json; updating current branch '$branch'."
|
||||||
b="$branch"
|
b="$branch"
|
||||||
else
|
else
|
||||||
def="$(inst_get_default_branch "$repo_ref")"
|
def="$(inst_get_default_branch "$repo_ref")"
|
||||||
echo "Warning: $repo_ref has no compatible acore-module.json and no git branch detected; updating default branch '$def'."
|
print_warn "Warning: $repo_ref has no compatible acore-module.json and no git branch detected; updating default branch '$def'."
|
||||||
b="$def"
|
b="$def"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
@@ -806,12 +984,12 @@ function inst_module_update {
|
|||||||
if Joiner:upd_repo "$url" "$dirname" "$b" ""; then
|
if Joiner:upd_repo "$url" "$dirname" "$b" ""; then
|
||||||
newCommit=$(git -C "$J_PATH_MODULES/$dirname" rev-parse HEAD 2>/dev/null || echo "")
|
newCommit=$(git -C "$J_PATH_MODULES/$dirname" rev-parse HEAD 2>/dev/null || echo "")
|
||||||
inst_mod_list_upsert "$repo_ref" "$b" "$newCommit"
|
inst_mod_list_upsert "$repo_ref" "$b" "$newCommit"
|
||||||
echo "[$repo_ref] Done, please re-run compiling and db assembly"
|
print_success "[$repo_ref] Done, please re-run compiling and db assembly"
|
||||||
else
|
else
|
||||||
echo "[$repo_ref] Cannot update"
|
print_error "[$repo_ref] Cannot update"
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
echo "[$repo_ref] Cannot update! Path doesn't exist ($J_PATH_MODULES/$dirname/)"
|
print_error "[$repo_ref] Cannot update! Path doesn't exist ($J_PATH_MODULES/$dirname/)"
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
fi
|
fi
|
||||||
@@ -840,9 +1018,9 @@ function inst_module_remove {
|
|||||||
dirname="${dirname:-$modname}"
|
dirname="${dirname:-$modname}"
|
||||||
if Joiner:remove "$dirname" ""; then
|
if Joiner:remove "$dirname" ""; then
|
||||||
inst_mod_list_remove "$repo_ref"
|
inst_mod_list_remove "$repo_ref"
|
||||||
echo "[$repo_ref] Done, please re-run compiling"
|
print_success "[$repo_ref] Done, please re-run compiling"
|
||||||
else
|
else
|
||||||
echo "[$repo_ref] Cannot remove"
|
print_error "[$repo_ref] Cannot remove"
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
|
|||||||
@@ -146,6 +146,27 @@ teardown() {
|
|||||||
[ "$output" = "myorg/mymodule" ]
|
[ "$output" = "myorg/mymodule" ]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@test "inst_extract_owner_name should handle URLs with ports correctly" {
|
||||||
|
cd "$TEST_DIR"
|
||||||
|
source "$TEST_DIR/apps/installer/includes/includes.sh"
|
||||||
|
|
||||||
|
# Test HTTPS URL with port
|
||||||
|
run inst_extract_owner_name "https://example.com:8080/user/repo.git"
|
||||||
|
[ "$output" = "user/repo" ]
|
||||||
|
|
||||||
|
# Test SSH URL with port
|
||||||
|
run inst_extract_owner_name "ssh://git@example.com:2222/owner/module"
|
||||||
|
[ "$output" = "owner/module" ]
|
||||||
|
|
||||||
|
# Test URL with port and custom directory (should ignore the directory part)
|
||||||
|
run inst_extract_owner_name "https://gitlab.internal:9443/team/project.git:custom-dir"
|
||||||
|
[ "$output" = "team/project" ]
|
||||||
|
|
||||||
|
# Test complex URL with port (should extract owner/name correctly)
|
||||||
|
run inst_extract_owner_name "https://git.company.com:8443/department/awesome-module.git"
|
||||||
|
[ "$output" = "department/awesome-module" ]
|
||||||
|
}
|
||||||
|
|
||||||
@test "duplicate module entries should be prevented across different formats" {
|
@test "duplicate module entries should be prevented across different formats" {
|
||||||
cd "$TEST_DIR"
|
cd "$TEST_DIR"
|
||||||
source "$TEST_DIR/apps/installer/includes/includes.sh"
|
source "$TEST_DIR/apps/installer/includes/includes.sh"
|
||||||
@@ -189,6 +210,30 @@ teardown() {
|
|||||||
[ "$status" -ne 0 ]
|
[ "$status" -ne 0 ]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@test "module installed via URL with port should be recognized correctly" {
|
||||||
|
cd "$TEST_DIR"
|
||||||
|
source "$TEST_DIR/apps/installer/includes/includes.sh"
|
||||||
|
|
||||||
|
# Install via URL with port
|
||||||
|
inst_mod_list_upsert "https://gitlab.internal:9443/myorg/my-module.git" "master" "abc123"
|
||||||
|
|
||||||
|
# Should be detected as installed using normalized owner/name
|
||||||
|
run inst_mod_is_installed "myorg/my-module"
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
|
||||||
|
# Should be detected when checking with different URL format
|
||||||
|
run inst_mod_is_installed "ssh://git@gitlab.internal:9443/myorg/my-module"
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
|
||||||
|
# Should be detected when checking with custom directory syntax
|
||||||
|
run inst_mod_is_installed "myorg/my-module:custom-dir"
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
|
||||||
|
# Different module should not be detected
|
||||||
|
run inst_mod_is_installed "myorg/different-module"
|
||||||
|
[ "$status" -ne 0 ]
|
||||||
|
}
|
||||||
|
|
||||||
@test "cross-format module removal should work" {
|
@test "cross-format module removal should work" {
|
||||||
cd "$TEST_DIR"
|
cd "$TEST_DIR"
|
||||||
source "$TEST_DIR/apps/installer/includes/includes.sh"
|
source "$TEST_DIR/apps/installer/includes/includes.sh"
|
||||||
@@ -355,3 +400,356 @@ EOF
|
|||||||
[ "$owner_name_format" = "azerothcore/mod-transmog" ]
|
[ "$owner_name_format" = "azerothcore/mod-transmog" ]
|
||||||
[ "$simple_format" = "azerothcore/mod-transmog" ]
|
[ "$simple_format" = "azerothcore/mod-transmog" ]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Tests for module exclusion functionality
|
||||||
|
|
||||||
|
@test "module exclusion should work with MODULES_EXCLUDE_LIST" {
|
||||||
|
cd "$TEST_DIR"
|
||||||
|
source "$TEST_DIR/apps/installer/includes/includes.sh"
|
||||||
|
|
||||||
|
# Test exclusion with simple name
|
||||||
|
export MODULES_EXCLUDE_LIST="mod-test-module"
|
||||||
|
run inst_mod_is_excluded "mod-test-module"
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
|
||||||
|
# Test exclusion with owner/name format
|
||||||
|
export MODULES_EXCLUDE_LIST="azerothcore/mod-test"
|
||||||
|
run inst_mod_is_excluded "mod-test"
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
|
||||||
|
# Test exclusion with space-separated list
|
||||||
|
export MODULES_EXCLUDE_LIST="mod-one mod-two mod-three"
|
||||||
|
run inst_mod_is_excluded "mod-two"
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
|
||||||
|
# Test exclusion with newline-separated list
|
||||||
|
export MODULES_EXCLUDE_LIST="
|
||||||
|
mod-alpha
|
||||||
|
mod-beta
|
||||||
|
mod-gamma
|
||||||
|
"
|
||||||
|
run inst_mod_is_excluded "mod-beta"
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
|
||||||
|
# Test exclusion with URL format
|
||||||
|
export MODULES_EXCLUDE_LIST="https://github.com/azerothcore/mod-transmog.git"
|
||||||
|
run inst_mod_is_excluded "mod-transmog"
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
|
||||||
|
# Test non-excluded module
|
||||||
|
export MODULES_EXCLUDE_LIST="mod-other"
|
||||||
|
run inst_mod_is_excluded "mod-transmog"
|
||||||
|
[ "$status" -eq 1 ]
|
||||||
|
|
||||||
|
# Test empty exclusion list
|
||||||
|
unset MODULES_EXCLUDE_LIST
|
||||||
|
run inst_mod_is_excluded "mod-transmog"
|
||||||
|
[ "$status" -eq 1 ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "install --all should skip excluded modules" {
|
||||||
|
cd "$TEST_DIR"
|
||||||
|
source "$TEST_DIR/apps/installer/includes/includes.sh"
|
||||||
|
|
||||||
|
# Setup modules list with excluded module
|
||||||
|
mkdir -p "$TEST_DIR/conf"
|
||||||
|
cat > "$TEST_DIR/conf/modules.list" << 'EOF'
|
||||||
|
azerothcore/mod-transmog master abc123
|
||||||
|
azerothcore/mod-excluded master def456
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Set exclusion list
|
||||||
|
export MODULES_EXCLUDE_LIST="mod-excluded"
|
||||||
|
|
||||||
|
# Mock the install process to capture output
|
||||||
|
run bash -c "source '$TEST_DIR/apps/installer/includes/includes.sh' && inst_module_install --all 2>&1"
|
||||||
|
|
||||||
|
# Should show that excluded module was skipped
|
||||||
|
[[ "$output" == *"azerothcore/mod-excluded"* && "$output" == *"Excluded by MODULES_EXCLUDE_LIST"* && "$output" == *"skipping"* ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "exclusion should work with multiple formats in same list" {
|
||||||
|
cd "$TEST_DIR"
|
||||||
|
source "$TEST_DIR/apps/installer/includes/includes.sh"
|
||||||
|
|
||||||
|
# Test multiple exclusion formats
|
||||||
|
export MODULES_EXCLUDE_LIST="mod-test https://github.com/azerothcore/mod-transmog.git custom/mod-other"
|
||||||
|
|
||||||
|
run inst_mod_is_excluded "mod-test"
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
|
||||||
|
run inst_mod_is_excluded "azerothcore/mod-transmog"
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
|
||||||
|
run inst_mod_is_excluded "custom/mod-other"
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
|
||||||
|
run inst_mod_is_excluded "mod-allowed"
|
||||||
|
[ "$status" -eq 1 ]
|
||||||
|
}
|
||||||
|
|
||||||
|
# Tests for color support functionality
|
||||||
|
|
||||||
|
@test "color functions should work correctly" {
|
||||||
|
cd "$TEST_DIR"
|
||||||
|
source "$TEST_DIR/apps/installer/includes/includes.sh"
|
||||||
|
|
||||||
|
# Test that print functions exist and work
|
||||||
|
run print_info "test message"
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
|
||||||
|
run print_warn "test warning"
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
|
||||||
|
run print_error "test error"
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
|
||||||
|
run print_success "test success"
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
|
||||||
|
run print_skip "test skip"
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
|
||||||
|
run print_header "test header"
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "color support should respect NO_COLOR environment variable" {
|
||||||
|
cd "$TEST_DIR"
|
||||||
|
|
||||||
|
# Test with NO_COLOR set
|
||||||
|
export NO_COLOR=1
|
||||||
|
source "$TEST_DIR/apps/installer/includes/includes.sh"
|
||||||
|
|
||||||
|
# Colors should be empty when NO_COLOR is set
|
||||||
|
[ -z "$C_RED" ]
|
||||||
|
[ -z "$C_GREEN" ]
|
||||||
|
[ -z "$C_RESET" ]
|
||||||
|
}
|
||||||
|
|
||||||
|
# Tests for interactive menu system
|
||||||
|
|
||||||
|
@test "module help should display comprehensive help" {
|
||||||
|
cd "$TEST_DIR"
|
||||||
|
source "$TEST_DIR/apps/installer/includes/includes.sh"
|
||||||
|
|
||||||
|
run inst_module_help
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
|
||||||
|
# Should contain key sections
|
||||||
|
[[ "$output" =~ "Module Manager Help" ]]
|
||||||
|
[[ "$output" =~ "Usage:" ]]
|
||||||
|
[[ "$output" =~ "Module Specification Syntax:" ]]
|
||||||
|
[[ "$output" =~ "Examples:" ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "module list should show installed modules correctly" {
|
||||||
|
cd "$TEST_DIR"
|
||||||
|
source "$TEST_DIR/apps/installer/includes/includes.sh"
|
||||||
|
|
||||||
|
# Setup modules list
|
||||||
|
mkdir -p "$TEST_DIR/conf"
|
||||||
|
cat > "$TEST_DIR/conf/modules.list" << 'EOF'
|
||||||
|
azerothcore/mod-transmog master abc123
|
||||||
|
custom/mod-test develop def456
|
||||||
|
EOF
|
||||||
|
|
||||||
|
run inst_module_list
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
|
||||||
|
# Should show both modules
|
||||||
|
[[ "$output" =~ "mod-transmog" ]]
|
||||||
|
[[ "$output" =~ "custom/mod-test" ]]
|
||||||
|
[[ "$output" =~ "master" ]]
|
||||||
|
[[ "$output" =~ "develop" ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "module list should handle empty list gracefully" {
|
||||||
|
cd "$TEST_DIR"
|
||||||
|
source "$TEST_DIR/apps/installer/includes/includes.sh"
|
||||||
|
|
||||||
|
# Ensure empty modules list
|
||||||
|
mkdir -p "$TEST_DIR/conf"
|
||||||
|
touch "$TEST_DIR/conf/modules.list"
|
||||||
|
|
||||||
|
run inst_module_list
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
[[ "$output" =~ "No modules installed" ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
# Tests for advanced parsing edge cases
|
||||||
|
|
||||||
|
@test "parsing should handle complex URL formats" {
|
||||||
|
cd "$TEST_DIR"
|
||||||
|
source "$TEST_DIR/apps/installer/includes/includes.sh"
|
||||||
|
|
||||||
|
# Test GitLab URL with custom directory and branch
|
||||||
|
run inst_parse_module_spec "https://gitlab.com/myorg/mymodule.git:custom-dir@develop:abc123"
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
IFS=' ' read -r repo_ref owner name branch commit url dirname <<< "$output"
|
||||||
|
[ "$repo_ref" = "https://gitlab.com/myorg/mymodule.git" ]
|
||||||
|
[ "$owner" = "myorg" ]
|
||||||
|
[ "$name" = "mymodule" ]
|
||||||
|
[ "$branch" = "develop" ]
|
||||||
|
[ "$commit" = "abc123" ]
|
||||||
|
[ "$dirname" = "custom-dir" ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "parsing should handle URLs with ports correctly (fix for port/dirname confusion)" {
|
||||||
|
cd "$TEST_DIR"
|
||||||
|
source "$TEST_DIR/apps/installer/includes/includes.sh"
|
||||||
|
|
||||||
|
# Test HTTPS URL with port - should NOT treat port as dirname
|
||||||
|
run inst_parse_module_spec "https://example.com:8080/user/repo.git"
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
IFS=' ' read -r repo_ref owner name branch commit url dirname <<< "$output"
|
||||||
|
[ "$repo_ref" = "https://example.com:8080/user/repo.git" ]
|
||||||
|
[ "$owner" = "user" ]
|
||||||
|
[ "$name" = "repo" ]
|
||||||
|
[ "$branch" = "-" ]
|
||||||
|
[ "$commit" = "-" ]
|
||||||
|
[ "$url" = "https://example.com:8080/user/repo.git" ]
|
||||||
|
[ "$dirname" = "repo" ] # Should default to repo name, NOT port number
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "parsing should handle URLs with ports and custom directory correctly" {
|
||||||
|
cd "$TEST_DIR"
|
||||||
|
source "$TEST_DIR/apps/installer/includes/includes.sh"
|
||||||
|
|
||||||
|
# Test URL with port AND custom directory - should parse custom directory correctly
|
||||||
|
run inst_parse_module_spec "https://example.com:8080/user/repo.git:custom-dir"
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
IFS=' ' read -r repo_ref owner name branch commit url dirname <<< "$output"
|
||||||
|
[ "$repo_ref" = "https://example.com:8080/user/repo.git" ]
|
||||||
|
[ "$owner" = "user" ]
|
||||||
|
[ "$name" = "repo" ]
|
||||||
|
[ "$branch" = "-" ]
|
||||||
|
[ "$commit" = "-" ]
|
||||||
|
[ "$url" = "https://example.com:8080/user/repo.git" ]
|
||||||
|
[ "$dirname" = "custom-dir" ] # Should be custom-dir, not port number
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "parsing should handle SSH URLs with ports correctly" {
|
||||||
|
cd "$TEST_DIR"
|
||||||
|
source "$TEST_DIR/apps/installer/includes/includes.sh"
|
||||||
|
|
||||||
|
# Test SSH URL with port
|
||||||
|
run inst_parse_module_spec "ssh://git@example.com:2222/user/repo"
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
IFS=' ' read -r repo_ref owner name branch commit url dirname <<< "$output"
|
||||||
|
[ "$repo_ref" = "ssh://git@example.com:2222/user/repo" ]
|
||||||
|
[ "$owner" = "user" ]
|
||||||
|
[ "$name" = "repo" ]
|
||||||
|
[ "$dirname" = "repo" ] # Should be repo name, not port number
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "parsing should handle SSH URLs with ports and custom directory" {
|
||||||
|
cd "$TEST_DIR"
|
||||||
|
source "$TEST_DIR/apps/installer/includes/includes.sh"
|
||||||
|
|
||||||
|
# Test SSH URL with port and custom directory
|
||||||
|
run inst_parse_module_spec "ssh://git@example.com:2222/user/repo:my-custom-dir@develop"
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
IFS=' ' read -r repo_ref owner name branch commit url dirname <<< "$output"
|
||||||
|
[ "$repo_ref" = "ssh://git@example.com:2222/user/repo" ]
|
||||||
|
[ "$owner" = "user" ]
|
||||||
|
[ "$name" = "repo" ]
|
||||||
|
[ "$branch" = "develop" ]
|
||||||
|
[ "$dirname" = "my-custom-dir" ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "parsing should handle complex URLs with ports, custom dirs, and branches" {
|
||||||
|
cd "$TEST_DIR"
|
||||||
|
source "$TEST_DIR/apps/installer/includes/includes.sh"
|
||||||
|
|
||||||
|
# Test comprehensive URL with port, custom directory, branch, and commit
|
||||||
|
run inst_parse_module_spec "https://gitlab.example.com:9443/myorg/myrepo.git:custom-name@feature-branch:abc123def"
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
IFS=' ' read -r repo_ref owner name branch commit url dirname <<< "$output"
|
||||||
|
[ "$repo_ref" = "https://gitlab.example.com:9443/myorg/myrepo.git" ]
|
||||||
|
[ "$owner" = "myorg" ]
|
||||||
|
[ "$name" = "myrepo" ]
|
||||||
|
[ "$branch" = "feature-branch" ]
|
||||||
|
[ "$commit" = "abc123def" ]
|
||||||
|
[ "$url" = "https://gitlab.example.com:9443/myorg/myrepo.git" ]
|
||||||
|
[ "$dirname" = "custom-name" ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "URL port parsing regression test - ensure ports are not confused with directory names" {
|
||||||
|
cd "$TEST_DIR"
|
||||||
|
source "$TEST_DIR/apps/installer/includes/includes.sh"
|
||||||
|
|
||||||
|
# These are the problematic cases that the fix addresses
|
||||||
|
local test_cases=(
|
||||||
|
"https://example.com:8080/repo.git"
|
||||||
|
"https://gitlab.internal:9443/group/project.git"
|
||||||
|
"ssh://git@server.com:2222/owner/repo"
|
||||||
|
"https://git.company.com:8443/team/module.git"
|
||||||
|
)
|
||||||
|
|
||||||
|
for spec in "${test_cases[@]}"; do
|
||||||
|
run inst_parse_module_spec "$spec"
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
IFS=' ' read -r repo_ref owner name branch commit url dirname <<< "$output"
|
||||||
|
|
||||||
|
# Critical: dirname should NEVER be a port number
|
||||||
|
[[ ! "$dirname" =~ ^[0-9]+$ ]] || {
|
||||||
|
echo "FAIL: Port number '$dirname' incorrectly parsed as directory name for spec: $spec"
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# dirname should be the repository name by default
|
||||||
|
local expected_name
|
||||||
|
if [[ "$spec" =~ /([^/]+)(\.git)?$ ]]; then
|
||||||
|
expected_name="${BASH_REMATCH[1]}"
|
||||||
|
expected_name="${expected_name%.git}"
|
||||||
|
fi
|
||||||
|
[ "$dirname" = "$expected_name" ] || {
|
||||||
|
echo "FAIL: Expected dirname '$expected_name' but got '$dirname' for spec: $spec"
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "parsing should handle URL with custom directory but no branch" {
|
||||||
|
cd "$TEST_DIR"
|
||||||
|
source "$TEST_DIR/apps/installer/includes/includes.sh"
|
||||||
|
|
||||||
|
run inst_parse_module_spec "https://github.com/owner/repo.git:my-dir"
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
IFS=' ' read -r repo_ref owner name branch commit url dirname <<< "$output"
|
||||||
|
[ "$repo_ref" = "https://github.com/owner/repo.git" ]
|
||||||
|
[ "$dirname" = "my-dir" ]
|
||||||
|
[ "$branch" = "-" ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "modules list should maintain alphabetical order" {
|
||||||
|
cd "$TEST_DIR"
|
||||||
|
source "$TEST_DIR/apps/installer/includes/includes.sh"
|
||||||
|
|
||||||
|
# Add modules in random order
|
||||||
|
inst_mod_list_upsert "zeta/mod-z" "master" "abc"
|
||||||
|
inst_mod_list_upsert "alpha/mod-a" "master" "def"
|
||||||
|
inst_mod_list_upsert "beta/mod-b" "master" "ghi"
|
||||||
|
|
||||||
|
# Read the list and verify alphabetical order
|
||||||
|
local entries=()
|
||||||
|
while read -r repo_ref branch commit; do
|
||||||
|
[[ -z "$repo_ref" ]] && continue
|
||||||
|
entries+=("$repo_ref")
|
||||||
|
done < <(inst_mod_list_read)
|
||||||
|
|
||||||
|
# Should be in alphabetical order by owner/name
|
||||||
|
[ "${entries[0]}" = "alpha/mod-a" ]
|
||||||
|
[ "${entries[1]}" = "beta/mod-b" ]
|
||||||
|
[ "${entries[2]}" = "zeta/mod-z" ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "module dispatcher should handle unknown commands gracefully" {
|
||||||
|
cd "$TEST_DIR"
|
||||||
|
source "$TEST_DIR/apps/installer/includes/includes.sh"
|
||||||
|
|
||||||
|
run inst_module "unknown-command"
|
||||||
|
[ "$status" -eq 1 ]
|
||||||
|
[[ "$output" =~ "Unknown module command" ]]
|
||||||
|
}
|
||||||
10
conf/dist/config.sh
vendored
10
conf/dist/config.sh
vendored
@@ -162,4 +162,14 @@ export CPUPROFILESIGNAL=${CPUPROFILESIGNAL:-12}
|
|||||||
# Lines starting with '#' and empty lines are ignored.
|
# Lines starting with '#' and empty lines are ignored.
|
||||||
export MODULES_LIST_FILE=${MODULES_LIST_FILE:-"$AC_PATH_ROOT/conf/modules.list"}
|
export MODULES_LIST_FILE=${MODULES_LIST_FILE:-"$AC_PATH_ROOT/conf/modules.list"}
|
||||||
|
|
||||||
|
# Space/newline separated list of modules to exclude when using
|
||||||
|
# 'module install --all' and 'module update --all'. Items can be specified
|
||||||
|
# as simple names (e.g., mod-transmog), owner/name, or full URLs.
|
||||||
|
# Example:
|
||||||
|
# export MODULES_EXCLUDE_LIST="azerothcore/mod-transmog azerothcore/mod-autobalance"
|
||||||
|
export MODULES_EXCLUDE_LIST=""
|
||||||
|
|
||||||
|
NO_COLOR=${NO_COLOR:-}
|
||||||
|
FORCE_COLOR=${FORCE_COLOR:-}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user