From ad11053412bdac59b5b743efb8b1f6a746093d98 Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Fri, 3 Oct 2014 01:34:22 +0400 Subject: [PATCH] Support for locking, unlocking, interruption, cleanup. #45 #114 --- cmd/mirror_drop.go | 5 ++++ cmd/mirror_edit.go | 5 ++++ cmd/mirror_rename.go | 5 ++++ cmd/mirror_show.go | 4 +++ cmd/mirror_update.go | 68 +++++++++++++++++++++++++++++++++++------- cmd/snapshot_create.go | 5 ++++ 6 files changed, 81 insertions(+), 11 deletions(-) diff --git a/cmd/mirror_drop.go b/cmd/mirror_drop.go index 97c62e40..ba9e8281 100644 --- a/cmd/mirror_drop.go +++ b/cmd/mirror_drop.go @@ -20,6 +20,11 @@ func aptlyMirrorDrop(cmd *commander.Command, args []string) error { return fmt.Errorf("unable to drop: %s", err) } + err = repo.CheckLock() + if err != nil { + return fmt.Errorf("unable to drop: %s", err) + } + force := context.flags.Lookup("force").Value.Get().(bool) if !force { snapshots := context.CollectionFactory().SnapshotCollection().ByRemoteRepoSource(repo) diff --git a/cmd/mirror_edit.go b/cmd/mirror_edit.go index 35e5747c..0cea1034 100644 --- a/cmd/mirror_edit.go +++ b/cmd/mirror_edit.go @@ -19,6 +19,11 @@ func aptlyMirrorEdit(cmd *commander.Command, args []string) error { return fmt.Errorf("unable to edit: %s", err) } + err = repo.CheckLock() + if err != nil { + return fmt.Errorf("unable to edit: %s", err) + } + context.flags.Visit(func(flag *flag.Flag) { switch flag.Name { case "filter": diff --git a/cmd/mirror_rename.go b/cmd/mirror_rename.go index 5cbfebe5..68d2f8e3 100644 --- a/cmd/mirror_rename.go +++ b/cmd/mirror_rename.go @@ -24,6 +24,11 @@ func aptlyMirrorRename(cmd *commander.Command, args []string) error { return fmt.Errorf("unable to rename: %s", err) } + err = repo.CheckLock() + if err != nil { + return fmt.Errorf("unable to rename: %s", err) + } + _, err = context.CollectionFactory().RemoteRepoCollection().ByName(newName) if err == nil { return fmt.Errorf("unable to rename: mirror %s already exists", newName) diff --git a/cmd/mirror_show.go b/cmd/mirror_show.go index b208c321..d2fea81f 100644 --- a/cmd/mirror_show.go +++ b/cmd/mirror_show.go @@ -2,6 +2,7 @@ package cmd import ( "fmt" + "github.com/smira/aptly/deb" "github.com/smira/aptly/utils" "github.com/smira/commander" "github.com/smira/flag" @@ -28,6 +29,9 @@ func aptlyMirrorShow(cmd *commander.Command, args []string) error { } fmt.Printf("Name: %s\n", repo.Name) + if repo.Status == deb.MirrorUpdating { + fmt.Printf("Status: In Update (PID %d)\n", repo.WorkerPID) + } fmt.Printf("Archive Root URL: %s\n", repo.ArchiveRoot) fmt.Printf("Distribution: %s\n", repo.Distribution) fmt.Printf("Components: %s\n", strings.Join(repo.Components, ", ")) diff --git a/cmd/mirror_update.go b/cmd/mirror_update.go index ab1adb7b..7d6eaa86 100644 --- a/cmd/mirror_update.go +++ b/cmd/mirror_update.go @@ -7,8 +7,9 @@ import ( "github.com/smira/aptly/utils" "github.com/smira/commander" "github.com/smira/flag" + "os" + "os/signal" "strings" - "time" ) func aptlyMirrorUpdate(cmd *commander.Command, args []string) error { @@ -30,6 +31,14 @@ func aptlyMirrorUpdate(cmd *commander.Command, args []string) error { return fmt.Errorf("unable to update: %s", err) } + force := context.flags.Lookup("force").Value.Get().(bool) + if !force { + err = repo.CheckLock() + if err != nil { + return fmt.Errorf("unable to update: %s", err) + } + } + ignoreMismatch := context.flags.Lookup("ignore-checksums").Value.Get().(bool) verifier, err := getVerifier(context.flags) @@ -76,6 +85,30 @@ func aptlyMirrorUpdate(cmd *commander.Command, args []string) error { return fmt.Errorf("unable to update: %s", err) } + defer func() { + // on any interreption, unlock the mirror + err := context.ReOpenDatabase() + if err == nil { + repo.MarkAsIdle() + context.CollectionFactory().RemoteRepoCollection().Update(repo) + } + }() + + repo.MarkAsUpdating() + err = context.CollectionFactory().RemoteRepoCollection().Update(repo) + if err != nil { + return fmt.Errorf("unable to update: %s", err) + } + + err = context.CloseDatabase() + if err != nil { + return fmt.Errorf("unable to update: %s", err) + } + + // Catch ^C + sigch := make(chan os.Signal) + signal.Notify(sigch, os.Interrupt) + count := len(queue) context.Progress().Printf("Download queue: %d items (%s)\n", count, utils.HumanBytes(downloadSize)) @@ -85,32 +118,44 @@ func aptlyMirrorUpdate(cmd *commander.Command, args []string) error { // Download all package files ch := make(chan error, count) - for _, task := range queue { - context.Downloader().DownloadWithChecksum(repo.PackageURL(task.RepoURI).String(), task.DestinationPath, ch, task.Checksums, ignoreMismatch) - } + go func() { + for _, task := range queue { + context.Downloader().DownloadWithChecksum(repo.PackageURL(task.RepoURI).String(), task.DestinationPath, ch, task.Checksums, ignoreMismatch) + } - // We don't need queued after this point - queue = nil + // We don't need queue after this point + queue = nil + }() // Wait for all downloads to finish errors := make([]string, 0) for count > 0 { - err = <-ch - if err != nil { - errors = append(errors, err.Error()) + select { + case <-sigch: + signal.Stop(sigch) + return fmt.Errorf("unable to update: interrupted") + case err = <-ch: + if err != nil { + errors = append(errors, err.Error()) + } + count-- } - count-- } context.Progress().ShutdownBar() + signal.Stop(sigch) if len(errors) > 0 { return fmt.Errorf("unable to update: download errors:\n %s\n", strings.Join(errors, "\n ")) } - repo.LastDownloadDate = time.Now() + err = context.ReOpenDatabase() + if err != nil { + return fmt.Errorf("unable to update: %s", err) + } + repo.FinalizeDownload() err = context.CollectionFactory().RemoteRepoCollection().Update(repo) if err != nil { return fmt.Errorf("unable to update: %s", err) @@ -137,6 +182,7 @@ Example: Flag: *flag.NewFlagSet("aptly-mirror-update", flag.ExitOnError), } + cmd.Flag.Bool("force", false, "force update mirror even if it is locked by another process") cmd.Flag.Bool("ignore-checksums", false, "ignore checksum mismatches while downloading package files and metadata") cmd.Flag.Bool("ignore-signatures", false, "disable verification of Release file signatures") cmd.Flag.Int64("download-limit", 0, "limit download speed (kbytes/sec)") diff --git a/cmd/snapshot_create.go b/cmd/snapshot_create.go index c4e34be9..aa9078fc 100644 --- a/cmd/snapshot_create.go +++ b/cmd/snapshot_create.go @@ -23,6 +23,11 @@ func aptlySnapshotCreate(cmd *commander.Command, args []string) error { return fmt.Errorf("unable to create snapshot: %s", err) } + err = repo.CheckLock() + if err != nil { + return fmt.Errorf("unable to create snapshot: %s", err) + } + err = context.CollectionFactory().RemoteRepoCollection().LoadComplete(repo) if err != nil { return fmt.Errorf("unable to create snapshot: %s", err)