v0.7.6 - Clone dossier non-vide et verification rapide
Changements : - Clone dans dossier non-vide (git init + remote add + fetch + checkout) - Verification rapide via git ls-remote au lieu de git fetch (timeout 15s) - Support branche par repo dans config.ini (champ branch) - Suppression fichiers Python et artefacts PyInstaller (_internal/) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
163
git.go
163
git.go
@@ -19,12 +19,13 @@ type RepoResult struct {
|
||||
Name string
|
||||
Path string
|
||||
URL string
|
||||
Branch string // branche configurée
|
||||
Pending bool
|
||||
UpToDate bool
|
||||
Offline bool
|
||||
NeedsClone bool
|
||||
HasUpdate bool // MAJ disponible (hash local != distant)
|
||||
Error string
|
||||
NewCommits int
|
||||
LocalChanges int
|
||||
UntrackedFiles int
|
||||
UntrackedList []string // liste des fichiers non suivis
|
||||
@@ -65,8 +66,17 @@ func absRepoPath(rel string) string {
|
||||
return filepath.Join(exeDir(), rel)
|
||||
}
|
||||
|
||||
func checkRemoteOffline(stderr string) bool {
|
||||
for _, kw := range []string{"could not resolve", "connection refused", "unable to connect", "timed out", "the remote end hung up", "timeout"} {
|
||||
if strings.Contains(strings.ToLower(stderr), kw) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func checkRepo(cfg RepoConfig) RepoResult {
|
||||
res := RepoResult{Name: cfg.Name, URL: cfg.URL}
|
||||
res := RepoResult{Name: cfg.Name, URL: cfg.URL, Branch: cfg.Branch}
|
||||
local := absRepoPath(cfg.Path)
|
||||
res.Path = local
|
||||
|
||||
@@ -74,12 +84,10 @@ func checkRepo(cfg RepoConfig) RepoResult {
|
||||
// Vérifier que le dépôt distant existe avant de proposer le clone
|
||||
code, _, stderr := runGit([]string{"ls-remote", "--exit-code", cfg.URL}, "", 15*time.Second)
|
||||
if code != 0 {
|
||||
for _, kw := range []string{"could not resolve", "connection refused", "unable to connect", "timed out", "the remote end hung up"} {
|
||||
if strings.Contains(strings.ToLower(stderr), kw) {
|
||||
res.Offline = true
|
||||
res.Error = "Hors ligne"
|
||||
return res
|
||||
}
|
||||
if checkRemoteOffline(stderr) {
|
||||
res.Offline = true
|
||||
res.Error = "Hors ligne"
|
||||
return res
|
||||
}
|
||||
if strings.Contains(strings.ToLower(stderr), "not found") || strings.Contains(strings.ToLower(stderr), "repository not found") {
|
||||
res.Error = "Dépôt introuvable : " + cfg.URL
|
||||
@@ -94,27 +102,45 @@ func checkRepo(cfg RepoConfig) RepoResult {
|
||||
|
||||
runGit([]string{"remote", "set-url", "origin", cfg.URL}, local, 10*time.Second)
|
||||
|
||||
code, _, stderr := runGit([]string{"fetch", "origin"}, local, 5*time.Minute)
|
||||
if code != 0 {
|
||||
for _, kw := range []string{"could not resolve", "connection refused", "unable to connect", "timed out", "the remote end hung up"} {
|
||||
if strings.Contains(strings.ToLower(stderr), kw) {
|
||||
res.Offline = true
|
||||
res.Error = "Hors ligne"
|
||||
return res
|
||||
}
|
||||
}
|
||||
res.Error = "Fetch: " + stderr
|
||||
// Hash local
|
||||
_, localHash, _ := runGit([]string{"rev-parse", "HEAD"}, local, 5*time.Second)
|
||||
if localHash == "" {
|
||||
res.Error = "Impossible de lire le commit local"
|
||||
return res
|
||||
}
|
||||
|
||||
_, branch, _ := runGit([]string{"rev-parse", "--abbrev-ref", "HEAD"}, local, 5*time.Second)
|
||||
if branch == "" {
|
||||
branch = "master"
|
||||
// Vérification rapide du remote via ls-remote (timeout court)
|
||||
branch := cfg.Branch
|
||||
code, lsOut, stderr := runGit([]string{"ls-remote", "origin", "refs/heads/" + branch}, local, 15*time.Second)
|
||||
if code != 0 {
|
||||
if checkRemoteOffline(stderr) {
|
||||
res.Offline = true
|
||||
res.Error = "Hors ligne"
|
||||
return res
|
||||
}
|
||||
res.Error = "ls-remote: " + stderr
|
||||
return res
|
||||
}
|
||||
|
||||
_, countStr, _ := runGit([]string{"rev-list", "--count", "HEAD..origin/" + branch}, local, 5*time.Second)
|
||||
fmt.Sscanf(countStr, "%d", &res.NewCommits)
|
||||
// Extraire le hash distant
|
||||
remoteHash := ""
|
||||
if lsOut != "" {
|
||||
parts := strings.Fields(lsOut)
|
||||
if len(parts) > 0 {
|
||||
remoteHash = parts[0]
|
||||
}
|
||||
}
|
||||
if remoteHash == "" {
|
||||
res.Error = fmt.Sprintf("Branche '%s' introuvable sur le remote", branch)
|
||||
return res
|
||||
}
|
||||
|
||||
// Comparer les hashs
|
||||
if localHash != remoteHash {
|
||||
res.HasUpdate = true
|
||||
}
|
||||
|
||||
// Modifications locales
|
||||
_, status, _ := runGit([]string{"status", "--porcelain"}, local, 5*time.Second)
|
||||
if status != "" {
|
||||
for _, line := range strings.Split(strings.TrimSpace(status), "\n") {
|
||||
@@ -127,7 +153,7 @@ func checkRepo(cfg RepoConfig) RepoResult {
|
||||
}
|
||||
}
|
||||
|
||||
res.UpToDate = res.NewCommits == 0 && res.LocalChanges == 0 && res.UntrackedFiles == 0
|
||||
res.UpToDate = !res.HasUpdate && res.LocalChanges == 0 && res.UntrackedFiles == 0
|
||||
return res
|
||||
}
|
||||
|
||||
@@ -136,9 +162,49 @@ func doClone(cfg RepoConfig) error {
|
||||
if err := os.MkdirAll(filepath.Dir(local), 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
code, _, stderr := runGit([]string{"clone", cfg.URL, local}, "", 300*time.Second)
|
||||
|
||||
// Si le dossier n'existe pas ou est vide, clone classique
|
||||
entries, _ := os.ReadDir(local)
|
||||
if len(entries) == 0 {
|
||||
code, _, stderr := runGit([]string{"clone", cfg.URL, local}, "", 300*time.Second)
|
||||
if code != 0 {
|
||||
return fmt.Errorf("%s", stderr)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Dossier non-vide sans .git : init + remote + fetch + checkout
|
||||
return doCloneInPlace(cfg, local)
|
||||
}
|
||||
|
||||
func doCloneInPlace(cfg RepoConfig, local string) error {
|
||||
code, _, stderr := runGit([]string{"init"}, local, 30*time.Second)
|
||||
if code != 0 {
|
||||
return fmt.Errorf("%s", stderr)
|
||||
return fmt.Errorf("git init: %s", stderr)
|
||||
}
|
||||
|
||||
code, _, stderr = runGit([]string{"remote", "add", "origin", cfg.URL}, local, 10*time.Second)
|
||||
if code != 0 {
|
||||
// remote existe déjà, mettre à jour l'URL
|
||||
runGit([]string{"remote", "set-url", "origin", cfg.URL}, local, 10*time.Second)
|
||||
}
|
||||
|
||||
code, _, stderr = runGit([]string{"fetch", "origin"}, local, 5*time.Minute)
|
||||
if code != 0 {
|
||||
return fmt.Errorf("fetch: %s", stderr)
|
||||
}
|
||||
|
||||
branch := cfg.Branch
|
||||
code, _, stderr = runGit([]string{"checkout", "origin/" + branch, "-b", branch}, local, 30*time.Second)
|
||||
if code != 0 {
|
||||
// Branche locale existe déjà
|
||||
code, _, stderr = runGit([]string{"checkout", branch}, local, 30*time.Second)
|
||||
if code == 0 {
|
||||
code, _, stderr = runGit([]string{"reset", "--hard", "origin/" + branch}, local, 30*time.Second)
|
||||
}
|
||||
}
|
||||
if code != 0 {
|
||||
return fmt.Errorf("checkout: %s", stderr)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -291,12 +357,49 @@ func doCloneWithProgress(cfg RepoConfig, cb ProgressCallback) error {
|
||||
if err := os.MkdirAll(filepath.Dir(local), 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
code, _, stderr := runGitWithProgress(
|
||||
[]string{"clone", "--progress", cfg.URL, local},
|
||||
"", 2*time.Hour, cb,
|
||||
|
||||
// Si le dossier n'existe pas ou est vide, clone classique avec progression
|
||||
entries, _ := os.ReadDir(local)
|
||||
if len(entries) == 0 {
|
||||
code, _, stderr := runGitWithProgress(
|
||||
[]string{"clone", "--progress", cfg.URL, local},
|
||||
"", 2*time.Hour, cb,
|
||||
)
|
||||
if code != 0 {
|
||||
return fmt.Errorf("%s", stderr)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Dossier non-vide sans .git : init + remote + fetch avec progression + checkout
|
||||
code, _, stderr := runGit([]string{"init"}, local, 30*time.Second)
|
||||
if code != 0 {
|
||||
return fmt.Errorf("git init: %s", stderr)
|
||||
}
|
||||
|
||||
code, _, stderr = runGit([]string{"remote", "add", "origin", cfg.URL}, local, 10*time.Second)
|
||||
if code != 0 {
|
||||
runGit([]string{"remote", "set-url", "origin", cfg.URL}, local, 10*time.Second)
|
||||
}
|
||||
|
||||
code, _, stderr = runGitWithProgress(
|
||||
[]string{"fetch", "--progress", "origin"},
|
||||
local, 2*time.Hour, cb,
|
||||
)
|
||||
if code != 0 {
|
||||
return fmt.Errorf("%s", stderr)
|
||||
return fmt.Errorf("fetch: %s", stderr)
|
||||
}
|
||||
|
||||
branch := cfg.Branch
|
||||
code, _, stderr = runGit([]string{"checkout", "origin/" + branch, "-b", branch}, local, 30*time.Second)
|
||||
if code != 0 {
|
||||
code, _, stderr = runGit([]string{"checkout", branch}, local, 30*time.Second)
|
||||
if code == 0 {
|
||||
code, _, stderr = runGit([]string{"reset", "--hard", "origin/" + branch}, local, 30*time.Second)
|
||||
}
|
||||
}
|
||||
if code != 0 {
|
||||
return fmt.Errorf("checkout: %s", stderr)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user