+# A Makefile for the Nit project
+class NitMakefile
+
+ # Nit files to compile
+ var nit_files: Array[String]
+
+ # List of rules to add in the Makefile
+ fun rules: Array[MakeRule] do
+ var rules = new Array[MakeRule]
+
+ var rule_all = new MakeRule("all", is_phony = true)
+ rules.add rule_all
+
+ for file in nit_files do
+ var bin = file.basename.strip_extension
+
+ rule_all.deps.add "bin/{bin}"
+
+ var rule = new MakeRule("bin/{bin}")
+ rule.deps.add "$(shell $(NITLS) -M {file})"
+ rule.lines.add "mkdir -p bin/"
+ rule.lines.add "$(NITC) {file} -o bin/{bin}"
+ rules.add rule
+ end
+
+ var rule_check = new MakeRule("check", is_phony = true)
+ rule_check.lines.add "$(NITUNIT) ."
+ rules.add rule_check
+
+ var rule_doc = new MakeRule("doc", is_phony = true)
+ rule_doc.lines.add "$(NITDOC) . -o doc/"
+ rules.add rule_doc
+
+ var rule_clean = new MakeRule("clean", is_phony = true)
+ if nit_files.not_empty then
+ rule_clean.lines.add "rm -rf bin/"
+ end
+ rule_clean.lines.add "rm -rf doc/"
+ rules.add rule_clean
+
+ return rules
+ end
+
+ # Render `self`
+ fun render: Writable do
+ var tpl = new Template
+ tpl.addn """
+# 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.\n"""
+
+ if nit_files.not_empty then
+ tpl.addn "NITC ?= nitc"
+ tpl.addn "NITLS ?= nitls"
+ end
+ tpl.addn "NITUNIT ?= nitunit"
+ tpl.addn "NITDOC ?= nitdoc"
+
+ for rule in rules do
+ tpl.add "\n{rule.render.write_to_string}"
+ end
+
+ return tpl
+ end
+end
+
+# A rule that goes into a Makefile
+class MakeRule
+
+ # Rule name
+ var name: String
+
+ # Is this rule a `.PHONY` one?
+ var is_phony: Bool = false is optional
+
+ # Rule dependencies
+ var deps = new Array[String]
+
+ # Rule lines
+ var lines = new Array[String]
+
+ # Render `self`
+ fun render: Writable do
+ var tpl = new Template
+ if is_phony then
+ tpl.addn ".PHONY: {name}"
+ end
+ tpl.add "{name}:"
+ if deps.not_empty then
+ tpl.add " {deps.join(" ")}"
+ end
+ tpl.add "\n"
+ for line in lines do
+ tpl.addn "\t{line}"
+ end
+ return tpl
+ end
+end
+
+private class ManPage
+ var mmodule: MModule
+ var name: nullable String is noinit
+ var synopsis: nullable String is noinit
+ var options = new HashMap[Array[String], String]
+
+ init from_file(mmodule: MModule, file: String) do
+ from_lines(mmodule, file.to_path.read_lines)
+ end
+
+ init from_string(mmodule: MModule, string: String) do
+ from_lines(mmodule, string.split("\n"))
+ end
+
+ init from_lines(mmodule: MModule, lines: Array[String]) do
+ init mmodule
+
+ var section = null
+ for i in [0..lines.length[ do
+ var line = lines[i]
+ if line.is_empty then continue
+
+ if line == "# NAME" then
+ section = "name"
+ continue
+ end
+ if line == "# SYNOPSIS" then
+ section = "synopsis"
+ continue
+ end
+ if line == "# OPTIONS" then
+ section = "options"
+ continue
+ end
+
+ if section == "name" and name == null then
+ name = line.trim
+ end
+ if section == "synopsis" and synopsis == null then
+ synopsis = line.trim
+ end
+ if section == "options" and line.has_prefix("###") then
+ var opts = new Array[String]
+ for opt in line.substring(3, line.length).trim.replace("`", "").split(",") do
+ opts.add opt.trim
+ end
+ var desc = ""
+ if i < lines.length - 1 then
+ desc = lines[i + 1].trim
+ end
+ options[opts] = desc
+ end
+ end
+ end
+
+ fun diff(toolcontext: ToolContext, ref: ManPage) do
+ if name != ref.name then
+ toolcontext.warning(mmodule.location, "diff-man",
+ "Warning: outdated man description. " +
+ "Expected `{ref.name or else ""}` got `{name or else ""}`.")
+ end
+ if synopsis != ref.synopsis then
+ toolcontext.warning(mmodule.location, "diff-man",
+ "Warning: outdated man synopsis. " +
+ "Expected `{ref.synopsis or else ""}` got `{synopsis or else ""}`.")
+ end
+ for name, desc in options do
+ if not ref.options.has_key(name) then
+ toolcontext.warning(mmodule.location, "diff-man",
+ "Warning: unknown man option `{name}`.`")
+ continue
+ end
+ var ref_desc = ref.options[name]
+ if desc != ref_desc then
+ toolcontext.warning(mmodule.location, "diff-man",
+ "Warning: outdated man option description. Expected `{ref_desc}` got `{desc}`.")
+ end
+ end
+ for ref_name, ref_desc in ref.options do
+ if not options.has_key(ref_name) then
+ toolcontext.warning(mmodule.location, "diff-man",
+ "Warning: missing man option `{ref_name}`.`")
+ end
+ end
+ end
+
+ redef fun to_s do
+ var tpl = new Template
+ tpl.addn "# NAME"
+ tpl.addn name or else ""
+ tpl.addn "# SYNOPSIS"
+ tpl.addn synopsis or else ""
+ tpl.addn "# OPTIONS"
+ for name, desc in options do
+ tpl.addn " * {name}: {desc}"
+ end
+ return tpl.write_to_string
+ end
+end
+