Helper System - jvPalma/dotrun GitHub Wiki
- Introduction
- The Namespace Problem
- Core Location and Integration
- Basic Usage
- 5-Level Specificity Matching
- Pattern Examples
- Special Features
- Environment Modes
- Security Features
- Collection Author Guidelines
- Best Practices
- Troubleshooting
- See Also
The loadHelpers system is DotRun's flexible, pattern-based helper loading mechanism introduced in v3.0.0 and enhanced in v3.1.0. It enables collection scripts to load shared helper modules without relying on hardcoded paths, solving the critical problem of dynamic namespace prefixes in imported collections.
The loadHelpers system provides:
- Pattern-based loading: Load helpers using flexible patterns instead of exact paths
- Collection independence: Scripts work regardless of namespace prefix changes
-
Dual-mode support: Works both via
dr scriptnameand directbash script.shexecution - Smart matching: 5-level specificity hierarchy finds the right helper automatically
- Security: Path traversal prevention, circular dependency detection, and de-duplication
-
Pattern Matching: Instead of exact paths, use patterns like
gcp/workstationor@dotrun-anc - Specificity Hierarchy: More specific patterns take precedence (absolute path > exact path > filename search)
-
Collection Namespacing: Collections install to numbered directories (e.g.,
01-dotrun-anc/) but scripts don't need to know the prefix -
Transparent Integration: Helper loading works seamlessly in both
drcommand execution and direct script execution
Collection scripts traditionally used static imports:
source "$DR_CONFIG/helpers/gcp/workstation.sh"But collections import to namespace directories with numeric prefixes:
~/.config/dotrun/helpers/01-dotrun-anc/gcp/workstation.sh
The numeric prefix (01-) controls load order and can be changed by users, breaking static import paths.
The loadHelpers function provides flexible, pattern-based helper loading that works regardless of namespace prefixes:
loadHelpers gcp/workstation # Finds helper in ANY collection namespaceThe system automatically searches across all collection directories, matching patterns intelligently while respecting a 5-level specificity hierarchy.
The loadHelpers system is implemented in:
~/.local/share/dotrun/helpers/loadHelpers.sh
The loadHelpers function integrates at three levels:
~/.drrc exports the DR_LOAD_HELPERS environment variable and sources the function for interactive shells:
# In ~/.drrc
export DR_LOAD_HELPERS="$HOME/.local/share/dotrun/helpers/loadHelpers.sh"
source "$DR_LOAD_HELPERS"The dr binary exports DR_LOAD_HELPERS before running scripts, ensuring all executed scripts have access:
# In dr binary (simplified)
export DR_LOAD_HELPERS="$SHARE_DIR/helpers/loadHelpers.sh"
bash "$script_path" "$@"Scripts work both via:
-
DotRun execution:
dr myscript(environment pre-configured) -
Direct execution:
bash ~/.config/dotrun/scripts/myscript.sh(sources function viaDR_LOAD_HELPERS)
All collection scripts should follow this pattern:
#!/usr/bin/env bash
### DOC
# myscript - Example collection script
### DOC
set -euo pipefail
# Load the loadHelpers function (works in both dr and direct execution)
[[ -n "${DR_LOAD_HELPERS:-}" ]] && source "$DR_LOAD_HELPERS"
# Load required helpers using flexible patterns
loadHelpers gcp/workstation # Load from any collection
loadHelpers dotrun-anc/utils/common # Specify collection name
loadHelpers @dotrun-anc # Load all helpers from collection
main() {
# Use functions from loaded helpers
echo "Script using helpers..."
}
main "$@"-
Function Sourcing:
[[ -n "${DR_LOAD_HELPERS:-}" ]] && source "$DR_LOAD_HELPERS"- Checks if environment variable is set
- Sources the loadHelpers function definition
- Safe for both execution modes
-
Helper Loading:
loadHelpers pattern- Use flexible patterns (see 5-Level Specificity)
- Load at script top, before main logic
- Multiple patterns for multiple helpers
-
Helper Usage: Call functions defined in loaded helpers
- Helpers export functions and variables
- Available throughout script after loading
The loadHelpers system uses a 5-level specificity hierarchy to resolve patterns, from most specific to least specific. More specific patterns always take precedence.
Pattern: /full/path/to/helper.sh
Behavior: Exact file path, no search performed.
Use Case: Loading helpers outside DotRun's helper directory (advanced use).
Example:
loadHelpers /opt/custom/helpers/special.shResult: Loads the exact file /opt/custom/helpers/special.sh if it exists.
Pattern: helpers/01-dotrun-anc/gcp/workstation.sh
Behavior: Exact relative path from $DR_CONFIG (usually ~/.config/dotrun).
Use Case: When you know the exact namespace prefix and want guaranteed match.
Example:
loadHelpers helpers/01-dotrun-anc/gcp/workstation.shResult: Loads ~/.config/dotrun/helpers/01-dotrun-anc/gcp/workstation.sh exactly.
Pattern: 01-dotrun-anc/gcp/workstation
Behavior: Auto-adds .sh extension and searches from $DR_CONFIG/helpers.
Use Case: Slightly cleaner syntax than Level 2 while maintaining specificity.
Example:
loadHelpers 01-dotrun-anc/gcp/workstationResult: Same as Level 2, but you omit the .sh extension.
Pattern: gcp/workstation or dotrun-anc/gcp/workstation
Behavior: Searches all collections, with collection name normalization.
Collection Name Normalization:
- Pattern
dotrun-ancmatches*-dotrun-ancdirectories - Example:
01-dotrun-anc,02-dotrun-anc, etc.
Search Patterns:
-
*/[0-9]*-collection/path.sh(numbered namespace directories) -
*/collection/path.sh(non-numbered directories)
Use Case: Standard usage in collection scripts (namespace-agnostic).
Examples:
# Path without collection name - searches all collections
loadHelpers gcp/workstation
# Path with collection name - searches specific collection(s)
loadHelpers dotrun-anc/gcp/workstationResult: Finds ~/.config/dotrun/helpers/01-dotrun-anc/gcp/workstation.sh regardless of numeric prefix.
Pattern: workstation
Behavior: Least specific - searches all helpers recursively by filename.
Use Case: Quick loading when filename is unique across all collections.
Warning: May load multiple files with the same name from different collections.
Example:
loadHelpers workstationResult: Searches entire ~/.config/dotrun/helpers/ tree for workstation.sh, may find multiple matches.
| Level | Pattern Example | Specificity | Guaranteed Unique? |
|---|---|---|---|
| 1 | /opt/custom/helpers/special.sh |
Absolute path | ✅ Yes |
| 2 | helpers/01-dotrun-anc/gcp/workstation.sh |
Exact relative | ✅ Yes |
| 3 | 01-dotrun-anc/gcp/workstation |
Exact + auto .sh | ✅ Yes |
| 4 | dotrun-anc/gcp/workstation |
Path search | |
| 4 | gcp/workstation |
Path search | |
| 5 | workstation |
Filename only | ❌ No |
Recommendation: Use Level 4 (path search with collection name) for collection scripts - it balances flexibility and specificity.
For a helper located at:
~/.config/dotrun/helpers/01-dotrun-anc/gcp/workstation.sh
All of these patterns will successfully load the same helper:
# Level 2: Exact path with namespace
loadHelpers helpers/01-dotrun-anc/gcp/workstation.sh
# Level 3: Exact without .sh extension
loadHelpers 01-dotrun-anc/gcp/workstation
# Level 4: Collection name normalized (preferred)
loadHelpers dotrun-anc/gcp/workstation
# Level 4: Path in any collection
loadHelpers gcp/workstation
# Level 5: Filename only (least specific)
loadHelpers workstationTo load multiple helpers in a script:
#!/usr/bin/env bash
set -euo pipefail
[[ -n "${DR_LOAD_HELPERS:-}" ]] && source "$DR_LOAD_HELPERS"
# Load helpers using different specificity levels
loadHelpers dotrun-anc/gcp/workstation # Level 4: Collection + path
loadHelpers utils/logging # Level 4: Path in any collection
loadHelpers @dotrun-anc # Special: All helpers from collection
main() {
# Functions from all loaded helpers now available
setup_gcp_workstation
log_info "Starting operation..."
}
main "$@"Load all helpers from a specific collection using the @collection syntax:
loadHelpers @dotrun-ancBehavior:
- Finds collection directory matching
*-dotrun-anc - Recursively loads all
.shfiles in that directory - Useful for collections with many interdependent helpers
Example Output:
Loading all helpers from collection: dotrun-anc
✓ Loaded: ~/.config/dotrun/helpers/01-dotrun-anc/gcp/workstation.sh
✓ Loaded: ~/.config/dotrun/helpers/01-dotrun-anc/utils/logging.sh
✓ Loaded: ~/.config/dotrun/helpers/01-dotrun-anc/utils/validation.sh
Loaded 3 helper(s) from collection dotrun-anc
Preview matches without actually loading helpers using the --list flag:
loadHelpers gcp/workstation --listExample Output:
Found 1 helper(s) matching 'gcp/workstation' (level: path):
/home/user/.config/dotrun/helpers/01-dotrun-anc/gcp/workstation.sh
Use Cases:
- Verify pattern matches expected helper
- Debug pattern specificity issues
- Discover available helpers during development
- Preview collection scope loading
List Mode with Collection Scope:
loadHelpers @dotrun-anc --list
# Output:
# Found 3 helper(s) in collection 'dotrun-anc':
# /home/user/.config/dotrun/helpers/01-dotrun-anc/gcp/workstation.sh
# /home/user/.config/dotrun/helpers/01-dotrun-anc/utils/logging.sh
# /home/user/.config/dotrun/helpers/01-dotrun-anc/utils/validation.shLess specific patterns (Level 5) may match multiple helpers with the same filename:
loadHelpers utilsBehavior:
- Searches all collections for
utils.sh - Loads all matches if multiple found
- Displays warning with list of matches
Example Output:
Warning: Multiple helpers matched 'utils' (level: filename)
- /home/user/.config/dotrun/helpers/01-dotrun-anc/utils.sh
- /home/user/.config/dotrun/helpers/02-myteam/utils.sh
Loading all matches...
When This Is Useful:
- Intentionally loading helpers with same name from different collections
- Collecting utilities from multiple sources
When to Avoid:
- Use more specific pattern if you need only one helper
- Example:
loadHelpers dotrun-anc/utilsinstead ofloadHelpers utils
Control loadHelpers output verbosity using environment variables.
Variable: DR_HELPERS_VERBOSE=1
Effect: Enable detailed output showing the search process.
Example:
DR_HELPERS_VERBOSE=1 loadHelpers gcp/workstationOutput:
[DEBUG] Searching for helper: gcp/workstation
[DEBUG] Trying level 4 (path search)
[DEBUG] Search pattern: */gcp/workstation.sh
[DEBUG] Found match: /home/user/.config/dotrun/helpers/01-dotrun-anc/gcp/workstation.sh
[DEBUG] Validating canonical path...
[DEBUG] Loading helper: /home/user/.config/dotrun/helpers/01-dotrun-anc/gcp/workstation.sh
✓ Loaded: gcp/workstation (level: path)
Use Cases:
- Debugging pattern matching issues
- Understanding search behavior
- Troubleshooting failed loads
Variable: DR_HELPERS_QUIET=1
Effect: Suppress all output except errors.
Example:
DR_HELPERS_QUIET=1 loadHelpers gcp/workstationOutput: (none, unless error occurs)
Use Cases:
- Production scripts where output clutters logs
- Automated workflows
- Scripts that load many helpers
You can combine environment variables with other features:
# Verbose list mode
DR_HELPERS_VERBOSE=1 loadHelpers gcp/workstation --list
# Quiet collection scope loading
DR_HELPERS_QUIET=1 loadHelpers @dotrun-ancThe loadHelpers system implements three critical security mechanisms to prevent malicious or accidental misuse.
Protection: All resolved helper paths are validated to ensure they exist within $DR_CONFIG/helpers.
Implementation:
# Security check using canonical paths
allowed_base="$(readlink -f "$DR_CONFIG/helpers")"
canonical_path="$(readlink -f "$helper")"
if [[ "$canonical_path" != "$allowed_base"* ]]; then
echo "Error: Helper outside allowed directory: $helper" >&2
return 1
fiWhat This Prevents:
- Path traversal attacks:
loadHelpers ../../../../etc/passwd - Symlinks pointing outside helper directory
- Absolute paths to sensitive system files
Example Error:
loadHelpers /etc/passwd
# Output:
# Error: Helper outside allowed directory: /etc/passwd
# Allowed directory: /home/user/.config/dotrun/helpersProtection: Maximum loading depth of 10 prevents infinite recursion when helpers load each other.
Implementation:
# Global counter and limit
declare -gri _DR_LOAD_DEPTH_MAX=10
declare -gi _DR_LOAD_DEPTH=0
# Check before loading
((_DR_LOAD_DEPTH++))
if [[ $_DR_LOAD_DEPTH -gt $_DR_LOAD_DEPTH_MAX ]]; then
echo "Error: Maximum helper loading depth exceeded" >&2
echo "Possible circular dependency detected" >&2
return 1
fi
# Decrement after loading
source "$helper"
((_DR_LOAD_DEPTH--))What This Prevents:
- Circular dependencies: Helper A loads Helper B, Helper B loads Helper A
- Deep chains: Helper A → B → C → D → E → F → G → H → I → J → K (exceeds limit)
- Stack overflow: Infinite recursion crashing the shell
Example Scenario:
# In helpers/01-dotrun-anc/utils/a.sh
loadHelpers utils/b
# In helpers/01-dotrun-anc/utils/b.sh
loadHelpers utils/a # Circular dependency!
# Loading either helper triggers:
# Error: Maximum helper loading depth exceeded
# Possible circular dependency detectedDepth Limit Rationale:
- 10 levels allows complex helper chains
- Prevents runaway recursion
- Constant
_DR_LOAD_DEPTH_MAXcan be adjusted if needed (requires modifyingloadHelpers.sh)
Protection: Tracks loaded helpers by canonical path to prevent re-sourcing the same file.
Implementation:
# Global associative array tracking loaded helpers
declare -gA _DR_LOADED_HELPERS
# Check if already loaded
canonical_path="$(readlink -f "$helper")"
if [[ -n "${_DR_LOADED_HELPERS[$canonical_path]:-}" ]]; then
[[ -z "${DR_HELPERS_QUIET:-}" ]] && echo "Skipping (already loaded): $helper" >&2
return 0
fi
# Source the helper
source "$helper"
# Mark as loaded
_DR_LOADED_HELPERS["$canonical_path"]=1What This Prevents:
- Redundant sourcing: Loading same helper multiple times wastes time
- Variable redefinition: Helpers re-defining functions/variables unnecessarily
- Side effects: Helpers with side effects executing multiple times
Example Scenario:
# Script loads same helper via different patterns
loadHelpers dotrun-anc/utils/logging # Loaded
loadHelpers utils/logging # Skipped (already loaded)
loadHelpers 01-dotrun-anc/utils/logging # Skipped (already loaded)
# Output:
# ✓ Loaded: dotrun-anc/utils/logging
# Skipping (already loaded): utils/logging
# Skipping (already loaded): 01-dotrun-anc/utils/loggingCanonical Path Resolution:
-
readlink -fresolves symlinks and relative paths to absolute paths - Same file loaded via different patterns resolves to same canonical path
- Associative array key is canonical path, ensuring true uniqueness
- Never load untrusted helpers: Only load helpers from known collections or your own scripts
-
Validate collection sources: Use
dr -col listto review installed collections - Audit helper contents: Review helper files before loading (especially from new collections)
- Use specific patterns: Avoid Level 5 (filename-only) which may match unexpected files
- Monitor depth warnings: If you hit the depth limit, review helper dependencies
What loadHelpers Does NOT Protect Against:
- Malicious helper code: If a helper contains malicious commands, they will execute
- Collection supply-chain attacks: Compromised collection repositories
-
User error: Loading wrong helper due to typo (use
--listto verify)
Recommendation: Treat helper loading like sourcing any shell script - only load trusted code.
If you're creating a collection that other users will import, follow these guidelines to ensure your scripts work reliably with the loadHelpers system.
#!/usr/bin/env bash
### DOC
# myscript - Brief description of what this script does
#
# Usage:
# dr myscript [options] [arguments]
#
# Options:
# -h, --help Show this help message
#
# Examples:
# dr myscript --example
### DOC
set -euo pipefail
# Load the loadHelpers function (works in both dr and direct execution)
[[ -n "${DR_LOAD_HELPERS:-}" ]] && source "$DR_LOAD_HELPERS"
# Load required helpers using flexible patterns
loadHelpers gcp/workstation # Works regardless of namespace prefix
loadHelpers utils/common # Another helper
loadHelpers @dotrun-anc # Or load all from collection at once
# Script functions
show_help() {
sed -n '/^### DOC$/,/^### DOC$/p' "$0" | sed '1d;$d' | sed 's/^# //; s/^#//'
}
main() {
# Parse arguments
if [[ "${1:-}" == "-h" ]] || [[ "${1:-}" == "--help" ]]; then
show_help
exit 0
fi
# Use functions from loaded helpers
echo "Script using helpers..."
# Your script logic here
}
main "$@"#!/usr/bin/env bash
### DOC
# Your documentation here
### DOC-
Shebang: Always use
#!/usr/bin/env bashfor portability -
DOC block: DotRun's documentation system (shown by
dr help scriptname) - Include usage, options, and examples
set -euo pipefail-
set -e: Exit on error -
set -u: Error on undefined variables -
set -o pipefail: Pipelines fail if any command fails
[[ -n "${DR_LOAD_HELPERS:-}" ]] && source "$DR_LOAD_HELPERS"-
Critical: This line must appear before any
loadHelperscalls - Checks if
DR_LOAD_HELPERSenvironment variable is set - Sources the function definition if available
- Safe for both
drexecution and directbash script.shexecution
loadHelpers gcp/workstation
loadHelpers utils/common- Load all dependencies before defining script functions
- Use Level 4 patterns (path with collection name) for reliability
- Group related helper loads together
main() {
# Your script logic
}
main "$@"- Encapsulate logic in
main()function - Pass all arguments:
main "$@" - Allows easier testing and helper function organization
Structure your collection's helpers directory logically:
my-collection/
├── dotrun.collection.yml
├── scripts/
│ ├── deploy.sh # Uses helpers below
│ └── monitor.sh
└── helpers/
├── gcp/
│ ├── auth.sh # GCP authentication utilities
│ └── workstation.sh # GCP Workstation management
├── kubernetes/
│ ├── context.sh # K8s context switching
│ └── deploy.sh # K8s deployment helpers
└── utils/
├── logging.sh # Logging utilities
└── validation.sh # Input validation helpers
Benefits:
- Logical categorization by domain (gcp, kubernetes, utils)
- Easier discovery for users
- Predictable patterns for loading (
gcp/auth,kubernetes/context)
loadHelpers my-collection/gcp/auth
loadHelpers my-collection/utils/loggingPros:
- Explicit about source collection
- Avoids conflicts with other collections
- Works regardless of namespace prefix
Cons:
- Slightly more verbose than path-only pattern
loadHelpers gcp/auth
loadHelpers utils/loggingPros:
- Cleaner, shorter syntax
- Works if helper path is unique across collections
Cons:
- May load wrong helper if multiple collections have same path
- Less explicit about dependencies
When to Use: Your collection has unique helper paths unlikely to conflict.
loadHelpers @my-collectionPros:
- Loads all helpers from collection at once
- Simplifies scripts with many helper dependencies
Cons:
- Loads helpers that may not be needed
- Slower for scripts needing only specific helpers
- Less clear what dependencies script actually uses
When to Use: Scripts need most/all helpers from the collection.
Before publishing your collection, test scripts with different namespace prefixes:
# Install collection with different prefixes
dr -col add https://github.com/you/my-collection # May install as 01-my-collection
# Manually rename namespace directory
cd ~/.config/dotrun/helpers
mv 01-my-collection 05-my-collection
# Test scripts still work
dr myscript # Should load helpers correctly despite prefix changeWhat to Verify:
- All
loadHelperscalls succeed - Script functions work as expected
- No hardcoded paths break due to namespace change
In your collection's README.md, document helper dependencies:
## Helper Dependencies
Scripts in this collection use the following helpers:
- `gcp/auth.sh` - GCP authentication utilities
- `gcp/workstation.sh` - GCP Workstation management
- `utils/logging.sh` - Logging utilities
These helpers are automatically loaded when scripts are executed via `dr scriptname`.Why This Matters:
- Users understand what helpers do
- Easier debugging if helper loading fails
- Clear documentation of collection structure
# BAD: Hardcoded absolute path breaks on other systems
source /home/you/.config/dotrun/helpers/01-my-collection/gcp/auth.shWhy: Breaks on other users' systems, defeats purpose of loadHelpers.
# BAD: Assumes namespace prefix never changes
source "$DR_CONFIG/helpers/01-my-collection/gcp/auth.sh"Why: Breaks if user changes namespace prefix (e.g., 01- → 05-).
# GOOD: Works regardless of namespace prefix
loadHelpers my-collection/gcp/authWhy: Flexible, robust, namespace-agnostic.
When writing helpers for your collection:
-
Export Functions: Use
function_name() { ... }orexport -f function_name - Avoid Global Side Effects: Don't execute code at helper source time
- Document Functions: Use comments to describe what functions do
-
Namespace Functions: Prefix with collection name to avoid conflicts (e.g.,
myteam_deploy()) - Handle Dependencies: If helper depends on another helper, load it inside the helper
Example Helper (helpers/gcp/auth.sh):
#!/usr/bin/env bash
# GCP authentication utilities
# myteam_gcp_login - Authenticate to GCP project
# Usage: myteam_gcp_login [project-id]
myteam_gcp_login() {
local project="${1:-default-project}"
echo "Authenticating to GCP project: $project"
gcloud auth login --project="$project"
}
# myteam_gcp_set_project - Set active GCP project
# Usage: myteam_gcp_set_project <project-id>
myteam_gcp_set_project() {
local project="$1"
[[ -z "$project" ]] && {
echo "Error: Project ID required" >&2
return 1
}
gcloud config set project "$project"
}
# Export functions for use in scripts
export -f myteam_gcp_login myteam_gcp_set_projectWhy These Practices Matter:
- Exported functions: Available in scripts that load the helper
- No side effects: Helper can be sourced without unexpected behavior
- Documentation: Users understand function purpose
- Namespacing: Prevents conflicts with other collections' functions
- Dependency handling: Helpers can load other helpers if needed
Follow these practices to use the loadHelpers system effectively and avoid common pitfalls.
Rule: More specific patterns guarantee unique matches and prevent surprises.
✅ Good:
loadHelpers dotrun-anc/gcp/workstation # Level 4: Collection + pathloadHelpers workstation # Level 5: Filename only - may match multiple filesWhy: Filename-only patterns may load helpers from unexpected collections if multiple collections have helpers with the same name.
Rule: Include collection name in pattern for clarity and reliability.
✅ Good:
loadHelpers dotrun-anc/utils/common # Explicit about source collectionloadHelpers utils/common # Works, but may match wrong collectionWhy: Including collection name makes dependencies explicit and prevents loading helpers from unintended collections.
Rule: Preview pattern matches during development before loading.
Example:
loadHelpers gcp/workstation --list
# Output:
# Found 1 helper(s) matching 'gcp/workstation' (level: path):
# /home/user/.config/dotrun/helpers/01-dotrun-anc/gcp/workstation.shWhy: Verifies pattern matches expected helper, catches typos early, prevents unexpected multiple matches.
When to Use:
- Developing new scripts with helper dependencies
- Debugging failed helper loads
- Verifying pattern specificity before committing code
Rule: Source loadHelpers function and load dependencies before defining main logic.
✅ Good Structure:
#!/usr/bin/env bash
set -euo pipefail
# 1. Source loadHelpers function
[[ -n "${DR_LOAD_HELPERS:-}" ]] && source "$DR_LOAD_HELPERS"
# 2. Load all dependencies
loadHelpers dotrun-anc/gcp/workstation
loadHelpers utils/logging
# 3. Define script functions
main() {
# Use helper functions
}
# 4. Execute main
main "$@"❌ Bad Structure:
#!/usr/bin/env bash
set -euo pipefail
main() {
# Loading helpers inside main function
[[ -n "${DR_LOAD_HELPERS:-}" ]] && source "$DR_LOAD_HELPERS"
loadHelpers dotrun-anc/gcp/workstation # Too late if main uses helpers
}
main "$@"Why: Loading at top ensures dependencies are available throughout script, makes dependencies visible upfront, follows shell scripting conventions.
Rule: Organize helper loads logically by category or purpose.
✅ Good:
# GCP helpers
loadHelpers dotrun-anc/gcp/auth
loadHelpers dotrun-anc/gcp/workstation
# Kubernetes helpers
loadHelpers dotrun-anc/kubernetes/context
loadHelpers dotrun-anc/kubernetes/deploy
# Utility helpers
loadHelpers dotrun-anc/utils/logging
loadHelpers dotrun-anc/utils/validation❌ Unorganized:
loadHelpers dotrun-anc/gcp/auth
loadHelpers dotrun-anc/utils/logging
loadHelpers dotrun-anc/kubernetes/context
loadHelpers dotrun-anc/gcp/workstation
loadHelpers dotrun-anc/utils/validation
loadHelpers dotrun-anc/kubernetes/deployWhy: Improves readability, makes dependencies easier to understand, simplifies maintenance.
Rule: Add comments explaining what each helper provides.
✅ Good:
# Load GCP authentication utilities (gcp_login, gcp_set_project)
loadHelpers dotrun-anc/gcp/auth
# Load Kubernetes context management (k8s_switch_context, k8s_get_current)
loadHelpers dotrun-anc/kubernetes/context
# Load logging utilities (log_info, log_error, log_debug)
loadHelpers dotrun-anc/utils/loggingWhy: Clarifies what functions each helper provides, helps other developers understand dependencies, simplifies debugging.
Rule: Use loadHelpers @collection sparingly - prefer explicit helper loads.
loadHelpers @dotrun-anc # Loads ALL helpers - may be slow✅ Prefer Explicit:
loadHelpers dotrun-anc/gcp/auth
loadHelpers dotrun-anc/utils/logging
# Only load what you needWhy: Collection scope loads all helpers (slow for large collections), makes actual dependencies unclear, may load helpers with side effects.
When Collection Scope Is Appropriate:
- Script genuinely needs most/all helpers from collection
- Development/debugging (temporary usage)
- Collection has few helpers (< 5)
Rule: Check if critical helpers loaded successfully.
✅ Good:
if ! loadHelpers dotrun-anc/gcp/auth 2>/dev/null; then
echo "Error: Required helper not found: dotrun-anc/gcp/auth" >&2
echo "Install the dotrun-anc collection: dr -col add <url>" >&2
exit 1
fiWhy: Provides clear error message to user, explains how to fix (install collection), prevents cryptic errors later when helper function is called.
Rule: Suppress helper loading output in scripts running in production/automation.
✅ Production Script:
#!/usr/bin/env bash
set -euo pipefail
# Quiet mode for cleaner logs
export DR_HELPERS_QUIET=1
[[ -n "${DR_LOAD_HELPERS:-}" ]] && source "$DR_LOAD_HELPERS"
loadHelpers dotrun-anc/gcp/auth
loadHelpers dotrun-anc/utils/logging
# Script logicWhy: Reduces log clutter, keeps output focused on script actions, errors still shown (quiet only suppresses success messages).
Rule: Understand which specificity level your pattern uses.
Use --list to Check:
loadHelpers gcp/workstation --list
# Output shows specificity level:
# Found 1 helper(s) matching 'gcp/workstation' (level: path)Level Priority:
- Level 1-3: Guaranteed unique match
-
Level 4: Usually unique, but verify with
--list - Level 5: Often matches multiple files - avoid unless intentional
| Scenario | Recommended Pattern | Specificity Level |
|---|---|---|
| Collection script loading own helper | collection/path/helper |
Level 4 |
| Script loading from specific collection | collection/path/helper |
Level 4 |
| Loading unique helper (any collection) | path/helper |
Level 4 |
| Loading all helpers from collection | @collection |
Special |
| Debugging/development | path/helper --list |
Level 4 + list |
| Loading external helper | /absolute/path.sh |
Level 1 |
| Avoid (too broad) | helper |
Level 5 ❌ |
Common errors and how to resolve them.
Symptom:
loadHelpers gcp/workstation
# Output:
# Error: No helpers found matching 'gcp/workstation'Possible Causes:
- Helper doesn't exist: The helper file isn't in any collection's helpers directory
- Wrong pattern: Pattern doesn't match actual file path
- Collection not installed: Collection containing helper not imported yet
- Typo in pattern: Pattern has spelling or path error
Solutions:
loadHelpers gcp/workstation --list
# If nothing found, try broader pattern:
loadHelpers workstation --list
# Or search for similar patterns:
find ~/.config/dotrun/helpers -name "*workstation*"# List all helper files
ls -R ~/.config/dotrun/helpers/
# Search for specific helper
find ~/.config/dotrun/helpers -name "workstation.sh"# List installed collections
dr -col list
# If collection missing, install it:
dr -col add https://github.com/user/collection-repoDR_HELPERS_VERBOSE=1 loadHelpers gcp/workstation
# Shows detailed search process:
# [DEBUG] Searching for helper: gcp/workstation
# [DEBUG] Trying level 4 (path search)
# [DEBUG] Search pattern: */gcp/workstation.sh
# [DEBUG] No matches foundSymptom:
loadHelpers utils/a
# Output:
# Error: Maximum helper loading depth exceeded
# Possible circular dependency detectedCause: Circular dependency between helpers (Helper A loads Helper B, Helper B loads Helper A).
Example Scenario:
File: ~/.config/dotrun/helpers/01-myteam/utils/a.sh
loadHelpers utils/b # Loads helper BFile: ~/.config/dotrun/helpers/01-myteam/utils/b.sh
loadHelpers utils/a # Loads helper A - CIRCULAR!Solutions:
Identify which helpers load each other:
# Search for loadHelpers calls in all helpers
grep -r "loadHelpers" ~/.config/dotrun/helpers/Option A: Extract shared logic to third helper
Before (circular):
# utils/a.sh
loadHelpers utils/b
do_a_thing() { do_b_thing; }
# utils/b.sh
loadHelpers utils/a
do_b_thing() { do_a_thing; }After (refactored):
# utils/common.sh (new)
shared_function() { ... }
# utils/a.sh
loadHelpers utils/common
do_a_thing() { shared_function; }
# utils/b.sh
loadHelpers utils/common
do_b_thing() { shared_function; }Option B: Merge helpers if closely related
If helpers are tightly coupled, combine into single helper.
If legitimate deep helper chain (rare), edit loadHelpers.sh:
# In ~/.local/share/dotrun/helpers/loadHelpers.sh
declare -gri _DR_LOAD_DEPTH_MAX=20 # Increase from 10 to 20Warning: Only increase if you're certain there's no circular dependency. Deep chains often indicate poor helper design.
Symptom:
loadHelpers utils
# Output:
# Warning: Multiple helpers matched 'utils' (level: filename)
# - /home/user/.config/dotrun/helpers/01-dotrun-anc/utils.sh
# - /home/user/.config/dotrun/helpers/02-myteam/utils.sh
# Loading all matches...Cause: Pattern is too broad (Level 5 - filename only) and multiple collections have helpers with the same name.
Impact:
- All matching helpers are loaded
- May load unintended helper from different collection
- Functions may be redefined if helpers export same function names
Solutions:
Instead of:
loadHelpers utils # Too broad - matches multiple filesUse:
loadHelpers dotrun-anc/utils # Specific to collectionOr even more specific:
loadHelpers dotrun-anc/utils/logging # Exact path# List all matches
loadHelpers utils --list
# Output shows all matches:
# Found 2 helper(s) matching 'utils' (level: filename):
# /home/user/.config/dotrun/helpers/01-dotrun-anc/utils.sh
# /home/user/.config/dotrun/helpers/02-myteam/utils.sh
# Review each helper to determine which you need
cat ~/.config/dotrun/helpers/01-dotrun-anc/utils.sh
cat ~/.config/dotrun/helpers/02-myteam/utils.shIf you genuinely need helpers from multiple collections:
# Load all helpers named "utils" from all collections
loadHelpers utils
# Or be explicit:
loadHelpers dotrun-anc/utils
loadHelpers myteam/utilsWhen This Is Appropriate:
- Helpers provide different, non-conflicting functions
- You intentionally want utilities from multiple collections
Symptom:
loadHelpers /etc/passwd
# Output:
# Error: Helper outside allowed directory: /etc/passwd
# Allowed directory: /home/user/.config/dotrun/helpersCause: Security violation - attempted to load file outside $DR_CONFIG/helpers directory.
Possible Triggers:
- Absolute path to sensitive file: Attempting to load system files
- Symlink to external file: Helper is symlink pointing outside allowed directory
-
Path traversal attempt: Using
../to escape helpers directory -
Incorrect DR_CONFIG:
DR_CONFIGenvironment variable misconfigured
Solutions:
Ensure helper path is within ~/.config/dotrun/helpers/:
# Check allowed directory
echo "$DR_CONFIG/helpers"
# Output: /home/user/.config/dotrun/helpers
# Verify helper exists in allowed directory
ls "$DR_CONFIG/helpers/01-dotrun-anc/gcp/workstation.sh"# Check if helper is a symlink
ls -l ~/.config/dotrun/helpers/01-dotrun-anc/gcp/workstation.sh
# If symlink, verify target is within allowed directory:
readlink -f ~/.config/dotrun/helpers/01-dotrun-anc/gcp/workstation.shIf symlink points outside ~/.config/dotrun/helpers/, either:
- Copy the actual file instead of symlinking
- Move target file into helpers directory
# Check DR_CONFIG environment variable
echo "$DR_CONFIG"
# Should output: /home/user/.config/dotrun
# If wrong or empty, source ~/.drrc:
source ~/.drrcIf trying to load external helper for legitimate reason, copy it into helpers directory:
# Instead of:
loadHelpers /opt/custom/helper.sh # Error: outside allowed directory
# Copy to helpers first:
cp /opt/custom/helper.sh ~/.config/dotrun/helpers/custom-helper.sh
loadHelpers custom-helper # Now worksGeneral Debugging Steps:
-
Enable Verbose Mode:
DR_HELPERS_VERBOSE=1 loadHelpers pattern
-
Use List Mode:
loadHelpers pattern --list
-
Check Environment:
echo "$DR_CONFIG" # Should be ~/.config/dotrun echo "$DR_LOAD_HELPERS" # Should be ~/.local/share/dotrun/helpers/loadHelpers.sh
-
Verify Helper Exists:
find ~/.config/dotrun/helpers -name "helper.sh"
-
Check Helper Syntax:
bash -n ~/.config/dotrun/helpers/01-dotrun-anc/utils.sh # Check for syntax errors
-
Test Direct Source:
source ~/.config/dotrun/helpers/01-dotrun-anc/utils.sh # Test if helper sources cleanly
If issues persist after troubleshooting:
-
Check DotRun version:
dr --help # Shows version -
Review helper file for syntax errors or issues:
cat ~/.config/dotrun/helpers/01-dotrun-anc/gcp/workstation.sh -
Check collection metadata:
cat ~/.config/dotrun/collections/dotrun-anc/dotrun.collection.yml -
File an issue on the collection or DotRun repository with:
- Error message
- Pattern attempted
- Output of
DR_HELPERS_VERBOSE=1 loadHelpers pattern - Helper file path and permissions
- Collection Management (Advanced) - Using helpers from imported collections, collection-based workflows
- Architecture Overview - System architecture, helper system integration, file structure
- Developer Experience - Advanced workflows, helper development patterns, collection authoring
Related Topics:
- Collections System - Importing and managing collections
- Script Management - Creating and organizing scripts
- Configuration System - Global configuration variables
Quick Links: