github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/internal/build/archive.go (about)

     1  
     2  //<developer>
     3  //    <name>linapex 曹一峰</name>
     4  //    <email>linapex@163.com</email>
     5  //    <wx>superexc</wx>
     6  //    <qqgroup>128148617</qqgroup>
     7  //    <url>https://jsq.ink</url>
     8  //    <role>pku engineer</role>
     9  //    <date>2019-03-16 19:16:38</date>
    10  //</624450091389816832>
    11  
    12  
    13  package build
    14  
    15  import (
    16  	"archive/tar"
    17  	"archive/zip"
    18  	"compress/gzip"
    19  	"fmt"
    20  	"io"
    21  	"os"
    22  	"path/filepath"
    23  	"strings"
    24  )
    25  
    26  type Archive interface {
    27  //目录将新目录项添加到存档并设置
    28  //用于随后调用头的目录。
    29  	Directory(name string) error
    30  
    31  //头将新文件添加到存档。文件被添加到目录中
    32  //按目录设置。文件的内容必须写入返回的
    33  //作家。
    34  	Header(os.FileInfo) (io.Writer, error)
    35  
    36  //关闭将刷新存档并关闭基础文件。
    37  	Close() error
    38  }
    39  
    40  func NewArchive(file *os.File) (Archive, string) {
    41  	switch {
    42  	case strings.HasSuffix(file.Name(), ".zip"):
    43  		return NewZipArchive(file), strings.TrimSuffix(file.Name(), ".zip")
    44  	case strings.HasSuffix(file.Name(), ".tar.gz"):
    45  		return NewTarballArchive(file), strings.TrimSuffix(file.Name(), ".tar.gz")
    46  	default:
    47  		return nil, ""
    48  	}
    49  }
    50  
    51  //addfile将现有文件追加到存档。
    52  func AddFile(a Archive, file string) error {
    53  	fd, err := os.Open(file)
    54  	if err != nil {
    55  		return err
    56  	}
    57  	defer fd.Close()
    58  	fi, err := fd.Stat()
    59  	if err != nil {
    60  		return err
    61  	}
    62  	w, err := a.Header(fi)
    63  	if err != nil {
    64  		return err
    65  	}
    66  	if _, err := io.Copy(w, fd); err != nil {
    67  		return err
    68  	}
    69  	return nil
    70  }
    71  
    72  //WriteArchive创建包含给定文件的存档。
    73  func WriteArchive(name string, files []string) (err error) {
    74  	archfd, err := os.Create(name)
    75  	if err != nil {
    76  		return err
    77  	}
    78  
    79  	defer func() {
    80  		archfd.Close()
    81  //失败时删除半写存档。
    82  		if err != nil {
    83  			os.Remove(name)
    84  		}
    85  	}()
    86  	archive, basename := NewArchive(archfd)
    87  	if archive == nil {
    88  		return fmt.Errorf("unknown archive extension")
    89  	}
    90  	fmt.Println(name)
    91  	if err := archive.Directory(basename); err != nil {
    92  		return err
    93  	}
    94  	for _, file := range files {
    95  		fmt.Println("   +", filepath.Base(file))
    96  		if err := AddFile(archive, file); err != nil {
    97  			return err
    98  		}
    99  	}
   100  	return archive.Close()
   101  }
   102  
   103  type ZipArchive struct {
   104  	dir  string
   105  	zipw *zip.Writer
   106  	file io.Closer
   107  }
   108  
   109  func NewZipArchive(w io.WriteCloser) Archive {
   110  	return &ZipArchive{"", zip.NewWriter(w), w}
   111  }
   112  
   113  func (a *ZipArchive) Directory(name string) error {
   114  	a.dir = name + "/"
   115  	return nil
   116  }
   117  
   118  func (a *ZipArchive) Header(fi os.FileInfo) (io.Writer, error) {
   119  	head, err := zip.FileInfoHeader(fi)
   120  	if err != nil {
   121  		return nil, fmt.Errorf("can't make zip header: %v", err)
   122  	}
   123  	head.Name = a.dir + head.Name
   124  	head.Method = zip.Deflate
   125  	w, err := a.zipw.CreateHeader(head)
   126  	if err != nil {
   127  		return nil, fmt.Errorf("can't add zip header: %v", err)
   128  	}
   129  	return w, nil
   130  }
   131  
   132  func (a *ZipArchive) Close() error {
   133  	if err := a.zipw.Close(); err != nil {
   134  		return err
   135  	}
   136  	return a.file.Close()
   137  }
   138  
   139  type TarballArchive struct {
   140  	dir  string
   141  	tarw *tar.Writer
   142  	gzw  *gzip.Writer
   143  	file io.Closer
   144  }
   145  
   146  func NewTarballArchive(w io.WriteCloser) Archive {
   147  	gzw := gzip.NewWriter(w)
   148  	tarw := tar.NewWriter(gzw)
   149  	return &TarballArchive{"", tarw, gzw, w}
   150  }
   151  
   152  func (a *TarballArchive) Directory(name string) error {
   153  	a.dir = name + "/"
   154  	return a.tarw.WriteHeader(&tar.Header{
   155  		Name:     a.dir,
   156  		Mode:     0755,
   157  		Typeflag: tar.TypeDir,
   158  	})
   159  }
   160  
   161  func (a *TarballArchive) Header(fi os.FileInfo) (io.Writer, error) {
   162  	head, err := tar.FileInfoHeader(fi, "")
   163  	if err != nil {
   164  		return nil, fmt.Errorf("can't make tar header: %v", err)
   165  	}
   166  	head.Name = a.dir + head.Name
   167  	if err := a.tarw.WriteHeader(head); err != nil {
   168  		return nil, fmt.Errorf("can't add tar header: %v", err)
   169  	}
   170  	return a.tarw, nil
   171  }
   172  
   173  func (a *TarballArchive) Close() error {
   174  	if err := a.tarw.Close(); err != nil {
   175  		return err
   176  	}
   177  	if err := a.gzw.Close(); err != nil {
   178  		return err
   179  	}
   180  	return a.file.Close()
   181  }
   182