...
This commit is contained in:
11
README.md
11
README.md
@@ -72,6 +72,17 @@ Herolib provides a wide range of functionality:
|
|||||||
|
|
||||||
- Cloud automation tools
|
- Cloud automation tools
|
||||||
- Git operations and management
|
- Git operations and management
|
||||||
|
### Offline Mode for Git Operations
|
||||||
|
|
||||||
|
Herolib now supports an `offline` mode for Git operations, which prevents automatic fetching from remote repositories. This can be useful in environments with limited or no internet connectivity, or when you want to avoid network calls during development or testing.
|
||||||
|
|
||||||
|
To enable offline mode:
|
||||||
|
|
||||||
|
- **Via `GitStructureConfig`**: Set the `offline` field to `true` in the `GitStructureConfig` struct.
|
||||||
|
- **Via `GitStructureArgsNew`**: When creating a new `GitStructure` instance using `gittools.new()`, set the `offline` parameter to `true`.
|
||||||
|
- **Via Environment Variable**: Set the `OFFLINE` environment variable to any value (e.g., `export OFFLINE=true`).
|
||||||
|
|
||||||
|
When offline mode is active, `git fetch --all` operations will be skipped, and a debug message "fetch skipped (offline)" will be printed.
|
||||||
- Documentation building
|
- Documentation building
|
||||||
- Hero AI integration
|
- Hero AI integration
|
||||||
- System management utilities
|
- System management utilities
|
||||||
|
|||||||
@@ -192,17 +192,17 @@ pub fn path_fix(path_ string) string {
|
|||||||
if starts_with_dot_slash {
|
if starts_with_dot_slash {
|
||||||
result_components << '.'
|
result_components << '.'
|
||||||
// Skip the first component which is '.'
|
// Skip the first component which is '.'
|
||||||
components = components[1..]
|
components = components[1..].clone()
|
||||||
} else if starts_with_dot_dot_slash {
|
} else if starts_with_dot_dot_slash {
|
||||||
result_components << '..'
|
result_components << '..'
|
||||||
// Skip the first component which is '..'
|
// Skip the first component which is '..'
|
||||||
components = components[1..]
|
components = components[1..].clone()
|
||||||
} else if is_absolute {
|
} else if is_absolute {
|
||||||
// Keep the empty component for absolute paths
|
// Keep the empty component for absolute paths
|
||||||
result_components << ''
|
result_components << ''
|
||||||
// Skip the first empty component
|
// Skip the first empty component
|
||||||
if components.len > 0 && components[0] == '' {
|
if components.len > 0 && components[0] == '' {
|
||||||
components = components[1..]
|
components = components[1..].clone()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ pub mut:
|
|||||||
ssh_key_name string // name of ssh key to be used when loading the gitstructure
|
ssh_key_name string // name of ssh key to be used when loading the gitstructure
|
||||||
ssh_key_path string
|
ssh_key_path string
|
||||||
reload bool
|
reload bool
|
||||||
|
offline bool = false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Retrieve or create a new GitStructure instance with the given configuration.
|
// Retrieve or create a new GitStructure instance with the given configuration.
|
||||||
@@ -37,6 +38,7 @@ pub fn new(args_ GitStructureArgsNew) !&GitStructure {
|
|||||||
debug: args.debug
|
debug: args.debug
|
||||||
ssh_key_name: args.ssh_key_name
|
ssh_key_name: args.ssh_key_name
|
||||||
ssh_key_path: args.ssh_key_path
|
ssh_key_path: args.ssh_key_path
|
||||||
|
offline: args.offline
|
||||||
}
|
}
|
||||||
|
|
||||||
return get(coderoot: args.coderoot, reload: args.reload, cfg: cfg)
|
return get(coderoot: args.coderoot, reload: args.reload, cfg: cfg)
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ pub mut:
|
|||||||
debug bool = true
|
debug bool = true
|
||||||
ssh_key_name string
|
ssh_key_name string
|
||||||
ssh_key_path string
|
ssh_key_path string
|
||||||
|
offline bool = false
|
||||||
}
|
}
|
||||||
|
|
||||||
// GitStructure holds information about repositories within a specific code root.
|
// GitStructure holds information about repositories within a specific code root.
|
||||||
@@ -53,13 +54,13 @@ pub fn (mut gitstructure GitStructure) load(reload bool) ! {
|
|||||||
redisclient.checkempty()
|
redisclient.checkempty()
|
||||||
|
|
||||||
for _, mut repo in gitstructure.repos {
|
for _, mut repo in gitstructure.repos {
|
||||||
// mut myfunction := fn (mut repo GitRepo) ! {
|
|
||||||
// }
|
|
||||||
// ths << spawn myfunction(mut repo_)
|
|
||||||
repo.status_update(reload: reload) or {
|
repo.status_update(reload: reload) or {
|
||||||
msg := 'Error in git repo: ${repo.path()}\n${err}'
|
// If status_update fails, the error is already captured within the repo object.
|
||||||
console.print_stderr(msg)
|
// We log it here and continue to process other repositories.
|
||||||
return error(msg)
|
console.print_stderr('Error updating status for repo ${repo.path()}: ${err}')
|
||||||
|
// Ensure last_load is reset to 0 if there was an error, so it's re-checked next time.
|
||||||
|
repo.last_load = 0
|
||||||
|
repo.cache_set()! // Persist the updated last_load and error state
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
module gittools
|
module gittools
|
||||||
|
|
||||||
import freeflowuniverse.herolib.core.redisclient
|
import freeflowuniverse.herolib.core.redisclient
|
||||||
|
import freeflowuniverse.herolib.ui.console
|
||||||
import time
|
import time
|
||||||
|
|
||||||
// ReposGetArgs defines arguments to retrieve repositories from the git structure.
|
// ReposGetArgs defines arguments to retrieve repositories from the git structure.
|
||||||
@@ -61,7 +62,13 @@ pub fn (mut gitstructure GitStructure) get_repos(args_ ReposGetArgs) ![]&GitRepo
|
|||||||
repo.cache_last_load_clear()!
|
repo.cache_last_load_clear()!
|
||||||
}
|
}
|
||||||
if args.status_update {
|
if args.status_update {
|
||||||
repo.status_update()!
|
repo.status_update() or {
|
||||||
|
// Log the error but continue processing other repositories
|
||||||
|
console.print_stderr('Error updating status for repo ${repo.path()}: ${err}')
|
||||||
|
// Ensure last_load is reset to 0 if there was an error, so it's re-checked next time.
|
||||||
|
repo.last_load = 0
|
||||||
|
repo.cache_set()! // Persist the updated last_load and error state
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if args.reset {
|
if args.reset {
|
||||||
repo.reset()!
|
repo.reset()!
|
||||||
|
|||||||
@@ -7,6 +7,21 @@ fn get_repo_status(gr GitRepo) !string {
|
|||||||
mut repo := gr
|
mut repo := gr
|
||||||
mut statuses := []string{}
|
mut statuses := []string{}
|
||||||
|
|
||||||
|
if repo.status_local.error.len > 0 {
|
||||||
|
mut err_msg := repo.status_local.error
|
||||||
|
if err_msg.len > 40 {
|
||||||
|
err_msg = err_msg[0..40] + '...'
|
||||||
|
}
|
||||||
|
statuses << 'ERROR (Local): ${err_msg}'
|
||||||
|
}
|
||||||
|
if repo.status_remote.error.len > 0 {
|
||||||
|
mut err_msg := repo.status_remote.error
|
||||||
|
if err_msg.len > 40 {
|
||||||
|
err_msg = err_msg[0..40] + '...'
|
||||||
|
}
|
||||||
|
statuses << 'ERROR (Remote): ${err_msg}'
|
||||||
|
}
|
||||||
|
|
||||||
if repo.has_changes {
|
if repo.has_changes {
|
||||||
statuses << 'COMMIT'
|
statuses << 'COMMIT'
|
||||||
}
|
}
|
||||||
@@ -38,32 +53,22 @@ fn format_repo_info(repo GitRepo) ![]string {
|
|||||||
|
|
||||||
// Print repositories based on the provided criteria, showing their statuses
|
// Print repositories based on the provided criteria, showing their statuses
|
||||||
pub fn (mut gitstructure GitStructure) repos_print(args ReposGetArgs) ! {
|
pub fn (mut gitstructure GitStructure) repos_print(args ReposGetArgs) ! {
|
||||||
// console.print_debug('#### Overview of repositories:')
|
|
||||||
// console.print_debug('')
|
|
||||||
|
|
||||||
mut repo_data := [][]string{}
|
mut repo_data := [][]string{}
|
||||||
|
|
||||||
// Collect repository information based on the provided criteria
|
// Collect repository information based on the provided criteria
|
||||||
for _, repo in gitstructure.get_repos(args)! {
|
for _, repo in gitstructure.get_repos(args)! {
|
||||||
// repo.status_update()!
|
|
||||||
repo_data << format_repo_info(repo)!
|
repo_data << format_repo_info(repo)!
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clear the console and start printing the formatted repository information
|
// Clear the console and start printing the formatted repository information
|
||||||
console.clear()
|
console.clear()
|
||||||
console.print_lf(1)
|
// console.print_lf(1) // Removed to reduce newlines
|
||||||
|
|
||||||
// Display header with optional argument filtering information
|
|
||||||
// header := if args.str().len > 0 {
|
|
||||||
// 'Repositories: ${gitstructure.config()!.coderoot} [${args.str()}]'
|
|
||||||
// } else {
|
|
||||||
// 'Repositories: ${gitstructure.config()!.coderoot}'
|
|
||||||
// }
|
|
||||||
header := 'Repositories: ${gitstructure.config()!.coderoot}'
|
header := 'Repositories: ${gitstructure.config()!.coderoot}'
|
||||||
console.print_header(header)
|
console.print_header(header)
|
||||||
|
console.print_lf(1) // Keep one newline after header
|
||||||
|
|
||||||
// Print the repository information in a formatted array
|
// Print the repository information in a formatted array
|
||||||
console.print_lf(1)
|
|
||||||
console.print_array(repo_data, ' ', true) // true -> aligned for better readability
|
console.print_array(repo_data, ' ', true) // true -> aligned for better readability
|
||||||
console.print_lf(5)
|
// console.print_lf(5) // Removed to reduce newlines
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ pub mut:
|
|||||||
ref_default string // is the default branch hash
|
ref_default string // is the default branch hash
|
||||||
branches map[string]string // Branch name -> commit hash
|
branches map[string]string // Branch name -> commit hash
|
||||||
tags map[string]string // Tag name -> commit hash
|
tags map[string]string // Tag name -> commit hash
|
||||||
|
error string // Error message if remote status update fails
|
||||||
}
|
}
|
||||||
|
|
||||||
// GitRepoStatusLocal holds local status information for a repository.
|
// GitRepoStatusLocal holds local status information for a repository.
|
||||||
@@ -44,6 +45,7 @@ pub mut:
|
|||||||
branches map[string]string // Branch name -> commit hash
|
branches map[string]string // Branch name -> commit hash
|
||||||
branch string // the current branch
|
branch string // the current branch
|
||||||
tag string // If the local branch is not set, the tag may be set
|
tag string // If the local branch is not set, the tag may be set
|
||||||
|
error string // Error message if local status update fails
|
||||||
}
|
}
|
||||||
|
|
||||||
// GitRepoConfig holds repository-specific configuration options.
|
// GitRepoConfig holds repository-specific configuration options.
|
||||||
|
|||||||
@@ -7,13 +7,33 @@ import os
|
|||||||
@[params]
|
@[params]
|
||||||
pub struct StatusUpdateArgs {
|
pub struct StatusUpdateArgs {
|
||||||
reload bool
|
reload bool
|
||||||
|
force bool // Add force flag to bypass cache when callers need it.
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (mut repo GitRepo) status_update(args StatusUpdateArgs) ! {
|
pub fn (mut repo GitRepo) status_update(args StatusUpdateArgs) ! {
|
||||||
|
// Clear previous errors
|
||||||
|
repo.status_local.error = ''
|
||||||
|
repo.status_remote.error = ''
|
||||||
|
|
||||||
// Check current time vs last check, if needed (check period) then load
|
// Check current time vs last check, if needed (check period) then load
|
||||||
repo.cache_get() or { return error('Failed to get cache for repo ${repo.name}: ${err}') } // Ensure we have the situation from redis
|
repo.cache_get() or {
|
||||||
repo.init() or { return error('Failed to initialize repo ${repo.name}: ${err}') }
|
repo.status_local.error = 'Failed to get cache: ${err}'
|
||||||
if 'OFFLINE' !in os.environ() {
|
return error('Failed to get cache for repo ${repo.name}: ${err}')
|
||||||
|
} // Ensure we have the situation from redis
|
||||||
|
repo.init() or {
|
||||||
|
repo.status_local.error = 'Failed to initialize: ${err}'
|
||||||
|
return error('Failed to initialize repo ${repo.name}: ${err}')
|
||||||
|
}
|
||||||
|
|
||||||
|
// If there's an existing error, skip loading and just return.
|
||||||
|
// This prevents repeated attempts to load a problematic repo.
|
||||||
|
if repo.status_local.error.len > 0 || repo.status_remote.error.len > 0 {
|
||||||
|
console.print_debug('Skipping load for ${repo.name} due to existing error.')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if 'OFFLINE' in os.environ() || (repo.gs.config()!.offline) {
|
||||||
|
console.print_debug('fetch skipped (offline)')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
current_time := int(time.now().unix())
|
current_time := int(time.now().unix())
|
||||||
@@ -21,7 +41,10 @@ pub fn (mut repo GitRepo) status_update(args StatusUpdateArgs) ! {
|
|||||||
|| current_time - repo.last_load >= repo.config.remote_check_period {
|
|| current_time - repo.last_load >= repo.config.remote_check_period {
|
||||||
// console.print_debug('${repo.name} ${current_time}-${repo.last_load} (${current_time - repo.last_load >= repo.config.remote_check_period}): ${repo.config.remote_check_period} +++')
|
// console.print_debug('${repo.name} ${current_time}-${repo.last_load} (${current_time - repo.last_load >= repo.config.remote_check_period}): ${repo.config.remote_check_period} +++')
|
||||||
// if true{exit(0)}
|
// if true{exit(0)}
|
||||||
repo.load() or { return error('Failed to load repository ${repo.name}: ${err}') }
|
repo.load() or {
|
||||||
|
repo.status_remote.error = 'Failed to load repository: ${err}'
|
||||||
|
return error('Failed to load repository ${repo.name}: ${err}')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -29,27 +52,40 @@ pub fn (mut repo GitRepo) status_update(args StatusUpdateArgs) ! {
|
|||||||
// Does not check cache, it is the callers responsibility to check cache and load accordingly.
|
// Does not check cache, it is the callers responsibility to check cache and load accordingly.
|
||||||
fn (mut repo GitRepo) load() ! {
|
fn (mut repo GitRepo) load() ! {
|
||||||
console.print_header('load ${repo.print_key()}')
|
console.print_header('load ${repo.print_key()}')
|
||||||
repo.init() or { return error('Failed to initialize repo during load operation: ${err}') }
|
repo.init() or {
|
||||||
|
repo.status_local.error = 'Failed to initialize repo during load operation: ${err}'
|
||||||
|
return error('Failed to initialize repo during load operation: ${err}')
|
||||||
|
}
|
||||||
|
|
||||||
git_path := '${repo.path()}/.git'
|
git_path := '${repo.path()}/.git'
|
||||||
if os.exists(git_path) == false {
|
if os.exists(git_path) == false {
|
||||||
|
repo.status_local.error = 'Repository not found: missing .git directory'
|
||||||
return error('Repository not found: ${repo.path()} is not a valid git repository (missing .git directory)')
|
return error('Repository not found: ${repo.path()} is not a valid git repository (missing .git directory)')
|
||||||
}
|
}
|
||||||
|
|
||||||
repo.exec('git fetch --all') or {
|
repo.exec('git fetch --all') or {
|
||||||
|
repo.status_remote.error = 'Failed to fetch updates: ${err}'
|
||||||
return error('Failed to fetch updates for ${repo.name} at ${repo.path()}: ${err}. Please check network connection and repository access.')
|
return error('Failed to fetch updates for ${repo.name} at ${repo.path()}: ${err}. Please check network connection and repository access.')
|
||||||
}
|
}
|
||||||
|
|
||||||
repo.load_branches() or { return error('Failed to load branches for ${repo.name}: ${err}') }
|
repo.load_branches() or {
|
||||||
|
repo.status_remote.error = 'Failed to load branches: ${err}'
|
||||||
|
return error('Failed to load branches for ${repo.name}: ${err}')
|
||||||
|
}
|
||||||
|
|
||||||
repo.load_tags() or { return error('Failed to load tags for ${repo.name}: ${err}') }
|
repo.load_tags() or {
|
||||||
|
repo.status_remote.error = 'Failed to load tags: ${err}'
|
||||||
|
return error('Failed to load tags for ${repo.name}: ${err}')
|
||||||
|
}
|
||||||
|
|
||||||
repo.last_load = int(time.now().unix())
|
repo.last_load = int(time.now().unix())
|
||||||
|
|
||||||
repo.has_changes = repo.detect_changes() or {
|
repo.has_changes = repo.detect_changes() or {
|
||||||
|
repo.status_local.error = 'Failed to detect changes: ${err}'
|
||||||
return error('Failed to detect changes in repository ${repo.name}: ${err}')
|
return error('Failed to detect changes in repository ${repo.name}: ${err}')
|
||||||
}
|
}
|
||||||
repo.cache_set() or {
|
repo.cache_set() or {
|
||||||
|
repo.status_local.error = 'Failed to update cache: ${err}'
|
||||||
return error('Failed to update cache for repository ${repo.name}: ${err}')
|
return error('Failed to update cache for repository ${repo.name}: ${err}')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user