package archive import ( "archive/tar" "errors" "fmt" "io" "io/fs" "path/filepath" "code.icb4dc0.de/buildr/buildr/internal/ignore" ) var ErrEmptyArchive = errors.New("no files were added to the archive") type Tar struct { Ignorer *ignore.Ignorer root *archiveNode } func (t *Tar) Write(writer io.Writer) error { if t.root == nil { return ErrEmptyArchive } tarWriter := tar.NewWriter(writer) if err := t.root.writeToTar(tarWriter, t.Ignorer, ""); err != nil { return err } return tarWriter.Close() } func (t *Tar) Remove(path string) bool { if t.root == nil { return false } return t.root.remove(path) } func (t *Tar) Add(srcPath, destPath string) error { if t.root == nil { t.root = newNode() } info, err := t.Ignorer.Stat(srcPath) if err != nil { return fmt.Errorf("failed to get file information for %s: %w", srcPath, err) } if info.IsDir() { return t.addDir(srcPath, destPath) } t.addFile(srcPath, destPath) return nil } func (t *Tar) addFile(srcPath, destPath string) { if t.root == nil { t.root = newNode() } t.root.addFile(srcPath, destPath) } func (t *Tar) addDir(srcPath, destPath string) error { if t.root == nil { t.root = newNode() } err := t.Ignorer.WalkDir(srcPath, func(path string, d fs.DirEntry, err error) error { if err != nil { return err } relativeToSource, err := filepath.Rel(srcPath, path) if err != nil { return fmt.Errorf("failed to determine relative path for %s: %w", path, err) } if d.IsDir() { t.root.addDir(filepath.Join(destPath, relativeToSource)) } else { t.root.addFile(path, filepath.Join(destPath, relativeToSource)) } return nil }) if err != nil { return fmt.Errorf("failed to add dir %s recursively: %w", srcPath, err) } return nil }