예제 #1
0
func renderDoc(this *HomeRouter, pdoc *hv.Package, q, tag, docPath string) bool {
	this.Data["PkgFullIntro"] = pdoc.Doc

	var buf bytes.Buffer
	links := make([]*utils.Link, 0, len(pdoc.Types)+len(pdoc.Imports)+len(pdoc.TestImports)+
		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 + "',")
		}
	}

	// Ignore C.
	for _, v := range append(pdoc.Imports, pdoc.TestImports...) {
		if v != "C" {
			links = append(links, &utils.Link{
				Name: path.Base(v) + ".",
				Path: v,
			})
		}
	}

	// Set exported objects type-ahead.
	exportDataSrc := buf.String()
	if len(exportDataSrc) > 0 {
		pdoc.IsHasExport = true
		this.Data["IsHasExports"] = true
		exportDataSrc = exportDataSrc[:len(exportDataSrc)-1]
		this.Data["ExportDataSrc"] = "<script>$('.search-export').typeahead({local: [" +
			exportDataSrc + "],limit: 10});</script>"
	}

	pdoc.UserExamples = getUserExamples(pdoc.ImportPath)

	pdoc.IsHasConst = len(pdoc.Consts) > 0
	pdoc.IsHasVar = len(pdoc.Vars) > 0
	if len(pdoc.Examples)+len(pdoc.UserExamples) > 0 {
		pdoc.IsHasExample = true
		this.Data["IsHasExample"] = pdoc.IsHasExample
		this.Data["Examples"] = append(pdoc.Examples, pdoc.UserExamples...)
	}

	// Commented and total objects number.
	var comNum, totalNum int

	// Constants.
	this.Data["IsHasConst"] = pdoc.IsHasConst
	this.Data["Consts"] = pdoc.Consts
	for i, v := range pdoc.Consts {
		if len(v.Doc) > 0 {
			buf.Reset()
			godoc.ToHTML(&buf, v.Doc, nil)
			v.Doc = buf.String()
		}
		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["IsHasVar"] = pdoc.IsHasVar
	this.Data["Vars"] = pdoc.Vars
	for i, v := range pdoc.Vars {
		if len(v.Doc) > 0 {
			buf.Reset()
			godoc.ToHTML(&buf, v.Doc, nil)
			v.Doc = buf.String()
		}
		buf.Reset()
		utils.FormatCode(&buf, &v.Decl, links)
		v.FmtDecl = buf.String()
		pdoc.Vars[i] = v
	}

	// Dirs.
	pinfos := models.GetSubPkgs(pdoc.ImportPath, tag, pdoc.Dirs)
	if len(pinfos) > 0 {
		pdoc.IsHasSubdir = true
		this.Data["IsHasSubdirs"] = pdoc.IsHasSubdir
		this.Data["Subdirs"] = pinfos
		this.Data["ViewDirPath"] = pdoc.ViewDirPath
	}

	// Files.
	if len(pdoc.Files) > 0 {
		pdoc.IsHasFile = true
		this.Data["IsHasFiles"] = pdoc.IsHasFile
		this.Data["Files"] = pdoc.Files

		var query string
		if i := strings.Index(pdoc.Files[0].BrowseUrl, "?"); i > -1 {
			query = pdoc.Files[0].BrowseUrl[i:]
		}
		this.Data["ViewFilePath"] = path.Dir(pdoc.Files[0].BrowseUrl) + "/" + query
	}

	var err error
	pfuncs := doc.RenderFuncs(pdoc)

	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() + " {"
		if exs := getExamples(pdoc, "", f.Name); len(exs) > 0 {
			f.Examples = exs
		}
		totalNum++
		pdoc.Funcs[i] = f
	}

	this.Data["Types"] = pdoc.Types
	for i, t := range pdoc.Types {
		for j, v := range t.Consts {
			if len(v.Doc) > 0 {
				buf.Reset()
				godoc.ToHTML(&buf, v.Doc, nil)
				v.Doc = buf.String()
			}
			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()
			t.Consts[j] = v
		}
		for j, v := range t.Vars {
			if len(v.Doc) > 0 {
				buf.Reset()
				godoc.ToHTML(&buf, v.Doc, nil)
				v.Doc = buf.String()
			}
			buf.Reset()
			utils.FormatCode(&buf, &v.Decl, links)
			v.FmtDecl = buf.String()
			t.Vars[j] = v
		}

		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() + " {"
			if exs := getExamples(pdoc, "", f.Name); len(exs) > 0 {
				f.Examples = 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() + " {"
			if exs := getExamples(pdoc, t.Name, m.Name); len(exs) > 0 {
				m.Examples = 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.Examples = exs
		}
		totalNum++
		pdoc.Types[i] = t
	}

	if !pdoc.IsCmd {
		// Calculate documentation complete %.
		this.Data["DocCPLabel"], this.Data["DocCP"] = calDocCP(comNum, totalNum)
	} else {
		this.Data["IsCmd"] = true
	}

	// Examples.
	links = append(links, &utils.Link{
		Name: path.Base(pdoc.ImportPath) + ".",
	})

	for _, e := range pdoc.Examples {
		buf.Reset()
		utils.FormatCode(&buf, &e.Code, links)
		e.Code = buf.String()
	}
	for _, e := range pdoc.UserExamples {
		buf.Reset()
		utils.FormatCode(&buf, &e.Code, links)
		e.Code = buf.String()
	}

	this.Data["ImportPath"] = pdoc.ImportPath

	if len(tag) == 0 && (pdoc.IsCmd || pdoc.IsGoRepo || pdoc.IsGoSubrepo) {
		this.Data["IsHasHv"] = true
	}

	// GitHub redirects non-HTTPS link and Safari loses "#XXX".
	if strings.HasPrefix(pdoc.ImportPath, "github") {
		this.Data["Secure"] = "s"
	}

	this.TplNames = "tpl/docs.tpl"
	data, err := this.RenderBytes()
	if err != nil {
		beego.Error("generatePage(", pdoc.ImportPath, ") -> RenderBytes:", err)
		return false
	}

	n := utils.SaveDocPage(docPath, com.Html2JS(data))
	if n == -1 {
		return false
	}
	pdoc.JsNum = n
	pdoc.Id, err = doc.SaveProject(pdoc, pfuncs)
	if err != nil {
		beego.Error("generatePage(", pdoc.ImportPath, ") -> SaveProject:", err)
		return false
	}

	models.SavePkgDoc(pdoc.ImportPath, pdoc.Readme)

	this.Data["UtcTime"] = pdoc.Created
	this.Data["TimeSince"] = calTimeSince(pdoc.Created)
	return true
}
예제 #2
0
// build generates data from source files.
func (w *walker) build(srcs []*source) (*Package, error) {
	// Set created time.
	w.pdoc.Created = time.Now().UTC()

	// Add source files to walker, I skipped references here.
	w.srcs = make(map[string]*source)
	for _, src := range srcs {
		srcName := strings.ToLower(src.name) // For readme comparation.
		switch {
		case strings.HasSuffix(src.name, ".go"):
			w.srcs[src.name] = src
		case len(w.pdoc.Tag) > 0:
			continue // Only save latest readme.
		case strings.HasPrefix(srcName, "readme_zh") || strings.HasPrefix(srcName, "readme_cn"):
			models.SavePkgDoc(w.pdoc.ImportPath, "zh", src.data)
		case strings.HasPrefix(srcName, "readme"):
			models.SavePkgDoc(w.pdoc.ImportPath, "en", src.data)
		}
	}

	w.fset = token.NewFileSet()

	// Find the package and associated files.
	ctxt := build.Context{
		GOOS:          runtime.GOOS,
		GOARCH:        runtime.GOARCH,
		CgoEnabled:    true,
		JoinPath:      path.Join,
		IsAbsPath:     path.IsAbs,
		SplitPathList: func(list string) []string { return strings.Split(list, ":") },
		IsDir:         func(path string) bool { panic("unexpected") },
		HasSubdir:     func(root, dir string) (rel string, ok bool) { panic("unexpected") },
		ReadDir:       func(dir string) (fi []os.FileInfo, err error) { return w.readDir(dir) },
		OpenFile:      func(path string) (r io.ReadCloser, err error) { return w.openFile(path) },
		Compiler:      "gc",
	}

	bpkg, err := ctxt.ImportDir(w.pdoc.ImportPath, 0)
	// Continue if there are no Go source files; we still want the directory info.
	_, nogo := err.(*build.NoGoError)
	if err != nil {
		if nogo {
			err = nil
			beego.Info("doc.walker.build -> No Go Source file")
		} else {
			return w.pdoc, errors.New("doc.walker.build -> " + err.Error())
		}
	}

	// Parse the Go files
	files := make(map[string]*ast.File)
	for _, name := range append(bpkg.GoFiles, bpkg.CgoFiles...) {
		file, err := parser.ParseFile(w.fset, name, w.srcs[name].data, parser.ParseComments)
		if err != nil {
			beego.Error("doc.walker.build -> parse go files:", err)
			continue
		}
		w.pdoc.Files = append(w.pdoc.Files, name)
		//w.pdoc.SourceSize += len(w.srcs[name].data)
		files[name] = file
	}

	apkg, _ := ast.NewPackage(w.fset, files, simpleImporter, nil)

	// Find examples in the test files.
	for _, name := range append(bpkg.TestGoFiles, bpkg.XTestGoFiles...) {
		file, err := parser.ParseFile(w.fset, name, w.srcs[name].data, parser.ParseComments)
		if err != nil {
			beego.Error("doc.walker.build -> find examples:", err)
			continue
		}
		//w.pdoc.TestFiles = append(w.pdoc.TestFiles, &File{Name: name, URL: w.srcs[name].browseURL})
		//w.pdoc.TestSourceSize += len(w.srcs[name].data)
		w.examples = append(w.examples, doc.Examples(file)...)
	}

	//w.vetPackage(apkg)

	mode := doc.Mode(0)
	if w.pdoc.ImportPath == "builtin" {
		mode |= doc.AllDecls
	}

	pdoc := doc.New(apkg, w.pdoc.ImportPath, mode)

	w.pdoc.Synopsis = utils.Synopsis(pdoc.Doc)
	pdoc.Doc = strings.TrimRight(pdoc.Doc, " \t\n\r")
	var buf bytes.Buffer
	doc.ToHTML(&buf, pdoc.Doc, nil)
	w.pdoc.Doc = w.pdoc.Doc + "<br />" + buf.String()
	w.pdoc.Doc = strings.Replace(w.pdoc.Doc, "<p>", "<p><b>", 1)
	w.pdoc.Doc = strings.Replace(w.pdoc.Doc, "</p>", "</b></p>", 1)
	w.pdoc.Doc = base32.StdEncoding.EncodeToString([]byte(w.pdoc.Doc))

	w.pdoc.Examples = w.getExamples("")
	w.pdoc.IsCmd = bpkg.IsCommand()
	w.srcLines = make(map[string][]string)
	w.pdoc.Consts = w.values(pdoc.Consts)
	w.pdoc.Funcs = w.funcs(pdoc.Funcs)
	w.pdoc.Types = w.types(pdoc.Types)
	w.pdoc.Vars = w.values(pdoc.Vars)
	//w.pdoc.Notes = w.notes(pdoc.Notes)

	w.pdoc.Imports = bpkg.Imports
	w.pdoc.TestImports = bpkg.TestImports
	//w.pdoc.XTestImports = bpkg.XTestImports

	beego.Info("doc.walker.build(", pdoc.ImportPath, "), Goroutine #", runtime.NumGoroutine())
	return w.pdoc, err
}