mouuff/go-rocket-update

Suggestion: allow basic templating in `ArchiveName` & `ExecutableName`

axllent opened this issue · 6 comments

Certain projects use the release tag in the archive name, eg awesome-package_0.1.2_linux_amd64.tar.gz, and I seem to recall some that even use it in the binary name too (not that I think the latter is a good idea).

My suggestion is to allow some basic go templating on both the Provider ArchiveName and Updater .ExecutableName of at least some common variables, such as {{.Tag}} {{.GOOS}}&{{.GOARCH}}. Whilst certain variables can be generated before the request (runtime.GOOS&runtime.GOARCH`), others are dependent on the remote info.

u := &updater.Updater{
    Provider: &provider.Github{
        RepositoryURL: "github.com/user/awesome-package",
        ArchiveName:   `awesome-package_{{.Tag}}_{{.GOOS}}_{{.GOARCH}}`,
    },
    ExecutableName: "awesome-package_{{.Tag}}",
    Version:        "0.1.1",
}

This would of course still remain completely backwards compatible with the current system, and one could even mix the two: ArchiveName: fmt.Sprintf("awesome-package_{{.Tag}}_%s_%s.tar.gz", runtime.GOOS, runtime.GOARCH).

The backstory is I've been meaning to rewrite a simple GitHub binary updater I wrote some time ago (far more primitive than yours), although I have been putting it off while I collect ideas etc. I just came across go-rocket-update which I think has a lot of potential, so rather than me spend time rewriting mine from scratch, I'd first check to see if you were open to suggestions to yours instead? I also have some other suggestions too if you're open to it.

Thank you for the suggestion! Yes I think it could be a good idea!
Today what you can do is call the provider by yourself to get the version (and then the updater) but I agree that variables would make things a lot easier :)

Implementation:

I think we should add the whole templating logic outside the updater.
The updater would just use an interface to get the variables.
We would have a default implementation for the basic {{.Tag}} {{.GOOS}} {{.GOARCH}} variables, and if a dev wants to add his own variables then he could make his own implementation of that interface.

I hadn't considered running it twice as an interim workaround, although I haven't implemented go-rocket-update yet in anything as I'm still in the testing phase, and seeing where this project is headed. I think that your implementation proposal makes good sense though, and hopefully doesn't add too much bulk or complication.

Not exactly running it twice, just running the provider to get the latest version, then setup the updater with this information.
But indeed GetLatestVersion will be called a second time by the updater.
I m not afraid of the bulk/complications. It's just another interface.
But fell free to make a PR with your own implementation :)

Here is a workaround for now.
Example with ticker:

func selfUpdate() (updater.UpdateStatus, error) {
	provider := &provider.Github{
		RepositoryURL: "github.com/achannarasappa/ticker",
	}
	latestVersion, err := provider.GetLatestVersion()
	if err != nil {
		return updater.Unknown, err
	}
	if len(latestVersion) > 0 {
		latestVersion = latestVersion[1:] // removes the 'v' prefix to match github archive
	}
	provider.ArchiveName = fmt.Sprintf("ticker-%s-%s-%s.tar.gz", latestVersion, runtime.GOOS, runtime.GOARCH)
	u := &updater.Updater{
		Provider:       provider,
		ExecutableName: "ticker",
		Version:        c.Version,
	}
	return u.Update()
}

I think I will try to find some time this or next month to implement that. except if you fell like making a PR :)
I think it could be a great addition!

It's unlikely I'll be able to spend much time on this in the next two months as well, as I just returned to work last week after a shoulder operation two months ago (long recovery, and now a huge backlog of work to catch up on). This was actually the main reason I was looking for existing self updater modules last week, as I just don't have the time to reinvent the wheel right now again :-) I'm also not in any rush either. If I do manage to spend some time on it I'll let you know though!