diff --git a/ciimage/Dockerfile b/ciimage/Dockerfile index c398fad56..25cc6fa3e 100644 --- a/ciimage/Dockerfile +++ b/ciimage/Dockerfile @@ -12,6 +12,7 @@ RUN apt-get -y update && apt-get -y upgrade \ && apt-get -y install qt4-linguist-tools \ && apt-get -y install python-dev \ && apt-get -y install libomp-dev openssh-client \ +&& apt-get -y install -y clang libclang-dev llvm-dev flex \ && python3 -m pip install hotdoc codecov \ && dub fetch urld \ && dub build urld --compiler=gdc diff --git a/docs/README.md b/docs/README.md index 9ed75c10b..18509c7ed 100644 --- a/docs/README.md +++ b/docs/README.md @@ -3,7 +3,7 @@ 1. Get [hotdoc](https://hotdoc.github.io/installing.html) (0.8.9 required) 1. Run hotdoc in the docs/ directory: - hotdoc run + ../meson/meson.py build/ ## Upload @@ -12,5 +12,4 @@ removes the html pages and replaces with the new content. You can simply run: - hotdoc run --git-upload-activate - + ninja -C build/ upload diff --git a/docs/hotdoc.json b/docs/hotdoc.json deleted file mode 100644 index 482bc95d1..000000000 --- a/docs/hotdoc.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "extra_assets": [ - "images/" - ], - "html_extra_theme": "theme/extra/", - "include_paths": [ - "markdown/" - ], - "output": "built_docs/", - "project_name": "Meson documentation", - "project_version": "1.0", - "default-license": "CC-BY-SAv4.0", - "sitemap": "sitemap.txt", - "git_upload_repository": "git@github.com:jpakkane/jpakkane.github.io.git", - "edit_on_github_repository": "https://github.com/mesonbuild/meson/" -} diff --git a/docs/markdown/Hotdoc-module.md b/docs/markdown/Hotdoc-module.md new file mode 100644 index 000000000..7d9fc555f --- /dev/null +++ b/docs/markdown/Hotdoc-module.md @@ -0,0 +1,79 @@ +--- +short-description: Hotdoc module +authors: + - name: Thibault Saunier + email: tsaunier@igalia.com + years: [2018] + has-copyright: false +... + +# Hotdoc module + +This module provides helper functions for generating documentation using +[hotdoc]. + +*Added 0.48.0* + +## Usage + +To use this module, just do: **`hotdoc = import('hotdoc')`**. The +following functions will then be available as methods on the object +with the name `hotdoc`. You can, of course, replace the name `hotdoc` +with anything else. + +### hotdoc.generate_doc() + +Generates documentation using [hotdoc] and installs it into `$prefix/share/doc/html`. + +**Positional argument:** + +* `project_name`: The name of the hotdoc project + +**Keyworded arguments:** + +* `sitemap` (*[string] or [file]*) (**required**): The hotdoc sitemap file +* `index` (*[string] or [file]*) (**required**): Location of the index file +* `dependencies`(*[targets]*): Targets on which the documentation generation depends on. +* `subprojects`: A list of `HotdocTarget` that are used as subprojects for hotdoc to generate + the documentation. +* ... Any argument of `hotdoc` can be used replacing dashes (`-`) with underscores (`_`). + For a full list of available parameters, just have a look at `hotdoc help`. + +[file]: Reference-manual.md#files +[string]: Reference-manual.md#string-object +[targets]: Reference-manual.md#build-target-object + +**Returns:** + +`HotdocTarget`: A [`custom_target`](Reference-manual.md#custom-target-object) with the +following extra methods: + +* `config_path`: Path to the generated `hotdoc` configuration file. + +### hotdoc.has_extensions() + +**Positional arguments:** + +* `...`: The hotdoc extension names to look for + +**No keyworded arguments** + +**Returns:** `true` if all the extensions where found, `false` otherwise. + +### Example + +``` meson +hotdoc = import('hotdoc') + +hotdoc.generate_doc('foobar', + project_version: '0.1', + sitemap: 'sitemap.txt', + index: 'index.md', + c_sources: ['path/to/file.c'], + c_smart_index: true, + languages: ['c'], + install: true, +) +``` + +[hotdoc]: https://hotdoc.github.io/ \ No newline at end of file diff --git a/docs/markdown/snippets/hotdoc_module.md b/docs/markdown/snippets/hotdoc_module.md new file mode 100644 index 000000000..4662ea22b --- /dev/null +++ b/docs/markdown/snippets/hotdoc_module.md @@ -0,0 +1,22 @@ +## Hotdoc module + +A new module has been written to ease generation of [hotdoc](https://hotdoc.github.io/) based +documentation. It supports complex use cases such as hotdoc subprojects (to create documentation +portals) and makes it straight forward to leverage full capabilities of hotdoc. + +Simple usage: + +``` meson +hotdoc = import('hotdoc') + +hotdoc.generate_doc( + 'foobar', + c_smart_index: true, + project_version: '0.1', + sitemap: 'sitemap.txt', + index: 'index.md', + c_sources: ['path/to/file.c'], + languages: ['c'], + install: true, +) +``` \ No newline at end of file diff --git a/docs/meson.build b/docs/meson.build new file mode 100644 index 000000000..c83d5f89f --- /dev/null +++ b/docs/meson.build @@ -0,0 +1,22 @@ +project('Meson documentation', version: '1.0') + +hotdoc = import('hotdoc') +documentation = hotdoc.generate_doc(meson.project_name(), + project_version: meson.project_version(), + sitemap: 'sitemap.txt', + build_by_default: true, + index: 'markdown/index.md', + install: false, + extra_assets: ['images/'], + include_paths: ['markdown'], + default_license: 'CC-BY-SAv4.0', + html_extra_theme: join_paths('theme', 'extra'), + git_upload_repository: 'git@github.com:jpakkane/jpakkane.github.io.git', + edit_on_github_repository: 'https://github.com/mesonbuild/meson/', + syntax_highlighting_activate: true, +) + +run_target('upload', + command: [find_program('hotdoc'), 'run', '--conf-file', documentation.config_path(), + '--git-upload'] +) \ No newline at end of file diff --git a/docs/sitemap.txt b/docs/sitemap.txt index 2d43e1806..4ba1b90df 100644 --- a/docs/sitemap.txt +++ b/docs/sitemap.txt @@ -29,7 +29,9 @@ index.md Subprojects.md Disabler.md Modules.md + Dlang-module.md Gnome-module.md + Hotdoc-module.md i18n-module.md Icestorm-module.md Pkgconfig-module.md @@ -40,7 +42,6 @@ index.md RPM-module.md Simd-module.md Windows-module.md - Dlang-module.md Java.md Vala.md D.md diff --git a/docs/theme/extra/templates/navbar_links.html b/docs/theme/extra/templates/navbar_links.html index 2edce2489..c9cba131d 100644 --- a/docs/theme/extra/templates/navbar_links.html +++ b/docs/theme/extra/templates/navbar_links.html @@ -13,7 +13,8 @@ ("Qt4-module.html","Qt4"), \ ("Qt5-module.html","Qt5"), \ ("RPM-module.html","RPM"), \ - ("Windows-module.html","Windows")): + ("Windows-module.html","Windows"), \ + ("Hotdoc-module.html","Hotdoc")):
  • @tup[1]
  • diff --git a/mesonbuild/build.py b/mesonbuild/build.py index d35c697ec..3debeeb41 100644 --- a/mesonbuild/build.py +++ b/mesonbuild/build.py @@ -1830,7 +1830,8 @@ class CustomTarget(Target): while hasattr(ed, 'held_object'): ed = ed.held_object if not isinstance(ed, (CustomTarget, BuildTarget)): - raise InvalidArguments('Can only depend on toplevel targets: custom_target or build_target (executable or a library)') + raise InvalidArguments('Can only depend on toplevel targets: custom_target or build_target (executable or a library) got: %s(%s)' + % (type(ed), ed)) self.extra_depends.append(ed) for i in depend_files: if isinstance(i, (File, str)): diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py index 7dd24c5c9..f0ba4a9df 100644 --- a/mesonbuild/interpreter.py +++ b/mesonbuild/interpreter.py @@ -2001,7 +2001,7 @@ class Interpreter(InterpreterBase): return [self.holderify(x) for x in item] if isinstance(item, build.CustomTarget): return CustomTargetHolder(item, self) - elif isinstance(item, (int, str)) or item is None: + elif isinstance(item, (int, str, bool)) or item is None: return item elif isinstance(item, build.Executable): return ExecutableHolder(item, self) @@ -2027,6 +2027,9 @@ class Interpreter(InterpreterBase): def process_new_values(self, invalues): invalues = listify(invalues) for v in invalues: + if isinstance(v, (RunTargetHolder, CustomTargetHolder, BuildTargetHolder)): + v = v.held_object + if isinstance(v, (build.BuildTarget, build.CustomTarget, build.RunTarget)): self.add_target(v.name, v) elif isinstance(v, list): @@ -2045,6 +2048,8 @@ class Interpreter(InterpreterBase): self.process_new_values(v.sources[0]) elif hasattr(v, 'held_object'): pass + elif isinstance(v, (int, str, bool)): + pass else: raise InterpreterException('Module returned a value of unknown type.') diff --git a/mesonbuild/mesonmain.py b/mesonbuild/mesonmain.py index e8b7b3097..7dddb58e4 100644 --- a/mesonbuild/mesonmain.py +++ b/mesonbuild/mesonmain.py @@ -200,6 +200,9 @@ def run_script_command(args): elif cmdname == 'msgfmthelper': import mesonbuild.scripts.msgfmthelper as abc cmdfunc = abc.run + elif cmdname == 'hotdoc': + import mesonbuild.scripts.hotdochelper as abc + cmdfunc = abc.run elif cmdname == 'regencheck': import mesonbuild.scripts.regen_checker as abc cmdfunc = abc.run diff --git a/mesonbuild/modules/hotdoc.py b/mesonbuild/modules/hotdoc.py new file mode 100644 index 000000000..1f7368a08 --- /dev/null +++ b/mesonbuild/modules/hotdoc.py @@ -0,0 +1,386 @@ +# Copyright 2018 The Meson development team + +# 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. + +'''This module provides helper functions for generating documentation using hotdoc''' + +import os +from collections import OrderedDict + +from mesonbuild import mesonlib +from mesonbuild import mlog, build +from mesonbuild.coredata import MesonException +from . import ModuleReturnValue +from . import ExtensionModule +from . import get_include_args +from ..dependencies import Dependency, InternalDependency, ExternalProgram +from ..interpreterbase import FeatureNew, InvalidArguments, noPosargs, noKwargs +from ..interpreter import CustomTargetHolder + + +def ensure_list(value): + if not isinstance(value, list): + return [value] + return value + + +MIN_HOTDOC_VERSION = '0.8.100' + + +class HotdocTargetBuilder: + def __init__(self, name, state, hotdoc, kwargs): + self.hotdoc = hotdoc + self.build_by_default = kwargs.pop('build_by_default', False) + self.kwargs = kwargs + self.name = name + self.state = state + self.include_paths = OrderedDict() + + self.builddir = state.environment.get_build_dir() + self.sourcedir = state.environment.get_source_dir() + self.subdir = state.subdir + self.build_command = state.environment.get_build_command() + + self.cmd = ['conf', '--project-name', name, "--disable-incremental-build", + '--output', os.path.join(self.builddir, self.subdir, self.name + '-doc')] + + self._extra_extension_paths = set() + self.extra_assets = set() + self._dependencies = [] + self._subprojects = [] + + def process_known_arg(self, option, types, argname=None, + value_processor=None, mandatory=False, + force_list=False): + if not argname: + argname = option.strip("-").replace("-", "_") + + value, _ = self.get_value( + types, argname, None, value_processor, mandatory, force_list) + + self.set_arg_value(option, value) + + def set_arg_value(self, option, value): + if value is None: + return + + if isinstance(value, bool): + self.cmd.append(option) + elif isinstance(value, list): + # Do not do anything on empty lists + if value: + if option: + self.cmd.extend([option] + value) + else: + self.cmd.extend(value) + else: + self.cmd.extend([option, value]) + + def check_extra_arg_type(self, arg, value): + if isinstance(value, list): + for v in value: + self.check_extra_arg_type(arg, v) + return + + if not isinstance(value, (str, bool, mesonlib.File)): + raise InvalidArguments('Argument "%s=%s" should be a string.' % (arg, value)) + + def process_extra_args(self): + for arg, value in self.kwargs.items(): + option = "--" + arg.replace("_", "-") + self.check_extra_arg_type(arg, value) + self.set_arg_value(option, value) + + def get_value(self, types, argname, default=None, value_processor=None, + mandatory=False, force_list=False): + if not isinstance(types, list): + types = [types] + try: + uvalue = value = self.kwargs.pop(argname) + if value_processor: + value = value_processor(value) + + for t in types: + if isinstance(value, t): + if force_list and not isinstance(value, list): + return [value], uvalue + return value, uvalue + raise MesonException("%s field value %s is not valid," + " valid types are %s" % (argname, value, + types)) + except KeyError: + if mandatory: + raise MesonException("%s mandatory field not found" % argname) + + if default is not None: + return default, default + + return None, None + + def setup_extension_paths(self, paths): + if not isinstance(paths, list): + paths = [paths] + + for path in paths: + self.add_extension_paths([path]) + + return [] + + def add_extension_paths(self, paths): + for path in paths: + if path in self._extra_extension_paths: + continue + + self._extra_extension_paths.add(path) + self.cmd.extend(["--extra-extension-path", path]) + + def process_extra_extension_paths(self): + self.get_value([list, str], 'extra_extensions_paths', + default="", value_processor=self.setup_extension_paths) + + def replace_dirs_in_string(self, string): + return string.replace("@SOURCE_ROOT@", self.sourcedir).replace("@BUILD_ROOT@", self.builddir) + + def process_dependencies(self, deps): + cflags = set() + for dep in mesonlib.listify(ensure_list(deps)): + dep = getattr(dep, "held_object", dep) + if isinstance(dep, InternalDependency): + inc_args = get_include_args(dep.include_directories) + cflags.update([self.replace_dirs_in_string(x) + for x in inc_args]) + cflags.update(self.process_dependencies(dep.libraries)) + cflags.update(self.process_dependencies(dep.sources)) + cflags.update(self.process_dependencies(dep.ext_deps)) + elif isinstance(dep, Dependency): + cflags.update(dep.get_compile_args()) + elif isinstance(dep, (build.StaticLibrary, build.SharedLibrary)): + self._dependencies.append(dep) + for incd in dep.get_include_dirs(): + cflags.update(incd.get_incdirs()) + elif isinstance(dep, HotdocTarget): + # Recurse in hotdoc target dependencies + self.process_dependencies(dep.get_target_dependencies()) + self._subprojects.extend(dep.subprojects) + self.process_dependencies(dep.subprojects) + self.add_include_path(os.path.join(self.builddir, dep.hotdoc_conf.subdir)) + self.cmd += ['--extra-assets=' + p for p in dep.extra_assets] + self.add_extension_paths(dep.extra_extension_paths) + elif isinstance(dep, build.CustomTarget) or isinstance(dep, build.BuildTarget): + self._dependencies.append(dep) + + return [f.strip('-I') for f in cflags] + + def process_extra_assets(self): + self._extra_assets, _ = self.get_value("--extra-assets", (str, list), default=[], + force_list=True) + for assets_path in self._extra_assets: + self.cmd.extend(["--extra-assets", assets_path]) + + def process_subprojects(self): + _, value = self.get_value([ + list, HotdocTarget], argname="subprojects", + force_list=True, value_processor=self.process_dependencies) + + if value is not None: + self._subprojects.extend(value) + + def flatten_config_command(self): + cmd = [] + for arg in mesonlib.listify(self.cmd, flatten=True): + if isinstance(arg, mesonlib.File): + arg = arg.absolute_path(self.state.environment.get_source_dir(), + self.state.environment.get_build_dir()) + + cmd.append(arg) + + return cmd + + def generate_hotdoc_config(self): + cwd = os.path.abspath(os.curdir) + ncwd = os.path.join(self.sourcedir, self.subdir) + mlog.log('Generating Hotdoc configuration for: ', mlog.bold(self.name)) + os.chdir(ncwd) + self.hotdoc.run_hotdoc(self.flatten_config_command()) + os.chdir(cwd) + + def ensure_file(self, value): + if isinstance(value, list): + res = [] + for val in value: + res.append(self.ensure_file(val)) + return res + + if not isinstance(value, mesonlib.File): + return mesonlib.File.from_source_file(self.sourcedir, self.subdir, value) + + return value + + def ensure_dir(self, value): + if os.path.isabs(value): + _dir = value + else: + _dir = os.path.join(self.sourcedir, self.subdir, value) + + if not os.path.isdir(_dir): + raise InvalidArguments('"%s" is not a directory.' % _dir) + + return os.path.relpath(_dir, os.path.join(self.builddir, self.subdir)) + + def check_forbiden_args(self): + for arg in ['conf_file']: + if arg in self.kwargs: + raise InvalidArguments('Argument "%s" is forbidden.' % arg) + + def add_include_path(self, path): + self.include_paths[path] = path + + def make_targets(self): + self.check_forbiden_args() + file_types = (str, mesonlib.File) + self.process_known_arg("--index", file_types, mandatory=True, value_processor=self.ensure_file) + self.process_known_arg("--sitemap", file_types, mandatory=True, value_processor=self.ensure_file) + self.process_known_arg("--html-extra-theme", str, value_processor=self.ensure_dir) + self.process_known_arg(None, list, "include_paths", force_list=True, + value_processor=lambda x: [self.add_include_path(self.ensure_dir(v)) for v in ensure_list(x)]) + self.process_known_arg('--c-include-directories', + [Dependency, build.StaticLibrary, build.SharedLibrary, list], argname="dependencies", + force_list=True, value_processor=self.process_dependencies) + self.process_extra_assets() + self.process_extra_extension_paths() + self.process_subprojects() + + install, install = self.get_value(bool, "install", mandatory=False) + self.process_extra_args() + + fullname = self.name + '-doc' + hotdoc_config_name = fullname + '.json' + hotdoc_config_path = os.path.join( + self.builddir, self.subdir, hotdoc_config_name) + with open(hotdoc_config_path, 'w') as f: + f.write('{}') + + self.cmd += ['--conf-file', hotdoc_config_path] + self.add_include_path(os.path.join(self.builddir, self.subdir)) + self.add_include_path(os.path.join(self.sourcedir, self.subdir)) + + depfile = os.path.join(self.builddir, self.subdir, self.name + '.deps') + self.cmd += ['--deps-file-dest', depfile] + + for path in self.include_paths.keys(): + self.cmd.extend(['--include-path', path]) + self.generate_hotdoc_config() + + target_cmd = self.build_command + ["--internal", "hotdoc"] + \ + self.hotdoc.get_command() + ['run', '--conf-file', hotdoc_config_name] + \ + ['--builddir', os.path.join(self.builddir, self.subdir)] + + target = HotdocTarget(fullname, + subdir=self.subdir, + subproject=self.state.subproject, + hotdoc_conf=mesonlib.File.from_built_file( + self.subdir, hotdoc_config_name), + extra_extension_paths=self._extra_extension_paths, + extra_assets=self._extra_assets, + subprojects=self._subprojects, + command=target_cmd, + depends=self._dependencies, + output=fullname, + depfile=os.path.basename(depfile), + build_by_default=self.build_by_default) + + install_script = None + if install is True: + install_script = HotdocRunScript(self.build_command, [ + "--internal", "hotdoc", + "--install", os.path.join(fullname, 'html'), + '--name', self.name, + '--builddir', os.path.join(self.builddir, self.subdir)] + + self.hotdoc.get_command() + + ['run', '--conf-file', hotdoc_config_name]) + + return (target, install_script) + + +class HotdocTargetHolder(CustomTargetHolder): + def __init__(self, target, interp): + super().__init__(target, interp) + self.methods.update({'config_path': self.config_path_method}) + + @noPosargs + @noKwargs + def config_path_method(self, *args, **kwargs): + conf = self.held_object.hotdoc_conf.absolute_path(self.interpreter.environment.source_dir, + self.interpreter.environment.build_dir) + return self.interpreter.holderify(conf) + + +class HotdocTarget(build.CustomTarget): + def __init__(self, name, subdir, subproject, hotdoc_conf, extra_extension_paths, extra_assets, + subprojects, **kwargs): + super().__init__(name, subdir, subproject, kwargs, absolute_paths=True) + self.hotdoc_conf = hotdoc_conf + self.extra_extension_paths = extra_extension_paths + self.extra_assets = extra_assets + self.subprojects = subprojects + + def __getstate__(self): + # Make sure we do not try to pickle subprojects + res = self.__dict__.copy() + res['subprojects'] = [] + + return res + + +class HotdocRunScript(build.RunScript): + def __init__(self, script, args): + super().__init__(script, args) + + +class HotDocModule(ExtensionModule): + @FeatureNew('Hotdoc Module', '0.48.0') + def __init__(self, interpreter): + super().__init__(interpreter) + self.hotdoc = ExternalProgram('hotdoc') + if not self.hotdoc.found(): + raise MesonException('hotdoc executable not found') + + try: + from hotdoc.run_hotdoc import run # noqa: F401 + self.hotdoc.run_hotdoc = run + except Exception as e: + raise MesonException('hotdoc %s required but not found. (%s)' % ( + MIN_HOTDOC_VERSION, e)) + + @noKwargs + def has_extensions(self, state, args, kwargs): + res = self.hotdoc.run_hotdoc(['--has-extension'] + args) == 0 + return ModuleReturnValue(res, [res]) + + def generate_doc(self, state, args, kwargs): + if len(args) != 1: + raise MesonException('One positional argument is' + ' required for the project name.') + + project_name = args[0] + builder = HotdocTargetBuilder(project_name, state, self.hotdoc, kwargs) + target, install_script = builder.make_targets() + targets = [HotdocTargetHolder(target, self.interpreter)] + if install_script: + targets.append(install_script) + + return ModuleReturnValue(targets[0], targets) + + +def initialize(interpreter): + return HotDocModule(interpreter) diff --git a/mesonbuild/scripts/hotdochelper.py b/mesonbuild/scripts/hotdochelper.py new file mode 100644 index 000000000..826745d09 --- /dev/null +++ b/mesonbuild/scripts/hotdochelper.py @@ -0,0 +1,36 @@ +import os +import shutil +import subprocess + +from . import destdir_join + +import argparse + +parser = argparse.ArgumentParser() +parser.add_argument('--install') +parser.add_argument('--extra-extension-path', action="append", default=[]) +parser.add_argument('--name') +parser.add_argument('--builddir') +parser.add_argument('--project-version') + + +def run(argv): + options, args = parser.parse_known_args(argv) + subenv = os.environ.copy() + + for ext_path in options.extra_extension_path: + subenv['PYTHONPATH'] = subenv.get('PYTHONPATH', '') + ':' + ext_path + + res = subprocess.call(args, cwd=options.builddir, env=subenv) + if res != 0: + exit(res) + + if options.install: + source_dir = os.path.join(options.builddir, options.install) + destdir = os.environ.get('DESTDIR', '') + installdir = destdir_join(destdir, + os.path.join(os.environ['MESON_INSTALL_PREFIX'], + 'share/doc/', options.name, "html")) + + shutil.rmtree(installdir, ignore_errors=True) + shutil.copytree(source_dir, installdir) diff --git a/test cases/frameworks/23 hotdoc/doc/index.md b/test cases/frameworks/23 hotdoc/doc/index.md new file mode 100644 index 000000000..ea5eeb106 --- /dev/null +++ b/test cases/frameworks/23 hotdoc/doc/index.md @@ -0,0 +1 @@ +# Hello world! diff --git a/test cases/frameworks/23 hotdoc/doc/meson.build b/test cases/frameworks/23 hotdoc/doc/meson.build new file mode 100644 index 000000000..a09bff08d --- /dev/null +++ b/test cases/frameworks/23 hotdoc/doc/meson.build @@ -0,0 +1,19 @@ +hotdoc = import('hotdoc') + +target = hotdoc.generate_doc( + 'foobar', + c_smart_index: true, + project_version: '0.1', + sitemap: 'sitemap.txt', + index: 'index.md', + c_sources: files('../../10 gtk-doc/include/foo.h'), + languages: ['c'], + install: true, +) + +assert(target.config_path() == target.full_path() + '.json', + 'Hotdoc config paths do not match.' +) + +assert(hotdoc.has_extensions('search') == true, + 'Extension "search" provided by hotdoc core should always be found') diff --git a/test cases/frameworks/23 hotdoc/doc/sitemap.txt b/test cases/frameworks/23 hotdoc/doc/sitemap.txt new file mode 100644 index 000000000..b82354a1d --- /dev/null +++ b/test cases/frameworks/23 hotdoc/doc/sitemap.txt @@ -0,0 +1,3 @@ +index.md + c-index + diff --git a/test cases/frameworks/23 hotdoc/meson.build b/test cases/frameworks/23 hotdoc/meson.build new file mode 100644 index 000000000..191569dd6 --- /dev/null +++ b/test cases/frameworks/23 hotdoc/meson.build @@ -0,0 +1,9 @@ +project('hotdoc', 'c') + +hotdoc = find_program('hotdoc', required: false) +if not hotdoc.found() + error('MESON_SKIP_TEST hotdoc not found.') +endif + +subdir('doc') +