First I want to say that your code is very well written and idiomatic for someone who is new to Go.
Here are a few suggestions:
- Prefer standard library tools for error handling rather than using an external library.
errors.Wrapf
can be replaced byfmt.Errorf
. - Call
file.Close
with defer, so that if writing to the file fails it will still get closed. The documentation forfile.Close
specifies that it will only return an error if the file is already closed, so you could consider just ignoring any error fromfile.Close
. - This is kind of subjective, but I think
downFile
should return the file name instead of an*os.File
because the file is already closed, so any attempt to read or write it would fail. SaveAsFile
has a lot of string arguments, and some of them are optional. If a caller callsSaveAsFile(url, digest, "", "")
, it's not obvious that the empty strings are the username and password.
What you can use for this last point is the option pattern, I would define SaveAsFile
as follows:
type opts struct {
user string
pass string
}
type SaveAsFileOption func(*opts)
func Auth(user, pass string) SaveAsFileOption {
return func(o *opts) {
o.user = user
o.pass = pass
}
}
func SaveAsFile(url, digest string, options SaveAsFileOption...) {
var o opts
for opt in options {
opt(&o)
}
// Then you can access user and pass through o.user and o.pass.
}
Callers can call SaveAsFile
either with SaveAsFile(url, digest)
, or with SaveAsFile(url, digest, Auth(user, pass))
. This also gives you the flexibility to define more options in the future.