Hi Andrew,

end up became too busy with other stuff. Would you mind to carate a MR
for dh-make-golang package on salsa?

The package has been already ported to Module-Aware Builds in the
`debian/experimental` branch. You may add your PR as patches in the
`debian/experimental` branch and then we can upload them into
experimental for the team to do some tests.


    I don't see a debian/experimental branch in the dh-make-golang repo in Salsa. I have attached my patch here.

    Could you please let me know if I am missing something (on why I don't see debian/experimental) Thanks


--
Thank you,
Balachandran Sivakumar

diff --git a/make.go b/make.go
index 8843475..cfba4fb 100644
--- a/make.go
+++ b/make.go
@@ -13,11 +13,13 @@ import (
 	"os/exec"
 	"os/user"
 	"path/filepath"
+	"regexp"
+	"strconv"
 	"strings"
 
+	"golang.org/x/net/html"
 	"golang.org/x/net/publicsuffix"
 	"golang.org/x/sync/errgroup"
-	"golang.org/x/tools/go/vcs"
 )
 
 type packageType int
@@ -106,7 +108,7 @@ func downloadFile(filename, url string) error {
 
 // upstream describes the upstream repo we are about to package.
 type upstream struct {
-	rr          *vcs.RepoRoot
+	rr          *RepoRoot
 	tarPath     string   // path to the downloaded or generated orig tarball tempfile
 	compression string   // compression method, either "gz" or "xz"
 	version     string   // Debian package upstream version number, e.g. 0.0~git20180204.1d24609
@@ -121,12 +123,139 @@ type upstream struct {
 	isRelease   bool     // whether what we end up packaging is a tagged release
 }
 
+type RepoRoot struct {
+	VCS          *VCSWrapper
+	Repo         string
+	Root         string
+	MajorVersion string
+}
+
+type VCSWrapper struct {
+	Cmd string
+}
+
+func (vcs *VCSWrapper) Create(dir, repo string) error {
+	if _, err := os.Stat(dir); os.IsExist(err) {
+		return fmt.Errorf("Dir %s already exists, aborting", dir)
+	}
+	parent := filepath.Dir(dir)
+	_, err := os.Stat(parent)
+	if os.IsNotExist(err) {
+		if err = os.MkdirAll(parent, 0755); err != nil {
+			return fmt.Errorf("Could not create parent dir for %s", dir)
+		}
+	}
+
+	cmd := exec.Command("git", "clone", repo, dir)
+	_, err = cmd.Output()
+	if err != nil {
+		return fmt.Errorf("Failed to clone repo %s: %w", repo, err)
+	}
+	return nil
+}
+
+func (vcs *VCSWrapper) CreateAtRev(dir, repo, rev string) error {
+	err := vcs.Create(dir, repo)
+	if err != nil {
+		return err
+	}
+	cmd := exec.Command("git", "-C", "dir", "checkout", rev)
+	_, cErr := cmd.Output()
+	if cErr != nil {
+		log.Println("ERROR: Could not checkout tag")
+		return cErr
+	}
+	return nil
+}
+
+func (vcs *VCSWrapper) Tags(dir string) ([]string, error) {
+	if _, err := os.Stat(dir); os.IsNotExist(err) {
+		return nil, fmt.Errorf("Dir %s already exists, aborting", dir)
+	}
+	cmd := exec.Command("git", "-C", dir, "tag", "-l")
+	out, err := cmd.Output()
+	if err != nil {
+		return nil, fmt.Errorf("Failed to get tags in dir %s: %s", dir, err)
+	}
+	tags := strings.Split(string(out), "\n")
+	return tags, nil
+}
+
+// Implemented based on https://go.dev/ref/mod#vcs-find
+func RepoRootForImportPath(importPath string, verbose bool) (*RepoRoot, error) {
+	parts := strings.Split(importPath, "/")
+	major := ""
+	if last := parts[len(parts)-1]; strings.HasPrefix(last, "v") {
+		if _, err := strconv.Atoi(last[1:]); err == nil {
+			major = last
+			parts := parts[:len(parts)-1]
+			importPath = strings.Join(parts, "/")
+		}
+	}
+	for len(parts) >= 3 {
+		uriPath := strings.Join(parts, "/")
+		resp, err := http.Get("https://"; + uriPath + "?go-get=1")
+		if err != nil {
+			return nil, err
+		}
+		if resp.StatusCode == http.StatusOK {
+			doc, err := html.Parse(resp.Body)
+			resp.Body.Close()
+			if err != nil {
+				return nil, err
+			}
+			if repo := repoFromModuleImport(doc); repo != "" {
+				return &RepoRoot{&VCSWrapper{"git"}, repo, importPath, major}, nil
+			}
+		} else {
+			// Most likely a 404, walk up the module import path and attempt again
+			if verbose {
+				log.Println("Walking up the module path to do go-get for repo info")
+			}
+			resp.Body.Close()
+		}
+		parts = parts[:len(parts)-1]
+	}
+	return nil, fmt.Errorf("Could not fetch repo info")
+
+}
+func repoFromModuleImport(doc *html.Node) string {
+	var repo string
+	var walk func(*html.Node)
+	walk = func(n *html.Node) {
+		if repo != "" {
+			return
+		}
+		if n.Type == html.ElementNode && n.Data == "meta" {
+			var name, content string
+			for _, a := range n.Attr {
+				if a.Key == "name" {
+					name = a.Val
+				} else if a.Key == "content" {
+					content = a.Val
+				}
+			}
+			if name == "go-import" {
+				p := strings.Fields(content)
+				if len(p) == 3 {
+					repo = p[2]
+				}
+			}
+		}
+		for c := n.FirstChild; c != nil && repo == ""; c = c.NextSibling {
+			walk(c)
+		}
+	}
+	walk(doc)
+	return repo
+}
+
 func (u *upstream) get(gopath, repo, rev string) error {
 	done := make(chan struct{})
 	defer close(done)
 	go progressSize("go get", filepath.Join(gopath, "src"), done)
 
-	rr, err := vcs.RepoRootForImportPath(repo, false)
+	rr, err := RepoRootForImportPath(repo, false)
 	if err != nil {
 		return fmt.Errorf("get repo root: %w", err)
 	}
@@ -326,7 +455,7 @@ func (u *upstream) findDependencies(gopath, repo string) error {
 	// Resolve all packages to the root of their repository.
 	roots := make(map[string]bool)
 	for dep := range godependencies {
-		rr, err := vcs.RepoRootForImportPath(dep, false)
+		rr, err := RepoRootForImportPath(dep, false)
 		if err != nil {
 			log.Printf("Could not determine repo path for import path %q: %v\n", dep, err)
 			continue
@@ -539,7 +668,6 @@ func normalizeDebianPackageName(str string) string {
 	if len(safe) < 2 {
 		return "TODO"
 	}
-
 	return safe
 }
 
@@ -598,13 +726,31 @@ func shortHostName(gopkg string, allowUnknownHoster bool) (host string, err erro
 // e.g. "golang.org/x/text" → "golang-golang-x-text".
 // This follows https://fedoraproject.org/wiki/PackagingDrafts/Go#Package_Names
 func debianNameFromGopkg(gopkg string, t packageType, customProgPkgName string, allowUnknownHoster bool) string {
+
 	parts := strings.Split(gopkg, "/")
+	suffix := parts[len(parts)-1]
+	var versionSuffixRegExp = regexp.MustCompile(`^v[0-9]+$`)
+	hasUsableMajorModVer := false
+	if versionSuffixRegExp.MatchString(suffix) {
+		if suffix == "v0" || suffix == "v1" {
+			log.Println("Building package for a Go module with major version < v2, skipping version name in package name")
+			parts = parts[:len(parts)-1]
+		} else {
+			hasUsableMajorModVer = true
+			log.Println("Building package for a Go module with a major version")
+		}
+	}
 
 	if t == typeProgram || t == typeProgramLibrary {
 		if customProgPkgName != "" {
 			return normalizeDebianPackageName(customProgPkgName)
 		}
-		return normalizeDebianPackageName(parts[len(parts)-1])
+		// If the major ver >= 2, use parts[len-2:] to get <prog>-<ver>
+		if hasUsableMajorModVer && len(parts) >= 2 {
+			return normalizeDebianPackageName(strings.Join(parts[len(parts)-2:], "-"))
+		} else {
+			return normalizeDebianPackageName(parts[len(parts)-1])
+		}
 	}
 
 	host, err := shortHostName(gopkg, allowUnknownHoster)
@@ -830,22 +976,24 @@ func execMake(args []string, usage func()) {
 
 	gitRevision = strings.TrimSpace(gitRevision)
 	gopkg := fs.Arg(0)
-
+	goPkgOrig := gopkg
 	// Ensure the specified argument is a Go package import path.
-	rr, err := vcs.RepoRootForImportPath(gopkg, false)
+	rr, err := RepoRootForImportPath(gopkg, false)
 	if err != nil {
 		log.Fatalf("Verifying arguments: %v — did you specify a Go package import path?", err)
 	}
 	if gopkg != rr.Root {
+		// Check if the difference is because the gopkg includes the version suffix
 		log.Printf("Continuing with repository root %q instead of specified import path %q (repositories are the unit of packaging in Debian)", rr.Root, gopkg)
 		gopkg = rr.Root
+		log.Printf("Using %q to create the debian package name", goPkgOrig)
 	}
 
 	// Set default source and binary package names.
 	// Note that debsrc may change depending on the actual package type.
-	debsrc := debianNameFromGopkg(gopkg, typeLibrary, customProgPkgName, allowUnknownHoster)
+	debsrc := debianNameFromGopkg(goPkgOrig, typeLibrary, customProgPkgName, allowUnknownHoster)
 	debLib := debsrc + "-dev"
-	debProg := debianNameFromGopkg(gopkg, typeProgram, customProgPkgName, allowUnknownHoster)
+	debProg := debianNameFromGopkg(goPkgOrig, typeProgram, customProgPkgName, allowUnknownHoster)
 
 	var pkgType packageType
 
@@ -889,7 +1037,7 @@ func execMake(args []string, usage func()) {
 	}
 
 	if pkgType != typeGuess {
-		debsrc = debianNameFromGopkg(gopkg, pkgType, customProgPkgName, allowUnknownHoster)
+		debsrc = debianNameFromGopkg(goPkgOrig, pkgType, customProgPkgName, allowUnknownHoster)
 		if _, err := os.Stat(debsrc); err == nil {
 			log.Fatalf("Output directory %q already exists, aborting\n", debsrc)
 		}
@@ -929,7 +1077,7 @@ func execMake(args []string, usage func()) {
 		if u.firstMain != "" {
 			log.Printf("Assuming you are packaging a program (because %q defines a main package), use -type to override\n", u.firstMain)
 			pkgType = typeProgram
-			debsrc = debianNameFromGopkg(gopkg, pkgType, customProgPkgName, allowUnknownHoster)
+			debsrc = debianNameFromGopkg(goPkgOrig, pkgType, customProgPkgName, allowUnknownHoster)
 		} else {
 			pkgType = typeLibrary
 		}
diff --git a/make_test.go b/make_test.go
index b8402f7..941fe56 100644
--- a/make_test.go
+++ b/make_test.go
@@ -2,8 +2,6 @@ package main
 
 import (
 	"testing"
-
-	"golang.org/x/tools/go/vcs"
 )
 
 var shortName = []struct {
@@ -59,6 +57,14 @@ var nameFromGoPkg = []struct {
 	{"git.sr.ht/~sircmpwn/getopt", typeGuess, "", "golang-sourcehut-sircmpwn-getopt"},
 	{"golang.org/x/term", typeLibrary, "", "golang-golang-x-term"},
 	{"github.com/cli/cli", typeProgram, "gh", "gh"},
+	{"github.com/Debian/test-pkg/v2", typeLibrary, "", "golang-github-debian-test-pkg-v2"},
+	{"github.com/open-policy-agent/regal", typeProgram, "", "regal"},
+	{"github.com/Debian/test-pkg/v0", typeLibrary, "", "golang-github-debian-test-pkg"},
+	{"github.com/Debian/test-pkg/v1", typeLibrary, "", "golang-github-debian-test-pkg"},
+	{"github.com/Debian/test-pkg/v15", typeLibrary, "", "golang-github-debian-test-pkg-v15"},
+	{"github.com/Debian/test-pkg/v37", typeLibrary, "", "golang-github-debian-test-pkg-v37"},
+	{"github.com/Debian/test-prog/v12", typeProgram, "", "test-prog-v12"},
+	{"github.com/Debian/test-prog/v1", typeProgram, "", "test-prog"},
 }
 
 func TestDebianNameFromGopkg(t *testing.T) {
@@ -85,7 +91,7 @@ var tarballUrl = []struct {
 func TestUpstreamTarmballUrl(t *testing.T) {
 	for _, tt := range tarballUrl {
 		u := upstream{
-			rr:          &vcs.RepoRoot{Repo: tt.repoRoot},
+			rr:          &RepoRoot{Repo: tt.repoRoot},
 			compression: tt.compression,
 			tag:         tt.tag,
 		}

Reply via email to