@@ -24,6 +24,7 @@ import (
2424const (
2525 defaultRepo = "usemoss/moss"
2626 bindingsModulePath = "github.com/usemoss/moss/sdks/go/bindings"
27+ installReceiptName = ".moss-install-checksum"
2728)
2829
2930type platform struct {
@@ -54,7 +55,7 @@ var platforms = []platform{
5455
5556func main () {
5657 all := flag .Bool ("all" , false , "install libraries for all supported platforms" )
57- releaseTag := flag .String ("release" , defaultReleaseTag , "C SDK GitHub release tag" )
58+ releaseTag := flag .String ("release" , "" , "C SDK GitHub release tag (default: target bindings metadata) " )
5859 repo := flag .String ("repo" , defaultRepo , "GitHub repository (owner/name)" )
5960 bindingsDir := flag .String ("bindings" , "" , "bindings directory (default: auto-detect)" )
6061 vendor := flag .Bool ("vendor" , false , "run go mod vendor before installing into a downloaded module" )
@@ -65,6 +66,12 @@ func main() {
6566 if err != nil {
6667 fatal (err )
6768 }
69+ if * releaseTag == "" {
70+ * releaseTag , err = nativeReleaseTag (root )
71+ if err != nil {
72+ fatal (err )
73+ }
74+ }
6875
6976 version := strings .TrimPrefix (* releaseTag , "c-sdk-" )
7077 version = strings .TrimPrefix (version , "v" )
@@ -182,6 +189,31 @@ func goEnv(name string) (string, error) {
182189 return strings .TrimSpace (string (out )), nil
183190}
184191
192+ func nativeReleaseTag (bindingsRoot string ) (string , error ) {
193+ f , err := os .Open (filepath .Join (bindingsRoot , "version.go" ))
194+ if err != nil {
195+ return "" , fmt .Errorf ("read bindings native version: %w" , err )
196+ }
197+ defer f .Close ()
198+
199+ const prefix = "const NativeLibReleaseTag = \" "
200+ scanner := bufio .NewScanner (f )
201+ for scanner .Scan () {
202+ line := strings .TrimSpace (scanner .Text ())
203+ if ! strings .HasPrefix (line , prefix ) || ! strings .HasSuffix (line , "\" " ) {
204+ continue
205+ }
206+ tag := strings .TrimSuffix (strings .TrimPrefix (line , prefix ), "\" " )
207+ if tag != "" {
208+ return tag , nil
209+ }
210+ }
211+ if err := scanner .Err (); err != nil {
212+ return "" , fmt .Errorf ("read bindings native version: %w" , err )
213+ }
214+ return "" , errors .New ("NativeLibReleaseTag not found in bindings/version.go; pass -release explicitly" )
215+ }
216+
185217func selectPlatforms (all bool ) ([]platform , error ) {
186218 if all {
187219 return platforms , nil
@@ -245,17 +277,9 @@ func installPlatform(bindingsRoot, libDir string, installHeader bool, baseURL, v
245277 destLib := filepath .Join (destDir , p .libFile )
246278 headerPath := filepath .Join (bindingsRoot , "include" , "libmoss.h" )
247279
248- if ! force {
249- if err := verifyFileChecksum (destLib , wantChecksum ); err == nil {
250- if ! installHeader {
251- fmt .Printf ("skip %s (already installed)\n " , p .id )
252- return nil
253- }
254- if _ , err := os .Stat (headerPath ); err == nil {
255- fmt .Printf ("skip %s (already installed)\n " , p .id )
256- return nil
257- }
258- }
280+ if ! force && fileExists (destLib ) && (! installHeader || fileExists (headerPath )) && receiptMatches (filepath .Join (destDir , installReceiptName ), archive , wantChecksum ) {
281+ fmt .Printf ("skip %s (already installed)\n " , p .id )
282+ return nil
259283 }
260284
261285 if err := os .MkdirAll (destDir , 0o755 ); err != nil {
@@ -291,11 +315,45 @@ func installPlatform(bindingsRoot, libDir string, installHeader bool, baseURL, v
291315 if err := copyFile (filepath .Join (extractedRoot , p .srcLib ), destLib ); err != nil {
292316 return err
293317 }
318+ if err := writeReceipt (filepath .Join (destDir , installReceiptName ), archive , wantChecksum ); err != nil {
319+ return err
320+ }
294321
295322 fmt .Printf ("installed %s -> %s\n " , p .id , destLib )
296323 return nil
297324}
298325
326+ func fileExists (path string ) bool {
327+ info , err := os .Stat (path )
328+ return err == nil && ! info .IsDir ()
329+ }
330+
331+ func receiptMatches (path , archive , checksum string ) bool {
332+ contents , err := os .ReadFile (path )
333+ if err != nil {
334+ return false
335+ }
336+ return strings .TrimSpace (string (contents )) == checksum + " " + archive
337+ }
338+
339+ func writeReceipt (path , archive , checksum string ) error {
340+ tmp , err := os .CreateTemp (filepath .Dir (path ), ".moss-install-*" )
341+ if err != nil {
342+ return err
343+ }
344+ tmpPath := tmp .Name ()
345+ defer os .Remove (tmpPath )
346+
347+ if _ , err := fmt .Fprintf (tmp , "%s %s\n " , checksum , archive ); err != nil {
348+ tmp .Close ()
349+ return err
350+ }
351+ if err := tmp .Close (); err != nil {
352+ return err
353+ }
354+ return os .Rename (tmpPath , path )
355+ }
356+
299357func extractTarGz (archivePath , destRoot , version , triple string ) error {
300358 f , err := os .Open (archivePath )
301359 if err != nil {
@@ -412,23 +470,6 @@ func downloadFile(url, dest, wantChecksum string) error {
412470 return os .Rename (tmpPath , dest )
413471}
414472
415- func verifyFileChecksum (path , want string ) error {
416- f , err := os .Open (path )
417- if err != nil {
418- return err
419- }
420- defer f .Close ()
421-
422- hasher := sha256 .New ()
423- if _ , err := io .Copy (hasher , f ); err != nil {
424- return err
425- }
426- if hex .EncodeToString (hasher .Sum (nil )) != want {
427- return fmt .Errorf ("checksum mismatch" )
428- }
429- return nil
430- }
431-
432473func copyFile (src , dest string ) error {
433474 in , err := os .Open (src )
434475 if err != nil {
0 commit comments