...

Source file src/github.com/bazelbuild/buildtools/unused_deps/jar_manifest.go

Documentation: github.com/bazelbuild/buildtools/unused_deps

     1  /*
     2  Copyright 2018 Google LLC
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      https://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package main
    18  
    19  import (
    20  	"archive/zip"
    21  	"fmt"
    22  	"io/ioutil"
    23  	"strings"
    24  )
    25  
    26  // manifestIndexNewline scans manifest and returns the index of the first
    27  // newline and the index of the byte following the newline.
    28  func manifestIndexNewline(manifest string) (int, int, error) {
    29  	// A newline in a jar manifest is denoted with CR LF, CR, or LF.
    30  	n := strings.IndexByte(manifest, '\n')
    31  	r := strings.IndexByte(manifest, '\r')
    32  	if n < 0 && r < 0 {
    33  		return -1, -1, fmt.Errorf("no newline in '%s'", manifest)
    34  	}
    35  
    36  	if n < 0 {
    37  		// Only CR.
    38  		return r, r + 1, nil
    39  	}
    40  	if r < 0 || n < r {
    41  		// Only LF or we have both but the LF comes first.
    42  		return n, n + 1, nil
    43  	}
    44  
    45  	// We have both CR and LF and the CR comes before the LF.  Check for the
    46  	// special case of adjacent CR LF, which together denode a newline.
    47  	if n == r+1 {
    48  		return r, n + 1, nil
    49  	}
    50  
    51  	return r, r + 1, nil
    52  }
    53  
    54  // jarManifestValue returns the value associated with key in the manifest of
    55  // the jar file named jarFileName.
    56  func jarManifestValue(jarFileName string, key string) (string, error) {
    57  	r, err := zip.OpenReader(jarFileName)
    58  	if err != nil {
    59  		return "", err
    60  	}
    61  	defer r.Close()
    62  
    63  	for _, f := range r.File {
    64  		if f.Name != "META-INF/MANIFEST.MF" {
    65  			continue
    66  		}
    67  
    68  		rc, err := f.Open()
    69  		if err != nil {
    70  			return "", err
    71  		}
    72  		defer rc.Close()
    73  
    74  		bytes, err := ioutil.ReadAll(rc)
    75  		if err != nil {
    76  			return "", err
    77  		}
    78  		contents := string(bytes)
    79  
    80  		found := strings.Index(contents, key+":")
    81  		if found < 0 {
    82  			return "", fmt.Errorf("manifest of jar %s contains no key %s", jarFileName, key)
    83  		}
    84  
    85  		label := ""
    86  		rest := contents[found+len(key+":"):]
    87  		for len(rest) > 0 && rest[0] == ' ' {
    88  			newline, next, err := manifestIndexNewline(rest)
    89  			if err != nil {
    90  				return "", fmt.Errorf("bad value for key %s in manifest of jar %s", key, jarFileName)
    91  			}
    92  			label += rest[1:newline]
    93  			rest = rest[next:]
    94  		}
    95  		return label, nil
    96  	}
    97  	return "", fmt.Errorf("jar file %s has no manifest", jarFileName)
    98  }
    99  

View as plain text