doc/commands: introduce catalog commands
authorAlexandre Terrasa <alexandre@moz-code.org>
Tue, 24 Oct 2017 21:51:01 +0000 (17:51 -0400)
committerAlexandre Terrasa <alexandre@moz-code.org>
Thu, 23 Nov 2017 16:08:40 +0000 (11:08 -0500)
Signed-off-by: Alexandre Terrasa <alexandre@moz-code.org>

src/doc/commands/commands_catalog.nit [new file with mode: 0644]
src/doc/commands/tests/test_commands_catalog.nit [new file with mode: 0644]

diff --git a/src/doc/commands/commands_catalog.nit b/src/doc/commands/commands_catalog.nit
new file mode 100644 (file)
index 0000000..be823d0
--- /dev/null
@@ -0,0 +1,341 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Commands to retrieve Catalog related data
+module commands_catalog
+
+import commands_model
+
+# A DocCommand based on a Catalog
+abstract class CmdCatalog
+       super DocCommand
+
+       # Catalog to query at
+       var catalog: Catalog
+end
+
+# A CmdSearch command using a Catalog
+class CmdCatalogSearch
+       super CmdCatalog
+       super CmdSearch
+
+       autoinit(view, catalog, query, limit, page, count, max)
+
+       redef fun init_results do
+               if results != null then return new CmdSuccess
+
+               var res = super
+               if not res isa CmdSuccess then return res
+
+               var query = self.query
+               if query == null then return new ErrorNoQuery
+               sorter = null
+
+               var index = view.index
+
+               # lookup by name prefix
+               var matches = index.find_by_name_prefix(query).uniq.
+                       sort(lname_sorter, name_sorter, kind_sorter)
+               matches = matches.rerank.sort(vis_sorter, score_sorter)
+
+               # lookup by tags
+               var malus = matches.length
+               if catalog.tag2proj.has_key(query) then
+                       for mpackage in catalog.tag2proj[query] do
+                               matches.add new IndexMatch(mpackage, malus)
+                               malus += 1
+                       end
+                       matches = matches.uniq.rerank.sort(vis_sorter, score_sorter)
+               end
+
+               # lookup by full_name prefix
+               malus = matches.length
+               var full_matches = new IndexMatches
+               for match in index.find_by_full_name_prefix(query).
+                       sort(lfname_sorter, fname_sorter) do
+                       match.score += 1
+                       full_matches.add match
+               end
+               matches = matches.uniq
+
+               # lookup by similarity
+               malus = matches.length
+               var sim_matches = new IndexMatches
+               for match in index.find_by_similarity(query).sort(score_sorter, lname_sorter, name_sorter) do
+                       if match.score > query.length then break
+                       match.score += 1
+                       sim_matches.add match
+               end
+               matches.add_all sim_matches
+               matches = matches.uniq
+               results = matches.rerank.sort(vis_sorter, score_sorter).mentities
+               return res
+       end
+
+       private var score_sorter = new ScoreComparator
+       private var vis_sorter = new VisibilityComparator
+       private var name_sorter = new NameComparator
+       private var lname_sorter = new NameLengthComparator
+       private var fname_sorter = new FullNameComparator
+       private var lfname_sorter = new FullNameLengthComparator
+       private var kind_sorter = new MEntityComparator
+end
+
+# Retrieve the catalog metadata for a MPackage
+class CmdMetadata
+       super CmdEntity
+
+       # MPackage metadata retrieved
+       var metadata: nullable MPackageMetadata = null is optional, writable
+
+       redef fun init_command do
+               if metadata != null then return new CmdSuccess
+
+               var res = super
+               if not res isa CmdSuccess then return res
+               var mentity = self.mentity.as(not null)
+
+               if mentity isa MPackage then
+                       metadata = mentity.metadata
+               else
+                       return new WarningNoMetadata(mentity)
+               end
+               return res
+       end
+end
+
+# No metadata for `mentity`
+class WarningNoMetadata
+       super CmdWarning
+
+       # MEntity provided
+       var mentity: MEntity
+
+       redef fun to_s do return "No metadata for `{mentity.full_name}`"
+end
+
+# Retrieve the packages in the catalog
+class CmdCatalogPackages
+       super CmdCatalog
+       super CmdEntities
+
+       autoinit(view, catalog, limit, page, count, max)
+
+       redef var sorter = new CatalogScoreSorter(catalog) is lazy
+
+       redef fun init_results do
+               if results != null then return new CmdSuccess
+
+               var res = super
+               if not res isa CmdSuccess then return res
+
+               results = catalog.mpackages.values.to_a
+               return res
+       end
+end
+
+# Retrieve the catalog stats
+class CmdCatalogStats
+       super CmdCatalog
+
+       # Retrieved catalog statistics
+       var stats: nullable CatalogStats = null is optional, writable
+
+       redef fun init_command do
+               super
+               self.stats = catalog.catalog_stats
+               return new CmdSuccess
+       end
+end
+
+# Retrieve the catalog tags list
+class CmdCatalogTags
+       super CmdCatalog
+
+       # Sorter to sort tags alphabetically
+       var tags_sorter = new CatalogTagsSorter is optional, writable
+
+       # Count of packages by tag
+       var packages_count_by_tags: nullable ArrayMap[String, Int] = null is optional, writable
+
+       redef fun init_command do
+               super
+               var tags_to_projects = new ArrayMap[String, Int]
+               var tags = catalog.tag2proj.keys.to_a
+               tags_sorter.sort(tags)
+               for tag in tags do
+                       if not catalog.tag2proj.has_key(tag) then continue
+                       tags_to_projects[tag] = catalog.tag2proj[tag].length
+               end
+               packages_count_by_tags = tags_to_projects
+               return new CmdSuccess
+       end
+end
+
+# Retrieve the packages for a tag
+class CmdCatalogTag
+       super CmdCatalogPackages
+
+       autoinit(view, catalog, tag, limit, page, count, max)
+
+       # The tag to retrieve
+       var tag: nullable String = null is optional, writable
+
+       redef fun init_command do
+               var tag = self.tag
+               if tag == null then return new ErrorNoTag
+
+               if not catalog.tag2proj.has_key(tag) then return new ErrorTagNotFound(tag)
+               return super
+       end
+
+       redef fun init_results do
+               if results != null then return new CmdSuccess
+
+               var res = super
+               if not res isa CmdSuccess then return res
+
+               results = catalog.tag2proj[tag].to_a
+               return res
+       end
+end
+
+# No tag name provided
+class ErrorNoTag
+       super CmdError
+
+       redef fun to_s do return "No tag name provided"
+end
+
+# No tag with this name in the catalog
+class ErrorTagNotFound
+       super CmdError
+
+       # The tag that was not found
+       var tag: String
+
+       redef fun to_s do return "No tag found for `{tag}`"
+end
+
+# Retrieve a person from the catalog
+class CmdCatalogPerson
+       super CmdCatalog
+
+       # Person to retrieve
+       #
+       # You can also pass a `person_name`.
+       var person: nullable Person = null is optional, writable
+
+       # Name of the person to retrieve
+       #
+       # You can also pass a `person` instance.
+       var person_name: nullable String = null is optional, writable
+
+       # Initialize the `person` result
+       fun init_person: CmdMessage do
+               var person = self.person
+               if person != null then
+                       person_name = person.name
+                       return new CmdSuccess
+               end
+
+               var name = self.person_name
+               if name == null then return new ErrorNoPerson
+               if not catalog.name2person.has_key(name) then return new ErrorPersonNotFound(name)
+               self.person = catalog.name2person[name]
+               return new CmdSuccess
+       end
+
+       redef fun init_command do
+               init_person
+               return super
+       end
+end
+
+# No person instance or name provided
+class ErrorNoPerson
+       super CmdError
+
+       redef fun to_s do return "No person provided"
+end
+
+# No person found with this name
+class ErrorPersonNotFound
+       super CmdError
+
+       # Name of the person that was not found
+       var name: String
+
+       redef fun to_s do return "No person found for `{name}`"
+end
+
+# Retrieve the packages maintained by a person
+class CmdCatalogMaintaining
+       super CmdCatalogPerson
+       super CmdCatalogPackages
+
+       autoinit(view, catalog, person, person_name, limit, page, count, max)
+
+       redef fun init_command do return super
+
+       redef fun init_results do
+               if results != null then return new CmdSuccess
+               var res = super
+               if not res isa CmdSuccess then return res
+               var person = self.person.as(not null)
+
+               if not catalog.maint2proj.has_key(person) then return res
+               results = catalog.maint2proj[person]
+               return res
+       end
+end
+
+# Retrieve the packages contributed by a person
+class CmdCatalogContributing
+       super CmdCatalogPerson
+       super CmdCatalogPackages
+
+       autoinit(view, catalog, person, person_name, limit, page, count, max)
+
+       # Include maintained packages?
+       #
+       # Default is `false`.
+       var maintaining = false is optional, writable
+
+       # FIXME linearization
+       redef fun init_command do return super
+
+       redef fun init_results do
+               if results != null then return new CmdSuccess
+
+               var res = super
+               if not res isa CmdSuccess then return res
+               var person = self.person.as(not null)
+
+               if not catalog.contrib2proj.has_key(person) then return res
+
+               var maint2proj = null
+               if catalog.maint2proj.has_key(person) then
+                       maint2proj = catalog.maint2proj[person]
+               end
+
+               var results = new Array[MPackage]
+               for mpackage in catalog.contrib2proj[person] do
+                       if not maintaining and maint2proj != null and maint2proj.has(mpackage) then continue
+                       results.add mpackage
+               end
+               self.results = results
+               return res
+       end
+end
diff --git a/src/doc/commands/tests/test_commands_catalog.nit b/src/doc/commands/tests/test_commands_catalog.nit
new file mode 100644 (file)
index 0000000..9d60706
--- /dev/null
@@ -0,0 +1,113 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+module test_commands_catalog is test
+
+import test_commands
+import doc::commands::commands_catalog
+
+class TestCommandsCatalog
+       super TestCommands
+       test
+
+       # Catalog used for tests
+       var test_catalog: Catalog is lazy do
+               var catalog = new Catalog(test_builder)
+
+               # Compute the poset
+               for p in test_view.mpackages do
+                       var g = p.root
+                       assert g != null
+                       test_builder.scan_group(g)
+
+                       catalog.deps.add_node(p)
+                       for gg in p.mgroups do for m in gg.mmodules do
+                               for im in m.in_importation.direct_greaters do
+                                       var ip = im.mpackage
+                                       if ip == null or ip == p then continue
+                                       test_catalog.deps.add_edge(p, ip)
+                               end
+                       end
+               end
+               # Build the catalog
+               for mpackage in test_view.mpackages do
+                       catalog.package_page(mpackage)
+                       catalog.git_info(mpackage)
+                       catalog.mpackage_stats(mpackage)
+               end
+               return catalog
+       end
+
+       fun test_cmd_catalog is test do
+               var cmd = new CmdCatalogPackages(test_view, test_catalog)
+               var res = cmd.init_command
+               assert res isa CmdSuccess
+               assert cmd.results.as(not null).first.full_name == "test_prog"
+       end
+
+       fun test_cmd_catalog_search is test do
+               var cmd = new CmdCatalogSearch(test_view, test_catalog, "test")
+               var res = cmd.init_command
+               assert res isa CmdSuccess
+               assert cmd.results.as(not null).first.full_name == "test_prog"
+               assert cmd.results.as(not null).first isa MPackage
+       end
+
+       fun test_cmd_catalog_stats is test do
+               var cmd = new CmdCatalogStats(test_view, test_catalog)
+               var res = cmd.init_command
+               assert res isa CmdSuccess
+               assert cmd.stats != null
+       end
+
+       fun test_cmd_catalog_tags is test do
+               var cmd = new CmdCatalogTags(test_view, test_catalog)
+               var res = cmd.init_command
+               assert res isa CmdSuccess
+               assert cmd.packages_count_by_tags.as(not null).length == 2
+       end
+
+       fun test_cmd_catalog_tag is test do
+               var cmd = new CmdCatalogTag(test_view, test_catalog, "test")
+               var res = cmd.init_command
+               assert res isa CmdSuccess
+               assert cmd.tag == "test"
+               assert cmd.results.as(not null).length == 1
+       end
+
+       fun test_cmd_catalog_person is test do
+               var cmd = new CmdCatalogPerson(test_view, test_catalog, person_name = "Alexandre Terrasa")
+               var res = cmd.init_command
+               assert res isa CmdSuccess
+               assert cmd.person.as(not null).name == "Alexandre Terrasa"
+       end
+
+       fun test_cmd_catalog_contributing is test do
+               var cmd = new CmdCatalogContributing(test_view, test_catalog,
+                       person_name = "Alexandre Terrasa")
+               var res = cmd.init_command
+               assert res isa CmdSuccess
+               assert cmd.person.as(not null).name == "Alexandre Terrasa"
+               assert cmd.results.as(not null).length == 1
+       end
+
+       fun test_cmd_catalog_maintaining is test do
+               var cmd = new CmdCatalogMaintaining(test_view, test_catalog,
+                       person_name = "Alexandre Terrasa")
+               var res = cmd.init_command
+               assert res isa CmdSuccess
+               assert cmd.person.as(not null).name == "Alexandre Terrasa"
+               assert cmd.results.as(not null).length == 2
+       end
+end