github.com/coreos/mantle@v0.13.0/system/targen/tar.go (about) 1 // Copyright 2016 CoreOS, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 // exec is extension of the standard os.exec package. 16 // Adds a handy dandy interface and assorted other features. 17 18 package targen 19 20 import ( 21 "archive/tar" 22 "io" 23 "os" 24 25 "github.com/coreos/pkg/capnslog" 26 ) 27 28 var plog = capnslog.NewPackageLogger("github.com/coreos/mantle", "targen") 29 30 type TarGen struct { 31 files []string 32 binaries []string 33 } 34 35 func New() *TarGen { 36 return &TarGen{} 37 } 38 39 func (t *TarGen) AddFile(path string) *TarGen { 40 plog.Tracef("adding file %q", path) 41 t.files = append(t.files, path) 42 return t 43 } 44 45 func (t *TarGen) AddBinary(path string) *TarGen { 46 plog.Tracef("adding binary %q", path) 47 t.binaries = append(t.binaries, path) 48 return t 49 } 50 51 func tarWriteFile(tw *tar.Writer, file string) error { 52 plog.Tracef("writing file %q", file) 53 54 st, err := os.Stat(file) 55 if err != nil { 56 return err 57 } 58 hdr := &tar.Header{ 59 Name: file, 60 Size: st.Size(), 61 Mode: int64(st.Mode()), 62 ModTime: st.ModTime(), 63 } 64 65 if err = tw.WriteHeader(hdr); err != nil { 66 return err 67 } 68 69 f, err := os.Open(file) 70 if err != nil { 71 return err 72 } 73 74 defer f.Close() 75 76 if _, err := io.Copy(tw, f); err != nil { 77 return err 78 } 79 80 return nil 81 } 82 83 func (t *TarGen) Generate(w io.Writer) error { 84 tw := tar.NewWriter(w) 85 86 // store processed files here so we skip duplicates. 87 copied := make(map[string]struct{}) 88 89 for _, file := range t.files { 90 if _, ok := copied[file]; ok { 91 plog.Tracef("skipping duplicate file %q", file) 92 continue 93 } 94 95 plog.Tracef("copying file %q", file) 96 97 if err := tarWriteFile(tw, file); err != nil { 98 return err 99 } 100 101 copied[file] = struct{}{} 102 } 103 104 for _, binary := range t.binaries { 105 libs, err := ldd(binary) 106 if err != nil { 107 return err 108 } 109 110 for _, lib := range libs { 111 if _, ok := copied[lib]; ok { 112 plog.Tracef("skipping duplicate library %q", lib) 113 114 continue 115 } 116 117 plog.Tracef("copying library %q", lib) 118 119 if err := tarWriteFile(tw, lib); err != nil { 120 return err 121 } 122 123 copied[lib] = struct{}{} 124 } 125 126 if _, ok := copied[binary]; ok { 127 plog.Tracef("skipping duplicate binary %q", binary) 128 continue 129 } 130 131 plog.Tracef("copying binary %q", binary) 132 133 if err := tarWriteFile(tw, binary); err != nil { 134 return err 135 } 136 137 copied[binary] = struct{}{} 138 } 139 140 if err := tw.Close(); err != nil { 141 return err 142 } 143 144 return nil 145 }