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