package main import ( "archive/tar" "compress/gzip" "flag" "fmt" "io" "io/ioutil" "log" "os" "path/filepath" "strings" "time" "github.com/otiai10/copy" ) var ( fname = flag.String("fname", "slug.tar.gz", "slug name") ) func main() { flag.Parse() fout, err := os.Create(*fname) if err != nil { log.Fatal(err) } defer fout.Close() gzw := gzip.NewWriter(fout) defer gzw.Close() tw := tar.NewWriter(gzw) defer tw.Close() dir, err := ioutil.TempDir("", "sluggen") if err != nil { log.Fatal(err) } copy.Copy("./book", dir) defer os.RemoveAll(dir) // clean up os.MkdirAll(filepath.Join(dir, "bin"), 0777) var scalefile string scalefile += fmt.Sprintf("web=1\n") os.MkdirAll(filepath.Join(dir, ".config"), 0777) os.MkdirAll(filepath.Join(dir, "client_body_temp"), 0777) os.MkdirAll(filepath.Join(dir, "proxy_temp"), 0777) os.MkdirAll(filepath.Join(dir, "fastcgi_temp"), 0777) os.MkdirAll(filepath.Join(dir, "uwsgi_temp"), 0777) os.MkdirAll(filepath.Join(dir, "scgi_temp"), 0777) err = ioutil.WriteFile(filepath.Join(dir, "static.json"), []byte(`{ "root": "." }`), 0666) err = ioutil.WriteFile(filepath.Join(dir, ".buildpacks"), []byte("https://github.com/heroku/heroku-buildpack-static"), 0666) if err != nil { log.Fatal(err) } err = ioutil.WriteFile(filepath.Join(dir, "DOKKU_SCALE"), []byte(scalefile), 0666) if err != nil { log.Fatal(err) } filepath.Walk(dir, func(file string, fi os.FileInfo, err error) error { // return on any error if err != nil { return err } // create a new dir/file header header, err := tar.FileInfoHeader(fi, fi.Name()) if err != nil { return err } // update the name to correctly reflect the desired destination when untaring header.Name = strings.TrimPrefix(strings.Replace(file, dir, "", -1), string(filepath.Separator)) // write the header if err := tw.WriteHeader(header); err != nil { return err } // return on non-regular files (thanks to [kumo](https://medium.com/@komuw/just-like-you-did-fbdd7df829d3) for this suggested update) if !fi.Mode().IsRegular() { return nil } // open files for taring f, err := os.Open(file) if err != nil { return err } // copy file data into tar writer if _, err := io.Copy(tw, f); err != nil { return err } // manually close here after each file operation; defering would cause each file close // to wait until all operations have completed. f.Close() return nil }) time.Sleep(time.Second) } // Copy the src file to dst. Any existing file will be overwritten and will not // copy file attributes. func Copy(src, dst string) error { in, err := os.Open(src) if err != nil { return err } defer in.Close() st, err := in.Stat() if err != nil { return err } out, err := os.OpenFile(dst, os.O_CREATE|os.O_WRONLY, st.Mode()) if err != nil { return err } defer out.Close() _, err = io.Copy(out, in) if err != nil { return err } return out.Close() }