--- /dev/null
+# 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 commands_main
+
+import doc::commands::commands_model
+
+# Cmd that finds the mains of an `mentity`
+class CmdMains
+ super CmdEntityList
+
+ redef fun init_results do
+ if results != null then return new CmdSuccess
+
+ var res = super
+ if not res isa CmdSuccess then return res
+ var mentity = self.mentity.as(not null)
+ var mentities = new Array[MEntity]
+
+ if mentity isa MPackage then
+ for mmodule in mentity.collect_all_mmodules(view) do
+ if mmodule_has_main(mmodule) then mentities.add mmodule
+ end
+ else if mentity isa MGroup then
+ for mmodule in mentity.collect_all_mmodules(view) do
+ if mmodule_has_main(mmodule) then mentities.add mmodule
+ end
+ else if mentity isa MModule then
+ if mmodule_has_main(mentity) then mentities.add mentity
+ else
+ return new WarningNoMains(mentity)
+ end
+
+ if mentities.is_empty then return new WarningNoMains(mentity)
+
+ self.results = mentities
+ return res
+ end
+
+ # Does `mmodule` has a `main` method?
+ private fun mmodule_has_main(mmodule: MModule): Bool do
+ for mclassdef in mmodule.collect_redef_mclassdefs(view) do
+ if mclassdef.name != "Sys" then continue
+ for mpropdef in mclassdef.collect_redef_mpropdefs(view) do
+ if mpropdef.name == "main" then return true
+ end
+ end
+ return false
+ end
+end
+
+# No tests for `mentity`
+class WarningNoMains
+ super CmdWarning
+
+ # MEntity provided
+ var mentity: MEntity
+
+ redef fun to_s do return "No main found for `{mentity.full_name}`"
+end
+
+# Cmd that finds the nitc command related to an `mentity`
+class CmdMainCompile
+ super CmdEntity
+
+ var file: nullable SourceFile = null
+
+ var command: nullable String is lazy do
+ var path = test_path(file)
+ if path == null then return null
+ return "nitc {path}"
+ end
+
+ redef fun init_command do
+ var res = super
+ if not res isa CmdSuccess then return res
+ var mentity = self.mentity.as(not null)
+
+ if mentity isa MModule then
+ file = mmodule_main(mentity)
+ if file == null then return new WarningNoMain(mentity)
+ else
+ return new WarningNoMain(mentity)
+ end
+ return res
+ end
+
+ # Does `mmodule` has a `main` method?
+ private fun mmodule_main(mmodule: MModule): nullable SourceFile do
+ for mclassdef in mmodule.mclassdefs do
+ if mclassdef.name != "Sys" then continue
+ for mpropdef in mclassdef.mpropdefs do
+ if mpropdef.name == "main" then return mmodule.location.file
+ end
+ end
+ return null
+ end
+
+ # Return the sourcefile path
+ #
+ # This method exists for the only purpose to be redefined by nitunit tests
+ # to avoid path diffs.
+ private fun test_path(file: nullable SourceFile): nullable String do
+ if file == null then return null
+ var base_path = mentity.as(MModule).mpackage.as(not null).location.file.as(not null).filename
+ return file.filename.replace(base_path, "")
+ end
+end
+
+# No tests for `mentity`
+class WarningNoMain
+ super CmdWarning
+
+ # MEntity provided
+ var mentity: MEntity
+
+ redef fun to_s do return "No main to compile for `{mentity.full_name}`"
+end
+
+# Cmd that finds the nitunit command related to an `mentity`
+class CmdTesting
+ super CmdEntityList
+
+ var command: nullable String is lazy do
+ var results = self.results
+ if results == null then return null
+
+ var tpl = new Template
+ tpl.add "nitunit"
+ for result in results do
+ var path = test_path(result)
+ if path == null then continue
+ tpl.add " {path}"
+ end
+ return tpl.write_to_string
+ end
+
+ redef fun init_results do
+ if results != null then return new CmdSuccess
+
+ var res = super
+ if not res isa CmdSuccess then return res
+ var mentity = self.mentity.as(not null)
+
+ var mentities = new Array[MEntity]
+ if not mentity isa MPackage then return new WarningNoTest(mentity)
+
+ for mgroup in mentity.collect_all_mgroups(view) do
+ if mgroup.is_test then
+ mentities.add mgroup
+ continue
+ end
+ for mmodule in mgroup.collect_mmodules(view) do
+ if mmodule.is_test then mentities.add mmodule
+ end
+ end
+
+ if mentities.is_empty then return new WarningNoTest(mentity)
+
+ self.results = mentities
+ return res
+ end
+
+ # Return the mentity path
+ #
+ # This method exists for the only purpose to be redefined by nitunit tests
+ # to avoid path diffs.
+ private fun test_path(mentity: MEntity): nullable String do
+ var file = mentity.location.file
+ if file == null then return null
+ var base_path = self.mentity.as(not null).location.file.as(not null).filename
+ return file.filename.replace(base_path, "")
+ end
+end
+
+# No tests for `mentity`
+class WarningNoTest
+ super CmdWarning
+
+ # MEntity provided
+ var mentity: MEntity
+
+ redef fun to_s do return "No nitunit files for `{mentity.full_name}`"
+end
+
+# Cmd that finds the man file related to an `mentity`
+class CmdManFile
+ super CmdEntity
+
+ # Man file
+ var file: nullable String = null
+
+ redef fun init_command do
+ var res = super
+ if not res isa CmdSuccess then return res
+ var mentity = self.mentity.as(not null)
+
+ var mpackage = null
+ if mentity isa MPackage then
+ mpackage = mentity
+ else if mentity isa MGroup then
+ mpackage = mentity.mpackage
+ else if mentity isa MModule then
+ mpackage = mentity.mpackage
+ end
+
+ if mpackage == null then return new WarningNoManFile(mentity)
+
+ var source_file = mpackage.location.file
+ if source_file == null then return new WarningNoManFile(mentity)
+
+ var man_dir = source_file.filename / "man"
+ if not man_dir.file_exists then return new WarningNoManFile(mentity)
+
+ var man_file = null
+ for file in man_dir.files do
+ if not file.has_prefix(mentity.name) then continue
+ man_file = man_dir / file
+ end
+ if man_file == null then return new WarningNoManFile(mentity)
+
+ self.file = man_file
+
+ return res
+ end
+end
+
+# No man file for `mentity`
+class WarningNoManFile
+ super CmdWarning
+
+ # MEntity provided
+ var mentity: MEntity
+
+ redef fun to_s do return "No man file for `{mentity.full_name}`"
+end
+
+class CmdManSynopsis
+ super CmdManFile
+
+ # Synopsis string extracted from man
+ var synopsis: nullable String
+
+ redef fun init_command do
+ var res = super
+ if not res isa CmdSuccess then return res
+ var mentity = self.mentity.as(not null)
+ var file = self.file.as(not null)
+
+ var lines = file.to_path.read_lines
+ var in_synopsis = false
+ for line in lines do
+ if in_synopsis and line.has_prefix(mentity.name) then
+ synopsis = line
+ break
+ end
+ if line != "# SYNOPSIS" then continue
+ in_synopsis = true
+ end
+
+ if synopsis == null then return new WarningNoManSynopsis(mentity)
+
+ return res
+ end
+end
+
+# No synopsis found in the man file for `mentity`
+class WarningNoManSynopsis
+ super CmdWarning
+
+ # MEntity provided
+ var mentity: MEntity
+
+ redef fun to_s do return "No synopsis found in the man file for `{mentity.full_name}`"
+end
+
+class CmdManOptions
+ super CmdManFile
+
+ # Options description
+ var options: nullable ArrayMap[String, String]
+
+ redef fun init_command do
+ var res = super
+ if not res isa CmdSuccess then return res
+ var mentity = self.mentity.as(not null)
+ var file = self.file.as(not null)
+
+ var options = new ArrayMap[String, String]
+
+ var lines = file.to_path.read_lines
+ var in_options = false
+ for i in [0 .. lines.length[ do
+ var line = lines[i]
+ if line == "# OPTIONS" then
+ in_options = true
+ else if in_options and line.has_prefix("### ") then
+ var opt = line.substring(4, line.length).trim.replace("`", "")
+ var desc = ""
+ if i < lines.length - 1 then
+ desc = lines[i + 1].trim
+ end
+ options[opt] = desc
+ else if line.has_prefix("# ") then
+ in_options = false
+ end
+ end
+
+ if options.is_empty then return new WarningNoManOptions(mentity)
+ self.options = options
+
+ return res
+ end
+end
+
+# No options description found in the man file for `mentity`
+class WarningNoManOptions
+ super CmdWarning
+
+ # MEntity provided
+ var mentity: MEntity
+
+ redef fun to_s do return "No options description found in the man file for `{mentity.full_name}`"
+end
--- /dev/null
+# 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_main is test
+
+import test_commands
+import doc::commands::commands_main
+
+class TestCommandsMain
+ super TestCommands
+ test
+
+ fun test_cmd_mains is test do
+ var cmd = new CmdMains(test_view, mentity_name = "test_prog")
+ var res = cmd.init_command
+ assert res isa CmdSuccess
+ var results = cmd.results
+ assert results != null
+ assert results.length == 1
+ assert results.first.full_name == "test_prog::test_prog"
+ end
+
+ fun test_cmd_main_compile is test do
+ var cmd = new CmdMainCompile(test_view, mentity_name = "test_prog::test_prog")
+ var res = cmd.init_command
+ assert res isa CmdSuccess
+
+ var command = cmd.command
+ assert command != null
+ assert command.has_prefix("nitc ")
+ assert command.has_suffix("test_prog.nit")
+ end
+
+ fun test_cmd_testing is test do
+ var cmd = new CmdTesting(test_view, mentity_name = "test_prog")
+ var res = cmd.init_command
+ assert res isa CmdSuccess
+
+ var command = cmd.command
+ assert command != null
+ assert command.has_prefix("nitunit ")
+ assert command.has_suffix("/tests")
+ end
+
+ fun test_cmd_man_synopsis is test do
+ var cmd = new CmdManSynopsis(test_view, mentity_name = "test_prog")
+ var res = cmd.init_command
+ assert res isa CmdSuccess
+ assert cmd.synopsis == "test_prog [*options*] ARGS..."
+ end
+
+ fun test_cmd_man_options is test do
+ var cmd = new CmdManOptions(test_view, mentity_name = "test_prog")
+ var res = cmd.init_command
+ assert res isa CmdSuccess
+
+ var options = cmd.options
+ assert options != null
+ assert options["--opt1"] == "Option 1."
+ assert options["--opt2"] == "Option 2."
+ end
+end