| 1219 | } |
| 1220 | |
| 1221 | func zipFile(out string, files []archiveFile) { |
| 1222 | fd, err := os.Create(out) |
| 1223 | if err != nil { |
| 1224 | log.Fatal(err) |
| 1225 | } |
| 1226 | |
| 1227 | zw := zip.NewWriter(fd) |
| 1228 | |
| 1229 | var fw *flate.Writer |
| 1230 | |
| 1231 | // Register the deflator. |
| 1232 | zw.RegisterCompressor(zip.Deflate, func(out io.Writer) (io.WriteCloser, error) { |
| 1233 | var err error |
| 1234 | if fw == nil { |
| 1235 | // Creating a flate compressor for every file is |
| 1236 | // expensive, create one and reuse it. |
| 1237 | fw, err = flate.NewWriter(out, flate.BestCompression) |
| 1238 | } else { |
| 1239 | fw.Reset(out) |
| 1240 | } |
| 1241 | return fw, err |
| 1242 | }) |
| 1243 | |
| 1244 | for _, f := range files { |
| 1245 | sf, err := os.Open(f.src) |
| 1246 | if err != nil { |
| 1247 | log.Fatal(err) |
| 1248 | } |
| 1249 | |
| 1250 | info, err := sf.Stat() |
| 1251 | if err != nil { |
| 1252 | log.Fatal(err) |
| 1253 | } |
| 1254 | |
| 1255 | fh, err := zip.FileInfoHeader(info) |
| 1256 | if err != nil { |
| 1257 | log.Fatal(err) |
| 1258 | } |
| 1259 | fh.Name = filepath.ToSlash(f.dst) |
| 1260 | fh.Method = zip.Deflate |
| 1261 | |
| 1262 | if strings.HasSuffix(f.dst, ".txt") { |
| 1263 | // Text file. Read it and convert line endings. |
| 1264 | bs, err := io.ReadAll(sf) |
| 1265 | if err != nil { |
| 1266 | log.Fatal(err) |
| 1267 | } |
| 1268 | bs = bytes.Replace(bs, []byte{'\n'}, []byte{'\r', '\n'}, -1) |
| 1269 | fh.UncompressedSize = uint32(len(bs)) |
| 1270 | fh.UncompressedSize64 = uint64(len(bs)) |
| 1271 | |
| 1272 | of, err := zw.CreateHeader(fh) |
| 1273 | if err != nil { |
| 1274 | log.Fatal(err) |
| 1275 | } |
| 1276 | of.Write(bs) |
| 1277 | } else { |
| 1278 | // Binary file. Copy verbatim. |