Browse Source

strings add i18n support

pull/103/head
Unknown 12 years ago
parent
commit
4ee4552d17
  1. 2
      README.md
  2. 8
      build.go
  3. 2
      conf/gpm.toml
  4. 1
      doc/error.go
  5. 68
      gpm.go
  6. 28
      i18n/en-US/prompt.txt
  7. 48
      install.go
  8. 185
      models/models.go

2
README.md

@ -12,8 +12,6 @@ gpm(Go Package Manager) is a Go package manage tool for search, install, update
## Todo
- All errors should have specific title for exactly where were created.
- Add i18n support for all strings.
- Command `build` add current path to GOPATH temporary.
- Add gpm working principle design.
- Add support for downloading tarballs from user sources.

8
build.go

@ -44,17 +44,17 @@ func runBuild(cmd *Command, args []string) {
if utils.IsExist(wd + "/" + proName) {
err := os.Remove(wd + "/" + proName)
if err != nil {
fmt.Printf("Fail to remove file in current directory: %s.\n", err)
fmt.Printf(fmt.Sprintf("ERROR: %s\n", promptMsg["RemoveFile"]), err)
return
}
}
err := os.Rename(v+"/bin/"+proName, wd+"/"+proName)
if err == nil {
fmt.Printf("Moved file from $GOPATH(%s) to current directory(%s).\n", v, wd)
fmt.Printf(fmt.Sprintf("%s\n", promptMsg["MovedFile"]), v, wd)
return
} else {
fmt.Printf("Fail to move file from $GOPATH(%s) to current directory: %s.\n", v, err)
}
fmt.Printf(fmt.Sprintf("%s\n", promptMsg["MoveFile"]), v, wd)
break
}
}

2
conf/gpm.toml

@ -1,7 +1,7 @@
# This is a configuration file for gpm with toml format.
title = "gpm(Go Package Manager)"
version = "v0.1.2 Build 0522"
version = "v0.1.3 Build 0522"
username = ""
password = ""
user_language = "en-US"

1
doc/error.go

@ -10,7 +10,6 @@ import (
var (
errNotModified = errors.New("package not modified")
ErrNoMatch = errors.New("no match")
errUpdateTimeout = errors.New("update timeout")
)

68
gpm.go

@ -26,12 +26,18 @@ import (
)
var (
config tomlConfig
appPath string // Application path.
config tomlConfig
appPath string // Application path.
)
var (
localNodes []*doc.Node
localBundles []*doc.Bundle
)
// Use for i18n, key is prompt code, value is corresponding message.
var promptMsg map[string]string
type tomlConfig struct {
Title, Version string
Username, Password string
@ -93,7 +99,7 @@ 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.")
fmt.Printf("ERROR: getAppPath -> Unable to indicate current execute path.\n")
return false
}
@ -104,17 +110,47 @@ func getAppPath() bool {
return true
}
// loadPromptMsg loads prompt messages according to user language.
func loadPromptMsg(lang string) bool {
promptMsg = make(map[string]string)
// Load prompt messages.
f, err := os.Open(appPath + "i18n/" + lang + "/prompt.txt")
if err != nil {
fmt.Printf("ERROR: loadUsage -> Fail to load prompt messages[ %s ]\n", err)
return false
}
defer f.Close()
// Read prompt messages.
fi, _ := f.Stat()
promptBytes := make([]byte, fi.Size())
f.Read(promptBytes)
promptStrs := strings.Split(string(promptBytes), "\n")
for _, p := range promptStrs {
i := strings.Index(p, "=")
if i > -1 {
promptMsg[p[:i]] = p[i+1:]
}
}
return true
}
// loadUsage loads usage according to user language.
func loadUsage(lang string) bool {
if !loadPromptMsg(lang) {
return false
}
// Load main usage.
f, err := os.Open(appPath + "i18n/" + lang + "/usage.tpl")
if err != nil {
fmt.Printf("loadUsage(): Fail to load main usage: %s.\n", err)
fmt.Printf(fmt.Sprintf("ERROR: loadUsage -> %s\n", promptMsg["LoadCommandUsage"]), "main", err)
return false
}
defer f.Close()
// Read command usages.
// Read main usages.
fi, _ := f.Stat()
usageBytes := make([]byte, fi.Size())
f.Read(usageBytes)
@ -124,17 +160,19 @@ func loadUsage(lang string) bool {
for _, cmd := range commands {
f, err := os.Open(appPath + "i18n/" + lang + "/usage_" + cmd.Name() + ".txt")
if err != nil {
fmt.Printf("loadUsage(): Fail to load usage(%s): %s.\n", cmd.Name(), err)
fmt.Printf(fmt.Sprintf("ERROR: loadUsage -> %s\n", promptMsg["LoadCommandUsage"]), cmd.Name(), err)
return false
}
defer f.Close()
// Read usage.
fi, _ := f.Stat()
usageBytes := make([]byte, fi.Size())
f.Read(usageBytes)
usages := strings.Split(string(usageBytes), "|||")
if len(usages) < 2 {
fmt.Printf("loadUsage(): nacceptable usage file: %s.\n", cmd.Name())
fmt.Printf(
fmt.Sprintf("ERROR: loadUsage -> %s\n", promptMsg["ReadCoammndUsage"]), cmd.Name())
return false
}
cmd.Short = usages[0]
@ -151,14 +189,14 @@ func loadLocalNodes() bool {
} else {
fr, err := os.Open(appPath + "data/nodes.json")
if err != nil {
fmt.Println(err)
fmt.Printf(fmt.Sprintf("ERROR: loadLocalNodes -> %s\n", promptMsg["LoadLocalData"]), err)
return false
}
defer fr.Close()
err = json.NewDecoder(fr).Decode(&localNodes)
if err != nil && err != io.EOF {
fmt.Println(err)
fmt.Printf(fmt.Sprintf("ERROR: loadLocalNodes -> %s\n", promptMsg["ParseJSON"]), err)
return false
}
}
@ -170,14 +208,14 @@ func loadLocalBundles() bool {
// Find all bundles.
dir, err := os.Open(appPath + "repo/bundles/")
if err != nil {
fmt.Println(err)
fmt.Printf(fmt.Sprintf("ERROR: loadLocalBundles -> %s\n", promptMsg["OpenFile"]), err)
return false
}
defer dir.Close()
fis, err := dir.Readdir(0)
if err != nil {
fmt.Println(err)
fmt.Printf(fmt.Sprintf("ERROR: loadLocalBundles -> %s\n", promptMsg["OpenFile"]), err)
return false
}
@ -186,7 +224,7 @@ func loadLocalBundles() bool {
if !fi.IsDir() && strings.HasSuffix(fi.Name(), ".json") {
fr, err := os.Open(appPath + "repo/bundles/" + fi.Name())
if err != nil {
fmt.Println(err)
fmt.Printf(fmt.Sprintf("ERROR: loadLocalBundles -> %s\n", promptMsg["OpenFile"]), err)
return false
}
@ -194,7 +232,7 @@ func loadLocalBundles() bool {
err = json.NewDecoder(fr).Decode(bundle)
fr.Close()
if err != nil && err != io.EOF {
fmt.Println(err)
fmt.Printf(fmt.Sprintf("ERROR: loadLocalBundles -> %s\n", promptMsg["ParseJSON"]), err)
return false
}
@ -219,7 +257,7 @@ func initialize() bool {
// Load configuration.
if _, err := toml.DecodeFile(appPath+"conf/gpm.toml", &config); err != nil {
fmt.Println(err)
fmt.Printf("initialize -> Fail to load configuration[ %s ]\n", err)
return false
}
@ -269,7 +307,7 @@ func main() {
}
// Uknown commands.
fmt.Fprintf(os.Stderr, "gpm: unknown subcommand %q\nRun 'gpm help' for usage.\n", args[0])
fmt.Fprintf(os.Stderr, fmt.Sprintf("%s\n", promptMsg["UnknownCommand"]), args[0])
setExitStatus(2)
exit()
}

28
i18n/en-US/prompt.txt

@ -0,0 +1,28 @@
LoadCommandUsage=Fail to load command(%s) usage[ %s ]
ReadCoammndUsage=Unacceptable command(%s) usage file.
LoadLocalData=Fail to load local data[ %s ]
ParseJSON=Fail to parse JSON[ %s ]
OpenFile=Fail to open file[ %s ]
RemoveFile=Fail to remove file[ %s ]
UnknownCommand=gpm: Unknown command %q. Run 'gpm help' for usage.
MoveFile=Fail to move file from $GOPATH(%s) to current directory(%s).
UnknownFlag=Unknown flag: %s.
DownloadError=Fail to download package(%s)[ %s ]
NotFoundError=Import path prefix matches known service, but regexp does not.
ErrNoMatch=Unsupported VCS platform.
MovedFile=Moved file from $GOPATH(%s) to current directory(%s).
PureDownload=You enabled pure download.
DownloadOnly=You enabled download without installing.
DownloadExDeps=You enabled download dependencies in example.
DownloadFromSrcs=You enabled download from sources.
NoPackage=Please list at least one package/bundle/snapshot.
DownloadPath=Packages will be downloaded to GOPATH(%s).
InstallStatus=Installing package: %s.
BundleInfo=Bundle(%s) contains following nodes:
ContinueDownload=Continue to download?(Y/n).
SkipDownloaded=Skipped downloaded package: %s.
SkipInvalidPath=Skipped invalid import path: %s.
InstallByGoGet=Installing package(%s) through 'go get'.
NoVCSTool=No version control tool is available, pure download enabled!
DownloadStatus=Downloading package: %s.

48
install.go

@ -6,6 +6,7 @@ package main
import (
"encoding/json"
"errors"
"fmt"
"net/http"
"os"
@ -44,13 +45,13 @@ func init() {
func printPrompt(flag string) {
switch flag {
case "-p":
fmt.Printf("You enabled pure download.\n")
fmt.Printf(fmt.Sprintf("%s\n", promptMsg["PureDownload"]))
case "-d":
fmt.Printf("You enabled download without installing.\n")
fmt.Printf(fmt.Sprintf("%s\n", promptMsg["DownloadOnly"]))
case "-e":
fmt.Printf("You enabled download dependencies in example.\n")
fmt.Printf(fmt.Sprintf("%s\n", promptMsg["DownloadExDeps"]))
case "-s":
fmt.Printf("You enabled download from sources.\n")
fmt.Printf(fmt.Sprintf("%s\n", promptMsg["DownloadFromSrcs"]))
}
}
@ -71,7 +72,7 @@ func checkFlags(args []string) int {
cmdInstall.Flags[f] = true
printPrompt(f)
} else {
fmt.Printf("Unknown flag: %s.\n", f)
fmt.Printf(fmt.Sprintf("%s\n", promptMsg["UnknownFlag"]), f)
return -1
}
num = i + 1
@ -103,7 +104,7 @@ func runInstall(cmd *Command, args []string) {
// Check length of arguments.
if len(args) < 1 {
fmt.Printf("Please list at least one package/bundle/snapshot.\n")
fmt.Printf(fmt.Sprintf("%s\n", promptMsg["NoPackage"]))
return
}
@ -111,7 +112,7 @@ func runInstall(cmd *Command, args []string) {
checkVCSTool()
installGOPATH = utils.GetBestMatchGOPATH(appPath)
fmt.Printf("Packages will be downloaded to GOPATH(%s).\n", installGOPATH)
fmt.Printf(fmt.Sprintf("%s\n", promptMsg["DownloadPath"]), installGOPATH)
// Generate temporary nodes.
nodes := make([]*doc.Node, len(args))
@ -129,7 +130,7 @@ func runInstall(cmd *Command, args []string) {
cmdArgs = append(cmdArgs, "<blank>")
for k := range downloadCache {
fmt.Printf("Installing package: %s.\n", k)
fmt.Printf(fmt.Sprintf("%s\n", promptMsg["InstallStatus"]), k)
cmdArgs[1] = k
executeGoCommand(cmdArgs)
}
@ -137,11 +138,15 @@ func runInstall(cmd *Command, args []string) {
// Save local nodes to file.
fw, err := os.Create(appPath + "data/nodes.json")
if err != nil {
fmt.Println(err)
fmt.Printf(fmt.Sprintf("ERROR: runInstall -> %s\n", promptMsg["OpenFile"]), err)
return
}
defer fw.Close()
fbytes, _ := json.MarshalIndent(&localNodes, "", "\t")
fbytes, err := json.MarshalIndent(&localNodes, "", "\t")
if err != nil {
fmt.Printf(fmt.Sprintf("ERROR: runInstall -> %s\n", promptMsg["ParseJSON"]), err)
return
}
fw.Write(fbytes)
}
@ -183,14 +188,13 @@ func downloadPackages(nodes []*doc.Node) {
case n.ImportPath[0] == 'B':
// Check local bundles.
bnodes := checkLocalBundles(n.ImportPath[1:])
if len(nodes) > 0 {
if len(bnodes) > 0 {
// Check with users if continue.
fmt.Printf("Bundle(%s) contains following nodes:\n",
n.ImportPath[1:])
fmt.Printf(fmt.Sprintf("%s\n", promptMsg["BundleInfo"]), n.ImportPath[1:])
for _, bn := range bnodes {
fmt.Printf("[%s] -> %s: %s.\n", bn.ImportPath, bn.Type, bn.Value)
}
fmt.Print("Continue to download?(Y/n).")
fmt.Printf(fmt.Sprintf("%s", promptMsg["ContinueDownload"]))
var option string
fmt.Fscan(os.Stdin, &option)
if strings.ToLower(option) != "y" {
@ -225,11 +229,11 @@ func downloadPackages(nodes []*doc.Node) {
saveNode(node)
}
} else {
fmt.Printf("Skipped downloaded package: %s.\n", n.ImportPath)
fmt.Printf(fmt.Sprintf("%s\n", promptMsg["SkipDownloaded"]), n.ImportPath)
}
default:
// Invalid import path.
fmt.Printf("Skipped invalid import path: %s.\n", n.ImportPath)
fmt.Printf(fmt.Sprintf("%s\n", promptMsg["SkipInvalidPath"]), n.ImportPath)
}
}
}
@ -254,7 +258,7 @@ func downloadPackage(node *doc.Node) (*doc.Node, []string) {
switch {
case !cmdInstall.Flags["-p"] &&
((node.ImportPath[0] == 'g' && isHasGit) || (node.ImportPath[0] == 'c' && isHasHg)): // github.com, code.google.com
fmt.Printf("Installing package(%s) through 'go get'.\n", node.ImportPath)
fmt.Printf(fmt.Sprintf("%s\n", promptMsg["InstallByGoGet"]), node.ImportPath)
args := checkGoGetFlags()
args = append(args, node.ImportPath)
executeGoCommand(args)
@ -262,16 +266,16 @@ func downloadPackage(node *doc.Node) (*doc.Node, []string) {
default: // Pure download.
if !cmdInstall.Flags["-p"] {
cmdInstall.Flags["-p"] = true
fmt.Printf("No version control tool is available, pure download enabled!\n")
fmt.Printf(fmt.Sprintf("%s\n", promptMsg["NoVCSTool"]))
}
fmt.Printf("Downloading package: %s.\n", node.ImportPath)
fmt.Printf(fmt.Sprintf("%s\n", promptMsg["InstallByGoGet"]), node.ImportPath)
// Mark as donwloaded.
downloadCache[node.ImportPath] = true
imports, err := pureDownload(node)
if err != nil {
fmt.Printf("Fail to download package(%s) with error: %s.\n", node.ImportPath, err)
fmt.Printf(fmt.Sprintf("%s\n", promptMsg["DownloadError"]), node.ImportPath, err)
return nil, nil
}
@ -317,7 +321,7 @@ func pureDownload(node *doc.Node) ([]string, error) {
if m == nil {
if s.prefix != "" {
return nil,
doc.NotFoundError{"Import path prefix matches known service, but regexp does not."}
doc.NotFoundError{fmt.Sprintf("%s\n", promptMsg["NotFoundError"])}
}
continue
}
@ -329,5 +333,5 @@ func pureDownload(node *doc.Node) ([]string, error) {
}
return s.get(doc.HttpClient, match, installGOPATH, node, cmdInstall.Flags)
}
return nil, doc.ErrNoMatch
return nil, errors.New(fmt.Sprintf("%s\n", promptMsg["NotFoundError"]))
}

185
models/models.go

@ -1,185 +0,0 @@
// Copyright (c) 2013 GPMGo Members. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
// Package models implemented database access funtions.
package models
import (
"database/sql"
"errors"
//"os"
"strconv"
"strings"
"time"
"github.com/coocood/qbs"
_ "github.com/mattn/go-sqlite3"
)
const (
DB_NAME = "./data/gowalker.db"
_SQLITE3_DRIVER = "sqlite3"
)
// PkgInfo is package information.
type PkgInfo struct {
Id int64
Path string `qbs:"index"` // Import path of package.
AbsPath string
Imports []string
Note string
Created time.Time `qbs:"index"` // Time when information last updated.
Commit string // Revision tag and project tags.
}
func connDb() *qbs.Qbs {
// 'sql.Open' only returns error when unknown driver, so it's not necessary to check in other places.
db, err := sql.Open(_SQLITE3_DRIVER, DB_NAME)
if err != nil {
//beego.Error("models.connDb():", err)
}
q := qbs.New(db, qbs.NewSqlite3())
return q
}
func setMg() (*qbs.Migration, error) {
db, err := sql.Open(_SQLITE3_DRIVER, DB_NAME)
mg := qbs.NewMigration(db, DB_NAME, qbs.NewSqlite3())
return mg, err
}
/*func init() {
// Initialize database.
os.Mkdir("./data", os.ModePerm)
// Connect to database.
q := connDb()
defer q.Db.Close()
mg, err := setMg()
if err != nil {
beego.Error("models.init():", err)
}
defer mg.Db.Close()
// Create data tables.
mg.CreateTableIfNotExists(new(PkgInfo))
beego.Trace("Initialized database ->", DB_NAME)
}*/
// GetProInfo returns package information from database.
func GetPkgInfo(path string) (*PkgInfo, error) {
// Check path length to reduce connect times.
if len(path) == 0 {
return nil, errors.New("models.GetPkgInfo(): Empty path as not found.")
}
// Connect to database.
q := connDb()
defer q.Db.Close()
pinfo := new(PkgInfo)
err := q.WhereEqual("path", path).Find(pinfo)
return pinfo, err
}
// GetGroupPkgInfo returns group of package infomration in order to reduce database connect times.
func GetGroupPkgInfo(paths []string) ([]*PkgInfo, error) {
// Connect to database.
q := connDb()
defer q.Db.Close()
pinfos := make([]*PkgInfo, 0, len(paths))
for _, v := range paths {
if len(v) > 0 {
pinfo := new(PkgInfo)
err := q.WhereEqual("path", v).Find(pinfo)
if err == nil {
pinfos = append(pinfos, pinfo)
} else {
pinfos = append(pinfos, &PkgInfo{Path: v})
}
}
}
return pinfos, nil
}
// GetPkgInfoById returns package information from database by pid.
func GetPkgInfoById(pid int) (*PkgInfo, error) {
// Connect to database.
q := connDb()
defer q.Db.Close()
pinfo := new(PkgInfo)
err := q.WhereEqual("id", pid).Find(pinfo)
return pinfo, err
}
// GetGroupPkgInfoById returns group of package infomration by pid in order to reduce database connect times.
// The formatted pid looks like '$<pid>|', so we need to cut '$' here.
func GetGroupPkgInfoById(pids []string) ([]*PkgInfo, error) {
// Connect to database.
q := connDb()
defer q.Db.Close()
pinfos := make([]*PkgInfo, 0, len(pids))
for _, v := range pids {
if len(v) > 1 {
pid, err := strconv.Atoi(v[1:])
if err == nil {
pinfo := new(PkgInfo)
err = q.WhereEqual("id", pid).Find(pinfo)
if err == nil {
pinfos = append(pinfos, pinfo)
}
}
}
}
return pinfos, nil
}
// DeleteProject deletes everything about the path in database, and update import information.
func DeleteProject(path string) error {
// Check path length to reduce connect times. (except launchpad.net)
if path[0] != 'l' && len(strings.Split(path, "/")) <= 2 {
return errors.New("models.DeleteProject(): Short path as not needed.")
}
// Connect to database.
q := connDb()
defer q.Db.Close()
var i1 int64
// Delete package information.
info := new(PkgInfo)
err := q.WhereEqual("path", path).Find(info)
if err == nil {
i1, err = q.Delete(info)
if err != nil {
//beego.Error("models.DeleteProject(): Information:", err)
}
}
if i1 > 0 {
//beego.Info("models.DeleteProject(", path, i1, ")")
}
return nil
}
// SearchDoc returns packages information that contain keyword
func SearchDoc(key string) ([]*PkgInfo, error) {
// Connect to database.
q := connDb()
defer q.Db.Close()
var pkgInfos []*PkgInfo
condition := qbs.NewCondition("path like ?", "%"+key+"%")
err := q.Condition(condition).OrderBy("path").FindAll(&pkgInfos)
return pkgInfos, err
}
Loading…
Cancel
Save