// 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 := make([]*models.PkgInfo, 0, 15) for _, v := range pkgs { if pinfo, err := models.GetPkgInfo(v); err == nil { pinfos = append(pinfos, pinfo) } else { pinfos = append(pinfos, &models.PkgInfo{Path: v}) } } if len(pinfos) > 0 { this.Data["IsFindPro"] = true this.Data["AllPros"] = pinfos } return true } return false }
// CheckGoPackage checks package by import path. func CheckPackage(importPath string, render macaron.Render, rt requestType) (*models.PkgInfo, error) { // Trim prefix of standard library. importPath = strings.TrimPrefix(importPath, "github.com/golang/go/tree/master/src") pinfo, err := models.GetPkgInfo(importPath) if rt != REQUEST_TYPE_REFRESH { if err == nil { fpath := setting.DocsGobPath + importPath + ".gob" if !setting.ProdMode && com.IsFile(fpath) { pdoc := new(Package) fr, err := os.Open(fpath) if err != nil { return nil, fmt.Errorf("read gob: %v", err) } else if err = gob.NewDecoder(fr).Decode(pdoc); err != nil { fr.Close() return nil, fmt.Errorf("decode gob: %v", err) } fr.Close() if err = renderDoc(render, pdoc, importPath); err != nil { return nil, fmt.Errorf("render cached doc: %v", err) } } pinfo.Views++ if err = models.SavePkgInfo(pinfo); err != nil { return nil, fmt.Errorf("update views: %v", err) } return pinfo, nil } } // Just in case, should never happen. if err == models.ErrEmptyPackagePath { return nil, err } var etag string if err != models.ErrPackageVersionTooOld && pinfo != nil { etag = pinfo.Etag } // Fetch package from VCS. c := make(chan crawlResult, 1) go func() { pdoc, err := crawlDoc(importPath, etag) c <- crawlResult{pdoc, err} }() var pdoc *Package err = nil // Reset. select { case cr := <-c: if cr.err == nil { pdoc = cr.pdoc } else { err = cr.err } case <-time.After(setting.FetchTimeout): err = ErrFetchTimeout } if err != nil { if err == ErrPackageNotModified { log.Debug("Package has not been modified: %s", pinfo.ImportPath) // Update time so cannot refresh too often. pinfo.Created = time.Now().UTC().Unix() return pinfo, models.SavePkgInfo(pinfo) } else if err == ErrInvalidRemotePath { return nil, ErrInvalidRemotePath // Allow caller to make redirect to search. } return nil, fmt.Errorf("check package: %v", err) } if !setting.ProdMode { fpath := setting.DocsGobPath + importPath + ".gob" os.MkdirAll(path.Dir(fpath), os.ModePerm) fw, err := os.Create(fpath) if err != nil { return nil, fmt.Errorf("create gob: %v", err) } defer fw.Close() if err = gob.NewEncoder(fw).Encode(pdoc); err != nil { return nil, fmt.Errorf("encode gob: %v", err) } } log.Info("Walked package: %s, Goroutine #%d", pdoc.ImportPath, runtime.NumGoroutine()) if err = renderDoc(render, pdoc, importPath); err != nil { return nil, fmt.Errorf("render doc: %v", err) } if pinfo != nil { pdoc.Id = pinfo.Id } pdoc.Created = time.Now().UTC().Unix() if err = models.SavePkgInfo(pdoc.PkgInfo); err != nil { return nil, fmt.Errorf("SavePkgInfo: %v", err) } return pdoc.PkgInfo, nil }
// 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 }
// CheckDoc checks the project documentation from the database or from the version // control system as needed. func CheckDoc(path, tag string, requestType int) (*Package, error) { // Package documentation and crawl sign. pdoc, needsCrawl := &Package{}, false // Reduce standard library path. if i := strings.Index(path, "/src/pkg/"); i > -1 { path = path[i+len("/src/pkg/"):] } // For code.google.com. path = strings.Replace(path, "source/browse/", "", 1) // Get the package documentation from database. pinfo, err := models.GetPkgInfo(path, tag) // If PACKAGE_VER does not match, refresh anyway. if err != nil || !strings.HasPrefix(pinfo.Etag, PACKAGE_VER) { // No package information in database. needsCrawl = true } else { // Check request type. switch requestType { case HUMAN_REQUEST: // Error means it does not exist. if err != nil { needsCrawl = true } else { // Check if the documentation is too old (1 day ago). needsCrawl = pinfo.Created.Add(_TIME_DAY).UTC().Before(time.Now().UTC()) } case REFRESH_REQUEST: if len(tag) > 0 { break // Things of Tag will not be changed. } // Check if the documentation is too frequently (within 5 minutes). needsCrawl = pinfo.Created.Add(_REFRESH_LIMIT).UTC().Before(time.Now().UTC()) if !needsCrawl { // Return error messages as limit time information. return nil, errors.New(pinfo.Created.Add(_REFRESH_LIMIT).UTC().String()) } } } if needsCrawl { // Fetch package from VCS. c := make(chan crawlResult, 1) go func() { pdoc, err = crawlDoc(path, tag, pinfo) c <- crawlResult{pdoc, err} }() select { case cr := <-c: if cr.err == nil { pdoc = cr.pdoc } err = cr.err case <-time.After(_FETCH_TIMEOUT): err = errUpdateTimeout } if err != nil { switch { case err == errNotModified: beego.Info("Serving(", path, ")without modified") pdoc = &Package{} pinfo.Created = time.Now().UTC() assginPkgInfo(pdoc, pinfo) return pdoc, nil case pdoc != nil && len(pdoc.ImportPath) > 0: beego.Error("Serving(", path, ")with error:", err) return pdoc, nil case err == errUpdateTimeout: // Handle timeout on packages never seen before as not found. beego.Error("Serving(", path, ")as not found after timeout") return nil, errors.New("doc.CheckDoc -> " + err.Error()) } } } else { assginPkgInfo(pdoc, pinfo) } return pdoc, err }
// 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 }
func (this *ApiRouter) PkgInfo() { pkginfo, _ := models.GetPkgInfo(this.GetString("pkgname"), "") this.Data["json"] = &pkginfo this.ServeJson(true) }
// 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 }
// CheckDoc checks the project documentation from the database or from the version // control system as needed. func CheckDoc(path string, requestType int) (*Package, error) { // Package documentation and crawl sign. pdoc, needsCrawl := &Package{}, false if i := strings.Index(path, "/src/pkg/"); i > -1 { path = path[i+len("/src/pkg/"):] } // Get the package documentation from database. pinfo, err := models.GetPkgInfo(path) if err != nil || !strings.HasPrefix(pinfo.Etag, PACKAGE_VER) { // No package information in database. needsCrawl = true } else { // Check request type. switch requestType { case HUMAN_REQUEST: // Error means it does not exist. if err != nil { needsCrawl = true } else { // Check if the documentation is too old (1 day ago). needsCrawl = pinfo.Created.Add(_TIME_DAY).UTC().Before(time.Now().UTC()) } case REFRESH_REQUEST: // Check if the documentation is too frequently (within 5 minutes). needsCrawl = pinfo.Created.Add(5 * time.Minute).UTC().Before(time.Now().UTC()) if !needsCrawl { // Return error messages as limit time information. return nil, errors.New(pinfo.Created.Add(5 * time.Minute).UTC().String()) } } } if needsCrawl { // Fetch package from VCS. c := make(chan crawlResult, 1) go func() { pdoc, err = crawlDoc(path, pinfo.Etag, pinfo.Views) c <- crawlResult{pdoc, err} }() var err error select { case cr := <-c: if cr.err == nil { pdoc = cr.pdoc } err = cr.err case <-time.After(_FETCH_TIMEOUT): err = errUpdateTimeout } if err != nil { switch { case pdoc != nil: beego.Error("Serving", path, "from database after error: ", err) return pdoc, nil case err == errUpdateTimeout: // Handle timeout on packages never seen before as not found. beego.Error("Serving", path, "as not found after timeout") return nil, errors.New("Status not found") case err == errNotModified: beego.Info("Serving", path, "without modified") err = nil pinfo.Created = time.Now().UTC() pdoc = &Package{} assginPkgInfo(pdoc, pinfo) } } } else { assginPkgInfo(pdoc, pinfo) } return pdoc, nil }
// CheckDoc returns 'Package' by given import path and tag, // or fetch from the VCS and render as needed. // It returns error when error occurs in the underlying functions. func CheckDoc(broPath, tag string, rt requestType) (*hv.Package, error) { // Package documentation and crawl sign. pdoc, needsCrawl := &hv.Package{}, false // Trim prefix of standard library path. broPath = strings.TrimPrefix(broPath, "code.google.com/p/go/source/browse/src/pkg/") // Check Block List. if strings.Contains(utils.Cfg.MustValue("info", "block_list"), "|"+broPath+"|") { return nil, errors.New("Unable to process the operation bacause " + broPath + " is in the Block List") } // Get the package info. pinfo, err := models.GetPkgInfo(broPath, tag) switch { case err != nil: // Error means it does not exist. beego.Trace("doc.CheckDoc -> ", err) // Check if it's "Error 1040: Too many connections" if strings.Contains(err.Error(), "Error 1040:") { break } fallthrough case err != nil || pinfo.PkgVer != hv.PACKAGE_VER: // If PACKAGE_VER does not match, refresh anyway. pinfo.PkgVer = 0 pinfo.Ptag = "ptag" needsCrawl = true default: // Check request type. switch rt { case RT_Human: case RT_Refresh: if len(tag) > 0 { break // Things of Tag will not be changed. } // Check if the refresh operation is too frequently (within 5 minutes). needsCrawl = time.Unix(pinfo.Created, 0).Add(_REFRESH_LIMIT).Before(time.Now()) if !needsCrawl { // Return limit time information as error message. return nil, errors.New(time.Unix(pinfo.Created, 0).Add(_REFRESH_LIMIT).UTC().String()) } } } if needsCrawl { // Fetch package from VCS. c := make(chan crawlResult, 1) go func() { // TODO pdoc, err = crawlDoc(broPath, tag, pinfo) c <- crawlResult{pdoc, err} }() select { case cr := <-c: if cr.err == nil { pdoc = cr.pdoc } err = cr.err case <-time.After(_FETCH_TIMEOUT): err = errUpdateTimeout } if pdoc == nil { if err != nil && strings.HasPrefix(err.Error(), "Cannot find Go files") && len(tag) == 0 { beego.Info("Added to block list:", broPath) utils.Cfg.SetValue("info", "block_list", utils.Cfg.MustValue("info", "block_list")+broPath+"|") utils.SaveConfig() } return nil, err } if err == nil { pdoc.IsNeedRender = true beego.Info("doc.CheckDoc(", pdoc.ImportPath, tag, "), Goroutine #", runtime.NumGoroutine()) } else { switch { case err == errNotModified: beego.Info("Serving(", broPath, ")without modified") pdoc = &hv.Package{} pinfo.Created = time.Now().UTC().Unix() pdoc.PkgInfo = pinfo return pdoc, nil case len(pdoc.ImportPath) > 0: return pdoc, err case err == errUpdateTimeout: // Handle timeout on packages never seen before as not found. beego.Error("Serving(", broPath, ")as not found after timeout") return nil, errors.New("doc.CheckDoc -> " + err.Error()) } } } else { pdoc.PkgInfo = pinfo } return pdoc, err }