This commit is contained in:
2025-02-05 07:57:05 +03:00
parent 01991027cc
commit c2eef5a6ab
15 changed files with 236 additions and 223 deletions

View File

@@ -37,6 +37,7 @@ pub fn new(args_ GitStructureArgsNew) !&GitStructure {
ssh_key_name: args.ssh_key_name
}
return get(coderoot: args.coderoot, reload: args.reload, cfg: cfg)
}
@@ -55,6 +56,11 @@ pub fn get(args_ GitStructureArgGet) !&GitStructure {
args.coderoot = '${os.home_dir()}/code'
}
//make sure coderoot exists
if ! os.exists(args.coderoot){
os.mkdir_all(args.coderoot)!
}
rediskey_ := cache_key(args.coderoot)
// Return existing instance if already created.

View File

@@ -48,8 +48,6 @@ pub fn (mut gitstructure GitStructure) load(reload bool) ! {
gitstructure.cache_reset()!
}
// mut ths := []thread !{}
// need to make sure redis is empty before doing the threads, is not removing the cache
redisclient.reset()!
redisclient.checkempty()
@@ -64,24 +62,6 @@ pub fn (mut gitstructure GitStructure) load(reload bool) ! {
}
}
// pp.work_on_items(todo)
// console.print_debug('loaded all threads for git on ${gitstructure.coderoot}')
// for th in ths {
// th.wait()!
// }
// for x in pp.get_results[SResult]() {
// println('result: ${x.s}')
// }
// console.print_debug("threads finished")
// now we need to load them back in our memory because these were done in sub process
// for _, mut r in gitstructure.repos {
// r.cache_get()!
// }
// gitstructure.init()!
}
// Recursively loads repositories from the provided path, updating their statuses, does not check the status

View File

@@ -20,8 +20,10 @@ pub mut:
msg string
url string
branch string
path string //path to start from
recursive bool
pull bool
reload bool //means reload the info into the cache
script bool = true // run non interactive
reset bool = true // means we will lose changes (only relevant for clone, pull)
}
@@ -37,16 +39,22 @@ pub mut:
// msg string
// url string
// pull bool
// reload bool //means reload the info into the cache
// script bool = true // run non interactive
// reset bool = true // means we will lose changes (only relevant for clone, pull)
//```
pub fn (mut gs GitStructure) do(args_ ReposActionsArgs) !string {
mut args := args_
console.print_debug('git do ${args.cmd}')
//console.print_debug('git do ${args.cmd}')
if args.repo == '' && args.account == '' && args.provider == '' && args.filter == '' {
curdir := os.getwd()
mut curdiro := pathlib.get_dir(path: curdir, create: false)!
if args.path == '' {
args.path = os.getwd()
}
//see if its one repo we are in, based on current path
if args.repo == '' && args.account == '' && args.provider == '' && args.filter == '' {
mut curdiro := pathlib.get_dir(path: args.path, create: false)!
mut parentpath := curdiro.parent_find('.git') or { pathlib.Path{} }
if parentpath.path != '' {
r0 := gs.repo_init_from_path_(parentpath.path)!
@@ -55,15 +63,33 @@ pub fn (mut gs GitStructure) do(args_ ReposActionsArgs) !string {
args.provider = r0.provider
}
}
//see if a url was used means we are in 1 repo
if args.url.len > 0 {
if !(args.repo == '' && args.account == '' && args.provider == '' && args.filter == ''){
return error("when specify url cannot specify repo, account, profider or filter")
}
mut r0 := gs.get_repo(url: args.url)!
args.repo = r0.name
args.account = r0.account
args.provider = r0.provider
}
args.cmd = args.cmd.trim_space().to_lower()
mut ui := gui.new()!
if args.cmd == 'reload' {
console.print_header(' - reload gitstructure ${gs.config()!.coderoot}')
gs.load(true)!
return ''
mut repos := gs.get_repos(
filter: args.filter
name: args.repo
account: args.account
provider: args.provider
)!
//reset the status for the repo
if args.reload{
for mut repo in repos{
repo.cache_last_load_clear()!
}
}
if args.cmd == 'list' {
@@ -76,42 +102,7 @@ pub fn (mut gs GitStructure) do(args_ ReposActionsArgs) !string {
return ''
}
mut repos := gs.get_repos(
filter: args.filter
name: args.repo
account: args.account
provider: args.provider
)!
if args.url.len > 0 {
mut g := gs.get_repo(url: args.url)!
g.load()!
if args.cmd == 'cd' {
return g.path()
}
if args.reset {
g.remove_changes()!
}
if args.cmd == 'pull' || args.pull {
g.pull()!
}
if args.cmd == 'push' {
if g.need_commit()! {
if args.msg.len == 0 {
return error('please specify message with -m ...')
}
g.commit(args.msg)!
}
g.push()!
}
if args.cmd == 'pull' || args.cmd == 'clone' || args.cmd == 'push' {
gpath := g.path()
console.print_debug('git do ok, on path ${gpath}')
return gpath
}
repos = [g]
}
//means we are on 1 repo
if args.cmd in 'sourcetree,edit'.split(',') {
if repos.len == 0 {
return error('please specify at least 1 repo for cmd:${args.cmd}')
@@ -131,6 +122,7 @@ pub fn (mut gs GitStructure) do(args_ ReposActionsArgs) !string {
}
if args.cmd in 'pull,push,commit,delete'.split(',') {
gs.repos_print(
filter: args.filter
name: args.repo
@@ -138,9 +130,9 @@ pub fn (mut gs GitStructure) do(args_ ReposActionsArgs) !string {
provider: args.provider
)!
mut need_commit := false
mut need_pull := false
mut need_push := false
mut need_commit0 := false
mut need_pull0 := false
mut need_push0 := false
if repos.len == 0 {
console.print_header(' - nothing to do.')
@@ -149,26 +141,30 @@ pub fn (mut gs GitStructure) do(args_ ReposActionsArgs) !string {
// check on repos who needs what
for mut g in repos {
g.load()!
// console.print_debug(st)
need_commit = g.need_commit()! || need_commit
if args.cmd == 'push' && need_commit {
need_push = true
if args.cmd in ["push"] && g.need_push_or_pull()! {
need_push0 = true
}
if args.cmd in ["push","pull"] && (need_push0 || g.need_push_or_pull()!){
need_pull0 = true
}
if args.cmd in ["push","pull","commit"] && (need_push0 || need_pull0 || g.need_commit()!) {
need_commit0 = true
}
need_pull = args.cmd in 'pull,push'.split(',') // always do pull when push and pull
need_push = args.cmd == 'push' && (g.need_push_or_pull()! || need_push)
}
mut ok := false
if need_commit || need_pull || need_push {
if need_commit0 || need_pull0 || need_push0 {
mut out := '\n ** NEED TO '
if need_commit {
if need_commit0 {
out += 'COMMIT '
}
if need_pull {
if need_pull0 {
out += 'PULL '
}
if need_push {
if need_push0 {
out += 'PUSH '
}
if args.reset {
@@ -178,91 +174,89 @@ pub fn (mut gs GitStructure) do(args_ ReposActionsArgs) !string {
if args.script {
ok = true
} else {
ok = ui.ask_yesno(question: 'Is above ok?')!
if need_commit0 || need_pull0 || need_push0 {
ok = ui.ask_yesno(question: 'Is above ok?')!
}else{
console.print_green("nothing to do")
}
}
if ok == false {
return error('cannot continue with action, you asked me to stop.\n${args}')
}
if need_commit0{
if args.msg.len == 0 && args.script {
return error('message needs to be specified for commit.')
}
if args.msg.len == 0 {
args.msg = ui.ask_question(
question: 'commit message for the actions: '
)!
}
}
}
if args.cmd == 'delete' {
if args.script {
ok = true
} else {
ok = ui.ask_yesno(question: 'Is it ok to delete above repos? (DANGEROUS)')!
}
}
if ok == false {
return error('cannot continue with action, you asked me to stop.\n${args}')
}
// mut changed := false
mut ths := []thread !bool{}
for mut g in repos {
ths << spawn fn (mut g GitRepo, args ReposActionsArgs, need_commit bool, need_push bool, shared ui generic.UserInterface) !bool {
redisclient.reset()!
redisclient.checkempty()
mut has_changed := false
need_commit_repo := (g.need_commit()! || need_commit)
&& args.cmd in 'commit,pull,push'.split(',')
need_pull_repo := args.cmd in 'pull,push'.split(',') // always do pull when push and pull
need_push_repo := args.cmd in 'push'.split(',')
&& (g.need_push_or_pull()! || need_push)
// console.print_debug(" --- git_do ${g.addr.name} ${st.need_commit} ${st.need_pull} ${st.need_push}")
if need_commit_repo {
mut msg := args.msg
if msg.len == 0 {
if args.script {
return error('message needs to be specified for commit.')
}
lock ui {
msg = ui.ask_question(
question: 'commit message for repo: ${g.account}/${g.name} '
)!
}
}
console.print_header(' - commit ${g.account}/${g.name}')
g.commit(msg)!
has_changed = true
}
if need_pull_repo {
if args.reset {
console.print_header(' - remove changes ${g.account}/${g.name}')
g.remove_changes()!
}
console.print_header(' - pull ${g.account}/${g.name}')
g.pull()!
has_changed = true
}
if need_push_repo {
console.print_header(' - push ${g.account}/${g.name}')
g.push()!
has_changed = true
}
if args.cmd == 'delete' {
g.delete()!
has_changed = true
}
return has_changed
}(mut g, args, need_commit, need_push, shared &ui)
}
for th in ths {
has_changed := th.wait()!
if has_changed {
// console.clear()
console.print_header('\nCompleted required actions.\n')
gs.repos_print(
filter: args.filter
name: args.repo
account: args.account
provider: args.provider
)!
if ok == false {
return error('cannot continue with action, you asked me to stop.\n${args}')
}
}
mut has_changed := false
for mut g in repos {
need_push_repo := need_push0 && g.need_push_or_pull()!
need_pull_repo := need_push_repo || (need_pull0 && g.need_push_or_pull()!)
need_commit_repo := need_push_repo || need_pull_repo || (need_commit0 && g.need_commit()!)
//console.print_debug(" --- git_do ${g.cache_key()} \n need_commit_repo:${need_commit_repo} \n need_pull_repo:${need_pull_repo} \n need_push_repo:${need_push_repo}")
if need_commit_repo {
mut msg := args.msg
console.print_header(' - commit ${g.account}/${g.name}')
g.commit(msg)!
has_changed = true
}
if need_push_repo {
if args.reset {
console.print_header(' - remove changes ${g.account}/${g.name}')
g.remove_changes()!
}
console.print_header(' - pull ${g.account}/${g.name}')
g.pull()!
has_changed = true
}
if need_pull_repo {
console.print_header(' - push ${g.account}/${g.name}')
g.push()!
has_changed = true
}
if args.cmd == 'delete' {
g.delete()!
has_changed = true
}
}
if has_changed {
// console.clear()
console.print_header('\nCompleted required actions.\n')
gs.repos_print(
filter: args.filter
name: args.repo
account: args.account
provider: args.provider
)!
}
return ''
}
// end for the commit, pull, push, delete

View File

@@ -14,7 +14,8 @@ pub mut:
provider string // Git provider (e.g., GitHub).
pull bool // Pull the last changes.
reset bool // Reset the changes.
reload bool // Reload the repo into redis cache
status_clean bool //make sure each cache status is but on 0, if we also do status_update this will result in a reload
status_update bool //make sure each repo get's status updated
url string // Repository URL
}
@@ -28,9 +29,10 @@ pub mut:
// name string // Specific repository name to retrieve.
// account string // Git account associated with the repository.
// provider string // Git provider (e.g., GitHub).
// pull bool // Pull the last changes.
// reset bool // Reset the changes.
// reload bool // Reload the repo into redis cache
// pull bool // Pull the last changes.
// reset bool // Reset the changes
// status_clean bool //make sure each cache status is but on 0, if we also do status_update this will result in a reload
// status_update bool //make sure each repo get's status updated
// url string // Repository URL, used if cloning is needed.
//```
// Returns:
@@ -40,14 +42,7 @@ pub fn (mut gitstructure GitStructure) get_repos(args_ ReposGetArgs) ![]&GitRepo
mut res := []&GitRepo{}
for _, repo in gitstructure.repos {
relpath := repo.get_relative_path()!
if args.filter != '' && relpath.contains(args.filter) {
res << repo
continue
}
for _, repo in gitstructure.repos {
if args.url.len > 0 {
// if being mathed from url load repo info
git_location := gitstructure.gitlocation_from_url(args.url)!
@@ -55,34 +50,26 @@ pub fn (mut gitstructure GitStructure) get_repos(args_ ReposGetArgs) ![]&GitRepo
args.provider = git_location.provider
args.name = git_location.name
}
if repo_match_check(repo, args) {
if repo_match_check(repo, args)! {
res << repo
}
}
// operate per repo on thread based on args
mut ths := []thread !{}
for mut repo in res {
// check redis cache outside, in threads is problematic
repo.cache_get() or { return error('failed to get repo cache ${err}') }
if time.since(time.unix(repo.last_load)) > 24 * time.hour {
args.reload = true
for mut repo in res{
if args.status_clean{
repo.cache_last_load_clear()!
}
ths << spawn fn (mut repo GitRepo, args ReposGetArgs) ! {
redisclient.reset()!
redisclient.checkempty()
if args.pull {
if args.status_update{
repo.status_update()!
}
if args.reset{
repo.reset()!
}else{
if args.pull{
repo.pull()!
} else if args.reset {
repo.reset()!
} else if args.reload {
repo.load()!
}
}(mut repo, args)
}
for th in ths {
th.wait()!
}
}
return res
@@ -138,10 +125,19 @@ pub fn (mut gitstructure GitStructure) get_repo(args_ ReposGetArgs) !&GitRepo {
//
// Returns:
// - bool: True if the repository matches, false otherwise.
fn repo_match_check(repo GitRepo, args ReposGetArgs) bool {
return (args.name.len == 0 || repo.name == args.name)
fn repo_match_check(repo GitRepo, args ReposGetArgs) !bool {
mut r:= (args.name.len == 0 || repo.name == args.name)
&& (args.account.len == 0 || repo.account == args.account)
&& (args.provider.len == 0 || repo.provider == args.provider)
relpath := repo.get_relative_path()!
if r{
if args.filter != '' && ! (relpath.contains(args.filter)) {
return false
}
}
return r
}

View File

@@ -41,6 +41,7 @@ pub fn (mut gitstructure GitStructure) repos_print(args ReposGetArgs) ! {
// Collect repository information based on the provided criteria
for _, repo in gitstructure.get_repos(args)! {
//repo.status_update()!
repo_data << format_repo_info(repo)!
}

View File

@@ -86,12 +86,13 @@ pub fn (mut repo GitRepo) commit(msg string) ! {
return error('Cannot commit repo: ${repo_path}. Error: ${err}')
}
console.print_green('Changes committed successfully.')
repo.load()!
} else {
console.print_debug('No changes to commit.')
}
repo.load()!
}
// Push local changes to the remote repository.
pub fn (mut repo GitRepo) push() ! {
repo.status_update()!
@@ -104,7 +105,6 @@ pub fn (mut repo GitRepo) push() ! {
repo.load()!
} else {
console.print_header('Everything is up to date.')
repo.load()!
}
}
@@ -146,6 +146,7 @@ pub fn (mut repo GitRepo) checkout() ! {
if repo.status_wanted.branch.len > 0 {
repo.exec('git checkout ${repo.status_wanted.branch}')!
}
repo.cache_last_load_clear()!
}
// Create a new branch in the repository.
@@ -153,6 +154,7 @@ pub fn (mut repo GitRepo) branch_create(branchname string) ! {
repo.exec('git branch -c ${branchname}') or {
return error('Cannot Create branch: ${repo.path()} to ${branchname}\nError: ${err}')
}
repo.cache_last_load_clear()!
console.print_green('Branch ${branchname} created successfully.')
}
@@ -194,9 +196,10 @@ pub fn (mut repo GitRepo) tag_exists(tag string) !bool {
// Deletes the Git repository
pub fn (mut repo GitRepo) delete() ! {
repo_path := repo.path()
key := repo.cache_key()
repo.cache_delete()!
osal.rm(repo_path)!
repo.load()!
repo.gs.repos.delete(key) // Remove from GitStructure's repos map
}
// Create GitLocation from the path within the Git repository
@@ -205,12 +208,19 @@ pub fn (mut gs GitRepo) gitlocation_from_path(path string) !GitLocation {
return error('Path must be relative, cannot start with / or ~')
}
// TODO: check that path is inside gitrepo
// TODO: get relative path in relation to root of gitrepo
mut git_path := gs.patho()!
if !os.exists(git_path.path) {
return error('Path does not exist inside the repository: ${git_path.path}')
repo_path := git_path.path
abs_path := os.abs_path(path)
// Check if path is inside git repo
if !abs_path.starts_with(repo_path) {
return error('Path ${path} is not inside the git repository at ${repo_path}')
}
// Get relative path in relation to root of gitrepo
rel_path := abs_path[repo_path.len + 1..] // +1 to skip the trailing slash
if !os.exists(abs_path) {
return error('Path does not exist inside the repository: ${abs_path}')
}
mut branch_or_tag := gs.status_wanted.branch
@@ -223,7 +233,7 @@ pub fn (mut gs GitRepo) gitlocation_from_path(path string) !GitLocation {
account: gs.account
name: gs.name
branch_or_tag: branch_or_tag
path: path // relative path in relation to git repo
path: rel_path // relative path in relation to git repo
}
}
@@ -244,12 +254,18 @@ pub fn (mut repo GitRepo) init() ! {
return error('Path does not exist: ${path_string}')
}
// TODO: check deploy key has been set in repo
// if not do git config core.sshCommand "ssh -i /path/to/deploy_key"
// Check if deploy key is set in repo config
if repo.deploysshkey.len > 0 {
repo.set_sshkey(repo.deploysshkey)!
git_config := repo.exec('git config --get core.sshCommand') or { '' }
if !git_config.contains(repo.deploysshkey) {
repo.set_sshkey(repo.deploysshkey)!
}
}
// Check that either tag or branch is set on wanted, but not both
if repo.status_wanted.tag.len > 0 && repo.status_wanted.branch.len > 0 {
return error('Cannot set both tag and branch in wanted status. Choose one or the other.')
}
// TODO: check tag or branch set on wanted, and not both
}
// Set the ssh key on the repo
@@ -261,7 +277,7 @@ fn (mut repo GitRepo) set_sshkey(key_name string) ! {
}
private_key := key.private_key_path()!
_ := 'git config core.sshcommand "ssh -i ~/.ssh/${private_key.path}"'
repo.exec('git config core.sshcommand "ssh -i ~/.ssh/${private_key.path}"')!
repo.deploysshkey = key_name
}

View File

@@ -38,3 +38,10 @@ fn (mut repo GitRepo) cache_delete() ! {
// TODO: report v bug, function should work without return as well
return
}
//put the data of last load on 0, means first time a git status check will be done it will update its info
fn (mut repo GitRepo) cache_last_load_clear() ! {
repo.cache_get()!
repo.last_load = 0
repo.cache_set()!
}

View File

@@ -31,7 +31,7 @@ pub fn (mut repo GitRepo) status_update(args StatusUpdateArgs) ! {
// Load repo information
// Does not check cache, it is the callers responsibility to check cache and load accordingly.
fn (mut repo GitRepo) load() ! {
console.print_header('load ${repo.cache_key()}')
console.print_header('load ${repo.print_key()}')
repo.init() or {
return error('Failed to initialize repo during load operation: ${err}')
}
@@ -109,13 +109,13 @@ fn (mut repo GitRepo) load_tags() ! {
tags_result := repo.exec('git tag --list') or {
return error('Failed to list tags: ${err}. Please ensure git is installed and repository is accessible.')
}
//println(tags_result)
for line in tags_result.split('\n') {
line_trimmed := line.trim_space()
if line_trimmed != '' {
parts := line_trimmed.split(' ')
if parts.len < 2 {
console.print_debug('Skipping malformed tag line: ${line_trimmed}')
//console.print_debug('Skipping malformed tag line: ${line_trimmed}')
continue
}
commit_hash := parts[0].trim_space()

View File

@@ -18,6 +18,10 @@ pub fn (mut repo GitRepo) cache_key() string {
return '${repo.gs.cache_key()}:${repo.provider}:${repo.account}:${repo.name}'
}
pub fn (mut repo GitRepo) print_key() string {
return '${repo.provider}:${repo.account}:${repo.name}'
}
// get path where the repo is on the fs
pub fn (repo GitRepo) path() string {
mut repo_ := repo