+
+ # Makefile
+
+ # The path to `self` Makefile
+ fun makefile_path: nullable String do
+ var path = package_path
+ if path == null then return null
+ if not is_expanded then return null
+ return path / "Makefile"
+ end
+
+ # Does `self` have a Makefile?
+ fun has_makefile: Bool do
+ var makefile_path = self.makefile_path
+ if makefile_path == null then return false
+ return makefile_path.file_exists
+ end
+
+ private fun check_makefile(toolcontext: ToolContext, mainmodule: MModule) do
+ var model = toolcontext.modelbuilder.model
+ var filter = new ModelFilter(accept_example = false, accept_test = false)
+
+ var cmd_bin = new CmdMains(model, filter, mentity = self)
+ var res_bin = cmd_bin.init_command
+ if not res_bin isa CmdSuccess then return
+
+ for mmodule in cmd_bin.results.as(not null) do
+ if not mmodule isa MModule then continue
+
+ if mmodule.makefile_path == null then
+ toolcontext.warning(location, "missing-makefile",
+ "Warning: no Makefile for executable module `{mmodule.full_name}`")
+ end
+ end
+ end
+
+ private fun gen_makefile(model: Model, mainmodule: MModule): nullable String do
+ var filter = new ModelFilter(accept_example = false, accept_test = false)
+
+ var pkg_path = package_path.as(not null)
+ var makefile_path = makefile_path.as(not null)
+
+ var bins = new Array[String]
+ var cmd_bin = new CmdMains(model, filter, mentity = self)
+ var res_bin = cmd_bin.init_command
+ if res_bin isa CmdSuccess then
+ for mmodule in cmd_bin.results.as(not null) do
+ if not mmodule isa MModule then continue
+ var mmodule_makefile = mmodule.makefile_path
+ if mmodule_makefile != null and mmodule_makefile != makefile_path then continue
+
+ var file = mmodule.location.file
+ if file == null then continue
+ # Remove package path prefix
+ var bin_path = file.filename
+ if pkg_path.has_suffix("/") then
+ bin_path = bin_path.replace(pkg_path, "")
+ else
+ bin_path = bin_path.replace("{pkg_path}/", "")
+ end
+ bins.add bin_path
+ end
+ end
+
+ if bins.is_empty then return null
+
+ var make = new NitMakefile(bins)
+ make.render.write_to_file(makefile_path)
+ return makefile_path
+ end
+
+ # Manpages
+
+ # The path to `self` manpage files
+ private fun man_path: nullable String do
+ var path = package_path
+ if path == null then return null
+ if not is_expanded then return null
+ return path / "man"
+ end
+
+ # Does `self` have a manpage files?
+ private fun has_man: Bool do
+ var man_path = self.man_path
+ if man_path == null then return false
+ return man_path.file_exists
+ end
+
+ private fun check_man(toolcontext: ToolContext, mainmodule: MModule) do
+ var model = toolcontext.modelbuilder.model
+ var filter = new ModelFilter(accept_example = false, accept_test = false)
+ var cmd = new CmdMains(model, filter, mentity = self)
+ var res = cmd.init_command
+ if not res isa CmdSuccess then return
+
+ for mmodule in cmd.results.as(not null) do
+ if not mmodule isa MModule then continue
+ mmodule.check_man(toolcontext)
+ end
+ end
+
+ private fun gen_man(toolcontext: ToolContext, mainmodule: MModule) do
+ var model = toolcontext.modelbuilder.model
+ var filter = new ModelFilter(accept_example = false, accept_test = false)
+ var cmd = new CmdMains(model, filter, mentity = self)
+ var res = cmd.init_command
+ if not res isa CmdSuccess then return
+
+ var pkg_man = man_path.as(not null)
+ for mmodule in cmd.results.as(not null) do
+ if not mmodule isa MModule then continue
+ if not has_man then pkg_man.mkdir
+ mmodule.gen_man(toolcontext)
+ end
+ end
+
+ # README
+
+ private fun check_readme(toolcontext: ToolContext) do
+ if not has_readme then
+ toolcontext.error(location, "No `README.md` file for `{name}`")
+ return
+ end
+ end
+end
+
+redef class MModule
+ private fun makefile_path: nullable String do
+ var file = location.file
+ if file == null then return null
+
+ var dir = file.filename.dirname
+ var makefile = (dir / "Makefile")
+ if not makefile.file_exists then return null
+
+ for line in makefile.to_path.read_lines do
+ if line.has_prefix("{name}:") then return makefile
+ end
+ return null
+ end
+
+ private fun man_path: nullable String do
+ var mpackage = self.mpackage
+ if mpackage == null then return null
+ var path = mpackage.man_path
+ if path == null then return null
+ return path / "{name}.man"
+ end
+
+ # Does `self` have a manpage?
+ private fun has_man: Bool do
+ var man_path = self.man_path
+ if man_path == null then return false
+ return man_path.file_exists
+ end
+
+ private fun make_module(toolcontext: ToolContext): Bool do
+ var mpackage = self.mpackage
+ if mpackage == null then return false
+ if not mpackage.is_expanded then return false
+
+ var pkg_path = mpackage.package_path
+ if pkg_path == null then return false
+
+ var pr = new ProcessReader("sh", "-c", "cd {pkg_path} && make -Bs bin/{name}")
+ var out = pr.read_all.trim
+ pr.close
+ pr.wait
+ if pr.status > 0 then
+ toolcontext.error(location, "unable to compile `{name}`")
+ print out
+ return false
+ end
+ return true
+ end
+
+ private fun stub_man(toolcontext: ToolContext): nullable String do
+ if not make_module(toolcontext) then return null
+ var mpackage = self.mpackage
+ if mpackage == null then return null
+ if not mpackage.is_expanded then return null
+
+ var pkg_path = mpackage.package_path
+ if pkg_path == null then return null
+
+ var pr = new ProcessReader("{pkg_path}/bin/{name}", "--stub-man")
+ var man = pr.read_all.trim
+ pr.close
+ pr.wait
+ if pr.status > 0 then
+ toolcontext.error(location, "unable to run `{pkg_path}/bin/{name} --stub-man`")
+ print man
+ return null
+ end
+ return man
+ end
+
+ private fun check_man(toolcontext: ToolContext) do
+ if not has_man then
+ toolcontext.error(location, "No manpage for bin {full_name}")
+ return
+ end
+ var man_path = self.man_path.as(not null)
+ var man = stub_man(toolcontext)
+ if man == null or man.is_empty then return
+
+ var old_man = new ManPage.from_file(self, man_path)
+ var new_man = new ManPage.from_string(self, man)
+ old_man.diff(toolcontext, new_man)
+ end
+
+ private fun gen_man(toolcontext: ToolContext) do
+ var man = stub_man(toolcontext)
+ if man == null or man.is_empty then return
+ var man_path = self.man_path
+ if man_path == null then return
+ man.write_to_file(man_path)
+ toolcontext.info("created manpage `{man_path}`", 0)
+ end