diff --git a/.github/workflows/appimage-build.yml b/.github/workflows/appimage-build.yml index 59d88320..3f080f57 100644 --- a/.github/workflows/appimage-build.yml +++ b/.github/workflows/appimage-build.yml @@ -35,7 +35,7 @@ jobs: libxkbcommon0 \ libgtk-3-bin libglib2.0-bin shared-mime-info gsettings-desktop-schemas \ liblua5.4-dev libpci-dev libperl-dev libssl-dev libayatana-appindicator3-dev \ - perl python3 python3-minimal python3-dev python3-cffi mono-devel desktop-file-utils \ + perl python3 python3-minimal python3-dev python3-cffi python3-sphinx mono-devel desktop-file-utils \ fonts-noto-color-emoji breeze-gtk-theme \ patchelf file curl diff --git a/.github/workflows/windows-build.yml b/.github/workflows/windows-build.yml index ce076795..7ddb272c 100644 --- a/.github/workflows/windows-build.yml +++ b/.github/workflows/windows-build.yml @@ -40,6 +40,7 @@ jobs: python -m pip install --upgrade pip python -m pip install cffi python -m pip install zstandard + python -m pip install sphinx $ProgressPreference = 'SilentlyContinue' function Download-WithRetry { diff --git a/docs/build-docs.py b/docs/build-docs.py new file mode 100644 index 00000000..4f6fa93e --- /dev/null +++ b/docs/build-docs.py @@ -0,0 +1,42 @@ +#!/usr/bin/env python3 + +import os +import shutil +import subprocess +import sys + + +def main(): + if len(sys.argv) != 4: + raise SystemExit("usage: build-docs.py SOURCE_DIR OUTPUT_DIR STAMP_FILE") + + source_dir = os.path.abspath(sys.argv[1]) + output_dir = os.path.abspath(sys.argv[2]) + stamp_file = os.path.abspath(sys.argv[3]) + doctree_dir = output_dir + ".doctrees" + + shutil.rmtree(output_dir, ignore_errors=True) + shutil.rmtree(doctree_dir, ignore_errors=True) + os.makedirs(output_dir, exist_ok=True) + + subprocess.run( + [ + sys.executable, + "-m", + "sphinx", + "-b", + "html", + "-d", + doctree_dir, + source_dir, + output_dir, + ], + check=True, + ) + + with open(stamp_file, "w", encoding="utf-8") as stamp: + stamp.write("built\n") + + +if __name__ == "__main__": + main() diff --git a/docs/install-docs.py b/docs/install-docs.py new file mode 100644 index 00000000..c6881211 --- /dev/null +++ b/docs/install-docs.py @@ -0,0 +1,36 @@ +#!/usr/bin/env python3 + +import os +import shutil +import sys + + +def main(): + if len(sys.argv) != 4: + raise SystemExit("usage: install-docs.py STAMP_FILE SOURCE_DIR DATADIR") + + _, source_dir, datadir = sys.argv[1:] + source_dir = os.path.abspath(source_dir) + + if not os.path.isfile(sys.argv[1]): + raise SystemExit("documentation build did not produce its stamp file") + if not os.path.isfile(os.path.join(source_dir, "index.html")): + raise SystemExit("documentation build did not produce index.html") + + if os.path.isabs(datadir): + destdir = os.environ.get("DESTDIR", "") + if destdir: + data_root = os.path.join(destdir, datadir.lstrip("/\\")) + else: + data_root = datadir + else: + data_root = os.path.join(os.environ["MESON_INSTALL_DESTDIR_PREFIX"], datadir) + + destination = os.path.join(data_root, "doc", "zoitechat", "html") + shutil.rmtree(destination, ignore_errors=True) + os.makedirs(os.path.dirname(destination), exist_ok=True) + shutil.copytree(source_dir, destination) + + +if __name__ == "__main__": + main() diff --git a/flatpak/net.zoite.Zoitechat.json b/flatpak/net.zoite.Zoitechat.json index 8adb58e7..1669dfe4 100644 --- a/flatpak/net.zoite.Zoitechat.json +++ b/flatpak/net.zoite.Zoitechat.json @@ -54,6 +54,7 @@ "buildsystem": "meson", "config-opts": [ "-Ddbus-service-use-appid=true", + "-Dinstall-docs=false", "-Dwith-perl=perl", "-Dwith-python=python3", "-Dwith-lua=lua" diff --git a/meson.build b/meson.build index 1f981fc8..4af1aae2 100644 --- a/meson.build +++ b/meson.build @@ -35,6 +35,9 @@ config_h.set_quoted('PACKAGE_NAME', meson.project_name()) config_h.set_quoted('GETTEXT_PACKAGE', 'zoitechat') config_h.set_quoted('LOCALEDIR', join_paths(get_option('prefix'), get_option('datadir'), 'locale')) +config_h.set_quoted('ZOITECHAT_DOCDIR', + join_paths(get_option('prefix'), get_option('datadir'), 'doc', 'zoitechat', 'html') +) config_h.set10('ENABLE_NLS', true) # Optional features @@ -160,6 +163,41 @@ foreach ldflag : test_ldflags endforeach add_project_link_arguments(global_ldflags, language: 'c') +if get_option('install-docs') + docs_python = find_program('python3', 'python') + docs_sphinx = run_command(docs_python, '-c', 'import sphinx', check: false) + if docs_sphinx.returncode() != 0 + error('Sphinx is required to build the local HTML documentation. Install Sphinx or configure with -Dinstall-docs=false.') + endif + + docs_source_dir = join_paths(meson.source_root(), 'docs') + docs_output_dir = join_paths(meson.build_root(), 'docs-html') + docs_build_script = join_paths(docs_source_dir, 'build-docs.py') + docs_install_script = join_paths(docs_source_dir, 'install-docs.py') + + docs_target = custom_target( + 'html-documentation', + output: 'html-documentation.stamp', + command: [ + docs_python, + docs_build_script, + docs_source_dir, + docs_output_dir, + '@OUTPUT@', + ], + build_by_default: true, + build_always_stale: true, + ) + + meson.add_install_script( + docs_python, + docs_install_script, + docs_target, + docs_output_dir, + get_option('datadir'), + ) +endif + subdir('src') if get_option('plugin') subdir('plugins') diff --git a/meson_options.txt b/meson_options.txt index 04b0265e..66142726 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -33,6 +33,9 @@ option('install-appdata', type: 'boolean', option('install-plugin-metainfo', type: 'boolean', value: false, description: 'Installs metainfo files for enabled plugins, useful when distros create split packages' ) +option('install-docs', type: 'boolean', value: true, + description: 'Build and install the local HTML documentation' +) # Plugins option('with-checksum', type: 'boolean', diff --git a/packaging/fedora/zoitechat.spec b/packaging/fedora/zoitechat.spec index 32143425..61eff828 100644 --- a/packaging/fedora/zoitechat.spec +++ b/packaging/fedora/zoitechat.spec @@ -15,6 +15,7 @@ BuildRequires: perl BuildRequires: perl-devel BuildRequires: python3 BuildRequires: python3-cffi +BuildRequires: python3-sphinx BuildRequires: publicsuffix-list BuildRequires: xwayland-run BuildRequires: weston @@ -87,6 +88,7 @@ xwfb-run -- /usr/bin/meson test -C %{_vpath_builddir} --num-processes %{_smp_bui %{_datadir}/icons/hicolor/scalable/apps/net.zoite.Zoitechat.svg %{_datadir}/metainfo/net.zoite.Zoitechat.appdata.xml %{_datadir}/metainfo/net.zoite.Zoitechat*.metainfo.xml +%{_datadir}/doc/zoitechat/html/ %dir %{_libdir}/zoitechat %dir %{_libdir}/zoitechat/plugins %dir %{_libdir}/zoitechat/python diff --git a/src/fe-gtk/menu.c b/src/fe-gtk/menu.c index 740b22c4..75a0c39c 100644 --- a/src/fe-gtk/menu.c +++ b/src/fe-gtk/menu.c @@ -24,6 +24,7 @@ #ifdef WIN32 #include #include +#include #else #include #endif @@ -1740,9 +1741,50 @@ menu_ctcpguiopen (void) editlist_gui_open (NULL, NULL, ctcp_list, buf, "ctcpreply", "ctcpreply.conf", ctcp_help); } +static char * +menu_find_local_docs (void) +{ + char *path; + +#ifdef WIN32 + char *base_path; + + base_path = g_win32_get_package_installation_directory_of_module (NULL); + if (!base_path) + return NULL; + + path = g_build_filename (base_path, "share", "doc", "zoitechat", "html", "index.html", NULL); + g_free (base_path); +#else + const char *appdir; + + appdir = g_getenv ("APPDIR"); + if (appdir && *appdir) + path = g_build_filename (appdir, "usr", "share", "doc", "zoitechat", "html", "index.html", NULL); + else + path = g_build_filename (ZOITECHAT_DOCDIR, "index.html", NULL); +#endif + + if (g_file_test (path, G_FILE_TEST_IS_REGULAR)) + return path; + + g_free (path); + return NULL; +} + static void menu_docs (GtkWidget *wid, gpointer none) { + char *path; + + path = menu_find_local_docs (); + if (path) + { + fe_open_url (path); + g_free (path); + return; + } + fe_open_url ("https://docs.zoitechat.org/en/latest/"); } diff --git a/win32/copy/copy.vcxproj b/win32/copy/copy.vcxproj index 5cb9ea26..385e2665 100644 --- a/win32/copy/copy.vcxproj +++ b/win32/copy/copy.vcxproj @@ -30,6 +30,8 @@ + + @@ -82,6 +84,7 @@ + @@ -97,6 +100,7 @@ +