|
|
@ -7,11 +7,8 @@ |
|
|
|
package main |
|
|
|
package main |
|
|
|
|
|
|
|
|
|
|
|
import ( |
|
|
|
import ( |
|
|
|
"flag" |
|
|
|
|
|
|
|
"fmt" |
|
|
|
"fmt" |
|
|
|
"go/build" |
|
|
|
|
|
|
|
"io" |
|
|
|
"io" |
|
|
|
"log" |
|
|
|
|
|
|
|
"os" |
|
|
|
"os" |
|
|
|
"os/exec" |
|
|
|
"os/exec" |
|
|
|
"path/filepath" |
|
|
|
"path/filepath" |
|
|
@ -26,8 +23,9 @@ import ( |
|
|
|
) |
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
var ( |
|
|
|
var ( |
|
|
|
config tomlConfig |
|
|
|
config tomlConfig |
|
|
|
appPath string // Application path.
|
|
|
|
appPath string // Application path.
|
|
|
|
|
|
|
|
isWindows bool // Indicates if current system is windows.
|
|
|
|
) |
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
type tomlConfig struct { |
|
|
|
type tomlConfig struct { |
|
|
@ -85,26 +83,34 @@ var commands = []*Command{ |
|
|
|
cmdInstall, |
|
|
|
cmdInstall, |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
var exitStatus = 0 |
|
|
|
// getAppPath returns application execute path for current process.
|
|
|
|
var exitMu sync.Mutex |
|
|
|
func getAppPath() bool { |
|
|
|
|
|
|
|
// Look up executable in PATH variable.
|
|
|
|
|
|
|
|
appPath, _ = exec.LookPath("gpm") |
|
|
|
|
|
|
|
if len(appPath) == 0 { |
|
|
|
|
|
|
|
fmt.Printf("getAppPath(): Unable to indicate current execute path.") |
|
|
|
|
|
|
|
return false |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
func setExitStatus(n int) { |
|
|
|
if runtime.GOOS == "windows" { |
|
|
|
exitMu.Lock() |
|
|
|
isWindows = true |
|
|
|
if exitStatus < n { |
|
|
|
// Replace all '\' to '/'.
|
|
|
|
exitStatus = n |
|
|
|
appPath = strings.Replace(filepath.Dir(appPath), "\\", "/", -1) + "/" |
|
|
|
} |
|
|
|
} |
|
|
|
exitMu.Unlock() |
|
|
|
return true |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// loadUsage loads usage according to user language.
|
|
|
|
func loadUsage(lang, appPath string) bool { |
|
|
|
func loadUsage(lang, appPath string) bool { |
|
|
|
// Load main usage.
|
|
|
|
// Load main usage.
|
|
|
|
f, err := os.Open(appPath + "i18n/" + lang + "/usage.tpl") |
|
|
|
f, err := os.Open(appPath + "i18n/" + lang + "/usage.tpl") |
|
|
|
if err != nil { |
|
|
|
if err != nil { |
|
|
|
fmt.Println("Load usage:", err) |
|
|
|
fmt.Printf("loadUsage(): Fail to load main usage: %s.\n", err) |
|
|
|
return false |
|
|
|
return false |
|
|
|
} |
|
|
|
} |
|
|
|
defer f.Close() |
|
|
|
defer f.Close() |
|
|
|
// Read usage.
|
|
|
|
|
|
|
|
|
|
|
|
// Read command usages.
|
|
|
|
fi, _ := f.Stat() |
|
|
|
fi, _ := f.Stat() |
|
|
|
usageBytes := make([]byte, fi.Size()) |
|
|
|
usageBytes := make([]byte, fi.Size()) |
|
|
|
f.Read(usageBytes) |
|
|
|
f.Read(usageBytes) |
|
|
@ -114,7 +120,7 @@ func loadUsage(lang, appPath string) bool { |
|
|
|
for _, cmd := range commands { |
|
|
|
for _, cmd := range commands { |
|
|
|
f, err := os.Open(appPath + "i18n/" + lang + "/usage_" + cmd.Name() + ".txt") |
|
|
|
f, err := os.Open(appPath + "i18n/" + lang + "/usage_" + cmd.Name() + ".txt") |
|
|
|
if err != nil { |
|
|
|
if err != nil { |
|
|
|
fmt.Println("Load usage:", err) |
|
|
|
fmt.Printf("loadUsage(): Fail to load usage(%s): %s.\n", cmd.Name(), err) |
|
|
|
return false |
|
|
|
return false |
|
|
|
} |
|
|
|
} |
|
|
|
defer f.Close() |
|
|
|
defer f.Close() |
|
|
@ -124,7 +130,7 @@ func loadUsage(lang, appPath string) bool { |
|
|
|
f.Read(usageBytes) |
|
|
|
f.Read(usageBytes) |
|
|
|
usages := strings.Split(string(usageBytes), "|||") |
|
|
|
usages := strings.Split(string(usageBytes), "|||") |
|
|
|
if len(usages) < 2 { |
|
|
|
if len(usages) < 2 { |
|
|
|
fmt.Println("Unacceptable usage file: ", cmd.Name()) |
|
|
|
fmt.Printf("loadUsage(): nacceptable usage file: %s.\n", cmd.Name()) |
|
|
|
return false |
|
|
|
return false |
|
|
|
} |
|
|
|
} |
|
|
|
cmd.Short = usages[0] |
|
|
|
cmd.Short = usages[0] |
|
|
@ -135,9 +141,10 @@ func loadUsage(lang, appPath string) bool { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
func main() { |
|
|
|
func main() { |
|
|
|
// Get application path.
|
|
|
|
// Get application execute path.
|
|
|
|
appPath, _ := exec.LookPath("gpm") |
|
|
|
if !getAppPath() { |
|
|
|
appPath = strings.Replace(filepath.Dir(appPath), "\\", "/", -1) + "/" |
|
|
|
return |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Load configuration.
|
|
|
|
// Load configuration.
|
|
|
|
if _, err := toml.DecodeFile(appPath+"conf/gpm.toml", &config); err != nil { |
|
|
|
if _, err := toml.DecodeFile(appPath+"conf/gpm.toml", &config); err != nil { |
|
|
@ -145,47 +152,25 @@ func main() { |
|
|
|
return |
|
|
|
return |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Load usage template by language.
|
|
|
|
// Load usages by language.
|
|
|
|
if !loadUsage(config.Lang, appPath) { |
|
|
|
if !loadUsage(config.Lang, appPath) { |
|
|
|
return |
|
|
|
return |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Initialization.
|
|
|
|
// Check length of arguments.
|
|
|
|
flag.Usage = usage |
|
|
|
args := os.Args[1:] |
|
|
|
flag.Parse() |
|
|
|
|
|
|
|
log.SetFlags(0) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
args := flag.Args() |
|
|
|
|
|
|
|
if len(args) < 1 { |
|
|
|
if len(args) < 1 { |
|
|
|
usage() |
|
|
|
usage() |
|
|
|
|
|
|
|
return |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Show help documentation.
|
|
|
|
if args[0] == "help" { |
|
|
|
if args[0] == "help" { |
|
|
|
help(args[1:]) |
|
|
|
help(args[1:]) |
|
|
|
return |
|
|
|
return |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Diagnose common mistake: GOPATH==GOROOT.
|
|
|
|
// Check commands and run.
|
|
|
|
// This setting is equivalent to not setting GOPATH at all,
|
|
|
|
|
|
|
|
// which is not what most people want when they do it.
|
|
|
|
|
|
|
|
if gopath := os.Getenv("GOPATH"); gopath == runtime.GOROOT() { |
|
|
|
|
|
|
|
fmt.Fprintf(os.Stderr, "warning: GOPATH set to GOROOT (%s) has no effect\n", gopath) |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
for _, p := range filepath.SplitList(gopath) { |
|
|
|
|
|
|
|
// Note: using HasPrefix instead of Contains because a ~ can appear
|
|
|
|
|
|
|
|
// in the middle of directory elements, such as /tmp/git-1.8.2~rc3
|
|
|
|
|
|
|
|
// or C:\PROGRA~1. Only ~ as a path prefix has meaning to the shell.
|
|
|
|
|
|
|
|
if strings.HasPrefix(p, "~") { |
|
|
|
|
|
|
|
fmt.Fprintf(os.Stderr, "gpm: GOPATH entry cannot start with shell metacharacter '~': %q\n", p) |
|
|
|
|
|
|
|
os.Exit(2) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if build.IsLocalImport(p) { |
|
|
|
|
|
|
|
fmt.Fprintf(os.Stderr, "gpm: GOPATH entry is relative; must be absolute path: %q.\nRun 'gpm help gopath' for usage.\n", p) |
|
|
|
|
|
|
|
os.Exit(2) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for _, cmd := range commands { |
|
|
|
for _, cmd := range commands { |
|
|
|
if cmd.Name() == args[0] && cmd.Run != nil { |
|
|
|
if cmd.Name() == args[0] && cmd.Run != nil { |
|
|
|
cmd.Run(cmd, args[1:]) |
|
|
|
cmd.Run(cmd, args[1:]) |
|
|
@ -194,11 +179,23 @@ func main() { |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Uknown commands.
|
|
|
|
fmt.Fprintf(os.Stderr, "gpm: unknown subcommand %q\nRun 'gpm help' for usage.\n", args[0]) |
|
|
|
fmt.Fprintf(os.Stderr, "gpm: unknown subcommand %q\nRun 'gpm help' for usage.\n", args[0]) |
|
|
|
setExitStatus(2) |
|
|
|
setExitStatus(2) |
|
|
|
exit() |
|
|
|
exit() |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var exitStatus = 0 |
|
|
|
|
|
|
|
var exitMu sync.Mutex |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func setExitStatus(n int) { |
|
|
|
|
|
|
|
exitMu.Lock() |
|
|
|
|
|
|
|
if exitStatus < n { |
|
|
|
|
|
|
|
exitStatus = n |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
exitMu.Unlock() |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
var usageTemplate string |
|
|
|
var usageTemplate string |
|
|
|
var helpTemplate = `{{if .Runnable}}usage: gpm {{.UsageLine}} |
|
|
|
var helpTemplate = `{{if .Runnable}}usage: gpm {{.UsageLine}} |
|
|
|
|
|
|
|
|
|
|
|