nitc :: Catalog :: _contrib2proj
Packages by contributorsnitc :: Catalog :: _documentation_score
Documentation score (between 0 and 100)nitc :: Catalog :: _maint2proj
Packages by maintainernitc :: Catalog :: _mpackages
List of all packages by their namesnitc :: Catalog :: _mpackages_stats
Package statistics cachenitc :: Catalog :: _name2person
Map person short names to person objectsnitc :: Catalog :: _piwik_tracker
Piwik tracker URL, if anynitc :: Catalog :: _warnings_per_kloc
Number of warnings per 1000 lines of code (w/kloc)nitc :: Catalog :: build_catalog
Build the catalog for Nitxnitc :: Catalog :: build_catalog
Build the catalog frommpackages
nitc :: Catalog :: catalog_stats=
Compose catalog statsnitc :: Catalog :: contrib2proj
Packages by contributorsnitc :: Catalog :: contrib2proj=
Packages by contributorsnitc :: Catalog :: defaultinit
nitc :: Catalog :: documentation_score
Documentation score (between 0 and 100)nitc :: Catalog :: documentation_score=
Documentation score (between 0 and 100)nitc :: Catalog :: gen_content_level
Recursively generate a level in the file tree of the content sectionnitc :: Catalog :: generate_page
Generate a full HTML page for a packagenitc :: Catalog :: li_package
Return a short HTML sequence for a packagenitc :: Catalog :: maint2proj=
Packages by maintainernitc :: Catalog :: modelbuilder=
The modelbuildernitc :: Catalog :: mpackage_stats
Compose package statsnitc :: Catalog :: mpackages=
List of all packages by their namesnitc :: Catalog :: mpackages_stats
Package statistics cachenitc :: Catalog :: mpackages_stats=
Package statistics cachenitc :: Catalog :: name2person
Map person short names to person objectsnitc :: Catalog :: name2person=
Map person short names to person objectsnitc :: Catalog :: package_page
Compute information for a packagenitc :: Catalog :: piwik_tracker=
Piwik tracker URL, if anynitc :: Catalog :: register_contrib
Scan, register and add a contributor to a packagenitc :: Catalog :: table_packages
Produce a HTML table containig information on the packagesnitc :: Catalog :: warnings_per_kloc
Number of warnings per 1000 lines of code (w/kloc)nitc :: Catalog :: warnings_per_kloc=
Number of warnings per 1000 lines of code (w/kloc)nitc :: Catalog :: _contrib2proj
Packages by contributorsnitc :: Catalog :: _documentation_score
Documentation score (between 0 and 100)nitc :: Catalog :: _maint2proj
Packages by maintainernitc :: Catalog :: _mpackages
List of all packages by their namesnitc :: Catalog :: _mpackages_stats
Package statistics cachenitc :: Catalog :: _name2person
Map person short names to person objectsnitc :: Catalog :: _piwik_tracker
Piwik tracker URL, if anynitc :: Catalog :: _warnings_per_kloc
Number of warnings per 1000 lines of code (w/kloc)nitc :: Catalog :: build_catalog
Build the catalog for Nitxnitc :: Catalog :: build_catalog
Build the catalog frommpackages
nitc :: Catalog :: catalog_stats=
Compose catalog statscore :: Object :: class_factory
Implementation used byget_class
to create the specific class.
nitc :: Catalog :: contrib2proj
Packages by contributorsnitc :: Catalog :: contrib2proj=
Packages by contributorsnitc :: Catalog :: defaultinit
core :: Object :: defaultinit
nitc :: Catalog :: documentation_score
Documentation score (between 0 and 100)nitc :: Catalog :: documentation_score=
Documentation score (between 0 and 100)nitc :: Catalog :: gen_content_level
Recursively generate a level in the file tree of the content sectionnitc :: Catalog :: generate_page
Generate a full HTML page for a packagecore :: Object :: is_same_instance
Return true ifself
and other
are the same instance (i.e. same identity).
core :: Object :: is_same_serialized
Isself
the same as other
in a serialization context?
core :: Object :: is_same_type
Return true ifself
and other
have the same dynamic type.
nitc :: Catalog :: li_package
Return a short HTML sequence for a packagenitc :: Catalog :: maint2proj=
Packages by maintainernitc :: Catalog :: modelbuilder=
The modelbuildernitc :: Catalog :: mpackage_stats
Compose package statsnitc :: Catalog :: mpackages=
List of all packages by their namesnitc :: Catalog :: mpackages_stats
Package statistics cachenitc :: Catalog :: mpackages_stats=
Package statistics cachenitc :: Catalog :: name2person
Map person short names to person objectsnitc :: Catalog :: name2person=
Map person short names to person objectscore :: Object :: native_class_name
The class name of the object in CString format.core :: Object :: output_class_name
Display class name on stdout (debug only).nitc :: Catalog :: package_page
Compute information for a packagenitc :: Catalog :: piwik_tracker=
Piwik tracker URL, if anynitc :: Catalog :: register_contrib
Scan, register and add a contributor to a packagenitc :: Catalog :: table_packages
Produce a HTML table containig information on the packagesnitc :: Catalog :: warnings_per_kloc
Number of warnings per 1000 lines of code (w/kloc)nitc :: Catalog :: warnings_per_kloc=
Number of warnings per 1000 lines of code (w/kloc)
# The main class of the calatog generator that has the knowledge
class Catalog
# The modelbuilder
# used to access the files and count source lines of code
var modelbuilder: ModelBuilder
# List of all packages by their names
var mpackages = new HashMap[String, MPackage]
# Packages by tag
var tag2proj = new MultiHashMap[String, MPackage]
# Packages by category
var cat2proj = new MultiHashMap[String, MPackage]
# Packages by maintainer
var maint2proj = new MultiHashMap[Person, MPackage]
# Packages by contributors
var contrib2proj = new MultiHashMap[Person, MPackage]
# Dependency between packages
fun deps: HashDigraph[MPackage] do return modelbuilder.model.mpackage_importation_graph
# Number of modules by package
var mmodules = new Counter[MPackage]
# Number of classes by package
var mclasses = new Counter[MPackage]
# Number of methods by package
var mmethods = new Counter[MPackage]
# Number of line of code by package
var loc = new Counter[MPackage]
# Number of errors
var errors = new Counter[MPackage]
# Number of warnings and advices
var warnings = new Counter[MPackage]
# Number of warnings per 1000 lines of code (w/kloc)
var warnings_per_kloc = new Counter[MPackage]
# Documentation score (between 0 and 100)
var documentation_score = new Counter[MPackage]
# Number of commits by package
var commits = new Counter[MPackage]
# Score by package
#
# The score is loosely computed using other metrics
var score = new Counter[MPackage]
# List of known people by their git string
var persons = new HashMap[String, Person]
# Map person short names to person objects
var name2person = new HashMap[String, Person]
# Package statistics cache
var mpackages_stats = new HashMap[MPackage, MPackageStats]
# Scan, register and add a contributor to a package
fun register_contrib(person: String, mpackage: MPackage): Person
do
var p = persons.get_or_null(person)
if p == null then
var new_p = new Person.parse(person)
# Maybe, we already have this person in fact?
p = persons.get_or_null(new_p.to_s)
if p == null then
p = new_p
persons[p.to_s] = p
end
end
var projs = contrib2proj[p]
if not projs.has(mpackage) then
projs.add mpackage
mpackage.metadata.contributors.add p
end
name2person[p.name] = p
return p
end
# Compute information for a package
fun package_page(mpackage: MPackage)
do
mpackages[mpackage.full_name] = mpackage
var score = score[mpackage].to_f
var mdoc = mpackage.mdoc_or_fallback
if mdoc != null then
score += 100.0
score += mdoc.content.length.score
end
var metadata = mpackage.metadata
var tryit = metadata.tryit
if tryit != null then
score += 1.0
end
var apk = metadata.apk
if apk != null then
score += 1.0
end
var homepage = metadata.homepage
if homepage != null then
score += 5.0
end
var maintainer = metadata.maintainer
if maintainer != null then
score += 5.0
var person = register_contrib(maintainer, mpackage)
mpackage.metadata.maintainers.add person
var projs = maint2proj[person]
if not projs.has(mpackage) then projs.add mpackage
end
var license = metadata.license
if license != null then
score += 5.0
end
var browse = metadata.browse
if browse != null then
score += 5.0
end
var tags = metadata.tags
for tag in tags do
tag2proj[tag].add mpackage
end
if tags.not_empty then
var cat = tags.first
cat2proj[cat].add mpackage
score += tags.length.score
end
if deps.has_vertex(mpackage) then
score += deps.predecessors(mpackage).length.score
score += deps.get_all_predecessors(mpackage).length.score
score += deps.successors(mpackage).length.score
score += deps.get_all_successors(mpackage).length.score
end
var contributors = mpackage.metadata.contributors
var more_contributors = metadata.more_contributors
for c in more_contributors do
register_contrib(c, mpackage)
end
score += contributors.length.to_f
var mmodules = 0
var mclasses = 0
var mmethods = 0
var loc = 0
var errors = 0
var warnings = 0
# The documentation value of each entity is ad hoc.
var entity_score = 0.0
var doc_score = 0.0
for g in mpackage.mgroups do
mmodules += g.mmodules.length
var gs = 1.0
entity_score += gs
if g.mdoc != null then doc_score += gs
for m in g.mmodules do
var source = m.location.file
if source != null then
for msg in source.messages do
if msg.level == 2 then
errors += 1
else
warnings += 1
end
end
end
var am = modelbuilder.mmodule2node(m)
if am != null then
var file = am.location.file
if file != null then
loc += file.line_starts.length - 1
end
end
var ms = gs
if m.is_test then ms /= 100.0
entity_score += ms
if m.mdoc != null then doc_score += ms else ms /= 10.0
for cd in m.mclassdefs do
var cs = ms * 0.2
if not cd.is_intro then cs /= 100.0
if not cd.mclass.visibility <= private_visibility then cs /= 100.0
entity_score += cs
if cd.mdoc != null then doc_score += cs
mclasses += 1
for pd in cd.mpropdefs do
var ps = ms * 0.1
if not pd.is_intro then ps /= 100.0
if not pd.mproperty.visibility <= private_visibility then ps /= 100.0
entity_score += ps
if pd.mdoc != null then doc_score += ps
if not pd isa MMethodDef then continue
mmethods += 1
end
end
end
end
self.mmodules[mpackage] = mmodules
self.mclasses[mpackage] = mclasses
self.mmethods[mpackage] = mmethods
self.loc[mpackage] = loc
self.errors[mpackage] = errors
self.warnings[mpackage] = warnings
if loc > 0 then
self.warnings_per_kloc[mpackage] = warnings * 1000 / loc
end
var documentation_score = (100.0 * doc_score / entity_score).to_i
self.documentation_score[mpackage] = documentation_score
#score += mmodules.score
score += mclasses.score
score += mmethods.score
score += loc.score
score += documentation_score.score
self.score[mpackage] = score.to_i
end
# Collect more information on a package using the `git` tool.
fun git_info(mpackage: MPackage)
do
var ini = mpackage.ini
if ini == null then return
var root = mpackage.root
if root == null then return
# TODO use real git info
#var repo = ini.get_or_null("upstream.git")
#var branch = ini.get_or_null("upstream.git.branch")
#var directory = ini.get_or_null("upstream.git.directory")
var dirpath = root.filepath
if dirpath == null then return
# Collect commits info
var res = git_run("log", "--no-merges", "--follow", "--pretty=tformat:%ad;%aN <%aE>", "--", dirpath)
var contributors = new Counter[String]
var commits = res.split("\n")
if commits.not_empty and commits.last == "" then commits.pop
self.commits[mpackage] = commits.length
for l in commits do
var s = l.split_once_on(';')
if s.length != 2 or s.last == "" then continue
# Collect date of last and first commit
if mpackage.metadata.last_date == null then mpackage.metadata.last_date = s.first
mpackage.metadata.first_date = s.first
# Count contributors
contributors.inc(s.last)
end
for c in contributors.sort.reverse_iterator do
register_contrib(c, mpackage)
end
end
# Compose package stats
fun mpackage_stats(mpackage: MPackage): MPackageStats do
var stats = new MPackageStats
stats.mmodules = mmodules[mpackage]
stats.mclasses = mclasses[mpackage]
stats.mmethods = mmethods[mpackage]
stats.loc = loc[mpackage]
stats.errors = errors[mpackage]
stats.warnings = warnings[mpackage]
stats.warnings_per_kloc = warnings_per_kloc[mpackage]
stats.documentation_score = documentation_score[mpackage]
stats.commits = commits[mpackage]
stats.score = score[mpackage]
mpackages_stats[mpackage] = stats
return stats
end
# Compose catalog stats
var catalog_stats: CatalogStats is lazy do
var stats = new CatalogStats
stats.packages = mpackages.length
stats.maintainers = maint2proj.length
stats.contributors = contrib2proj.length
stats.tags = tag2proj.length
stats.modules = mmodules.sum
stats.classes = mclasses.sum
stats.methods = mmethods.sum
stats.loc = loc.sum
return stats
end
end
src/catalog/catalog.nit:246,1--543,3
redef class Catalog
redef init
do
# Register `self` to the global NitdocDecorator
# FIXME this is ugly. But no better idea at the moment.
modelbuilder.model.nitdoc_md_processor.decorator.as(NitdocDecorator).catalog = self
end
# The output directory where to generate pages
var outdir: String is noautoinit
# Return a empty `CatalogPage`.
fun new_page(rootpath: String): CatalogPage
do
return new CatalogPage(self, rootpath)
end
# Recursively generate a level in the file tree of the *content* section
private fun gen_content_level(ot: OrderedTree[MConcern], os: Array[Object], res: Template)
do
res.add "<ul>\n"
for o in os do
res.add "<li>"
if o isa MGroup then
var d = ""
var mdoc = o.mdoc
if mdoc != null then d = ": {mdoc.html_synopsis.write_to_string}"
res.add "<strong>{o.name}</strong>{d} ({o.filepath.to_s})"
else if o isa MModule then
var d = ""
var mdoc = o.mdoc
if mdoc != null then d = ": {mdoc.html_synopsis.write_to_string}"
res.add "<strong>{o.name}</strong>{d} ({o.filepath.to_s})"
else
abort
end
var subs = ot.sub.get_or_null(o)
if subs != null then gen_content_level(ot, subs, res)
res.add "</li>\n"
end
res.add "</ul>\n"
end
# Generate a full HTML page for a package
fun generate_page(mpackage: MPackage): Writable
do
var res = new_page("..")
var name = mpackage.name.html_escape
res.more_head.add """<title>{{{name}}}</title>"""
res.add """<div class="content">"""
var mdoc = mpackage.mdoc_or_fallback
if mdoc == null then
res.add """<h1 class="package-name">{{{name}}}</h1>"""
else
res.add """
<div style="float: left">
<h1 class="package-name">{{{name}}} - </h1>
</div>
"""
res.add mdoc.html_documentation
end
res.add "<h2>Content</h2>"
var ot = new OrderedTree[MConcern]
for g in mpackage.mgroups do
var pa = g.parent
if g.is_interesting then
ot.add(pa, g)
pa = g
end
for mp in g.mmodules do
ot.add(pa, mp)
end
end
ot.sort_with(alpha_comparator)
gen_content_level(ot, ot.roots, res)
res.add """
</div>
<div class="sidebar">
<ul class="box">
"""
var tryit = mpackage.metadata.metadata("upstream.tryit")
if tryit != null then
var e = tryit.html_escape
res.add "<li><a href=\"{e}\">Try<span style=\"color:white\">n</span>it!</a></li>\n"
end
var apk = mpackage.metadata.metadata("upstream.apk")
if apk != null then
var e = apk.html_escape
res.add "<li><a href=\"{e}\">Android apk</a></li>\n"
end
res.add """</ul>\n<ul class="box">\n"""
var homepage = mpackage.metadata.metadata("upstream.homepage")
if homepage != null then
var e = homepage.html_escape
res.add "<li><a href=\"{e}\">{e}</a></li>\n"
end
for maintainer in mpackage.metadata.maintainers do
res.add "<li>{maintainer.to_html}</li>"
end
var license = mpackage.metadata.metadata("package.license")
if license != null then
var e = license.html_escape
res.add "<li><a href=\"http://opensource.org/licenses/{e}\">{e}</a> license</li>\n"
end
res.add "</ul>\n"
res.add "<h3>Source Code</h3>\n<ul class=\"box\">\n"
var browse = mpackage.metadata.metadata("upstream.browse")
if browse != null then
var e = browse.html_escape
res.add "<li><a href=\"{e}\">{e}</a></li>\n"
end
var git = mpackage.metadata.metadata("upstream.git")
if git != null then
var e = git.html_escape
res.add "<li><tt>{e}</tt></li>\n"
end
var last_date = mpackage.metadata.last_date
if last_date != null then
var e = last_date.html_escape
res.add "<li>most recent commit: {e}</li>\n"
end
var first_date = mpackage.metadata.first_date
if first_date != null then
var e = first_date.html_escape
res.add "<li>oldest commit: {e}</li>\n"
end
var commits = commits[mpackage]
if commits != 0 then
res.add "<li>{commits} commits</li>\n"
end
res.add "</ul>\n"
res.add "<h3>Quality</h3>\n<ul class=\"box\">\n"
var errors = errors[mpackage]
if errors > 0 then
res.add "<li>{errors} errors</li>\n"
end
res.add "<li>{warnings[mpackage]} warnings ({warnings_per_kloc[mpackage]}/kloc)</li>\n"
res.add "<li>{documentation_score[mpackage]}% documented</li>\n"
res.add "</ul>\n"
res.add "<h3>Tags</h3>\n"
var ts2 = new Array[String]
for t in mpackage.metadata.tags do
t = t.html_escape
ts2.add "<a href=\"../index.html#tag_{t}\">{t}</a>"
end
res.add_list(ts2, ", ", ", ")
if deps.vertices.has(mpackage) then
var reqs = deps.get_all_successors(mpackage)
reqs.remove(mpackage)
alpha_comparator.sort(reqs)
res.add "<h3>Requirements</h3>\n"
if reqs.is_empty then
res.add "none"
else
var list = new Array[String]
for r in reqs do
var direct = deps.has_arc(mpackage, r)
var s = "<a href=\"{r}.html\">"
if direct then s += "<strong>"
s += r.to_s
if direct then s += "</strong>"
s += "</a>"
list.add s
end
res.add_list(list, ", ", " and ")
end
reqs = deps.get_all_predecessors(mpackage)
reqs.remove(mpackage)
alpha_comparator.sort(reqs)
res.add "<h3>Clients</h3>\n"
if reqs.is_empty then
res.add "none"
else
var list = new Array[String]
for r in reqs do
var direct = deps.has_arc(r, mpackage)
var s = "<a href=\"{r}.html\">"
if direct then s += "<strong>"
s += r.to_s
if direct then s += "</strong>"
s += "</a>"
list.add s
end
res.add_list(list, ", ", " and ")
end
end
var contributors = mpackage.metadata.contributors
if not contributors.is_empty then
res.add "<h3>Contributors</h3>\n<ul class=\"box\">"
for c in contributors do
res.add "<li>{c.to_html}</li>"
end
res.add "</ul>"
end
res.add """
<h3>Stats</h3>
<ul class="box">
<li>{{{mmodules[mpackage]}}} modules</li>
<li>{{{mclasses[mpackage]}}} classes</li>
<li>{{{mmethods[mpackage]}}} methods</li>
<li>{{{loc[mpackage]}}} lines of code</li>
</ul>
"""
res.add """
</div>
"""
return res
end
# Return a short HTML sequence for a package
#
# Intended to use in lists.
fun li_package(p: MPackage): String
do
var res = ""
var f = "p/{p.name}.html"
res += "<a href=\"{f}\">{p}</a>"
var d = p.mdoc_or_fallback
if d != null then res += " - {d.html_synopsis.write_to_string}"
return res
end
# List packages by group.
#
# For each key of the `map` a `<h3>` is generated.
# Each package is then listed.
#
# The list of keys is generated first to allow fast access to the correct `<h3>`.
# `id_prefix` is used to give an id to the `<h3>` element.
fun list_by(map: MultiHashMap[Object, MPackage], id_prefix: String): Template
do
var res = new Template
var keys = map.keys.to_a
alpha_comparator.sort(keys)
var list = [for x in keys do "<a href=\"#{id_prefix}{x.to_s.html_escape}\">{x.to_s.html_escape}</a>"]
res.add_list(list, ", ", " and ")
for k in keys do
var projs = map[k].to_a
alpha_comparator.sort(projs)
var e = k.to_s.html_escape
res.add "<h3 id=\"{id_prefix}{e}\">{e} ({projs.length})</h3>\n<ul>\n"
for p in projs do
res.add "<li>"
res.add li_package(p)
res.add "</li>"
end
res.add "</ul>"
end
return res
end
# List the 10 best packages from `cpt`
fun list_best(cpt: Counter[MPackage]): Template
do
var res = new Template
res.add "<ul>"
var best = cpt.sort
for i in [1..10] do
if i > best.length then break
var p = best[best.length-i]
res.add "<li>"
res.add li_package(p)
# res.add " ({cpt[p]})"
res.add "</li>"
end
res.add "</ul>"
return res
end
# Produce a HTML table containig information on the packages
#
# `package_page` must have been called before so that information is computed.
fun table_packages(mpackages: Array[MPackage]): Template
do
alpha_comparator.sort(mpackages)
var res = new Template
res.add "<table data-toggle=\"table\" data-sort-name=\"name\" data-sort-order=\"desc\" width=\"100%\">\n"
res.add "<thead><tr>\n"
res.add "<th data-field=\"name\" data-sortable=\"true\">name</th>\n"
res.add "<th data-field=\"maint\" data-sortable=\"true\">maint</th>\n"
res.add "<th data-field=\"contrib\" data-sortable=\"true\">contrib</th>\n"
if deps.vertices.not_empty then
res.add "<th data-field=\"reqs\" data-sortable=\"true\">reqs</th>\n"
res.add "<th data-field=\"dreqs\" data-sortable=\"true\">direct<br>reqs</th>\n"
res.add "<th data-field=\"cli\" data-sortable=\"true\">clients</th>\n"
res.add "<th data-field=\"dcli\" data-sortable=\"true\">direct<br>clients</th>\n"
end
res.add "<th data-field=\"mod\" data-sortable=\"true\">modules</th>\n"
res.add "<th data-field=\"cla\" data-sortable=\"true\">classes</th>\n"
res.add "<th data-field=\"met\" data-sortable=\"true\">methods</th>\n"
res.add "<th data-field=\"loc\" data-sortable=\"true\">lines</th>\n"
res.add "<th data-field=\"score\" data-sortable=\"true\">score</th>\n"
res.add "<th data-field=\"errors\" data-sortable=\"true\">errors</th>\n"
res.add "<th data-field=\"warnings\" data-sortable=\"true\">warnings</th>\n"
res.add "<th data-field=\"warnings_per_kloc\" data-sortable=\"true\">w/kloc</th>\n"
res.add "<th data-field=\"doc\" data-sortable=\"true\">doc</th>\n"
res.add "</tr></thead>"
for p in mpackages do
res.add "<tr>"
res.add "<td><a href=\"p/{p.name}.html\">{p.name}</a></td>"
var maint = "?"
if p.metadata.maintainers.not_empty then maint = p.metadata.maintainers.first.name.html_escape
res.add "<td>{maint}</td>"
res.add "<td>{p.metadata.contributors.length}</td>"
if deps.vertices.not_empty then
res.add "<td>{deps.get_all_successors(p).length-1}</td>"
res.add "<td>{deps.successors(p).length}</td>"
res.add "<td>{deps.get_all_predecessors(p).length-1}</td>"
res.add "<td>{deps.predecessors(p).length}</td>"
end
res.add "<td>{mmodules[p]}</td>"
res.add "<td>{mclasses[p]}</td>"
res.add "<td>{mmethods[p]}</td>"
res.add "<td>{loc[p]}</td>"
res.add "<td>{score[p]}</td>"
res.add "<td>{errors[p]}</td>"
res.add "<td>{warnings[p]}</td>"
res.add "<td>{warnings_per_kloc[p]}</td>"
res.add "<td>{documentation_score[p]}</td>"
res.add "</tr>\n"
end
res.add "</table>\n"
return res
end
# Piwik tracker URL, if any
var piwik_tracker: nullable String = null
# Piwik site ID
# Used when `piwik_tracker` is set
var piwik_site_id: Int = 1
end
src/nitcatalog.nit:186,1--533,3
redef class Catalog
# Build the catalog for Nitx
private fun build_catalog(model: Model, filter: nullable ModelFilter) do
# Scan all modules of collected packages
for p in model.collect_mpackages(filter) do
var g = p.root
assert g != null
modelbuilder.scan_group(g)
end
# Build the catalog
for mpackage in model.collect_mpackages(filter) do
package_page(mpackage)
git_info(mpackage)
mpackage_stats(mpackage)
end
end
end
src/nitx.nit:121,1--137,3
redef class Catalog
# Build the catalog from `mpackages`
fun build_catalog(mpackages: Array[MPackage]) do
# Compute the poset
for p in mpackages do
var g = p.root
assert g != null
modelbuilder.scan_group(g)
end
# Build the catalog
for mpackage in mpackages do
package_page(mpackage)
git_info(mpackage)
mpackage_stats(mpackage)
end
end
end
src/nitdoc.nit:227,1--244,3