github.com/Xenoex/gopm@v0.6.5/cmd/update.go (about) 1 // Copyright 2013 gopm authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"): you may 4 // not use this file except in compliance with the License. You may obtain 5 // a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 // License for the specific language governing permissions and limitations 13 // under the License. 14 15 package cmd 16 17 import ( 18 "encoding/json" 19 "fmt" 20 "net/http" 21 "os" 22 "os/exec" 23 "path" 24 "path/filepath" 25 "runtime" 26 27 "github.com/Unknwon/com" 28 "github.com/codegangsta/cli" 29 30 "github.com/gpmgo/gopm/doc" 31 "github.com/gpmgo/gopm/log" 32 ) 33 34 var CmdUpdate = cli.Command{ 35 Name: "update", 36 Usage: "check and update gopm resources including itself", 37 Description: `Command update checks updates of resources and gopm itself. 38 39 gopm update 40 41 Resources will be updated automatically after executed this command, 42 but you have to confirm before updaing gopm itself.`, 43 Action: runUpdate, 44 Flags: []cli.Flag{ 45 cli.BoolFlag{"verbose, v", "show process details"}, 46 }, 47 } 48 49 func exePath() string { 50 file, err := exec.LookPath(os.Args[0]) 51 if err != nil { 52 log.Error("Update", "Fail to execute exec.LookPath") 53 log.Fatal("", err.Error()) 54 } 55 path, err := filepath.Abs(file) 56 if err != nil { 57 log.Error("Update", "Fail to get absolutely path") 58 log.Fatal("", err.Error()) 59 } 60 return path 61 } 62 63 type version struct { 64 Gopm int 65 PackageNameList int `json:"package_name_list"` 66 } 67 68 func runUpdate(ctx *cli.Context) { 69 setup(ctx) 70 71 isAnythingUpdated := false 72 // Load local version info. 73 localVerInfo := loadLocalVerInfo() 74 75 // Get remote version info. 76 var remoteVerInfo version 77 if err := com.HttpGetJSON(http.DefaultClient, "http://gopm.io/VERSION.json", &remoteVerInfo); err != nil { 78 log.Error("Update", "Fail to fetch VERSION.json") 79 log.Fatal("", err.Error()) 80 } 81 82 // Package name list. 83 if remoteVerInfo.PackageNameList > localVerInfo.PackageNameList { 84 log.Log("Updating pkgname.list...%v > %v", 85 localVerInfo.PackageNameList, remoteVerInfo.PackageNameList) 86 data, err := com.HttpGetBytes(http.DefaultClient, "https://raw2.github.com/gpmgo/docs/master/pkgname.list", nil) 87 if err != nil { 88 log.Error("Update", "Fail to update pkgname.list") 89 log.Fatal("", err.Error()) 90 } 91 92 if err = com.WriteFile(path.Join(doc.HomeDir, doc.PKG_NAME_LIST_PATH), data); err != nil { 93 log.Error("Update", "Fail to save pkgname.list") 94 log.Fatal("", err.Error()) 95 } 96 log.Log("Update pkgname.list to %v succeed!", remoteVerInfo.PackageNameList) 97 isAnythingUpdated = true 98 } 99 100 // Gopm. 101 if remoteVerInfo.Gopm > localVerInfo.Gopm { 102 log.Log("Updating gopm...%v > %v", 103 localVerInfo.Gopm, remoteVerInfo.Gopm) 104 installRepoPath = doc.HomeDir + "/repos" 105 106 tmpDirPath := filepath.Join(doc.HomeDir, "temp") 107 tmpBinPath := filepath.Join(tmpDirPath, "gopm") 108 if runtime.GOOS == "windows" { 109 tmpBinPath += ".exe" 110 } 111 112 os.MkdirAll(tmpDirPath, os.ModePerm) 113 os.Remove(tmpBinPath) 114 115 // Fetch code. 116 args := []string{"bin", "-u", "-d"} 117 if ctx.Bool("verbose") { 118 args = append(args, "-v") 119 } 120 args = append(args, []string{"github.com/gpmgo/gopm", tmpDirPath}...) 121 stdout, stderr, err := com.ExecCmd("gopm", args...) 122 if err != nil { 123 log.Error("Update", "Fail to execute 'gopm bin -u -d github.com/gpmgo/gopm "+tmpDirPath+"'") 124 log.Fatal("", err.Error()) 125 } 126 if len(stderr) > 0 { 127 fmt.Print(stderr) 128 } 129 if len(stdout) > 0 { 130 fmt.Print(stdout) 131 } 132 133 // Check if previous steps were successful. 134 if !com.IsExist(tmpBinPath) { 135 log.Error("Update", "Fail to continue command") 136 log.Fatal("", "Previous steps weren't successful, no binary produced") 137 } 138 139 movePath := exePath() 140 log.Log("New binary will be replaced for %s", movePath) 141 // Move binary to given directory. 142 if runtime.GOOS != "windows" { 143 err := os.Rename(tmpBinPath, movePath) 144 if err != nil { 145 log.Error("Update", "Fail to move binary") 146 log.Fatal("", err.Error()) 147 } 148 os.Chmod(movePath+"/"+path.Base(tmpBinPath), os.ModePerm) 149 } else { 150 batPath := filepath.Join(tmpDirPath, "update.bat") 151 f, err := os.Create(batPath) 152 if err != nil { 153 log.Error("Update", "Fail to generate bat file") 154 log.Fatal("", err.Error()) 155 } 156 f.WriteString("@echo off\r\n") 157 f.WriteString(fmt.Sprintf("ping -n 1 127.0.0.1>nul\r\ncopy \"%v\" \"%v\" >nul\r\ndel \"%v\" >nul\r\n\r\n", 158 tmpBinPath, movePath, tmpBinPath)) 159 //f.WriteString(fmt.Sprintf("del \"%v\"\r\n", batPath)) 160 f.Close() 161 162 attr := &os.ProcAttr{ 163 Dir: workDir, 164 Env: os.Environ(), 165 Files: []*os.File{os.Stdin, os.Stdout, os.Stderr}, 166 } 167 168 _, err = os.StartProcess(batPath, []string{batPath}, attr) 169 if err != nil { 170 log.Error("Update", "Fail to start bat process") 171 log.Fatal("", err.Error()) 172 } 173 } 174 175 log.Success("SUCC", "Update", "Command execute successfully!") 176 isAnythingUpdated = true 177 } 178 179 // Save JSON. 180 f, err := os.Create(path.Join(doc.HomeDir, doc.VER_PATH)) 181 if err != nil { 182 log.Error("Update", "Fail to create VERSION.json") 183 log.Fatal("", err.Error()) 184 } 185 if err := json.NewEncoder(f).Encode(&remoteVerInfo); err != nil { 186 log.Error("Update", "Fail to encode VERSION.json") 187 log.Fatal("", err.Error()) 188 } 189 190 if !isAnythingUpdated { 191 log.Log("Nothing need to be updated") 192 } 193 log.Log("Exit old gopm") 194 } 195 196 func loadLocalVerInfo() (ver version) { 197 verPath := path.Join(doc.HomeDir, doc.VER_PATH) 198 199 // First time run should not exist. 200 if !com.IsExist(verPath) { 201 return ver 202 } 203 204 f, err := os.Open(verPath) 205 if err != nil { 206 log.Error("Update", "Fail to open VERSION.json") 207 log.Fatal("", err.Error()) 208 } 209 210 if err := json.NewDecoder(f).Decode(&ver); err != nil { 211 log.Error("Update", "Fail to decode VERSION.json") 212 log.Fatal("", err.Error()) 213 } 214 return ver 215 }