Merge ~dviererbe/ubuntu/+source/dh-make-golang:lp2046369 into ubuntu/+source/dh-make-golang:ubuntu/devel

Proposed by Dominik Viererbe
Status: Merged
Merge reported by: Dominik Viererbe
Merged at revision: 0b036a097be51a70929463d03e311e58b84ccd06
Proposed branch: ~dviererbe/ubuntu/+source/dh-make-golang:lp2046369
Merge into: ubuntu/+source/dh-make-golang:ubuntu/devel
Diff against target: 1435 lines (+1309/-2)
11 files modified
debian/changelog (+12/-0)
debian/control (+2/-1)
debian/copyright (+4/-0)
debian/go/src/golang.org/x/tools/go/vcs/discovery.go (+83/-0)
debian/go/src/golang.org/x/tools/go/vcs/env.go (+39/-0)
debian/go/src/golang.org/x/tools/go/vcs/go.mod (+7/-0)
debian/go/src/golang.org/x/tools/go/vcs/http.go (+80/-0)
debian/go/src/golang.org/x/tools/go/vcs/vcs.go (+764/-0)
debian/go/src/golang.org/x/tools/go/vcs/vcs_test.go (+309/-0)
debian/rules (+9/-0)
dev/null (+0/-1)
Reviewer Review Type Date Requested Status
Simon Chopin Pending
git-ubuntu import Pending
Review via email: mp+463019@code.launchpad.net

Description of the change

Fixes FTBFS of 0.6.0-2build1 (LP: #2046369) by backporting changes from 0.7.0-1 in debian sid.

Syncing 0.7.0-1 is currently undesirable, because it requires a sync of golang-github-google-go-github 60.0.0-1 from debian sid, which causes reverse dependencies to FTBFS. We can address this issue and remove the delta next cycle, but the Beta release is too close address it now.

To post a comment you must log in.
Revision history for this message
Dominik Viererbe (dviererbe) wrote :

* Builds in a PPA with proposed enabled: https://launchpad.net/~dviererbe/+archive/ubuntu/lp2046369-ppa2/+packages
* The package has no autopkgtests.

Revision history for this message
Dominik Viererbe (dviererbe) wrote :

Someone synced 0.7.0-1 and golang-github-google-go-github 60.0.0-1 anyway. Therefore this merge is not needed anymore.

Note: I set the state to "merged" even though this MP never got merged, because there is no state to "reject" the merge.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/debian/changelog b/debian/changelog
2index c231f11..77e461b 100644
3--- a/debian/changelog
4+++ b/debian/changelog
5@@ -1,3 +1,15 @@
6+dh-make-golang (0.6.0-2ubuntu1) noble; urgency=medium
7+
8+ * Disable lto.
9+ * Include copy of golang.org/x/tools/go/vcs@v0.1.0-deprecated (LP: #2046369);
10+ backported from 0.7.0-1 in debian unstable (see debian bug: #1043070):
11+ - debian/go/src/golang.org/x/tools/go/vcs
12+ - debian/copyright: add copiright information
13+ - debian/rules: add execute_after_dh_auto_configure target to configure copy
14+ - debian/patches/*: removed
15+
16+ -- Dominik Viererbe <dominik.viererbe@canonical.com> Mon, 25 Mar 2024 13:27:14 +0200
17+
18 dh-make-golang (0.6.0-2build1) mantic; urgency=medium
19
20 * No-change rebuild with Go 1.21.
21diff --git a/debian/control b/debian/control
22index 553d6f6..bd69f19 100644
23--- a/debian/control
24+++ b/debian/control
25@@ -1,5 +1,6 @@
26 Source: dh-make-golang
27-Maintainer: Debian Go Packaging Team <team+pkg-go@tracker.debian.org>
28+Maintainer: Ubuntu Developers <ubuntu-devel-discuss@lists.ubuntu.com>
29+XSBC-Original-Maintainer: Debian Go Packaging Team <team+pkg-go@tracker.debian.org>
30 Uploaders: Michael Stapelberg <stapelberg@debian.org>,
31 Dr. Tobias Quathamer <toddy@debian.org>,
32 Anthony Fok <foka@debian.org>,
33diff --git a/debian/copyright b/debian/copyright
34index d05ed52..a7307d5 100644
35--- a/debian/copyright
36+++ b/debian/copyright
37@@ -16,6 +16,10 @@ Copyright:
38 License: BSD-3-clause
39 Comment: Debian packaging is licensed under the same terms as upstream
40
41+Files: debian/go/src/golang.org/x/tools/go/vcs/*
42+Copyright: 2009 The Go Authors
43+License: BSD-3-clause
44+
45 License: BSD-3-clause
46 Copyright © 2015, Michael Stapelberg, Google Inc. and contributors
47 All rights reserved.
48diff --git a/debian/go/src/golang.org/x/tools/go/vcs/discovery.go b/debian/go/src/golang.org/x/tools/go/vcs/discovery.go
49new file mode 100644
50index 0000000..7d179bc
51--- /dev/null
52+++ b/debian/go/src/golang.org/x/tools/go/vcs/discovery.go
53@@ -0,0 +1,83 @@
54+// Copyright 2012 The Go Authors. All rights reserved.
55+// Use of this source code is governed by a BSD-style
56+// license that can be found in the LICENSE file.
57+
58+package vcs
59+
60+import (
61+ "encoding/xml"
62+ "fmt"
63+ "io"
64+ "strings"
65+)
66+
67+// charsetReader returns a reader for the given charset. Currently
68+// it only supports UTF-8 and ASCII. Otherwise, it returns a meaningful
69+// error which is printed by go get, so the user can find why the package
70+// wasn't downloaded if the encoding is not supported. Note that, in
71+// order to reduce potential errors, ASCII is treated as UTF-8 (i.e. characters
72+// greater than 0x7f are not rejected).
73+func charsetReader(charset string, input io.Reader) (io.Reader, error) {
74+ switch strings.ToLower(charset) {
75+ case "ascii":
76+ return input, nil
77+ default:
78+ return nil, fmt.Errorf("can't decode XML document using charset %q", charset)
79+ }
80+}
81+
82+// parseMetaGoImports returns meta imports from the HTML in r.
83+// Parsing ends at the end of the <head> section or the beginning of the <body>.
84+//
85+// This copy of cmd/go/internal/vcs.parseMetaGoImports always operates
86+// in IgnoreMod ModuleMode.
87+func parseMetaGoImports(r io.Reader) (imports []metaImport, err error) {
88+ d := xml.NewDecoder(r)
89+ d.CharsetReader = charsetReader
90+ d.Strict = false
91+ var t xml.Token
92+ for {
93+ t, err = d.RawToken()
94+ if err != nil {
95+ if err == io.EOF || len(imports) > 0 {
96+ err = nil
97+ }
98+ return
99+ }
100+ if e, ok := t.(xml.StartElement); ok && strings.EqualFold(e.Name.Local, "body") {
101+ return
102+ }
103+ if e, ok := t.(xml.EndElement); ok && strings.EqualFold(e.Name.Local, "head") {
104+ return
105+ }
106+ e, ok := t.(xml.StartElement)
107+ if !ok || !strings.EqualFold(e.Name.Local, "meta") {
108+ continue
109+ }
110+ if attrValue(e.Attr, "name") != "go-import" {
111+ continue
112+ }
113+ if f := strings.Fields(attrValue(e.Attr, "content")); len(f) == 3 {
114+ // Ignore VCS type "mod", which is applicable only in module mode.
115+ if f[1] == "mod" {
116+ continue
117+ }
118+ imports = append(imports, metaImport{
119+ Prefix: f[0],
120+ VCS: f[1],
121+ RepoRoot: f[2],
122+ })
123+ }
124+ }
125+}
126+
127+// attrValue returns the attribute value for the case-insensitive key
128+// `name', or the empty string if nothing is found.
129+func attrValue(attrs []xml.Attr, name string) string {
130+ for _, a := range attrs {
131+ if strings.EqualFold(a.Name.Local, name) {
132+ return a.Value
133+ }
134+ }
135+ return ""
136+}
137diff --git a/debian/go/src/golang.org/x/tools/go/vcs/env.go b/debian/go/src/golang.org/x/tools/go/vcs/env.go
138new file mode 100644
139index 0000000..189210c
140--- /dev/null
141+++ b/debian/go/src/golang.org/x/tools/go/vcs/env.go
142@@ -0,0 +1,39 @@
143+// Copyright 2013 The Go Authors. All rights reserved.
144+// Use of this source code is governed by a BSD-style
145+// license that can be found in the LICENSE file.
146+
147+package vcs
148+
149+import (
150+ "os"
151+ "strings"
152+)
153+
154+// envForDir returns a copy of the environment
155+// suitable for running in the given directory.
156+// The environment is the current process's environment
157+// but with an updated $PWD, so that an os.Getwd in the
158+// child will be faster.
159+func envForDir(dir string) []string {
160+ env := os.Environ()
161+ // Internally we only use rooted paths, so dir is rooted.
162+ // Even if dir is not rooted, no harm done.
163+ return mergeEnvLists([]string{"PWD=" + dir}, env)
164+}
165+
166+// mergeEnvLists merges the two environment lists such that
167+// variables with the same name in "in" replace those in "out".
168+func mergeEnvLists(in, out []string) []string {
169+NextVar:
170+ for _, inkv := range in {
171+ k := strings.SplitAfterN(inkv, "=", 2)[0]
172+ for i, outkv := range out {
173+ if strings.HasPrefix(outkv, k) {
174+ out[i] = inkv
175+ continue NextVar
176+ }
177+ }
178+ out = append(out, inkv)
179+ }
180+ return out
181+}
182diff --git a/debian/go/src/golang.org/x/tools/go/vcs/go.mod b/debian/go/src/golang.org/x/tools/go/vcs/go.mod
183new file mode 100644
184index 0000000..74da6cb
185--- /dev/null
186+++ b/debian/go/src/golang.org/x/tools/go/vcs/go.mod
187@@ -0,0 +1,7 @@
188+// Deprecated: This module contains one deprecated package.
189+// See the package deprecation notice for more information.
190+module golang.org/x/tools/go/vcs
191+
192+go 1.19
193+
194+require golang.org/x/sys v0.9.0
195diff --git a/debian/go/src/golang.org/x/tools/go/vcs/http.go b/debian/go/src/golang.org/x/tools/go/vcs/http.go
196new file mode 100644
197index 0000000..5836511
198--- /dev/null
199+++ b/debian/go/src/golang.org/x/tools/go/vcs/http.go
200@@ -0,0 +1,80 @@
201+// Copyright 2012 The Go Authors. All rights reserved.
202+// Use of this source code is governed by a BSD-style
203+// license that can be found in the LICENSE file.
204+
205+package vcs
206+
207+import (
208+ "fmt"
209+ "io"
210+ "io/ioutil"
211+ "log"
212+ "net/http"
213+ "net/url"
214+)
215+
216+// httpClient is the default HTTP client, but a variable so it can be
217+// changed by tests, without modifying http.DefaultClient.
218+var httpClient = http.DefaultClient
219+
220+// httpGET returns the data from an HTTP GET request for the given URL.
221+func httpGET(url string) ([]byte, error) {
222+ resp, err := httpClient.Get(url)
223+ if err != nil {
224+ return nil, err
225+ }
226+ defer resp.Body.Close()
227+ if resp.StatusCode != 200 {
228+ return nil, fmt.Errorf("%s: %s", url, resp.Status)
229+ }
230+ b, err := ioutil.ReadAll(resp.Body)
231+ if err != nil {
232+ return nil, fmt.Errorf("%s: %v", url, err)
233+ }
234+ return b, nil
235+}
236+
237+// httpsOrHTTP returns the body of either the importPath's
238+// https resource or, if unavailable, the http resource.
239+func httpsOrHTTP(importPath string) (urlStr string, body io.ReadCloser, err error) {
240+ fetch := func(scheme string) (urlStr string, res *http.Response, err error) {
241+ u, err := url.Parse(scheme + "://" + importPath)
242+ if err != nil {
243+ return "", nil, err
244+ }
245+ u.RawQuery = "go-get=1"
246+ urlStr = u.String()
247+ if Verbose {
248+ log.Printf("Fetching %s", urlStr)
249+ }
250+ res, err = httpClient.Get(urlStr)
251+ return
252+ }
253+ closeBody := func(res *http.Response) {
254+ if res != nil {
255+ res.Body.Close()
256+ }
257+ }
258+ urlStr, res, err := fetch("https")
259+ if err != nil || res.StatusCode != 200 {
260+ if Verbose {
261+ if err != nil {
262+ log.Printf("https fetch failed.")
263+ } else {
264+ log.Printf("ignoring https fetch with status code %d", res.StatusCode)
265+ }
266+ }
267+ closeBody(res)
268+ urlStr, res, err = fetch("http")
269+ }
270+ if err != nil {
271+ closeBody(res)
272+ return "", nil, err
273+ }
274+ // Note: accepting a non-200 OK here, so people can serve a
275+ // meta import in their http 404 page.
276+ if Verbose {
277+ log.Printf("Parsing meta tags from %s (status code %d)", urlStr, res.StatusCode)
278+ }
279+ return urlStr, res.Body, nil
280+}
281diff --git a/debian/go/src/golang.org/x/tools/go/vcs/vcs.go b/debian/go/src/golang.org/x/tools/go/vcs/vcs.go
282new file mode 100644
283index 0000000..232177d
284--- /dev/null
285+++ b/debian/go/src/golang.org/x/tools/go/vcs/vcs.go
286@@ -0,0 +1,764 @@
287+// Copyright 2012 The Go Authors. All rights reserved.
288+// Use of this source code is governed by a BSD-style
289+// license that can be found in the LICENSE file.
290+
291+// Package vcs exposes functions for resolving import paths
292+// and using version control systems, which can be used to
293+// implement behavior similar to the standard "go get" command.
294+//
295+// Deprecated: Use the go list command with -json flag instead,
296+// which implements up-to-date import path resolution behavior,
297+// module support, and includes the latest security fixes.
298+//
299+// This package was a copy of internal code in package cmd/go/internal/get
300+// before module support, modified to make the identifiers exported.
301+// It was provided here for developers who wanted to write tools with similar semantics.
302+// It needed to be manually kept in sync with upstream when changes were
303+// made to cmd/go/internal/get, as tracked in go.dev/issue/11490.
304+// By now, it has diverged significantly from upstream cmd/go/internal/get
305+// behavior and will not receive any further updates.
306+package vcs // import "golang.org/x/tools/go/vcs"
307+
308+import (
309+ "bytes"
310+ "encoding/json"
311+ "errors"
312+ "fmt"
313+ exec "golang.org/x/sys/execabs"
314+ "log"
315+ "net/url"
316+ "os"
317+ "path/filepath"
318+ "regexp"
319+ "strconv"
320+ "strings"
321+)
322+
323+// Verbose enables verbose operation logging.
324+var Verbose bool
325+
326+// ShowCmd controls whether VCS commands are printed.
327+var ShowCmd bool
328+
329+// A Cmd describes how to use a version control system
330+// like Mercurial, Git, or Subversion.
331+type Cmd struct {
332+ Name string
333+ Cmd string // name of binary to invoke command
334+
335+ CreateCmd string // command to download a fresh copy of a repository
336+ DownloadCmd string // command to download updates into an existing repository
337+
338+ TagCmd []TagCmd // commands to list tags
339+ TagLookupCmd []TagCmd // commands to lookup tags before running tagSyncCmd
340+ TagSyncCmd string // command to sync to specific tag
341+ TagSyncDefault string // command to sync to default tag
342+
343+ LogCmd string // command to list repository changelogs in an XML format
344+
345+ Scheme []string
346+ PingCmd string
347+}
348+
349+// A TagCmd describes a command to list available tags
350+// that can be passed to Cmd.TagSyncCmd.
351+type TagCmd struct {
352+ Cmd string // command to list tags
353+ Pattern string // regexp to extract tags from list
354+}
355+
356+// vcsList lists the known version control systems
357+var vcsList = []*Cmd{
358+ vcsHg,
359+ vcsGit,
360+ vcsSvn,
361+ vcsBzr,
362+}
363+
364+// ByCmd returns the version control system for the given
365+// command name (hg, git, svn, bzr).
366+func ByCmd(cmd string) *Cmd {
367+ for _, vcs := range vcsList {
368+ if vcs.Cmd == cmd {
369+ return vcs
370+ }
371+ }
372+ return nil
373+}
374+
375+// vcsHg describes how to use Mercurial.
376+var vcsHg = &Cmd{
377+ Name: "Mercurial",
378+ Cmd: "hg",
379+
380+ CreateCmd: "clone -U {repo} {dir}",
381+ DownloadCmd: "pull",
382+
383+ // We allow both tag and branch names as 'tags'
384+ // for selecting a version. This lets people have
385+ // a go.release.r60 branch and a go1 branch
386+ // and make changes in both, without constantly
387+ // editing .hgtags.
388+ TagCmd: []TagCmd{
389+ {"tags", `^(\S+)`},
390+ {"branches", `^(\S+)`},
391+ },
392+ TagSyncCmd: "update -r {tag}",
393+ TagSyncDefault: "update default",
394+
395+ LogCmd: "log --encoding=utf-8 --limit={limit} --template={template}",
396+
397+ Scheme: []string{"https", "http", "ssh"},
398+ PingCmd: "identify {scheme}://{repo}",
399+}
400+
401+// vcsGit describes how to use Git.
402+var vcsGit = &Cmd{
403+ Name: "Git",
404+ Cmd: "git",
405+
406+ CreateCmd: "clone {repo} {dir}",
407+ DownloadCmd: "pull --ff-only",
408+
409+ TagCmd: []TagCmd{
410+ // tags/xxx matches a git tag named xxx
411+ // origin/xxx matches a git branch named xxx on the default remote repository
412+ {"show-ref", `(?:tags|origin)/(\S+)$`},
413+ },
414+ TagLookupCmd: []TagCmd{
415+ {"show-ref tags/{tag} origin/{tag}", `((?:tags|origin)/\S+)$`},
416+ },
417+ TagSyncCmd: "checkout {tag}",
418+ TagSyncDefault: "checkout master",
419+
420+ Scheme: []string{"git", "https", "http", "git+ssh"},
421+ PingCmd: "ls-remote {scheme}://{repo}",
422+}
423+
424+// vcsBzr describes how to use Bazaar.
425+var vcsBzr = &Cmd{
426+ Name: "Bazaar",
427+ Cmd: "bzr",
428+
429+ CreateCmd: "branch {repo} {dir}",
430+
431+ // Without --overwrite bzr will not pull tags that changed.
432+ // Replace by --overwrite-tags after http://pad.lv/681792 goes in.
433+ DownloadCmd: "pull --overwrite",
434+
435+ TagCmd: []TagCmd{{"tags", `^(\S+)`}},
436+ TagSyncCmd: "update -r {tag}",
437+ TagSyncDefault: "update -r revno:-1",
438+
439+ Scheme: []string{"https", "http", "bzr", "bzr+ssh"},
440+ PingCmd: "info {scheme}://{repo}",
441+}
442+
443+// vcsSvn describes how to use Subversion.
444+var vcsSvn = &Cmd{
445+ Name: "Subversion",
446+ Cmd: "svn",
447+
448+ CreateCmd: "checkout {repo} {dir}",
449+ DownloadCmd: "update",
450+
451+ // There is no tag command in subversion.
452+ // The branch information is all in the path names.
453+
454+ LogCmd: "log --xml --limit={limit}",
455+
456+ Scheme: []string{"https", "http", "svn", "svn+ssh"},
457+ PingCmd: "info {scheme}://{repo}",
458+}
459+
460+func (v *Cmd) String() string {
461+ return v.Name
462+}
463+
464+// run runs the command line cmd in the given directory.
465+// keyval is a list of key, value pairs. run expands
466+// instances of {key} in cmd into value, but only after
467+// splitting cmd into individual arguments.
468+// If an error occurs, run prints the command line and the
469+// command's combined stdout+stderr to standard error.
470+// Otherwise run discards the command's output.
471+func (v *Cmd) run(dir string, cmd string, keyval ...string) error {
472+ _, err := v.run1(dir, cmd, keyval, true)
473+ return err
474+}
475+
476+// runVerboseOnly is like run but only generates error output to standard error in verbose mode.
477+func (v *Cmd) runVerboseOnly(dir string, cmd string, keyval ...string) error {
478+ _, err := v.run1(dir, cmd, keyval, false)
479+ return err
480+}
481+
482+// runOutput is like run but returns the output of the command.
483+func (v *Cmd) runOutput(dir string, cmd string, keyval ...string) ([]byte, error) {
484+ return v.run1(dir, cmd, keyval, true)
485+}
486+
487+// run1 is the generalized implementation of run and runOutput.
488+func (v *Cmd) run1(dir string, cmdline string, keyval []string, verbose bool) ([]byte, error) {
489+ m := make(map[string]string)
490+ for i := 0; i < len(keyval); i += 2 {
491+ m[keyval[i]] = keyval[i+1]
492+ }
493+ args := strings.Fields(cmdline)
494+ for i, arg := range args {
495+ args[i] = expand(m, arg)
496+ }
497+
498+ _, err := exec.LookPath(v.Cmd)
499+ if err != nil {
500+ fmt.Fprintf(os.Stderr,
501+ "go: missing %s command. See http://golang.org/s/gogetcmd\n",
502+ v.Name)
503+ return nil, err
504+ }
505+
506+ cmd := exec.Command(v.Cmd, args...)
507+ cmd.Dir = dir
508+ cmd.Env = envForDir(cmd.Dir)
509+ if ShowCmd {
510+ fmt.Printf("cd %s\n", dir)
511+ fmt.Printf("%s %s\n", v.Cmd, strings.Join(args, " "))
512+ }
513+ var buf bytes.Buffer
514+ cmd.Stdout = &buf
515+ cmd.Stderr = &buf
516+ err = cmd.Run()
517+ out := buf.Bytes()
518+ if err != nil {
519+ if verbose || Verbose {
520+ fmt.Fprintf(os.Stderr, "# cd %s; %s %s\n", dir, v.Cmd, strings.Join(args, " "))
521+ os.Stderr.Write(out)
522+ }
523+ return nil, err
524+ }
525+ return out, nil
526+}
527+
528+// Ping pings the repo to determine if scheme used is valid.
529+// This repo must be pingable with this scheme and VCS.
530+func (v *Cmd) Ping(scheme, repo string) error {
531+ return v.runVerboseOnly(".", v.PingCmd, "scheme", scheme, "repo", repo)
532+}
533+
534+// Create creates a new copy of repo in dir.
535+// The parent of dir must exist; dir must not.
536+func (v *Cmd) Create(dir, repo string) error {
537+ return v.run(".", v.CreateCmd, "dir", dir, "repo", repo)
538+}
539+
540+// CreateAtRev creates a new copy of repo in dir at revision rev.
541+// The parent of dir must exist; dir must not.
542+// rev must be a valid revision in repo.
543+func (v *Cmd) CreateAtRev(dir, repo, rev string) error {
544+ if err := v.Create(dir, repo); err != nil {
545+ return err
546+ }
547+ return v.run(dir, v.TagSyncCmd, "tag", rev)
548+}
549+
550+// Download downloads any new changes for the repo in dir.
551+// dir must be a valid VCS repo compatible with v.
552+func (v *Cmd) Download(dir string) error {
553+ return v.run(dir, v.DownloadCmd)
554+}
555+
556+// Tags returns the list of available tags for the repo in dir.
557+// dir must be a valid VCS repo compatible with v.
558+func (v *Cmd) Tags(dir string) ([]string, error) {
559+ var tags []string
560+ for _, tc := range v.TagCmd {
561+ out, err := v.runOutput(dir, tc.Cmd)
562+ if err != nil {
563+ return nil, err
564+ }
565+ re := regexp.MustCompile(`(?m-s)` + tc.Pattern)
566+ for _, m := range re.FindAllStringSubmatch(string(out), -1) {
567+ tags = append(tags, m[1])
568+ }
569+ }
570+ return tags, nil
571+}
572+
573+// TagSync syncs the repo in dir to the named tag, which is either a
574+// tag returned by Tags or the empty string (the default tag).
575+// dir must be a valid VCS repo compatible with v and the tag must exist.
576+func (v *Cmd) TagSync(dir, tag string) error {
577+ if v.TagSyncCmd == "" {
578+ return nil
579+ }
580+ if tag != "" {
581+ for _, tc := range v.TagLookupCmd {
582+ out, err := v.runOutput(dir, tc.Cmd, "tag", tag)
583+ if err != nil {
584+ return err
585+ }
586+ re := regexp.MustCompile(`(?m-s)` + tc.Pattern)
587+ m := re.FindStringSubmatch(string(out))
588+ if len(m) > 1 {
589+ tag = m[1]
590+ break
591+ }
592+ }
593+ }
594+ if tag == "" && v.TagSyncDefault != "" {
595+ return v.run(dir, v.TagSyncDefault)
596+ }
597+ return v.run(dir, v.TagSyncCmd, "tag", tag)
598+}
599+
600+// Log logs the changes for the repo in dir.
601+// dir must be a valid VCS repo compatible with v.
602+func (v *Cmd) Log(dir, logTemplate string) ([]byte, error) {
603+ if err := v.Download(dir); err != nil {
604+ return []byte{}, err
605+ }
606+
607+ const N = 50 // how many revisions to grab
608+ return v.runOutput(dir, v.LogCmd, "limit", strconv.Itoa(N), "template", logTemplate)
609+}
610+
611+// LogAtRev logs the change for repo in dir at the rev revision.
612+// dir must be a valid VCS repo compatible with v.
613+// rev must be a valid revision for the repo in dir.
614+func (v *Cmd) LogAtRev(dir, rev, logTemplate string) ([]byte, error) {
615+ if err := v.Download(dir); err != nil {
616+ return []byte{}, err
617+ }
618+
619+ // Append revision flag to LogCmd.
620+ logAtRevCmd := v.LogCmd + " --rev=" + rev
621+ return v.runOutput(dir, logAtRevCmd, "limit", strconv.Itoa(1), "template", logTemplate)
622+}
623+
624+// A vcsPath describes how to convert an import path into a
625+// version control system and repository name.
626+type vcsPath struct {
627+ prefix string // prefix this description applies to
628+ re string // pattern for import path
629+ repo string // repository to use (expand with match of re)
630+ vcs string // version control system to use (expand with match of re)
631+ check func(match map[string]string) error // additional checks
632+ ping bool // ping for scheme to use to download repo
633+
634+ regexp *regexp.Regexp // cached compiled form of re
635+}
636+
637+// FromDir inspects dir and its parents to determine the
638+// version control system and code repository to use.
639+// On return, root is the import path
640+// corresponding to the root of the repository.
641+func FromDir(dir, srcRoot string) (vcs *Cmd, root string, err error) {
642+ // Clean and double-check that dir is in (a subdirectory of) srcRoot.
643+ dir = filepath.Clean(dir)
644+ srcRoot = filepath.Clean(srcRoot)
645+ if len(dir) <= len(srcRoot) || dir[len(srcRoot)] != filepath.Separator {
646+ return nil, "", fmt.Errorf("directory %q is outside source root %q", dir, srcRoot)
647+ }
648+
649+ var vcsRet *Cmd
650+ var rootRet string
651+
652+ origDir := dir
653+ for len(dir) > len(srcRoot) {
654+ for _, vcs := range vcsList {
655+ if _, err := os.Stat(filepath.Join(dir, "."+vcs.Cmd)); err == nil {
656+ root := filepath.ToSlash(dir[len(srcRoot)+1:])
657+ // Record first VCS we find, but keep looking,
658+ // to detect mistakes like one kind of VCS inside another.
659+ if vcsRet == nil {
660+ vcsRet = vcs
661+ rootRet = root
662+ continue
663+ }
664+ // Allow .git inside .git, which can arise due to submodules.
665+ if vcsRet == vcs && vcs.Cmd == "git" {
666+ continue
667+ }
668+ // Otherwise, we have one VCS inside a different VCS.
669+ return nil, "", fmt.Errorf("directory %q uses %s, but parent %q uses %s",
670+ filepath.Join(srcRoot, rootRet), vcsRet.Cmd, filepath.Join(srcRoot, root), vcs.Cmd)
671+ }
672+ }
673+
674+ // Move to parent.
675+ ndir := filepath.Dir(dir)
676+ if len(ndir) >= len(dir) {
677+ // Shouldn't happen, but just in case, stop.
678+ break
679+ }
680+ dir = ndir
681+ }
682+
683+ if vcsRet != nil {
684+ return vcsRet, rootRet, nil
685+ }
686+
687+ return nil, "", fmt.Errorf("directory %q is not using a known version control system", origDir)
688+}
689+
690+// RepoRoot represents a version control system, a repo, and a root of
691+// where to put it on disk.
692+type RepoRoot struct {
693+ VCS *Cmd
694+
695+ // Repo is the repository URL, including scheme.
696+ Repo string
697+
698+ // Root is the import path corresponding to the root of the
699+ // repository.
700+ Root string
701+}
702+
703+// RepoRootForImportPath analyzes importPath to determine the
704+// version control system, and code repository to use.
705+func RepoRootForImportPath(importPath string, verbose bool) (*RepoRoot, error) {
706+ rr, err := RepoRootForImportPathStatic(importPath, "")
707+ if err == errUnknownSite {
708+ rr, err = RepoRootForImportDynamic(importPath, verbose)
709+
710+ // RepoRootForImportDynamic returns error detail
711+ // that is irrelevant if the user didn't intend to use a
712+ // dynamic import in the first place.
713+ // Squelch it.
714+ if err != nil {
715+ if Verbose {
716+ log.Printf("import %q: %v", importPath, err)
717+ }
718+ err = fmt.Errorf("unrecognized import path %q", importPath)
719+ }
720+ }
721+
722+ if err == nil && strings.Contains(importPath, "...") && strings.Contains(rr.Root, "...") {
723+ // Do not allow wildcards in the repo root.
724+ rr = nil
725+ err = fmt.Errorf("cannot expand ... in %q", importPath)
726+ }
727+ return rr, err
728+}
729+
730+var errUnknownSite = errors.New("dynamic lookup required to find mapping")
731+
732+// RepoRootForImportPathStatic attempts to map importPath to a
733+// RepoRoot using the commonly-used VCS hosting sites in vcsPaths
734+// (github.com/user/dir), or from a fully-qualified importPath already
735+// containing its VCS type (foo.com/repo.git/dir)
736+//
737+// If scheme is non-empty, that scheme is forced.
738+func RepoRootForImportPathStatic(importPath, scheme string) (*RepoRoot, error) {
739+ if strings.Contains(importPath, "://") {
740+ return nil, fmt.Errorf("invalid import path %q", importPath)
741+ }
742+ for _, srv := range vcsPaths {
743+ if !strings.HasPrefix(importPath, srv.prefix) {
744+ continue
745+ }
746+ m := srv.regexp.FindStringSubmatch(importPath)
747+ if m == nil {
748+ if srv.prefix != "" {
749+ return nil, fmt.Errorf("invalid %s import path %q", srv.prefix, importPath)
750+ }
751+ continue
752+ }
753+
754+ // Build map of named subexpression matches for expand.
755+ match := map[string]string{
756+ "prefix": srv.prefix,
757+ "import": importPath,
758+ }
759+ for i, name := range srv.regexp.SubexpNames() {
760+ if name != "" && match[name] == "" {
761+ match[name] = m[i]
762+ }
763+ }
764+ if srv.vcs != "" {
765+ match["vcs"] = expand(match, srv.vcs)
766+ }
767+ if srv.repo != "" {
768+ match["repo"] = expand(match, srv.repo)
769+ }
770+ if srv.check != nil {
771+ if err := srv.check(match); err != nil {
772+ return nil, err
773+ }
774+ }
775+ vcs := ByCmd(match["vcs"])
776+ if vcs == nil {
777+ return nil, fmt.Errorf("unknown version control system %q", match["vcs"])
778+ }
779+ if srv.ping {
780+ if scheme != "" {
781+ match["repo"] = scheme + "://" + match["repo"]
782+ } else {
783+ for _, scheme := range vcs.Scheme {
784+ if vcs.Ping(scheme, match["repo"]) == nil {
785+ match["repo"] = scheme + "://" + match["repo"]
786+ break
787+ }
788+ }
789+ }
790+ }
791+ rr := &RepoRoot{
792+ VCS: vcs,
793+ Repo: match["repo"],
794+ Root: match["root"],
795+ }
796+ return rr, nil
797+ }
798+ return nil, errUnknownSite
799+}
800+
801+// RepoRootForImportDynamic finds a *RepoRoot for a custom domain that's not
802+// statically known by RepoRootForImportPathStatic.
803+//
804+// This handles custom import paths like "name.tld/pkg/foo" or just "name.tld".
805+func RepoRootForImportDynamic(importPath string, verbose bool) (*RepoRoot, error) {
806+ slash := strings.Index(importPath, "/")
807+ if slash < 0 {
808+ slash = len(importPath)
809+ }
810+ host := importPath[:slash]
811+ if !strings.Contains(host, ".") {
812+ return nil, errors.New("import path doesn't contain a hostname")
813+ }
814+ urlStr, body, err := httpsOrHTTP(importPath)
815+ if err != nil {
816+ return nil, fmt.Errorf("http/https fetch: %v", err)
817+ }
818+ defer body.Close()
819+ imports, err := parseMetaGoImports(body)
820+ if err != nil {
821+ return nil, fmt.Errorf("parsing %s: %v", importPath, err)
822+ }
823+ metaImport, err := matchGoImport(imports, importPath)
824+ if err != nil {
825+ if err != errNoMatch {
826+ return nil, fmt.Errorf("parse %s: %v", urlStr, err)
827+ }
828+ return nil, fmt.Errorf("parse %s: no go-import meta tags", urlStr)
829+ }
830+ if verbose {
831+ log.Printf("get %q: found meta tag %#v at %s", importPath, metaImport, urlStr)
832+ }
833+ // If the import was "uni.edu/bob/project", which said the
834+ // prefix was "uni.edu" and the RepoRoot was "evilroot.com",
835+ // make sure we don't trust Bob and check out evilroot.com to
836+ // "uni.edu" yet (possibly overwriting/preempting another
837+ // non-evil student). Instead, first verify the root and see
838+ // if it matches Bob's claim.
839+ if metaImport.Prefix != importPath {
840+ if verbose {
841+ log.Printf("get %q: verifying non-authoritative meta tag", importPath)
842+ }
843+ urlStr0 := urlStr
844+ urlStr, body, err = httpsOrHTTP(metaImport.Prefix)
845+ if err != nil {
846+ return nil, fmt.Errorf("fetch %s: %v", urlStr, err)
847+ }
848+ imports, err := parseMetaGoImports(body)
849+ if err != nil {
850+ return nil, fmt.Errorf("parsing %s: %v", importPath, err)
851+ }
852+ if len(imports) == 0 {
853+ return nil, fmt.Errorf("fetch %s: no go-import meta tag", urlStr)
854+ }
855+ metaImport2, err := matchGoImport(imports, importPath)
856+ if err != nil || metaImport != metaImport2 {
857+ return nil, fmt.Errorf("%s and %s disagree about go-import for %s", urlStr0, urlStr, metaImport.Prefix)
858+ }
859+ }
860+
861+ if err := validateRepoRoot(metaImport.RepoRoot); err != nil {
862+ return nil, fmt.Errorf("%s: invalid repo root %q: %v", urlStr, metaImport.RepoRoot, err)
863+ }
864+ rr := &RepoRoot{
865+ VCS: ByCmd(metaImport.VCS),
866+ Repo: metaImport.RepoRoot,
867+ Root: metaImport.Prefix,
868+ }
869+ if rr.VCS == nil {
870+ return nil, fmt.Errorf("%s: unknown vcs %q", urlStr, metaImport.VCS)
871+ }
872+ return rr, nil
873+}
874+
875+// validateRepoRoot returns an error if repoRoot does not seem to be
876+// a valid URL with scheme.
877+func validateRepoRoot(repoRoot string) error {
878+ url, err := url.Parse(repoRoot)
879+ if err != nil {
880+ return err
881+ }
882+ if url.Scheme == "" {
883+ return errors.New("no scheme")
884+ }
885+ return nil
886+}
887+
888+// metaImport represents the parsed <meta name="go-import"
889+// content="prefix vcs reporoot" /> tags from HTML files.
890+type metaImport struct {
891+ Prefix, VCS, RepoRoot string
892+}
893+
894+// errNoMatch is returned from matchGoImport when there's no applicable match.
895+var errNoMatch = errors.New("no import match")
896+
897+// pathPrefix reports whether sub is a prefix of s,
898+// only considering entire path components.
899+func pathPrefix(s, sub string) bool {
900+ // strings.HasPrefix is necessary but not sufficient.
901+ if !strings.HasPrefix(s, sub) {
902+ return false
903+ }
904+ // The remainder after the prefix must either be empty or start with a slash.
905+ rem := s[len(sub):]
906+ return rem == "" || rem[0] == '/'
907+}
908+
909+// matchGoImport returns the metaImport from imports matching importPath.
910+// An error is returned if there are multiple matches.
911+// errNoMatch is returned if none match.
912+func matchGoImport(imports []metaImport, importPath string) (_ metaImport, err error) {
913+ match := -1
914+ for i, im := range imports {
915+ if !pathPrefix(importPath, im.Prefix) {
916+ continue
917+ }
918+
919+ if match != -1 {
920+ err = fmt.Errorf("multiple meta tags match import path %q", importPath)
921+ return
922+ }
923+ match = i
924+ }
925+ if match == -1 {
926+ err = errNoMatch
927+ return
928+ }
929+ return imports[match], nil
930+}
931+
932+// expand rewrites s to replace {k} with match[k] for each key k in match.
933+func expand(match map[string]string, s string) string {
934+ for k, v := range match {
935+ s = strings.Replace(s, "{"+k+"}", v, -1)
936+ }
937+ return s
938+}
939+
940+// vcsPaths lists the known vcs paths.
941+var vcsPaths = []*vcsPath{
942+ // Github
943+ {
944+ prefix: "github.com/",
945+ re: `^(?P<root>github\.com/[A-Za-z0-9_.\-]+/[A-Za-z0-9_.\-]+)(/[\p{L}0-9_.\-]+)*$`,
946+ vcs: "git",
947+ repo: "https://{root}",
948+ check: noVCSSuffix,
949+ },
950+
951+ // Bitbucket
952+ {
953+ prefix: "bitbucket.org/",
954+ re: `^(?P<root>bitbucket\.org/(?P<bitname>[A-Za-z0-9_.\-]+/[A-Za-z0-9_.\-]+))(/[A-Za-z0-9_.\-]+)*$`,
955+ repo: "https://{root}",
956+ check: bitbucketVCS,
957+ },
958+
959+ // Launchpad
960+ {
961+ prefix: "launchpad.net/",
962+ re: `^(?P<root>launchpad\.net/((?P<project>[A-Za-z0-9_.\-]+)(?P<series>/[A-Za-z0-9_.\-]+)?|~[A-Za-z0-9_.\-]+/(\+junk|[A-Za-z0-9_.\-]+)/[A-Za-z0-9_.\-]+))(/[A-Za-z0-9_.\-]+)*$`,
963+ vcs: "bzr",
964+ repo: "https://{root}",
965+ check: launchpadVCS,
966+ },
967+
968+ // Git at OpenStack
969+ {
970+ prefix: "git.openstack.org",
971+ re: `^(?P<root>git\.openstack\.org/[A-Za-z0-9_.\-]+/[A-Za-z0-9_.\-]+)(\.git)?(/[A-Za-z0-9_.\-]+)*$`,
972+ vcs: "git",
973+ repo: "https://{root}",
974+ check: noVCSSuffix,
975+ },
976+
977+ // General syntax for any server.
978+ {
979+ re: `^(?P<root>(?P<repo>([a-z0-9.\-]+\.)+[a-z0-9.\-]+(:[0-9]+)?/[A-Za-z0-9_.\-/]*?)\.(?P<vcs>bzr|git|hg|svn))(/[A-Za-z0-9_.\-]+)*$`,
980+ ping: true,
981+ },
982+}
983+
984+func init() {
985+ // fill in cached regexps.
986+ // Doing this eagerly discovers invalid regexp syntax
987+ // without having to run a command that needs that regexp.
988+ for _, srv := range vcsPaths {
989+ srv.regexp = regexp.MustCompile(srv.re)
990+ }
991+}
992+
993+// noVCSSuffix checks that the repository name does not
994+// end in .foo for any version control system foo.
995+// The usual culprit is ".git".
996+func noVCSSuffix(match map[string]string) error {
997+ repo := match["repo"]
998+ for _, vcs := range vcsList {
999+ if strings.HasSuffix(repo, "."+vcs.Cmd) {
1000+ return fmt.Errorf("invalid version control suffix in %s path", match["prefix"])
1001+ }
1002+ }
1003+ return nil
1004+}
1005+
1006+// bitbucketVCS determines the version control system for a
1007+// Bitbucket repository, by using the Bitbucket API.
1008+func bitbucketVCS(match map[string]string) error {
1009+ if err := noVCSSuffix(match); err != nil {
1010+ return err
1011+ }
1012+
1013+ var resp struct {
1014+ SCM string `json:"scm"`
1015+ }
1016+ url := expand(match, "https://api.bitbucket.org/2.0/repositories/{bitname}?fields=scm")
1017+ data, err := httpGET(url)
1018+ if err != nil {
1019+ return err
1020+ }
1021+ if err := json.Unmarshal(data, &resp); err != nil {
1022+ return fmt.Errorf("decoding %s: %v", url, err)
1023+ }
1024+
1025+ if ByCmd(resp.SCM) != nil {
1026+ match["vcs"] = resp.SCM
1027+ if resp.SCM == "git" {
1028+ match["repo"] += ".git"
1029+ }
1030+ return nil
1031+ }
1032+
1033+ return fmt.Errorf("unable to detect version control system for bitbucket.org/ path")
1034+}
1035+
1036+// launchpadVCS solves the ambiguity for "lp.net/project/foo". In this case,
1037+// "foo" could be a series name registered in Launchpad with its own branch,
1038+// and it could also be the name of a directory within the main project
1039+// branch one level up.
1040+func launchpadVCS(match map[string]string) error {
1041+ if match["project"] == "" || match["series"] == "" {
1042+ return nil
1043+ }
1044+ _, err := httpGET(expand(match, "https://code.launchpad.net/{project}{series}/.bzr/branch-format"))
1045+ if err != nil {
1046+ match["root"] = expand(match, "launchpad.net/{project}")
1047+ match["repo"] = expand(match, "https://{root}")
1048+ }
1049+ return nil
1050+}
1051diff --git a/debian/go/src/golang.org/x/tools/go/vcs/vcs_test.go b/debian/go/src/golang.org/x/tools/go/vcs/vcs_test.go
1052new file mode 100644
1053index 0000000..a17b50d
1054--- /dev/null
1055+++ b/debian/go/src/golang.org/x/tools/go/vcs/vcs_test.go
1056@@ -0,0 +1,309 @@
1057+// Copyright 2013 The Go Authors. All rights reserved.
1058+// Use of this source code is governed by a BSD-style
1059+// license that can be found in the LICENSE file.
1060+
1061+package vcs
1062+
1063+import (
1064+ "errors"
1065+ "io/ioutil"
1066+ "os"
1067+ "path"
1068+ "path/filepath"
1069+ "reflect"
1070+ "runtime"
1071+ "strings"
1072+ "testing"
1073+)
1074+
1075+// Test that RepoRootForImportPath creates the correct RepoRoot for a given importPath.
1076+// TODO(cmang): Add tests for SVN and BZR.
1077+func TestRepoRootForImportPath(t *testing.T) {
1078+ if runtime.GOOS == "android" {
1079+ t.Skipf("incomplete source tree on %s", runtime.GOOS)
1080+ }
1081+
1082+ tests := []struct {
1083+ path string
1084+ want *RepoRoot
1085+ }{
1086+ {
1087+ "github.com/golang/groupcache",
1088+ &RepoRoot{
1089+ VCS: vcsGit,
1090+ Repo: "https://github.com/golang/groupcache",
1091+ },
1092+ },
1093+ // Unicode letters in directories (issue 18660).
1094+ {
1095+ "github.com/user/unicode/испытание",
1096+ &RepoRoot{
1097+ VCS: vcsGit,
1098+ Repo: "https://github.com/user/unicode",
1099+ },
1100+ },
1101+ }
1102+
1103+ for _, test := range tests {
1104+ got, err := RepoRootForImportPath(test.path, false)
1105+ if err != nil {
1106+ t.Errorf("RepoRootForImportPath(%q): %v", test.path, err)
1107+ continue
1108+ }
1109+ want := test.want
1110+ if got.VCS.Name != want.VCS.Name || got.Repo != want.Repo {
1111+ t.Errorf("RepoRootForImportPath(%q) = VCS(%s) Repo(%s), want VCS(%s) Repo(%s)", test.path, got.VCS, got.Repo, want.VCS, want.Repo)
1112+ }
1113+ }
1114+}
1115+
1116+// Test that FromDir correctly inspects a given directory and returns the right VCS and root.
1117+func TestFromDir(t *testing.T) {
1118+ tempDir, err := ioutil.TempDir("", "vcstest")
1119+ if err != nil {
1120+ t.Fatal(err)
1121+ }
1122+ defer os.RemoveAll(tempDir)
1123+
1124+ for j, vcs := range vcsList {
1125+ dir := filepath.Join(tempDir, "example.com", vcs.Name, "."+vcs.Cmd)
1126+ if j&1 == 0 {
1127+ err := os.MkdirAll(dir, 0755)
1128+ if err != nil {
1129+ t.Fatal(err)
1130+ }
1131+ } else {
1132+ err := os.MkdirAll(filepath.Dir(dir), 0755)
1133+ if err != nil {
1134+ t.Fatal(err)
1135+ }
1136+ f, err := os.Create(dir)
1137+ if err != nil {
1138+ t.Fatal(err)
1139+ }
1140+ f.Close()
1141+ }
1142+
1143+ want := RepoRoot{
1144+ VCS: vcs,
1145+ Root: path.Join("example.com", vcs.Name),
1146+ }
1147+ var got RepoRoot
1148+ got.VCS, got.Root, err = FromDir(dir, tempDir)
1149+ if err != nil {
1150+ t.Errorf("FromDir(%q, %q): %v", dir, tempDir, err)
1151+ continue
1152+ }
1153+ if got.VCS.Name != want.VCS.Name || got.Root != want.Root {
1154+ t.Errorf("FromDir(%q, %q) = VCS(%s) Root(%s), want VCS(%s) Root(%s)", dir, tempDir, got.VCS, got.Root, want.VCS, want.Root)
1155+ }
1156+ }
1157+}
1158+
1159+var parseMetaGoImportsTests = []struct {
1160+ in string
1161+ out []metaImport
1162+}{
1163+ {
1164+ `<meta name="go-import" content="foo/bar git https://github.com/rsc/foo/bar">`,
1165+ []metaImport{{"foo/bar", "git", "https://github.com/rsc/foo/bar"}},
1166+ },
1167+ {
1168+ `<meta name="go-import" content="foo/bar git https://github.com/rsc/foo/bar">
1169+ <meta name="go-import" content="baz/quux git http://github.com/rsc/baz/quux">`,
1170+ []metaImport{
1171+ {"foo/bar", "git", "https://github.com/rsc/foo/bar"},
1172+ {"baz/quux", "git", "http://github.com/rsc/baz/quux"},
1173+ },
1174+ },
1175+ {
1176+ `<meta name="go-import" content="foo/bar git https://github.com/rsc/foo/bar">
1177+ <meta name="go-import" content="foo/bar mod http://github.com/rsc/baz/quux">`,
1178+ []metaImport{
1179+ {"foo/bar", "git", "https://github.com/rsc/foo/bar"},
1180+ },
1181+ },
1182+ {
1183+ `<meta name="go-import" content="foo/bar mod http://github.com/rsc/baz/quux">
1184+ <meta name="go-import" content="foo/bar git https://github.com/rsc/foo/bar">`,
1185+ []metaImport{
1186+ {"foo/bar", "git", "https://github.com/rsc/foo/bar"},
1187+ },
1188+ },
1189+ {
1190+ `<head>
1191+ <meta name="go-import" content="foo/bar git https://github.com/rsc/foo/bar">
1192+ </head>`,
1193+ []metaImport{{"foo/bar", "git", "https://github.com/rsc/foo/bar"}},
1194+ },
1195+ {
1196+ `<meta name="go-import" content="foo/bar git https://github.com/rsc/foo/bar">
1197+ <body>`,
1198+ []metaImport{{"foo/bar", "git", "https://github.com/rsc/foo/bar"}},
1199+ },
1200+ {
1201+ `<!doctype html><meta name="go-import" content="foo/bar git https://github.com/rsc/foo/bar">`,
1202+ []metaImport{{"foo/bar", "git", "https://github.com/rsc/foo/bar"}},
1203+ },
1204+ {
1205+ // XML doesn't like <div style=position:relative>.
1206+ `<!doctype html><title>Page Not Found</title><meta name=go-import content="chitin.io/chitin git https://github.com/chitin-io/chitin"><div style=position:relative>DRAFT</div>`,
1207+ []metaImport{{"chitin.io/chitin", "git", "https://github.com/chitin-io/chitin"}},
1208+ },
1209+ {
1210+ `<meta name="go-import" content="myitcv.io git https://github.com/myitcv/x">
1211+ <meta name="go-import" content="myitcv.io/blah2 mod https://raw.githubusercontent.com/myitcv/pubx/master">
1212+ `,
1213+ []metaImport{{"myitcv.io", "git", "https://github.com/myitcv/x"}},
1214+ },
1215+}
1216+
1217+func TestParseMetaGoImports(t *testing.T) {
1218+ for i, tt := range parseMetaGoImportsTests {
1219+ out, err := parseMetaGoImports(strings.NewReader(tt.in))
1220+ if err != nil {
1221+ t.Errorf("test#%d: %v", i, err)
1222+ continue
1223+ }
1224+ if !reflect.DeepEqual(out, tt.out) {
1225+ t.Errorf("test#%d:\n\thave %q\n\twant %q", i, out, tt.out)
1226+ }
1227+ }
1228+}
1229+
1230+func TestValidateRepoRoot(t *testing.T) {
1231+ tests := []struct {
1232+ root string
1233+ ok bool
1234+ }{
1235+ {
1236+ root: "",
1237+ ok: false,
1238+ },
1239+ {
1240+ root: "http://",
1241+ ok: true,
1242+ },
1243+ {
1244+ root: "git+ssh://",
1245+ ok: true,
1246+ },
1247+ {
1248+ root: "http#://",
1249+ ok: false,
1250+ },
1251+ {
1252+ root: "-config",
1253+ ok: false,
1254+ },
1255+ {
1256+ root: "-config://",
1257+ ok: false,
1258+ },
1259+ }
1260+
1261+ for _, test := range tests {
1262+ err := validateRepoRoot(test.root)
1263+ ok := err == nil
1264+ if ok != test.ok {
1265+ want := "error"
1266+ if test.ok {
1267+ want = "nil"
1268+ }
1269+ t.Errorf("validateRepoRoot(%q) = %q, want %s", test.root, err, want)
1270+ }
1271+ }
1272+}
1273+
1274+func TestMatchGoImport(t *testing.T) {
1275+ tests := []struct {
1276+ imports []metaImport
1277+ path string
1278+ mi metaImport
1279+ err error
1280+ }{
1281+ {
1282+ imports: []metaImport{
1283+ {Prefix: "example.com/user/foo", VCS: "git", RepoRoot: "https://example.com/repo/target"},
1284+ },
1285+ path: "example.com/user/foo",
1286+ mi: metaImport{Prefix: "example.com/user/foo", VCS: "git", RepoRoot: "https://example.com/repo/target"},
1287+ },
1288+ {
1289+ imports: []metaImport{
1290+ {Prefix: "example.com/user/foo", VCS: "git", RepoRoot: "https://example.com/repo/target"},
1291+ },
1292+ path: "example.com/user/foo/",
1293+ mi: metaImport{Prefix: "example.com/user/foo", VCS: "git", RepoRoot: "https://example.com/repo/target"},
1294+ },
1295+ {
1296+ imports: []metaImport{
1297+ {Prefix: "example.com/user/foo", VCS: "git", RepoRoot: "https://example.com/repo/target"},
1298+ {Prefix: "example.com/user/fooa", VCS: "git", RepoRoot: "https://example.com/repo/target"},
1299+ },
1300+ path: "example.com/user/foo",
1301+ mi: metaImport{Prefix: "example.com/user/foo", VCS: "git", RepoRoot: "https://example.com/repo/target"},
1302+ },
1303+ {
1304+ imports: []metaImport{
1305+ {Prefix: "example.com/user/foo", VCS: "git", RepoRoot: "https://example.com/repo/target"},
1306+ {Prefix: "example.com/user/fooa", VCS: "git", RepoRoot: "https://example.com/repo/target"},
1307+ },
1308+ path: "example.com/user/fooa",
1309+ mi: metaImport{Prefix: "example.com/user/fooa", VCS: "git", RepoRoot: "https://example.com/repo/target"},
1310+ },
1311+ {
1312+ imports: []metaImport{
1313+ {Prefix: "example.com/user/foo", VCS: "git", RepoRoot: "https://example.com/repo/target"},
1314+ {Prefix: "example.com/user/foo/bar", VCS: "git", RepoRoot: "https://example.com/repo/target"},
1315+ },
1316+ path: "example.com/user/foo/bar",
1317+ err: errors.New("should not be allowed to create nested repo"),
1318+ },
1319+ {
1320+ imports: []metaImport{
1321+ {Prefix: "example.com/user/foo", VCS: "git", RepoRoot: "https://example.com/repo/target"},
1322+ {Prefix: "example.com/user/foo/bar", VCS: "git", RepoRoot: "https://example.com/repo/target"},
1323+ },
1324+ path: "example.com/user/foo/bar/baz",
1325+ err: errors.New("should not be allowed to create nested repo"),
1326+ },
1327+ {
1328+ imports: []metaImport{
1329+ {Prefix: "example.com/user/foo", VCS: "git", RepoRoot: "https://example.com/repo/target"},
1330+ {Prefix: "example.com/user/foo/bar", VCS: "git", RepoRoot: "https://example.com/repo/target"},
1331+ },
1332+ path: "example.com/user/foo/bar/baz/qux",
1333+ err: errors.New("should not be allowed to create nested repo"),
1334+ },
1335+ {
1336+ imports: []metaImport{
1337+ {Prefix: "example.com/user/foo", VCS: "git", RepoRoot: "https://example.com/repo/target"},
1338+ {Prefix: "example.com/user/foo/bar", VCS: "git", RepoRoot: "https://example.com/repo/target"},
1339+ },
1340+ path: "example.com/user/foo/bar/baz/",
1341+ err: errors.New("should not be allowed to create nested repo"),
1342+ },
1343+ {
1344+ imports: []metaImport{
1345+ {Prefix: "example.com/user/foo", VCS: "git", RepoRoot: "https://example.com/repo/target"},
1346+ {Prefix: "example.com/user/foo/bar", VCS: "git", RepoRoot: "https://example.com/repo/target"},
1347+ },
1348+ path: "example.com",
1349+ err: errors.New("pathologically short path"),
1350+ },
1351+ }
1352+
1353+ for _, test := range tests {
1354+ mi, err := matchGoImport(test.imports, test.path)
1355+ if mi != test.mi {
1356+ t.Errorf("unexpected metaImport; got %v, want %v", mi, test.mi)
1357+ }
1358+
1359+ got := err
1360+ want := test.err
1361+ if (got == nil) != (want == nil) {
1362+ t.Errorf("unexpected error; got %v, want %v", got, want)
1363+ }
1364+ }
1365+}
1366diff --git a/debian/patches/01-Update-the-import-path-of-golang-github-google-go-github.patch b/debian/patches/01-Update-the-import-path-of-golang-github-google-go-github.patch
1367deleted file mode 100644
1368index 8d3467b..0000000
1369--- a/debian/patches/01-Update-the-import-path-of-golang-github-google-go-github.patch
1370+++ /dev/null
1371@@ -1,34 +0,0 @@
1372-From: Roger Shimizu <rosh@debian.org>
1373-Date: Fri, 17 Jul 2020 22:55:35 +0900
1374-Subject: Update the import path of golang-github-google-go-github
1375-
1376----
1377- main.go | 2 +-
1378- 1 file changed, 1 insertion(+), 1 deletion(-)
1379-
1380-Index: dh-make-golang/main.go
1381-===================================================================
1382---- dh-make-golang.orig/main.go 2022-11-18 12:45:52.035957432 +0100
1383-+++ dh-make-golang/main.go 2022-11-18 12:45:52.035957432 +0100
1384-@@ -4,7 +4,7 @@
1385- "fmt"
1386- "os"
1387-
1388-- "github.com/google/go-github/v38/github"
1389-+ "github.com/google/go-github/github"
1390- "github.com/gregjones/httpcache"
1391- )
1392-
1393-Index: dh-make-golang/go.mod
1394-===================================================================
1395---- dh-make-golang.orig/go.mod 2022-11-18 12:43:54.600226791 +0100
1396-+++ dh-make-golang/go.mod 2022-11-18 12:46:09.780533980 +0100
1397-@@ -4,7 +4,7 @@
1398-
1399- require (
1400- github.com/charmbracelet/glamour v0.3.0
1401-- github.com/google/go-github/v38 v38.1.0
1402-+ github.com/google/go-github v38.1.0
1403- github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79
1404- github.com/mattn/go-isatty v0.0.12
1405- golang.org/x/mod v0.5.1 // indirect
1406diff --git a/debian/patches/series b/debian/patches/series
1407deleted file mode 100644
1408index c2ce9b0..0000000
1409--- a/debian/patches/series
1410+++ /dev/null
1411@@ -1 +0,0 @@
1412-01-Update-the-import-path-of-golang-github-google-go-github.patch
1413diff --git a/debian/rules b/debian/rules
1414index 71be22f..c93b44f 100755
1415--- a/debian/rules
1416+++ b/debian/rules
1417@@ -1,10 +1,19 @@
1418 #!/usr/bin/make -f
1419
1420+export DEB_BUILD_MAINT_OPTIONS = optimize=-lto
1421 export DH_GOLANG_INSTALL_EXTRA := description.json
1422
1423 %:
1424 dh $@ --builddirectory=_build --buildsystem=golang --with=golang
1425
1426+execute_after_dh_auto_configure:
1427+ # golang.org/x/tools/go/vcs v0.1.0-deprecated
1428+ ln -s $(CURDIR)/debian/go/src \
1429+ _build/src/github.com/Debian/dh-make-golang/vendor
1430+ # github.com/google/go-github/github (with Go modules disabled)
1431+ sed -i -e 's#go-github/v[0-9]\+/github#go-github/github#' \
1432+ _build/src/github.com/Debian/dh-make-golang/main.go
1433+
1434 override_dh_auto_install:
1435 dh_auto_install -- --no-source
1436

Subscribers

People subscribed via source and target branches