...

Source file src/github.com/datawire/ambassador/v2/cmd/reproducer/search.go

Documentation: github.com/datawire/ambassador/v2/cmd/reproducer

     1  package reproducer
     2  
     3  import (
     4  	"archive/tar"
     5  	"archive/zip"
     6  	"bytes"
     7  	"compress/gzip"
     8  	"io"
     9  	"io/ioutil"
    10  	"net/http"
    11  	"os"
    12  	"path/filepath"
    13  	"strings"
    14  
    15  	"github.com/pkg/errors"
    16  )
    17  
    18  // A fileVistior function is invoked with a relative path to the file, the detected contentType of
    19  // the file, the detected encoding of the file, and the content itself.
    20  type fileVisitor func(path, contentType, encoding string, content []byte) error
    21  
    22  // The break search error is used as a signal a file visitor can use to abort the search early.
    23  var breakSearch = errors.Errorf("break search")
    24  
    25  // The search function abstracts away the details of searching archives for a given file. It expects
    26  // to be invoked pointing to a file or an archive. It will traverse all text files contained in the
    27  // possibly nested archives and invoke the supplied visitor function with detected content type
    28  // info. See the visitor function definition for an explanation of what is passed to the visitor
    29  // function.
    30  func search(filename string, action fileVisitor) error {
    31  	f, err := os.Open(filename)
    32  	if err != nil {
    33  		return errors.Wrapf(err, "opening file %s", filename)
    34  	}
    35  	content, err := ioutil.ReadAll(f)
    36  	if err != nil {
    37  		return errors.Wrapf(err, "reading file %s", filename)
    38  	}
    39  	return search_r(filename, "", content, action)
    40  }
    41  
    42  func search_r(base, filename string, content []byte, action fileVisitor) error {
    43  	contentType := http.DetectContentType(content)
    44  	parts := strings.SplitN(contentType, ";", 2)
    45  	encoding := ""
    46  	if len(parts) == 2 {
    47  		contentType = parts[0]
    48  		encoding = parts[1]
    49  	}
    50  
    51  	switch contentType {
    52  	case "application/x-gzip":
    53  		zr, err := gzip.NewReader(bytes.NewReader(content))
    54  		if err != nil {
    55  			return errors.Wrapf(err, "ungzipping file contents")
    56  		}
    57  		unzippedContents, err := ioutil.ReadAll(zr)
    58  		if err != nil {
    59  			return errors.Wrapf(err, "reading gzip contents %s", filename)
    60  		}
    61  
    62  		return search_r(base, filename, unzippedContents, action)
    63  	case "application/zip":
    64  		zr, err := zip.NewReader(bytes.NewReader(content), int64(len(content)))
    65  		if err != nil {
    66  			return errors.Wrapf(err, "unzipping contents")
    67  		}
    68  		for _, f := range zr.File {
    69  			rc, err := f.Open()
    70  			if err != nil {
    71  				return errors.Wrapf(err, "opening zip entry %s", f.Name)
    72  			}
    73  			entryContents, err := ioutil.ReadAll(rc)
    74  			if err != nil {
    75  				return errors.Wrapf(err, "reading zip entry %s", f.Name)
    76  			}
    77  			err = search_r(base, filepath.Join(filename, f.Name), entryContents, action)
    78  			if err != nil {
    79  				return err
    80  			}
    81  		}
    82  
    83  		return nil
    84  	case "text/plain":
    85  		if filename == "" {
    86  			filename = base
    87  		}
    88  		return action(filename, contentType, encoding, content)
    89  	case "application/octet-stream":
    90  		tin := tar.NewReader(bytes.NewReader(content))
    91  		for {
    92  			header, err := tin.Next()
    93  			if err == io.EOF {
    94  				break
    95  			}
    96  
    97  			if err != nil {
    98  				return errors.Wrapf(err, "untarring file %s", filename)
    99  			}
   100  
   101  			switch header.Typeflag {
   102  			case tar.TypeReg:
   103  				name := header.Name
   104  				entryContents, err := ioutil.ReadAll(tin)
   105  				if err != nil {
   106  					return errors.Wrapf(err, "decoding tar entry %s", name)
   107  				}
   108  
   109  				err = search_r(base, filepath.Join(filename, name), entryContents, action)
   110  				if err != nil {
   111  					return err
   112  				}
   113  			}
   114  		}
   115  	default:
   116  		return errors.Errorf("unrecognized content type %s", contentType)
   117  	}
   118  
   119  	return nil
   120  }
   121  

View as plain text