mirror of
https://github.com/aptly-dev/aptly.git
synced 2026-05-31 04:30:44 +00:00
Merge branch 'lebauce-snapshot-api'
This commit is contained in:
@@ -3,6 +3,7 @@ gom 'code.google.com/p/go.crypto/ssh/terminal', :commit => '7aa593ce8cea'
|
|||||||
gom 'code.google.com/p/gographviz', :commit => '454bc64fdfa2'
|
gom 'code.google.com/p/gographviz', :commit => '454bc64fdfa2'
|
||||||
gom 'code.google.com/p/mxk/go1/flowcontrol', :commit => '5ff2502e2556'
|
gom 'code.google.com/p/mxk/go1/flowcontrol', :commit => '5ff2502e2556'
|
||||||
gom 'code.google.com/p/snappy-go/snappy', :commit => '12e4b4183793'
|
gom 'code.google.com/p/snappy-go/snappy', :commit => '12e4b4183793'
|
||||||
|
gom 'github.com/AlekSi/pointer', :commit => '5f6d527dae3d678b46fbb20331ddf44e2b841943'
|
||||||
gom 'github.com/cheggaaa/pb', :commit => '74be7a1388046f374ac36e93d46f5d56e856f827'
|
gom 'github.com/cheggaaa/pb', :commit => '74be7a1388046f374ac36e93d46f5d56e856f827'
|
||||||
gom 'github.com/gin-gonic/gin', :commit => '0808f8a824cfb9aef6ea4fd664af238544b66fc1'
|
gom 'github.com/gin-gonic/gin', :commit => '0808f8a824cfb9aef6ea4fd664af238544b66fc1'
|
||||||
gom 'github.com/jlaffaye/ftp', :commit => 'fec71e62e457557fbe85cefc847a048d57815d76'
|
gom 'github.com/jlaffaye/ftp', :commit => 'fec71e62e457557fbe85cefc847a048d57815d76'
|
||||||
|
|||||||
+62
@@ -2,8 +2,12 @@
|
|||||||
package api
|
package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/smira/aptly/aptly"
|
"github.com/smira/aptly/aptly"
|
||||||
|
"github.com/smira/aptly/deb"
|
||||||
|
"github.com/smira/aptly/query"
|
||||||
|
"sort"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Lock order acquisition (canonical):
|
// Lock order acquisition (canonical):
|
||||||
@@ -16,3 +20,61 @@ import (
|
|||||||
func apiVersion(c *gin.Context) {
|
func apiVersion(c *gin.Context) {
|
||||||
c.JSON(200, gin.H{"Version": aptly.Version})
|
c.JSON(200, gin.H{"Version": aptly.Version})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Common piece of code to show list of packages,
|
||||||
|
// with searching & details if requested
|
||||||
|
func showPackages(c *gin.Context, reflist *deb.PackageRefList) {
|
||||||
|
result := []*deb.Package{}
|
||||||
|
|
||||||
|
list, err := deb.NewPackageListFromRefList(reflist, context.CollectionFactory().PackageCollection(), context.Progress())
|
||||||
|
if err != nil {
|
||||||
|
c.Fail(404, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
queryS := c.Request.URL.Query().Get("q")
|
||||||
|
if queryS != "" {
|
||||||
|
q, err := query.Parse(c.Request.URL.Query().Get("q"))
|
||||||
|
if err != nil {
|
||||||
|
c.Fail(400, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
withDeps := c.Request.URL.Query().Get("withDeps") == "1"
|
||||||
|
architecturesList := []string{}
|
||||||
|
|
||||||
|
if withDeps {
|
||||||
|
if len(context.ArchitecturesList()) > 0 {
|
||||||
|
architecturesList = context.ArchitecturesList()
|
||||||
|
} else {
|
||||||
|
architecturesList = list.Architectures(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
sort.Strings(architecturesList)
|
||||||
|
|
||||||
|
if len(architecturesList) == 0 {
|
||||||
|
c.Fail(400, fmt.Errorf("unable to determine list of architectures, please specify explicitly"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
list.PrepareIndex()
|
||||||
|
|
||||||
|
list, err = list.Filter([]deb.PackageQuery{q}, withDeps,
|
||||||
|
nil, context.DependencyOptions(), architecturesList)
|
||||||
|
if err != nil {
|
||||||
|
c.Fail(500, fmt.Errorf("unable to search: %s", err))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.Request.URL.Query().Get("format") == "details" {
|
||||||
|
list.ForEach(func(p *deb.Package) error {
|
||||||
|
result = append(result, p)
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
c.JSON(200, result)
|
||||||
|
} else {
|
||||||
|
c.JSON(200, list.Strings())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
+1
-47
@@ -6,11 +6,9 @@ import (
|
|||||||
"github.com/smira/aptly/aptly"
|
"github.com/smira/aptly/aptly"
|
||||||
"github.com/smira/aptly/database"
|
"github.com/smira/aptly/database"
|
||||||
"github.com/smira/aptly/deb"
|
"github.com/smira/aptly/deb"
|
||||||
"github.com/smira/aptly/query"
|
|
||||||
"github.com/smira/aptly/utils"
|
"github.com/smira/aptly/utils"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"sort"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// GET /api/repos
|
// GET /api/repos
|
||||||
@@ -178,51 +176,7 @@ func apiReposPackagesShow(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
queryS := c.Request.URL.Query().Get("q")
|
showPackages(c, repo.RefList())
|
||||||
if queryS != "" {
|
|
||||||
q, err := query.Parse(queryS)
|
|
||||||
if err != nil {
|
|
||||||
c.Fail(400, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
list, err := deb.NewPackageListFromRefList(repo.RefList(), context.CollectionFactory().PackageCollection(), nil)
|
|
||||||
if err != nil {
|
|
||||||
c.Fail(500, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
list.PrepareIndex()
|
|
||||||
|
|
||||||
withDeps := c.Request.URL.Query().Get("withDeps") == "1"
|
|
||||||
architecturesList := []string{}
|
|
||||||
|
|
||||||
if withDeps {
|
|
||||||
if len(context.ArchitecturesList()) > 0 {
|
|
||||||
architecturesList = context.ArchitecturesList()
|
|
||||||
} else {
|
|
||||||
architecturesList = list.Architectures(false)
|
|
||||||
}
|
|
||||||
|
|
||||||
sort.Strings(architecturesList)
|
|
||||||
|
|
||||||
if len(architecturesList) == 0 {
|
|
||||||
c.Fail(400, fmt.Errorf("unable to determine list of architectures, please specify explicitly"))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
result, err := list.Filter([]deb.PackageQuery{q}, withDeps,
|
|
||||||
nil, context.DependencyOptions(), architecturesList)
|
|
||||||
if err != nil {
|
|
||||||
c.Fail(500, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
c.JSON(200, result.Strings())
|
|
||||||
} else {
|
|
||||||
c.JSON(200, repo.RefList().Strings())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handler for both add and delete
|
// Handler for both add and delete
|
||||||
|
|||||||
@@ -34,6 +34,12 @@ func Router(c *ctx.AptlyContext) http.Handler {
|
|||||||
|
|
||||||
root.POST("/repos/:name/file/:dir/:file", apiReposPackageFromFile)
|
root.POST("/repos/:name/file/:dir/:file", apiReposPackageFromFile)
|
||||||
root.POST("/repos/:name/file/:dir", apiReposPackageFromDir)
|
root.POST("/repos/:name/file/:dir", apiReposPackageFromDir)
|
||||||
|
|
||||||
|
root.POST("/repos/:name/snapshots", apiSnapshotsCreateFromRepository)
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
root.POST("/mirrors/:name/snapshots", apiSnapshotsCreateFromMirror)
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
@@ -52,6 +58,16 @@ func Router(c *ctx.AptlyContext) http.Handler {
|
|||||||
root.DELETE("/publish/:prefix/:distribution", apiPublishDrop)
|
root.DELETE("/publish/:prefix/:distribution", apiPublishDrop)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
root.GET("/snapshots", apiSnapshotsList)
|
||||||
|
root.POST("/snapshots", apiSnapshotsCreate)
|
||||||
|
root.PUT("/snapshots/:name", apiSnapshotsUpdate)
|
||||||
|
root.GET("/snapshots/:name", apiSnapshotsShow)
|
||||||
|
root.GET("/snapshots/:name/packages", apiSnapshotsSearchPackages)
|
||||||
|
root.DELETE("/snapshots/:name", apiSnapshotsDrop)
|
||||||
|
root.GET("/snapshots/:name/diff/:withSnapshot", apiSnapshotsDiff)
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
root.GET("/graph.:ext", apiGraph)
|
root.GET("/graph.:ext", apiGraph)
|
||||||
}
|
}
|
||||||
|
|||||||
+405
@@ -0,0 +1,405 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/smira/aptly/deb"
|
||||||
|
)
|
||||||
|
|
||||||
|
// GET /api/snapshots
|
||||||
|
func apiSnapshotsList(c *gin.Context) {
|
||||||
|
SortMethodString := c.Request.URL.Query().Get("sort")
|
||||||
|
|
||||||
|
collection := context.CollectionFactory().SnapshotCollection()
|
||||||
|
collection.RLock()
|
||||||
|
defer collection.RUnlock()
|
||||||
|
|
||||||
|
if SortMethodString == "" {
|
||||||
|
SortMethodString = "name"
|
||||||
|
}
|
||||||
|
|
||||||
|
result := []*deb.Snapshot{}
|
||||||
|
collection.ForEachSorted(SortMethodString, func(snapshot *deb.Snapshot) error {
|
||||||
|
result = append(result, snapshot)
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
c.JSON(200, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
// POST /api/mirrors/:name/snapshots/
|
||||||
|
func apiSnapshotsCreateFromMirror(c *gin.Context) {
|
||||||
|
var (
|
||||||
|
err error
|
||||||
|
repo *deb.RemoteRepo
|
||||||
|
snapshot *deb.Snapshot
|
||||||
|
)
|
||||||
|
|
||||||
|
var b struct {
|
||||||
|
Name string `binding:"required"`
|
||||||
|
Description string
|
||||||
|
}
|
||||||
|
|
||||||
|
if !c.Bind(&b) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
collection := context.CollectionFactory().RemoteRepoCollection()
|
||||||
|
collection.Lock()
|
||||||
|
defer collection.Unlock()
|
||||||
|
|
||||||
|
snapshotCollection := context.CollectionFactory().SnapshotCollection()
|
||||||
|
snapshotCollection.Lock()
|
||||||
|
defer snapshotCollection.Unlock()
|
||||||
|
|
||||||
|
repo, err = collection.ByName(c.Params.ByName("name"))
|
||||||
|
if err != nil {
|
||||||
|
c.Fail(404, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = repo.CheckLock()
|
||||||
|
if err != nil {
|
||||||
|
c.Fail(409, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = collection.LoadComplete(repo)
|
||||||
|
if err != nil {
|
||||||
|
c.Fail(500, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
snapshot, err = deb.NewSnapshotFromRepository(b.Name, repo)
|
||||||
|
if err != nil {
|
||||||
|
c.Fail(400, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if b.Description != "" {
|
||||||
|
snapshot.Description = b.Description
|
||||||
|
}
|
||||||
|
|
||||||
|
err = snapshotCollection.Add(snapshot)
|
||||||
|
if err != nil {
|
||||||
|
c.Fail(500, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.JSON(201, snapshot)
|
||||||
|
}
|
||||||
|
|
||||||
|
// POST /api/snapshots
|
||||||
|
func apiSnapshotsCreate(c *gin.Context) {
|
||||||
|
var (
|
||||||
|
err error
|
||||||
|
snapshot *deb.Snapshot
|
||||||
|
)
|
||||||
|
|
||||||
|
var b struct {
|
||||||
|
Name string `binding:"required"`
|
||||||
|
Description string
|
||||||
|
SourceIDs []string
|
||||||
|
PackageRefs []string
|
||||||
|
}
|
||||||
|
|
||||||
|
if !c.Bind(&b) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if b.Description == "" {
|
||||||
|
if len(b.SourceIDs)+len(b.PackageRefs) == 0 {
|
||||||
|
b.Description = "Created as empty"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
snapshotCollection := context.CollectionFactory().SnapshotCollection()
|
||||||
|
snapshotCollection.Lock()
|
||||||
|
defer snapshotCollection.Unlock()
|
||||||
|
|
||||||
|
sources := make([]*deb.Snapshot, len(b.SourceIDs))
|
||||||
|
|
||||||
|
for i := 0; i < len(b.SourceIDs); i++ {
|
||||||
|
sources[i], err = snapshotCollection.ByUUID(b.SourceIDs[i])
|
||||||
|
if err != nil {
|
||||||
|
c.Fail(404, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = snapshotCollection.LoadComplete(sources[i])
|
||||||
|
if err != nil {
|
||||||
|
c.Fail(500, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
packageRefs := make([][]byte, len(b.PackageRefs))
|
||||||
|
for i, ref := range b.PackageRefs {
|
||||||
|
packageRefs[i] = []byte(ref)
|
||||||
|
}
|
||||||
|
|
||||||
|
packageRefList := &deb.PackageRefList{packageRefs}
|
||||||
|
snapshot = deb.NewSnapshotFromRefList(b.Name, sources, packageRefList, b.Description)
|
||||||
|
|
||||||
|
err = snapshotCollection.Add(snapshot)
|
||||||
|
if err != nil {
|
||||||
|
c.Fail(500, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.JSON(201, snapshot)
|
||||||
|
}
|
||||||
|
|
||||||
|
// POST /api/repos/:name/snapshots/:snapname
|
||||||
|
func apiSnapshotsCreateFromRepository(c *gin.Context) {
|
||||||
|
var (
|
||||||
|
err error
|
||||||
|
repo *deb.LocalRepo
|
||||||
|
snapshot *deb.Snapshot
|
||||||
|
)
|
||||||
|
|
||||||
|
var b struct {
|
||||||
|
Name string `binding:"required"`
|
||||||
|
Description string
|
||||||
|
}
|
||||||
|
|
||||||
|
if !c.Bind(&b) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
collection := context.CollectionFactory().LocalRepoCollection()
|
||||||
|
collection.Lock()
|
||||||
|
defer collection.Unlock()
|
||||||
|
|
||||||
|
snapshotCollection := context.CollectionFactory().SnapshotCollection()
|
||||||
|
snapshotCollection.Lock()
|
||||||
|
defer snapshotCollection.Unlock()
|
||||||
|
|
||||||
|
repo, err = collection.ByName(c.Params.ByName("name"))
|
||||||
|
if err != nil {
|
||||||
|
c.Fail(404, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = collection.LoadComplete(repo)
|
||||||
|
if err != nil {
|
||||||
|
c.Fail(500, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
snapshot, err = deb.NewSnapshotFromLocalRepo(b.Name, repo)
|
||||||
|
if err != nil {
|
||||||
|
c.Fail(400, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if b.Description != "" {
|
||||||
|
snapshot.Description = b.Description
|
||||||
|
}
|
||||||
|
|
||||||
|
err = snapshotCollection.Add(snapshot)
|
||||||
|
if err != nil {
|
||||||
|
c.Fail(500, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.JSON(201, snapshot)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PUT /api/snapshots/:name
|
||||||
|
func apiSnapshotsUpdate(c *gin.Context) {
|
||||||
|
var (
|
||||||
|
err error
|
||||||
|
snapshot *deb.Snapshot
|
||||||
|
)
|
||||||
|
|
||||||
|
var b struct {
|
||||||
|
Name string
|
||||||
|
Description string
|
||||||
|
}
|
||||||
|
|
||||||
|
if !c.Bind(&b) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
collection := context.CollectionFactory().SnapshotCollection()
|
||||||
|
collection.Lock()
|
||||||
|
defer collection.Unlock()
|
||||||
|
|
||||||
|
snapshot, err = context.CollectionFactory().SnapshotCollection().ByName(c.Params.ByName("name"))
|
||||||
|
if err != nil {
|
||||||
|
c.Fail(404, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = context.CollectionFactory().SnapshotCollection().ByName(b.Name)
|
||||||
|
if err == nil {
|
||||||
|
c.Fail(409, fmt.Errorf("unable to rename: snapshot %s already exists", b.Name))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if b.Name != "" {
|
||||||
|
snapshot.Name = b.Name
|
||||||
|
}
|
||||||
|
|
||||||
|
if b.Description != "" {
|
||||||
|
snapshot.Description = b.Description
|
||||||
|
}
|
||||||
|
|
||||||
|
err = context.CollectionFactory().SnapshotCollection().Update(snapshot)
|
||||||
|
if err != nil {
|
||||||
|
c.Fail(403, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.JSON(200, snapshot)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GET /api/snapshots/:name
|
||||||
|
func apiSnapshotsShow(c *gin.Context) {
|
||||||
|
collection := context.CollectionFactory().SnapshotCollection()
|
||||||
|
collection.RLock()
|
||||||
|
defer collection.RUnlock()
|
||||||
|
|
||||||
|
snapshot, err := collection.ByName(c.Params.ByName("name"))
|
||||||
|
if err != nil {
|
||||||
|
c.Fail(404, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = collection.LoadComplete(snapshot)
|
||||||
|
if err != nil {
|
||||||
|
c.Fail(500, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.JSON(200, snapshot)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DELETE /api/snapshots/:name
|
||||||
|
func apiSnapshotsDrop(c *gin.Context) {
|
||||||
|
name := c.Params.ByName("name")
|
||||||
|
force := c.Request.URL.Query().Get("force") == "1"
|
||||||
|
|
||||||
|
collection := context.CollectionFactory().LocalRepoCollection()
|
||||||
|
collection.Lock()
|
||||||
|
defer collection.Unlock()
|
||||||
|
|
||||||
|
snapshotCollection := context.CollectionFactory().SnapshotCollection()
|
||||||
|
snapshotCollection.RLock()
|
||||||
|
defer snapshotCollection.RUnlock()
|
||||||
|
|
||||||
|
publishedCollection := context.CollectionFactory().PublishedRepoCollection()
|
||||||
|
publishedCollection.RLock()
|
||||||
|
defer publishedCollection.RUnlock()
|
||||||
|
|
||||||
|
snapshot, err := snapshotCollection.ByName(name)
|
||||||
|
if err != nil {
|
||||||
|
c.Fail(404, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
published := publishedCollection.BySnapshot(snapshot)
|
||||||
|
|
||||||
|
if len(published) > 0 {
|
||||||
|
for _, repo := range published {
|
||||||
|
err = publishedCollection.LoadComplete(repo, context.CollectionFactory())
|
||||||
|
if err != nil {
|
||||||
|
c.Fail(500, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
c.Fail(409, fmt.Errorf("unable to drop: snapshot is published"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !force {
|
||||||
|
snapshots := snapshotCollection.BySnapshotSource(snapshot)
|
||||||
|
if len(snapshots) > 0 {
|
||||||
|
c.Fail(409, fmt.Errorf("won't delete snapshot that was used as source for other snapshots, use ?force=1 to override"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
err = context.CollectionFactory().SnapshotCollection().Drop(snapshot)
|
||||||
|
if err != nil {
|
||||||
|
c.Fail(500, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.JSON(200, gin.H{})
|
||||||
|
}
|
||||||
|
|
||||||
|
// GET /api/snapshots/:name/diff/:withSnapshot
|
||||||
|
func apiSnapshotsDiff(c *gin.Context) {
|
||||||
|
onlyMatching := c.Request.URL.Query().Get("onlyMatching") == "1"
|
||||||
|
|
||||||
|
collection := context.CollectionFactory().SnapshotCollection()
|
||||||
|
collection.RLock()
|
||||||
|
defer collection.RUnlock()
|
||||||
|
|
||||||
|
snapshotA, err := collection.ByName(c.Params.ByName("name"))
|
||||||
|
if err != nil {
|
||||||
|
c.Fail(404, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
snapshotB, err := collection.ByName(c.Params.ByName("withSnapshot"))
|
||||||
|
if err != nil {
|
||||||
|
c.Fail(404, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = context.CollectionFactory().SnapshotCollection().LoadComplete(snapshotA)
|
||||||
|
if err != nil {
|
||||||
|
c.Fail(500, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = context.CollectionFactory().SnapshotCollection().LoadComplete(snapshotB)
|
||||||
|
if err != nil {
|
||||||
|
c.Fail(500, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate diff
|
||||||
|
diff, err := snapshotA.RefList().Diff(snapshotB.RefList(), context.CollectionFactory().PackageCollection())
|
||||||
|
if err != nil {
|
||||||
|
c.Fail(500, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
result := []deb.PackageDiff{}
|
||||||
|
|
||||||
|
for _, pdiff := range diff {
|
||||||
|
if onlyMatching && (pdiff.Left == nil || pdiff.Right == nil) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
result = append(result, pdiff)
|
||||||
|
}
|
||||||
|
|
||||||
|
c.JSON(200, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GET /api/snapshots/:name/packages
|
||||||
|
func apiSnapshotsSearchPackages(c *gin.Context) {
|
||||||
|
collection := context.CollectionFactory().SnapshotCollection()
|
||||||
|
collection.RLock()
|
||||||
|
defer collection.RUnlock()
|
||||||
|
|
||||||
|
snapshot, err := collection.ByName(c.Params.ByName("name"))
|
||||||
|
if err != nil {
|
||||||
|
c.Fail(404, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = collection.LoadComplete(snapshot)
|
||||||
|
if err != nil {
|
||||||
|
c.Fail(500, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
showPackages(c, snapshot.RefList())
|
||||||
|
}
|
||||||
+12
-64
@@ -4,49 +4,8 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"github.com/smira/aptly/deb"
|
"github.com/smira/aptly/deb"
|
||||||
"github.com/smira/commander"
|
"github.com/smira/commander"
|
||||||
"sort"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Snapshot sorting methods
|
|
||||||
const (
|
|
||||||
SortName = iota
|
|
||||||
SortTime
|
|
||||||
)
|
|
||||||
|
|
||||||
type snapshotListToSort struct {
|
|
||||||
list []*deb.Snapshot
|
|
||||||
sortMethod int
|
|
||||||
}
|
|
||||||
|
|
||||||
func parseSortMethod(sortMethod string) (int, error) {
|
|
||||||
switch sortMethod {
|
|
||||||
case "time", "Time":
|
|
||||||
return SortTime, nil
|
|
||||||
case "name", "Name":
|
|
||||||
return SortName, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return -1, fmt.Errorf("sorting method \"%s\" unknown", sortMethod)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s snapshotListToSort) Swap(i, j int) {
|
|
||||||
s.list[i], s.list[j] = s.list[j], s.list[i]
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s snapshotListToSort) Less(i, j int) bool {
|
|
||||||
switch s.sortMethod {
|
|
||||||
case SortName:
|
|
||||||
return s.list[i].Name < s.list[j].Name
|
|
||||||
case SortTime:
|
|
||||||
return s.list[i].CreatedAt.Before(s.list[j].CreatedAt)
|
|
||||||
}
|
|
||||||
panic("unknown sort method")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s snapshotListToSort) Len() int {
|
|
||||||
return len(s.list)
|
|
||||||
}
|
|
||||||
|
|
||||||
func aptlySnapshotList(cmd *commander.Command, args []string) error {
|
func aptlySnapshotList(cmd *commander.Command, args []string) error {
|
||||||
var err error
|
var err error
|
||||||
if len(args) != 0 {
|
if len(args) != 0 {
|
||||||
@@ -57,35 +16,24 @@ func aptlySnapshotList(cmd *commander.Command, args []string) error {
|
|||||||
raw := cmd.Flag.Lookup("raw").Value.Get().(bool)
|
raw := cmd.Flag.Lookup("raw").Value.Get().(bool)
|
||||||
sortMethodString := cmd.Flag.Lookup("sort").Value.Get().(string)
|
sortMethodString := cmd.Flag.Lookup("sort").Value.Get().(string)
|
||||||
|
|
||||||
snapshotsToSort := &snapshotListToSort{}
|
collection := context.CollectionFactory().SnapshotCollection()
|
||||||
snapshotsToSort.list = make([]*deb.Snapshot, context.CollectionFactory().SnapshotCollection().Len())
|
|
||||||
snapshotsToSort.sortMethod, err = parseSortMethod(sortMethodString)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
i := 0
|
|
||||||
context.CollectionFactory().SnapshotCollection().ForEach(func(snapshot *deb.Snapshot) error {
|
|
||||||
snapshotsToSort.list[i] = snapshot
|
|
||||||
i++
|
|
||||||
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
|
|
||||||
context.CloseDatabase()
|
|
||||||
|
|
||||||
sort.Sort(snapshotsToSort)
|
|
||||||
|
|
||||||
if raw {
|
if raw {
|
||||||
for _, snapshot := range snapshotsToSort.list {
|
collection.ForEachSorted(sortMethodString, func(snapshot *deb.Snapshot) error {
|
||||||
fmt.Printf("%s\n", snapshot.Name)
|
fmt.Printf("%s\n", snapshot.Name)
|
||||||
}
|
return nil
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
if len(snapshotsToSort.list) > 0 {
|
if collection.Len() > 0 {
|
||||||
fmt.Printf("List of snapshots:\n")
|
fmt.Printf("List of snapshots:\n")
|
||||||
|
|
||||||
for _, snapshot := range snapshotsToSort.list {
|
err = collection.ForEachSorted(sortMethodString, func(snapshot *deb.Snapshot) error {
|
||||||
fmt.Printf(" * %s\n", snapshot.String())
|
fmt.Printf(" * %s\n", snapshot.String())
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf("\nTo get more information about snapshot, run `aptly snapshot show <name>`.\n")
|
fmt.Printf("\nTo get more information about snapshot, run `aptly snapshot show <name>`.\n")
|
||||||
@@ -93,8 +41,8 @@ func aptlySnapshotList(cmd *commander.Command, args []string) error {
|
|||||||
fmt.Printf("\nNo snapshots found, create one with `aptly snapshot create...`.\n")
|
fmt.Printf("\nNo snapshots found, create one with `aptly snapshot create...`.\n")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return err
|
|
||||||
|
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeCmdSnapshotList() *commander.Command {
|
func makeCmdSnapshotList() *commander.Command {
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package deb
|
package deb
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/smira/aptly/aptly"
|
"github.com/smira/aptly/aptly"
|
||||||
"github.com/smira/aptly/utils"
|
"github.com/smira/aptly/utils"
|
||||||
@@ -38,6 +39,11 @@ type Package struct {
|
|||||||
collection *PackageCollection
|
collection *PackageCollection
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check interface
|
||||||
|
var (
|
||||||
|
_ json.Marshaler = &Package{}
|
||||||
|
)
|
||||||
|
|
||||||
// NewPackageFromControlFile creates Package from parsed Debian control file
|
// NewPackageFromControlFile creates Package from parsed Debian control file
|
||||||
func NewPackageFromControlFile(input Stanza) *Package {
|
func NewPackageFromControlFile(input Stanza) *Package {
|
||||||
result := &Package{
|
result := &Package{
|
||||||
@@ -205,6 +211,16 @@ func (p *Package) String() string {
|
|||||||
return fmt.Sprintf("%s_%s_%s", p.Name, p.Version, p.Architecture)
|
return fmt.Sprintf("%s_%s_%s", p.Name, p.Version, p.Architecture)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MarshalJSON implements json.Marshaller interface
|
||||||
|
func (p *Package) MarshalJSON() ([]byte, error) {
|
||||||
|
stanza := p.Stanza()
|
||||||
|
stanza["FilesHash"] = fmt.Sprintf("%08x", p.FilesHash)
|
||||||
|
stanza["Key"] = string(p.Key(""))
|
||||||
|
stanza["ShortKey"] = string(p.ShortKey(""))
|
||||||
|
|
||||||
|
return json.Marshal(stanza)
|
||||||
|
}
|
||||||
|
|
||||||
// GetField returns fields from package
|
// GetField returns fields from package
|
||||||
func (p *Package) GetField(name string) string {
|
func (p *Package) GetField(name string) string {
|
||||||
switch name {
|
switch name {
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ package deb
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"github.com/AlekSi/pointer"
|
||||||
"github.com/ugorji/go/codec"
|
"github.com/ugorji/go/codec"
|
||||||
"sort"
|
"sort"
|
||||||
)
|
)
|
||||||
@@ -154,6 +156,27 @@ type PackageDiff struct {
|
|||||||
Left, Right *Package
|
Left, Right *Package
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check interface
|
||||||
|
var (
|
||||||
|
_ json.Marshaler = PackageDiff{}
|
||||||
|
)
|
||||||
|
|
||||||
|
// MarshalJSON implements json.Marshaler interface
|
||||||
|
func (d PackageDiff) MarshalJSON() ([]byte, error) {
|
||||||
|
serialized := struct {
|
||||||
|
Left, Right *string
|
||||||
|
}{}
|
||||||
|
|
||||||
|
if d.Left != nil {
|
||||||
|
serialized.Left = pointer.ToString(string(d.Left.Key("")))
|
||||||
|
}
|
||||||
|
if d.Right != nil {
|
||||||
|
serialized.Right = pointer.ToString(string(d.Right.Key("")))
|
||||||
|
}
|
||||||
|
|
||||||
|
return json.Marshal(serialized)
|
||||||
|
}
|
||||||
|
|
||||||
// PackageDiffs is a list of PackageDiff records
|
// PackageDiffs is a list of PackageDiff records
|
||||||
type PackageDiffs []PackageDiff
|
type PackageDiffs []PackageDiff
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import (
|
|||||||
"github.com/smira/aptly/utils"
|
"github.com/smira/aptly/utils"
|
||||||
"github.com/ugorji/go/codec"
|
"github.com/ugorji/go/codec"
|
||||||
"log"
|
"log"
|
||||||
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
@@ -296,6 +297,22 @@ func (collection *SnapshotCollection) ForEach(handler func(*Snapshot) error) err
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (collection *SnapshotCollection) ForEachSorted(sortMethod string, handler func(*Snapshot) error) error {
|
||||||
|
sorter, err := newSnapshotSorter(sortMethod, collection)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, i := range sorter.list {
|
||||||
|
err = handler(collection.list[i])
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// Len returns number of snapshots in collection
|
// Len returns number of snapshots in collection
|
||||||
// ForEach runs method for each snapshot
|
// ForEach runs method for each snapshot
|
||||||
func (collection *SnapshotCollection) Len() int {
|
func (collection *SnapshotCollection) Len() int {
|
||||||
@@ -327,3 +344,55 @@ func (collection *SnapshotCollection) Drop(snapshot *Snapshot) error {
|
|||||||
|
|
||||||
return collection.db.Delete(snapshot.RefKey())
|
return collection.db.Delete(snapshot.RefKey())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Snapshot sorting methods
|
||||||
|
const (
|
||||||
|
SortName = iota
|
||||||
|
SortTime
|
||||||
|
)
|
||||||
|
|
||||||
|
type snapshotSorter struct {
|
||||||
|
list []int
|
||||||
|
collection *SnapshotCollection
|
||||||
|
sortMethod int
|
||||||
|
}
|
||||||
|
|
||||||
|
func newSnapshotSorter(sortMethod string, collection *SnapshotCollection) (*snapshotSorter, error) {
|
||||||
|
s := &snapshotSorter{collection: collection}
|
||||||
|
|
||||||
|
switch sortMethod {
|
||||||
|
case "time", "Time":
|
||||||
|
s.sortMethod = SortTime
|
||||||
|
case "name", "Name":
|
||||||
|
s.sortMethod = SortName
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("sorting method \"%s\" unknown", sortMethod)
|
||||||
|
}
|
||||||
|
|
||||||
|
s.list = make([]int, len(collection.list))
|
||||||
|
for i := range s.list {
|
||||||
|
s.list[i] = i
|
||||||
|
}
|
||||||
|
|
||||||
|
sort.Sort(s)
|
||||||
|
|
||||||
|
return s, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *snapshotSorter) Swap(i, j int) {
|
||||||
|
s.list[i], s.list[j] = s.list[j], s.list[i]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *snapshotSorter) Less(i, j int) bool {
|
||||||
|
switch s.sortMethod {
|
||||||
|
case SortName:
|
||||||
|
return s.collection.list[s.list[i]].Name < s.collection.list[s.list[j]].Name
|
||||||
|
case SortTime:
|
||||||
|
return s.collection.list[s.list[i]].CreatedAt.Before(s.collection.list[s.list[j]].CreatedAt)
|
||||||
|
}
|
||||||
|
panic("unknown sort method")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *snapshotSorter) Len() int {
|
||||||
|
return len(s.list)
|
||||||
|
}
|
||||||
|
|||||||
@@ -47,6 +47,14 @@ class APITest(BaseTest):
|
|||||||
kwargs["headers"]["Content-Type"] = "application/json"
|
kwargs["headers"]["Content-Type"] = "application/json"
|
||||||
return requests.post("http://%s%s" % (self.base_url, uri), *args, **kwargs)
|
return requests.post("http://%s%s" % (self.base_url, uri), *args, **kwargs)
|
||||||
|
|
||||||
|
def put(self, uri, *args, **kwargs):
|
||||||
|
if "json" in kwargs:
|
||||||
|
kwargs["data"] = json.dumps(kwargs.pop("json"))
|
||||||
|
if not "headers" in kwargs:
|
||||||
|
kwargs["headers"] = {}
|
||||||
|
kwargs["headers"]["Content-Type"] = "application/json"
|
||||||
|
return requests.put("http://%s%s" % (self.base_url, uri), *args, **kwargs)
|
||||||
|
|
||||||
def delete(self, uri, *args, **kwargs):
|
def delete(self, uri, *args, **kwargs):
|
||||||
if "json" in kwargs:
|
if "json" in kwargs:
|
||||||
kwargs["data"] = json.dumps(kwargs.pop("json"))
|
kwargs["data"] = json.dumps(kwargs.pop("json"))
|
||||||
|
|||||||
@@ -267,6 +267,16 @@ class BaseTest(object):
|
|||||||
if a != b:
|
if a != b:
|
||||||
self.verify_match(a, b, match_prepare=pprint.pformat)
|
self.verify_match(a, b, match_prepare=pprint.pformat)
|
||||||
|
|
||||||
|
def check_subset(self, a, b):
|
||||||
|
diff = ''
|
||||||
|
for k, v in a.items():
|
||||||
|
if k not in b:
|
||||||
|
diff += "unexpected key '%s'\n" % (k,)
|
||||||
|
elif b[k] != v:
|
||||||
|
diff += "wrong value '%s' for key '%s', expected '%s'\n" % (v, k, b[k])
|
||||||
|
if diff:
|
||||||
|
raise Exception("content doesn't match:\n" + diff)
|
||||||
|
|
||||||
def verify_match(self, a, b, match_prepare=None):
|
def verify_match(self, a, b, match_prepare=None):
|
||||||
if match_prepare is not None:
|
if match_prepare is not None:
|
||||||
a = match_prepare(a)
|
a = match_prepare(a)
|
||||||
|
|||||||
@@ -1 +1,2 @@
|
|||||||
|
List of snapshots:
|
||||||
ERROR: sorting method "planet" unknown
|
ERROR: sorting method "planet" unknown
|
||||||
|
|||||||
@@ -87,5 +87,8 @@ class ListSnapshot7Test(BaseTest):
|
|||||||
"""
|
"""
|
||||||
list snapshots: wrong parameter sort
|
list snapshots: wrong parameter sort
|
||||||
"""
|
"""
|
||||||
|
fixtureCmds = [
|
||||||
|
"aptly snapshot create empty empty"
|
||||||
|
]
|
||||||
runCmd = "aptly -sort=planet snapshot list"
|
runCmd = "aptly -sort=planet snapshot list"
|
||||||
expectedCode = 1
|
expectedCode = 1
|
||||||
|
|||||||
@@ -7,3 +7,4 @@ from .files import *
|
|||||||
from .publish import *
|
from .publish import *
|
||||||
from .version import *
|
from .version import *
|
||||||
from .graph import *
|
from .graph import *
|
||||||
|
from .snapshots import *
|
||||||
|
|||||||
@@ -163,6 +163,10 @@ class ReposAPITestShowQuery(APITest):
|
|||||||
self.check_equal(sorted(self.get("/api/repos/" + repo_name + "/packages", params={"q": "Version (> 0.6.1-1.4)"}).json()),
|
self.check_equal(sorted(self.get("/api/repos/" + repo_name + "/packages", params={"q": "Version (> 0.6.1-1.4)"}).json()),
|
||||||
['Pi386 libboost-program-options-dev 1.49.0.1 918d2f433384e378', 'Psource pyspi 0.6.1-1.4 f8f1daa806004e89'])
|
['Pi386 libboost-program-options-dev 1.49.0.1 918d2f433384e378', 'Psource pyspi 0.6.1-1.4 f8f1daa806004e89'])
|
||||||
|
|
||||||
|
self.check_equal(sorted(p['Key'] for p in self.get("/api/repos/" + repo_name + "/packages",
|
||||||
|
params={"q": "pyspi", "format": "details"}).json()),
|
||||||
|
['Psource pyspi 0.6.1-1.3 3a8b37cbd9a3559e', 'Psource pyspi 0.6.1-1.4 f8f1daa806004e89'])
|
||||||
|
|
||||||
resp = self.get("/api/repos/" + repo_name + "/packages", params={"q": "pyspi)"})
|
resp = self.get("/api/repos/" + repo_name + "/packages", params={"q": "pyspi)"})
|
||||||
self.check_equal(resp.status_code, 400)
|
self.check_equal(resp.status_code, 400)
|
||||||
self.check_equal(resp.json()[0]["error"], u'parsing failed: unexpected token ): expecting end of query')
|
self.check_equal(resp.json()[0]["error"], u'parsing failed: unexpected token ): expecting end of query')
|
||||||
|
|||||||
@@ -0,0 +1,199 @@
|
|||||||
|
from api_lib import APITest
|
||||||
|
|
||||||
|
|
||||||
|
class SnapshotsAPITestCreateShow(APITest):
|
||||||
|
"""
|
||||||
|
GET /api/snapshots/:name, POST /api/snapshots, GET /api/snapshots/:name/packages
|
||||||
|
"""
|
||||||
|
def check(self):
|
||||||
|
snapshot_name = self.random_name()
|
||||||
|
snapshot_desc = {u'Description': u'fun snapshot',
|
||||||
|
u'Name': snapshot_name}
|
||||||
|
|
||||||
|
resp = self.post("/api/snapshots", json=snapshot_desc)
|
||||||
|
self.check_subset(snapshot_desc, resp.json())
|
||||||
|
self.check_equal(resp.status_code, 201)
|
||||||
|
|
||||||
|
self.check_subset(snapshot_desc, self.get("/api/snapshots/" + snapshot_name).json())
|
||||||
|
self.check_equal(self.get("/api/snapshots/" + snapshot_name).status_code, 200)
|
||||||
|
|
||||||
|
self.check_equal(self.get("/api/snapshots/" + self.random_name()).status_code, 404)
|
||||||
|
|
||||||
|
|
||||||
|
class SnapshotsAPITestCreateFromRefs(APITest):
|
||||||
|
"""
|
||||||
|
GET /api/snapshots/:name, POST /api/snapshots, GET /api/snapshots/:name/packages
|
||||||
|
"""
|
||||||
|
def check(self):
|
||||||
|
snapshot_name = self.random_name()
|
||||||
|
snapshot_desc = {u'Description': u'fun snapshot',
|
||||||
|
u'Name': snapshot_name,
|
||||||
|
u'SourceIDs': ['123']}
|
||||||
|
|
||||||
|
resp = self.post("/api/snapshots", json=snapshot_desc)
|
||||||
|
self.check_equal(resp.status_code, 404)
|
||||||
|
|
||||||
|
resp = self.post("/api/snapshots", json={"Name": self.random_name()})
|
||||||
|
self.check_equal(resp.status_code, 201)
|
||||||
|
snapshot_desc['SourceIDs'] = [resp.json()["UUID"]]
|
||||||
|
|
||||||
|
snapshot = snapshot_desc.copy()
|
||||||
|
snapshot['PackageRefs'] = ["Pi386 libboost-program-options-dev 1.49.0.1 918d2f433384e378"]
|
||||||
|
resp = self.post("/api/snapshots", json=snapshot)
|
||||||
|
self.check_equal(resp.status_code, 201)
|
||||||
|
self.check_subset(snapshot_desc, resp.json())
|
||||||
|
|
||||||
|
self.check_subset(snapshot_desc, self.get("/api/snapshots/" + snapshot_name).json())
|
||||||
|
self.check_equal(self.get("/api/snapshots/" + snapshot_name).status_code, 200)
|
||||||
|
|
||||||
|
self.check_equal(self.get("/api/snapshots/" + self.random_name()).status_code, 404)
|
||||||
|
|
||||||
|
|
||||||
|
class SnapshotsAPITestCreateFromRepo(APITest):
|
||||||
|
"""
|
||||||
|
POST /api/repos, POST /api/repos/:name/snapshots, GET /api/snapshots/:name
|
||||||
|
"""
|
||||||
|
def check(self):
|
||||||
|
repo_name = self.random_name()
|
||||||
|
snapshot_name = self.random_name()
|
||||||
|
self.check_equal(self.post("/api/repos", json={"Name": repo_name}).status_code, 201)
|
||||||
|
|
||||||
|
resp = self.post("/api/repos/" + repo_name + '/snapshots', json={'Name': snapshot_name})
|
||||||
|
self.check_equal(resp.status_code, 400)
|
||||||
|
|
||||||
|
d = self.random_name()
|
||||||
|
self.check_equal(self.upload("/api/files/" + d,
|
||||||
|
"libboost-program-options-dev_1.49.0.1_i386.deb").status_code, 200)
|
||||||
|
|
||||||
|
self.check_equal(self.post("/api/repos/" + repo_name + "/file/" + d).status_code, 200)
|
||||||
|
|
||||||
|
resp = self.post("/api/repos/" + repo_name + '/snapshots', json={'Name': snapshot_name})
|
||||||
|
self.check_equal(self.get("/api/snapshots/" + snapshot_name).status_code, 200)
|
||||||
|
|
||||||
|
self.check_subset({u'Architecture': 'i386',
|
||||||
|
u'Package': 'libboost-program-options-dev',
|
||||||
|
u'Version': '1.49.0.1',
|
||||||
|
'FilesHash': '918d2f433384e378'},
|
||||||
|
self.get("/api/snapshots/" + snapshot_name + "/packages", params={"format": "details"}).json()[0])
|
||||||
|
|
||||||
|
self.check_subset({u'Architecture': 'i386',
|
||||||
|
u'Package': 'libboost-program-options-dev',
|
||||||
|
u'Version': '1.49.0.1',
|
||||||
|
'FilesHash': '918d2f433384e378'},
|
||||||
|
self.get("/api/snapshots/" + snapshot_name + "/packages",
|
||||||
|
params={"format": "details", "q": "Version (> 0.6.1-1.4)"}).json()[0])
|
||||||
|
|
||||||
|
|
||||||
|
class SnapshotsAPITestCreateUpdate(APITest):
|
||||||
|
"""
|
||||||
|
POST /api/snapshots, PUT /api/snapshots/:name, GET /api/snapshots/:name
|
||||||
|
"""
|
||||||
|
def check(self):
|
||||||
|
snapshot_name = self.random_name()
|
||||||
|
snapshot_desc = {u'Description': u'fun snapshot',
|
||||||
|
u'Name': snapshot_name}
|
||||||
|
|
||||||
|
resp = self.post("/api/snapshots", json=snapshot_desc)
|
||||||
|
self.check_equal(resp.status_code, 201)
|
||||||
|
|
||||||
|
new_snapshot_name = self.random_name()
|
||||||
|
resp = self.put("/api/snapshots/" + snapshot_name, json={'Name': new_snapshot_name,
|
||||||
|
'Description': 'New description'})
|
||||||
|
self.check_equal(resp.status_code, 200)
|
||||||
|
|
||||||
|
resp = self.get("/api/snapshots/" + new_snapshot_name)
|
||||||
|
self.check_equal(resp.status_code, 200)
|
||||||
|
self.check_subset({"Name": new_snapshot_name,
|
||||||
|
"Description": "New description"}, resp.json())
|
||||||
|
|
||||||
|
|
||||||
|
class SnapshotsAPITestCreateDelete(APITest):
|
||||||
|
"""
|
||||||
|
POST /api/snapshots, DELETE /api/snapshots/:name, GET /api/snapshots/:name
|
||||||
|
"""
|
||||||
|
def check(self):
|
||||||
|
snapshot_name = self.random_name()
|
||||||
|
snapshot_desc = {u'Description': u'fun snapshot',
|
||||||
|
u'Name': snapshot_name}
|
||||||
|
|
||||||
|
resp = self.post("/api/snapshots", json=snapshot_desc)
|
||||||
|
self.check_equal(resp.status_code, 201)
|
||||||
|
|
||||||
|
self.check_equal(self.delete("/api/snapshots/" + snapshot_name).status_code, 200)
|
||||||
|
|
||||||
|
self.check_equal(self.get("/api/snapshots/" + snapshot_name).status_code, 404)
|
||||||
|
|
||||||
|
|
||||||
|
class SnapshotsAPITestSearch(APITest):
|
||||||
|
"""
|
||||||
|
POST /api/snapshots, GET /api/snapshots?sort=name, GET /api/snapshots/:name
|
||||||
|
"""
|
||||||
|
def check(self):
|
||||||
|
|
||||||
|
repo_name = self.random_name()
|
||||||
|
self.check_equal(self.post("/api/repos", json={"Name": repo_name}).status_code, 201)
|
||||||
|
|
||||||
|
d = self.random_name()
|
||||||
|
snapshot_name = self.random_name()
|
||||||
|
self.check_equal(self.upload("/api/files/" + d,
|
||||||
|
"libboost-program-options-dev_1.49.0.1_i386.deb").status_code, 200)
|
||||||
|
|
||||||
|
self.check_equal(self.post("/api/repos/" + repo_name + "/file/" + d).status_code, 200)
|
||||||
|
|
||||||
|
resp = self.post("/api/repos/" + repo_name + '/snapshots', json={'Name': snapshot_name})
|
||||||
|
self.check_equal(resp.status_code, 201)
|
||||||
|
|
||||||
|
resp = self.get("/api/snapshots/" + snapshot_name + "/packages",
|
||||||
|
params={"q": "libboost-program-options-dev", "format": "details"})
|
||||||
|
self.check_equal(resp.status_code, 200)
|
||||||
|
|
||||||
|
self.check_equal(len(resp.json()), 1)
|
||||||
|
self.check_equal(resp.json()[0]["Package"], "libboost-program-options-dev")
|
||||||
|
|
||||||
|
resp = self.get("/api/snapshots/" + snapshot_name + "/packages")
|
||||||
|
self.check_equal(resp.status_code, 200)
|
||||||
|
|
||||||
|
self.check_equal(len(resp.json()), 1)
|
||||||
|
self.check_equal(resp.json(), ["Pi386 libboost-program-options-dev 1.49.0.1 918d2f433384e378"])
|
||||||
|
|
||||||
|
|
||||||
|
class SnapshotsAPITestDiff(APITest):
|
||||||
|
"""
|
||||||
|
GET /api/snapshot/:name/diff/:name2
|
||||||
|
"""
|
||||||
|
def check(self):
|
||||||
|
repos = [self.random_name() for x in xrange(2)]
|
||||||
|
snapshots = [self.random_name() for x in xrange(2)]
|
||||||
|
|
||||||
|
for repo_name in repos:
|
||||||
|
self.check_equal(self.post("/api/repos", json={"Name": repo_name}).status_code, 201)
|
||||||
|
|
||||||
|
d = self.random_name()
|
||||||
|
self.check_equal(self.upload("/api/files/" + d,
|
||||||
|
"libboost-program-options-dev_1.49.0.1_i386.deb").status_code, 200)
|
||||||
|
|
||||||
|
self.check_equal(self.post("/api/repos/" + repo_name + "/file/" + d).status_code, 200)
|
||||||
|
|
||||||
|
resp = self.post("/api/repos/" + repo_name + '/snapshots', json={'Name': snapshots[0]})
|
||||||
|
self.check_equal(resp.status_code, 201)
|
||||||
|
|
||||||
|
resp = self.post("/api/snapshots", json={'Name': snapshots[1]})
|
||||||
|
self.check_equal(resp.status_code, 201)
|
||||||
|
|
||||||
|
resp = self.get("/api/snapshots/" + snapshots[0] + "/diff/" + snapshots[1])
|
||||||
|
self.check_equal(resp.status_code, 200)
|
||||||
|
self.check_equal(resp.json(), [{'Left': 'Pi386 libboost-program-options-dev 1.49.0.1 918d2f433384e378',
|
||||||
|
'Right': None}])
|
||||||
|
|
||||||
|
resp = self.get("/api/snapshots/" + snapshots[1] + "/diff/" + snapshots[0])
|
||||||
|
self.check_equal(resp.status_code, 200)
|
||||||
|
self.check_equal(resp.json(), [{'Right': 'Pi386 libboost-program-options-dev 1.49.0.1 918d2f433384e378',
|
||||||
|
'Left': None}])
|
||||||
|
|
||||||
|
resp = self.get("/api/snapshots/" + snapshots[0] + "/diff/" + snapshots[0])
|
||||||
|
self.check_equal(resp.status_code, 200)
|
||||||
|
self.check_equal(resp.json(), [])
|
||||||
|
|
||||||
|
resp = self.get("/api/snapshots/" + snapshots[1] + "/diff/" + snapshots[1])
|
||||||
|
self.check_equal(resp.status_code, 200)
|
||||||
|
self.check_equal(resp.json(), [])
|
||||||
Reference in New Issue
Block a user