From e9a5685e2e4c4a0d176cca42ffece47e14b25ddd Mon Sep 17 00:00:00 2001 From: Unknown Date: Mon, 19 Aug 2013 17:43:57 +0800 Subject: [PATCH] Added back command serve --- cmd/serve.go | 414 +++++++++++++++++++++++++++++++++++++++++++++++++ cmd/service.go | 213 +++++++++++++++++++++++++ doc/struct.go | 8 + gopm.go | 2 +- 4 files changed, 636 insertions(+), 1 deletion(-) create mode 100644 cmd/serve.go create mode 100644 cmd/service.go diff --git a/cmd/serve.go b/cmd/serve.go new file mode 100644 index 000000000..450585a39 --- /dev/null +++ b/cmd/serve.go @@ -0,0 +1,414 @@ +// Copyright 2013 gopm authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"): you may +// not use this file except in compliance with the License. You may obtain +// a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. + +package cmd + +import ( + "fmt" + "github.com/syndtr/goleveldb/leveldb" + "github.com/syndtr/goleveldb/leveldb/errors" + "github.com/syndtr/goleveldb/leveldb/opt" + "io/ioutil" + "net/http" + "os" + "os/user" + "strconv" + "strings" + + "github.com/gpmgo/gopm/doc" +) + +var ( + dbDir = "~/.gopm/db" +) + +const ( + STOP = iota + LOCALRUN + RUNNING +) + +var CmdServe = &Command{ + UsageLine: "serve [:port]", + Short: "serve for package search", + Long: ` + serve provide a web service to search packages, download packages + +The serve flags are: + + -l + only service for localhost ip +`, +} + +func init() { + CmdServe.Run = runServe + CmdServe.Flags = map[string]bool{ + "-l": false, + } +} + +func printServePrompt(flag string) { + switch flag { + case "-l": + doc.ColorLog("[INFO] You enabled start a service only localhost.\n") + } +} + +// Not implemented +func autoPort() string { + return "8991" +} + +// search packages +func runServe(cmd *Command, args []string) { + // Check flags. + num := checkFlags(cmd.Flags, args, printServePrompt) + if num == -1 { + return + } + args = args[num:] + + var listen string + var port string + if cmd.Flags["-l"] { + listen += "127.0.0.1:" + port = autoPort() + } else { + listen += "0.0.0.0:" + port = "8991" + } + + // Check length of arguments. + if len(args) >= 1 { + port = args[0] + } + + startService(listen + port) +} + +func splitWord(word string, res *map[string]bool) { + for i, _ := range word { + for j, _ := range word[i:] { + w := word[i : i+j+1] + (*res)[w] = true + } + } + return +} + +func splitPkgName(pkgName string) (res map[string]bool) { + //var src string + ps := strings.Split(pkgName, "/") + if len(ps) > 1 { + ps = ps[1:] + } + + res = make(map[string]bool, 0) + res[strings.Join(ps, "/")] = true + for _, w := range ps { + splitWord(w, &res) + } + return +} + +var ( + ro *opt.ReadOptions = &opt.ReadOptions{} + wo *opt.WriteOptions = &opt.WriteOptions{} +) + +func dbGet(key string) (string, error) { + v, err := db.Get([]byte(key), ro) + return string(v), err +} + +func dbPut(key string, value string) error { + fmt.Println("put ", key, ": ", value) + return db.Put([]byte(key), []byte(value), wo) +} + +func batchPut(batch *leveldb.Batch, key string, value string) error { + fmt.Println("put ", key, ": ", value) + batch.Put([]byte(key), []byte(value)) + return nil +} + +func addNode(nod *doc.Node) error { + batch := new(leveldb.Batch) + strLastId, err := dbGet("lastId") + if err != nil { + if err == errors.ErrNotFound { + strLastId = "0" + err = batchPut(batch, "lastId", strLastId) + } else { + return err + } + } + if err != nil { + return err + } + + fmt.Println("last id is ", strLastId) + + lastId, err := strconv.ParseInt(strLastId, 0, 64) + if err != nil { + return err + } + + nodKey := fmt.Sprintf("index:%v", nod.ImportPath) + + id, err := dbGet(nodKey) + if err != nil { + if err == errors.ErrNotFound { + id = fmt.Sprintf("%v", lastId+1) + fmt.Println(id) + err = batchPut(batch, "lastId", id) + if err == nil { + err = batchPut(batch, nodKey, id) + } + if err == nil { + err = batchPut(batch, "pkg:"+id, nod.ImportPath) + } + total, err := dbGet("total") + if err != nil { + if err == errors.ErrNotFound { + total = "1" + } else { + return err + } + } else { + totalInt, err := strconv.ParseInt(total, 0, 64) + if err != nil { + return err + } + totalInt = totalInt + 1 + total = fmt.Sprintf("%v", totalInt) + } + + err = batchPut(batch, "total", total) + } else { + return err + } + } + + if err != nil { + return err + } + + vers, err := dbGet("ver:" + id) + needSplit := (err == errors.ErrNotFound) + if err != nil { + if err != errors.ErrNotFound { + return err + } + } else { + return nil + } + + if vers == "" { + fmt.Println(nod) + vers = nod.VerString() + } else { + if !strings.Contains(vers, nod.VerString()) { + vers = vers + "," + nod.VerString() + } else { + return nil + } + } + + err = batchPut(batch, "ver:"+id, vers) + if err != nil { + return err + } + + if !needSplit { + return nil + } + + keys := splitPkgName(nod.ImportPath) + + for key, _ := range keys { + err = batchPut(batch, fmt.Sprintf("key:%v:%v", key, id), "") + if err != nil { + return err + } + } + + return db.Write(batch, wo) +} + +func rmPkg(nod *doc.Node) { + +} + +var db *leveldb.DB + +// service should be run +func autoRun() { + s, _, _ := runningStatus() + if s == STOP { + os.StartProcess("gopm", []string{"serve", "-l"}, nil) + } +} + +func runningStatus() (int, int, int) { + contentByte, err := ioutil.ReadFile("~/.gopm/var/pid") + if err != nil { + return STOP, 0, 0 + } + content := string(contentByte) + if len(content) < 0 || !strings.Contains(content, ",") { + return STOP, 0, 0 + } + cs := strings.Split(string(content), ",") + if len(cs) != 3 { + return STOP, 0, 0 + } + status, err := strconv.Atoi(cs[0]) + if err != nil { + return STOP, 0, 0 + } + if status < STOP || status > RUNNING { + return STOP, 0, 0 + } + pid, err := strconv.Atoi(cs[1]) + if err != nil { + return STOP, 0, 0 + } + + _, err = os.FindProcess(pid) + if err != nil { + return STOP, 0, 0 + } + + port, err := strconv.Atoi(cs[2]) + if err != nil { + return STOP, 0, 0 + } + + return status, pid, port +} + +func startService(listen string) { + // check the pre serve's type + curUser, err := user.Current() + if err != nil { + fmt.Println(err) + return + } + + dbDir = strings.Replace(dbDir, "~", curUser.HomeDir, -1) + + db, err = leveldb.OpenFile(dbDir, &opt.Options{Flag: opt.OFCreateIfMissing}) + if err != nil { + fmt.Println(err) + return + } + defer db.Close() + + // these handlers should only access by localhost + http.HandleFunc("/add", addHandler) + http.HandleFunc("/rm", rmHandler) + + // these handlers can be accessed according listen's ip + http.HandleFunc("/search", searchHandler) + http.HandleFunc("/searche", searcheHandler) + http.ListenAndServe(listen, nil) +} + +func searchHandler(w http.ResponseWriter, r *http.Request) { + r.ParseForm() + ids := make(map[string]bool) + for key, _ := range r.Form { + iter := db.NewIterator(ro) + rkey := fmt.Sprintf("key:%v:", key) + if iter.Seek([]byte(rkey)) { + k := iter.Key() + if !strings.HasPrefix(string(k), rkey) { + break + } else { + ids[string(k)] = true + } + } + for iter.Next() { + k := iter.Key() + if !strings.HasPrefix(string(k), rkey) { + break + } + ids[string(k)] = true + } + } + + pkgs := make([]string, 0) + + for id, _ := range ids { + idkeys := strings.SplitN(id, ":", -1) + rId := idkeys[len(idkeys)-1] + fmt.Println(rId) + pkg, err := dbGet(fmt.Sprintf("pkg:%v", rId)) + if err != nil { + doc.ColorLog(err.Error()) + continue + } + pkgs = append(pkgs, pkg) + } + + w.Write([]byte("[\"" + strings.Join(pkgs, "\", \"") + "\"]")) +} + +func searcheHandler(w http.ResponseWriter, r *http.Request) { + //if r.Method == "POST" { + r.ParseForm() + pkgs := make([]string, 0) + for key, _ := range r.Form { + _, err := dbGet("index:" + key) + + if err != nil { + doc.ColorLog(err.Error()) + continue + } + + pkgs = append(pkgs, key) + } + + w.Write([]byte("[\"" + strings.Join(pkgs, "\", \"") + "\"]")) + //} +} + +func addHandler(w http.ResponseWriter, r *http.Request) { + //if r.Method == "POST" { + r.ParseForm() + for key, _ := range r.Form { + fmt.Println(key) + // pkg := NewPkg(key, "") + nod := &doc.Node{ + ImportPath: key, + DownloadURL: key, + IsGetDeps: true, + } + if nod != nil { + err := addNode(nod) + if err != nil { + fmt.Println(err) + } + } else { + fmt.Println(key) + } + } + //} +} + +func rmHandler(w http.ResponseWriter, r *http.Request) { + +} diff --git a/cmd/service.go b/cmd/service.go new file mode 100644 index 000000000..11f0bf19e --- /dev/null +++ b/cmd/service.go @@ -0,0 +1,213 @@ +// Copyright 2013 gopm authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"): you may +// not use this file except in compliance with the License. You may obtain +// a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. + +package cmd + +// func getService(pkgName string) Service { +// for _, service := range services { +// if service.HasPkg(pkgName) { +// return service +// } +// } +// return nil +// } + +// type Service interface { +// PkgUrl(pkg *Pkg) string +// HasPkg(pkgName string) bool +// PkgExt() string +// } + +// type Pkg struct { +// Name string +// Ver string +// VerId string +// } + +// func NewPkg(pkgName string, ver string) *Pkg { +// vers := strings.Split(ver, ":") +// if len(vers) > 2 { +// return nil +// } + +// var verId string +// if len(vers) == 2 { +// verId = vers[1] +// } + +// if len(vers) == 1 { +// vers[0] = TRUNK +// } + +// service := getService(pkgName) +// if service == nil { +// return nil +// } + +// return &Pkg{service, pkgName, vers[0], verId} +// } + +// func (p *Pkg) VerSimpleString() string { +// if p.VerId != "" { +// return p.VerId +// } +// return p.Ver +// } + +// func (p *Pkg) Url() string { +// return p.Service.PkgUrl(p) +// } + +// func (p *Pkg) FileName() string { +// return fmt.Sprintf("%v.%v", p.VerSimpleString(), p.Service.PkgExt()) +// } + +// // github repository +// type GithubService struct { +// } + +// func (s *GithubService) PkgUrl(pkg *Pkg) string { +// var verPath string +// if pkg.Ver == TRUNK { +// verPath = "master" +// } else { +// verPath = pkg.VerId +// } +// return fmt.Sprintf("https://%v/archive/%v.zip", pkg.Name, verPath) +// } + +// func (s *GithubService) HasPkg(pkgName string) bool { +// return strings.HasPrefix(pkgName, "github.com") +// } + +// func (s *GithubService) PkgExt() string { +// return "zip" +// } + +// // git osc repos +// type GitOscService struct { +// } + +// func (s *GitOscService) PkgUrl(pkg *Pkg) string { +// var verPath string +// if pkg.Ver == TRUNK { +// verPath = "master" +// } else { +// verPath = pkg.VerId +// } +// return fmt.Sprintf("https://%v/repository/archive?ref=%v", pkg.Name, verPath) +// } + +// func (s *GitOscService) HasPkg(pkgName string) bool { +// return strings.HasPrefix(pkgName, "git.oschina.net") +// } + +// func (s *GitOscService) PkgExt() string { +// return "zip" +// } + +// // bitbucket.org +// type BitBucketService struct { +// } + +// func (s *BitBucketService) PkgUrl(pkg *Pkg) string { +// var verPath string +// if pkg.Ver == TRUNK { +// verPath = "default" +// } else { +// verPath = pkg.VerId +// } + +// return fmt.Sprintf("https://%v/get/%v.zip", pkg.Name, verPath) +// } + +// func (s *BitBucketService) HasPkg(pkgName string) bool { +// return strings.HasPrefix(pkgName, "bitbucket.org") +// } + +// func (s *BitBucketService) PkgExt() string { +// return "zip" +// } + +// type GitCafeService struct { +// } + +// func (s *GitCafeService) PkgUrl(pkg *Pkg) string { +// var verPath string +// if pkg.Ver == TRUNK { +// verPath = "master" +// } else { +// verPath = pkg.VerId +// } + +// return fmt.Sprintf("https://%v/tarball/%v", pkg.Name, verPath) +// } + +// func (s *GitCafeService) HasPkg(pkgName string) bool { +// return strings.HasPrefix(pkgName, "gitcafe.com") +// } + +// func (s *GitCafeService) PkgExt() string { +// return "tar.gz" +// } + +// // git lab repos, not completed +// type GitLabService struct { +// DomainOrIp string +// Username string +// Passwd string +// PrivateKey string +// } + +// func (s *GitLabService) PkgUrl(pkg *Pkg) string { +// var verPath string +// if pkg.Ver == TRUNK { +// verPath = "master" +// } else { +// verPath = pkg.VerId +// } + +// return fmt.Sprintf("https://%v/repository/archive/%v", pkg.Name, verPath) +// } + +// func (s *GitLabService) HasPkg(pkgName string) bool { +// return strings.HasPrefix(pkgName, s.DomainOrIp) +// } + +// func (s *GitLabService) PkgExt() string { +// return "tar.gz" +// } + +// // code.csdn.net +// type CodeCSDNService struct { +// } + +// func (s *CodeCSDNService) PkgUrl(pkg *Pkg) string { +// var verPath string +// if pkg.Ver == TRUNK { +// verPath = "master" +// } else { +// verPath = pkg.VerId +// } + +// return fmt.Sprintf("https://%v/repository/archive?ref=%v", pkg.Name, verPath) +// } + +// func (s *CodeCSDNService) HasPkg(pkgName string) bool { +// return strings.HasPrefix(pkgName, "code.csdn.net") +// } + +// func (s *CodeCSDNService) PkgExt() string { +// return "zip" +// } diff --git a/doc/struct.go b/doc/struct.go index 3a1163cb7..0993f6707 100644 --- a/doc/struct.go +++ b/doc/struct.go @@ -15,6 +15,7 @@ package doc import ( + "fmt" "go/token" "net/http" "os" @@ -39,6 +40,13 @@ type Node struct { IsGetDeps bool } +func (nod *Node) VerString() string { + if nod.Value == "" { + return nod.Type + } + return fmt.Sprintf("%v:%v", nod.Type, nod.Value) +} + // source is source code file. type source struct { rawURL string diff --git a/gopm.go b/gopm.go index 6671acad3..b564be06b 100644 --- a/gopm.go +++ b/gopm.go @@ -48,7 +48,7 @@ var ( var commands = []*cmd.Command{ cmd.CmdGet, cmd.CmdSearch, - //cmd.CmdServe, + cmd.CmdServe, /* cmdBuild, cmdClean,