From 0fa0f44e3d973479f0d7633e607eedc96783514c Mon Sep 17 00:00:00 2001 From: Christoph Fiehe Date: Wed, 2 Oct 2024 12:04:47 +0200 Subject: [PATCH] Allow to add/switch components of a published local repository This commit modifies the behavior of the publish switch method in the way, that it can also be used to add/switch components of a published local repository. Furthermore, the commit ensures that the sources returned by a published repository are ordered by their component names. Signed-off-by: Christoph Fiehe --- api/publish.go | 233 ++++++++++++++++---- api/router.go | 1 + cmd/publish_add.go | 175 +++++++++++++++ cmd/publish_show.go | 3 +- cmd/publish_snapshot.go | 7 +- cmd/publish_switch.go | 80 ++++--- cmd/publish_update.go | 9 +- completion.d/_aptly | 2 +- deb/publish.go | 42 +++- deb/publish_test.go | 13 +- man/aptly.1 | 8 +- system/t06_publish/AzurePublish2Test_gold | 2 +- system/t06_publish/AzurePublish3Test_gold | 2 +- system/t06_publish/PublishAdd1Test_gold | 8 + system/t06_publish/PublishAdd2Test_gold | 8 + system/t06_publish/PublishAdd3Test_gold | 1 + system/t06_publish/PublishSwitch11Test_gold | 2 +- system/t06_publish/PublishSwitch12Test_gold | 9 +- system/t06_publish/PublishSwitch13Test_gold | 2 +- system/t06_publish/PublishSwitch14Test_gold | 2 +- system/t06_publish/PublishSwitch15Test_gold | 2 +- system/t06_publish/PublishSwitch1Test_gold | 2 +- system/t06_publish/PublishSwitch2Test_gold | 2 +- system/t06_publish/PublishSwitch3Test_gold | 2 +- system/t06_publish/PublishSwitch4Test_gold | 2 +- system/t06_publish/PublishSwitch5Test_gold | 2 +- system/t06_publish/PublishSwitch6Test_gold | 2 +- system/t06_publish/PublishSwitch8Test_gold | 2 +- system/t06_publish/PublishUpdate10Test_gold | 2 +- system/t06_publish/PublishUpdate11Test_gold | 2 +- system/t06_publish/PublishUpdate12Test_gold | 2 +- system/t06_publish/PublishUpdate13Test_gold | 2 +- system/t06_publish/PublishUpdate1Test_gold | 2 +- system/t06_publish/PublishUpdate2Test_gold | 2 +- system/t06_publish/PublishUpdate3Test_gold | 2 +- system/t06_publish/PublishUpdate4Test_gold | 2 +- system/t06_publish/PublishUpdate7Test_gold | 2 +- system/t06_publish/PublishUpdate8Test_gold | 2 +- system/t06_publish/S3Publish2Test_gold | 2 +- system/t06_publish/S3Publish3Test_gold | 2 +- system/t06_publish/S3Publish6Test_gold | 2 +- system/t06_publish/SwiftPublish2Test_gold | 2 +- system/t06_publish/SwiftPublish3Test_gold | 2 +- system/t06_publish/add.py | 57 +++++ system/t06_publish/switch.py | 13 +- system/t12_api/publish.py | 4 +- 46 files changed, 588 insertions(+), 141 deletions(-) create mode 100644 cmd/publish_add.go create mode 100644 system/t06_publish/PublishAdd1Test_gold create mode 100644 system/t06_publish/PublishAdd2Test_gold create mode 100644 system/t06_publish/PublishAdd3Test_gold create mode 100644 system/t06_publish/add.py diff --git a/api/publish.go b/api/publish.go index a520878a0..a1024d523 100644 --- a/api/publish.go +++ b/api/publish.go @@ -52,10 +52,10 @@ func parseEscapedPath(path string) string { return result } -// @Summary Get publish points -// @Description Get list of available publish points. Each publish point is returned as in “show” API. +// @Summary Get published repositories +// @Description Get a list of published repositories. Each published repository is returned as in "show" API. // @Tags Publish -// @Produce json +// @Produce json // @Success 200 {array} deb.PublishedRepo // @Failure 500 {object} Error "Internal Error" // @Router /api/publish [get] @@ -84,7 +84,50 @@ func apiPublishList(c *gin.Context) { c.JSON(200, result) } -// POST /publish/:prefix +// @Summary Show published repository +// @Description Get published repository by name. +// @Tags Publish +// @Consume json +// @Produce json +// @Param prefix path string true "publishing prefix, use ':.' instead of '.' because it is ambigious in URLs" +// @Param distribution path string true "distribution name" +// @Success 200 {object} deb.RemoteRepo +// @Failure 404 {object} Error "Published repository not found" +// @Failure 500 {object} Error "Internal Error" +// @Router /api/publish/{prefix}/{distribution} [get] +func apiPublishShow(c *gin.Context) { + param := parseEscapedPath(c.Params.ByName("prefix")) + storage, prefix := deb.ParsePrefix(param) + distribution := parseEscapedPath(c.Params.ByName("distribution")) + + collectionFactory := context.NewCollectionFactory() + collection := collectionFactory.PublishedRepoCollection() + + published, err := collection.ByStoragePrefixDistribution(storage, prefix, distribution) + if err != nil { + AbortWithJSONError(c, http.StatusNotFound, fmt.Errorf("unable to show: %s", err)) + return + } + err = collection.LoadComplete(published, collectionFactory) + if err != nil { + AbortWithJSONError(c, 500, fmt.Errorf("unable to show: %s", err)) + return + } + + c.JSON(200, published) +} + +// @Summary Create published repository +// @Description Create a published repository with specified parameters. +// @Tags Publish +// @Accept json +// @Produce json +// @Param prefix path string true "publishing prefix" +// @Success 200 {object} deb.RemoteRepo +// @Failure 400 {object} Error "Bad Request" +// @Failure 404 {object} Error "Source not found" +// @Failure 500 {object} Error "Internal Error" +// @Router /api/publish/{prefix} [post] func apiPublishRepoOrSnapshot(c *gin.Context) { param := parseEscapedPath(c.Params.ByName("prefix")) storage, prefix := deb.ParsePrefix(param) @@ -106,7 +149,7 @@ func apiPublishRepoOrSnapshot(c *gin.Context) { Architectures []string Signing SigningOptions AcquireByHash *bool - MultiDist bool + MultiDist *bool } if c.Bind(&b) != nil { @@ -120,7 +163,7 @@ func apiPublishRepoOrSnapshot(c *gin.Context) { } if len(b.Sources) == 0 { - AbortWithJSONError(c, 400, fmt.Errorf("unable to publish: soures are empty")) + AbortWithJSONError(c, http.StatusBadRequest, fmt.Errorf("unable to publish: soures are empty")) return } @@ -141,7 +184,7 @@ func apiPublishRepoOrSnapshot(c *gin.Context) { snapshot, err = snapshotCollection.ByName(source.Name) if err != nil { - AbortWithJSONError(c, 404, fmt.Errorf("unable to publish: %s", err)) + AbortWithJSONError(c, http.StatusNotFound, fmt.Errorf("unable to publish: %s", err)) return } @@ -165,7 +208,7 @@ func apiPublishRepoOrSnapshot(c *gin.Context) { localRepo, err = localCollection.ByName(source.Name) if err != nil { - AbortWithJSONError(c, 404, fmt.Errorf("unable to publish: %s", err)) + AbortWithJSONError(c, http.StatusNotFound, fmt.Errorf("unable to publish: %s", err)) return } @@ -178,7 +221,7 @@ func apiPublishRepoOrSnapshot(c *gin.Context) { sources = append(sources, localRepo) } } else { - AbortWithJSONError(c, 400, fmt.Errorf("unknown SourceKind")) + AbortWithJSONError(c, http.StatusBadRequest, fmt.Errorf("unknown SourceKind")) return } @@ -191,7 +234,8 @@ func apiPublishRepoOrSnapshot(c *gin.Context) { resources = append(resources, string(published.Key())) collection := collectionFactory.PublishedRepoCollection() - taskName := fmt.Sprintf("Publish %s: %s", b.SourceKind, strings.Join(names, ", ")) + taskName := fmt.Sprintf("Publish %s repository %s/%s with components \"%s\" and sources \"%s\"", + b.SourceKind, published.StoragePrefix(), published.Distribution, strings.Join(components, `", "`), strings.Join(names, `", "`)) maybeRunTaskInBackground(c, taskName, resources, func(out aptly.Progress, detail *task.Detail) (*task.ProcessReturnValue, error) { taskDetail := task.PublishDetail{ Detail: detail, @@ -226,13 +270,17 @@ func apiPublishRepoOrSnapshot(c *gin.Context) { published.AcquireByHash = *b.AcquireByHash } + if b.MultiDist != nil { + published.MultiDist = *b.MultiDist + } + duplicate := collection.CheckDuplicate(published) if duplicate != nil { collectionFactory.PublishedRepoCollection().LoadComplete(duplicate, collectionFactory) return &task.ProcessReturnValue{Code: http.StatusBadRequest, Value: nil}, fmt.Errorf("prefix/distribution already used by another published repo: %s", duplicate) } - err := published.Publish(context.PackagePool(), context, collectionFactory, signer, publishOutput, b.ForceOverwrite, b.MultiDist) + err := published.Publish(context.PackagePool(), context, collectionFactory, signer, publishOutput, b.ForceOverwrite) if err != nil { return &task.ProcessReturnValue{Code: http.StatusInternalServerError, Value: nil}, fmt.Errorf("unable to publish: %s", err) } @@ -246,11 +294,22 @@ func apiPublishRepoOrSnapshot(c *gin.Context) { }) } -// PUT /publish/:prefix/:distribution +// @Summary Update published repository +// @Description Update a published repository. +// @Tags Publish +// @Accept json +// @Produce json +// @Param prefix path string true "publishing prefix" +// @Param distribution path string true "distribution name" +// @Success 200 {object} deb.RemoteRepo +// @Failure 400 {object} Error "Bad Request" +// @Failure 404 {object} Error "Published repository or source not found" +// @Failure 500 {object} Error "Internal Error" +// @Router /api/publish/{prefix}/{distribution} [put] func apiPublishUpdateSwitch(c *gin.Context) { param := parseEscapedPath(c.Params.ByName("prefix")) storage, prefix := deb.ParsePrefix(param) - distribution := c.Params.ByName("distribution") + distribution := parseEscapedPath(c.Params.ByName("distribution")) var b struct { ForceOverwrite bool @@ -262,8 +321,12 @@ func apiPublishUpdateSwitch(c *gin.Context) { Component string `binding:"required"` Name string `binding:"required"` } + Sources []struct { + Component string `binding:"required"` + Name string `binding:"required"` + } AcquireByHash *bool - MultiDist bool + MultiDist *bool } if c.Bind(&b) != nil { @@ -272,7 +335,7 @@ func apiPublishUpdateSwitch(c *gin.Context) { signer, err := getSigner(&b.Signing) if err != nil { - AbortWithJSONError(c, 500, fmt.Errorf("unable to initialize GPG signer: %s", err)) + AbortWithJSONError(c, http.StatusInternalServerError, fmt.Errorf("unable to initialize GPG signer: %s", err)) return } @@ -281,49 +344,113 @@ func apiPublishUpdateSwitch(c *gin.Context) { published, err := collection.ByStoragePrefixDistribution(storage, prefix, distribution) if err != nil { - AbortWithJSONError(c, 404, fmt.Errorf("unable to update: %s", err)) + AbortWithJSONError(c, http.StatusNotFound, fmt.Errorf("unable to update: %s", err)) return } + err = collection.LoadComplete(published, collectionFactory) if err != nil { - AbortWithJSONError(c, 500, fmt.Errorf("unable to update: %s", err)) + AbortWithJSONError(c, http.StatusInternalServerError, fmt.Errorf("unable to update: %s", err)) return } - var updatedComponents []string - var updatedSnapshots []string - var resources []string + var ( + sources map[string]string + updatedComponents []string + updatedSources []string + ) + + if b.Sources != nil { + sources = make(map[string]string, len(b.Sources)) + // For faster access, turn list of sources into map (component -> name) + for _, source := range b.Sources { + sources[source.Component] = source.Name + } + + // Determine those components, which must be removed from the published repository + for _, component := range published.Components() { + _, exists := sources[component] + if !exists { + published.RemoveComponent(component) + } + } + } if published.SourceKind == deb.SourceLocalRepo { if len(b.Snapshots) > 0 { - AbortWithJSONError(c, 400, fmt.Errorf("snapshots shouldn't be given when updating local repo")) + AbortWithJSONError(c, http.StatusNotFound, fmt.Errorf("snapshots shouldn't be given when updating local repo")) return } - updatedComponents = published.Components() - for _, component := range updatedComponents { - published.UpdateLocalRepo(component) + localRepoCollection := collectionFactory.LocalRepoCollection() + for component, name := range sources { + localRepo, err := localRepoCollection.ByName(name) + if err != nil { + AbortWithJSONError(c, http.StatusNotFound, err) + return + } + + err = localRepoCollection.LoadComplete(localRepo) + if err != nil { + AbortWithJSONError(c, http.StatusInternalServerError, err) + return + } + + sourceUUID, exists := published.Sources[component] + if exists { + if localRepo.UUID != sourceUUID { + published.UpsertLocalRepo(component, localRepo) + updatedComponents = append(updatedComponents, component) + updatedSources = append(updatedSources, name) + } + } else { + published.UpsertLocalRepo(component, localRepo) + updatedComponents = append(updatedComponents, component) + updatedSources = append(updatedSources, name) + } + } + } else if published.SourceKind == deb.SourceSnapshot { + // For reasons of backward compatibility, resort to the former 'Snapshots' attribute + // if the newer 'Sources' attribute is not specified. + if b.Sources == nil && b.Snapshots != nil { + fmt.Printf("@rDEPRECATION WARNING@|: The usage of the 'Snapshots' attribute for switching snapshots of a published repository is deprecated. " + + "Use the 'Sources' attribute instead and specify the entire sources list. " + + "Sources, which are missing in the list, but exist in the published repository, are removed. " + + "Support of the 'Snapshots' attribute is dropped in one of the following releases.") + + sources = make(map[string]string, len(b.Snapshots)) + for _, source := range b.Snapshots { + sources[source.Component] = source.Name + } } - } else if published.SourceKind == "snapshot" { - for _, snapshotInfo := range b.Snapshots { - snapshotCollection := collectionFactory.SnapshotCollection() - snapshot, err2 := snapshotCollection.ByName(snapshotInfo.Name) - if err2 != nil { - AbortWithJSONError(c, 404, err2) + snapshotCollection := collectionFactory.SnapshotCollection() + for component, name := range sources { + snapshot, err := snapshotCollection.ByName(name) + if err != nil { + AbortWithJSONError(c, http.StatusNotFound, err) return } - err2 = snapshotCollection.LoadComplete(snapshot) - if err2 != nil { - AbortWithJSONError(c, 500, err2) + err = snapshotCollection.LoadComplete(snapshot) + if err != nil { + AbortWithJSONError(c, http.StatusInternalServerError, err) return } - published.UpdateSnapshot(snapshotInfo.Component, snapshot) - updatedComponents = append(updatedComponents, snapshotInfo.Component) - updatedSnapshots = append(updatedSnapshots, snapshot.Name) + sourceUUID, exists := published.Sources[component] + if exists { + if snapshot.UUID != sourceUUID { + published.UpsertSnapshot(component, snapshot) + updatedComponents = append(updatedComponents, component) + updatedSources = append(updatedSources, name) + } + } else { + published.UpsertSnapshot(component, snapshot) + updatedComponents = append(updatedComponents, component) + updatedSources = append(updatedSources, name) + } } } else { - AbortWithJSONError(c, 500, fmt.Errorf("unknown published repository type")) + AbortWithJSONError(c, http.StatusInternalServerError, fmt.Errorf("unknown published repository type")) return } @@ -339,10 +466,17 @@ func apiPublishUpdateSwitch(c *gin.Context) { published.AcquireByHash = *b.AcquireByHash } - resources = append(resources, string(published.Key())) - taskName := fmt.Sprintf("Update published %s (%s): %s", published.SourceKind, strings.Join(updatedComponents, " "), strings.Join(updatedSnapshots, ", ")) + if b.MultiDist != nil { + published.MultiDist = *b.MultiDist + } + + resources := []string{string(published.Key())} + + taskName := fmt.Sprintf("Update published %s repository %s/%s with components \"%s\" and sources \"%s\"", + published.SourceKind, published.StoragePrefix(), published.Distribution, strings.Join(updatedComponents, `", "`), + strings.Join(updatedSources, `", "`)) maybeRunTaskInBackground(c, taskName, resources, func(out aptly.Progress, _ *task.Detail) (*task.ProcessReturnValue, error) { - err := published.Publish(context.PackagePool(), context, collectionFactory, signer, out, b.ForceOverwrite, b.MultiDist) + err := published.Publish(context.PackagePool(), context, collectionFactory, signer, out, b.ForceOverwrite) if err != nil { return &task.ProcessReturnValue{Code: http.StatusInternalServerError, Value: nil}, fmt.Errorf("unable to update: %s", err) } @@ -364,14 +498,27 @@ func apiPublishUpdateSwitch(c *gin.Context) { }) } -// DELETE /publish/:prefix/:distribution +// @Summary Delete published repository +// @Description Delete a published repository. +// @Tags Publish +// @Accept json +// @Produce json +// @Param prefix path string true "publishing prefix" +// @Param distribution path string true "distribution name" +// @Param force query int true "force: 1 to enable" +// @Param skipCleanup query int true "skipCleanup: 1 to enable" +// @Success 200 {object} task.ProcessReturnValue +// @Failure 400 {object} Error "Bad Request" +// @Failure 404 {object} Error "Published repository not found" +// @Failure 500 {object} Error "Internal Error" +// @Router /api/publish/{prefix}/{distribution} [delete] func apiPublishDrop(c *gin.Context) { force := c.Request.URL.Query().Get("force") == "1" skipCleanup := c.Request.URL.Query().Get("SkipCleanup") == "1" param := parseEscapedPath(c.Params.ByName("prefix")) storage, prefix := deb.ParsePrefix(param) - distribution := c.Params.ByName("distribution") + distribution := parseEscapedPath(c.Params.ByName("distribution")) collectionFactory := context.NewCollectionFactory() collection := collectionFactory.PublishedRepoCollection() @@ -384,7 +531,7 @@ func apiPublishDrop(c *gin.Context) { resources := []string{string(published.Key())} - taskName := fmt.Sprintf("Delete published %s (%s)", prefix, distribution) + taskName := fmt.Sprintf("Delete published %s repository %s/%s", published.SourceKind, published.StoragePrefix(), published.Distribution) maybeRunTaskInBackground(c, taskName, resources, func(out aptly.Progress, _ *task.Detail) (*task.ProcessReturnValue, error) { err := collection.Remove(context, storage, prefix, distribution, collectionFactory, out, force, skipCleanup) diff --git a/api/router.go b/api/router.go index d5b6e6123..7811c08d9 100644 --- a/api/router.go +++ b/api/router.go @@ -187,6 +187,7 @@ func Router(c *ctx.AptlyContext) http.Handler { { api.GET("/publish", apiPublishList) + api.GET("/publish/:prefix/:distribution", apiPublishShow) api.POST("/publish", apiPublishRepoOrSnapshot) api.POST("/publish/:prefix", apiPublishRepoOrSnapshot) api.PUT("/publish/:prefix/:distribution", apiPublishUpdateSwitch) diff --git a/cmd/publish_add.go b/cmd/publish_add.go new file mode 100644 index 000000000..72603d4f7 --- /dev/null +++ b/cmd/publish_add.go @@ -0,0 +1,175 @@ +package cmd + +import ( + "fmt" + "strings" + + "github.com/aptly-dev/aptly/deb" + "github.com/aptly-dev/aptly/utils" + "github.com/smira/commander" + "github.com/smira/flag" +) + +func aptlyPublishAdd(cmd *commander.Command, args []string) error { + var ( + err error + names []string + published *deb.PublishedRepo + ) + + components := strings.Split(context.Flags().Lookup("component").Value.String(), ",") + + if len(args) < len(components)+1 || len(args) > len(components)+2 { + cmd.Usage() + return commander.ErrCommandError + } + + distribution := args[0] + param := "." + + if len(args) == len(components)+2 { + param = args[1] + names = args[2:] + } else { + names = args[1:] + } + + if len(names) != len(components) { + return fmt.Errorf("mismatch in number of components (%d) and sources (%d)", len(components), len(names)) + } + + storage, prefix := deb.ParsePrefix(param) + + collectionFactory := context.NewCollectionFactory() + published, err = collectionFactory.PublishedRepoCollection().ByStoragePrefixDistribution(storage, prefix, distribution) + if err != nil { + return fmt.Errorf("unable to add: %s", err) + } + + err = collectionFactory.PublishedRepoCollection().LoadComplete(published, collectionFactory) + if err != nil { + return fmt.Errorf("unable to add: %s", err) + } + + publishedComponents := published.Components() + + if published.SourceKind == deb.SourceLocalRepo { + localRepoCollection := collectionFactory.LocalRepoCollection() + for i, component := range components { + if utils.StrSliceHasItem(publishedComponents, component) { + return fmt.Errorf("unable to add: component %s already exists in published local repository", component) + } + + localRepo, err := localRepoCollection.ByName(names[i]) + if err != nil { + return fmt.Errorf("unable to add: %s", err) + } + + err = localRepoCollection.LoadComplete(localRepo) + if err != nil { + return fmt.Errorf("unable to add: %s", err) + } + + published.UpsertLocalRepo(component, localRepo) + } + } else if published.SourceKind == deb.SourceSnapshot { + snapshotCollection := collectionFactory.SnapshotCollection() + for i, component := range components { + if utils.StrSliceHasItem(publishedComponents, component) { + return fmt.Errorf("unable to add: component %s already exists in published snapshot repository", component) + } + + snapshot, err := snapshotCollection.ByName(names[i]) + if err != nil { + return fmt.Errorf("unable to add: %s", err) + } + + err = snapshotCollection.LoadComplete(snapshot) + if err != nil { + return fmt.Errorf("unable to add: %s", err) + } + + published.UpsertSnapshot(component, snapshot) + } + } else { + return fmt.Errorf("unknown published repository type") + } + + signer, err := getSigner(context.Flags()) + if err != nil { + return fmt.Errorf("unable to initialize GPG signer: %s", err) + } + + forceOverwrite := context.Flags().Lookup("force-overwrite").Value.Get().(bool) + if forceOverwrite { + context.Progress().ColoredPrintf("@rWARNING@|: force overwrite mode enabled, aptly might corrupt other published repositories sharing " + + "the same package pool.\n") + } + + if context.Flags().IsSet("skip-contents") { + published.SkipContents = context.Flags().Lookup("skip-contents").Value.Get().(bool) + } + + if context.Flags().IsSet("skip-bz2") { + published.SkipBz2 = context.Flags().Lookup("skip-bz2").Value.Get().(bool) + } + + if context.Flags().IsSet("multi-dist") { + published.MultiDist = context.Flags().Lookup("multi-dist").Value.Get().(bool) + } + + err = published.Publish(context.PackagePool(), context, collectionFactory, signer, context.Progress(), forceOverwrite) + if err != nil { + return fmt.Errorf("unable to publish: %s", err) + } + + err = collectionFactory.PublishedRepoCollection().Update(published) + if err != nil { + return fmt.Errorf("unable to save to DB: %s", err) + } + + context.Progress().Printf("\nPublished %s repository %s has been successfully updated by adding new source.\n", published.SourceKind, published.String()) + + return err +} + +func makeCmdPublishAdd() *commander.Command { + cmd := &commander.Command{ + Run: aptlyPublishAdd, + UsageLine: "add [[:]] ", + Short: "add package source to published repository", + Long: ` +The command adds (in place) one or multiple package sources to a published repository. +All publishing parameters are preserved (architecture list, distribution, ...). + +The flag -component is mandatory. Use a comma-separated list of components, +if multiple components should be added. The number of given components must be +equal to the number of sources, e.g.: + + aptly publish add -component=main,contrib wheezy wheezy-main wheezy-contrib + +Example: + + $ aptly publish add -component=contrib wheezy ppa wheezy-contrib + +This command assigns the snapshot wheezy-contrib to the component contrib and +adds it as new package source to the published repository ppa/wheezy. +`, + Flag: *flag.NewFlagSet("aptly-publish-add", flag.ExitOnError), + } + cmd.Flag.String("gpg-key", "", "GPG key ID to use when signing the release") + cmd.Flag.Var(&keyRingsFlag{}, "keyring", "GPG keyring to use (instead of default)") + cmd.Flag.String("secret-keyring", "", "GPG secret keyring to use (instead of default)") + cmd.Flag.String("passphrase", "", "GPG passphrase for the key (warning: could be insecure)") + cmd.Flag.String("passphrase-file", "", "GPG passphrase-file for the key (warning: could be insecure)") + cmd.Flag.String("prefix", "", "publishing prefix in the form of [:]") + cmd.Flag.Bool("batch", false, "run GPG with detached tty") + cmd.Flag.Bool("skip-signing", false, "don't sign Release files with GPG") + cmd.Flag.Bool("skip-contents", false, "don't generate Contents indexes") + cmd.Flag.Bool("skip-bz2", false, "don't generate bzipped indexes") + cmd.Flag.String("component", "", "component names to add (for multi-component publishing, separate components with commas)") + cmd.Flag.Bool("force-overwrite", false, "overwrite files in package pool in case of mismatch") + cmd.Flag.Bool("multi-dist", false, "enable multiple packages with the same filename in different distributions") + + return cmd +} diff --git a/cmd/publish_show.go b/cmd/publish_show.go index d943df3fa..a0af446b1 100644 --- a/cmd/publish_show.go +++ b/cmd/publish_show.go @@ -52,7 +52,8 @@ func aptlyPublishShowTxt(_ *commander.Command, args []string) error { fmt.Printf("Architectures: %s\n", strings.Join(repo.Architectures, " ")) fmt.Printf("Sources:\n") - for component, sourceID := range repo.Sources { + for _, component := range repo.Components() { + sourceID := repo.Sources[component] var name string if repo.SourceKind == deb.SourceSnapshot { source, e := collectionFactory.SnapshotCollection().ByUUID(sourceID) diff --git a/cmd/publish_snapshot.go b/cmd/publish_snapshot.go index 1e79fac27..ace4f6d2d 100644 --- a/cmd/publish_snapshot.go +++ b/cmd/publish_snapshot.go @@ -116,7 +116,6 @@ func aptlyPublishSnapshotOrRepo(cmd *commander.Command, args []string) error { origin := context.Flags().Lookup("origin").Value.String() notAutomatic := context.Flags().Lookup("notautomatic").Value.String() butAutomaticUpgrades := context.Flags().Lookup("butautomaticupgrades").Value.String() - multiDist := context.Flags().Lookup("multi-dist").Value.Get().(bool) published, err := deb.NewPublishedRepo(storage, prefix, distribution, context.ArchitecturesList(), components, sources, collectionFactory) if err != nil { @@ -150,6 +149,10 @@ func aptlyPublishSnapshotOrRepo(cmd *commander.Command, args []string) error { published.AcquireByHash = context.Flags().Lookup("acquire-by-hash").Value.Get().(bool) } + if context.Flags().IsSet("multi-dist") { + published.MultiDist = context.Flags().Lookup("multi-dist").Value.Get().(bool) + } + duplicate := collectionFactory.PublishedRepoCollection().CheckDuplicate(published) if duplicate != nil { collectionFactory.PublishedRepoCollection().LoadComplete(duplicate, collectionFactory) @@ -166,7 +169,7 @@ func aptlyPublishSnapshotOrRepo(cmd *commander.Command, args []string) error { context.Progress().ColoredPrintf("@rWARNING@|: force overwrite mode enabled, aptly might corrupt other published repositories sharing the same package pool.\n") } - err = published.Publish(context.PackagePool(), context, collectionFactory, signer, context.Progress(), forceOverwrite, multiDist) + err = published.Publish(context.PackagePool(), context, collectionFactory, signer, context.Progress(), forceOverwrite) if err != nil { return fmt.Errorf("unable to publish: %s", err) } diff --git a/cmd/publish_switch.go b/cmd/publish_switch.go index a55347475..51882cbe6 100644 --- a/cmd/publish_switch.go +++ b/cmd/publish_switch.go @@ -5,15 +5,18 @@ import ( "strings" "github.com/aptly-dev/aptly/deb" + "github.com/aptly-dev/aptly/utils" "github.com/smira/commander" "github.com/smira/flag" ) func aptlyPublishSwitch(cmd *commander.Command, args []string) error { - var err error + var ( + err error + names []string + ) components := strings.Split(context.Flags().Lookup("component").Value.String(), ",") - multiDist := context.Flags().Lookup("multi-dist").Value.Get().(bool) if len(args) < len(components)+1 || len(args) > len(components)+2 { cmd.Usage() @@ -23,11 +26,6 @@ func aptlyPublishSwitch(cmd *commander.Command, args []string) error { distribution := args[0] param := "." - var ( - names []string - snapshot *deb.Snapshot - ) - if len(args) == len(components)+2 { param = args[1] names = args[2:] @@ -45,10 +43,6 @@ func aptlyPublishSwitch(cmd *commander.Command, args []string) error { return fmt.Errorf("unable to update: %s", err) } - if published.SourceKind != deb.SourceSnapshot { - return fmt.Errorf("unable to update: not a snapshot publish") - } - err = collectionFactory.PublishedRepoCollection().LoadComplete(published, collectionFactory) if err != nil { return fmt.Errorf("unable to update: %s", err) @@ -63,18 +57,46 @@ func aptlyPublishSwitch(cmd *commander.Command, args []string) error { return fmt.Errorf("mismatch in number of components (%d) and snapshots (%d)", len(components), len(names)) } - for i, component := range components { - snapshot, err = collectionFactory.SnapshotCollection().ByName(names[i]) - if err != nil { - return fmt.Errorf("unable to switch: %s", err) - } + if published.SourceKind == deb.SourceLocalRepo { + localRepoCollection := collectionFactory.LocalRepoCollection() + for i, component := range components { + if !utils.StrSliceHasItem(publishedComponents, component) { + return fmt.Errorf("unable to switch: component %s does not exist in published repository", component) + } - err = collectionFactory.SnapshotCollection().LoadComplete(snapshot) - if err != nil { - return fmt.Errorf("unable to switch: %s", err) - } + localRepo, err := localRepoCollection.ByName(names[i]) + if err != nil { + return fmt.Errorf("unable to switch: %s", err) + } - published.UpdateSnapshot(component, snapshot) + err = localRepoCollection.LoadComplete(localRepo) + if err != nil { + return fmt.Errorf("unable to switch: %s", err) + } + + published.UpsertLocalRepo(component, localRepo) + } + } else if published.SourceKind == deb.SourceSnapshot { + snapshotCollection := collectionFactory.SnapshotCollection() + for i, component := range components { + if !utils.StrSliceHasItem(publishedComponents, component) { + return fmt.Errorf("unable to switch: component %s does not exist in published repository", component) + } + + snapshot, err := snapshotCollection.ByName(names[i]) + if err != nil { + return fmt.Errorf("unable to switch: %s", err) + } + + err = snapshotCollection.LoadComplete(snapshot) + if err != nil { + return fmt.Errorf("unable to switch: %s", err) + } + + published.UpsertSnapshot(component, snapshot) + } + } else { + return fmt.Errorf("unknown published repository type") } signer, err := getSigner(context.Flags()) @@ -96,7 +118,11 @@ func aptlyPublishSwitch(cmd *commander.Command, args []string) error { published.SkipBz2 = context.Flags().Lookup("skip-bz2").Value.Get().(bool) } - err = published.Publish(context.PackagePool(), context, collectionFactory, signer, context.Progress(), forceOverwrite, multiDist) + if context.Flags().IsSet("multi-dist") { + published.MultiDist = context.Flags().Lookup("multi-dist").Value.Get().(bool) + } + + err = published.Publish(context.PackagePool(), context, collectionFactory, signer, context.Progress(), forceOverwrite) if err != nil { return fmt.Errorf("unable to publish: %s", err) } @@ -115,7 +141,7 @@ func aptlyPublishSwitch(cmd *commander.Command, args []string) error { } } - context.Progress().Printf("\nPublish for snapshot %s has been successfully switched to new snapshot.\n", published.String()) + context.Progress().Printf("\nPublished %s repository %s has been successfully switched to new source.\n", published.SourceKind, published.String()) return err } @@ -123,15 +149,15 @@ func aptlyPublishSwitch(cmd *commander.Command, args []string) error { func makeCmdPublishSwitch() *commander.Command { cmd := &commander.Command{ Run: aptlyPublishSwitch, - UsageLine: "switch [[:]] ", - Short: "update published repository by switching to new snapshot", + UsageLine: "switch [[:]] ", + Short: "update published repository by switching to new source", Long: ` -Command switches in-place published snapshots with new snapshot contents. All +Command switches in-place published snapshots with new source contents. All publishing parameters are preserved (architecture list, distribution, component). For multiple component repositories, flag -component should be given with -list of components to update. Corresponding snapshots should be given in the +list of components to update. Corresponding sources should be given in the same order, e.g.: aptly publish switch -component=main,contrib wheezy wh-main wh-contrib diff --git a/cmd/publish_update.go b/cmd/publish_update.go index 9bceda509..00ba02319 100644 --- a/cmd/publish_update.go +++ b/cmd/publish_update.go @@ -17,7 +17,6 @@ func aptlyPublishUpdate(cmd *commander.Command, args []string) error { distribution := args[0] param := "." - multiDist := context.Flags().Lookup("multi-dist").Value.Get().(bool) if len(args) == 2 { param = args[1] @@ -65,7 +64,11 @@ func aptlyPublishUpdate(cmd *commander.Command, args []string) error { published.SkipBz2 = context.Flags().Lookup("skip-bz2").Value.Get().(bool) } - err = published.Publish(context.PackagePool(), context, collectionFactory, signer, context.Progress(), forceOverwrite, multiDist) + if context.Flags().IsSet("multi-dist") { + published.MultiDist = context.Flags().Lookup("multi-dist").Value.Get().(bool) + } + + err = published.Publish(context.PackagePool(), context, collectionFactory, signer, context.Progress(), forceOverwrite) if err != nil { return fmt.Errorf("unable to publish: %s", err) } @@ -84,7 +87,7 @@ func aptlyPublishUpdate(cmd *commander.Command, args []string) error { } } - context.Progress().Printf("\nPublish for local repo %s has been successfully updated.\n", published.String()) + context.Progress().Printf("\nPublished %s repository %s has been successfully updated.\n", published.SourceKind, published.String()) return err } diff --git a/completion.d/_aptly b/completion.d/_aptly index 8e8d2bbd6..362d23cc0 100644 --- a/completion.d/_aptly +++ b/completion.d/_aptly @@ -92,7 +92,7 @@ local keyring="*-keyring=[gpg keyring to use when verifying Release file (could "list[list published repositories]" \ "repo[publish local repository]" \ "snapshot[publish snapshot]" \ - "switch[update published repository by switching to new snapshot]" \ + "switch[update published repository by switching to new source]" \ "update[update published local repository]" \ "show[shows details of published repository]" ret=0 ;; diff --git a/deb/publish.go b/deb/publish.go index 2bdd608de..fb13de608 100644 --- a/deb/publish.go +++ b/deb/publish.go @@ -46,7 +46,7 @@ type PublishedRepo struct { Codename string // Architectures is a list of all architectures published Architectures []string - // SourceKind is "local"/"repo" + // SourceKind is "local"/"snapshot" SourceKind string // Map of sources by each component: component name -> source UUID @@ -70,6 +70,9 @@ type PublishedRepo struct { // Provide index files per hash also AcquireByHash bool + + // Enable multiple packages with same filename in different distributions + MultiDist bool } // ParsePrefix splits [storage:]prefix into components @@ -284,7 +287,8 @@ func (p *PublishedRepo) MarshalJSON() ([]byte, error) { } sources := []sourceInfo{} - for component, item := range p.sourceItems { + for _, component := range p.Components() { + item := p.sourceItems[component] name := "" if item.snapshot != nil { name = item.snapshot.Name @@ -452,8 +456,26 @@ func (p *PublishedRepo) UpdateLocalRepo(component string) { p.rePublishing = true } -// UpdateSnapshot switches snapshot for component -func (p *PublishedRepo) UpdateSnapshot(component string, snapshot *Snapshot) { +// UpsertLocalRepo inserts/updates local repository source for component +func (p *PublishedRepo) UpsertLocalRepo(component string, localRepo *LocalRepo) { + if p.SourceKind != SourceLocalRepo { + panic("not local repo publish") + } + + item, exists := p.sourceItems[component] + if !exists { + item = repoSourceItem{} + } + item.localRepo = localRepo + item.packageRefs = localRepo.RefList() + p.sourceItems[component] = item + + p.Sources[component] = localRepo.UUID + p.rePublishing = true +} + +// UpsertSnapshot inserts/updates snapshot source for component +func (p *PublishedRepo) UpsertSnapshot(component string, snapshot *Snapshot) { if p.SourceKind != SourceSnapshot { panic("not snapshot publish") } @@ -469,6 +491,14 @@ func (p *PublishedRepo) UpdateSnapshot(component string, snapshot *Snapshot) { p.rePublishing = true } +// RemoveComponent removes component from published repository +func (p *PublishedRepo) RemoveComponent(component string) { + delete(p.Sources, component) + delete(p.sourceItems, component) + + p.rePublishing = true +} + // Encode does msgpack encoding of PublishedRepo func (p *PublishedRepo) Encode() []byte { var buf bytes.Buffer @@ -547,7 +577,7 @@ func (p *PublishedRepo) GetCodename() string { // Publish publishes snapshot (repository) contents, links package files, generates Packages & Release files, signs them func (p *PublishedRepo) Publish(packagePool aptly.PackagePool, publishedStorageProvider aptly.PublishedStorageProvider, - collectionFactory *CollectionFactory, signer pgp.Signer, progress aptly.Progress, forceOverwrite, multiDist bool) error { + collectionFactory *CollectionFactory, signer pgp.Signer, progress aptly.Progress, forceOverwrite bool) error { publishedStorage := publishedStorageProvider.GetPublishedStorage(p.Storage) err := publishedStorage.MkDir(filepath.Join(p.Prefix, "pool")) @@ -659,7 +689,7 @@ func (p *PublishedRepo) Publish(packagePool aptly.PackagePool, publishedStorageP if err2 != nil { return err2 } - if multiDist { + if p.MultiDist { relPath = filepath.Join("pool", p.Distribution, component, poolDir) } else { relPath = filepath.Join("pool", component, poolDir) diff --git a/deb/publish_test.go b/deb/publish_test.go index 6fdad759a..91b6565fa 100644 --- a/deb/publish_test.go +++ b/deb/publish_test.go @@ -196,7 +196,8 @@ func (s *PublishedRepoSuite) TestNewPublishedRepo(c *C) { func (s *PublishedRepoSuite) TestMultiDistPool(c *C) { repo, err := NewPublishedRepo("", "ppa", "squeeze", nil, []string{"main"}, []interface{}{s.snapshot}, s.factory) c.Assert(err, IsNil) - err = repo.Publish(s.packagePool, s.provider, s.factory, &NullSigner{}, nil, false, true) + repo.MultiDist = true + err = repo.Publish(s.packagePool, s.provider, s.factory, &NullSigner{}, nil, false) c.Assert(err, IsNil) publishedStorage := files.NewPublishedStorage(s.root, "", "") @@ -360,7 +361,7 @@ func (s *PublishedRepoSuite) TestDistributionComponentGuessing(c *C) { } func (s *PublishedRepoSuite) TestPublish(c *C) { - err := s.repo.Publish(s.packagePool, s.provider, s.factory, &NullSigner{}, nil, false, false) + err := s.repo.Publish(s.packagePool, s.provider, s.factory, &NullSigner{}, nil, false) c.Assert(err, IsNil) c.Check(s.repo.Architectures, DeepEquals, []string{"i386"}) @@ -407,7 +408,7 @@ func (s *PublishedRepoSuite) TestPublish(c *C) { } func (s *PublishedRepoSuite) TestPublishNoSigner(c *C) { - err := s.repo.Publish(s.packagePool, s.provider, s.factory, nil, nil, false, false) + err := s.repo.Publish(s.packagePool, s.provider, s.factory, nil, nil, false) c.Assert(err, IsNil) c.Check(filepath.Join(s.publishedStorage.PublicPath(), "ppa/dists/squeeze/Release"), PathExists) @@ -415,7 +416,7 @@ func (s *PublishedRepoSuite) TestPublishNoSigner(c *C) { } func (s *PublishedRepoSuite) TestPublishLocalRepo(c *C) { - err := s.repo2.Publish(s.packagePool, s.provider, s.factory, nil, nil, false, false) + err := s.repo2.Publish(s.packagePool, s.provider, s.factory, nil, nil, false) c.Assert(err, IsNil) c.Check(filepath.Join(s.publishedStorage.PublicPath(), "ppa/dists/maverick/Release"), PathExists) @@ -423,7 +424,7 @@ func (s *PublishedRepoSuite) TestPublishLocalRepo(c *C) { } func (s *PublishedRepoSuite) TestPublishLocalSourceRepo(c *C) { - err := s.repo4.Publish(s.packagePool, s.provider, s.factory, nil, nil, false, false) + err := s.repo4.Publish(s.packagePool, s.provider, s.factory, nil, nil, false) c.Assert(err, IsNil) c.Check(filepath.Join(s.publishedStorage.PublicPath(), "ppa/dists/maverick/Release"), PathExists) @@ -431,7 +432,7 @@ func (s *PublishedRepoSuite) TestPublishLocalSourceRepo(c *C) { } func (s *PublishedRepoSuite) TestPublishOtherStorage(c *C) { - err := s.repo5.Publish(s.packagePool, s.provider, s.factory, nil, nil, false, false) + err := s.repo5.Publish(s.packagePool, s.provider, s.factory, nil, nil, false) c.Assert(err, IsNil) c.Check(filepath.Join(s.publishedStorage2.PublicPath(), "ppa/dists/maverick/Release"), PathExists) diff --git a/man/aptly.1 b/man/aptly.1 index fe986f0ff..4ab370468 100644 --- a/man/aptly.1 +++ b/man/aptly.1 @@ -1616,14 +1616,14 @@ suite to publish (defaults to distribution) \-\fBcodename\fR= codename to publish (defaults to distribution) . -.SH "UPDATE PUBLISHED REPOSITORY BY SWITCHING TO NEW SNAPSHOT" -\fBaptly\fR \fBpublish\fR \fBswitch\fR \fIdistribution\fR [[\fIendpoint\fR:]\fIprefix\fR] \fInew\-snapshot\fR +.SH "UPDATE PUBLISHED REPOSITORY BY SWITCHING TO NEW SOURCE" +\fBaptly\fR \fBpublish\fR \fBswitch\fR \fIdistribution\fR [[\fIendpoint\fR:]\fIprefix\fR] \fInew\-source\fR . .P -Command switches in\-place published snapshots with new snapshot contents\. All publishing parameters are preserved (architecture list, distribution, component)\. +Command switches in\-place published sources with new source contents\. All publishing parameters are preserved (architecture list, distribution, component)\. . .P -For multiple component repositories, flag \-component should be given with list of components to update\. Corresponding snapshots should be given in the same order, e\.g\.: +For multiple component repositories, flag \-component should be given with list of components to update\. Corresponding sources should be given in the same order, e\.g\.: . .IP "" 4 . diff --git a/system/t06_publish/AzurePublish2Test_gold b/system/t06_publish/AzurePublish2Test_gold index d9fa9ada0..ea8cafb98 100644 --- a/system/t06_publish/AzurePublish2Test_gold +++ b/system/t06_publish/AzurePublish2Test_gold @@ -5,4 +5,4 @@ Signing file 'Release' with gpg, please enter your passphrase when prompted: Clearsigning file 'Release' with gpg, please enter your passphrase when prompted: Cleaning up prefix "." components main... -Publish for local repo azure:test1:./maverick [i386, source] publishes {main: [local-repo]} has been successfully updated. +Published local repository azure:test1:./maverick [i386, source] publishes {main: [local-repo]} has been successfully updated. diff --git a/system/t06_publish/AzurePublish3Test_gold b/system/t06_publish/AzurePublish3Test_gold index fbcd2e792..c18551698 100644 --- a/system/t06_publish/AzurePublish3Test_gold +++ b/system/t06_publish/AzurePublish3Test_gold @@ -5,4 +5,4 @@ Signing file 'Release' with gpg, please enter your passphrase when prompted: Clearsigning file 'Release' with gpg, please enter your passphrase when prompted: Cleaning up prefix "." components main... -Publish for snapshot azure:test1:./maverick (origin: LP-PPA-gladky-anton-gnuplot) [amd64, i386] publishes {main: [snap3]: Pulled into 'snap2' with 'snap1' as source, pull request was: 'gnuplot-x11'} has been successfully switched to new snapshot. +Published snapshot repository azure:test1:./maverick (origin: LP-PPA-gladky-anton-gnuplot) [amd64, i386] publishes {main: [snap3]: Pulled into 'snap2' with 'snap1' as source, pull request was: 'gnuplot-x11'} has been successfully switched to new source. diff --git a/system/t06_publish/PublishAdd1Test_gold b/system/t06_publish/PublishAdd1Test_gold new file mode 100644 index 000000000..0a36770d6 --- /dev/null +++ b/system/t06_publish/PublishAdd1Test_gold @@ -0,0 +1,8 @@ +Loading packages... +Generating metadata files and linking package files... +Finalizing metadata files... +Signing file 'Release' with gpg, please enter your passphrase when prompted: +Clearsigning file 'Release' with gpg, please enter your passphrase when prompted: +Cleaning up prefix "." components a, c... + +Published snapshot repository ./maverick [i386] publishes {a: [snap2]: Created as empty}, {b: [snap2]: Created as empty}, {c: [snap3]: Created as empty} has been successfully switched to new source. diff --git a/system/t06_publish/PublishAdd2Test_gold b/system/t06_publish/PublishAdd2Test_gold new file mode 100644 index 000000000..3a36cf09e --- /dev/null +++ b/system/t06_publish/PublishAdd2Test_gold @@ -0,0 +1,8 @@ +Loading packages... +Generating metadata files and linking package files... +Finalizing metadata files... +Signing file 'Release' with gpg, please enter your passphrase when prompted: +Clearsigning file 'Release' with gpg, please enter your passphrase when prompted: +Cleaning up prefix "." components a, c... + +Published local repository ./maverick [i386] publishes {a: [local-repo2]}, {b: [local-repo2]}, {c: [local-repo3]} has been successfully switched to new source. diff --git a/system/t06_publish/PublishAdd3Test_gold b/system/t06_publish/PublishAdd3Test_gold new file mode 100644 index 000000000..749a07705 --- /dev/null +++ b/system/t06_publish/PublishAdd3Test_gold @@ -0,0 +1 @@ +ERROR: unable to add: component b already exists in published snapshot repository diff --git a/system/t06_publish/PublishSwitch11Test_gold b/system/t06_publish/PublishSwitch11Test_gold index 2385a0edd..9d87127b4 100644 --- a/system/t06_publish/PublishSwitch11Test_gold +++ b/system/t06_publish/PublishSwitch11Test_gold @@ -7,4 +7,4 @@ Signing file 'Release' with gpg, please enter your passphrase when prompted: Clearsigning file 'Release' with gpg, please enter your passphrase when prompted: Cleaning up prefix "." components main... -Publish for snapshot ./maverick [i386, source] publishes {main: [snap2]: Snapshot from local repo [local-repo2]} has been successfully switched to new snapshot. +Published snapshot repository ./maverick [i386, source] publishes {main: [snap2]: Snapshot from local repo [local-repo2]} has been successfully switched to new source. diff --git a/system/t06_publish/PublishSwitch12Test_gold b/system/t06_publish/PublishSwitch12Test_gold index 8a50172b6..ce8636a43 100644 --- a/system/t06_publish/PublishSwitch12Test_gold +++ b/system/t06_publish/PublishSwitch12Test_gold @@ -1,8 +1 @@ -Loading packages... -Generating metadata files and linking package files... -Finalizing metadata files... -Signing file 'Release' with gpg, please enter your passphrase when prompted: -Clearsigning file 'Release' with gpg, please enter your passphrase when prompted: -Cleaning up prefix "." components a, c... - -Publish for snapshot ./maverick [i386] publishes {a: [snap2]: Created as empty}, {b: [snap2]: Created as empty}, {c: [snap3]: Created as empty} has been successfully switched to new snapshot. +ERROR: unable to switch: component c does not exist in published repository diff --git a/system/t06_publish/PublishSwitch13Test_gold b/system/t06_publish/PublishSwitch13Test_gold index 3f440f06d..271997f33 100644 --- a/system/t06_publish/PublishSwitch13Test_gold +++ b/system/t06_publish/PublishSwitch13Test_gold @@ -5,4 +5,4 @@ Signing file 'Release' with gpg, please enter your passphrase when prompted: Clearsigning file 'Release' with gpg, please enter your passphrase when prompted: Cleaning up prefix "." components main... -Publish for snapshot ./maverick (origin: LP-PPA-gladky-anton-gnuplot) [amd64, i386] publishes {main: [snap3]: Pulled into 'snap2' with 'snap1' as source, pull request was: 'gnuplot-x11'} has been successfully switched to new snapshot. +Published snapshot repository ./maverick (origin: LP-PPA-gladky-anton-gnuplot) [amd64, i386] publishes {main: [snap3]: Pulled into 'snap2' with 'snap1' as source, pull request was: 'gnuplot-x11'} has been successfully switched to new source. diff --git a/system/t06_publish/PublishSwitch14Test_gold b/system/t06_publish/PublishSwitch14Test_gold index 9b8ce8f1c..1cdaf0858 100644 --- a/system/t06_publish/PublishSwitch14Test_gold +++ b/system/t06_publish/PublishSwitch14Test_gold @@ -4,4 +4,4 @@ Finalizing metadata files... Signing file 'Release' with gpg, please enter your passphrase when prompted: Clearsigning file 'Release' with gpg, please enter your passphrase when prompted: -Publish for snapshot ./maverick (origin: LP-PPA-gladky-anton-gnuplot) [amd64, i386] publishes {main: [snap3]: Pulled into 'snap2' with 'snap1' as source, pull request was: 'gnuplot-x11'} has been successfully switched to new snapshot. +Published snapshot repository ./maverick (origin: LP-PPA-gladky-anton-gnuplot) [amd64, i386] publishes {main: [snap3]: Pulled into 'snap2' with 'snap1' as source, pull request was: 'gnuplot-x11'} has been successfully switched to new source. diff --git a/system/t06_publish/PublishSwitch15Test_gold b/system/t06_publish/PublishSwitch15Test_gold index 3f440f06d..271997f33 100644 --- a/system/t06_publish/PublishSwitch15Test_gold +++ b/system/t06_publish/PublishSwitch15Test_gold @@ -5,4 +5,4 @@ Signing file 'Release' with gpg, please enter your passphrase when prompted: Clearsigning file 'Release' with gpg, please enter your passphrase when prompted: Cleaning up prefix "." components main... -Publish for snapshot ./maverick (origin: LP-PPA-gladky-anton-gnuplot) [amd64, i386] publishes {main: [snap3]: Pulled into 'snap2' with 'snap1' as source, pull request was: 'gnuplot-x11'} has been successfully switched to new snapshot. +Published snapshot repository ./maverick (origin: LP-PPA-gladky-anton-gnuplot) [amd64, i386] publishes {main: [snap3]: Pulled into 'snap2' with 'snap1' as source, pull request was: 'gnuplot-x11'} has been successfully switched to new source. diff --git a/system/t06_publish/PublishSwitch1Test_gold b/system/t06_publish/PublishSwitch1Test_gold index 3f440f06d..271997f33 100644 --- a/system/t06_publish/PublishSwitch1Test_gold +++ b/system/t06_publish/PublishSwitch1Test_gold @@ -5,4 +5,4 @@ Signing file 'Release' with gpg, please enter your passphrase when prompted: Clearsigning file 'Release' with gpg, please enter your passphrase when prompted: Cleaning up prefix "." components main... -Publish for snapshot ./maverick (origin: LP-PPA-gladky-anton-gnuplot) [amd64, i386] publishes {main: [snap3]: Pulled into 'snap2' with 'snap1' as source, pull request was: 'gnuplot-x11'} has been successfully switched to new snapshot. +Published snapshot repository ./maverick (origin: LP-PPA-gladky-anton-gnuplot) [amd64, i386] publishes {main: [snap3]: Pulled into 'snap2' with 'snap1' as source, pull request was: 'gnuplot-x11'} has been successfully switched to new source. diff --git a/system/t06_publish/PublishSwitch2Test_gold b/system/t06_publish/PublishSwitch2Test_gold index c84644236..7cc00d448 100644 --- a/system/t06_publish/PublishSwitch2Test_gold +++ b/system/t06_publish/PublishSwitch2Test_gold @@ -5,4 +5,4 @@ Signing file 'Release' with gpg, please enter your passphrase when prompted: Clearsigning file 'Release' with gpg, please enter your passphrase when prompted: Cleaning up prefix "ppa" components main... -Publish for snapshot ppa/maverick [amd64, i386] publishes {main: [snap1]: Snapshot from mirror [gnuplot-maverick]: http://ppa.launchpad.net/gladky-anton/gnuplot/ubuntu/ maverick} has been successfully switched to new snapshot. +Published snapshot repository ppa/maverick [amd64, i386] publishes {main: [snap1]: Snapshot from mirror [gnuplot-maverick]: http://ppa.launchpad.net/gladky-anton/gnuplot/ubuntu/ maverick} has been successfully switched to new source. diff --git a/system/t06_publish/PublishSwitch3Test_gold b/system/t06_publish/PublishSwitch3Test_gold index 3f440f06d..271997f33 100644 --- a/system/t06_publish/PublishSwitch3Test_gold +++ b/system/t06_publish/PublishSwitch3Test_gold @@ -5,4 +5,4 @@ Signing file 'Release' with gpg, please enter your passphrase when prompted: Clearsigning file 'Release' with gpg, please enter your passphrase when prompted: Cleaning up prefix "." components main... -Publish for snapshot ./maverick (origin: LP-PPA-gladky-anton-gnuplot) [amd64, i386] publishes {main: [snap3]: Pulled into 'snap2' with 'snap1' as source, pull request was: 'gnuplot-x11'} has been successfully switched to new snapshot. +Published snapshot repository ./maverick (origin: LP-PPA-gladky-anton-gnuplot) [amd64, i386] publishes {main: [snap3]: Pulled into 'snap2' with 'snap1' as source, pull request was: 'gnuplot-x11'} has been successfully switched to new source. diff --git a/system/t06_publish/PublishSwitch4Test_gold b/system/t06_publish/PublishSwitch4Test_gold index 7256431a1..899c3d536 100644 --- a/system/t06_publish/PublishSwitch4Test_gold +++ b/system/t06_publish/PublishSwitch4Test_gold @@ -5,4 +5,4 @@ Signing file 'Release' with gpg, please enter your passphrase when prompted: Clearsigning file 'Release' with gpg, please enter your passphrase when prompted: Cleaning up prefix "ppa" components main... -Publish for snapshot ppa/maverick [i386] publishes {main: [snap1]: Snapshot from mirror [gnuplot-maverick]: http://ppa.launchpad.net/gladky-anton/gnuplot/ubuntu/ maverick} has been successfully switched to new snapshot. +Published snapshot repository ppa/maverick [i386] publishes {main: [snap1]: Snapshot from mirror [gnuplot-maverick]: http://ppa.launchpad.net/gladky-anton/gnuplot/ubuntu/ maverick} has been successfully switched to new source. diff --git a/system/t06_publish/PublishSwitch5Test_gold b/system/t06_publish/PublishSwitch5Test_gold index c28babdcc..498bf248d 100644 --- a/system/t06_publish/PublishSwitch5Test_gold +++ b/system/t06_publish/PublishSwitch5Test_gold @@ -1 +1 @@ -ERROR: unable to update: published repo with storage:prefix/distribution ppa/maverick not found +ERROR: unable to switch: published repo with storage:prefix/distribution ppa/maverick not found diff --git a/system/t06_publish/PublishSwitch6Test_gold b/system/t06_publish/PublishSwitch6Test_gold index bb45822f0..9253c44d0 100644 --- a/system/t06_publish/PublishSwitch6Test_gold +++ b/system/t06_publish/PublishSwitch6Test_gold @@ -1 +1 @@ -ERROR: unable to update: not a snapshot publish +ERROR: unable to switch: local repo with name snap1 not found diff --git a/system/t06_publish/PublishSwitch8Test_gold b/system/t06_publish/PublishSwitch8Test_gold index d9870ff94..a10e335fe 100644 --- a/system/t06_publish/PublishSwitch8Test_gold +++ b/system/t06_publish/PublishSwitch8Test_gold @@ -5,4 +5,4 @@ Signing file 'Release' with gpg, please enter your passphrase when prompted: Clearsigning file 'Release' with gpg, please enter your passphrase when prompted: Cleaning up prefix "." components b, c... -Publish for snapshot ./maverick [amd64, i386, source] publishes {a: [snap1]: Snapshot from mirror [gnuplot-maverick]: http://ppa.launchpad.net/gladky-anton/gnuplot/ubuntu/ maverick}, {b: [snap3]: Pulled into 'snap2' with 'snap1' as source, pull request was: 'gnuplot-x11'}, {c: [local2]: Snapshot from local repo [local-repo]} has been successfully switched to new snapshot. +Published snapshot repository ./maverick [amd64, i386, source] publishes {a: [snap1]: Snapshot from mirror [gnuplot-maverick]: http://ppa.launchpad.net/gladky-anton/gnuplot/ubuntu/ maverick}, {b: [snap3]: Pulled into 'snap2' with 'snap1' as source, pull request was: 'gnuplot-x11'}, {c: [local2]: Snapshot from local repo [local-repo]} has been successfully switched to new source. diff --git a/system/t06_publish/PublishUpdate10Test_gold b/system/t06_publish/PublishUpdate10Test_gold index bda2f4dd3..082275a34 100644 --- a/system/t06_publish/PublishUpdate10Test_gold +++ b/system/t06_publish/PublishUpdate10Test_gold @@ -7,4 +7,4 @@ Signing file 'Release' with gpg, please enter your passphrase when prompted: Clearsigning file 'Release' with gpg, please enter your passphrase when prompted: Cleaning up prefix "." components main... -Publish for local repo ./maverick [i386, source] publishes {main: [local-repo]} has been successfully updated. +Published local repository ./maverick [i386, source] publishes {main: [local-repo]} has been successfully updated. diff --git a/system/t06_publish/PublishUpdate11Test_gold b/system/t06_publish/PublishUpdate11Test_gold index 72e92234f..05b56b2a2 100644 --- a/system/t06_publish/PublishUpdate11Test_gold +++ b/system/t06_publish/PublishUpdate11Test_gold @@ -5,4 +5,4 @@ Signing file 'Release' with gpg, please enter your passphrase when prompted: Clearsigning file 'Release' with gpg, please enter your passphrase when prompted: Cleaning up prefix "." components main... -Publish for local repo ./maverick [i386, source] publishes {main: [local-repo]} has been successfully updated. +Published local repository ./maverick [i386, source] publishes {main: [local-repo]} has been successfully updated. diff --git a/system/t06_publish/PublishUpdate12Test_gold b/system/t06_publish/PublishUpdate12Test_gold index 3b7a5709e..7488eec4e 100644 --- a/system/t06_publish/PublishUpdate12Test_gold +++ b/system/t06_publish/PublishUpdate12Test_gold @@ -4,4 +4,4 @@ Finalizing metadata files... Signing file 'Release' with gpg, please enter your passphrase when prompted: Clearsigning file 'Release' with gpg, please enter your passphrase when prompted: -Publish for local repo ./maverick [i386, source] publishes {main: [local-repo]} has been successfully updated. +Published local repository ./maverick [i386, source] publishes {main: [local-repo]} has been successfully updated. diff --git a/system/t06_publish/PublishUpdate13Test_gold b/system/t06_publish/PublishUpdate13Test_gold index 72e92234f..05b56b2a2 100644 --- a/system/t06_publish/PublishUpdate13Test_gold +++ b/system/t06_publish/PublishUpdate13Test_gold @@ -5,4 +5,4 @@ Signing file 'Release' with gpg, please enter your passphrase when prompted: Clearsigning file 'Release' with gpg, please enter your passphrase when prompted: Cleaning up prefix "." components main... -Publish for local repo ./maverick [i386, source] publishes {main: [local-repo]} has been successfully updated. +Published local repository ./maverick [i386, source] publishes {main: [local-repo]} has been successfully updated. diff --git a/system/t06_publish/PublishUpdate1Test_gold b/system/t06_publish/PublishUpdate1Test_gold index 72e92234f..05b56b2a2 100644 --- a/system/t06_publish/PublishUpdate1Test_gold +++ b/system/t06_publish/PublishUpdate1Test_gold @@ -5,4 +5,4 @@ Signing file 'Release' with gpg, please enter your passphrase when prompted: Clearsigning file 'Release' with gpg, please enter your passphrase when prompted: Cleaning up prefix "." components main... -Publish for local repo ./maverick [i386, source] publishes {main: [local-repo]} has been successfully updated. +Published local repository ./maverick [i386, source] publishes {main: [local-repo]} has been successfully updated. diff --git a/system/t06_publish/PublishUpdate2Test_gold b/system/t06_publish/PublishUpdate2Test_gold index 72e92234f..05b56b2a2 100644 --- a/system/t06_publish/PublishUpdate2Test_gold +++ b/system/t06_publish/PublishUpdate2Test_gold @@ -5,4 +5,4 @@ Signing file 'Release' with gpg, please enter your passphrase when prompted: Clearsigning file 'Release' with gpg, please enter your passphrase when prompted: Cleaning up prefix "." components main... -Publish for local repo ./maverick [i386, source] publishes {main: [local-repo]} has been successfully updated. +Published local repository ./maverick [i386, source] publishes {main: [local-repo]} has been successfully updated. diff --git a/system/t06_publish/PublishUpdate3Test_gold b/system/t06_publish/PublishUpdate3Test_gold index 72e92234f..05b56b2a2 100644 --- a/system/t06_publish/PublishUpdate3Test_gold +++ b/system/t06_publish/PublishUpdate3Test_gold @@ -5,4 +5,4 @@ Signing file 'Release' with gpg, please enter your passphrase when prompted: Clearsigning file 'Release' with gpg, please enter your passphrase when prompted: Cleaning up prefix "." components main... -Publish for local repo ./maverick [i386, source] publishes {main: [local-repo]} has been successfully updated. +Published local repository ./maverick [i386, source] publishes {main: [local-repo]} has been successfully updated. diff --git a/system/t06_publish/PublishUpdate4Test_gold b/system/t06_publish/PublishUpdate4Test_gold index dce245d58..29502a022 100644 --- a/system/t06_publish/PublishUpdate4Test_gold +++ b/system/t06_publish/PublishUpdate4Test_gold @@ -5,4 +5,4 @@ Signing file 'Release' with gpg, please enter your passphrase when prompted: Clearsigning file 'Release' with gpg, please enter your passphrase when prompted: Cleaning up prefix "." components main... -Publish for local repo ./maverick [source] publishes {main: [local-repo]} has been successfully updated. +Published local repository ./maverick [source] publishes {main: [local-repo]} has been successfully updated. diff --git a/system/t06_publish/PublishUpdate7Test_gold b/system/t06_publish/PublishUpdate7Test_gold index 813d7055e..a13b260ca 100644 --- a/system/t06_publish/PublishUpdate7Test_gold +++ b/system/t06_publish/PublishUpdate7Test_gold @@ -5,4 +5,4 @@ Signing file 'Release' with gpg, please enter your passphrase when prompted: Clearsigning file 'Release' with gpg, please enter your passphrase when prompted: Cleaning up prefix "." components contrib, main... -Publish for local repo ./maverick [i386, source] publishes {contrib: [repo2]}, {main: [repo1]} has been successfully updated. +Published local repository ./maverick [i386, source] publishes {contrib: [repo2]}, {main: [repo1]} has been successfully updated. diff --git a/system/t06_publish/PublishUpdate8Test_gold b/system/t06_publish/PublishUpdate8Test_gold index 09aa9845b..1a6ebd262 100644 --- a/system/t06_publish/PublishUpdate8Test_gold +++ b/system/t06_publish/PublishUpdate8Test_gold @@ -3,4 +3,4 @@ Generating metadata files and linking package files... Finalizing metadata files... Cleaning up prefix "." components contrib, main... -Publish for local repo ./squeeze [i386] publishes {contrib: [repo2]}, {main: [repo1]} has been successfully updated. +Published local repository ./squeeze [i386] publishes {contrib: [repo2]}, {main: [repo1]} has been successfully updated. diff --git a/system/t06_publish/S3Publish2Test_gold b/system/t06_publish/S3Publish2Test_gold index 12c9c0e6a..d6ffd382f 100644 --- a/system/t06_publish/S3Publish2Test_gold +++ b/system/t06_publish/S3Publish2Test_gold @@ -5,4 +5,4 @@ Signing file 'Release' with gpg, please enter your passphrase when prompted: Clearsigning file 'Release' with gpg, please enter your passphrase when prompted: Cleaning up prefix "." components main... -Publish for local repo s3:test1:./maverick [i386, source] publishes {main: [local-repo]} has been successfully updated. +Published local repository s3:test1:./maverick [i386, source] publishes {main: [local-repo]} has been successfully updated. diff --git a/system/t06_publish/S3Publish3Test_gold b/system/t06_publish/S3Publish3Test_gold index 7d609f0f8..54c8a83e1 100644 --- a/system/t06_publish/S3Publish3Test_gold +++ b/system/t06_publish/S3Publish3Test_gold @@ -5,4 +5,4 @@ Signing file 'Release' with gpg, please enter your passphrase when prompted: Clearsigning file 'Release' with gpg, please enter your passphrase when prompted: Cleaning up prefix "." components main... -Publish for snapshot s3:test1:./maverick (origin: LP-PPA-gladky-anton-gnuplot) [amd64, i386] publishes {main: [snap3]: Pulled into 'snap2' with 'snap1' as source, pull request was: 'gnuplot-x11'} has been successfully switched to new snapshot. +Published snapshot repository s3:test1:./maverick (origin: LP-PPA-gladky-anton-gnuplot) [amd64, i386] publishes {main: [snap3]: Pulled into 'snap2' with 'snap1' as source, pull request was: 'gnuplot-x11'} has been successfully switched to new source. diff --git a/system/t06_publish/S3Publish6Test_gold b/system/t06_publish/S3Publish6Test_gold index 12c9c0e6a..d6ffd382f 100644 --- a/system/t06_publish/S3Publish6Test_gold +++ b/system/t06_publish/S3Publish6Test_gold @@ -5,4 +5,4 @@ Signing file 'Release' with gpg, please enter your passphrase when prompted: Clearsigning file 'Release' with gpg, please enter your passphrase when prompted: Cleaning up prefix "." components main... -Publish for local repo s3:test1:./maverick [i386, source] publishes {main: [local-repo]} has been successfully updated. +Published local repository s3:test1:./maverick [i386, source] publishes {main: [local-repo]} has been successfully updated. diff --git a/system/t06_publish/SwiftPublish2Test_gold b/system/t06_publish/SwiftPublish2Test_gold index 5beaf677b..1ec018b61 100644 --- a/system/t06_publish/SwiftPublish2Test_gold +++ b/system/t06_publish/SwiftPublish2Test_gold @@ -5,4 +5,4 @@ Signing file 'Release' with gpg, please enter your passphrase when prompted: Clearsigning file 'Release' with gpg, please enter your passphrase when prompted: Cleaning up prefix "." components main... -Publish for local repo swift:test1:./maverick [i386, source] publishes {main: [local-repo]} has been successfully updated. +Published local repository swift:test1:./maverick [i386, source] publishes {main: [local-repo]} has been successfully updated. diff --git a/system/t06_publish/SwiftPublish3Test_gold b/system/t06_publish/SwiftPublish3Test_gold index 16c322a51..051131b54 100644 --- a/system/t06_publish/SwiftPublish3Test_gold +++ b/system/t06_publish/SwiftPublish3Test_gold @@ -5,4 +5,4 @@ Signing file 'Release' with gpg, please enter your passphrase when prompted: Clearsigning file 'Release' with gpg, please enter your passphrase when prompted: Cleaning up prefix "." components main... -Publish for snapshot swift:test1:./maverick (origin: LP-PPA-gladky-anton-gnuplot) [amd64, i386] publishes {main: [snap3]: Pulled into 'snap2' with 'snap1' as source, pull request was: 'gnuplot-x11'} has been successfully switched to new snapshot. +Published snapshot repository swift:test1:./maverick (origin: LP-PPA-gladky-anton-gnuplot) [amd64, i386] publishes {main: [snap3]: Pulled into 'snap2' with 'snap1' as source, pull request was: 'gnuplot-x11'} has been successfully switched to new source. diff --git a/system/t06_publish/add.py b/system/t06_publish/add.py new file mode 100644 index 000000000..643d01c34 --- /dev/null +++ b/system/t06_publish/add.py @@ -0,0 +1,57 @@ +from lib import BaseTest + + +class PublishAdd1Test(BaseTest): + """ + publish add: add new component to snapshot publish + """ + fixtureCmds = [ + "aptly snapshot create snap1 empty", + "aptly snapshot create snap2 empty", + "aptly snapshot create snap3 empty", + "aptly publish snapshot -architectures=i386 -keyring=${files}/aptly.pub -secret-keyring=${files}/aptly.sec -distribution=maverick -component=a,b snap1 snap2", + ] + runCmd = "aptly publish add -keyring=${files}/aptly.pub -secret-keyring=${files}/aptly.sec -component=c maverick snap3" + gold_processor = BaseTest.expand_environ + + def check(self): + super(PublishAdd1Test, self).check() + + self.check_exists('public/dists/maverick/a/binary-i386/Packages') + self.check_exists('public/dists/maverick/b/binary-i386/Packages') + self.check_exists('public/dists/maverick/c/binary-i386/Packages') + + +class PublishAdd2Test(BaseTest): + """ + publish add: add new component to local repo publish + """ + fixtureCmds = [ + "aptly repo create local-repo1", + "aptly repo create local-repo2", + "aptly repo create local-repo3", + "aptly publish repo -architectures=i386 -keyring=${files}/aptly.pub -secret-keyring=${files}/aptly.sec -distribution=maverick -component=a,b local-repo1 local-repo2", + ] + runCmd = "aptly publish switch -keyring=${files}/aptly.pub -secret-keyring=${files}/aptly.sec -component=c maverick local-repo3" + gold_processor = BaseTest.expand_environ + + def check(self): + super(PublishAdd2Test, self).check() + + self.check_exists('public/dists/maverick/a/binary-i386/Packages') + self.check_exists('public/dists/maverick/b/binary-i386/Packages') + self.check_exists('public/dists/maverick/c/binary-i386/Packages') + + +class PublishAdd3Test(BaseTest): + """ + publish add: add already existing component + """ + fixtureCmds = [ + "aptly snapshot create snap1 empty", + "aptly snapshot create snap2 empty", + "aptly snapshot create snap3 empty", + "aptly publish snapshot -architectures=i386 -keyring=${files}/aptly.pub -secret-keyring=${files}/aptly.sec -distribution=maverick -component=a,b snap1 snap2", + ] + runCmd = "aptly publish add -keyring=${files}/aptly.pub -secret-keyring=${files}/aptly.sec -component=b maverick snap3" + expectedCode = 1 diff --git a/system/t06_publish/switch.py b/system/t06_publish/switch.py index 933e08c15..6a86a3cc4 100644 --- a/system/t06_publish/switch.py +++ b/system/t06_publish/switch.py @@ -424,22 +424,15 @@ def check(self): class PublishSwitch12Test(BaseTest): """ - publish switch: add new component to publish + publish switch: wrong component names """ fixtureCmds = [ "aptly snapshot create snap1 empty", "aptly snapshot create snap2 empty", - "aptly snapshot create snap3 empty", "aptly publish snapshot -architectures=i386 -keyring=${files}/aptly.pub -secret-keyring=${files}/aptly.sec -distribution=maverick -component=a,b snap1 snap2", ] - runCmd = "aptly publish switch -keyring=${files}/aptly.pub -secret-keyring=${files}/aptly.sec -component=a,c maverick snap2 snap3" - gold_processor = BaseTest.expand_environ - - def check(self): - super(PublishSwitch12Test, self).check() - - self.check_exists('public/dists/maverick/a/binary-i386/Packages') - self.check_exists('public/dists/maverick/c/binary-i386/Packages') + runCmd = "aptly publish switch -keyring=${files}/aptly.pub -secret-keyring=${files}/aptly.sec -component=a,c maverick snap2 snap1" + expectedCode = 1 class PublishSwitch13Test(BaseTest): diff --git a/system/t12_api/publish.py b/system/t12_api/publish.py index 428664219..6cbeea4a2 100644 --- a/system/t12_api/publish.py +++ b/system/t12_api/publish.py @@ -562,7 +562,7 @@ def check(self): task = self.put_task( "/api/publish/" + prefix + "/wheezy", json={ - "Snapshots": [{"Component": "main", "Name": snapshot2_name}], + "Sources": [{"Component": "main", "Name": snapshot2_name}], "Signing": DefaultSigningOptions, "SkipContents": True, }) @@ -705,7 +705,7 @@ def check(self): task = self.put_task("/api/publish/" + prefix + "/wheezy", json={ - "Snapshots": [{"Component": "main", "Name": snapshot2_name}], + "Sources": [{"Component": "main", "Name": snapshot2_name}], "Signing": DefaultSigningOptions, "SkipCleanup": True, "SkipContents": True,