package main import ( "bufio" "crypto/md5" "crypto/sha256" "errors" "fmt" "io" "os" "path/filepath" "strings" "go.wit.com/lib/cobol" "go.wit.com/lib/gui/shell" "go.wit.com/lib/protobuf/zoopb" "go.wit.com/log" "google.golang.org/protobuf/types/known/timestamppb" ) func populateDebInfo(p *zoopb.Package) error { // SIMPLE SANITY CHECKS if p.DebInfo != nil { // already added p.DebInfo return nil } fullname := filepath.Join(me.pb.BaseDir, p.Filename) cmd := []string{"dpkg", "-I", fullname} r := shell.Run(cmd) if r.Error != nil { return r.Error } if r.Exit != 0 { return errors.New("dpkg returned -1") } stat, err := os.Stat(fullname) if err != nil { return err } filedata, err := os.Open(fullname) if err != nil { return err } defer filedata.Close() // SIMPLE SANITY CHECKS END // SHA256 HASH p.DebInfo = new(zoopb.DebInfo) hSHA256 := sha256.New() hMD5 := md5.New() // probably deprecate, but love md5sum too much // hSHA1 := sha1.New() // deprecated // TeeReader allows writing to multiple hashers at once // multiWriter := io.MultiWriter(hMD5, hSHA1, hSHA256) multiWriter := io.MultiWriter(hSHA256, hMD5) if _, err := io.Copy(multiWriter, filedata); err != nil { return err } p.DebInfo.SHA256 = fmt.Sprintf("%x", hSHA256.Sum(nil)) // should be the standard now p.DebInfo.MD5SUM = fmt.Sprintf("%x", hMD5.Sum(nil)) // probably deprecate // p.DebInfo.SHA1 = fmt.Sprintf("%x", hSHA1.Sum(nil)) // deprecated // SHA256 HASH END // set file create time p.Ctime = timestamppb.New(stat.ModTime()) // PARSE "dpkg -I ", then exit as we are done starting := true all := strings.Join(r.Stdout, "\n") scanner := bufio.NewScanner(strings.NewReader(all)) for scanner.Scan() { line := scanner.Text() parts := strings.Fields(line) if starting { if parts[0] == "new" { if argv.Verbose { log.Printf("new: %v\n", parts) } // skip the first dpkg -I line continue } if parts[0] == "size" { if argv.Verbose { log.Printf("size: %v\n", parts) } // todo: make this correct p.DebInfo.Size = parts[1] p.DebInfo.InstalledSize = parts[1] // scan all the entries from size for scanner.Scan() { line = scanner.Text() parts = strings.Fields(line) if strings.HasPrefix(line, " ") { if argv.Verbose { log.Printf("sizeline: %v\n", parts) } continue } starting = false break } } if starting { if argv.Verbose { log.Printf("parts: %v\n", parts) } continue } } varname := strings.TrimSuffix(parts[0], ":") varval := strings.Join(parts[1:], " ") // log.Printf("varname:%s varval:%s\n", varname, varval) switch varname { case "Package": p.Package = varval case "Filename": log.Printf("Filename: varname:%s varval:%s\n", varname, varval) // p.Package = varval case "Version": p.Version = varval case "Architecture": p.Architecture = varval case "GoPath": p.Namespace = varval case "Maintainer": p.DebInfo.Maintainer = varval case "Packager": p.DebInfo.Packager = varval case "Depends": p.DebInfo.Depends = varval case "Source": p.DebInfo.Source = varval case "URL": p.DebInfo.URL = varval case "Build-Depends": p.DebInfo.BuildDepends = varval case "Installed-Size:": case "Installed-Size": p.DebInfo.InstalledSize = varval case "Homepage": p.DebInfo.URL = varval case "Conflicts": p.DebInfo.Conflicts = varval case "Source-Date": t, err := cobol.GetTime(varval) if err == nil { p.GitDate = timestamppb.New(t) } else { if argv.Verbose { log.Info("FIXME: Package-Build-Date", varval, err) } } case "Build-Date": case "Package-Build-Date": t, err := cobol.GetTime(varval) if err == nil { p.BuildDate = timestamppb.New(t) } else { if argv.Verbose { log.Info("FIXME: Package-Build-Date", varval, err) } } case "Git-Tag-Date": if argv.Verbose { log.Info("FIXME: Git-Tag-Date", varval) } case "Description": description := varval for scanner.Scan() { line := scanner.Text() if strings.HasPrefix(line, " ") { line = strings.TrimSpace(line) description += line + "\n" continue } break } p.DebInfo.Description = description default: // This forces me(it could be you!) to fix this parser varname2 := strings.TrimSuffix(varname, ":") log.Printf("UNKNOWN: varname:%s varval:%s varname2=%s\n", varname, varval, varname2) panic("fix mirrors populateDebInfo()") } } // pb.DebInfo should be correctly populated. You can verify these with "mirrors --verify" return nil } func makeDebianControlFile(p *zoopb.Package, varname string) (string, string) { switch varname { case "Package": return "Package", p.Package case "Filename": return "Filename", p.Filename case "Version": return "Version", p.Version case "Architecture": return "Architecture", p.Architecture case "Maintainer": return "Maintainer", p.DebInfo.Maintainer // return "Maintainer", p.Author case "Source": if argv.Verbose { log.Info("skipping from controlfile", varname) // return "Source", p.DebInfo.Source } return "Source", "" case "Conflicts": return "Conflicts", p.DebInfo.Conflicts case "Packager": return "Packager", p.DebInfo.Packager // return "Packager", p.Packager case "Depends": return "Depends", p.DebInfo.Depends case "Namespace": return "Namespace", p.Namespace case "GitHash": return "Last-Git-Hash", p.DebInfo.GitHash case "GitDate": if p.DebInfo.GitDate == "" { return "Git-Hash-Date", "" } return "Git-Hash-Date", cobol.Time(p.DebInfo.GitDate) case "BuildDepends": return "Build-Depends", p.DebInfo.BuildDepends case "InstalledSize": return "Installed-Size", p.DebInfo.InstalledSize case "Homepage": return "Homepage", p.DebInfo.Homepage case "PreDepends": return "Pre-Depends", p.DebInfo.PreDepends case "Suggests": return "Suggests", p.DebInfo.Suggests case "MultiArch": return "Multi-Arch", p.DebInfo.MultiArch case "Tag": return "Tag", p.DebInfo.Tag case "Size": return "Size", p.DebInfo.Size case "Section": return "Section", p.DebInfo.Section case "URL": return "URL", p.DebInfo.URL //case "Size": // return "Size", p.DebInfo.Size case "BuildDate": if p.BuildDate == nil { return "Build-Date", "" } return "Build-Date", cobol.Time(p.BuildDate) case "DebCtime": return "Deb-File-Date", cobol.Time(p.Ctime) case "SHA1": return "SHA1", "" // deprecated // return "SHA1", p.DebInfo.SHA1 case "MD5SUM": return "MD5Sum", p.DebInfo.MD5SUM case "SHA256": return "SHA256", p.DebInfo.SHA256 case "SHA512": return "SHA512", "" // totally rediculously overkill case "Description": var out string lines := strings.Split(p.DebInfo.Description, "\n") if len(lines) == 0 { return "Description", out } out = "Description: " + strings.TrimSpace(lines[0]) if len(lines) == 1 { return "Description", out } for _, line := range lines[1:] { out += " " + strings.TrimSpace(line) } return "Description", out default: dieMaking(varname) } return "", "" } func dieMaking(varname string) { log.Info("DebInfo sent a field we didn't have. fix the code above", varname) log.Printf("UNHANDLED ABOVE DEBINFO VAR: varname:%s\n", varname) // This forces me(it could be you!) to fix this parser panic("fix mirrors makeDebianControlFile()") } // make a list of the newest .deb files func doMakePackagesFile(all *zoopb.Packages) string { var pfile string for p := range all.IterAll() { var controlfile string parts, err := zoopb.GetDebInfoFields(p) if err != nil { log.Info(err) } for _, varname := range parts { varname, varval := makeDebianControlFile(p, varname) varval = strings.TrimSpace(varval) if varval == "" { continue } controlfile += log.Sprintf("%s: %s\n", varname, varval) } controlfile += log.Sprintf("\n") pfile += controlfile } return pfile } /* log.Printf("Scanning for .deb files in %s\n", poolDir) debInfos, err := scanDebs(poolDir, 200) if err != nil { log.Printf("Failed to scan .deb files: %v\n", err) me.sh.BadExit("scan pool scan dir", err) } var counter int for _, deb := range debInfos { newdeb := new(zoopb.Package) newdeb.DebInfo = new(zoopb.DebInfo) newdeb.Filename = deb.Filename newdeb.DebInfo.Filename = deb.Filename newdeb.DebInfo.MD5SUM = deb.MD5Sum // newdeb.DebInfo.SHA1 = deb.SHA1Sum newdeb.DebInfo.SHA256 = deb.SHA256Sum // log.Info("len(CONTROLDATA)", len(deb.ControlData)) // log.Sprintf("VAR='%s' VAL='%s'\n", varname, varvalue) // log.Info("%v", deb.ControlData) for varname, varvalue := range deb.ControlData { switch varname { case "Package": newdeb.Package = varvalue case "Version": newdeb.Version = varvalue case "Architecture": newdeb.Architecture = varvalue case "Git-Tag-Date": if argv.Verbose { log.Info("CONVERT THIS TO TIME", varname, varvalue) } case "Depends": newdeb.DebInfo.Depends = varvalue case "Build-Depends": newdeb.DebInfo.BuildDepends = varvalue case "Packager": newdeb.DebInfo.Packager = varvalue case "Package-Build-Date": varname = "PackageBuildDate" const layout = "2006/01/02 15:04:05 MST" parsedTime, err := time.Parse(layout, varvalue) if err != nil { log.Info("CONVERT TO TIME failed", varname, varvalue, err) } newdeb.BuildDate = timestamppb.New(parsedTime) case "URL": newdeb.DebInfo.Homepage = varvalue default: if err := debian.SetDebInfoString(newdeb, varname, varvalue); err == nil { if argv.Verbose { log.Printf("Searching for Sugarman WORKED: VAR='%-30s' VAL='%s'\n", varname, varvalue) } } else { log.Printf("Searching for Sugarman (unknwon var): VAR='%-30s' VAL='%s' err=%v\n", varname, varvalue, err) } // todo: add to protomap } } */