Skip to content

Commit 53115e2

Browse files
committed
Support uploading source packages
1 parent ca79ef9 commit 53115e2

File tree

3 files changed

+216
-102
lines changed

3 files changed

+216
-102
lines changed

aptblob.go

Lines changed: 133 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020
"context"
2121
"fmt"
2222
"os"
23+
"path/filepath"
2324
"strings"
2425

2526
"github.com/spf13/cobra"
@@ -79,96 +80,58 @@ func cmdUpload(ctx context.Context, bucket *blob.Bucket, comp component, keyID s
7980
addToTokenSet(&release, "Components", comp.name)
8081

8182
binaryAdditions := make(map[string][]deb.Paragraph)
83+
var sourceAdditions []deb.Paragraph
8284
for _, path := range paths {
83-
pkg, err := uploadBinaryPackage(ctx, bucket, path)
84-
if err != nil {
85-
return err
86-
}
87-
arch := pkg.Get("Architecture")
88-
if arch == "all" {
89-
for _, arch := range strings.Fields(release.Get("Architectures")) {
90-
binaryAdditions[arch] = append(binaryAdditions[arch], pkg)
85+
switch filepath.Ext(path) {
86+
case ".deb":
87+
pkg, err := uploadBinaryPackage(ctx, bucket, path)
88+
if err != nil {
89+
return err
9190
}
92-
continue
93-
}
94-
addToTokenSet(&release, "Architectures", arch)
95-
binaryAdditions[arch] = append(binaryAdditions[arch], pkg)
96-
}
97-
98-
for arch, newPackages := range binaryAdditions {
99-
// List existing packages.
100-
var packages []deb.Paragraph
101-
if packagesReader, err := bucket.NewReader(ctx, comp.binaryIndexPath(arch), nil); err == nil {
102-
p := deb.NewParser(packagesReader)
103-
p.Fields = deb.ControlFields
104-
for p.Next() {
105-
packages = append(packages, p.Paragraph())
91+
arch := pkg.Get("Architecture")
92+
if arch == "all" {
93+
for _, arch := range strings.Fields(release.Get("Architectures")) {
94+
binaryAdditions[arch] = append(binaryAdditions[arch], pkg)
95+
}
96+
continue
10697
}
107-
packagesReader.Close()
108-
if err := p.Err(); err != nil {
109-
return fmt.Errorf("%s: %w", comp.binaryIndexPath(arch), err)
98+
addToTokenSet(&release, "Architectures", arch)
99+
binaryAdditions[arch] = append(binaryAdditions[arch], pkg)
100+
case ".dsc":
101+
pkg, err := uploadSourcePackage(ctx, bucket, path)
102+
if err != nil {
103+
return err
110104
}
111-
} else if gcerrors.Code(err) != gcerrors.NotFound {
112-
return err
113-
}
114-
115-
// Append packages to index.
116-
packages = append(packages, newPackages...)
117-
packageIndexHashes, packageIndexGzipHashes, err :=
118-
uploadPackageIndex(ctx, bucket, comp, arch, packages)
119-
if err != nil {
120-
return err
105+
sourceAdditions = append(sourceAdditions, pkg)
106+
default:
107+
return fmt.Errorf("%s: unrecognized extension", path)
121108
}
109+
}
122110

123-
// Update release signatures.
124-
packagesDistPath := strings.TrimPrefix(comp.binaryIndexPath(arch), comp.dist.dir()+"/")
125-
packagesGzipDistPath := strings.TrimPrefix(comp.binaryIndexGzipPath(arch), comp.dist.dir()+"/")
126-
err = updateSignature(&release, "MD5Sum",
127-
deb.IndexSignature{
128-
Filename: packagesDistPath,
129-
Checksum: packageIndexHashes.md5[:],
130-
Size: packageIndexHashes.size,
131-
},
132-
deb.IndexSignature{
133-
Filename: packagesGzipDistPath,
134-
Checksum: packageIndexGzipHashes.md5[:],
135-
Size: packageIndexGzipHashes.size,
136-
},
111+
for arch, packages := range binaryAdditions {
112+
err := appendToIndex(ctx,
113+
bucket,
114+
comp.dist,
115+
&release,
116+
comp.binaryIndexPath(arch),
117+
deb.ControlFields,
118+
packages,
137119
)
138120
if err != nil {
139-
return fmt.Errorf("%s: %w", comp.dist.indexPath(), err)
140-
}
141-
err = updateSignature(&release, "SHA1",
142-
deb.IndexSignature{
143-
Filename: packagesDistPath,
144-
Checksum: packageIndexHashes.sha1[:],
145-
Size: packageIndexHashes.size,
146-
},
147-
deb.IndexSignature{
148-
Filename: packagesGzipDistPath,
149-
Checksum: packageIndexGzipHashes.sha1[:],
150-
Size: packageIndexGzipHashes.size,
151-
},
152-
)
153-
if err != nil {
154-
return fmt.Errorf("%s: %w", comp.dist.indexPath(), err)
155-
}
156-
err = updateSignature(&release, "SHA256",
157-
deb.IndexSignature{
158-
Filename: packagesDistPath,
159-
Checksum: packageIndexHashes.sha256[:],
160-
Size: packageIndexHashes.size,
161-
},
162-
deb.IndexSignature{
163-
Filename: packagesGzipDistPath,
164-
Checksum: packageIndexGzipHashes.sha256[:],
165-
Size: packageIndexGzipHashes.size,
166-
},
167-
)
168-
if err != nil {
169-
return fmt.Errorf("%s: %w", comp.dist.indexPath(), err)
121+
return err
170122
}
171123
}
124+
err = appendToIndex(ctx,
125+
bucket,
126+
comp.dist,
127+
&release,
128+
comp.sourceIndexPath(),
129+
deb.SourceControlFields,
130+
sourceAdditions,
131+
)
132+
if err != nil {
133+
return err
134+
}
172135

173136
if err := uploadReleaseIndex(ctx, bucket, comp.dist, release, keyID); err != nil {
174137
return err
@@ -177,6 +140,96 @@ func cmdUpload(ctx context.Context, bucket *blob.Bucket, comp component, keyID s
177140
return nil
178141
}
179142

143+
func appendToIndex(ctx context.Context, bucket *blob.Bucket, dist distribution, release *deb.Paragraph, key string, fields map[string]deb.FieldType, newParagraphs []deb.Paragraph) error {
144+
if len(newParagraphs) == 0 {
145+
return nil
146+
}
147+
148+
// List existing packages.
149+
packages, err := downloadIndex(ctx, bucket, key, fields)
150+
if err != nil {
151+
return err
152+
}
153+
154+
// Append packages to index.
155+
packages = append(packages, newParagraphs...)
156+
indexHashes, gzipIndexHashes, err := uploadIndex(ctx, bucket, key, packages)
157+
if err != nil {
158+
return err
159+
}
160+
161+
// Update release signatures.
162+
distPath := strings.TrimPrefix(key, dist.dir()+"/")
163+
gzipDistPath := distPath + gzipExtension
164+
err = updateSignature(release, "MD5Sum",
165+
deb.IndexSignature{
166+
Filename: distPath,
167+
Checksum: indexHashes.md5[:],
168+
Size: indexHashes.size,
169+
},
170+
deb.IndexSignature{
171+
Filename: gzipDistPath,
172+
Checksum: gzipIndexHashes.md5[:],
173+
Size: gzipIndexHashes.size,
174+
},
175+
)
176+
if err != nil {
177+
return fmt.Errorf("%s: %w", dist.indexPath(), err)
178+
}
179+
err = updateSignature(release, "SHA1",
180+
deb.IndexSignature{
181+
Filename: distPath,
182+
Checksum: indexHashes.sha1[:],
183+
Size: indexHashes.size,
184+
},
185+
deb.IndexSignature{
186+
Filename: gzipDistPath,
187+
Checksum: gzipIndexHashes.sha1[:],
188+
Size: gzipIndexHashes.size,
189+
},
190+
)
191+
if err != nil {
192+
return fmt.Errorf("%s: %w", dist.indexPath(), err)
193+
}
194+
err = updateSignature(release, "SHA256",
195+
deb.IndexSignature{
196+
Filename: distPath,
197+
Checksum: indexHashes.sha256[:],
198+
Size: indexHashes.size,
199+
},
200+
deb.IndexSignature{
201+
Filename: gzipDistPath,
202+
Checksum: gzipIndexHashes.sha256[:],
203+
Size: gzipIndexHashes.size,
204+
},
205+
)
206+
if err != nil {
207+
return fmt.Errorf("%s: %w", dist.indexPath(), err)
208+
}
209+
return nil
210+
}
211+
212+
func downloadIndex(ctx context.Context, bucket *blob.Bucket, key string, fields map[string]deb.FieldType) ([]deb.Paragraph, error) {
213+
r, err := bucket.NewReader(ctx, key, nil)
214+
if err != nil {
215+
if gcerrors.Code(err) == gcerrors.NotFound {
216+
return nil, nil
217+
}
218+
return nil, fmt.Errorf("%s: %w", key, err)
219+
}
220+
defer r.Close()
221+
p := deb.NewParser(r)
222+
p.Fields = fields
223+
var paragraphs []deb.Paragraph
224+
for p.Next() {
225+
paragraphs = append(paragraphs, append(deb.Paragraph(nil), p.Paragraph()...))
226+
}
227+
if err := p.Err(); err != nil {
228+
return nil, fmt.Errorf("%s: %w", key, err)
229+
}
230+
return paragraphs, nil
231+
}
232+
180233
func updateSignature(para *deb.Paragraph, key string, newSigs ...deb.IndexSignature) error {
181234
if len(newSigs) == 0 {
182235
return nil
@@ -215,20 +268,6 @@ func updateSignature(para *deb.Paragraph, key string, newSigs ...deb.IndexSignat
215268
return nil
216269
}
217270

218-
// promotePackageField ensures the Package field is the first in the paragraph.
219-
// It modifies the paragraph in-place.
220-
//
221-
// This is necessary for Packages and Sources paragraphs to be spec-compliant.
222-
func promotePackageField(para deb.Paragraph) {
223-
for i, f := range para {
224-
if f.Name == "Package" {
225-
copy(para[1:], para[:i])
226-
para[0] = f
227-
return
228-
}
229-
}
230-
}
231-
232271
func main() {
233272
rootCmd := &cobra.Command{
234273
Use: "aptblob",

internal/deb/deb.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,11 +105,14 @@ func ExtractControl(r io.Reader) ([]byte, error) {
105105

106106
// ControlFields is the set of fields in the binary package control file.
107107
var ControlFields = map[string]FieldType{
108+
"Description": Multiline,
109+
}
110+
111+
// SourceControlFields is the set of fields in the source package control file.
112+
var SourceControlFields = map[string]FieldType{
108113
"Binary": Folded,
109-
"Changes": Multiline,
110114
"Checksums-Sha1": Multiline,
111115
"Checksums-Sha256": Multiline,
112-
"Description": Multiline,
113116
"Dgit": Folded,
114117
"Files": Multiline,
115118
"Package-List": Multiline,

0 commit comments

Comments
 (0)