goforward: What is it? How do I use it?

215 views
Skip to first unread message

AJ ONeal

unread,
Jun 29, 2019, 12:14:43 AM6/29/19
to golang-nuts
I was looking at the Module page on the Wiki ( https://github.com/golang/go/wiki/Modules ) for instruction on how to handle breaking API changes (v2, v3, etc) and I noticed mention of the mythical `goforward`:

A more sophisticated approach here could exploit type aliases (introduced in Go 1.9) and forwarding shims between major versions residing in different subdirectories. This can provide additional compatibility and allow one major version to be implemented in terms of another major version, but would entail more work for a module author. An in-progress tool to automate this is goforward. Please see here for more details and rationale, along with a functioning initial version of goforward.

I also found multiple mentions of it (by the author, I assume) on the Golang issues on Github, claiming that it may solve various problems. And I think "that's cool, but... how do I get it?"

I went to the suggested link ( https://go-review.googlesource.com/c/tools/+/137076/ ), but there's no instruction on how to install, how to use it, and maybe even gives less digestible information than on the modules wiki.

The googlesource.com interface is perhaps the strangest I've ever seen for git / code. I'm guessing it must be some sort of internal Google tool that you kinda have to be a googler to understand.

Nevertheless, I see

Repo: tools 
Branch: master

and so I figure there must be a repo somewhere containing this code.

I click on the tools link which takes me to https://go-review.googlesource.com/q/project:tools ... very confusing.
I found the repo settings link which lead me to https://go-review.googlesource.com/admin/repos/tools where I finally see something familiar:

git clone "https://go.googlesource.com/tools"

 Now I have the repo cloned... but there's no mention of "goforward" and hardly any mention of "forward" at all (which is not the forward I'm looking for).

It appears that the latest commit was yesterday (June 27th, 2019), but I couldn't find the HEAD in the interface and I can't even checkout the parent commit (which is shown in the interface):

git checkout a44989a 
 
error: pathspec 'a44989a' did not match any file(s) known to git

Where is this thing and how can I try it out?

Ian Lance Taylor

unread,
Jun 29, 2019, 12:53:52 AM6/29/19
to AJ ONeal, golang-nuts
It's in https://golang.org/cl/137076. Not sure what it needs before
being submitted, other than a review.

Ian

t hepudds

unread,
Jun 29, 2019, 3:02:32 AM6/29/19
to golang-nuts
Hi AJ,

In terms of detailed write-ups on how gofoward works, to my knowledge the best place to start is reading the commit message and then the help message you get once you build goforward.

The author (Bryan Mills) has stated there is still some work to do to finish it up, including addressing some bugs, but people have used it successfully.  A sample recent PR generated by someone from the broader community using gofoward is here:

In terms of how you get it, when you go to https://go-review.googlesource.com/c/tools/+/137076/, you should see a 'Download' button on the right side. If you click on that, it gives you 4-5 options ranging from 'git fetch' to downloading a zip.

Here's a quick example (following one of the 'Download' options there):

  $ cd $(mktemp -d)
  $ git fetch "https://go.googlesource.com/tools" refs/changes/76/137076/9 && git checkout FETCH_HEAD
  $ cd cmd/goforward
  $ go build
  $ ./goforward help

    Usage: goforward [-n] [-move | -filter=REGEXP] [-replace] [-filename=NAME] SOURCE DEST
    ...

Hope that helps some,
thepudds

t hepudds

unread,
Jun 29, 2019, 3:07:30 AM6/29/19
to golang-nuts
Hi AJ,

To reduce the suspense, I probably should have included the full help message:

 $ ./gofoward help
 Usage: goforward [-n] [-move | -filter=REGEXP] [-replace] [-filename=NAME] SOURCE DEST

  -filename string
        destination file in which to write forwards (default "forward.go")
  -filter string
        forward only the top-level identifiers matching this regexp (default ".*")
  -move
        move the existing contents of SOURCE to DEST, leaving forwarding declarations at SOURCE
        (otherwise, write declarations at DEST forwarding to SOURCE)
  -n    print the locations and contents of files instead of writing them
  -replace
        replace conflicting declarations in the destination package
        (otherwise, do not forward conflicting declarations)

HTH,
thepudds

aon...@bigsquid.com

unread,
Jul 1, 2019, 7:41:55 PM7/1/19
to golang-nuts

In terms of how you get it, when you go to https://go-review.googlesource.com/c/tools/+/137076/, you should see a 'Download' button on the right side. If you click on that, it gives you 4-5 options ranging from 'git fetch' to downloading a zip.

I did not see that before. Odd that they put it over on the right by the message history rather than on the left by the code history.

Thanks for sharing the output of the help too.

I'm not confident that there is now more documentation in this thread in regards to go forward than there is anywhere else on the web.

:)

aon...@bigsquid.com

unread,
Jul 1, 2019, 10:15:57 PM7/1/19
to golang-nuts

I'm not confident that there is now more documentation in this thread in regards to go forward than there is anywhere else on the web.

I meant to say "I'm now confident that there is more ..."

What it does:

It reads an entire source package and outputs a single type alias file that describes the package.

The idea being that you may have few major breaking changes that need a new function definition or a new type, but the majority of code could stay the same between your v1 and v2, and it may be possible to fix many bugs or add many features to both v1 and v2 simultaneously this way.

How to use it:


  cat go.mod
module github.com/example/go-foo


What the result looks like:

  ls barpkg/v2/
forward.go
 
  cat forward.go
// generated by goforward github.com/example/go-foo/barpkg github.com/example/go-foo/barpkg/v2
package adapter
import (
"time"
"github.com/example/go-foo/barpkg"
 
// Sprockets by spacely are the best
var Sprocket = barpkg.Sprocket 
 
// Widget does some such or other
type Widget = barpkg.Widget  

// New returns a Widget that's guaranteed to break by exp 
func New(exp time.Time) *Widget {
return &barkpkg.New(exp)
Reply all
Reply to author
Forward
0 new messages