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  }