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