@@ -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+
180233func 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-
232271func main () {
233272 rootCmd := & cobra.Command {
234273 Use : "aptblob" ,
0 commit comments