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  }