Beispiel #1
0
// 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
}
Beispiel #2
0
// 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
}
Beispiel #3
0
// 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
}
Beispiel #4
0
// 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
}
Beispiel #5
0
// 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("&quot;" + t.Name + "&quot;,")
	}

	for _, f := range pdoc.Funcs {
		links = append(links, &utils.Link{
			Name:    f.Name,
			Comment: template.HTMLEscapeString(f.Doc),
		})
		buf.WriteString("&quot;" + f.Name + "&quot;,")
	}

	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("&quot;" + f.Name + "&quot;,")
		}

		for _, m := range t.Methods {
			buf.WriteString("&quot;" + t.Name + "." + m.Name + "&quot;,")
		}
	}

	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, "&#34;", "\"", -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
}
Beispiel #6
0
func (this *ApiRouter) PkgInfo() {
	pkginfo, _ := models.GetPkgInfo(this.GetString("pkgname"), "")
	this.Data["json"] = &pkginfo
	this.ServeJson(true)
}
Beispiel #7
0
// 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("&quot;" + t.Name + "&quot;,")
	}

	for _, f := range pdoc.Funcs {
		links = append(links, &utils.Link{
			Name:    f.Name,
			Comment: template.HTMLEscapeString(f.Doc),
		})
		buf.WriteString("&quot;" + f.Name + "&quot;,")
	}

	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("&quot;" + f.Name + "&quot;,")
		}

		for _, m := range t.Methods {
			buf.WriteString("&quot;" + t.Name + "." + m.Name + "&quot;,")
		}
	}

	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, "&#34;", "\"", -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
}
Beispiel #8
0
// 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
}
Beispiel #9
0
// 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
}