Parsing & generation of source package stanzas.

This commit is contained in:
Andrey Smirnov
2014-02-14 22:04:48 +04:00
parent 213c1e0b4f
commit 22c427bb96
2 changed files with 215 additions and 23 deletions
+131 -20
View File
@@ -37,16 +37,25 @@ func (f *PackageFile) Verify(packageRepo *Repository) (bool, error) {
// Package is single instance of Debian package // Package is single instance of Debian package
type Package struct { type Package struct {
// Is this source package
IsSource bool
// Basic package properties
Name string Name string
Version string Version string
Architecture string Architecture string
Source string // If this source package, this field holds "real" architecture value,
Provides []string // while Architecture would be equal to "source"
SourceArchitecture string
// For binary package, name of source package
Source string
Provides []string
// Various dependencies // Various dependencies
Depends []string Depends []string
PreDepends []string BuildDepends []string
Suggests []string BuildDependsInDep []string
Recommends []string PreDepends []string
Suggests []string
Recommends []string
// Files in package // Files in package
Files []PackageFile Files []PackageFile
// Extra information from stanza // Extra information from stanza
@@ -112,6 +121,83 @@ func NewPackageFromControlFile(input Stanza) *Package {
return result return result
} }
// NewSourcePackageFromControlFile creates Package from parsed Debian control file for source package
func NewSourcePackageFromControlFile(input Stanza) (*Package, error) {
result := &Package{
IsSource: true,
Name: input["Package"],
Version: input["Version"],
Architecture: "source",
SourceArchitecture: input["Architecture"],
}
delete(input, "Package")
delete(input, "Version")
delete(input, "Architecture")
parseSums := func(field string, setter func(sum *utils.ChecksumInfo, data string)) error {
for _, line := range strings.Split(input[field], "\n") {
line = strings.TrimSpace(line)
if line == "" {
continue
}
parts := strings.Fields(line)
if len(parts) != 3 {
return fmt.Errorf("unparseable hash sum line: %#v", line)
}
size, err := strconv.ParseInt(parts[1], 10, 64)
if err != nil {
return fmt.Errorf("unable to parse size: %s", err)
}
found := false
pos := 0
for i, file := range result.Files {
if file.Filename == parts[2] {
found = true
pos = i
break
}
}
if !found {
result.Files = append(result.Files, PackageFile{Filename: parts[2]})
pos = len(result.Files) - 1
}
result.Files[pos].Checksums.Size = size
setter(&result.Files[pos].Checksums, parts[0])
}
delete(input, field)
return nil
}
err := parseSums("Files", func(sum *utils.ChecksumInfo, data string) { sum.MD5 = data })
if err != nil {
return nil, err
}
err = parseSums("Checksums-Sha1", func(sum *utils.ChecksumInfo, data string) { sum.SHA1 = data })
if err != nil {
return nil, err
}
err = parseSums("Checksums-Sha256", func(sum *utils.ChecksumInfo, data string) { sum.SHA256 = data })
if err != nil {
return nil, err
}
result.BuildDepends = parseDependencies(input, "Build-Depends")
result.BuildDependsInDep = parseDependencies(input, "Build-Depends-Indep")
result.Extra = input
return result, nil
}
// Key returns unique key identifying package // Key returns unique key identifying package
func (p *Package) Key() []byte { func (p *Package) Key() []byte {
return []byte("P" + p.Architecture + " " + p.Name + " " + p.Version) return []byte("P" + p.Architecture + " " + p.Name + " " + p.Version)
@@ -169,18 +255,38 @@ func (p *Package) Stanza() (result Stanza) {
result = p.Extra.Copy() result = p.Extra.Copy()
result["Package"] = p.Name result["Package"] = p.Name
result["Version"] = p.Version result["Version"] = p.Version
result["Filename"] = p.Files[0].Filename
result["Architecture"] = p.Architecture
result["Source"] = p.Source
if p.Files[0].Checksums.MD5 != "" { if p.IsSource {
result["MD5sum"] = p.Files[0].Checksums.MD5 result["Architecture"] = p.SourceArchitecture
} else {
result["Architecture"] = p.Architecture
result["Source"] = p.Source
} }
if p.Files[0].Checksums.SHA1 != "" {
result["SHA1"] = " " + p.Files[0].Checksums.SHA1 if p.IsSource {
} md5, sha1, sha256 := make([]string, len(p.Files)), make([]string, len(p.Files)), make([]string, len(p.Files))
if p.Files[0].Checksums.SHA256 != "" {
result["SHA256"] = " " + p.Files[0].Checksums.SHA256 for i, f := range p.Files {
md5[i] = fmt.Sprintf(" %s %d %s\n", f.Checksums.MD5, f.Checksums.Size, f.Filename)
sha1[i] = fmt.Sprintf(" %s %d %s\n", f.Checksums.SHA1, f.Checksums.Size, f.Filename)
sha256[i] = fmt.Sprintf(" %s %d %s\n", f.Checksums.SHA256, f.Checksums.Size, f.Filename)
}
result["Files"] = strings.Join(md5, "")
result["Checksums-Sha1"] = strings.Join(sha1, "")
result["Checksums-Sha256"] = strings.Join(sha256, "")
} else {
result["Filename"] = p.Files[0].Filename
if p.Files[0].Checksums.MD5 != "" {
result["MD5sum"] = p.Files[0].Checksums.MD5
}
if p.Files[0].Checksums.SHA1 != "" {
result["SHA1"] = " " + p.Files[0].Checksums.SHA1
}
if p.Files[0].Checksums.SHA256 != "" {
result["SHA256"] = " " + p.Files[0].Checksums.SHA256
}
result["Size"] = fmt.Sprintf("%d", p.Files[0].Checksums.Size)
} }
if p.Depends != nil { if p.Depends != nil {
@@ -198,8 +304,12 @@ func (p *Package) Stanza() (result Stanza) {
if p.Provides != nil { if p.Provides != nil {
result["Provides"] = strings.Join(p.Provides, ", ") result["Provides"] = strings.Join(p.Provides, ", ")
} }
if p.BuildDepends != nil {
result["Size"] = fmt.Sprintf("%d", p.Files[0].Checksums.Size) result["Build-Depends"] = strings.Join(p.BuildDepends, ", ")
}
if p.BuildDependsInDep != nil {
result["Build-Depends-Indep"] = strings.Join(p.BuildDependsInDep, ", ")
}
return return
} }
@@ -216,11 +326,12 @@ func (p *Package) Equals(p2 *Package) bool {
} }
} }
return p.Name == p2.Name && p.Version == p2.Version && return p.Name == p2.Name && p.Version == p2.Version && p.SourceArchitecture == p2.SourceArchitecture &&
p.Architecture == p2.Architecture && utils.StrSlicesEqual(p.Depends, p2.Depends) && p.Architecture == p2.Architecture && utils.StrSlicesEqual(p.Depends, p2.Depends) &&
utils.StrSlicesEqual(p.PreDepends, p2.PreDepends) && utils.StrSlicesEqual(p.Suggests, p2.Suggests) && utils.StrSlicesEqual(p.PreDepends, p2.PreDepends) && utils.StrSlicesEqual(p.Suggests, p2.Suggests) &&
utils.StrSlicesEqual(p.Recommends, p2.Recommends) && utils.StrMapsEqual(p.Extra, p2.Extra) && utils.StrSlicesEqual(p.Recommends, p2.Recommends) && utils.StrMapsEqual(p.Extra, p2.Extra) &&
p.Source == p2.Source && utils.StrSlicesEqual(p.Provides, p2.Provides) p.Source == p2.Source && utils.StrSlicesEqual(p.Provides, p2.Provides) && utils.StrSlicesEqual(p.BuildDepends, p2.BuildDepends) &&
utils.StrSlicesEqual(p.BuildDependsInDep, p2.BuildDependsInDep) && p.IsSource == p2.IsSource
} }
// LinkFromPool links package file from pool to dist's pool location // LinkFromPool links package file from pool to dist's pool location
+84 -3
View File
@@ -1,6 +1,7 @@
package debian package debian
import ( import (
"bytes"
"github.com/smira/aptly/database" "github.com/smira/aptly/database"
"github.com/smira/aptly/utils" "github.com/smira/aptly/utils"
. "launchpad.net/gocheck" . "launchpad.net/gocheck"
@@ -8,16 +9,18 @@ import (
"path/filepath" "path/filepath"
) )
var packageStanza = Stanza{"Source": "alien-arena", "Pre-Depends": "dpkg (>= 1.6)", "Suggests": "alien-arena-mars", "Recommends": "aliean-arena-luna", "Depends": "libc6 (>= 2.7), alien-arena-data (>= 7.40)", "Filename": "pool/contrib/a/alien-arena/alien-arena-common_7.40-2_i386.deb", "SHA1": " 46955e48cad27410a83740a21d766ce362364024", "SHA256": " eb4afb9885cba6dc70cccd05b910b2dbccc02c5900578be5e99f0d3dbf9d76a5", "Priority": "extra", "Maintainer": "Debian Games Team <pkg-games-devel@lists.alioth.debian.org>", "Description": "Common files for Alien Arena client and server ALIEN ARENA is a standalone 3D first person online deathmatch shooter\n crafted from the original source code of Quake II and Quake III, released\n by id Software under the GPL license. With features including 32 bit\n graphics, new particle engine and effects, light blooms, reflective water,\n hi resolution textures and skins, hi poly models, stain maps, ALIEN ARENA\n pushes the envelope of graphical beauty rivaling today's top games.\n .\n This package installs the common files for Alien Arena.\n", "Homepage": "http://red.planetarena.org", "Tag": "role::app-data, role::shared-lib, special::auto-inst-parts", "Installed-Size": "456", "Version": "7.40-2", "Replaces": "alien-arena (<< 7.33-1)", "Size": "187518", "MD5sum": "1e8cba92c41420aa7baa8a5718d67122", "Package": "alien-arena-common", "Section": "contrib/games", "Architecture": "i386"}
type PackageSuite struct { type PackageSuite struct {
stanza Stanza stanza Stanza
sourceStanza Stanza
} }
var _ = Suite(&PackageSuite{}) var _ = Suite(&PackageSuite{})
func (s *PackageSuite) SetUpTest(c *C) { func (s *PackageSuite) SetUpTest(c *C) {
s.stanza = packageStanza.Copy() s.stanza = packageStanza.Copy()
buf := bytes.NewBufferString(sourcePackageMeta)
s.sourceStanza, _ = NewControlFileReader(buf).ReadStanza()
} }
func (s *PackageSuite) TestPackageFileVerify(c *C) { func (s *PackageSuite) TestPackageFileVerify(c *C) {
@@ -58,6 +61,7 @@ func (s *PackageSuite) TestPackageFileVerify(c *C) {
func (s *PackageSuite) TestNewFromPara(c *C) { func (s *PackageSuite) TestNewFromPara(c *C) {
p := NewPackageFromControlFile(s.stanza) p := NewPackageFromControlFile(s.stanza)
c.Check(p.IsSource, Equals, false)
c.Check(p.Name, Equals, "alien-arena-common") c.Check(p.Name, Equals, "alien-arena-common")
c.Check(p.Version, Equals, "7.40-2") c.Check(p.Version, Equals, "7.40-2")
c.Check(p.Architecture, Equals, "i386") c.Check(p.Architecture, Equals, "i386")
@@ -69,6 +73,37 @@ func (s *PackageSuite) TestNewFromPara(c *C) {
c.Check(p.Depends, DeepEquals, []string{"libc6 (>= 2.7)", "alien-arena-data (>= 7.40)"}) c.Check(p.Depends, DeepEquals, []string{"libc6 (>= 2.7)", "alien-arena-data (>= 7.40)"})
} }
func (s *PackageSuite) TestNewSourceFromPara(c *C) {
p, err := NewSourcePackageFromControlFile(s.sourceStanza)
c.Check(err, IsNil)
c.Check(p.IsSource, Equals, true)
c.Check(p.Name, Equals, "access-modifier-checker")
c.Check(p.Version, Equals, "1.0-4")
c.Check(p.Architecture, Equals, "source")
c.Check(p.SourceArchitecture, Equals, "all")
c.Check(p.Provides, IsNil)
c.Check(p.BuildDepends, DeepEquals, []string{"cdbs", "debhelper (>= 7)", "default-jdk", "maven-debian-helper"})
c.Check(p.BuildDependsInDep, DeepEquals, []string{"default-jdk-doc", "junit (>= 3.8.1)", "libannotation-indexer-java (>= 1.3)", "libannotation-indexer-java-doc", "libasm3-java", "libmaven-install-plugin-java", "libmaven-javadoc-plugin-java", "libmaven-scm-java", "libmaven2-core-java", "libmaven2-core-java-doc", "libmetainf-services-java", "libmetainf-services-java-doc", "libmaven-plugin-tools-java (>= 2.8)"})
c.Check(p.Files, HasLen, 3)
c.Check(p.Files[0].Filename, Equals, "access-modifier-checker_1.0-4.dsc")
c.Check(p.Files[0].Checksums.Size, Equals, int64(2583))
c.Check(p.Files[0].Checksums.MD5, Equals, "eb2a7a57c92ebac9d3d1c2d2d719f290")
c.Check(p.Files[0].Checksums.SHA1, Equals, "a70b87bba4391c0138cc9cc75efa747c4eeea2d7")
c.Check(p.Files[0].Checksums.SHA256, Equals, "36ae7f68974bd69450229244510faa8f8056709913770218821069e6cce6b4b8")
c.Check(p.Files[1].Filename, Equals, "access-modifier-checker_1.0.orig.tar.gz")
c.Check(p.Files[1].Checksums.Size, Equals, int64(10049))
c.Check(p.Files[1].Checksums.MD5, Equals, "f280abdc753beea4243d99530f023f12")
c.Check(p.Files[1].Checksums.SHA1, Equals, "c5bea16095ae1685941193370d20756e036d61a7")
c.Check(p.Files[1].Checksums.SHA256, Equals, "9d362301892bd647a361755bde28f0a39644a5bbb2ff5300060373ee29d9d87a")
c.Check(p.Files[2].Filename, Equals, "access-modifier-checker_1.0-4.debian.tar.gz")
c.Check(p.Depends, IsNil)
}
func (s *PackageSuite) TestWithProvides(c *C) { func (s *PackageSuite) TestWithProvides(c *C) {
s.stanza["Provides"] = "arena" s.stanza["Provides"] = "arena"
p := NewPackageFromControlFile(s.stanza) p := NewPackageFromControlFile(s.stanza)
@@ -101,6 +136,11 @@ func (s *PackageSuite) TestStanza(c *C) {
stanza := p.Stanza() stanza := p.Stanza()
c.Assert(stanza, DeepEquals, s.stanza) c.Assert(stanza, DeepEquals, s.stanza)
p, _ = NewSourcePackageFromControlFile(s.sourceStanza.Copy())
stanza = p.Stanza()
c.Assert(stanza, DeepEquals, s.sourceStanza)
} }
func (s *PackageSuite) TestString(c *C) { func (s *PackageSuite) TestString(c *C) {
@@ -120,6 +160,11 @@ func (s *PackageSuite) TestEquals(c *C) {
p2 = NewPackageFromControlFile(packageStanza.Copy()) p2 = NewPackageFromControlFile(packageStanza.Copy())
p2.Files[0].Checksums.MD5 = "abcdefabcdef" p2.Files[0].Checksums.MD5 = "abcdefabcdef"
c.Check(p.Equals(p2), Equals, false) c.Check(p.Equals(p2), Equals, false)
so, _ := NewSourcePackageFromControlFile(s.sourceStanza.Copy())
so2, _ := NewSourcePackageFromControlFile(s.sourceStanza.Copy())
c.Check(so.Equals(so2), Equals, true)
} }
func (s *PackageSuite) TestMatchesArchitecture(c *C) { func (s *PackageSuite) TestMatchesArchitecture(c *C) {
@@ -267,3 +312,39 @@ func (s *PackageCollectionSuite) TestDeleteByKey(c *C) {
_, err = s.collection.ByKey(s.p.Key()) _, err = s.collection.ByKey(s.p.Key())
c.Check(err, ErrorMatches, "key not found") c.Check(err, ErrorMatches, "key not found")
} }
var packageStanza = Stanza{"Source": "alien-arena", "Pre-Depends": "dpkg (>= 1.6)", "Suggests": "alien-arena-mars", "Recommends": "aliean-arena-luna", "Depends": "libc6 (>= 2.7), alien-arena-data (>= 7.40)", "Filename": "pool/contrib/a/alien-arena/alien-arena-common_7.40-2_i386.deb", "SHA1": " 46955e48cad27410a83740a21d766ce362364024", "SHA256": " eb4afb9885cba6dc70cccd05b910b2dbccc02c5900578be5e99f0d3dbf9d76a5", "Priority": "extra", "Maintainer": "Debian Games Team <pkg-games-devel@lists.alioth.debian.org>", "Description": "Common files for Alien Arena client and server ALIEN ARENA is a standalone 3D first person online deathmatch shooter\n crafted from the original source code of Quake II and Quake III, released\n by id Software under the GPL license. With features including 32 bit\n graphics, new particle engine and effects, light blooms, reflective water,\n hi resolution textures and skins, hi poly models, stain maps, ALIEN ARENA\n pushes the envelope of graphical beauty rivaling today's top games.\n .\n This package installs the common files for Alien Arena.\n", "Homepage": "http://red.planetarena.org", "Tag": "role::app-data, role::shared-lib, special::auto-inst-parts", "Installed-Size": "456", "Version": "7.40-2", "Replaces": "alien-arena (<< 7.33-1)", "Size": "187518", "MD5sum": "1e8cba92c41420aa7baa8a5718d67122", "Package": "alien-arena-common", "Section": "contrib/games", "Architecture": "i386"}
const sourcePackageMeta = `Package: access-modifier-checker
Binary: libaccess-modifier-checker-java, libaccess-modifier-checker-java-doc
Version: 1.0-4
Maintainer: Debian Java Maintainers <pkg-java-maintainers@lists.alioth.debian.org>
Uploaders: James Page <james.page@ubuntu.com>
Build-Depends: cdbs, debhelper (>= 7), default-jdk, maven-debian-helper
Build-Depends-Indep: default-jdk-doc, junit (>= 3.8.1), libannotation-indexer-java (>= 1.3), libannotation-indexer-java-doc, libasm3-java, libmaven-install-plugin-java, libmaven-javadoc-plugin-java, libmaven-scm-java, libmaven2-core-java, libmaven2-core-java-doc, libmetainf-services-java, libmetainf-services-java-doc, libmaven-plugin-tools-java (>= 2.8)
Architecture: all
Standards-Version: 3.9.3
Format: 3.0 (quilt)
Files:
eb2a7a57c92ebac9d3d1c2d2d719f290 2583 access-modifier-checker_1.0-4.dsc
f280abdc753beea4243d99530f023f12 10049 access-modifier-checker_1.0.orig.tar.gz
182b18d7a4bfd1a4e6bfda886f986766 4310 access-modifier-checker_1.0-4.debian.tar.gz
Dm-Upload-Allowed: yes
Vcs-Browser: http://git.debian.org/?p=pkg-java/access-modifier-checker.git
Vcs-Git: git://git.debian.org/git/pkg-java/access-modifier-checker.git
Checksums-Sha1:
a70b87bba4391c0138cc9cc75efa747c4eeea2d7 2583 access-modifier-checker_1.0-4.dsc
c5bea16095ae1685941193370d20756e036d61a7 10049 access-modifier-checker_1.0.orig.tar.gz
54033d40ae2f35eb147df0876c649eb9d2eb86bc 4310 access-modifier-checker_1.0-4.debian.tar.gz
Checksums-Sha256:
36ae7f68974bd69450229244510faa8f8056709913770218821069e6cce6b4b8 2583 access-modifier-checker_1.0-4.dsc
9d362301892bd647a361755bde28f0a39644a5bbb2ff5300060373ee29d9d87a 10049 access-modifier-checker_1.0.orig.tar.gz
23852c63f7b5511b4c827a443ff0f92926fc71efc57dc47b49cb2fd9136d8f95 4310 access-modifier-checker_1.0-4.debian.tar.gz
Homepage: https://github.com/kohsuke/access-modifier
Package-List:
libaccess-modifier-checker-java deb java optional
libaccess-modifier-checker-java-doc deb doc optional
Directory: pool/main/a/access-modifier-checker
Priority: source
Section: java
`