-
-
Notifications
You must be signed in to change notification settings - Fork 3.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Checking for updates #31
Changes from all commits
1e70e7e
4126585
6069ddb
eb2a179
f41d895
0560199
cd1826f
4671230
3b10dbd
9b45b52
1d96fda
2ad0d4f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,6 @@ | ||
# ipfs can generate profiling dump files | ||
cpu.prof | ||
|
||
*.swp | ||
.ipfsconfig | ||
*.out | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -13,6 +13,7 @@ import ( | |
config "github.com/jbenet/go-ipfs/config" | ||
core "github.com/jbenet/go-ipfs/core" | ||
daemon "github.com/jbenet/go-ipfs/daemon" | ||
updates "github.com/jbenet/go-ipfs/updates" | ||
u "github.com/jbenet/go-ipfs/util" | ||
) | ||
|
||
|
@@ -24,6 +25,7 @@ var CmdIpfs = &commander.Command{ | |
|
||
Basic commands: | ||
|
||
init Initialize ipfs local configuration. | ||
add <path> Add an object to ipfs. | ||
cat <ref> Show ipfs object data. | ||
ls <ref> List links from an object. | ||
|
@@ -67,7 +69,8 @@ var log = u.Logger("cmd/ipfs") | |
func init() { | ||
config, err := config.PathRoot() | ||
if err != nil { | ||
config = "" | ||
u.POut("Failure initializing the default Config Directory: ", err) | ||
os.Exit(1) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @dborzov this should probably not fail if the |
||
} | ||
CmdIpfs.Flag.String("c", config, "specify config directory") | ||
} | ||
|
@@ -117,6 +120,19 @@ func localNode(confdir string, online bool) (*core.IpfsNode, error) { | |
return nil, err | ||
} | ||
|
||
if cfg.Version.EligibleForUpdateCheck() { | ||
obsolete := updates.CheckForUpdates() | ||
if obsolete != nil { | ||
if cfg.Version.Check == config.CheckError { | ||
return nil, obsolete | ||
} | ||
log.Warning(fmt.Sprintf("%v", obsolete)) // when "warn" version.check mode we just show warning message | ||
} else { | ||
// update most recent check timestamp in config | ||
cfg.RecordCurrentUpdateCheck(filename) | ||
} | ||
} | ||
|
||
return core.NewIpfsNode(cfg, online) | ||
} | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
package config | ||
|
||
import "time" | ||
|
||
// Version regulates checking if the most recent version is run | ||
type Version struct { | ||
Check string // "ignore" for do not check, "warn" and "error" for reacting when obsolete | ||
Current string // ipfs version for which config was generated | ||
UpdateCheckedTime time.Time // timestamp for the last time API endpoint was checked for updates | ||
UpdateCheckPeriod time.Duration // time duration over which the update check will not be performed | ||
} | ||
|
||
// supported Version.Check values | ||
const ( | ||
CheckError = "error" // value for Version.Check to raise error and exit if version is obsolete | ||
CheckWarn = "warn" // value for Version.Check to show warning message if version is obsolete | ||
CheckIgnore = "ignore" // value for Version.Check to not perform update check | ||
) | ||
|
||
var defaultUpdateCheckPeriod = time.Hour * 48 | ||
|
||
// EligibleForUpdateCheck returns if update check API endpoint is needed for this specific runtime | ||
func (v *Version) EligibleForUpdateCheck() bool { | ||
if v.Check == CheckIgnore || v.UpdateCheckedTime.Add(v.UpdateCheckPeriod).After(time.Now()) { | ||
return false | ||
} | ||
return true | ||
} | ||
|
||
// RecordCurrentUpdateCheck is called to record that update check was performed and showed that the running version is the most recent one | ||
func (cfg *Config) RecordCurrentUpdateCheck(filename string) { | ||
cfg.Version.UpdateCheckedTime = time.Now() | ||
if cfg.Version.UpdateCheckPeriod == time.Duration(0) { | ||
// UpdateCheckPeriod was not initialized for some reason (e.g. config file used is broken) | ||
cfg.Version.UpdateCheckPeriod = defaultUpdateCheckPeriod | ||
} | ||
|
||
WriteConfigFile(filename, cfg) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
package updates | ||
|
||
import ( | ||
"encoding/json" | ||
"fmt" | ||
"net/http" | ||
"os" | ||
|
||
"github.com/coreos/go-semver/semver" | ||
u "github.com/jbenet/go-ipfs/util" | ||
) | ||
|
||
const ( | ||
Version = "0.1.0" // actual current application's version literal | ||
EndpointURLLatestReleases = "https://api.github.com/repos/jbenet/go-ipfs/tags" | ||
VersionErrorShort = `Warning: You are running version %s of go-ipfs. The latest version is %s.` | ||
VersionErrorLong = ` | ||
Warning: You are running version %s of go-ipfs. The latest version is %s. | ||
Since this is alpha software, it is strongly recommended you update. | ||
|
||
You can update go-ipfs by running | ||
|
||
ipfs version update | ||
|
||
You can silence this message by running | ||
|
||
ipfs config update.check ignore | ||
|
||
` | ||
) | ||
|
||
var log = u.Logger("updates") | ||
|
||
var currentVersion *semver.Version | ||
|
||
func init() { | ||
var err error | ||
currentVersion, err = semver.NewVersion(Version) | ||
if err != nil { | ||
u.PErr("The const Version literal in version.go needs to be in semver format: %s \n", Version) | ||
os.Exit(1) | ||
} | ||
} | ||
|
||
func CheckForUpdates() error { | ||
resp, err := http.Get(EndpointURLLatestReleases) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. to speedup commands for users, we could limit update checks to once per day (store the last time checked in the config or something). Otherwise ipfs will feel slow, having to wait for a full HTTP RTT There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. func CheckForUpdates() error {
if !shouldCheck() {
return nil
}
...
storeUpdateCheckTime()
return nil
} Or something There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. CheckForUpdates() is config ambguous at the moment. I added these flags to There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 yep, hadn't seen those yet, thanks! |
||
if err != nil { | ||
// can't reach the endpoint, coud be firewall, or no internet connection or something else | ||
log.Error("update check: error connecting to API endpoint for newer versions: %v", err) | ||
return nil | ||
} | ||
var body interface{} | ||
_ = json.NewDecoder(resp.Body).Decode(&body) | ||
releases, ok := body.([]interface{}) | ||
if !ok { | ||
// the response body does not seem to meet specified Github API format | ||
// https://developer.github.com/v3/repos/#list-tags | ||
log.Error("update check: API endpoint for newer versions does not seem to be in Github API specified format") | ||
return nil | ||
} | ||
for _, r := range releases { | ||
release, ok := r.(map[string]interface{}) | ||
if !ok { | ||
continue | ||
} | ||
tagName, ok := release["name"].(string) | ||
if !ok { | ||
continue | ||
} | ||
if len(tagName) > 0 && tagName[0] == 'v' { | ||
// both 'v0.1.0' and '0.1.0' semver tagname conventions can be encountered | ||
tagName = tagName[1:] | ||
} | ||
releaseVersion, err := semver.NewVersion(tagName) | ||
if err != nil { | ||
continue | ||
} | ||
if currentVersion.LessThan(*releaseVersion) { | ||
return fmt.Errorf(VersionErrorLong, Version, tagName) | ||
} | ||
} | ||
return nil | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe these values (
"error"
,"ignore"
, etc) should be constants in the update package: