Skip to content

Commit

Permalink
Implement check-depends (#171)
Browse files Browse the repository at this point in the history
* 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
creekorful authored Nov 25, 2021
1 parent 04307a0 commit 7147d3b
Show file tree
Hide file tree
Showing 6 changed files with 323 additions and 7 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ dh-make-golang
_build/
*~
*.sw[op]
.idea
155 changes: 155 additions & 0 deletions check_depends.go
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
}
142 changes: 142 additions & 0 deletions check_depends_test.go
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)
}
}
4 changes: 3 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ require (
github.com/google/go-github/v38 v38.1.0
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79
github.com/mattn/go-isatty v0.0.12
golang.org/x/mod v0.5.1 // indirect
golang.org/x/net v0.0.0-20210331212208-0fccb6fa2b5c
golang.org/x/sync v0.0.0-20190423024810-112230192c58
golang.org/x/tools v0.0.0-20190731163215-a81e99d7481f
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e
pault.ag/go/debian v0.12.0
)
25 changes: 19 additions & 6 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
github.com/alecthomas/assert v0.0.0-20170929043011-405dbfeb8e38 h1:smF2tmSOzy2Mm+0dGI2AIUHY+w0BUc+4tn40djz7+6U=
github.com/DataDog/zstd v1.4.8/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw=
github.com/alecthomas/assert v0.0.0-20170929043011-405dbfeb8e38/go.mod h1:r7bzyVFMNntcxPZXK3/+KdruV1H5KSlyVY0gc+NgInI=
github.com/alecthomas/chroma v0.8.2 h1:x3zkuE2lUk/RIekyAJ3XRqSCP4zwWDfcw/YJCuCAACg=
github.com/alecthomas/chroma v0.8.2/go.mod h1:sko8vR34/90zvl5QdcUdvzL3J8NKjAUx9va9jPuFNoM=
github.com/alecthomas/colour v0.0.0-20160524082231-60882d9e2721 h1:JHZL0hZKJ1VENNfmXvHbgYlbUOvpzYzvy2aZU5gXVeo=
github.com/alecthomas/colour v0.0.0-20160524082231-60882d9e2721/go.mod h1:QO9JBoKquHd+jz9nshCh40fOfO+JzsoXy8qTHF68zU0=
github.com/alecthomas/kong v0.2.4/go.mod h1:kQOmtJgV+Lb4aj+I2LEn40cbtawdWJ9Y8QLq+lElKxE=
github.com/alecthomas/repr v0.0.0-20180818092828-117648cd9897 h1:p9Sln00KOTlrYkxI1zYWl1QLnEqAqEARBEYa8FQnQcY=
github.com/alecthomas/repr v0.0.0-20180818092828-117648cd9897/go.mod h1:xTS7Pm1pD1mvyM075QCDSRqH6qRLXylzS24ZTpRiSzQ=
github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk=
github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4=
Expand All @@ -18,7 +16,6 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
github.com/dlclark/regexp2 v1.2.0 h1:8sAhBGEM0dRWogWqWyQeIJnxjWO6oIjl8FKqREDsGfk=
github.com/dlclark/regexp2 v1.2.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-github/v38 v38.1.0 h1:C6h1FkaITcBFK7gAmq4eFzt6gbhEhk7L5z6R3Uva+po=
github.com/google/go-github/v38 v38.1.0/go.mod h1:cStvrz/7nFr0FoENgG6GLbp53WaelXucT+BBz/3VKx4=
Expand All @@ -28,6 +25,7 @@ github.com/gorilla/css v1.0.0 h1:BQqNyPTi50JCFMTw/b67hByjMVXZRwGha6wxVGkeihY=
github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c=
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 h1:+ngKgrYPPJrOjhax5N+uePQ0Fh1Z7PheYoUI/0nzkPA=
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
github.com/kjk/lzma v0.0.0-20161016003348-3fd93898850d/go.mod h1:phT/jsRPBAEqjAibu1BurrabCBNTYiVI+zbmyCZJY6Q=
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
Expand All @@ -49,26 +47,32 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rivo/uniseg v0.1.0 h1:+2KBaVoUmb9XzDsrx/Ct0W/EYOSFf/nWTauy++DprtY=
github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ=
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMxjDjgmT5uz5wzYJKVo23qUhYTos=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.3.3 h1:37BdQwPx8VOSic8eDSWee6QL9mRpZRm9VJp/QugNrW0=
github.com/yuin/goldmark v1.3.3/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/goldmark-emoji v1.0.1 h1:ctuWEyzGBwiucEqxzwe0SOYDXPAucOrE9NQC18Wa1os=
github.com/yuin/goldmark-emoji v1.0.1/go.mod h1:2w1E6FEWLcDQkoTE+7HU6QF1F6SLlNGjRIBbIZQFqkQ=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897 h1:pLI5jrR7OSLijeIDcmRxNmw2api+jEfxLoykJVice/E=
golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/mod v0.5.1 h1:OJxoQ/rynoF0dcCdI7cLPktw/hR2cueqYfjm43oqK38=
golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210331212208-0fccb6fa2b5c h1:KHUzaHIpjWVlVVNh65G3hhuj3KB1HnjY6Cq5cTvRQT8=
golang.org/x/net v0.0.0-20210331212208-0fccb6fa2b5c/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200413165638-669c56c373c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
Expand All @@ -81,5 +85,14 @@ 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=
golang.org/x/tools v0.0.0-20190731163215-a81e99d7481f h1:vwy91pya0J00SsPf35DrwOUOe/76iE4RbegH6XWNn9I=
golang.org/x/tools v0.0.0-20190731163215-a81e99d7481f/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e h1:aZzprAO9/8oim3qStq3wc1Xuxx4QmAGriC4VU4ojemQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
pault.ag/go/debian v0.12.0 h1:b8ctSdBSGJ98NE1VLn06aSx70EUpczlP2qqSHEiYYJA=
pault.ag/go/debian v0.12.0/go.mod h1:UbnMr3z/KZepjq7VzbYgBEfz8j4+Pyrm2L5X1fzhy/k=
pault.ag/go/topsort v0.0.0-20160530003732-f98d2ad46e1a h1:WwS7vlB5H2AtwKj1jsGwp2ZLud1x6WXRXh2fXsRqrcA=
pault.ag/go/topsort v0.0.0-20160530003732-f98d2ad46e1a/go.mod h1:INqx0ClF7kmPAMk2zVTX8DRnhZ/yaA/Mg52g8KFKE7k=
Loading

0 comments on commit 7147d3b

Please sign in to comment.