|
package main |
|
|
|
import ( |
|
"archive/tar" |
|
"compress/gzip" |
|
"crypto/sha256" |
|
"flag" |
|
"fmt" |
|
"io" |
|
"io/ioutil" |
|
"log" |
|
"os" |
|
|
|
"github.com/vbatts/tar-split/tar/asm" |
|
"github.com/vbatts/tar-split/tar/storage" |
|
) |
|
|
|
var ( |
|
flKeep = flag.Bool("keep", false, "keep tempfiles around") |
|
) |
|
|
|
func main() { |
|
flag.Parse() |
|
|
|
// files to add to the archive |
|
tarFileList := []string{os.Args[0], "app.go", "README.md"} |
|
keepFileList := []string{} |
|
|
|
// 1) create a tar.gz && 2) get the sha256 of the tar.gz |
|
h := sha256.New() |
|
|
|
tf, err := ioutil.TempFile("", "tar-split-test.") |
|
if err != nil { |
|
log.Fatal(err) |
|
} |
|
if !*flKeep { |
|
defer os.Remove(tf.Name()) |
|
} else { |
|
keepFileList = append(keepFileList, tf.Name()) |
|
} |
|
defer tf.Close() |
|
|
|
mw := io.MultiWriter(h, tf) |
|
zw := gzip.NewWriter(mw) |
|
tw := tar.NewWriter(zw) |
|
|
|
// add some files to the tar archive |
|
for _, file := range tarFileList { |
|
func() { |
|
fh, err := os.Open(file) |
|
if err != nil { |
|
log.Fatal(err) |
|
} |
|
defer fh.Close() |
|
fi, err := fh.Stat() |
|
if err != nil { |
|
log.Fatal(err) |
|
} |
|
hdr, err := tar.FileInfoHeader(fi, "") |
|
if err != nil { |
|
log.Fatal(err) |
|
} |
|
|
|
if err := tw.WriteHeader(hdr); err != nil { |
|
log.Fatal(err) |
|
} |
|
|
|
if _, err := io.Copy(tw, fh); err != nil { |
|
log.Fatal(err) |
|
} |
|
}() |
|
} |
|
|
|
if err := tw.Close(); err != nil { |
|
log.Fatal(err) |
|
} |
|
if err := zw.Close(); err != nil { |
|
log.Fatal(err) |
|
} |
|
|
|
checksumIn := h.Sum(nil) |
|
fmt.Printf("Starting Sum on %q: %x\n", tf.Name(), checksumIn) |
|
|
|
// 3) extract (and inflate) the tar and disassemble it |
|
if _, err := tf.Seek(0, 0); err != nil { |
|
log.Fatal(err) |
|
} |
|
gr, err := gzip.NewReader(tf) |
|
if err != nil { |
|
log.Fatal(err) |
|
} |
|
|
|
metaPackerFile, err := ioutil.TempFile("", "tar-split.packer.json.") |
|
if err != nil { |
|
log.Fatal(err) |
|
} |
|
if !*flKeep { |
|
defer os.Remove(metaPackerFile.Name()) |
|
} else { |
|
keepFileList = append(keepFileList, metaPackerFile.Name()) |
|
} |
|
metaPacker := storage.NewJSONPacker(metaPackerFile) |
|
|
|
// since we have the files in tarFileList are present locally, we can discard the bodies here |
|
filePutter := storage.NewDiscardFilePutter() |
|
|
|
its, err := asm.NewInputTarStream(gr, metaPacker, filePutter) |
|
if err != nil { |
|
log.Fatal(err) |
|
} |
|
|
|
// This is where the application would actuall extract the tar archive |
|
if _, err := io.Copy(ioutil.Discard, its); err != nil { |
|
log.Fatal(err) |
|
} |
|
if err := metaPackerFile.Sync(); err != nil { |
|
log.Fatal(err) |
|
} |
|
|
|
// 4) assemble (and deflate) the tar |
|
if _, err := metaPackerFile.Seek(0, 0); err != nil { |
|
log.Fatal(err) |
|
} |
|
metaUnpacker := storage.NewJSONUnpacker(metaPackerFile) |
|
fileGetter := storage.NewPathFileGetter(".") |
|
ots := asm.NewOutputTarStream(fileGetter, metaUnpacker) |
|
h.Reset() // get ready to get the checksum of the resulting tar.gz |
|
gw := gzip.NewWriter(h) |
|
tr := io.TeeReader(ots, gw) |
|
if _, err := io.Copy(ioutil.Discard, tr); err != nil { |
|
log.Fatal(err) |
|
} |
|
if err := ots.Close(); err != nil { |
|
log.Fatal(err) |
|
} |
|
if err := gw.Close(); err != nil { |
|
log.Fatal(err) |
|
} |
|
|
|
// 5) checksum it for validity |
|
checksumOut := h.Sum(nil) |
|
fmt.Printf("Ending Sum on %q: %x\n", tf.Name(), checksumOut) |
|
|
|
if *flKeep { |
|
fmt.Printf("Preserved temporary files %v\n", keepFileList) |
|
} |
|
|
|
} |