package archive import ( "archive/tar" "compress/gzip" "fmt" "io" "os" "strings" makeshift "git.towk2.me/towk/makeshift/pkg" ) func Create(filenames []string, buf io.Writer, hooks []makeshift.Hook) error { // Create new Writers for gzip and tar // These writers are chained. Writing to the tar writer will // write to the gzip writer which in turn will write to // the "buf" writer gw := gzip.NewWriter(buf) defer gw.Close() tw := tar.NewWriter(gw) defer tw.Close() // Iterate over files and add them to the tar archive for _, filename := range filenames { err := addToArchive(tw, filename, hooks) if err != nil { return err } } return nil } func Expand(path string) error { return nil } func addToArchive(tw *tar.Writer, filename string, hooks []makeshift.Hook) error { var ( tempfile = fmt.Sprintf("%s.tmp", filename) file *os.File contents []byte data any err error ) // run pre-hooks to modify the contents of the file // before archiving using plugins for _, hook := range hooks { // set the file in the data store before running hook contents, err = os.ReadFile(filename) if err != nil { return fmt.Errorf("failed to read '%s' to download: %v", filename, err) } hook.Data.Set("file", contents) err = hook.Run() if err != nil { return err } // create temporary file to use to add to archive hook = hooks[len(hooks)-1] data, err = hook.Data.Get("out") if err != nil { return fmt.Errorf("failed to get output data from '%s' plugin: %v", hook.Plugin.Name(), err) } err = os.WriteFile(tempfile, data.([]byte), 0o777) if err != nil { return fmt.Errorf("failed to write temporary file: %v", err) } } // use original file if no hooks to write archive if len(hooks) == 0 { file, err = os.Open(filename) } else { file, err = os.Open(tempfile) } if err != nil { return fmt.Errorf("failed to open archive file: %v", err) } defer file.Close() // get FileInfo for file size, mode, etc. info, err := file.Stat() if err != nil { return err } // skip file if it's a directory if info.IsDir() { return nil } // create a tar Header from the FileInfo data header, err := tar.FileInfoHeader(info, info.Name()) if err != nil { return fmt.Errorf("failed to create FileInfoHeader: %v", err) } // use full path as name (FileInfoHeader only takes the basename) to // preserve directory structure // see for more info: https://golang.org/src/archive/tar/common.go?#L626 header.Name = filename // Write file header to the tar archive err = tw.WriteHeader(header) if err != nil { return err } // copy file content to tar archive if len(hooks) == 0 { _, err = io.Copy(tw, file) } else { _, err = io.Copy(tw, strings.NewReader(string(data.([]byte)))) } if err != nil { return err } // delete the temporary file since we're done with it if len(hooks) != 0 { err = os.Remove(tempfile) if err != nil { return err } } return nil }