diff --git a/main.go b/main.go index 5101c9ab..a6a08c7f 100644 --- a/main.go +++ b/main.go @@ -4,10 +4,10 @@ import ( "fmt" "io/ioutil" "os" - "os/user" "sort" "github.com/dnote-io/cli/upgrade" + "github.com/dnote-io/cli/utils" "gopkg.in/yaml.v2" ) @@ -18,72 +18,39 @@ type Config struct { type Note map[string][]string -const configFilename = ".dnoterc" -const dnoteFilename = ".dnote" - -func getConfigPath() (string, error) { - usr, err := user.Current() - if err != nil { - return "", err - } - - return fmt.Sprintf("%s/%s", usr.HomeDir, configFilename), nil -} - -func getDnotePath() (string, error) { - usr, err := user.Current() - if err != nil { - return "", err - } - - return fmt.Sprintf("%s/%s", usr.HomeDir, dnoteFilename), nil -} - -func generateConfigFile() error { - content := []byte("book: general\n") - configPath, err := getConfigPath() - if err != nil { - return err - } - - err = ioutil.WriteFile(configPath, content, 0644) - return err -} - -func touchDnoteFile() error { - dnotePath, err := getDnotePath() - if err != nil { - return err - } - - err = ioutil.WriteFile(dnotePath, []byte{}, 0644) - return err -} - // initDnote creates a config file if one does not exist func initDnote() error { - configPath, err := getConfigPath() + configPath, err := utils.GetConfigPath() if err != nil { return err } - dnotePath, err := getDnotePath() + dnotePath, err := utils.GetDnotePath() + if err != nil { + return err + } + dnoteUpdatePath, err := utils.GetDnoteUpdatePath() if err != nil { return err } if !checkFileExists(configPath) { - err := generateConfigFile() + err := utils.GenerateConfigFile() if err != nil { return err } } if !checkFileExists(dnotePath) { - err := touchDnoteFile() + err := utils.TouchDnoteFile() + if err != nil { + return err + } + } + if !checkFileExists(dnoteUpdatePath) { + err := utils.TouchDnoteUpgradeFile() if err != nil { return err } } - return nil } @@ -96,7 +63,7 @@ func check(e error) { func readConfig() (Config, error) { var ret Config - configPath, err := getConfigPath() + configPath, err := utils.GetConfigPath() if err != nil { return ret, err } @@ -129,7 +96,7 @@ func writeConfig(config Config) error { return err } - configPath, err := getConfigPath() + configPath, err := utils.GetConfigPath() if err != nil { return err } @@ -162,7 +129,7 @@ func changeBook(bookName string) error { func readNote() (Note, error) { ret := Note{} - notePath, err := getDnotePath() + notePath, err := utils.GetDnotePath() if err != nil { return ret, err } @@ -202,7 +169,7 @@ func writeNote(content string) error { return err } - notePath, err := getDnotePath() + notePath, err := utils.GetDnotePath() if err != nil { return err } @@ -241,7 +208,7 @@ func main() { check(err) err = upgrade.AutoUpdate() if err != nil { - fmt.Println("Warning: Failed to check for update", err) + fmt.Println("Warning - Failed to check for update:", err) } if len(os.Args) < 2 { diff --git a/upgrade/upgrade.go b/upgrade/upgrade.go index ae6c9701..9e6c93ef 100644 --- a/upgrade/upgrade.go +++ b/upgrade/upgrade.go @@ -1,9 +1,8 @@ package upgrade import ( - "bytes" "context" - "encoding/binary" + "errors" "fmt" "io" "io/ioutil" @@ -12,15 +11,26 @@ import ( "os/exec" "os/user" "path" + "regexp" "runtime" + "strconv" "time" + "github.com/dnote-io/cli/utils" "github.com/google/go-github/github" ) -const dnoteUpdateFilename = ".dnote-update" const version = "0.0.3" +func GetDnoteUpdatePath() (string, error) { + usr, err := user.Current() + if err != nil { + return "", err + } + + return fmt.Sprintf("%s/%s", usr.HomeDir, utils.DnoteUpdateFilename), nil +} + // getAsset finds the asset to download from the liast of assets in a release func getAsset(release *github.RepositoryRelease) *github.ReleaseAsset { filename := fmt.Sprintf("dnote-%s-%s", runtime.GOOS, runtime.GOARCH) @@ -33,37 +43,46 @@ func getAsset(release *github.RepositoryRelease) *github.ReleaseAsset { return nil } -func getDnoteUpdatePath() (string, error) { - usr, err := user.Current() - if err != nil { - return "", err - } - return fmt.Sprintf("%s/%s", usr.HomeDir, dnoteUpdateFilename), nil -} - -// shouldCheckUpdate checks if update should be checked -func shouldCheckUpdate() (bool, error) { - updatePath, err := getDnoteUpdatePath() +// getLastUpdateEpoch reads and parses the last update epoch +func getLastUpdateEpoch() (int64, error) { + updatePath, err := utils.GetDnoteUpdatePath() if err != nil { - return false, err + return 0, err } b, err := ioutil.ReadFile(updatePath) if err != nil { - return false, err + return 0, err } - buf := bytes.NewBuffer(b) - lastEpoch, err := binary.ReadVarint(buf) + re := regexp.MustCompile(`LAST_UPDATE_EPOCH: (\d+)\n`) + match := re.FindStringSubmatch(string(b)) + + if len(match) != 2 { + msg := fmt.Sprintf("Error parsing %s", utils.DnoteUpdateFilename) + return 0, errors.New(msg) + } + + lastEpoch, err := strconv.ParseInt(match[1], 10, 64) + if err != nil { + return 0, err + } + + return lastEpoch, nil +} + +// shouldCheckUpdate checks if update should be checked +func shouldCheckUpdate() (bool, error) { + var updatePeriod int64 = 86400 * 7 + + now := time.Now().Unix() + lastEpoch, err := getLastUpdateEpoch() if err != nil { return false, err } - now := time.Now().Unix() - var epochTarget int64 = 86400 * 7 // 7 days - - return now-lastEpoch > epochTarget, nil + return now-lastEpoch > updatePeriod, nil } // AutoUpdate triggers update if needed @@ -74,13 +93,15 @@ func AutoUpdate() error { } if shouldCheck { - Update() + tryUpgrade() } return nil } -func Update() error { +func tryUpgrade() error { + defer utils.TouchDnoteUpgradeFile() + // Fetch the latest version gh := github.NewClient(nil) releases, _, err := gh.Repositories.ListReleases(context.Background(), "dnote-io", "cli", nil) @@ -139,6 +160,6 @@ func Update() error { } fmt.Printf("Updated: v%s -> v%s", version, latestVersion) - fmt.Println("Change note: https://github.com/dnote-io/cli/releases") + fmt.Println("Changelog: https://github.com/dnote-io/cli/releases") return nil } diff --git a/utils/utils.go b/utils/utils.go new file mode 100644 index 00000000..aa3fc293 --- /dev/null +++ b/utils/utils.go @@ -0,0 +1,75 @@ +package utils + +import ( + "fmt" + "io/ioutil" + "os/user" + "strconv" + "time" +) + +const configFilename = ".dnoterc" +const DnoteUpdateFilename = ".dnote-update" +const dnoteFilename = ".dnote" + +func GetConfigPath() (string, error) { + usr, err := user.Current() + if err != nil { + return "", err + } + + return fmt.Sprintf("%s/%s", usr.HomeDir, configFilename), nil +} + +func GetDnotePath() (string, error) { + usr, err := user.Current() + if err != nil { + return "", err + } + + return fmt.Sprintf("%s/%s", usr.HomeDir, dnoteFilename), nil +} + +func GenerateConfigFile() error { + content := []byte("book: general\n") + configPath, err := GetConfigPath() + if err != nil { + return err + } + + err = ioutil.WriteFile(configPath, content, 0644) + return err +} + +func TouchDnoteFile() error { + dnotePath, err := GetDnotePath() + if err != nil { + return err + } + + err = ioutil.WriteFile(dnotePath, []byte{}, 0644) + return err +} + +func TouchDnoteUpgradeFile() error { + fmt.Println("toching dnoteupdate") + dnoteUpdatePath, err := GetDnoteUpdatePath() + if err != nil { + return err + } + + epoch := strconv.FormatInt(time.Now().Unix(), 10) + content := []byte(fmt.Sprintf("LAST_UPGRADE_EPOCH: %s\n", epoch)) + + err = ioutil.WriteFile(dnoteUpdatePath, content, 0644) + return err +} + +func GetDnoteUpdatePath() (string, error) { + usr, err := user.Current() + if err != nil { + return "", err + } + + return fmt.Sprintf("%s/%s", usr.HomeDir, DnoteUpdateFilename), nil +}