diff --git a/Archive/Archive.go b/Archive/Archive.go index ef8c24e..be3761a 100644 --- a/Archive/Archive.go +++ b/Archive/Archive.go @@ -5,111 +5,86 @@ import ( "compress/gzip" "io" "os" - "path/filepath" "strings" ) -func Gzip(source, target string) error { +func CreateArchive(files []string, target string) error { var ( - reader, writer *os.File - archiver *gzip.Writer - filename string - e error + outFile *os.File + gzipWriter *gzip.Writer + tarWriter *tar.Writer + file string + e error ) - reader, e = os.Open(source) + // Create output file + outFile, e = os.Create(target) if e != nil { return e } + defer outFile.Close() - //filename = filepath.Base(source) - //target = filepath.Join(target, fmt.Sprintf("%s.gz", filename)) + gzipWriter = gzip.NewWriter(outFile) + defer gzipWriter.Close() + tarWriter = tar.NewWriter(gzipWriter) + defer tarWriter.Close() - writer, e = os.Create(target) - if e != nil { - return e - } + // Iterate over files and add them to the tar archive - defer writer.Close() - - archiver = gzip.NewWriter(writer) - archiver.Name = filename - defer archiver.Close() + for _, file = range files { + e = addToArchive(tarWriter, file) + if e != nil { + return e + } + } - _, e = io.Copy(archiver, reader) - return e + return nil } -func Tar(source, target string) error { +func addToArchive(tarWriter *tar.Writer, filename string) error { var ( - tarfile, file *os.File - tarball *tar.Writer - header *tar.Header - e error + file *os.File + info os.FileInfo + header *tar.Header + e error ) - tarfile, e = os.Create(target) + // Open the file which will be written into the archive + file, e = os.Open(filename) if e != nil { return e } - defer tarfile.Close() - - tarball = tar.NewWriter(tarfile) - defer tarball.Close() - - return filepath.Walk(source, - func(path string, info os.FileInfo, e error) error { - if e != nil { - return e - } - - header, e = tar.FileInfoHeader(info, info.Name()) - if e != nil { - return e - } - - // TODO change "/" to work cross platform - header.Name = strings.TrimPrefix(strings.TrimPrefix(path, source), "/") - - if header.Name == "" { - return nil - } - - e = tarball.WriteHeader(header) - if e != nil { - return e - } + defer file.Close() - if info.IsDir() { - return nil - } - - file, e = os.Open(path) - if e != nil { - return e - } - defer file.Close() + // Get FileInfo about our file providing file size, mode, etc. + info, e = file.Stat() + if e != nil { + return e + } - _, e = io.Copy(tarball, file) - return e - }) -} + // Create a tar Header from the FileInfo data + header, e = tar.FileInfoHeader(info, info.Name()) + if e != nil { + return e + } -func TarGzip(source, target string) error { - var ( - tarPath string = strings.ReplaceAll(target, ".gz", "") - e error - ) + // Use full path as name (FileInfoHeader only takes the basename) + // If we don't do this the directory strucuture would + // not be preserved + // https://golang.org/src/archive/tar/common.go?#L626 + header.Name = strings.TrimPrefix(filename, "/") - e = Tar(source, tarPath) + // Write file header to the tar archive + e = tarWriter.WriteHeader(header) if e != nil { return e } - e = Gzip(tarPath, target) + // Copy file content to tar archive + _, e = io.Copy(tarWriter, file) if e != nil { return e } - return os.Remove(tarPath) + return nil } diff --git a/Archive/Unarchive.go b/Archive/Unarchive.go index f609d89..9105cc3 100644 --- a/Archive/Unarchive.go +++ b/Archive/Unarchive.go @@ -2,64 +2,45 @@ package Archive import ( "archive/tar" + "bufio" + "bytes" "compress/gzip" "io" "io/fs" "os" "path/filepath" - "strings" ) -func UnGzip(source, target string) error { +func ExtractArchive(source, target string) error { var ( - reader, writer *os.File - archive *gzip.Reader - e error + inFile *os.File + gzipReader *gzip.Reader + tarReader *tar.Reader + e error ) - reader, e = os.Open(source) + inFile, e = os.Open(source) if e != nil { return e } - defer reader.Close() + defer inFile.Close() - archive, e = gzip.NewReader(reader) - if e != nil { - return e - } - defer archive.Close() - - target = filepath.Join(target, archive.Name) - - writer, e = os.Create(target) - if e != nil { - return e - } - defer writer.Close() + gzipReader, e = gzip.NewReader(inFile) + defer gzipReader.Close() + tarReader = tar.NewReader(gzipReader) - _, e = io.Copy(writer, archive) - return e + return extractFromArchive(tarReader, target) } -func Untar(tarball, target string) error { +func extractFromArchive(tarReader *tar.Reader, target string) error { var ( - reader *os.File - tarReader *tar.Reader - header *tar.Header - info fs.FileInfo - file *os.File - path string - e error + header *tar.Header + info fs.FileInfo + file *os.File + path, basePath string + e error ) - reader, e = os.Open(tarball) - if e != nil { - return e - } - - defer reader.Close() - tarReader = tar.NewReader(reader) - for { header, e = tarReader.Next() if e == io.EOF { @@ -72,6 +53,10 @@ func Untar(tarball, target string) error { path = filepath.Join(target, header.Name) info = header.FileInfo() + if filepath.Base(info.Name()) == "manifest.yml" { + continue + } + if info.IsDir() { e = os.MkdirAll(path, info.Mode()) if e != nil { @@ -80,7 +65,20 @@ func Untar(tarball, target string) error { continue } - file, e = os.OpenFile(path, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, info.Mode()) + basePath, e = filepath.Abs(filepath.Dir(path)) + if e != nil { + return e + } + + _, e = os.Stat(basePath) + if os.IsNotExist(e) { + e = os.MkdirAll(basePath, info.Mode()) + if e != nil { + return e + } + } + + file, e = os.OpenFile(path, os.O_CREATE|os.O_RDWR, info.Mode()) if e != nil { return e } @@ -94,23 +92,60 @@ func Untar(tarball, target string) error { } return nil + } -func UntarGzip(source, target string) error { +func ExtractManifestFile(source string) (string, error) { var ( - tarPath string = strings.ReplaceAll(source, ".gz", "") - e error + inFile *os.File + gzipReader *gzip.Reader + tarReader *tar.Reader + e error ) - e = UnGzip(source, tarPath) + inFile, e = os.Open(source) if e != nil { - return e + return "", e } + defer inFile.Close() - e = Untar(tarPath, target) - if e != nil { - return e + gzipReader, e = gzip.NewReader(inFile) + defer gzipReader.Close() + tarReader = tar.NewReader(gzipReader) + + return extractManifestFromArchive(tarReader) +} + +func extractManifestFromArchive(tarReader *tar.Reader) (string, error) { + var ( + header *tar.Header + info fs.FileInfo + manifestWriter *bufio.Writer + manifestBytes bytes.Buffer + e error + ) + + for { + header, e = tarReader.Next() + if e == io.EOF { + break + } + if e != nil { + return manifestBytes.String(), e + } + + info = header.FileInfo() + if filepath.Base(info.Name()) != "manifest.yml" { + continue + } + + manifestWriter = bufio.NewWriter(&manifestBytes) + + _, e = io.Copy(manifestWriter, tarReader) + if e != nil { + return manifestBytes.String(), e + } } - return os.Remove(tarPath) + return manifestBytes.String(), nil } diff --git a/Client/Database/Init.go b/Client/Database/Init.go index 7f199a4..636f89c 100644 --- a/Client/Database/Init.go +++ b/Client/Database/Init.go @@ -32,7 +32,7 @@ func init() { } } -func InitDB() error { +func InitBoltDB() error { var ( tx *bolt.Tx e error @@ -58,3 +58,53 @@ func InitDB() error { return e } + +func InitSqlite3DB() error { + var ( + stmt *sql.Stmt + e error + ) + + stmt, e = DB.Prepare(` +CREATE TABLE IF NOT EXISTS installed_packages ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + name VARCHAR(64) NOT NULL, + version VARCHAR(64) NOT NULL, + installed_at INTEGER NOT NULL +) +`) + if e != nil { + return e + } + + _, e = stmt.Exec() + if e != nil { + return e + } + + stmt, e = DB.Prepare(` +CREATE TABLE IF NOT EXISTS dependancy_linker ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + package_id INTEGER, + dependancy_id INTEGER, + FOREIGN KEY(package_id) REFERENCES installed_packages(id), + FOREIGN KEY(dependancy_id) REFERENCES installed_packages(id) +) +`) + if e != nil { + return e + } + + _, e = stmt.Exec() + return e +} + +func InitDB() error { + var e error + e = InitBoltDB() + if e != nil { + return e + } + + return InitSqlite3DB() +} diff --git a/Client/Database/InstalledPkgs.go b/Client/Database/InstalledPkgs.go new file mode 100644 index 0000000..62186a8 --- /dev/null +++ b/Client/Database/InstalledPkgs.go @@ -0,0 +1,61 @@ +package Database + +import ( + "database/sql" + "time" + + _ "github.com/mattn/go-sqlite3" +) + +func IsPackageInstalled(name, version string) (int64, error) { + var ( + row *sql.Row + id int64 + e error + ) + + row = DB.QueryRow(` +SELECT id FROM installed_packages WHERE name = ? AND version = ?; + `, name, version) + + e = row.Scan(&id) + return id, e +} + +func InsertPackage(name, version string, depIds []int64) error { + var ( + stmt *sql.Stmt + result sql.Result + pkgId int64 + depId int64 + e error + ) + + stmt, e = DB.Prepare("INSERT INTO installed_packages(name, version, installed_at) VALUES(?,?,?)") + if e != nil { + return e + } + + result, e = stmt.Exec(name, version, time.Now().Unix()) + if e != nil { + return e + } + pkgId, e = result.LastInsertId() + if e != nil { + return e + } + + for _, depId = range depIds { + stmt, e = DB.Prepare("INSERT INTO dependancy_linker(package_id, dependancy_id) VALUES(?,?)") + if e != nil { + return e + } + + _, e = stmt.Exec(pkgId, depId) + if e != nil { + return e + } + } + + return e +} diff --git a/Client/Filesystem/CommitFiles.go b/Client/Filesystem/CommitFiles.go index 5db8987..642a72d 100644 --- a/Client/Filesystem/CommitFiles.go +++ b/Client/Filesystem/CommitFiles.go @@ -42,7 +42,6 @@ func CommitFiles() error { if e != nil { return e } - ProgressBar.CloseBar(bar) } return nil diff --git a/Client/Filesystem/FilesystemDiff.go b/Client/Filesystem/FilesystemDiff.go index d5d0ffa..aef648f 100644 --- a/Client/Filesystem/FilesystemDiff.go +++ b/Client/Filesystem/FilesystemDiff.go @@ -220,8 +220,6 @@ func GetFilesystemDiff(root string) (FilesystemStatus, error) { return nil }) - ProgressBar.CloseBar(bar) - return nil }) diff --git a/Client/Filesystem/PickFiles.go b/Client/Filesystem/PickFiles.go index f41ab86..580aac4 100644 --- a/Client/Filesystem/PickFiles.go +++ b/Client/Filesystem/PickFiles.go @@ -92,7 +92,6 @@ func pickFilesRecursive(rootPath string) error { } } - ProgressBar.CloseBar(bar) return nil }) diff --git a/Client/Package/CreatePackage.go b/Client/Package/CreatePackage.go index 09e9ed9..8b60db9 100644 --- a/Client/Package/CreatePackage.go +++ b/Client/Package/CreatePackage.go @@ -28,12 +28,15 @@ func writeManifestFile(path, name, version string) error { e error ) - manifest = fmt.Sprintf(`name: "%s" -version: "%s" -dependancies: - - pkg1: v1.0.0 - - pkg2: v1.0.0 -`, name, version) + manifest, e = Manifest{ + Name: name, + Version: version, + Dependancies: make(map[string]string), + }.CreateManifestString() + + if e != nil { + return e + } filePath = filepath.Join(path, "manifest.yml") @@ -58,7 +61,6 @@ func CreatePackage() error { pkgName string pkgVersion string pkgNameVersion string - tmpDir string index int e error ) @@ -125,22 +127,15 @@ func CreatePackage() error { pkgNameVersion = fmt.Sprintf("%s-%s", pkgName, pkgVersion) - tmpDir, e = ioutil.TempDir("/tmp", pkgNameVersion) + e = writeManifestFile("/tmp/", pkgName, pkgVersion) if e != nil { return e } - defer os.RemoveAll(tmpDir) - for _, file := range pkgFiles { - Filesystem.CopyFile(file, filepath.Join(tmpDir, file)) - } - - e = writeManifestFile(tmpDir, pkgName, pkgVersion) - if e != nil { - return e - } + // TODO: Write this file to a better spot? + pkgFiles = append(pkgFiles, "/tmp/manifest.yml") - e = Archive.TarGzip(tmpDir, pkgNameVersion+".tar.gz") + e = Archive.CreateArchive(pkgFiles, pkgNameVersion+".tar.gz") if e != nil { return e } diff --git a/Client/Package/InstallPackage.go b/Client/Package/InstallPackage.go index 24c4fda..978097e 100644 --- a/Client/Package/InstallPackage.go +++ b/Client/Package/InstallPackage.go @@ -6,13 +6,36 @@ import ( "os" "PackageManager/Archive" + "PackageManager/Client/Database" "PackageManager/Variables" ) +func CheckPackageDependancies(deps map[string]string) ([]int64, error) { + var ( + name, version string + depIds []int64 + id int64 + e error + ) + + for name, version = range deps { + id, e = Database.IsPackageInstalled(name, version) + if e != nil { + return depIds, e + } + depIds = append(depIds, id) + } + + return depIds, e +} + func InstallPackage(pkgs []string) error { var ( - pkg string - e error + manifest Manifest + depIds []int64 + pkg string + mStr string + e error ) for _, pkg = range pkgs { @@ -27,7 +50,35 @@ func InstallPackage(pkgs []string) error { "Installing %s...\n", pkg, ) - e = Archive.UntarGzip(pkg, Variables.RootDir) + + mStr, e = Archive.ExtractManifestFile(pkg) + if e != nil { + return e + } + + manifest, e = ParseManifestFile(mStr) + if e != nil { + return e + } + + if !Variables.IgnoreDepsCheck { + depIds, e = CheckPackageDependancies(manifest.Dependancies) + if e != nil { + // TODO: Search for package on error + return e + } + } + + e = Archive.ExtractArchive(pkg, Variables.RootDir) + if e != nil { + return e + } + + e = Database.InsertPackage(manifest.Name, manifest.Version, depIds) + if e != nil { + return e + } + fmt.Printf( "%s successfully installed\n", pkg, diff --git a/Client/Package/Manifest.go b/Client/Package/Manifest.go new file mode 100644 index 0000000..d28003b --- /dev/null +++ b/Client/Package/Manifest.go @@ -0,0 +1,33 @@ +package Package + +import ( + yaml "gopkg.in/yaml.v2" +) + +type Manifest struct { + Name string `yaml:"name"` + Version string `yaml:"version"` + Dependancies map[string]string `yaml:"dependancies,flow"` +} + +func ParseManifestFile(manifest string) (Manifest, error) { + var ( + m Manifest = Manifest{} + e error + ) + + e = yaml.Unmarshal([]byte(manifest), &m) + return m, e +} + +func (m Manifest) CreateManifestString() (string, error) { + var ( + mByte []byte + e error + ) + mByte, e = yaml.Marshal(&m) + if e != nil { + return "", e + } + return string(mByte), e +} diff --git a/Client/ProgressBar/Bar.go b/Client/ProgressBar/Bar.go index e60e3cd..e9e3640 100644 --- a/Client/ProgressBar/Bar.go +++ b/Client/ProgressBar/Bar.go @@ -29,7 +29,3 @@ func InitBar(name string, total int) *mpb.Bar { return bar } - -func CloseBar(bar *mpb.Bar) { - bar.Abort(false) -} diff --git a/Client/main.go b/Client/main.go index 1797c66..a23bc76 100644 --- a/Client/main.go +++ b/Client/main.go @@ -36,6 +36,12 @@ Filesystem diff: -Cp | -create-pkg Create package from fs diff + + -Il | -install-local + Install package from local tarball + + -ignore-deps-check + Skip dependancies check ` helpMsg = fmt.Sprintf(helpMsg, os.Args[0]) fmt.Println(helpMsg) @@ -52,8 +58,11 @@ func main() { resetAddedFilesFlag bool resetAddedFilesFlagLong bool - createPackageFlag bool - createPackageFlagLong bool + createPackageFlag bool + createPackageFlagLong bool + installLocalPackageFlag bool + installLocalPackageFlagLong bool + ignoreDepsCheckFlag bool verboseOutputFlag bool verboseOutputFlagLong bool @@ -74,6 +83,9 @@ func main() { panic(e) } + defer Database.DB.Close() + defer Database.FsDB.Close() + // TODO: Rework usage function // Initialise flags @@ -95,16 +107,21 @@ func main() { flag.BoolVar(&createPackageFlag, "Cp", false, "Create package from fs diff") flag.BoolVar(&createPackageFlagLong, "create-pkg", false, "Create package from fs diff") + flag.BoolVar(&installLocalPackageFlag, "Il", false, "Install package from local tarball") + flag.BoolVar(&installLocalPackageFlagLong, "install-local", false, "Install package from local tarball") + + flag.BoolVar(&ignoreDepsCheckFlag, "ignore-deps-check", false, "Ignore dependancies check") + flag.Parse() Variables.VerboseOutput = verboseOutputFlag || verboseOutputFlagLong + Variables.IgnoreDepsCheck = ignoreDepsCheckFlag if getFilesystemDiffFlag || getFilesystemDiffFlagLong { var rootPath string = Variables.RootDir if len(flag.Args()) > 1 { - // TODO: Fix this msg - fmt.Println(Color.Fatal("Option takes one optional argument")) flag.Usage() + fmt.Println(Color.Fatal("Option takes one optional argument")) return } @@ -121,7 +138,7 @@ func main() { } if addFileDiffFlag || addFileDiffFlagLong { - if len(flag.Args()) > 1 && len(flag.Args()) < 1 { + if len(flag.Args()) > 1 || len(flag.Args()) < 1 { fmt.Println(Color.Fatal("Must supply one argument")) flag.Usage() return @@ -157,16 +174,13 @@ func main() { return } - /* - - if installLocalPackageFlag || installLocalPackageFlagLong { - e = Package.InstallPackage(flag.Args()) - if e != nil { - panic(e) - } - return + if installLocalPackageFlag || installLocalPackageFlagLong { + e = Package.InstallPackage(flag.Args()) + if e != nil { + panic(e) } - */ + return + } flag.Usage() fmt.Println(Color.Fatal("Nothing to do")) diff --git a/Variables/Variables.go b/Variables/Variables.go index bffc376..7a0f874 100644 --- a/Variables/Variables.go +++ b/Variables/Variables.go @@ -12,7 +12,9 @@ const ( var ( Editor string = "vi" - VerboseOutput bool = false + VerboseOutput bool = false + IgnoreDepsCheck bool = false + RootDir string = "/" FsHashPicksBucket []byte = []byte("FilesystemPicks") FsHashIndexBucket []byte = []byte("FilesystemIndex") diff --git a/go.mod b/go.mod index f73a3a7..edcf589 100644 --- a/go.mod +++ b/go.mod @@ -2,4 +2,13 @@ module PackageManager go 1.16 -require github.com/mattn/go-sqlite3 v1.14.7 +require ( + github.com/VividCortex/ewma v1.2.0 // indirect + github.com/mattn/go-isatty v0.0.13 // indirect + github.com/mattn/go-sqlite3 v1.14.8 + github.com/vbauerster/mpb v3.4.0+incompatible + go.etcd.io/bbolt v1.3.6 + golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 // indirect + golang.org/x/sync v0.0.0-20210220032951-036812b2e83c + gopkg.in/yaml.v2 v2.4.0 +) diff --git a/go.sum b/go.sum index 96ff824..513d355 100644 --- a/go.sum +++ b/go.sum @@ -1,2 +1,28 @@ -github.com/mattn/go-sqlite3 v1.14.7 h1:fxWBnXkxfM6sRiuH3bqJ4CfzZojMOLVc0UTsTglEghA= -github.com/mattn/go-sqlite3 v1.14.7/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= +github.com/VividCortex/ewma v1.2.0 h1:f58SaIzcDXrSy3kWaHNvuJgJ3Nmz59Zji6XoJR/q1ow= +github.com/VividCortex/ewma v1.2.0/go.mod h1:nz4BbCtbLyFDeC9SUHbtcT5644juEuWfUAUnGx7j5l4= +github.com/mattn/go-isatty v0.0.13 h1:qdl+GuBjcsKKDco5BsxPJlId98mSWNKqYA+Co0SC1yA= +github.com/mattn/go-isatty v0.0.13/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-sqlite3 v1.14.8 h1:gDp86IdQsN/xWjIEmr9MF6o9mpksUgh0fu+9ByFxzIU= +github.com/mattn/go-sqlite3 v1.14.8/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= +github.com/vbauerster/mpb v3.4.0+incompatible h1:mfiiYw87ARaeRW6x5gWwYRUawxaW1tLAD8IceomUCNw= +github.com/vbauerster/mpb v3.4.0+incompatible/go.mod h1:zAHG26FUhVKETRu+MWqYXcI70POlC6N8up9p1dID7SU= +go.etcd.io/bbolt v1.3.6 h1:/ecaJf0sk1l4l6V4awd65v2C3ILy7MSj+s/x1ADCIMU= +go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4= +golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 h1:/UOmuWzQfxxo9UtlXMwuQU8CMgg1eZXqTRwkSQJWKOI= +golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 h1:SrN+KX8Art/Sf4HNj6Zcz06G7VEz+7w9tdXTPOZ7+l4= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=