v0.7.8 - Bouton Arreter pour annuler les telechargements
Changements : - Bouton Arreter dans la barre de boutons (actif pendant les operations) - Annulation des operations git en cours via context.Context - Detection et affichage du message Annule dans le journal Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Binary file not shown.
17
git.go
17
git.go
@@ -280,8 +280,8 @@ func parseGitProgress(line string) (ProgressInfo, bool) {
|
|||||||
|
|
||||||
// runGitWithProgress exécute une commande git et capture la progression en temps réel.
|
// runGitWithProgress exécute une commande git et capture la progression en temps réel.
|
||||||
// Le timeout est désactivé (0) ou très long pour les gros dépôts.
|
// Le timeout est désactivé (0) ou très long pour les gros dépôts.
|
||||||
func runGitWithProgress(args []string, cwd string, timeout time.Duration, cb ProgressCallback) (int, string, string) {
|
func runGitWithProgress(parent context.Context, args []string, cwd string, timeout time.Duration, cb ProgressCallback) (int, string, string) {
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
ctx, cancel := context.WithTimeout(parent, timeout)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
fullArgs := append([]string{"-c", "safe.directory=*"}, args...)
|
fullArgs := append([]string{"-c", "safe.directory=*"}, args...)
|
||||||
@@ -339,6 +339,9 @@ func runGitWithProgress(args []string, cwd string, timeout time.Duration, cb Pro
|
|||||||
stderr := strings.TrimSpace(stderrBuf.String())
|
stderr := strings.TrimSpace(stderrBuf.String())
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if ctx.Err() == context.Canceled {
|
||||||
|
return 1, stdout, "Annulé"
|
||||||
|
}
|
||||||
if ctx.Err() == context.DeadlineExceeded {
|
if ctx.Err() == context.DeadlineExceeded {
|
||||||
return 1, stdout, "Timeout"
|
return 1, stdout, "Timeout"
|
||||||
}
|
}
|
||||||
@@ -352,7 +355,7 @@ func runGitWithProgress(args []string, cwd string, timeout time.Duration, cb Pro
|
|||||||
}
|
}
|
||||||
|
|
||||||
// doCloneWithProgress clone un dépôt avec suivi de progression.
|
// doCloneWithProgress clone un dépôt avec suivi de progression.
|
||||||
func doCloneWithProgress(cfg RepoConfig, cb ProgressCallback) error {
|
func doCloneWithProgress(ctx context.Context, cfg RepoConfig, cb ProgressCallback) error {
|
||||||
local := absRepoPath(cfg.Path)
|
local := absRepoPath(cfg.Path)
|
||||||
if err := os.MkdirAll(filepath.Dir(local), 0755); err != nil {
|
if err := os.MkdirAll(filepath.Dir(local), 0755); err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -362,7 +365,7 @@ func doCloneWithProgress(cfg RepoConfig, cb ProgressCallback) error {
|
|||||||
entries, _ := os.ReadDir(local)
|
entries, _ := os.ReadDir(local)
|
||||||
if len(entries) == 0 {
|
if len(entries) == 0 {
|
||||||
code, _, stderr := runGitWithProgress(
|
code, _, stderr := runGitWithProgress(
|
||||||
[]string{"clone", "--progress", cfg.URL, local},
|
ctx, []string{"clone", "--progress", cfg.URL, local},
|
||||||
"", 2*time.Hour, cb,
|
"", 2*time.Hour, cb,
|
||||||
)
|
)
|
||||||
if code != 0 {
|
if code != 0 {
|
||||||
@@ -383,7 +386,7 @@ func doCloneWithProgress(cfg RepoConfig, cb ProgressCallback) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
code, _, stderr = runGitWithProgress(
|
code, _, stderr = runGitWithProgress(
|
||||||
[]string{"fetch", "--progress", "origin"},
|
ctx, []string{"fetch", "--progress", "origin"},
|
||||||
local, 2*time.Hour, cb,
|
local, 2*time.Hour, cb,
|
||||||
)
|
)
|
||||||
if code != 0 {
|
if code != 0 {
|
||||||
@@ -405,13 +408,13 @@ func doCloneWithProgress(cfg RepoConfig, cb ProgressCallback) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// doPullWithProgress fait un pull avec suivi de progression.
|
// doPullWithProgress fait un pull avec suivi de progression.
|
||||||
func doPullWithProgress(res RepoResult, cb ProgressCallback) error {
|
func doPullWithProgress(ctx context.Context, res RepoResult, cb ProgressCallback) error {
|
||||||
_, branch, _ := runGit([]string{"rev-parse", "--abbrev-ref", "HEAD"}, res.Path, 5*time.Second)
|
_, branch, _ := runGit([]string{"rev-parse", "--abbrev-ref", "HEAD"}, res.Path, 5*time.Second)
|
||||||
if branch == "" {
|
if branch == "" {
|
||||||
branch = "master"
|
branch = "master"
|
||||||
}
|
}
|
||||||
code, _, stderr := runGitWithProgress(
|
code, _, stderr := runGitWithProgress(
|
||||||
[]string{"pull", "--progress", "origin", branch},
|
ctx, []string{"pull", "--progress", "origin", branch},
|
||||||
res.Path, 2*time.Hour, cb,
|
res.Path, 2*time.Hour, cb,
|
||||||
)
|
)
|
||||||
if code != 0 {
|
if code != 0 {
|
||||||
|
|||||||
49
gui.go
49
gui.go
@@ -2,6 +2,7 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"context"
|
||||||
_ "embed"
|
_ "embed"
|
||||||
"fmt"
|
"fmt"
|
||||||
"image"
|
"image"
|
||||||
@@ -222,10 +223,13 @@ type App struct {
|
|||||||
btnRefresh *walk.PushButton
|
btnRefresh *walk.PushButton
|
||||||
btnUpdateAll *walk.PushButton
|
btnUpdateAll *walk.PushButton
|
||||||
btnAction *walk.PushButton
|
btnAction *walk.PushButton
|
||||||
|
btnStop *walk.PushButton
|
||||||
|
|
||||||
reposConfig []RepoConfig
|
reposConfig []RepoConfig
|
||||||
suConfig SelfUpdateConfig
|
suConfig SelfUpdateConfig
|
||||||
checking atomic.Bool
|
checking atomic.Bool
|
||||||
|
cancelMu sync.Mutex
|
||||||
|
cancelFunc context.CancelFunc
|
||||||
}
|
}
|
||||||
|
|
||||||
func runApp() error {
|
func runApp() error {
|
||||||
@@ -327,6 +331,12 @@ func (a *App) buildAndRun() error {
|
|||||||
Enabled: false,
|
Enabled: false,
|
||||||
OnClicked: a.doAction,
|
OnClicked: a.doAction,
|
||||||
},
|
},
|
||||||
|
PushButton{
|
||||||
|
AssignTo: &a.btnStop,
|
||||||
|
Text: "Arrêter",
|
||||||
|
Enabled: false,
|
||||||
|
OnClicked: a.stopOperations,
|
||||||
|
},
|
||||||
HSpacer{},
|
HSpacer{},
|
||||||
PushButton{Text: "config.ini", OnClicked: a.openConfig},
|
PushButton{Text: "config.ini", OnClicked: a.openConfig},
|
||||||
PushButton{Text: "Logs", OnClicked: a.openLogs},
|
PushButton{Text: "Logs", OnClicked: a.openLogs},
|
||||||
@@ -540,6 +550,30 @@ func (a *App) makeProgressCB(row int) ProgressCallback {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ── Annulation ────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
// newCancelCtx crée un nouveau contexte annulable et stocke la fonction cancel.
|
||||||
|
func (a *App) newCancelCtx() context.Context {
|
||||||
|
a.cancelMu.Lock()
|
||||||
|
defer a.cancelMu.Unlock()
|
||||||
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
a.cancelFunc = cancel
|
||||||
|
return ctx
|
||||||
|
}
|
||||||
|
|
||||||
|
// stopOperations annule toutes les opérations git en cours.
|
||||||
|
func (a *App) stopOperations() {
|
||||||
|
a.cancelMu.Lock()
|
||||||
|
fn := a.cancelFunc
|
||||||
|
a.cancelFunc = nil
|
||||||
|
a.cancelMu.Unlock()
|
||||||
|
if fn != nil {
|
||||||
|
fn()
|
||||||
|
a.appendLog("Opérations annulées par l'utilisateur")
|
||||||
|
logInfo("Opérations annulées par l'utilisateur")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ── Actions dépôt ─────────────────────────────────────────────────────────────
|
// ── Actions dépôt ─────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
func (a *App) onSelectionChanged() {
|
func (a *App) onSelectionChanged() {
|
||||||
@@ -575,22 +609,25 @@ func (a *App) doAction() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
a.btnAction.SetEnabled(false)
|
a.btnAction.SetEnabled(false)
|
||||||
|
a.btnStop.SetEnabled(true)
|
||||||
a.appendLog(fmt.Sprintf("[%s] Mise à jour en cours...", res.Name))
|
a.appendLog(fmt.Sprintf("[%s] Mise à jour en cours...", res.Name))
|
||||||
|
|
||||||
|
ctx := a.newCancelCtx()
|
||||||
cb := a.makeProgressCB(idx)
|
cb := a.makeProgressCB(idx)
|
||||||
go func() {
|
go func() {
|
||||||
var err error
|
var err error
|
||||||
if res.NeedsClone {
|
if res.NeedsClone {
|
||||||
err = doCloneWithProgress(cfg, cb)
|
err = doCloneWithProgress(ctx, cfg, cb)
|
||||||
} else {
|
} else {
|
||||||
if res.LocalChanges > 0 {
|
if res.LocalChanges > 0 {
|
||||||
err = doCheckout(res)
|
err = doCheckout(res)
|
||||||
}
|
}
|
||||||
if err == nil && res.HasUpdate {
|
if err == nil && res.HasUpdate {
|
||||||
err = doPullWithProgress(res, cb)
|
err = doPullWithProgress(ctx, res, cb)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
a.mw.Synchronize(func() {
|
a.mw.Synchronize(func() {
|
||||||
|
a.btnStop.SetEnabled(false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
a.model.setProgress(idx, 0, "Erreur")
|
a.model.setProgress(idx, 0, "Erreur")
|
||||||
a.appendLog(fmt.Sprintf("[%s] Erreur: %v", res.Name, err))
|
a.appendLog(fmt.Sprintf("[%s] Erreur: %v", res.Name, err))
|
||||||
@@ -614,7 +651,9 @@ func (a *App) doAction() {
|
|||||||
func (a *App) updateAll() {
|
func (a *App) updateAll() {
|
||||||
a.btnUpdateAll.SetEnabled(false)
|
a.btnUpdateAll.SetEnabled(false)
|
||||||
a.btnRefresh.SetEnabled(false)
|
a.btnRefresh.SetEnabled(false)
|
||||||
|
a.btnStop.SetEnabled(true)
|
||||||
pending := atomic.Int32{}
|
pending := atomic.Int32{}
|
||||||
|
ctx := a.newCancelCtx()
|
||||||
|
|
||||||
for i, cfg := range a.reposConfig {
|
for i, cfg := range a.reposConfig {
|
||||||
res, ok := a.model.getResult(i)
|
res, ok := a.model.getResult(i)
|
||||||
@@ -627,13 +666,13 @@ func (a *App) updateAll() {
|
|||||||
go func() {
|
go func() {
|
||||||
var err error
|
var err error
|
||||||
if res.NeedsClone {
|
if res.NeedsClone {
|
||||||
err = doCloneWithProgress(cfg, cb)
|
err = doCloneWithProgress(ctx, cfg, cb)
|
||||||
} else {
|
} else {
|
||||||
if res.LocalChanges > 0 {
|
if res.LocalChanges > 0 {
|
||||||
err = doCheckout(res)
|
err = doCheckout(res)
|
||||||
}
|
}
|
||||||
if err == nil && res.HasUpdate {
|
if err == nil && res.HasUpdate {
|
||||||
err = doPullWithProgress(res, cb)
|
err = doPullWithProgress(ctx, res, cb)
|
||||||
}
|
}
|
||||||
if err == nil && res.UntrackedFiles > 0 {
|
if err == nil && res.UntrackedFiles > 0 {
|
||||||
err = doClean(res)
|
err = doClean(res)
|
||||||
@@ -650,12 +689,14 @@ func (a *App) updateAll() {
|
|||||||
a.appendLog(fmt.Sprintf("[%s] Mise à jour OK", res.Name))
|
a.appendLog(fmt.Sprintf("[%s] Mise à jour OK", res.Name))
|
||||||
}
|
}
|
||||||
if pending.Add(-1) == 0 {
|
if pending.Add(-1) == 0 {
|
||||||
|
a.btnStop.SetEnabled(false)
|
||||||
a.startCheck()
|
a.startCheck()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
if pending.Load() == 0 {
|
if pending.Load() == 0 {
|
||||||
|
a.btnStop.SetEnabled(false)
|
||||||
a.startCheck()
|
a.startCheck()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
2
main.go
2
main.go
@@ -9,7 +9,7 @@ import (
|
|||||||
"github.com/lxn/walk"
|
"github.com/lxn/walk"
|
||||||
)
|
)
|
||||||
|
|
||||||
const VERSION = "0.7.7"
|
const VERSION = "0.7.8"
|
||||||
|
|
||||||
func exeDir() string {
|
func exeDir() string {
|
||||||
exe, err := os.Executable()
|
exe, err := os.Executable()
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
0.7.7
|
0.7.8
|
||||||
|
|||||||
Reference in New Issue
Block a user