func StreamArchive(output io.Writer, location string) (err error) {
	buf := bufio.NewWriter(output)
	countW := &countWriter{w: buf}
	zw, _ := gzip.NewWriterLevel(countW, gzip.NoCompression)
	tw := tar.NewWriter(zw)
	bw := &tarBodyWriter{
		writer: tw,
		buf:    make([]byte, chunkSize),
	}
	toc, err := Archive(bw, location)
	if err != nil {
		return err
	}
	if err := tw.Close(); err != nil {
		return err
	}
	if err := zw.Close(); err != nil {
		return err
	}
	tocOff := countW.n
	{
		zw, _ = gzip.NewWriterLevel(countW, gzip.NoCompression)
		tocJSON, err := json.MarshalIndent(toc, "", "  ")
		if err != nil {
			return err
		}
		tw := tar.NewWriter(zw)
		if err := tw.WriteHeader(&tar.Header{
			Typeflag: tar.TypeReg,
			Name:     tocTarName,
			Size:     int64(len(tocJSON)),
		}); err != nil {
			return err
		}
		if _, err := tw.Write(tocJSON); err != nil {
			return err
		}
		if err := tw.Close(); err != nil {
			return err
		}
		if err := zw.Close(); err != nil {
			return err
		}
	}
	if _, err := countW.Write(footerBytes(tocOff)); err != nil {
		return err
	}
	return buf.Flush()
}
StreamArchive and UnarchiveStream stick the chunked archive into a single
file. So far this use case is just for local archiving and replacing bytes,
but it implements some of the patterns present in crfs/stargz in case that is
a future use-case for this format. For the time being we'll assume any
network requests for files will download individual chunks from an index, but
for now it seemed good to follow in this general direction over picking
something arbitrary.
package chunkedarchive
import (
	"archive/tar"
	"bufio"
	"bytes"
	"compress/gzip"
	"encoding/json"
	"fmt"
	"io"
	"strconv"
	"sync"
	"github.com/maxmcd/bramble/pkg/hasher"
	"github.com/pkg/errors"
)
const (
	footerSize = 47
	tocTarName = "chunkedarchive.index.json"
)