Skip to content

Instantly share code, notes, and snippets.

@maximilien
Forked from jonmorehouse/tar.go
Last active November 4, 2020 18:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save maximilien/deaaa55f255c8ff45c26 to your computer and use it in GitHub Desktop.
Save maximilien/deaaa55f255c8ff45c26 to your computer and use it in GitHub Desktop.
package main
import (
"os"
"archive/tar"
"log"
"io"
"compress/gzip"
)
func addFile(tw * tar.Writer, path string) error {
file, err := os.Open(path)
if err != nil {
return err
}
defer file.Close()
if stat, err := file.Stat(); err == nil {
// now lets create the header as needed for this file within the tarball
header := new(tar.Header)
header.Name = path
header.Size = stat.Size()
header.Mode = int64(stat.Mode())
header.ModTime = stat.ModTime()
// write the header to the tarball archive
if err := tw.WriteHeader(header); err != nil {
return err
}
// copy the file data to the tarball
if _, err := io.Copy(tw, file); err != nil {
return err
}
}
return nil
}
func main() {
// set up the output file
file, err := os.Create("output.tar.gz")
if err != nil {
log.Fatalln(err)
}
defer file.Close()
// set up the gzip writer
gw := gzip.NewWriter(file)
defer gw.Close()
tw := tar.NewWriter(gw)
defer tw.Close()
// grab the paths that need to be added in
paths := []string{
"readme.txt",
}
// add each file as needed into the current tar archive
for i := range paths {
if err := addFile(tw, paths[i]); err != nil {
log.Fatalln(err)
}
}
}
@maximilien
Copy link
Author

Modified from above to be more as a library method to create a tarball

func CreateTarball(tarballFilePath string, filePaths []string) error {
    file, err := os.Create(tarballFilePath)
    if err != nil {
        return errors.New(fmt.Sprintf("Could not create tarball file '%s', got error '%s'", tarballFilePath, err.Error()))
    }
    defer file.Close()

    gzipWriter := gzip.NewWriter(file)
    defer gzipWriter.Close()

    tarWriter := tar.NewWriter(gzipWriter)
    defer tarWriter.Close()

    for _, filePath := range filePaths {
        err := addFileToTarWriter(filePath, tarWriter)
        if err != nil {
            return errors.New(fmt.Sprintf("Could not add file '%s', to tarball, got error '%s'", filePath, err.Error()))
        }
    }

    return nil
}

// Private methods

func addFileToTarWriter(filePath string, tarWriter *tar.Writer) error {
    file, err := os.Open(filePath)
    if err != nil {
        return errors.New(fmt.Sprintf("Could not open file '%s', got error '%s'", filePath, err.Error()))
    }
    defer file.Close()

    stat, err := file.Stat()
    if err != nil {
        return errors.New(fmt.Sprintf("Could not get stat for file '%s', got error '%s'", filePath, err.Error()))
    }

    header := &tar.Header{
        Name:    filePath,
        Size:    stat.Size(),
        Mode:    int64(stat.Mode()),
        ModTime: stat.ModTime(),
    }

    err = tarWriter.WriteHeader(header)
    if err != nil {
        return errors.New(fmt.Sprintf("Could not write header for file '%s', got error '%s'", filePath, err.Error()))
    }

    _, err = io.Copy(tarWriter, file)
    if err != nil {
        return errors.New(fmt.Sprintf("Could not copy the file '%s' data to the tarball, got error '%s'", filePath, err.Error()))
    }

    return nil
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment