// 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, i2, i3 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) } } // Delete package declaration pdecl := new(PkgDecl) err = q.WhereEqual("path", path).Find(pdecl) if err == nil { i2, err = q.Delete(pdecl) if err != nil { beego.Error("models.DeleteProject(): Declaration:", err) } else if info.Id > 0 && !utils.IsGoRepoPath(path) { // Don't need to check standard library. // Update import information. imports := strings.Split(pdecl.Imports, "|") imports = imports[:len(imports)-1] for _, v := range imports { if !utils.IsGoRepoPath(v) { // Only count non-standard library. updateImportInfo(q, v, int(info.Id), false) } } } } // Delete package documentation pdoc := &PkgDoc{Path: path} i3, err = q.Delete(pdoc) if err != nil { beego.Error("models.DeleteProject(): Documentation:", err) } if i1+i2+i3 > 0 { beego.Info("models.DeleteProject(", path, i1, i2, i3, ")") } return nil }
// checkSpecialUsage checks special usage of keywords. // It returns true if it is a special usage, false otherwise. func checkSpecialUsage(this *SearchRouter, q string) bool { switch { case q == "gorepo": // Show list of standard library. pinfos, _ := models.GetGoRepo() if len(pinfos) > 0 { this.Data["IsFindPro"] = true this.Data["Results"] = pinfos } return true case q == "imports": // Show imports package list. pkgs := strings.Split(this.Input().Get("pkgs"), "|") pinfos, _ := models.GetGroupPkgInfo(pkgs) if len(pinfos) > 0 { this.Data["IsFindPro"] = true this.Data["Results"] = pinfos } return true case q == "imported": // Show packages that import this project. pkgs := strings.Split( strings.Replace(this.Input().Get("pkgs"), "$", "", -1), "|") pinfos := models.GetGroupPkgInfoById(pkgs) if len(pinfos) > 0 { this.Data["IsFindPro"] = true this.Data["Results"] = pinfos } return true case strings.Index(q, ":l=") > -1: // Add label to the project. // Get label(s). i := strings.Index(q, ":l=") if utils.IsGoRepoPath(q[:i]) { this.Redirect("/"+q[:i], 302) return true } if isLabel(q[i+3:]) && models.UpdateLabelInfo(q[:i], q[i+3:], true) { this.Redirect("/"+q[:i], 302) } return true case strings.Index(q, ":rl=") > -1: // Remove label to the project. // Get label(s). i := strings.Index(q, ":rl=") if utils.IsGoRepoPath(q[:i]) { this.Redirect("/"+q[:i], 302) return true } if isLabel(q[i+4:]) && models.UpdateLabelInfo(q[:i], q[i+4:], false) { this.Redirect("/"+q[:i], 302) } return true } return false }
// checkSpecialUsage checks special usage of keywords. // It returns true if it is a special usage, false otherwise. func checkSpecialUsage(this *SearchController, q string) bool { switch { case q == "gorepo": // Show list of standard library. pkgInfos, _ := models.GetGoRepo() // Show results after searched. if len(pkgInfos) > 0 { this.Data["IsFindPro"] = true this.Data["AllPros"] = pkgInfos } return true case q == "imports": // Show imports package list. pkgs := strings.Split(this.Input().Get("pkgs"), "|") pinfos, _ := models.GetGroupPkgInfo(pkgs) if len(pinfos) > 0 { this.Data["IsFindPro"] = true this.Data["AllPros"] = pinfos } return true case q == "imported": // Show packages that import this project. pkgs := strings.Split(this.Input().Get("pkgs"), "|") pinfos, _ := models.GetGroupPkgInfoById(pkgs) if len(pinfos) > 0 { this.Data["IsFindPro"] = true this.Data["AllPros"] = pinfos } return true case strings.Index(q, ":tag=") > -1: // Add tag(s) to the project. // Get tag(s). i := strings.Index(q, ":tag=") if utils.IsGoRepoPath(q[:i]) { this.Redirect("/"+q[:i], 302) return true } if isTag(q[i+5:]) && models.UpdateTagInfo(q[:i], q[i+5:], true) { this.Redirect("/"+q[:i], 302) } return true case strings.Index(q, ":rtag=") > -1: // Remove tag(s) to the project. // Get tag(s). i := strings.Index(q, ":rtag=") if utils.IsGoRepoPath(q[:i]) { this.Redirect("/"+q[:i], 302) return true } if isTag(q[i+6:]) && models.UpdateTagInfo(q[:i], q[i+6:], false) { this.Redirect("/"+q[:i], 302) } return true } return false }
// SaveProject save package information, declaration, documentation to database, and update import information. func SaveProject(pinfo *PkgInfo, pdecl *PkgDecl, pdoc *PkgDoc, imports []string) error { // Connect to database. q := connDb() defer q.Close() // Save package information. info := new(PkgInfo) err := q.WhereEqual("path", pinfo.Path).Find(info) if err == nil { pinfo.Id = info.Id } _, err = q.Save(pinfo) if err != nil { beego.Error("models.SaveProject -> Information:", err) } // Save package declaration if pdecl != nil { decl := new(PkgDecl) cond := qbs.NewCondition("path = ?", pinfo.Path).And("tag = ?", pdecl.Tag) err = q.Condition(cond).Find(decl) if err == nil { pdecl.Id = decl.Id } _, err = q.Save(pdecl) if err != nil { beego.Error("models.SaveProject -> Declaration:", err) } } // Save package documentation if pdoc != nil && len(pdoc.Doc) > 0 { _, err = q.Save(pdoc) if err != nil { beego.Error("models.SaveProject -> Documentation:", err) } } // Don't need to check standard library. if imports != nil && !utils.IsGoRepoPath(pinfo.Path) { // Update import information. for _, v := range imports { if !utils.IsGoRepoPath(v) { // Only count non-standard library. updateImportInfo(q, v, int(pinfo.Id), true) } } } return nil }
// getRepo downloads package data. func getRepo(client *http.Client, importPath string, etag string) (pdoc *Package, err error) { const VER_PREFIX = PACKAGE_VER + "-" // Check version prefix. if strings.HasPrefix(etag, VER_PREFIX) { etag = etag[len(VER_PREFIX):] } else { etag = "" } switch { case utils.IsGoRepoPath(importPath): pdoc, err = getStandardDoc(client, importPath, etag) case utils.IsValidRemotePath(importPath): pdoc, err = getStatic(client, importPath) if err == errNoMatch { pdoc, err = getDynamic(client, importPath) } default: return nil, errors.New("doc.getRepo(): No match: " + importPath) } // Save revision tag. if pdoc != nil { pdoc.Etag = VER_PREFIX + pdoc.Etag } return pdoc, err }
// getRepo downloads package data and returns 'Package' by given import path and tag. // It returns error when error occurs in the underlying functions. func getRepo(client *http.Client, path, tag, ptag string) (pdoc *hv.Package, err error) { switch { case utils.IsGoRepoPath(path): pdoc, err = getStandardDoc(client, path, tag, ptag) case utils.IsValidRemotePath(path): pdoc, err = getStatic(client, path, tag, ptag) if err == errNoMatch { pdoc, err = getDynamic(client, path, tag, ptag) } default: return nil, errors.New( fmt.Sprintf("doc.getRepo -> No match( %s:%s )", path, tag)) } if pdoc == nil { return nil, err } pdoc.PkgVer = hv.PACKAGE_VER // Render README. for name, content := range pdoc.Readme { p, err := httplib.Post("https://api.github.com/markdown/raw?"+GetGithubCredentials()). Header("Content-Type", "text/plain").Body(content).Bytes() if err != nil { return nil, errors.New( fmt.Sprintf("doc.getRepo -> Render README( %s:%s ): %v", path, tag, err)) } pdoc.Readme[name] = p } return pdoc, err }
// crawlDoc fetchs package from VCS. func crawlDoc(path string, etag string, views int64) (pdoc *Package, err error) { // I have no idea what the f**k does this mean. if i := strings.Index(path, "/libgo/go/"); i > 0 && utils.IsGoRepoPath(path[i+len("/libgo/go/"):]) { // Go Frontend source tree mirror. pdoc = nil err = errors.New("Go Frontend source tree mirror.") } else { var pdocNew *Package pdocNew, err = getRepo(httpClient, path, etag) // For timeout logic in client.go to work, we cannot leave connections idling. This is ugly. httpTransport.CloseIdleConnections() if err != errNotModified && pdocNew != nil { pdoc = pdocNew pdoc.Views = views } } switch { case err == nil: pdoc.Views = views if err = SaveProject(pdoc); err != nil { beego.Error("doc.SaveProject(", path, "):", err) } case isNotFound(err): // We do not need to delete standard library, so here is fine. if err = models.DeleteProject(path); err != nil { beego.Error("doc.DeleteProject(", path, "):", err) } } return pdoc, err }
func getPkgInfoWithQ(path, tag string, q *qbs.Qbs) (*hv.PkgInfo, error) { // Check path length to reduce connect times. if len(path) == 0 { return nil, errors.New("models.getPkgInfoWithQ -> Empty path as not found.") } pinfo := new(hv.PkgInfo) q.WhereEqual("import_path", path).Find(pinfo) proPath := utils.GetProjectPath(path) if utils.IsGoRepoPath(path) { proPath = "code.google.com/p/go" } beego.Trace("models.getPkgInfoWithQ -> proPath:", proPath) ptag := new(PkgTag) cond := qbs.NewCondition("path = ?", proPath).And("tag = ?", tag) err := q.Condition(cond).Find(ptag) if err != nil { pinfo.Ptag = "ptag" return pinfo, errors.New( fmt.Sprintf("models.getPkgInfoWithQ( %s:%s ) -> 'PkgTag': %s", path, tag, err)) } pinfo.Vcs = ptag.Vcs pinfo.Tags = ptag.Tags // Only 'PkgInfo' cannot prove that package exists, // we have to check 'PkgDecl' as well in case it was deleted by mistake. pdecl := new(PkgDecl) cond = qbs.NewCondition("pid = ?", pinfo.Id).And("tag = ?", tag) err = q.Condition(cond).Find(pdecl) if err != nil { // Basically, error means not found, so we set 'pinfo.PkgVer' to 0 // because server uses it to decide whether force update. pinfo.PkgVer = 0 pinfo.Ptag = "ptag" return pinfo, errors.New( fmt.Sprintf("models.getPkgInfoWithQ( %s:%s ) -> 'PkgDecl': %s", path, tag, err)) } docPath := path + utils.TagSuffix("-", tag) if !com.IsExist("." + utils.DocsJsPath + docPath + ".js") { pinfo.PkgVer = 0 pinfo.Ptag = "ptag" return pinfo, errors.New( fmt.Sprintf("models.getPkgInfoWithQ( %s:%s ) -> JS: File not found", path, tag)) } return pinfo, nil }
// SaveProject save package information, declaration, documentation to database, and update import information. func SaveProject(pinfo *PkgInfo, pdecl *PkgDecl, pdoc *PkgDoc, imports []string) error { // Connect to database. q, err := connDb() if err != nil { beego.Error("models.SaveProject():", err) } defer q.Db.Close() // Save package information. info := new(PkgInfo) err = q.WhereEqual("path", pinfo.Path).Find(info) if err != nil { _, err = q.Save(pinfo) } else { pinfo.Id = info.Id _, err = q.Save(pinfo) } if err != nil { beego.Error("models.SaveProject(): Information:", err) } // Save package declaration _, err = q.Save(pdecl) if err != nil { beego.Error("models.SaveProject(): Declaration:", err) } // Save package documentation if len(pdoc.Doc) > 0 { _, err = q.Save(pdoc) if err != nil { beego.Error("models.SaveProject(): Documentation:", err) } } // Update import information. for _, v := range imports { if !utils.IsGoRepoPath(v) { // Only count non-standard library. updateImportInfo(q, v, int(pinfo.Id), true) } } return nil }
// getRepo downloads package data and returns 'Package' by given import path and tag. // It returns error when error occurs in the underlying functions. func getRepo(client *http.Client, path, tag, ptag string) (pdoc *hv.Package, err error) { switch { case utils.IsGoRepoPath(path): pdoc, err = getStandardDoc(client, path, tag, ptag) case utils.IsValidRemotePath(path): pdoc, err = getStatic(client, path, tag, ptag) if err == errNoMatch { pdoc, err = getDynamic(client, path, tag, ptag) } default: return nil, errors.New( fmt.Sprintf("doc.getRepo -> No match( %s:%s )", path, tag)) } if pdoc != nil { pdoc.PkgVer = hv.PACKAGE_VER } return pdoc, err }
// Get implemented Get method for HomeRouter. func (this *HomeRouter) Get() { // Filter unusual User-Agent. ua := this.Ctx.Request.Header.Get("User-Agent") if len(ua) < 20 { beego.Warn("User-Agent:", this.Ctx.Request.Header.Get("User-Agent")) this.Ctx.WriteString("") return } // Set language version. curLang := globalSetting(this.Ctx, this.Input(), this.Data) // Get argument(s). q := strings.TrimRight( strings.TrimSpace(this.Input().Get("q")), "/") if path, ok := utils.IsBrowseURL(q); ok { q = path } // Get pure URL. reqUrl := this.Ctx.Request.RequestURI[1:] if i := strings.Index(reqUrl, "?"); i > -1 { reqUrl = reqUrl[:i] if path, ok := utils.IsBrowseURL(reqUrl); ok { reqUrl = path } } // Redirect to query string. if len(reqUrl) == 0 && len(q) > 0 { reqUrl = q this.Redirect("/"+reqUrl, 302) return } // User Recent projects. urpids, _ := this.Ctx.Request.Cookie("UserRecentPros") urpts, _ := this.Ctx.Request.Cookie("URPTimestamps") this.TplNames = "home_" + curLang.Lang + ".html" // Check to show home page or documentation page. if len(reqUrl) == 0 && len(q) == 0 { serveHome(this, urpids, urpts) } else { // Documentation. this.TplNames = "docs_" + curLang.Lang + ".html" broPath := reqUrl // Browse path. // Check if it's the standard library. if utils.IsGoRepoPath(broPath) { broPath = "code.google.com/p/go/source/browse/src/pkg/" + broPath } // Check if it's a remote path that can be used for 'go get', if not means it's a keyword. if !utils.IsValidRemotePath(broPath) { // Search. this.Redirect("/search?q="+reqUrl, 302) return } // Get tag field. tag := strings.TrimSpace(this.Input().Get("tag")) if tag == "master" || tag == "default" { tag = "" } // Check documentation of this import path, and update automatically as needed. pdoc, err := doc.CheckDoc(reqUrl, tag, doc.HUMAN_REQUEST) if err == nil { if pdoc != nil { pdoc.UserExamples = getUserExamples(pdoc.ImportPath) // Generate documentation page. if generatePage(this, pdoc, broPath, tag, curLang.Lang) { ps, ts := updateCacheInfo(pdoc, urpids, urpts) this.Ctx.SetCookie("UserRecentPros", ps, 9999999999, "/") this.Ctx.SetCookie("URPTimestamps", ts, 9999999999, "/") return } } } else { this.Data["IsHasError"] = true this.Data["ErrMsg"] = strings.Replace(err.Error(), doc.GetGithubCredentials(), "<githubCred>", 1) beego.Error("HomeRouter.Get ->", err) this.TplNames = "home_" + curLang.Lang + ".html" serveHome(this, urpids, urpts) return } this.Redirect("/search?q="+reqUrl, 302) return } }
// generatePage genarates documentation page for project. // it returns false when its a invaild(empty) project. func generatePage(this *HomeController, pdoc *doc.Package, q string, lang string) bool { // Set properties. this.TplNames = "docs_" + lang + ".html" // Refresh (within 10 seconds). this.Data["IsRefresh"] = pdoc.Created.Add(10 * time.Second).UTC().After(time.Now().UTC()) // Get project name. lastIndex := strings.LastIndex(q, "/") proName := q[lastIndex+1:] if i := strings.Index(proName, "?"); i > -1 { proName = proName[:i] } this.Data["ProName"] = proName // Project VCS home page. switch { case q[:4] == "code": // code.google.com if strings.Index(q, "source/") == -1 { this.Data["ProPath"] = strings.Replace(q, pdoc.ProjectName, pdoc.ProjectName+"/source/browse", 1) } else { this.Data["ProPath"] = q } case q[:3] == "git": // github.com if proName != pdoc.ProjectName { // Not root. this.Data["ProPath"] = strings.Replace(q, proName, "tree/master/"+proName, 1) } else { this.Data["ProPath"] = q + "/tree/master" } } this.Data["Views"] = pdoc.Views + 1 // Remove last "/". if urlLen := len(q); q[urlLen-1] == '/' { q = q[:urlLen-1] } if utils.IsGoRepoPath(pdoc.ImportPath) { this.Data["IsGoRepo"] = true } pkgDocPath := q[:lastIndex] this.Data["ProDocPath"] = pkgDocPath // Upper level project URL. // Introduction. this.Data["ImportPath"] = pdoc.ImportPath // Load project data from database. pdecl, err := models.LoadProject(pdoc.ImportPath) if err != nil { beego.Error("SearchController.generatePage(): models.LoadProject()", err) return false } var buf bytes.Buffer godoc.ToHTML(&buf, pdecl.Doc, nil) pkgInfo := buf.String() pkgInfo = strings.Replace(pkgInfo, "<p>", "<p><b>", 1) pkgInfo = strings.Replace(pkgInfo, "</p>", "</b></p>", 1) this.Data["PkgFullIntro"] = pkgInfo // Convert data format. err = ConvertDataFormat(pdoc, pdecl) if err != nil { beego.Error("SearchController.generatePage(): ConvertDataFormat", err) return false } links := make([]*utils.Link, 0, len(pdoc.Types)+len(pdoc.Imports)) // Get all types and import packages for _, t := range pdoc.Types { links = append(links, &utils.Link{ Name: t.Name, Comment: t.Doc, }) } for _, v := range pdoc.Imports { links = append(links, &utils.Link{ Name: path.Base(v) + ".", Path: v, }) } // Index. this.Data["IsHasConst"] = len(pdoc.Consts) > 0 this.Data["IsHasVar"] = len(pdoc.Vars) > 0 this.Data["Funcs"] = pdoc.Funcs for i, f := range pdoc.Funcs { buf.Reset() godoc.ToHTML(&buf, f.Doc, nil) f.Doc = buf.String() buf.Reset() utils.FormatCode(&buf, f.Decl, links) f.FmtDecl = buf.String() buf.Reset() utils.FormatCode(&buf, f.Code, links) f.Code = buf.String() pdoc.Funcs[i] = f } this.Data["Types"] = pdoc.Types for i, t := range pdoc.Types { for j, f := range t.Funcs { buf.Reset() godoc.ToHTML(&buf, f.Doc, nil) f.Doc = buf.String() buf.Reset() utils.FormatCode(&buf, f.Decl, links) f.FmtDecl = buf.String() buf.Reset() utils.FormatCode(&buf, f.Code, links) f.Code = buf.String() t.Funcs[j] = f } for j, m := range t.Methods { buf.Reset() godoc.ToHTML(&buf, m.Doc, nil) m.Doc = buf.String() buf.Reset() utils.FormatCode(&buf, m.Decl, links) m.FmtDecl = buf.String() buf.Reset() utils.FormatCode(&buf, m.Code, links) m.Code = buf.String() t.Methods[j] = m } buf.Reset() godoc.ToHTML(&buf, t.Doc, nil) t.Doc = buf.String() buf.Reset() utils.FormatCode(&buf, t.Decl, links) t.FmtDecl = buf.String() pdoc.Types[i] = t } // Constants. this.Data["Consts"] = pdoc.Consts for i, v := range pdoc.Consts { buf.Reset() utils.FormatCode(&buf, v.Decl, links) v.FmtDecl = buf.String() pdoc.Consts[i] = v } // Variables. this.Data["Vars"] = pdoc.Vars for i, v := range pdoc.Vars { buf.Reset() utils.FormatCode(&buf, v.Decl, links) v.FmtDecl = buf.String() pdoc.Vars[i] = v } // Dirs. this.Data["IsHasSubdirs"] = len(pdoc.Dirs) > 0 pinfos := make([]*models.PkgInfo, 0, len(pdoc.Dirs)) for _, v := range pdoc.Dirs { v = pdoc.ImportPath + "/" + v if pinfo, err := models.GetPkgInfo(v); err == nil { pinfos = append(pinfos, pinfo) } else { pinfos = append(pinfos, &models.PkgInfo{Path: v}) } } this.Data["Subdirs"] = pinfos this.Data["Files"] = pdoc.Files this.Data["ImportPkgs"] = pdecl.Imports this.Data["ImportPkgNum"] = len(pdoc.Imports) - 1 this.Data["UtcTime"] = pdoc.Created this.Data["GOOS"] = pdecl.Goos this.Data["GOARCH"] = pdecl.Goarch return true }
// Get implemented Get method for HomeController. // It serves home page of Go Walker. func (this *HomeController) Get() { // Print unusual User-Agent. ua := this.Ctx.Request.Header.Get("User-Agent") if len(ua) < 20 { beego.Trace("User-Agent:", this.Ctx.Request.Header.Get("User-Agent")) } // Check language version by different ways. lang := checkLangVer(this.Ctx.Request, this.Input().Get("lang")) // Get language version. curLang, restLangs := getLangVer( this.Ctx.Request.Header.Get("Accept-Language"), lang) // Save language information in cookies. this.Ctx.SetCookie("lang", curLang.Lang+";path=/", 0) // Get query field. q := strings.TrimSpace(this.Input().Get("q")) if path, ok := utils.IsBrowseURL(q); ok { q = path } // Get pure URL. reqUrl := this.Ctx.Request.RequestURI[1:] if i := strings.Index(reqUrl, "?"); i > -1 { reqUrl = reqUrl[:i] } if len(reqUrl) == 0 && len(q) > 0 { reqUrl = q } // Set properties this.Layout = "layout_" + curLang.Lang + ".html" // Set language properties. this.Data["Lang"] = curLang.Lang this.Data["CurLang"] = curLang.Name this.Data["RestLangs"] = restLangs // Check show home page or documentation page. if len(reqUrl) == 0 && len(q) == 0 { // Home page. this.TplNames = "home_" + curLang.Lang + ".html" // Recent projects this.Data["RecentPros"] = recentViewedPros // Get popular project list from database. pkgInfos, _ := models.GetPopularPros() this.Data["PopPros"] = pkgInfos // Set standard library keyword type-ahead. this.Data["DataSrc"] = utils.GoRepoSet } else { // Documentation page. broPath := reqUrl // Browse path. // Check if it is standard library. if utils.IsGoRepoPath(broPath) { broPath = "code.google.com/p/go/source/browse/src/pkg/" + broPath } // Check if it is a remote path that can be used for 'go get', if not means it's a keyword. if !utils.IsValidRemotePath(broPath) { // Show search page this.Redirect("/search?q="+reqUrl, 302) return } // Check documentation of this import path, and update automatically as needed. pdoc, err := doc.CheckDoc(reqUrl, doc.HUMAN_REQUEST) if err == nil { // Generate documentation page. /* TODO */ if pdoc != nil && generatePage(this, pdoc, broPath, curLang.Lang) { // Update recent project list. updateRecentPros(pdoc) // Update project views. pinfo := &models.PkgInfo{ Path: pdoc.ImportPath, Synopsis: pdoc.Synopsis, Created: pdoc.Created, ProName: pdoc.ProjectName, ViewedTime: pdoc.ViewedTime, Views: pdoc.Views, Etag: pdoc.Etag, } models.AddViews(pinfo) return } } else { beego.Error("HomeController.Get():", err) } // Show search page this.Redirect("/search?q="+reqUrl, 302) return } }
// generatePage genarates documentation page for project. // it returns false when its a invaild(empty) project. func generatePage(this *HomeController, pdoc *doc.Package, q string, lang string) bool { // Load project data from database. pdecl, err := models.LoadProject(pdoc.ImportPath) if err != nil { beego.Error("HomeController.generatePage():", err) return false } // Set properties. this.TplNames = "docs_" + lang + ".html" // Refresh (within 10 seconds). this.Data["IsRefresh"] = pdoc.Created.Add(10 * time.Second).UTC().After(time.Now().UTC()) // Get VCS name, project name, project home page, and Upper level project URL. this.Data["VCS"], this.Data["ProName"], this.Data["ProPath"], this.Data["ProDocPath"] = getVCSInfo(q, pdoc) if utils.IsGoRepoPath(pdoc.ImportPath) && strings.Index(pdoc.ImportPath, ".") == -1 { this.Data["IsGoRepo"] = true } this.Data["Views"] = pdoc.Views + 1 // Tags. this.Data["Tags"] = getTags(pdoc.Tags, lang) // Introduction. this.Data["ImportPath"] = pdoc.ImportPath byts, _ := base32.StdEncoding.DecodeString(pdecl.Doc) this.Data["PkgFullIntro"] = string(byts) var buf bytes.Buffer // Convert data format. err = ConvertDataFormat(pdoc, pdecl) if err != nil { beego.Error("HomeController.generatePage(): ConvertDataFormat", err) return false } links := make([]*utils.Link, 0, len(pdoc.Types)+len(pdoc.Imports)+len(pdoc.Funcs)+10) // Get all types, functions and import packages for _, t := range pdoc.Types { links = append(links, &utils.Link{ Name: t.Name, Comment: template.HTMLEscapeString(t.Doc), }) buf.WriteString(""" + t.Name + "",") } for _, f := range pdoc.Funcs { links = append(links, &utils.Link{ Name: f.Name, Comment: template.HTMLEscapeString(f.Doc), }) buf.WriteString(""" + f.Name + "",") } for _, t := range pdoc.Types { for _, f := range t.Funcs { links = append(links, &utils.Link{ Name: f.Name, Comment: template.HTMLEscapeString(f.Doc), }) buf.WriteString(""" + f.Name + "",") } for _, m := range t.Methods { buf.WriteString(""" + t.Name + "." + m.Name + "",") } } for _, v := range pdoc.Imports { links = append(links, &utils.Link{ Name: path.Base(v) + ".", Path: v, }) } exportDataSrc := buf.String() if len(exportDataSrc) > 0 { this.Data["HasExports"] = true exportDataSrc = exportDataSrc[:len(exportDataSrc)-1] // Set export keyword type-ahead. this.Data["ExportDataSrc"] = exportDataSrc } // Index. this.Data["IsHasConst"] = len(pdoc.Consts) > 0 this.Data["IsHasVar"] = len(pdoc.Vars) > 0 this.Data["Funcs"] = pdoc.Funcs for i, f := range pdoc.Funcs { buf.Reset() godoc.ToHTML(&buf, f.Doc, nil) f.Doc = buf.String() buf.Reset() utils.FormatCode(&buf, &f.Decl, links) f.FmtDecl = buf.String() buf.Reset() utils.FormatCode(&buf, &f.Code, links) f.Code = buf.String() pdoc.Funcs[i] = f } this.Data["Types"] = pdoc.Types for i, t := range pdoc.Types { for j, f := range t.Funcs { buf.Reset() godoc.ToHTML(&buf, f.Doc, nil) f.Doc = buf.String() buf.Reset() utils.FormatCode(&buf, &f.Decl, links) f.FmtDecl = buf.String() buf.Reset() utils.FormatCode(&buf, &f.Code, links) f.Code = buf.String() t.Funcs[j] = f } for j, m := range t.Methods { buf.Reset() godoc.ToHTML(&buf, m.Doc, nil) m.Doc = buf.String() buf.Reset() utils.FormatCode(&buf, &m.Decl, links) m.FmtDecl = buf.String() buf.Reset() utils.FormatCode(&buf, &m.Code, links) m.Code = buf.String() t.Methods[j] = m } buf.Reset() godoc.ToHTML(&buf, t.Doc, nil) t.Doc = buf.String() buf.Reset() utils.FormatCode(&buf, &t.Decl, links) t.FmtDecl = buf.String() pdoc.Types[i] = t } // Constants. this.Data["Consts"] = pdoc.Consts for i, v := range pdoc.Consts { buf.Reset() v.Decl = template.HTMLEscapeString(v.Decl) v.Decl = strings.Replace(v.Decl, """, "\"", -1) utils.FormatCode(&buf, &v.Decl, links) v.FmtDecl = buf.String() pdoc.Consts[i] = v } // Variables. this.Data["Vars"] = pdoc.Vars for i, v := range pdoc.Vars { buf.Reset() utils.FormatCode(&buf, &v.Decl, links) v.FmtDecl = buf.String() pdoc.Vars[i] = v } // Dirs. this.Data["IsHasSubdirs"] = len(pdoc.Dirs) > 0 pinfos := make([]*models.PkgInfo, 0, len(pdoc.Dirs)) for _, v := range pdoc.Dirs { v = pdoc.ImportPath + "/" + v if pinfo, err := models.GetPkgInfo(v); err == nil { pinfos = append(pinfos, pinfo) } else { pinfos = append(pinfos, &models.PkgInfo{Path: v}) } } this.Data["Subdirs"] = pinfos // Tags. this.Data["TagsDataSrc"] = tagSet this.Data["Files"] = pdoc.Files this.Data["ImportPkgs"] = pdecl.Imports this.Data["ImportPkgNum"] = len(pdoc.Imports) - 1 this.Data["IsImported"] = pdoc.ImportedNum > 0 this.Data["ImportPid"] = pdoc.ImportPid this.Data["ImportedNum"] = pdoc.ImportedNum this.Data["UtcTime"] = pdoc.Created this.Data["GOOS"] = pdecl.Goos this.Data["GOARCH"] = pdecl.Goarch return true }
// Get implemented Get method for HomeRouter. func (this *HomeRouter) Get() { // Get argument(s). q := strings.TrimRight( strings.TrimSpace(this.Input().Get("q")), "/") if path, ok := utils.IsBrowseURL(q); ok { q = path } // Get pure URL. reqUrl := this.Ctx.Request.RequestURI[1:] if i := strings.Index(reqUrl, "?"); i > -1 { reqUrl = reqUrl[:i] if path, ok := utils.IsBrowseURL(reqUrl); ok { reqUrl = path } } // Redirect to query string. if len(reqUrl) == 0 && len(q) > 0 { reqUrl = q this.Redirect("/"+reqUrl, 302) return } // User History. urpids, _ := this.Ctx.Request.Cookie("UserHistory") urpts, _ := this.Ctx.Request.Cookie("UHTimestamps") if len(reqUrl) == 0 && len(q) == 0 { serveHome(this, urpids, urpts) return } // Documentation page. broPath := reqUrl // Browse path. // Check if it's the standard library. if utils.IsGoRepoPath(broPath) { broPath = "code.google.com/p/go/source/browse/src/pkg/" + broPath } else if utils.IsGoSubrepoPath(broPath) { this.Redirect("/code.google.com/p/"+broPath, 301) return } else if strings.Index(broPath, "source/browse/") > -1 { broPath = strings.Replace(broPath, "source/browse/", "", 1) } // Check if it's a remote path that can be used for 'go get', if not means it's a keyword. if !utils.IsValidRemotePath(broPath) { // Search. this.Redirect("/search?q="+reqUrl, 302) return } // Get tag field. tag := strings.TrimSpace(this.Input().Get("tag")) if tag == "master" || tag == "default" { tag = "" } // Check documentation of current import path, update automatically as needed. pdoc, err := doc.CheckDoc(reqUrl, tag, doc.RT_Human) if err == nil { // errNoMatch leads to pdoc == nil. if pdoc != nil { // Generate documentation page. if generatePage(this, pdoc, broPath, tag) { ps, ts := updateCacheInfo(pdoc, urpids, urpts) this.Ctx.SetCookie("UserHistory", ps, 9999999999, "/") this.Ctx.SetCookie("UHTimestamps", ts, 9999999999, "/") return } } this.Redirect("/search?q="+reqUrl, 302) return } // Error. this.Data["IsHasError"] = true this.Data["ErrMsg"] = strings.Replace(err.Error(), doc.GetGithubCredentials(), "<githubCred>", 1) if !strings.Contains(err.Error(), "Cannot find Go files") { beego.Error("HomeRouter.Get ->", err) } serveHome(this, urpids, urpts) }
// 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 { beego.Error("models.DeleteProject(", path, ") -> Short path as not needed") return nil } q := connDb() defer q.Close() var i1, i2, i3, i4, i5 int64 // Delete package information. info := new(PkgInfo) err := q.WhereEqual("path", path).Find(info) if err == nil { i1, err = q.WhereEqual("path", path).Delete(info) if err != nil { beego.Error("models.DeleteProject(", path, ") -> Information:", err) } } // Delete package declaration. if info.Id > 0 { // Find. var pdecls []*PkgDecl err = q.WhereEqual("pid", info.Id).FindAll(&pdecls) if err != nil { beego.Error("models.DeleteProject(", path, ") -> Find declaration:", err) } // Update. if !utils.IsGoRepoPath(path) { for _, pd := range pdecls { // Don't need to check standard library. // Update import information. imports := strings.Split(pd.Imports, "|") imports = imports[:len(imports)-1] for _, v := range imports { if !utils.IsGoRepoPath(v) { // Only count non-standard library. updateImportInfo(q, v, int(info.Id), false) } } } } // Delete. i2, err = q.WhereEqual("pid", info.Id).Delete(new(PkgDecl)) if err != nil { beego.Error("models.DeleteProject(", path, ") -> Delete declaration:", err) } } // Delete package documentation. i3, err = q.WhereEqual("path", path).Delete(new(PkgDoc)) if err != nil { beego.Error("models.DeleteProject(", path, ") -> Documentation:", err) } // Delete package examples. i4, err = q.WhereEqual("path", path).Delete(new(PkgExam)) if err != nil { beego.Error("models.DeleteProject(", path, ") -> Examples:", err) } // Delete package functions. if info.Id > 0 { i5, err = q.WhereEqual("path", path).Delete(new(PkgExam)) if err != nil { beego.Error("models.DeleteProject(", path, ") -> Functions:", err) } } if i1+i2+i3+i4+i5 > 0 { beego.Info("models.DeleteProject(", path, i1, i2, i3, i4, i5, ")") } return nil }
// generatePage genarates documentation page for project. // it returns false when its a invaild(empty) project. func generatePage(this *HomeRouter, pdoc *doc.Package, q, tag, lang string) bool { // Load project data from database. pdecl, err := models.LoadProject(pdoc.ImportPath, tag) if err != nil { beego.Error("HomeController.generatePage ->", err) return false } // Set properties. this.TplNames = "docs_" + lang + ".html" // Refresh (within 10 seconds). this.Data["IsRefresh"] = pdoc.Created.Add(10 * time.Second).UTC().After(time.Now().UTC()) // Get VCS name, project name, project home page, and Upper level project URL. this.Data["VCS"], this.Data["ProName"], this.Data["ProPath"], this.Data["ProDocPath"] = getVCSInfo(q, tag, pdoc) if utils.IsGoRepoPath(pdoc.ImportPath) && strings.Index(pdoc.ImportPath, ".") == -1 { this.Data["IsGoRepo"] = true } this.Data["Views"] = pdoc.Views + 1 // Labels. this.Data["Labels"] = getLabels(pdoc.Labels) // Introduction. this.Data["ImportPath"] = pdoc.ImportPath byts, _ := base32.StdEncoding.DecodeString( models.LoadPkgDoc(pdoc.ImportPath, lang, "rm")) this.Data["PkgDoc"] = string(byts) byts, _ = base32.StdEncoding.DecodeString(pdecl.Doc) this.Data["PkgFullIntro"] = string(byts) var buf bytes.Buffer // Convert data format. err = ConvertDataFormat(pdoc, pdecl) if err != nil { beego.Error("HomeController.generatePage -> ConvertDataFormat:", err) return false } links := make([]*utils.Link, 0, len(pdoc.Types)+len(pdoc.Imports)+len(pdoc.Funcs)+10) // Get all types, functions and import packages for _, t := range pdoc.Types { links = append(links, &utils.Link{ Name: t.Name, Comment: template.HTMLEscapeString(t.Doc), }) buf.WriteString(""" + t.Name + "",") } for _, f := range pdoc.Funcs { links = append(links, &utils.Link{ Name: f.Name, Comment: template.HTMLEscapeString(f.Doc), }) buf.WriteString(""" + f.Name + "",") } for _, t := range pdoc.Types { for _, f := range t.Funcs { links = append(links, &utils.Link{ Name: f.Name, Comment: template.HTMLEscapeString(f.Doc), }) buf.WriteString(""" + f.Name + "",") } for _, m := range t.Methods { buf.WriteString(""" + t.Name + "." + m.Name + "",") } } for _, v := range pdoc.Imports { links = append(links, &utils.Link{ Name: path.Base(v) + ".", Path: v, }) } exportDataSrc := buf.String() if len(exportDataSrc) > 0 { this.Data["HasExports"] = true exportDataSrc = exportDataSrc[:len(exportDataSrc)-1] // Set export keyword type-ahead. this.Data["ExportDataSrc"] = exportDataSrc } // Commented and total objects number. var comNum, totalNum int // Index. this.Data["IsHasConst"] = len(pdoc.Consts) > 0 this.Data["IsHasVar"] = len(pdoc.Vars) > 0 // Constants. this.Data["Consts"] = pdoc.Consts for i, v := range pdoc.Consts { buf.Reset() v.Decl = template.HTMLEscapeString(v.Decl) v.Decl = strings.Replace(v.Decl, """, "\"", -1) utils.FormatCode(&buf, &v.Decl, links) v.FmtDecl = buf.String() pdoc.Consts[i] = v } // Variables. this.Data["Vars"] = pdoc.Vars for i, v := range pdoc.Vars { buf.Reset() utils.FormatCode(&buf, &v.Decl, links) v.FmtDecl = buf.String() pdoc.Vars[i] = v } this.Data["Funcs"] = pdoc.Funcs for i, f := range pdoc.Funcs { if len(f.Doc) > 0 { buf.Reset() godoc.ToHTML(&buf, f.Doc, nil) f.Doc = buf.String() comNum++ } buf.Reset() utils.FormatCode(&buf, &f.Decl, links) f.FmtDecl = buf.String() buf.Reset() utils.FormatCode(&buf, &f.Code, links) f.Code = buf.String() if exs := getExamples(pdoc, "", f.Name); len(exs) > 0 { f.IsHasExam = true f.Exams = exs } totalNum++ pdoc.Funcs[i] = f } this.Data["Types"] = pdoc.Types for i, t := range pdoc.Types { for j, f := range t.Funcs { if len(f.Doc) > 0 { buf.Reset() godoc.ToHTML(&buf, f.Doc, nil) f.Doc = buf.String() comNum++ } buf.Reset() utils.FormatCode(&buf, &f.Decl, links) f.FmtDecl = buf.String() buf.Reset() utils.FormatCode(&buf, &f.Code, links) f.Code = buf.String() if exs := getExamples(pdoc, "", f.Name); len(exs) > 0 { f.IsHasExam = true f.Exams = exs } totalNum++ t.Funcs[j] = f } for j, m := range t.Methods { if len(m.Doc) > 0 { buf.Reset() godoc.ToHTML(&buf, m.Doc, nil) m.Doc = buf.String() comNum++ } buf.Reset() utils.FormatCode(&buf, &m.Decl, links) m.FmtDecl = buf.String() buf.Reset() utils.FormatCode(&buf, &m.Code, links) m.Code = buf.String() if exs := getExamples(pdoc, t.Name, m.Name); len(exs) > 0 { m.IsHasExam = true m.Exams = exs } totalNum++ t.Methods[j] = m } if len(t.Doc) > 0 { buf.Reset() godoc.ToHTML(&buf, t.Doc, nil) t.Doc = buf.String() comNum++ } buf.Reset() utils.FormatCode(&buf, &t.Decl, links) t.FmtDecl = buf.String() if exs := getExamples(pdoc, "", t.Name); len(exs) > 0 { t.IsHasExam = true t.Exams = exs } totalNum++ pdoc.Types[i] = t } if !pdoc.IsCmd { // Calculate documentation complete %. this.Data["DocCPLabel"], this.Data["DocCP"] = calDocCP(comNum, totalNum) // Examples. this.Data["IsHasExams"] = len(pdoc.Examples)+len(pdoc.UserExamples) > 0 this.Data["Exams"] = append(pdoc.Examples, pdoc.UserExamples...) // Tags. this.Data["IsHasTags"] = len(pdoc.Tags) > 1 if len(tag) == 0 { tag = "master" } this.Data["CurTag"] = tag this.Data["Tags"] = pdoc.Tags } else { this.Data["IsCmd"] = true } // Dirs. this.Data["IsHasSubdirs"] = len(pdoc.Dirs) > 0 pinfos := make([]*models.PkgInfo, 0, len(pdoc.Dirs)) for _, v := range pdoc.Dirs { v = pdoc.ImportPath + "/" + v if pinfo, err := models.GetPkgInfo(v, tag); err == nil { pinfos = append(pinfos, pinfo) } else { pinfos = append(pinfos, &models.PkgInfo{Path: v}) } } this.Data["Subdirs"] = pinfos // Labels. this.Data["LabelDataSrc"] = labelSet this.Data["Files"] = pdoc.Files this.Data["ImportPkgs"] = pdecl.Imports this.Data["ImportPkgNum"] = len(pdoc.Imports) - 1 this.Data["IsImported"] = pdoc.ImportedNum > 0 this.Data["ImportPid"] = pdoc.ImportPid this.Data["ImportedNum"] = pdoc.ImportedNum this.Data["UtcTime"] = pdoc.Created return true }
// SaveProject saves package information, declaration and functions; // update import information. func SaveProject(pinfo *hv.PkgInfo, pdecl *PkgDecl, pfuncs []*PkgFunc, imports []string) error { q := connDb() defer q.Close() // Load package information(save after checked import information). info := new(hv.PkgInfo) err := q.WhereEqual("import_path", pinfo.ImportPath).Find(info) if err == nil { pinfo.Id = info.Id } // ------------------------------ // Update imported information. // ------------------------------ isMaster := pdecl != nil && len(pdecl.Tag) == 0 if info.Id > 0 { // Current package. importeds := strings.Split(info.RefPids, "|") importPids := make([]string, 0, len(importeds)) for _, v := range importeds { pid, _ := strconv.ParseInt(v, 10, 64) if checkImport(q, info.ImportPath, pid) { importPids = append(importPids, v) } } pinfo.RefPids = strings.Join(importPids, "|") pinfo.RefNum = len(importPids) } if isMaster { pimp := new(PkgImport) err := q.WhereEqual("path", pinfo.ImportPath).Find(pimp) if err == nil { importPids := strings.Split(pinfo.RefPids, "|") pimps := strings.Split(pimp.Imports, "|") for _, v := range pimps { if len(v) == 0 { continue } pid, _ := strconv.ParseInt(v, 10, 64) if i := getRefIndex(importPids, v); i == -1 && checkImport(q, info.ImportPath, pid) { importPids = append(importPids, v) } } q.WhereEqual("id", pimp.Id).Delete(pimp) pinfo.RefPids = strings.Join(importPids, "|") pinfo.RefNum = len(importPids) if pinfo.RefNum > 0 && strings.HasPrefix(pinfo.RefPids, "|") { pinfo.RefPids = pinfo.RefPids[1:] pinfo.RefNum-- } } } else { pinfo.Ptag = info.Ptag } _, err = q.Save(pinfo) if err != nil { beego.Error("models.SaveProject(", pinfo.ImportPath, ") -> Information2:", err) } // Don't need to check standard library and non-master projects. if imports != nil && isMaster && !utils.IsGoRepoPath(pinfo.ImportPath) { // Other packages. for _, v := range imports { if !utils.IsGoRepoPath(v) { // Only count non-standard library. updateImportInfo(q, v, int(pinfo.Id), int(pinfo.Rank), true) } } } // ------------- END ------------ // Save package declaration. decl := new(PkgDecl) if pdecl != nil { cond := qbs.NewCondition("pid = ?", pinfo.Id).And("tag = ?", pdecl.Tag) err = q.Condition(cond).Find(decl) if err == nil { pdecl.Id = decl.Id } pdecl.Pid = pinfo.Id _, err = q.Save(pdecl) if err != nil { beego.Error("models.SaveProject(", pinfo.ImportPath, ") -> Declaration:", err) } // ------------------------------ // Save package tag. // ------------------------------ proPath := utils.GetProjectPath(pinfo.ImportPath) if utils.IsGoRepoPath(pinfo.ImportPath) { proPath = "code.google.com/p/go" } pkgTag := new(PkgTag) cond = qbs.NewCondition("path = ?", proPath).And("tag = ?", pdecl.Tag) err = q.Condition(cond).Find(pkgTag) if err != nil { pkgTag.Path = proPath pkgTag.Tag = pdecl.Tag } pkgTag.Vcs = pinfo.Vcs pkgTag.Tags = pinfo.Tags _, err = q.Save(pkgTag) if err != nil { beego.Error("models.SaveProject(", pinfo.ImportPath, ") -> PkgTag:", err) } // ------------- END ------------ } // ------------------------------ // Save package functions. // ------------------------------ if pfuncs != nil { // Old package need to clean old data. if decl.Id > 0 { // Update all old functions' 'IsOle' to be true. type pkgFunc struct { IsOld bool } pfunc := new(pkgFunc) pfunc.IsOld = true _, err = q.WhereEqual("pid", pdecl.Id).Update(pfunc) } // Save new ones. for _, pf := range pfuncs { f := new(PkgFunc) cond := qbs.NewCondition("pid = ?", pdecl.Id).And("name = ?", pf.Name) err = q.Condition(cond).Find(f) if err == nil { pf.Id = f.Id } pf.Pid = pdecl.Id _, err = q.Save(pf) if err != nil { beego.Error("models.SaveProject(", pinfo.ImportPath, ") -> Update function(", pf.Name, "):", err) } } if decl.Id > 0 { // Delete old ones if exist. cond := qbs.NewCondition("pid = ?", pdecl.Id).And("is_old = ?", true) _, err = q.Condition(cond).Delete(new(PkgFunc)) if err != nil { beego.Error("models.SaveProject(", pinfo.ImportPath, ") -> Delete functions:", err) } } } // ------------- END ------------ return nil }
// DeleteProject deletes everything of the package, // and update import information. func DeleteProject(path string) { // Check path length to reduce connect times(except launchpad.net). if path[0] != 'l' && len(strings.Split(path, "/")) <= 2 { beego.Trace("models.DeleteProject(", path, ") -> Short path as not needed") return } var i1, i2, i3, i4, i5 int64 // Delete package information. // TODO: NEED TO DELETE ALL SUB-PEOJECTS. info := &hv.PkgInfo{ImportPath: path} has, err := x.Get(info) if err != nil { beego.Error("models.DeleteProject(", path, ") -> Get hv.PkgInfo", err) return } if has { i1, err = x.Where("import_path = ?", path).Delete(info) if err != nil { beego.Error("models.DeleteProject(", path, ") -> Information:", err) } } // Delete package declaration. if info.Id > 0 { // Find. var pdecls []PkgDecl err = x.Where("pid = ?", info.Id).Find(&pdecls) if err != nil { beego.Error("models.DeleteProject(", path, ") -> Find declaration:", err) } // Update. if !utils.IsGoRepoPath(path) { for _, pd := range pdecls { // Don't need to check standard library. // Update import information. imports := strings.Split(pd.Imports, "|") imports = imports[:len(imports)-1] for _, v := range imports { if !utils.IsGoRepoPath(v) { // Only count non-standard library. updateImportInfo(v, int(info.Id), 0, false) } } } } // Delete. i2, err = x.Where("pid = ?", info.Id).Delete(new(PkgDecl)) if err != nil { beego.Error("models.DeleteProject(", path, ") -> Delete declaration:", err) } } // Delete package examples. i4, err = x.Where("path = ?", path).Delete(new(PkgExam)) if err != nil { beego.Error("models.DeleteProject(", path, ") -> Examples:", err) } // Delete package functions. if info.Id > 0 { i5, err = x.Where("path = ?", path).Delete(new(PkgExam)) if err != nil { beego.Error("models.DeleteProject(", path, ") -> Functions:", err) } } if i1+i2+i3+i4+i5 > 0 { beego.Info("models.DeleteProject(", path, i1, i2, i3, i4, i5, ")") } return }
// SaveProject saves package information, declaration and functions; // update import information. func SaveProject(pinfo *hv.PkgInfo, pdecl *PkgDecl, pfuncs []PkgFunc, imports []string) error { // Load package information(save after checked import information). info := &hv.PkgInfo{ImportPath: pinfo.ImportPath} has, err := x.Get(info) if err != nil { return errors.New( fmt.Sprintf("models.SaveProject( %s ) -> Get hv.PkgInfo: %s", pinfo.ImportPath, err)) } if has { pinfo.Id = info.Id } // ------------------------------ // Update imported information. // ------------------------------ isMaster := pdecl != nil && len(pdecl.Tag) == 0 if info.Id > 0 { // Current package. importeds := strings.Split(info.RefPids, "|") importPids := make([]string, 0, len(importeds)) for _, v := range importeds { pid, _ := strconv.ParseInt(v, 10, 64) if checkImport(info.ImportPath, pid) { importPids = append(importPids, v) } } pinfo.RefPids = strings.Join(importPids, "|") pinfo.RefNum = len(importPids) } if isMaster { pimp := &PkgImport{Path: pinfo.ImportPath} has, err := x.Get(pimp) if err != nil { return errors.New( fmt.Sprintf("models.SaveProject( %s ) -> Get PkgImport: %s", pinfo.ImportPath, err)) } if has { importPids := strings.Split(pinfo.RefPids, "|") pimps := strings.Split(pimp.Imports, "|") for _, v := range pimps { if len(v) == 0 { continue } pid, _ := strconv.ParseInt(v, 10, 64) if i := getRefIndex(importPids, v); i == -1 && checkImport(info.ImportPath, pid) { importPids = append(importPids, v) } } _, err := x.Id(pimp.Id).Delete(pimp) if err != nil { beego.Error("models.SaveProject(", pinfo.ImportPath, ") -> Delete PkgImport:", err.Error()) } pinfo.RefPids = strings.Join(importPids, "|") pinfo.RefNum = len(importPids) if pinfo.RefNum > 0 && strings.HasPrefix(pinfo.RefPids, "|") { pinfo.RefPids = pinfo.RefPids[1:] pinfo.RefNum-- } } } else { pinfo.Ptag = info.Ptag } if has { _, err = x.Id(pinfo.Id).UseBool("is_cgo").Update(pinfo) } else { _, err = x.Insert(pinfo) } if err != nil { beego.Error("models.SaveProject(", pinfo.ImportPath, ") -> Information2:", err) } // Don't need to check standard library and non-master projects. if imports != nil && isMaster && !utils.IsGoRepoPath(pinfo.ImportPath) { // Other packages. for _, v := range imports { if !utils.IsGoRepoPath(v) && v != "C" { // Only count non-standard library. updateImportInfo(v, int(pinfo.Id), int(pinfo.Rank), true) } } } // ------------- END ------------ // Save package declaration. decl := new(PkgDecl) if pdecl != nil { has, err := x.Where("pid = ?", pinfo.Id).And("tag = ?", pdecl.Tag).Get(decl) if err != nil { beego.Error("models.SaveProject(", pinfo.Id, pdecl.Tag, ") -> Get PkgDecl:", err.Error()) } if has { pdecl.Id = decl.Id } pdecl.Pid = pinfo.Id if has { _, err = x.Id(pdecl.Id).Update(pdecl) } else { _, err = x.Insert(pdecl) } if err != nil { beego.Error("models.SaveProject(", pinfo.ImportPath, ") -> Declaration:", err) } // ------------------------------ // Save package tag. // ------------------------------ proPath := utils.GetProjectPath(pinfo.ImportPath) if utils.IsGoRepoPath(pinfo.ImportPath) { proPath = "code.google.com/p/go" } pkgTag := &PkgTag{ Path: proPath, Tag: pdecl.Tag, } has, err = x.Get(pkgTag) if err != nil { beego.Error("models.SaveProject(", proPath, pdecl.Tag, ") -> Get PkgTag:", err) } if !has { pkgTag.Path = proPath pkgTag.Tag = pdecl.Tag } pkgTag.Vcs = pinfo.Vcs pkgTag.Tags = pinfo.Tags if has { _, err = x.Id(pkgTag.Id).Update(pkgTag) } else { _, err = x.Insert(pkgTag) } if err != nil { beego.Error("models.SaveProject(", pinfo.ImportPath, ") -> Save PkgTag:", err) } // ------------- END ------------ } // ------------------------------ // Save package functions. // ------------------------------ if pfuncs != nil { // Old package need to clean old data. if decl.Id > 0 { // Update all old functions' 'IsOle' to be true. type pkgFunc struct { IsOld bool } pfunc := &pkgFunc{IsOld: true} _, err = x.Where("pid = ?", pdecl.Id).UseBool().Update(pfunc) if err != nil { beego.Error("models.SaveProject(", pdecl.Id, ") -> Mark function old:", err) } } // Save new ones. for _, pf := range pfuncs { f := &PkgFunc{ Pid: pdecl.Id, Name: pf.Name, } has, err := x.Get(f) if err != nil { beego.Error("models.SaveProject(", pdecl.Id, ") -> Get PkgFunc:", err) continue } if has { pf.Id = f.Id } pf.Pid = pdecl.Id if has { _, err = x.Id(pf.Id).UseBool().Update(pf) } else { _, err = x.Insert(pf) } if err != nil { beego.Error("models.SaveProject(", pinfo.ImportPath, ") -> Update function(", pf.Name, "):", err) } } if decl.Id > 0 { // Delete old ones if exist. _, err := x.Where("pid = ?", pdecl.Id).And("is_old = ?", true).Delete(new(PkgFunc)) if err != nil { beego.Error("models.SaveProject(", pinfo.ImportPath, ") -> Delete functions:", err) } } } // ------------- END ------------ return nil }
// SaveProject saves package information, declaration and functions; // update import information. func SaveProject(pinfo *PkgInfo, pdecl *PkgDecl, pfuncs []*PkgFunc, imports []string) error { q := connDb() defer q.Close() // Load package information(save after checked import information). info := new(PkgInfo) err := q.WhereEqual("path", pinfo.Path).Find(info) if err == nil { pinfo.Id = info.Id } // Save package declaration. decl := new(PkgDecl) if pdecl != nil { cond := qbs.NewCondition("pid = ?", pinfo.Id).And("tag = ?", pdecl.Tag) err = q.Condition(cond).Find(decl) if err == nil { pdecl.Id = decl.Id } pdecl.Pid = pinfo.Id _, err = q.Save(pdecl) if err != nil { beego.Error("models.SaveProject(", pinfo.Path, ") -> Declaration:", err) } } // ------------------------------ // Save package functions. // ------------------------------ if pfuncs != nil { // Old package need to clean old data. if decl.Id > 0 { // Update all old functions' 'IsOle' to be true. type pkgFunc struct { IsOld bool } pfunc := new(pkgFunc) pfunc.IsOld = true _, err = q.WhereEqual("pid", pdecl.Id).Update(pfunc) } isMaster := pdecl.Tag == "" // Save new ones. for _, pf := range pfuncs { f := new(PkgFunc) cond := qbs.NewCondition("pid = ?", pdecl.Id).And("name = ?", pf.Name) err = q.Condition(cond).Find(f) if err == nil { pf.Id = f.Id } pf.Pid = pdecl.Id pf.IsMaster = isMaster _, err = q.Save(pf) if err != nil { beego.Error("models.SaveProject(", pinfo.Path, ") -> Update function(", pf.Name, "):", err) } } if decl.Id > 0 { // Delete old ones if exist. cond := qbs.NewCondition("pid = ?", pdecl.Id).And("is_old = ?", true) _, err = q.Condition(cond).Delete(new(PkgFunc)) if err != nil { beego.Error("models.SaveProject(", pinfo.Path, ") -> Delete functions:", err) } } } // ------------- END ------------ // ------------------------------ // Update imported information. // ------------------------------ if info.Id > 0 { // Current package. importeds := strings.Split( strings.Replace(info.ImportPid, "$", "", -1), "|") importPids := make([]string, 0, len(importeds)) for _, v := range importeds { pid, _ := strconv.ParseInt(v, 10, 64) if checkImport(q, info.Path, pid) { importPids = append(importPids, "$"+v) } } pinfo.ImportPid = strings.Join(importPids, "|") pinfo.ImportedNum = len(importPids) } _, err = q.Save(pinfo) if err != nil { beego.Error("models.SaveProject(", pinfo.Path, ") -> Information:", err) } // Don't need to check standard library. if imports != nil && !utils.IsGoRepoPath(pinfo.Path) { // Other packages. for _, v := range imports { if !utils.IsGoRepoPath(v) { // Only count non-standard library. updateImportInfo(q, v, int(pinfo.Id), true) } } } // ------------- END ------------ return nil }
// GetPkgInfo returns 'PkgInfo' by given import path and tag. // It returns error when the package does not exist. func GetPkgInfo(path, tag string) (*hv.PkgInfo, error) { // Check path length to reduce connect times. if len(path) == 0 { return nil, errors.New("models.GetPkgInfo -> Empty path as not found.") } pinfo := &hv.PkgInfo{ImportPath: path} has, err := x.Get(pinfo) if !has || err != nil { return pinfo, errors.New( fmt.Sprintf("models.GetPkgInfo( %s:%s ) -> Get hv.PkgInfo: %v", path, tag, err)) } proPath := utils.GetProjectPath(path) if utils.IsGoRepoPath(path) { proPath = "code.google.com/p/go" } beego.Trace("models.GetPkgInfo -> proPath:", proPath) ptag := &PkgTag{ Path: proPath, Tag: tag, } has, err = x.Get(ptag) if !has || err != nil { pinfo.Ptag = "ptag" return pinfo, errors.New( fmt.Sprintf("models.GetPkgInfo( %s:%s ) -> Get PkgTag: %v", path, tag, err)) } pinfo.Vcs = ptag.Vcs pinfo.Tags = ptag.Tags // Only 'PkgInfo' cannot prove that package exists, // we have to check 'PkgDecl' as well in case it was deleted by mistake. pdecl := &PkgDecl{ Pid: pinfo.Id, Tag: tag, } has, err = x.Get(pdecl) if err != nil { return pinfo, errors.New( fmt.Sprintf("models.GetPkgInfo( %s:%s ) -> Get PkgDecl: %v", path, tag, err)) } if !has { pinfo.PkgVer = 0 pinfo.Ptag = "ptag" return pinfo, errors.New( fmt.Sprintf("models.GetPkgInfo( %s:%s ) -> PkgDecl not exist: %v", path, tag, err)) } docPath := path + utils.TagSuffix("-", tag) if !com.IsExist("." + utils.DocsJsPath + docPath + ".js") { pinfo.PkgVer = 0 pinfo.Ptag = "ptag" return pinfo, errors.New( fmt.Sprintf("models.GetPkgInfo( %s:%s ) -> JS: File not found", path, tag)) } return pinfo, nil }
// Get implemented Get method for HomeRouter. func (this *HomeRouter) Get() { // Filter unusual User-Agent. ua := this.Ctx.Request.Header.Get("User-Agent") if len(ua) < 20 { beego.Warn("User-Agent:", this.Ctx.Request.Header.Get("User-Agent")) return } // Set language version. curLang := setLangVer(this.Ctx, this.Input(), this.Data) // Get query field. q := strings.TrimSpace(this.Input().Get("q")) // Remove last "/". q = strings.TrimRight(q, "/") if path, ok := utils.IsBrowseURL(q); ok { q = path } // Get pure URL. reqUrl := this.Ctx.Request.RequestURI[1:] if i := strings.Index(reqUrl, "?"); i > -1 { reqUrl = reqUrl[:i] if path, ok := utils.IsBrowseURL(reqUrl); ok { reqUrl = path } } // Redirect to query string. if len(reqUrl) == 0 && len(q) > 0 { reqUrl = q this.Redirect("/"+reqUrl, 302) return } // Check show home page or documentation page. if len(reqUrl) == 0 && len(q) == 0 { // Home page. this.Data["IsHome"] = true this.TplNames = "home_" + curLang.Lang + ".html" // Recent projects this.Data["RecentPros"] = recentViewedPros // Get popular project and examples list from database. this.Data["PopPros"], this.Data["RecentExams"] = models.GetPopulars(20, 12) // Set standard library keyword type-ahead. this.Data["DataSrc"] = utils.GoRepoSet } else { // Documentation page. this.TplNames = "docs_" + curLang.Lang + ".html" broPath := reqUrl // Browse path. // Check if it is standard library. if utils.IsGoRepoPath(broPath) { broPath = "code.google.com/p/go/source/browse/src/pkg/" + broPath } // Check if it is a remote path that can be used for 'gopm get', if not means it's a keyword. if !utils.IsValidRemotePath(broPath) { // Show search page this.Redirect("/search?q="+reqUrl, 302) return } // Get tag field. tag := strings.TrimSpace(this.Input().Get("tag")) if tag == "master" || tag == "default" { tag = "" } // Check documentation of this import path, and update automatically as needed. pdoc, err := doc.CheckDoc(reqUrl, tag, doc.HUMAN_REQUEST) if err == nil || pdoc == nil { pdoc.UserExamples = getUserExamples(pdoc.ImportPath) // Generate documentation page. if generatePage(this, pdoc, broPath, tag, curLang.Lang) { // Update recent project list. updateRecentPros(pdoc) // Update project views. pinfo := &models.PkgInfo{ Path: pdoc.ImportPath, Synopsis: pdoc.Synopsis, Created: pdoc.Created, ProName: pdoc.ProjectName, ViewedTime: pdoc.ViewedTime, Views: pdoc.Views, IsCmd: pdoc.IsCmd, Etag: pdoc.Etag, Labels: pdoc.Labels, Tags: strings.Join(pdoc.Tags, "|||"), ImportedNum: pdoc.ImportedNum, ImportPid: pdoc.ImportPid, } models.AddViews(pinfo) return } } else { beego.Error("HomeRouter.Get ->", err) } // Show search page this.Redirect("/search?q="+reqUrl, 302) return } }