|
| 1 | +/* |
| 2 | +Copyright 2018 Google, Inc. All rights reserved. |
| 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 | + http://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 differs |
| 18 | + |
| 19 | +import ( |
| 20 | + "io/ioutil" |
| 21 | + "os" |
| 22 | + "path/filepath" |
| 23 | + "strconv" |
| 24 | + "strings" |
| 25 | + |
| 26 | + pkgutil "github.com/GoogleContainerTools/container-diff/pkg/util" |
| 27 | + "github.com/GoogleContainerTools/container-diff/util" |
| 28 | + "github.com/sirupsen/logrus" |
| 29 | +) |
| 30 | + |
| 31 | +//Emerge package database location |
| 32 | +const emergePkgFile string = "/var/db/pkg" |
| 33 | + |
| 34 | +type EmergeAnalyzer struct { |
| 35 | +} |
| 36 | + |
| 37 | +func (em EmergeAnalyzer) Name() string { |
| 38 | + return "EmergeAnalyzer" |
| 39 | +} |
| 40 | + |
| 41 | +// Diff compares the packages installed by emerge. |
| 42 | +func (em EmergeAnalyzer) Diff(image1, image2 pkgutil.Image) (util.Result, error) { |
| 43 | + diff, err := singleVersionDiff(image1, image2, em) |
| 44 | + return diff, err |
| 45 | +} |
| 46 | + |
| 47 | +func (em EmergeAnalyzer) Analyze(image pkgutil.Image) (util.Result, error) { |
| 48 | + analysis, err := singleVersionAnalysis(image, em) |
| 49 | + return analysis, err |
| 50 | +} |
| 51 | + |
| 52 | +func (em EmergeAnalyzer) getPackages(image pkgutil.Image) (map[string]util.PackageInfo, error) { |
| 53 | + var path string |
| 54 | + path = image.FSPath |
| 55 | + switch path { |
| 56 | + case "": |
| 57 | + path = emergePkgFile |
| 58 | + default: |
| 59 | + path = filepath.Join(path, emergePkgFile) |
| 60 | + } |
| 61 | + packages := make(map[string]util.PackageInfo) |
| 62 | + if _, err := os.Stat(path); err != nil { |
| 63 | + // invalid image directory path |
| 64 | + logrus.Errorf("Invalid image directory path %s", path) |
| 65 | + return packages, err |
| 66 | + } |
| 67 | + |
| 68 | + contents, err := ioutil.ReadDir(path) |
| 69 | + if err != nil { |
| 70 | + logrus.Errorf("Non-content in image directory path %s", path) |
| 71 | + return packages, err |
| 72 | + } |
| 73 | + |
| 74 | + for i := 0; i < len(contents); i++ { |
| 75 | + c := contents[i] |
| 76 | + pkgPrefix := c.Name() |
| 77 | + pkgContents, err := ioutil.ReadDir(filepath.Join(path, pkgPrefix)) |
| 78 | + if err != nil { |
| 79 | + return packages, err |
| 80 | + } |
| 81 | + for j := 0; j < len(pkgContents); j++ { |
| 82 | + c := pkgContents[j] |
| 83 | + pkgRawName := c.Name() |
| 84 | + // in usual, name of package installed by emerge is formatted as '{pkgName}-{version}' e.g.(pymongo-3.9.0) |
| 85 | + s := strings.Split(pkgRawName, "-") |
| 86 | + if len(s) != 2 { |
| 87 | + continue |
| 88 | + } |
| 89 | + pkgName, version := s[0], s[1] |
| 90 | + pkgPath := filepath.Join(path, pkgPrefix, pkgRawName, "SIZE") |
| 91 | + size, err := getPkgSize(pkgPath) |
| 92 | + if err != nil { |
| 93 | + return packages, err |
| 94 | + } |
| 95 | + currPackage := util.PackageInfo{Version: version, Size: size} |
| 96 | + fullPackageName := strings.Join([]string{pkgPrefix, pkgName}, "/") |
| 97 | + packages[fullPackageName] = currPackage |
| 98 | + } |
| 99 | + } |
| 100 | + |
| 101 | + return packages, nil |
| 102 | +} |
| 103 | + |
| 104 | +// emerge will count the total size of a package and store it as a SIZE file in pkg metadata directory |
| 105 | +// getPkgSize read this SIZE file of a given package |
| 106 | +func getPkgSize(pkgPath string) (int64, error) { |
| 107 | + var sizeFile *os.File |
| 108 | + var err error |
| 109 | + sizeFile, err = os.Open(pkgPath) |
| 110 | + if err != nil { |
| 111 | + logrus.Debugf("unable to open SIZE file for pkg %s", pkgPath) |
| 112 | + return 0, err |
| 113 | + } |
| 114 | + defer sizeFile.Close() |
| 115 | + fileBody, err := ioutil.ReadAll(sizeFile) |
| 116 | + if err != nil { |
| 117 | + logrus.Debugf("unable to read SIZE file for pkg %s", pkgPath) |
| 118 | + return 0, err |
| 119 | + } |
| 120 | + strFileBody := strings.Replace(string(fileBody), "\n", "", -1) |
| 121 | + size, _ := strconv.ParseInt(strFileBody, 10, 64) |
| 122 | + return size, nil |
| 123 | +} |
0 commit comments