[mirror] Scalable static site server for Git forges (like GitHub Pages)
at main 3.0 kB view raw
1package git_pages 2 3import ( 4 "archive/tar" 5 "context" 6 "fmt" 7 "io" 8) 9 10type Flusher interface { 11 Flush() error 12} 13 14// Inverse of `ExtractTar`. 15func CollectTar( 16 context context.Context, writer io.Writer, manifest *Manifest, metadata ManifestMetadata, 17) ( 18 err error, 19) { 20 archive := tar.NewWriter(writer) 21 22 appendFile := func(header *tar.Header, data []byte, transform Transform) (err error) { 23 switch transform { 24 case Transform_Identity: 25 case Transform_Zstd: 26 data, err = zstdDecoder.DecodeAll(data, []byte{}) 27 if err != nil { 28 return fmt.Errorf("zstd: %s: %w", header.Name, err) 29 } 30 default: 31 return fmt.Errorf("%s: unexpected transform", header.Name) 32 } 33 header.Size = int64(len(data)) 34 35 err = archive.WriteHeader(header) 36 if err != nil { 37 return fmt.Errorf("tar: %w", err) 38 } 39 _, err = archive.Write(data) 40 if err != nil { 41 return fmt.Errorf("tar: %w", err) 42 } 43 return 44 } 45 46 for fileName, entry := range manifest.Contents { 47 var header tar.Header 48 if fileName == "" { 49 continue 50 } 51 header.Name = fileName 52 53 switch entry.GetType() { 54 case Type_Directory: 55 header.Typeflag = tar.TypeDir 56 header.Mode = 0755 57 header.ModTime = metadata.LastModified 58 err = appendFile(&header, nil, Transform_Identity) 59 60 case Type_InlineFile: 61 header.Typeflag = tar.TypeReg 62 header.Mode = 0644 63 header.ModTime = metadata.LastModified 64 err = appendFile(&header, entry.GetData(), entry.GetTransform()) 65 66 case Type_ExternalFile: 67 var blobReader io.Reader 68 var blobMetadata BlobMetadata 69 var blobData []byte 70 blobReader, blobMetadata, err = backend.GetBlob(context, string(entry.Data)) 71 if err != nil { 72 return 73 } 74 blobData, err = io.ReadAll(blobReader) 75 if err != nil { 76 return 77 } 78 header.Typeflag = tar.TypeReg 79 header.Mode = 0644 80 header.ModTime = blobMetadata.LastModified 81 err = appendFile(&header, blobData, entry.GetTransform()) 82 83 case Type_Symlink: 84 header.Typeflag = tar.TypeSymlink 85 header.Mode = 0644 86 header.ModTime = metadata.LastModified 87 err = appendFile(&header, entry.GetData(), Transform_Identity) 88 89 default: 90 panic(fmt.Errorf("CollectTar encountered invalid entry: %v, %v", 91 entry.GetType(), entry.GetTransform())) 92 } 93 if err != nil { 94 return err 95 } 96 } 97 98 if redirects := CollectRedirectsFile(manifest); redirects != "" { 99 err = appendFile(&tar.Header{ 100 Name: RedirectsFileName, 101 Typeflag: tar.TypeReg, 102 Mode: 0644, 103 ModTime: metadata.LastModified, 104 }, []byte(redirects), Transform_Identity) 105 if err != nil { 106 return err 107 } 108 } 109 110 if headers := CollectHeadersFile(manifest); headers != "" { 111 err = appendFile(&tar.Header{ 112 Name: HeadersFileName, 113 Typeflag: tar.TypeReg, 114 Mode: 0644, 115 ModTime: metadata.LastModified, 116 }, []byte(headers), Transform_Identity) 117 if err != nil { 118 return err 119 } 120 } 121 122 err = archive.Flush() 123 if err != nil { 124 return fmt.Errorf("tar: %w", err) 125 } 126 127 flusher, ok := writer.(Flusher) 128 if ok { 129 err = flusher.Flush() 130 } 131 return err 132}