github.com/tiagovtristao/plz@v13.4.0+incompatible/tools/jarcat/ar/ar.go (about)

     1  // Package ar provides an ar file archiver.
     2  package ar
     3  
     4  import (
     5  	"bufio"
     6  	"io"
     7  	"os"
     8  	"path"
     9  	"runtime"
    10  	"strings"
    11  	"time"
    12  
    13  	"github.com/peterebden/ar"
    14  	"gopkg.in/op/go-logging.v1"
    15  
    16  	"github.com/thought-machine/please/src/fs"
    17  )
    18  
    19  var log = logging.MustGetLogger("ar")
    20  
    21  // mtime is the time we attach for the modification time of all files.
    22  var mtime = time.Date(2000, time.January, 1, 0, 0, 0, 0, time.UTC)
    23  
    24  // Create creates a new ar archive from the given sources.
    25  // If combine is true they are treated as existing ar files and combined.
    26  // If rename is true the srcs are renamed as gcc would (i.e. the extension is replaced by .o).
    27  func Create(srcs []string, out string, combine, rename bool) error {
    28  	// Rename the sources as gcc would.
    29  	if rename {
    30  		for i, src := range srcs {
    31  			src = path.Base(src)
    32  			if ext := path.Ext(src); ext != "" {
    33  				src = src[:len(src)-len(ext)] + ".o"
    34  			}
    35  			srcs[i] = src
    36  			log.Debug("renamed ar source to %s", src)
    37  		}
    38  	}
    39  
    40  	log.Debug("Writing ar to %s", out)
    41  	f, err := os.Create(out)
    42  	if err != nil {
    43  		return err
    44  	}
    45  	defer f.Close()
    46  	bw := bufio.NewWriter(f)
    47  	defer bw.Flush()
    48  	w := ar.NewWriter(bw)
    49  	// Write BSD-style names on OSX, GNU-style ones on Linux
    50  	if runtime.GOOS == "darwin" {
    51  		if err := w.WriteGlobalHeader(); err != nil {
    52  			return err
    53  		}
    54  	} else {
    55  		if err := w.WriteGlobalHeaderForLongFiles(allSourceNames(srcs, combine)); err != nil {
    56  			return err
    57  		}
    58  	}
    59  	for _, src := range srcs {
    60  		log.Debug("ar source file: %s", src)
    61  		f, err := os.Open(src)
    62  		if err != nil {
    63  			return err
    64  		}
    65  		if combine {
    66  			// Read archive & write its contents in
    67  			r := ar.NewReader(f)
    68  			for {
    69  				hdr, err := r.Next()
    70  				if err != nil {
    71  					if err == io.EOF {
    72  						break
    73  					}
    74  					return err
    75  				} else if hdr.Name == "/" || hdr.Name == "__.SYMDEF SORTED" || hdr.Name == "__.SYMDEF" {
    76  					log.Debug("skipping symbol table")
    77  					continue
    78  				}
    79  				// Zero things out
    80  				hdr.ModTime = mtime
    81  				hdr.Uid = 0
    82  				hdr.Gid = 0
    83  				// Fix weird bug about octal numbers (looks like we're prepending 100 multiple times)
    84  				hdr.Mode &= ^0100000
    85  				log.Debug("copying '%s' in from %s, mode %x", hdr.Name, src, hdr.Mode)
    86  				if err := w.WriteHeader(hdr); err != nil {
    87  					return err
    88  				} else if _, err = io.Copy(w, r); err != nil {
    89  					return err
    90  				}
    91  			}
    92  		} else {
    93  			// Write in individual file
    94  			info, err := os.Lstat(src)
    95  			if err != nil {
    96  				return err
    97  			}
    98  			hdr := &ar.Header{
    99  				Name:    src,
   100  				ModTime: mtime,
   101  				Mode:    int64(info.Mode()),
   102  				Size:    info.Size(),
   103  			}
   104  			log.Debug("creating file %s", hdr.Name)
   105  			if err := w.WriteHeader(hdr); err != nil {
   106  				return err
   107  			} else if _, err := io.Copy(w, f); err != nil {
   108  				return err
   109  			}
   110  		}
   111  		f.Close()
   112  	}
   113  	return nil
   114  }
   115  
   116  // Find finds all the .a files under the current directory and returns their names.
   117  func Find() ([]string, error) {
   118  	ret := []string{}
   119  	return ret, fs.Walk(".", func(name string, isDir bool) error {
   120  		if strings.HasSuffix(name, ".a") && !isDir {
   121  			ret = append(ret, name)
   122  		}
   123  		return nil
   124  	})
   125  }
   126  
   127  // allSourceNames returns the name of all source files that we will add to the archive.
   128  func allSourceNames(srcs []string, combine bool) []string {
   129  	if !combine {
   130  		return srcs
   131  	}
   132  	ret := []string{}
   133  	for _, src := range srcs {
   134  		f, err := os.Open(src)
   135  		if err == nil {
   136  			r := ar.NewReader(f)
   137  			for {
   138  				hdr, err := r.Next()
   139  				if err != nil {
   140  					break
   141  				}
   142  				ret = append(ret, hdr.Name)
   143  			}
   144  		}
   145  	}
   146  	return ret
   147  }