From bc7b86cc0b97cae5ea9915f9ab191b878a905bc0 Mon Sep 17 00:00:00 2001
From: Mark Gillard <marzer_@hotmail.com>
Date: Fri, 8 Dec 2023 15:40:56 +0200
Subject: [PATCH] added config option `main_page`

also:
- fixed searching for `CHANGELOG` too far up
---
 CHANGELOG.md         |  5 +++++
 src/poxy/fixers.py   |  4 ++--
 src/poxy/project.py  | 48 +++++++++++++++++++++++++++++++++++++++++++-
 src/poxy/run.py      | 11 +---------
 src/poxy/version.txt |  2 +-
 5 files changed, 56 insertions(+), 14 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index bd04367..e0eb697 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,10 @@
 # Changelog
 
+## v0.15.0 - 2023-12-08
+
+-   added config option `main_page` (a.k.a. `USE_MDFILE_AS_MAINPAGE`)
+-   fixed searching for `CHANGELOG` too far up the directory heirarchy (now stops when a `.git` folder is encountered)
+
 ## v0.14.0 - 2023-11-25
 
 -   added the use of `*` wildcards in `implementation_headers`
diff --git a/src/poxy/fixers.py b/src/poxy/fixers.py
index ebc5a3e..453995e 100644
--- a/src/poxy/fixers.py
+++ b/src/poxy/fixers.py
@@ -838,8 +838,8 @@ class Links(HTMLFixer):
     __internal_doc_id = re.compile(r'^[a-fA-F0-9]+$')
     __local_href = re.compile(r'^([-/_a-zA-Z0-9]+\.[a-zA-Z]+)(?:#(.*))?$')
     __godbolt = re.compile(r'^\s*(?:https?[:]//)?(?:www[.])?godbolt[.]org/z/.+?$', re.I)
-    __cppreference = re.compile(r'^\s*(?:https?[:]//)?(?:[a-z]+[.])?cppreference[.]com.*$', re.I)
-    __named_req = re.compile(r'^\s*(?:https?[:]//)?(?:[a-z]+[.])?cppreference[.]com/w/cpp/named_req/.+?$', re.I)
+    __cppreference = re.compile(r'^\s*(?:https?[:]//)?(?:[a-z]+[.])?cppreference[.]com/.*$', re.I)
+    __named_req = re.compile(r'^\s*(?:https?[:]//)?(?:[a-z]+[.])?cppreference[.]com/.+?/named_req/.+?$', re.I)
 
     def __call__(self, context: Context, doc: soup.HTMLDocument, path: Path):
         changed = False
diff --git a/src/poxy/project.py b/src/poxy/project.py
index 7aaa794..33fa1b1 100644
--- a/src/poxy/project.py
+++ b/src/poxy/project.py
@@ -1050,6 +1050,7 @@ class Context(object):
             Optional(r'autolinks'): {str: str},
             Optional(r'badges'): {str: ValueOrArray(str, name=r'badges', length=2)},
             Optional(r'changelog'): Or(str, bool),
+            Optional(r'main_page'): Or(str, bool),
             Optional(r'code_blocks'): CodeBlocks.schema,
             Optional(r'cpp'): Or(str, int, error=r'cpp: expected string or integer'),
             Optional(r'defines'): {str: Or(str, int, bool)},  # legacy
@@ -1560,7 +1561,11 @@ def add_internal_asset(p) -> str:
                                 ):
                                     self.changelog = candidate_file
                                     break
-                            if self.changelog or candidate_dir.parent == candidate_dir:
+                            if (
+                                self.changelog
+                                or candidate_dir.parent == candidate_dir
+                                or (candidate_dir / '.git').exists()
+                            ):
                                 break
                             candidate_dir = candidate_dir.parent
                         if not self.changelog:
@@ -1580,6 +1585,47 @@ def add_internal_asset(p) -> str:
                 self.changelog = temp_changelog_path
             self.verbose_value(r'Context.changelog', self.changelog)
 
+            # main_page (USE_MDFILE_AS_MAINPAGE)
+            self.main_page = ''
+            if r'main_page' in config:
+                if isinstance(config['main_page'], bool):
+                    if config['main_page']:
+                        candidate_names = (r'README', r'HOME', r'MAINPAGE', r'INDEX')
+                        candidate_extensions = (r'.md', r'.txt', r'')
+                        as_lowercase = (False, True)
+                        candidate_dir = self.input_dir
+                        while True:
+                            for name, ext, lower in itertools.product(
+                                candidate_names, candidate_extensions, as_lowercase
+                            ):
+                                candidate_file = Path(candidate_dir, rf'{name.lower() if lower else name}{ext}')
+                                if (
+                                    candidate_file.exists()
+                                    and candidate_file.is_file()
+                                    and candidate_file.stat().st_size <= 1024 * 1024 * 2
+                                ):
+                                    self.main_page = candidate_file
+                                    break
+                            if (
+                                self.main_page
+                                or candidate_dir.parent == candidate_dir
+                                or (candidate_dir / '.git').exists()
+                            ):
+                                break
+                            candidate_dir = candidate_dir.parent
+                        if not self.main_page:
+                            self.warning(
+                                rf'main_page: Option was set to true but no file with a known main_page file name could be found! Consider using an explicit path.'
+                            )
+
+                else:
+                    self.main_page = coerce_path(config['main_page'])
+                    if not self.main_page.is_absolute():
+                        self.main_page = Path(self.input_dir, self.main_page)
+                    if not self.main_page.exists() or not self.main_page.is_file():
+                        raise Error(rf'main_page: {config["main_page"]} did not exist or was not a file')
+            self.verbose_value(r'Context.main_page', self.main_page)
+
             # sources (INPUT, FILE_PATTERNS, STRIP_FROM_PATH, STRIP_FROM_INC_PATH, EXTRACT_ALL)
             self.sources = Sources(
                 config,
diff --git a/src/poxy/run.py b/src/poxy/run.py
index bf82136..ab402a0 100644
--- a/src/poxy/run.py
+++ b/src/poxy/run.py
@@ -195,16 +195,7 @@ def preprocess_doxyfile(context: Context):
         df.add_value(r'CLANG_OPTIONS', rf'-std=c++{context.cpp%100}')
         df.add_value(r'CLANG_OPTIONS', r'-Wno-everything')
 
-        home_md_path = None
-        for home_md in (r'HOME.md', r'home.md', r'INDEX.md', r'index.md', r'README.md', r'readme.md'):
-            p = Path(context.input_dir, home_md)
-            if p.exists() and p.is_file():
-                home_md_path = p
-                break
-        if home_md_path is not None:
-            home_md_temp_path = Path(context.temp_pages_dir, r'home.md')
-            copy_file(home_md_path, home_md_temp_path, logger=context.verbose_logger)
-            df.set_value(r'USE_MDFILE_AS_MAINPAGE', home_md_temp_path)
+        df.set_value(r'USE_MDFILE_AS_MAINPAGE', context.main_page)
 
         df.append()
         df.append(r'# context.warnings', end='\n\n')  # ---------------------------------------------------
diff --git a/src/poxy/version.txt b/src/poxy/version.txt
index a803cc2..a551051 100644
--- a/src/poxy/version.txt
+++ b/src/poxy/version.txt
@@ -1 +1 @@
-0.14.0
+0.15.0