2016-11-18 22:39:22 +01:00

167 lines
5.0 KiB
Go

package main
import (
"bytes"
"crypto/sha1"
"fmt"
"io/ioutil"
"strings"
)
func ChecklinesDistinfo(lines []*Line) {
if G.opts.Debug {
defer tracecall1(lines[0].Fname)()
}
fname := lines[0].Fname
var patchesDir = "patches"
if G.Pkg != nil && hasSuffix(fname, "/lang/php55/distinfo") {
patchesDir = G.CurPkgsrcdir + "/lang/php55/patches"
} else if G.Pkg != nil && dirExists(G.CurrentDir+"/"+G.Pkg.Patchdir) {
patchesDir = G.Pkg.Patchdir
}
if G.opts.Debug {
traceStep1("patchesDir=%q", patchesDir)
}
ck := &distinfoLinesChecker{
fname, patchesDir, isCommitted(fname),
make(map[string]bool), nil, "", false, nil}
ck.checkLines(lines)
ChecklinesTrailingEmptyLines(lines)
ck.checkUnrecordedPatches()
SaveAutofixChanges(lines)
}
type distinfoLinesChecker struct {
distinfoFilename string
patchdir string // Relative to G.currentDir
distinfoIsCommitted bool
patches map[string]bool // "patch-aa" => true
currentFirstLine *Line
currentFilename string
isPatch bool
algorithms []string
}
func (ck *distinfoLinesChecker) checkLines(lines []*Line) {
lines[0].CheckRcsid(``, "")
if 1 < len(lines) && lines[1].Text != "" {
lines[1].Note0("Empty line expected.")
}
for i, line := range lines {
if i < 2 {
continue
}
m, alg, filename, hash := match3(line.Text, `^(\w+) \((\w[^)]*)\) = (.*)(?: bytes)?$`)
if !m {
line.Error0("Invalid line.")
continue
}
if filename != ck.currentFilename {
ck.onFilenameChange(line, filename)
}
ck.algorithms = append(ck.algorithms, alg)
ck.checkGlobalMismatch(line, filename, alg, hash)
ck.checkUncommittedPatch(line, filename, hash)
}
ck.onFilenameChange(NewLineEOF(ck.distinfoFilename), "")
}
func (ck *distinfoLinesChecker) onFilenameChange(line *Line, nextFname string) {
currentFname := ck.currentFilename
if currentFname != "" {
algorithms := strings.Join(ck.algorithms, ", ")
if ck.isPatch {
if algorithms != "SHA1" {
line.Error2("Expected SHA1 hash for %s, got %s.", currentFname, algorithms)
}
} else if hasPrefix(currentFname, "patch-") && algorithms == "SHA1" {
ck.currentFirstLine.Warn2("Patch file %q does not exist in directory %q.", currentFname, cleanpath(ck.patchdir))
Explain(
"If the patches directory looks correct, the patch may have been",
"removed without updating the distinfo file. In such a case please",
"update the distinfo file.",
"",
"If the patches directory looks wrong, pkglint needs to be improved.")
} else if algorithms != "SHA1, RMD160, Size" && algorithms != "SHA1, RMD160, SHA512, Size" {
line.Error2("Expected SHA1, RMD160, SHA512, Size checksums for %q, got %s.", currentFname, algorithms)
}
}
ck.isPatch = hasPrefix(nextFname, "patch-") && fileExists(G.CurrentDir+"/"+ck.patchdir+"/"+nextFname)
ck.currentFilename = nextFname
ck.currentFirstLine = line
ck.algorithms = nil
}
func (ck *distinfoLinesChecker) checkPatchSha1(line *Line, patchFname, distinfoSha1Hex string) {
patchBytes, err := ioutil.ReadFile(G.CurrentDir + "/" + patchFname)
if err != nil {
line.Error1("%s does not exist.", patchFname)
return
}
h := sha1.New()
netbsd := []byte("$" + "NetBSD")
for _, patchLine := range bytes.SplitAfter(patchBytes, []byte("\n")) {
if !bytes.Contains(patchLine, netbsd) {
h.Write(patchLine)
}
}
fileSha1Hex := fmt.Sprintf("%x", h.Sum(nil))
if distinfoSha1Hex != fileSha1Hex {
if !line.AutofixReplace(distinfoSha1Hex, fileSha1Hex) {
line.Errorf("%s hash of %s differs (distinfo has %s, patch file has %s). Run \"%s makepatchsum\".", "SHA1", patchFname, distinfoSha1Hex, fileSha1Hex, confMake)
}
}
}
func (ck *distinfoLinesChecker) checkUnrecordedPatches() {
files, err := ioutil.ReadDir(G.CurrentDir + "/" + ck.patchdir)
if err != nil {
if G.opts.Debug {
traceStep("Cannot read patchesDir %q: %s", ck.patchdir, err)
}
return
}
for _, file := range files {
patch := file.Name()
if file.Mode().IsRegular() && !ck.patches[patch] && hasPrefix(patch, "patch-") {
NewLineWhole(ck.distinfoFilename).Errorf("patch %q is not recorded. Run \"%s makepatchsum\".", ck.patchdir+"/"+patch, confMake)
}
}
}
// Inter-package check for differing distfile checksums.
func (ck *distinfoLinesChecker) checkGlobalMismatch(line *Line, fname, alg, hash string) {
if G.Hash != nil && !hasPrefix(fname, "patch-") { // Intentionally checking the filename instead of ck.isPatch
key := alg + ":" + fname
otherHash := G.Hash[key]
if otherHash != nil {
if otherHash.hash != hash {
line.Errorf("The hash %s for %s is %s, which differs from %s in %s.",
alg, fname, hash, otherHash.hash, otherHash.line.ReferenceFrom(line))
}
} else {
G.Hash[key] = &Hash{hash, line}
}
}
}
func (ck *distinfoLinesChecker) checkUncommittedPatch(line *Line, patchName, sha1Hash string) {
if ck.isPatch {
patchFname := ck.patchdir + "/" + patchName
if ck.distinfoIsCommitted && !isCommitted(G.CurrentDir+"/"+patchFname) {
line.Warn1("%s is registered in distinfo but not added to CVS.", patchFname)
}
ck.checkPatchSha1(line, patchFname, sha1Hash)
ck.patches[patchName] = true
}
}