-
Notifications
You must be signed in to change notification settings - Fork 79
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Initial commit * Base implementation * Add pault.ag/go/debian * Now parse d/control dependencies * Finalize parseGoModDependencies implementation * s/log/fmt * Add unit test * Use XS-Go-Import-Path to resolve module * Last fixes * Ignore .idea * check-depends: use vcs.RepoRootForImportPath This allows us to translate i.e from github.com/google/go-github/v38 to github.com/google/go-github. * Run gofmt
- Loading branch information
1 parent
04307a0
commit 7147d3b
Showing
6 changed files
with
323 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,3 +2,4 @@ dh-make-golang | |
_build/ | ||
*~ | ||
*.sw[op] | ||
.idea |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,155 @@ | ||
package main | ||
|
||
import ( | ||
"fmt" | ||
"golang.org/x/mod/modfile" | ||
"golang.org/x/tools/go/vcs" | ||
"io/ioutil" | ||
"log" | ||
"os" | ||
"path/filepath" | ||
"pault.ag/go/debian/control" | ||
"strings" | ||
) | ||
|
||
type dependency struct { | ||
importPath string | ||
packageName string | ||
// todo version? | ||
} | ||
|
||
func execCheckDepends(args []string) { | ||
cwd, err := os.Getwd() | ||
if err != nil { | ||
log.Fatalf("error while getting current directory: %s", err) | ||
} | ||
|
||
// Load the already packaged Go modules | ||
golangBinaries, err := getGolangBinaries() | ||
if err != nil { | ||
log.Fatalf("error while getting packaged Go modules: %s", err) | ||
} | ||
|
||
// Load the dependencies defined in the Go module (go.mod) | ||
goModDepds, err := parseGoModDependencies(cwd, golangBinaries) | ||
if err != nil { | ||
log.Fatalf("error while parsing go.mod: %s", err) | ||
} | ||
|
||
// Load the dependencies defined in the Debian packaging (d/control) | ||
packageDeps, err := parseDebianControlDependencies(cwd) | ||
if err != nil { | ||
log.Fatalf("error while parsing d/control: %s", err) | ||
} | ||
|
||
hasChanged := false | ||
|
||
// Check for newly introduced dependencies (defined in go.mod but not in d/control) | ||
for _, goModDep := range goModDepds { | ||
found := false | ||
|
||
if goModDep.packageName == "" { | ||
fmt.Printf("NEW dependency %s is NOT yet packaged in Debian\n", goModDep.importPath) | ||
continue | ||
} | ||
|
||
for _, packageDep := range packageDeps { | ||
if packageDep.packageName == goModDep.packageName { | ||
found = true | ||
break | ||
} | ||
} | ||
|
||
if !found { | ||
hasChanged = true | ||
fmt.Printf("NEW dependency %s (%s)\n", goModDep.importPath, goModDep.packageName) | ||
} | ||
} | ||
|
||
// Check for now unused dependencies (defined in d/control but not in go.mod) | ||
for _, packageDep := range packageDeps { | ||
found := false | ||
|
||
for _, goModDep := range goModDepds { | ||
if goModDep.packageName == packageDep.packageName { | ||
found = true | ||
break | ||
} | ||
} | ||
|
||
if !found { | ||
hasChanged = true | ||
fmt.Printf("RM dependency %s (%s)\n", packageDep.importPath, packageDep.packageName) | ||
} | ||
} | ||
|
||
if !hasChanged { | ||
fmt.Printf("go.mod and d/control are in sync\n") | ||
} | ||
} | ||
|
||
// parseGoModDependencies parse ALL dependencies listed in go.mod | ||
// i.e. it returns the one defined in go.mod as well as the transitively ones | ||
// TODO: this may not be the best way of doing thing since it requires the package to be converted to go module | ||
func parseGoModDependencies(directory string, goBinaries map[string]string) ([]dependency, error) { | ||
b, err := ioutil.ReadFile(filepath.Join(directory, "go.mod")) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
modFile, err := modfile.Parse("go.mod", b, nil) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
var dependencies []dependency | ||
for _, require := range modFile.Require { | ||
if !require.Indirect { | ||
packageName := "" | ||
|
||
// Translate all packages to the root of their repository | ||
rr, err := vcs.RepoRootForImportPath(require.Mod.Path, false) | ||
if err != nil { | ||
log.Printf("Could not determine repo path for import path %q: %v\n", require.Mod.Path, err) | ||
continue | ||
} | ||
|
||
if val, exists := goBinaries[rr.Root]; exists { | ||
packageName = val | ||
} | ||
|
||
dependencies = append(dependencies, dependency{ | ||
importPath: rr.Root, | ||
packageName: packageName, | ||
}) | ||
} | ||
} | ||
|
||
return dependencies, nil | ||
} | ||
|
||
// parseDebianControlDependencies parse the Build-Depends defined in d/control | ||
func parseDebianControlDependencies(directory string) ([]dependency, error) { | ||
ctrl, err := control.ParseControlFile(filepath.Join(directory, "debian", "control")) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
var dependencies []dependency | ||
|
||
for _, bp := range ctrl.Source.BuildDepends.GetAllPossibilities() { | ||
packageName := strings.Trim(bp.Name, "\n") | ||
|
||
// Ignore non -dev dependencies (i.e, debhelper-compat, git, cmake, etc...) | ||
if !strings.HasSuffix(packageName, "-dev") { | ||
continue | ||
} | ||
|
||
dependencies = append(dependencies, dependency{ | ||
importPath: "", // TODO XS-Go-Import-Path? | ||
packageName: packageName, | ||
}) | ||
} | ||
|
||
return dependencies, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,142 @@ | ||
package main | ||
|
||
import ( | ||
"io/ioutil" | ||
"os" | ||
"path/filepath" | ||
"reflect" | ||
"testing" | ||
) | ||
|
||
func TestParseDebianControlDependencies(t *testing.T) { | ||
f := `Source: terminews | ||
Maintainer: Debian Go Packaging Team <team+pkg-go@tracker.debian.org> | ||
Uploaders: | ||
Aloïs Micard <alois@micard.lu>, | ||
Section: news | ||
Testsuite: autopkgtest-pkg-go | ||
Priority: optional | ||
Build-Depends: | ||
debhelper-compat (= 13), | ||
dh-golang, | ||
golang-any, | ||
golang-github-advancedlogic-goose-dev, | ||
golang-github-fatih-color-dev, | ||
golang-github-jroimartin-gocui-dev, | ||
golang-github-mattn-go-sqlite3-dev, | ||
golang-github-mmcdole-gofeed-dev, | ||
Standards-Version: 4.5.1 | ||
Vcs-Browser: https://salsa.debian.org/go-team/packages/terminews | ||
Vcs-Git: https://salsa.debian.org/go-team/packages/terminews.git | ||
Homepage: https://github.com/antavelos/terminews | ||
Rules-Requires-Root: no | ||
XS-Go-Import-Path: github.com/antavelos/terminews | ||
Package: terminews | ||
Architecture: any | ||
Depends: | ||
${misc:Depends}, | ||
${shlibs:Depends}, | ||
Built-Using: | ||
${misc:Built-Using}, | ||
Description: read your RSS feeds from your terminal | ||
Terminews is a terminal based application (TUI) | ||
that allows you to manage RSS resources and display their news feeds. | ||
` | ||
tmpDir, err := ioutil.TempDir("", "dh-make-golang") | ||
if err != nil { | ||
t.Fatalf("Could not create temp dir: %v", err) | ||
} | ||
defer os.RemoveAll(tmpDir) | ||
|
||
if err := os.MkdirAll(filepath.Join(tmpDir, "dummy-package", "debian"), 0750); err != nil { | ||
t.Fatalf("Could not create dummy Debian package: %v", err) | ||
} | ||
if err := ioutil.WriteFile(filepath.Join(tmpDir, "dummy-package", "debian", "control"), []byte(f), 0640); err != nil { | ||
t.Fatalf("Could not create dummy Debian package: %v", err) | ||
} | ||
|
||
deps, err := parseDebianControlDependencies(filepath.Join(tmpDir, "dummy-package")) | ||
if err != nil { | ||
t.Fatalf("Could not parse Debian package dependencies: %v", err) | ||
|
||
} | ||
|
||
want := []dependency{ | ||
{ | ||
importPath: "", | ||
packageName: "golang-github-advancedlogic-goose-dev", | ||
}, | ||
{ | ||
importPath: "", | ||
packageName: "golang-github-fatih-color-dev", | ||
}, { | ||
importPath: "", | ||
packageName: "golang-github-jroimartin-gocui-dev", | ||
}, | ||
{ | ||
importPath: "", | ||
packageName: "golang-github-mattn-go-sqlite3-dev", | ||
}, | ||
{ | ||
importPath: "", | ||
packageName: "golang-github-mmcdole-gofeed-dev", | ||
}, | ||
} | ||
|
||
if !reflect.DeepEqual(deps, want) { | ||
t.Fatalf("Wrong dependencies returned (got %v want %v)", deps, want) | ||
} | ||
} | ||
|
||
func TestParseGoModDependencies(t *testing.T) { | ||
f := `module github.com/Debian/dh-make-golang | ||
go 1.16 | ||
require ( | ||
github.com/charmbracelet/glamour v0.3.0 | ||
github.com/google/go-github/v38 v38.1.0 | ||
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 | ||
)` | ||
tmpDir, err := ioutil.TempDir("", "dh-make-golang") | ||
if err != nil { | ||
t.Fatalf("Could not create temp dir: %v", err) | ||
} | ||
defer os.RemoveAll(tmpDir) | ||
|
||
if err := os.MkdirAll(filepath.Join(tmpDir, "dummy-package"), 0750); err != nil { | ||
t.Fatalf("Could not create dummy Debian package: %v", err) | ||
} | ||
if err := ioutil.WriteFile(filepath.Join(tmpDir, "dummy-package", "go.mod"), []byte(f), 0640); err != nil { | ||
t.Fatalf("Could not create dummy Debian package: %v", err) | ||
} | ||
|
||
deps, err := parseGoModDependencies(filepath.Join(tmpDir, "dummy-package"), map[string]string{ | ||
"github.com/charmbracelet/glamour": "golang-github-charmbracelet-glamour-dev", | ||
"github.com/google/go-github": "golang-github-google-go-github-dev", | ||
"github.com/gregjones/httpcache": "golang-github-gregjones-httpcache-dev", | ||
}) | ||
if err != nil { | ||
t.Fatalf("Could not parse go.mod dependencies: %v", err) | ||
|
||
} | ||
|
||
want := []dependency{ | ||
{ | ||
importPath: "github.com/charmbracelet/glamour", | ||
packageName: "golang-github-charmbracelet-glamour-dev", | ||
}, | ||
{ | ||
importPath: "github.com/google/go-github", | ||
packageName: "golang-github-google-go-github-dev", | ||
}, { | ||
importPath: "github.com/gregjones/httpcache", | ||
packageName: "golang-github-gregjones-httpcache-dev", | ||
}, | ||
} | ||
|
||
if !reflect.DeepEqual(deps, want) { | ||
t.Fatalf("Wrong dependencies returned (got %v want %v)", deps, want) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.