github.com/sashka/siva@v1.6.0/cmd/siva/pack.go (about)

     1  package main
     2  
     3  import (
     4  	"fmt"
     5  	"io"
     6  	"io/ioutil"
     7  	"os"
     8  	"path/filepath"
     9  
    10  	"gopkg.in/src-d/go-siva.v1"
    11  )
    12  
    13  type CmdPack struct {
    14  	cmd
    15  	Append bool `long:"append" description:"If append, the files are added to an existing siva file"`
    16  	Delete bool `long:"delete" description:"If delete, the files are deleted to an existing siva file"`
    17  	Input  struct {
    18  		Files []string `positional-arg-name:"input" description:"files or directories to be add to the archive."`
    19  	} `positional-args:"yes"`
    20  }
    21  
    22  func (c *CmdPack) Execute(args []string) error {
    23  	if err := c.validate(); err != nil {
    24  		return err
    25  	}
    26  
    27  	if err := c.do(); err != nil {
    28  		if err := os.Remove(c.Args.File); err != nil {
    29  			return err
    30  		}
    31  
    32  		return err
    33  	}
    34  
    35  	return nil
    36  }
    37  
    38  func (c *CmdPack) do() error {
    39  	if err := c.buildWriter(c.Append); err != nil {
    40  		return err
    41  	}
    42  
    43  	if err := c.pack(); err != nil {
    44  		_ = c.close()
    45  		return err
    46  	}
    47  
    48  	return c.close()
    49  }
    50  
    51  func (c *CmdPack) validate() error {
    52  	if err := c.cmd.validate(); err != nil {
    53  		return err
    54  	}
    55  
    56  	if len(c.Input.Files) == 0 {
    57  		return fmt.Errorf("Invalid input count, please add one or more input files/dirs")
    58  	}
    59  
    60  	return nil
    61  }
    62  
    63  func (c *CmdPack) pack() error {
    64  	for _, file := range c.Input.Files {
    65  		fi, err := os.Stat(file)
    66  		if err != nil {
    67  			return fmt.Errorf("Invalid input file/dir %q, no such file", file)
    68  		}
    69  
    70  		if err := c.packPath(file, fi); err != nil {
    71  			return err
    72  		}
    73  	}
    74  
    75  	return nil
    76  }
    77  
    78  func (c *CmdPack) packPath(fullpath string, fi os.FileInfo) error {
    79  	if fi.Mode().IsDir() {
    80  		return c.packDir(fullpath)
    81  	}
    82  
    83  	if !fi.Mode().IsRegular() {
    84  		return nil
    85  	}
    86  
    87  	return c.packFile(fullpath, fi)
    88  }
    89  
    90  func (c *CmdPack) packDir(fullpath string) error {
    91  	fis, err := ioutil.ReadDir(fullpath)
    92  	if err != nil {
    93  		return err
    94  	}
    95  
    96  	for _, fi := range fis {
    97  		p := filepath.Join(fullpath, fi.Name())
    98  		err := c.packPath(p, fi)
    99  		if err != nil {
   100  			return err
   101  		}
   102  	}
   103  
   104  	return nil
   105  }
   106  
   107  func (c *CmdPack) packFile(fullpath string, fi os.FileInfo) error {
   108  	if os.SameFile(c.fi, fi) {
   109  		fmt.Fprintf(os.Stderr,
   110  			"skipping %q, cannot archive the target file\n", fullpath)
   111  		return nil
   112  	}
   113  
   114  	c.println(fullpath)
   115  	if err := c.writeFileHeader(fullpath, fi); err != nil {
   116  		return nil
   117  	}
   118  
   119  	return c.writeFile(fullpath, fi)
   120  }
   121  
   122  func (c *CmdPack) writeFileHeader(fullpath string, fi os.FileInfo) error {
   123  	h := &siva.Header{
   124  		Name:    siva.ToSafePath(fullpath),
   125  		Mode:    fi.Mode(),
   126  		ModTime: fi.ModTime(),
   127  	}
   128  
   129  	if c.Delete {
   130  		h.Flags = siva.FlagDeleted
   131  	}
   132  
   133  	if err := c.w.WriteHeader(h); err != nil {
   134  		return err
   135  	}
   136  
   137  	return nil
   138  }
   139  
   140  func (c *CmdPack) writeFile(fullpath string, fi os.FileInfo) error {
   141  	f, err := os.Open(fullpath)
   142  	if err != nil {
   143  		return err
   144  	}
   145  
   146  	defer f.Close()
   147  	n, err := io.Copy(c.w, f)
   148  	if err != nil {
   149  		return err
   150  	}
   151  
   152  	if n != fi.Size() {
   153  		return fmt.Errorf("unexpected bytes written")
   154  	}
   155  
   156  	return c.w.Flush()
   157  }