github.com/yinchengtsinghua/golang-Eos-dpos-Ethereum@v0.0.0-20190121132951-92cc4225ed8e/internal/build/archive.go (about)

     1  
     2  //此源码被清华学神尹成大魔王专业翻译分析并修改
     3  //尹成QQ77025077
     4  //尹成微信18510341407
     5  //尹成所在QQ群721929980
     6  //尹成邮箱 yinc13@mails.tsinghua.edu.cn
     7  //尹成毕业于清华大学,微软区块链领域全球最有价值专家
     8  //https://mvp.microsoft.com/zh-cn/PublicProfile/4033620
     9  //版权所有2016 Go Ethereum作者
    10  //此文件是Go以太坊库的一部分。
    11  //
    12  //Go-Ethereum库是免费软件:您可以重新分发它和/或修改
    13  //根据GNU发布的较低通用公共许可证的条款
    14  //自由软件基金会,或者许可证的第3版,或者
    15  //(由您选择)任何更高版本。
    16  //
    17  //Go以太坊图书馆的发行目的是希望它会有用,
    18  //但没有任何保证;甚至没有
    19  //适销性或特定用途的适用性。见
    20  //GNU较低的通用公共许可证,了解更多详细信息。
    21  //
    22  //你应该收到一份GNU较低级别的公共许可证副本
    23  //以及Go以太坊图书馆。如果没有,请参见<http://www.gnu.org/licenses/>。
    24  
    25  package build
    26  
    27  import (
    28  	"archive/tar"
    29  	"archive/zip"
    30  	"compress/gzip"
    31  	"fmt"
    32  	"io"
    33  	"os"
    34  	"path/filepath"
    35  	"strings"
    36  )
    37  
    38  type Archive interface {
    39  //目录将新目录项添加到存档并设置
    40  //用于随后调用头的目录。
    41  	Directory(name string) error
    42  
    43  //头将新文件添加到存档。文件被添加到目录中
    44  //按目录设置。文件的内容必须写入返回的
    45  //作家。
    46  	Header(os.FileInfo) (io.Writer, error)
    47  
    48  //关闭将刷新存档并关闭基础文件。
    49  	Close() error
    50  }
    51  
    52  func NewArchive(file *os.File) (Archive, string) {
    53  	switch {
    54  	case strings.HasSuffix(file.Name(), ".zip"):
    55  		return NewZipArchive(file), strings.TrimSuffix(file.Name(), ".zip")
    56  	case strings.HasSuffix(file.Name(), ".tar.gz"):
    57  		return NewTarballArchive(file), strings.TrimSuffix(file.Name(), ".tar.gz")
    58  	default:
    59  		return nil, ""
    60  	}
    61  }
    62  
    63  //addfile将现有文件追加到存档。
    64  func AddFile(a Archive, file string) error {
    65  	fd, err := os.Open(file)
    66  	if err != nil {
    67  		return err
    68  	}
    69  	defer fd.Close()
    70  	fi, err := fd.Stat()
    71  	if err != nil {
    72  		return err
    73  	}
    74  	w, err := a.Header(fi)
    75  	if err != nil {
    76  		return err
    77  	}
    78  	if _, err := io.Copy(w, fd); err != nil {
    79  		return err
    80  	}
    81  	return nil
    82  }
    83  
    84  //WriteArchive创建包含给定文件的存档。
    85  func WriteArchive(name string, files []string) (err error) {
    86  	archfd, err := os.Create(name)
    87  	if err != nil {
    88  		return err
    89  	}
    90  
    91  	defer func() {
    92  		archfd.Close()
    93  //失败时删除半写存档。
    94  		if err != nil {
    95  			os.Remove(name)
    96  		}
    97  	}()
    98  	archive, basename := NewArchive(archfd)
    99  	if archive == nil {
   100  		return fmt.Errorf("unknown archive extension")
   101  	}
   102  	fmt.Println(name)
   103  	if err := archive.Directory(basename); err != nil {
   104  		return err
   105  	}
   106  	for _, file := range files {
   107  		fmt.Println("   +", filepath.Base(file))
   108  		if err := AddFile(archive, file); err != nil {
   109  			return err
   110  		}
   111  	}
   112  	return archive.Close()
   113  }
   114  
   115  type ZipArchive struct {
   116  	dir  string
   117  	zipw *zip.Writer
   118  	file io.Closer
   119  }
   120  
   121  func NewZipArchive(w io.WriteCloser) Archive {
   122  	return &ZipArchive{"", zip.NewWriter(w), w}
   123  }
   124  
   125  func (a *ZipArchive) Directory(name string) error {
   126  	a.dir = name + "/"
   127  	return nil
   128  }
   129  
   130  func (a *ZipArchive) Header(fi os.FileInfo) (io.Writer, error) {
   131  	head, err := zip.FileInfoHeader(fi)
   132  	if err != nil {
   133  		return nil, fmt.Errorf("can't make zip header: %v", err)
   134  	}
   135  	head.Name = a.dir + head.Name
   136  	head.Method = zip.Deflate
   137  	w, err := a.zipw.CreateHeader(head)
   138  	if err != nil {
   139  		return nil, fmt.Errorf("can't add zip header: %v", err)
   140  	}
   141  	return w, nil
   142  }
   143  
   144  func (a *ZipArchive) Close() error {
   145  	if err := a.zipw.Close(); err != nil {
   146  		return err
   147  	}
   148  	return a.file.Close()
   149  }
   150  
   151  type TarballArchive struct {
   152  	dir  string
   153  	tarw *tar.Writer
   154  	gzw  *gzip.Writer
   155  	file io.Closer
   156  }
   157  
   158  func NewTarballArchive(w io.WriteCloser) Archive {
   159  	gzw := gzip.NewWriter(w)
   160  	tarw := tar.NewWriter(gzw)
   161  	return &TarballArchive{"", tarw, gzw, w}
   162  }
   163  
   164  func (a *TarballArchive) Directory(name string) error {
   165  	a.dir = name + "/"
   166  	return a.tarw.WriteHeader(&tar.Header{
   167  		Name:     a.dir,
   168  		Mode:     0755,
   169  		Typeflag: tar.TypeDir,
   170  	})
   171  }
   172  
   173  func (a *TarballArchive) Header(fi os.FileInfo) (io.Writer, error) {
   174  	head, err := tar.FileInfoHeader(fi, "")
   175  	if err != nil {
   176  		return nil, fmt.Errorf("can't make tar header: %v", err)
   177  	}
   178  	head.Name = a.dir + head.Name
   179  	if err := a.tarw.WriteHeader(head); err != nil {
   180  		return nil, fmt.Errorf("can't add tar header: %v", err)
   181  	}
   182  	return a.tarw, nil
   183  }
   184  
   185  func (a *TarballArchive) Close() error {
   186  	if err := a.tarw.Close(); err != nil {
   187  		return err
   188  	}
   189  	if err := a.gzw.Close(); err != nil {
   190  		return err
   191  	}
   192  	return a.file.Close()
   193  }