mkdocs-document-dates 3.6.0__tar.gz → 3.7.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {mkdocs_document_dates-3.6.0 → mkdocs_document_dates-3.7.0}/LICENSE +1 -1
- mkdocs_document_dates-3.7.0/MANIFEST.in +9 -0
- {mkdocs_document_dates-3.6.0/mkdocs_document_dates.egg-info → mkdocs_document_dates-3.7.0}/PKG-INFO +19 -30
- {mkdocs_document_dates-3.6.0 → mkdocs_document_dates-3.7.0}/README.md +13 -15
- mkdocs_document_dates-3.7.0/mkdocs_document_dates/__init__.py +1 -0
- {mkdocs_document_dates-3.6.0 → mkdocs_document_dates-3.7.0}/mkdocs_document_dates/cache_manager.py +85 -5
- {mkdocs_document_dates-3.6.0 → mkdocs_document_dates-3.7.0}/mkdocs_document_dates/hooks/pre-commit +1 -1
- mkdocs_document_dates-3.7.0/mkdocs_document_dates/hooks_installer.py +98 -0
- {mkdocs_document_dates-3.6.0 → mkdocs_document_dates-3.7.0}/mkdocs_document_dates/plugin.py +38 -11
- mkdocs_document_dates-3.7.0/mkdocs_document_dates/static/.DS_Store +0 -0
- {mkdocs_document_dates-3.6.0 → mkdocs_document_dates-3.7.0}/mkdocs_document_dates/static/core/core.css +2 -1
- {mkdocs_document_dates-3.6.0 → mkdocs_document_dates-3.7.0}/mkdocs_document_dates/static/core/core.js +5 -12
- {mkdocs_document_dates-3.6.0 → mkdocs_document_dates-3.7.0}/mkdocs_document_dates/static/core/utils.js +12 -0
- {mkdocs_document_dates-3.6.0 → mkdocs_document_dates-3.7.0}/mkdocs_document_dates/static/templates/recently_updated_group.html +30 -7
- {mkdocs_document_dates-3.6.0 → mkdocs_document_dates-3.7.0}/mkdocs_document_dates/utils.py +16 -7
- {mkdocs_document_dates-3.6.0 → mkdocs_document_dates-3.7.0/mkdocs_document_dates.egg-info}/PKG-INFO +19 -30
- {mkdocs_document_dates-3.6.0 → mkdocs_document_dates-3.7.0}/mkdocs_document_dates.egg-info/SOURCES.txt +1 -0
- {mkdocs_document_dates-3.6.0 → mkdocs_document_dates-3.7.0}/mkdocs_document_dates.egg-info/entry_points.txt +1 -0
- mkdocs_document_dates-3.7.0/pyproject.toml +48 -0
- mkdocs_document_dates-3.7.0/setup.py +50 -0
- mkdocs_document_dates-3.6.0/MANIFEST.in +0 -2
- mkdocs_document_dates-3.6.0/mkdocs_document_dates/__init__.py +0 -6
- mkdocs_document_dates-3.6.0/mkdocs_document_dates/hooks_installer.py +0 -120
- mkdocs_document_dates-3.6.0/pyproject.toml +0 -4
- mkdocs_document_dates-3.6.0/setup.py +0 -69
- {mkdocs_document_dates-3.6.0 → mkdocs_document_dates-3.7.0}/mkdocs_document_dates/static/config/user.config.css +0 -0
- {mkdocs_document_dates-3.6.0 → mkdocs_document_dates-3.7.0}/mkdocs_document_dates/static/config/user.config.js +0 -0
- {mkdocs_document_dates-3.6.0 → mkdocs_document_dates-3.7.0}/mkdocs_document_dates/static/core/default.config.js +0 -0
- {mkdocs_document_dates-3.6.0 → mkdocs_document_dates-3.7.0}/mkdocs_document_dates/static/core/md5.min.js +0 -0
- {mkdocs_document_dates-3.6.0 → mkdocs_document_dates-3.7.0}/mkdocs_document_dates/static/core/timeago.full.min.js +0 -0
- {mkdocs_document_dates-3.6.0 → mkdocs_document_dates-3.7.0}/mkdocs_document_dates/static/core/timeago.min.js +0 -0
- {mkdocs_document_dates-3.6.0 → mkdocs_document_dates-3.7.0}/mkdocs_document_dates/static/fonts/material-icons.css +0 -0
- {mkdocs_document_dates-3.6.0 → mkdocs_document_dates-3.7.0}/mkdocs_document_dates/static/fonts/materialicons.woff2 +0 -0
- {mkdocs_document_dates-3.6.0 → mkdocs_document_dates-3.7.0}/mkdocs_document_dates/static/templates/recently_updated_detail.html +0 -0
- {mkdocs_document_dates-3.6.0 → mkdocs_document_dates-3.7.0}/mkdocs_document_dates/static/templates/recently_updated_grid.html +0 -0
- {mkdocs_document_dates-3.6.0 → mkdocs_document_dates-3.7.0}/mkdocs_document_dates/static/templates/recently_updated_list.html +0 -0
- {mkdocs_document_dates-3.6.0 → mkdocs_document_dates-3.7.0}/mkdocs_document_dates/static/tippy/backdrop.css +0 -0
- {mkdocs_document_dates-3.6.0 → mkdocs_document_dates-3.7.0}/mkdocs_document_dates/static/tippy/light.css +0 -0
- {mkdocs_document_dates-3.6.0 → mkdocs_document_dates-3.7.0}/mkdocs_document_dates/static/tippy/material.css +0 -0
- {mkdocs_document_dates-3.6.0 → mkdocs_document_dates-3.7.0}/mkdocs_document_dates/static/tippy/popper.min.js +0 -0
- {mkdocs_document_dates-3.6.0 → mkdocs_document_dates-3.7.0}/mkdocs_document_dates/static/tippy/scale.css +0 -0
- {mkdocs_document_dates-3.6.0 → mkdocs_document_dates-3.7.0}/mkdocs_document_dates/static/tippy/shift-away.css +0 -0
- {mkdocs_document_dates-3.6.0 → mkdocs_document_dates-3.7.0}/mkdocs_document_dates/static/tippy/tippy.css +0 -0
- {mkdocs_document_dates-3.6.0 → mkdocs_document_dates-3.7.0}/mkdocs_document_dates/static/tippy/tippy.umd.min.js +0 -0
- {mkdocs_document_dates-3.6.0 → mkdocs_document_dates-3.7.0}/mkdocs_document_dates.egg-info/dependency_links.txt +0 -0
- {mkdocs_document_dates-3.6.0 → mkdocs_document_dates-3.7.0}/mkdocs_document_dates.egg-info/requires.txt +0 -0
- {mkdocs_document_dates-3.6.0 → mkdocs_document_dates-3.7.0}/mkdocs_document_dates.egg-info/top_level.txt +0 -0
- {mkdocs_document_dates-3.6.0 → mkdocs_document_dates-3.7.0}/setup.cfg +0 -0
{mkdocs_document_dates-3.6.0/mkdocs_document_dates.egg-info → mkdocs_document_dates-3.7.0}/PKG-INFO
RENAMED
|
@@ -1,28 +1,19 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: mkdocs-document-dates
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.7.0
|
|
4
4
|
Summary: A new generation MkDocs plugin for displaying exact creation date, last updated date, authors, email of documents
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
5
|
+
Author-email: Aaron Wang <aaronwqt@gmail.com>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/jaywhj/mkdocs-document-dates
|
|
8
|
+
Project-URL: Repository, https://github.com/jaywhj/mkdocs-document-dates
|
|
9
|
+
Project-URL: Documentation, https://jaywhj.netlify.app/document-dates-en
|
|
9
10
|
Classifier: Programming Language :: Python :: 3
|
|
10
11
|
Classifier: Operating System :: OS Independent
|
|
11
12
|
Requires-Python: >=3.7
|
|
12
13
|
Description-Content-Type: text/markdown
|
|
13
14
|
License-File: LICENSE
|
|
14
15
|
Requires-Dist: mkdocs>=1.1.0
|
|
15
|
-
Dynamic: author
|
|
16
|
-
Dynamic: author-email
|
|
17
|
-
Dynamic: classifier
|
|
18
|
-
Dynamic: description
|
|
19
|
-
Dynamic: description-content-type
|
|
20
|
-
Dynamic: home-page
|
|
21
|
-
Dynamic: license
|
|
22
16
|
Dynamic: license-file
|
|
23
|
-
Dynamic: requires-dist
|
|
24
|
-
Dynamic: requires-python
|
|
25
|
-
Dynamic: summary
|
|
26
17
|
|
|
27
18
|
# mkdocs-document-dates
|
|
28
19
|
|
|
@@ -36,7 +27,7 @@ A new generation MkDocs plugin for displaying exact **creation date, last update
|
|
|
36
27
|
|
|
37
28
|
## Features
|
|
38
29
|
|
|
39
|
-
- [x]
|
|
30
|
+
- [x] Works in any environment: no-Git, Git environments, Docker, all CI/CD build systems, etc.
|
|
40
31
|
- [x] Support list display of recently updated documents (in descending order of update date)
|
|
41
32
|
- [x] Support for manually specifying date and author in `Front Matter`
|
|
42
33
|
- [x] Support for multiple date formats (date, datetime, timeago)
|
|
@@ -67,41 +58,39 @@ plugins:
|
|
|
67
58
|
- document-dates
|
|
68
59
|
```
|
|
69
60
|
|
|
70
|
-
Or,
|
|
61
|
+
Or, common configuration:
|
|
71
62
|
|
|
72
63
|
```yaml
|
|
73
64
|
plugins:
|
|
74
65
|
- document-dates:
|
|
75
66
|
position: top # Display position: top(after title) bottom(end of document), default: top
|
|
76
67
|
type: date # Date type: date datetime timeago, default: date
|
|
77
|
-
exclude: # List of excluded files
|
|
68
|
+
exclude: # List of excluded files (support unix shell-style wildcards)
|
|
78
69
|
- temp.md # Example: exclude the specified file
|
|
79
70
|
- blog/* # Example: exclude all files in blog folder, including subfolders
|
|
80
|
-
|
|
81
|
-
time_format: '%H:%M:%S' # Time format strings (valid only if type=datetime)
|
|
71
|
+
- '*/index.md' # Example: exclude all index.md files in any subfolders
|
|
82
72
|
```
|
|
83
73
|
|
|
84
74
|
## Customization Settings
|
|
85
75
|
|
|
86
76
|
In addition to the above basic configuration, the plug-in also provides a wealth of customization options to meet a variety of individual needs:
|
|
87
77
|
|
|
88
|
-
- [
|
|
89
|
-
- [
|
|
90
|
-
- [
|
|
91
|
-
- [
|
|
92
|
-
- [
|
|
93
|
-
- [
|
|
94
|
-
- [
|
|
95
|
-
- [Other Tips](https://jaywhj.netlify.app/document-dates-en#Other-Tips): Introducing the Do's of using plugin in Docker
|
|
78
|
+
- [Date & Time](https://jaywhj.netlify.app/document-dates-en#Date--Time): Introduces the mechanism for obtaining document dates and methods for personalized customization, support for manually specifying the creation date and last updated date for each document
|
|
79
|
+
- [Author](https://jaywhj.netlify.app/document-dates-en#Author): Introduces the mechanism for obtaining document authors and methods for personalized customization, support for manually specifying the author information for each document, such as name, link, avatar, email, etc.
|
|
80
|
+
- [Avatar](https://jaywhj.netlify.app/document-dates-en#Avatar): You can manually specify the avatar for each author, support local file path and URL path
|
|
81
|
+
- [Structure and Style](https://jaywhj.netlify.app/document-dates-en#Structure-and-Style): You can freely configure the plugin's display structure in mkdocs.yml or Front Matter. You can quickly set the plugin styles through preset entrances, such as icons, themes, colors, fonts, animations, dividing line and so on
|
|
82
|
+
- [Template Variables](https://jaywhj.netlify.app/document-dates-en#Template-Variables): Can be used to optimize `sitemap.xml` for site SEO
|
|
83
|
+
- [Recently Updated Module](https://jaywhj.netlify.app/document-dates-en#Recently-Updated-Module): Enable list of recently updated documents (in descending order of update date), this is ideal for sites with a large number of documents, so that readers can quickly see what's new
|
|
84
|
+
- [Localization Language](https://jaywhj.netlify.app/document-dates-en#Localization-Language): More localization languages for `timeago` and `tooltip`
|
|
96
85
|
- [Development Stories](https://jaywhj.netlify.app/document-dates-en#Development-Stories): Describes the origin of the plug-in, the difficulties and solutions encountered in development, and the principles and directions of product design
|
|
97
86
|
|
|
98
87
|
See the documentation for details: https://jaywhj.netlify.app/document-dates-en
|
|
99
88
|
|
|
100
|
-
|
|
89
|
+

|
|
101
90
|
|
|
102
91
|
## Other Projects
|
|
103
92
|
|
|
104
|
-
- [**MaterialX**](https://github.com/jaywhj/mkdocs-materialx), the next generation of mkdocs-material
|
|
93
|
+
- [**MaterialX**](https://github.com/jaywhj/mkdocs-materialx), the next generation of mkdocs-material. Build beautiful sites the way you already know and love. Based on `mkdocs-material-9.7.1` and is named `X`, it provides ongoing maintenance and updates (since mkdocs-material will stop being maintained).
|
|
105
94
|
Updates have been released that refactor and add a lot of new features, see https://github.com/jaywhj/mkdocs-materialx/releases/
|
|
106
95
|
|
|
107
96
|
<br />
|
|
@@ -10,7 +10,7 @@ A new generation MkDocs plugin for displaying exact **creation date, last update
|
|
|
10
10
|
|
|
11
11
|
## Features
|
|
12
12
|
|
|
13
|
-
- [x]
|
|
13
|
+
- [x] Works in any environment: no-Git, Git environments, Docker, all CI/CD build systems, etc.
|
|
14
14
|
- [x] Support list display of recently updated documents (in descending order of update date)
|
|
15
15
|
- [x] Support for manually specifying date and author in `Front Matter`
|
|
16
16
|
- [x] Support for multiple date formats (date, datetime, timeago)
|
|
@@ -41,41 +41,39 @@ plugins:
|
|
|
41
41
|
- document-dates
|
|
42
42
|
```
|
|
43
43
|
|
|
44
|
-
Or,
|
|
44
|
+
Or, common configuration:
|
|
45
45
|
|
|
46
46
|
```yaml
|
|
47
47
|
plugins:
|
|
48
48
|
- document-dates:
|
|
49
49
|
position: top # Display position: top(after title) bottom(end of document), default: top
|
|
50
50
|
type: date # Date type: date datetime timeago, default: date
|
|
51
|
-
exclude: # List of excluded files
|
|
51
|
+
exclude: # List of excluded files (support unix shell-style wildcards)
|
|
52
52
|
- temp.md # Example: exclude the specified file
|
|
53
53
|
- blog/* # Example: exclude all files in blog folder, including subfolders
|
|
54
|
-
|
|
55
|
-
time_format: '%H:%M:%S' # Time format strings (valid only if type=datetime)
|
|
54
|
+
- '*/index.md' # Example: exclude all index.md files in any subfolders
|
|
56
55
|
```
|
|
57
56
|
|
|
58
57
|
## Customization Settings
|
|
59
58
|
|
|
60
59
|
In addition to the above basic configuration, the plug-in also provides a wealth of customization options to meet a variety of individual needs:
|
|
61
60
|
|
|
62
|
-
- [
|
|
63
|
-
- [
|
|
64
|
-
- [
|
|
65
|
-
- [
|
|
66
|
-
- [
|
|
67
|
-
- [
|
|
68
|
-
- [
|
|
69
|
-
- [Other Tips](https://jaywhj.netlify.app/document-dates-en#Other-Tips): Introducing the Do's of using plugin in Docker
|
|
61
|
+
- [Date & Time](https://jaywhj.netlify.app/document-dates-en#Date--Time): Introduces the mechanism for obtaining document dates and methods for personalized customization, support for manually specifying the creation date and last updated date for each document
|
|
62
|
+
- [Author](https://jaywhj.netlify.app/document-dates-en#Author): Introduces the mechanism for obtaining document authors and methods for personalized customization, support for manually specifying the author information for each document, such as name, link, avatar, email, etc.
|
|
63
|
+
- [Avatar](https://jaywhj.netlify.app/document-dates-en#Avatar): You can manually specify the avatar for each author, support local file path and URL path
|
|
64
|
+
- [Structure and Style](https://jaywhj.netlify.app/document-dates-en#Structure-and-Style): You can freely configure the plugin's display structure in mkdocs.yml or Front Matter. You can quickly set the plugin styles through preset entrances, such as icons, themes, colors, fonts, animations, dividing line and so on
|
|
65
|
+
- [Template Variables](https://jaywhj.netlify.app/document-dates-en#Template-Variables): Can be used to optimize `sitemap.xml` for site SEO
|
|
66
|
+
- [Recently Updated Module](https://jaywhj.netlify.app/document-dates-en#Recently-Updated-Module): Enable list of recently updated documents (in descending order of update date), this is ideal for sites with a large number of documents, so that readers can quickly see what's new
|
|
67
|
+
- [Localization Language](https://jaywhj.netlify.app/document-dates-en#Localization-Language): More localization languages for `timeago` and `tooltip`
|
|
70
68
|
- [Development Stories](https://jaywhj.netlify.app/document-dates-en#Development-Stories): Describes the origin of the plug-in, the difficulties and solutions encountered in development, and the principles and directions of product design
|
|
71
69
|
|
|
72
70
|
See the documentation for details: https://jaywhj.netlify.app/document-dates-en
|
|
73
71
|
|
|
74
|
-
|
|
72
|
+

|
|
75
73
|
|
|
76
74
|
## Other Projects
|
|
77
75
|
|
|
78
|
-
- [**MaterialX**](https://github.com/jaywhj/mkdocs-materialx), the next generation of mkdocs-material
|
|
76
|
+
- [**MaterialX**](https://github.com/jaywhj/mkdocs-materialx), the next generation of mkdocs-material. Build beautiful sites the way you already know and love. Based on `mkdocs-material-9.7.1` and is named `X`, it provides ongoing maintenance and updates (since mkdocs-material will stop being maintained).
|
|
79
77
|
Updates have been released that refactor and add a lot of new features, see https://github.com/jaywhj/mkdocs-materialx/releases/
|
|
80
78
|
|
|
81
79
|
<br />
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""MkDocs Document Dates Plugin."""
|
{mkdocs_document_dates-3.6.0 → mkdocs_document_dates-3.7.0}/mkdocs_document_dates/cache_manager.py
RENAMED
|
@@ -1,16 +1,92 @@
|
|
|
1
1
|
import logging
|
|
2
|
+
import os
|
|
2
3
|
import subprocess
|
|
3
4
|
from pathlib import Path
|
|
5
|
+
from logging.handlers import RotatingFileHandler
|
|
6
|
+
from typing import Optional
|
|
4
7
|
from .utils import read_jsonl_cache, write_jsonl_cache, get_file_creation_time, get_git_first_commit_time
|
|
5
8
|
|
|
6
9
|
logger = logging.getLogger("mkdocs.plugins.document_dates")
|
|
7
|
-
|
|
10
|
+
_LOGGING_CONFIGURED = False
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def _default_log_file() -> Path:
|
|
14
|
+
try:
|
|
15
|
+
git_root = Path(subprocess.check_output(
|
|
16
|
+
['git', 'rev-parse', '--show-toplevel'],
|
|
17
|
+
env=_clean_git_env(),
|
|
18
|
+
encoding='utf-8'
|
|
19
|
+
).strip())
|
|
20
|
+
base_dir = git_root
|
|
21
|
+
except Exception:
|
|
22
|
+
base_dir = Path.cwd()
|
|
23
|
+
return base_dir / "mkdocs_document_dates.log"
|
|
24
|
+
|
|
25
|
+
def configure_file_logging(log_file: Optional[Path] = None, level: int = logging.DEBUG) -> Optional[Path]:
|
|
26
|
+
global _LOGGING_CONFIGURED
|
|
27
|
+
if _LOGGING_CONFIGURED:
|
|
28
|
+
return log_file
|
|
29
|
+
|
|
30
|
+
env_log_file = os.getenv("MKDOCS_DOCUMENT_DATES_LOG_FILE")
|
|
31
|
+
if log_file is None and env_log_file:
|
|
32
|
+
log_file = Path(env_log_file).expanduser()
|
|
33
|
+
|
|
34
|
+
if log_file is None:
|
|
35
|
+
return None
|
|
36
|
+
|
|
37
|
+
log_file.parent.mkdir(parents=True, exist_ok=True)
|
|
38
|
+
|
|
39
|
+
handler = RotatingFileHandler(
|
|
40
|
+
log_file,
|
|
41
|
+
maxBytes=5 * 1024 * 1024,
|
|
42
|
+
backupCount=3,
|
|
43
|
+
encoding="utf-8",
|
|
44
|
+
)
|
|
45
|
+
handler.setLevel(level)
|
|
46
|
+
handler.setFormatter(logging.Formatter(
|
|
47
|
+
fmt="%(asctime)s [%(filename)s:%(lineno)d] %(message)s",
|
|
48
|
+
datefmt="%Y-%m-%d %H:%M:%S",
|
|
49
|
+
))
|
|
50
|
+
|
|
51
|
+
logger.setLevel(level)
|
|
52
|
+
logger.addHandler(handler)
|
|
53
|
+
logger.propagate = False
|
|
54
|
+
_LOGGING_CONFIGURED = True
|
|
55
|
+
logger.debug(f"File logging enabled: {log_file}")
|
|
56
|
+
return log_file
|
|
57
|
+
|
|
58
|
+
def _env_truthy(name: str) -> bool:
|
|
59
|
+
value = os.getenv(name)
|
|
60
|
+
if value is None:
|
|
61
|
+
return False
|
|
62
|
+
value = value.strip().lower()
|
|
63
|
+
return value not in ("", "0", "false", "no", "off")
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def _clean_git_env():
|
|
67
|
+
env = os.environ.copy()
|
|
68
|
+
|
|
69
|
+
for k in [
|
|
70
|
+
"GIT_DIR",
|
|
71
|
+
"GIT_WORK_TREE",
|
|
72
|
+
"GIT_COMMON_DIR",
|
|
73
|
+
"GIT_INDEX_FILE",
|
|
74
|
+
"GIT_PREFIX",
|
|
75
|
+
"GIT_SUPER_PREFIX",
|
|
76
|
+
"GIT_CEILING_DIRECTORIES",
|
|
77
|
+
]:
|
|
78
|
+
env.pop(k, None)
|
|
79
|
+
|
|
80
|
+
env["GIT_OPTIONAL_LOCKS"] = "0"
|
|
81
|
+
|
|
82
|
+
return env
|
|
8
83
|
|
|
9
84
|
def find_mkdocs_projects():
|
|
10
85
|
projects = []
|
|
11
86
|
try:
|
|
12
87
|
git_root = Path(subprocess.check_output(
|
|
13
88
|
['git', 'rev-parse', '--show-toplevel'],
|
|
89
|
+
env=_clean_git_env(),
|
|
14
90
|
encoding='utf-8'
|
|
15
91
|
).strip())
|
|
16
92
|
|
|
@@ -39,7 +115,7 @@ def setup_gitattributes(docs_dir: Path):
|
|
|
39
115
|
content += '\n'
|
|
40
116
|
content += f"{union_merge_line}\n"
|
|
41
117
|
gitattributes_path.write_text(content, encoding='utf-8')
|
|
42
|
-
subprocess.run(["git", "add", str(gitattributes_path)], check=True)
|
|
118
|
+
subprocess.run(["git", "add", str(gitattributes_path)], cwd=docs_dir, env=_clean_git_env(), check=True)
|
|
43
119
|
logger.info(f"Updated .gitattributes file: {gitattributes_path}")
|
|
44
120
|
return True
|
|
45
121
|
except (IOError, OSError) as e:
|
|
@@ -49,8 +125,12 @@ def setup_gitattributes(docs_dir: Path):
|
|
|
49
125
|
return False
|
|
50
126
|
|
|
51
127
|
def update_cache():
|
|
52
|
-
|
|
128
|
+
if os.getenv("MKDOCS_DOCUMENT_DATES_LOG_FILE"):
|
|
129
|
+
configure_file_logging()
|
|
130
|
+
elif _env_truthy("MKDOCS_DOCUMENT_DATES_DEBUG"):
|
|
131
|
+
configure_file_logging(_default_log_file())
|
|
53
132
|
|
|
133
|
+
global_updated = False
|
|
54
134
|
for project_dir in find_mkdocs_projects():
|
|
55
135
|
try:
|
|
56
136
|
project_updated = False
|
|
@@ -65,7 +145,7 @@ def update_cache():
|
|
|
65
145
|
|
|
66
146
|
# 获取docs目录下已跟踪(tracked)的markdown文件
|
|
67
147
|
cmd = ["git", "ls-files", "*.md"]
|
|
68
|
-
result = subprocess.run(cmd, cwd=docs_dir, capture_output=True, encoding='utf-8')
|
|
148
|
+
result = subprocess.run(cmd, cwd=docs_dir, env=_clean_git_env(), capture_output=True, encoding='utf-8')
|
|
69
149
|
tracked_files = result.stdout.splitlines() if result.stdout else []
|
|
70
150
|
|
|
71
151
|
if not tracked_files:
|
|
@@ -115,4 +195,4 @@ def update_cache():
|
|
|
115
195
|
|
|
116
196
|
|
|
117
197
|
if __name__ == "__main__":
|
|
118
|
-
update_cache()
|
|
198
|
+
update_cache()
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import sys
|
|
3
|
+
import subprocess
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
DEFAULT_HOOKS_DIRNAME = ".githooks"
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class HookInstallError(Exception):
|
|
10
|
+
pass
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def get_repo_root() -> Path:
|
|
14
|
+
result = subprocess.run(
|
|
15
|
+
["git", "rev-parse", "--show-toplevel"],
|
|
16
|
+
capture_output=True,
|
|
17
|
+
text=True,
|
|
18
|
+
)
|
|
19
|
+
if result.returncode != 0 or not result.stdout.strip():
|
|
20
|
+
raise HookInstallError("This command must be run inside a Git repo. Please cd into your project directory and try again.")
|
|
21
|
+
return Path(result.stdout.strip())
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def ensure_hooks_dir(repo_root: Path) -> Path:
|
|
25
|
+
hooks_dir = repo_root / DEFAULT_HOOKS_DIRNAME
|
|
26
|
+
try:
|
|
27
|
+
hooks_dir.mkdir(parents=True, exist_ok=True)
|
|
28
|
+
os.chmod(hooks_dir, 0o755)
|
|
29
|
+
except Exception as e:
|
|
30
|
+
raise HookInstallError(f"Failed to create hooks directory: {hooks_dir} ({e})")
|
|
31
|
+
return hooks_dir
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def write_hooks(source_dir: Path, target_dir: Path):
|
|
35
|
+
if not source_dir.exists():
|
|
36
|
+
raise HookInstallError(f"Hooks source directory not found: {source_dir}")
|
|
37
|
+
|
|
38
|
+
shebang = f"#!{sys.executable}"
|
|
39
|
+
|
|
40
|
+
try:
|
|
41
|
+
for file in source_dir.iterdir():
|
|
42
|
+
if file.name.startswith(".") or not file.is_file():
|
|
43
|
+
continue
|
|
44
|
+
|
|
45
|
+
content = file.read_text(encoding="utf-8")
|
|
46
|
+
|
|
47
|
+
if content.startswith("#!"):
|
|
48
|
+
os.linesep
|
|
49
|
+
content = shebang + "\n" + content.split("\n", 1)[1]
|
|
50
|
+
else:
|
|
51
|
+
content = shebang + "\n" + content
|
|
52
|
+
|
|
53
|
+
target = target_dir / file.name
|
|
54
|
+
target.write_text(content, encoding="utf-8")
|
|
55
|
+
os.chmod(target, 0o755)
|
|
56
|
+
|
|
57
|
+
except Exception as e:
|
|
58
|
+
raise HookInstallError(f"Failed to write hook files: {e}")
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def set_hooks_path(repo_root: Path, hooks_dir: Path):
|
|
62
|
+
rel_path = hooks_dir.relative_to(repo_root).as_posix()
|
|
63
|
+
|
|
64
|
+
# # 配置自定义合并驱动
|
|
65
|
+
# script_path = hooks_dir / 'json_merge_driver.py'
|
|
66
|
+
# subprocess.run(['git', 'config', 'merge.custom_json_merge.name', 'Custom JSON merge driver'], check=True)
|
|
67
|
+
# subprocess.run(['git', 'config', 'merge.custom_json_merge.driver', f'"{sys.executable}" "{script_path}" %O %A %B'], check=True)
|
|
68
|
+
|
|
69
|
+
result = subprocess.run(
|
|
70
|
+
["git", "config", "core.hooksPath", rel_path],
|
|
71
|
+
cwd=repo_root,
|
|
72
|
+
capture_output=True,
|
|
73
|
+
text=True,
|
|
74
|
+
)
|
|
75
|
+
if result.returncode != 0:
|
|
76
|
+
raise HookInstallError(result.stderr.strip() or "Failed to set hooksPath")
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def install():
|
|
80
|
+
try:
|
|
81
|
+
repo_root = get_repo_root()
|
|
82
|
+
hooks_dir = ensure_hooks_dir(repo_root)
|
|
83
|
+
|
|
84
|
+
source_dir = Path(__file__).parent / "hooks"
|
|
85
|
+
|
|
86
|
+
write_hooks(source_dir, hooks_dir)
|
|
87
|
+
set_hooks_path(repo_root, hooks_dir)
|
|
88
|
+
|
|
89
|
+
print(f"✔ Hooks installed successfully: {hooks_dir}")
|
|
90
|
+
|
|
91
|
+
except HookInstallError as e:
|
|
92
|
+
print(f"✖ Installation failed: {e}", file=sys.stderr)
|
|
93
|
+
except Exception as e:
|
|
94
|
+
print(f"✖ Unexpected error: {e}", file=sys.stderr)
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
if __name__ == "__main__":
|
|
98
|
+
install()
|
|
@@ -10,7 +10,7 @@ from mkdocs.config import config_options
|
|
|
10
10
|
from mkdocs.structure.pages import Page
|
|
11
11
|
from mkdocs.utils import get_relative_url
|
|
12
12
|
from urllib.parse import urlparse
|
|
13
|
-
from .utils import get_file_creation_time, load_git_metadata, load_git_last_updated_date, read_jsonl_cache,is_excluded, get_recently_updated_files
|
|
13
|
+
from .utils import get_file_creation_time, load_git_metadata, load_git_last_updated_date, read_jsonl_cache, compile_exclude_patterns, is_excluded, get_recently_updated_files
|
|
14
14
|
|
|
15
15
|
logger = logging.getLogger("mkdocs.plugins.document_dates")
|
|
16
16
|
logger.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, CRITICAL
|
|
@@ -43,11 +43,13 @@ class DocumentDatesPlugin(BasePlugin):
|
|
|
43
43
|
|
|
44
44
|
def __init__(self):
|
|
45
45
|
super().__init__()
|
|
46
|
+
|
|
46
47
|
self.dates_cache = {}
|
|
47
48
|
self.last_updated_dates = {}
|
|
48
49
|
self.authors_yml = {}
|
|
49
50
|
self.recent_docs_html = None
|
|
50
51
|
self.recent_enable = False
|
|
52
|
+
self._exclude_patterns = []
|
|
51
53
|
|
|
52
54
|
def on_config(self, config):
|
|
53
55
|
docs_dir_path = Path(config['docs_dir'])
|
|
@@ -96,7 +98,14 @@ class DocumentDatesPlugin(BasePlugin):
|
|
|
96
98
|
# https://cdn.jsdelivr.net/npm/timeago.js@4.0.2/dist/timeago.min.js
|
|
97
99
|
# https://cdnjs.cloudflare.com/ajax/libs/timeago.js/4.0.2/timeago.full.min.js
|
|
98
100
|
if self.config['type'] == 'timeago':
|
|
99
|
-
config
|
|
101
|
+
scripts = config.get('extra_javascript') or []
|
|
102
|
+
has_timeago = any(
|
|
103
|
+
str(item).endswith('timeago.min.js') or str(item).endswith('timeago.full.min.js')
|
|
104
|
+
for item in scripts
|
|
105
|
+
)
|
|
106
|
+
if not has_timeago:
|
|
107
|
+
scripts.insert(0, 'assets/document_dates/core/timeago.min.js')
|
|
108
|
+
config['extra_javascript'] = scripts
|
|
100
109
|
|
|
101
110
|
"""
|
|
102
111
|
Tippy.js, for Tooltip
|
|
@@ -138,6 +147,8 @@ class DocumentDatesPlugin(BasePlugin):
|
|
|
138
147
|
'assets/document_dates/core/core.js'
|
|
139
148
|
])
|
|
140
149
|
|
|
150
|
+
self._exclude_patterns = compile_exclude_patterns(self.config['exclude'])
|
|
151
|
+
|
|
141
152
|
return config
|
|
142
153
|
|
|
143
154
|
def on_page_markdown(self, markdown, page: Page, config, files):
|
|
@@ -157,14 +168,19 @@ class DocumentDatesPlugin(BasePlugin):
|
|
|
157
168
|
|
|
158
169
|
# 获取作者信息
|
|
159
170
|
authors = self._get_author_info(rel_path, page, config)
|
|
160
|
-
|
|
161
|
-
#
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
171
|
+
|
|
172
|
+
# 按 MaterialX 的数据规范给 meta 填充数据
|
|
173
|
+
mx = page.meta.setdefault("_mx", {})
|
|
174
|
+
mx["document_dates"] = {
|
|
175
|
+
"dates": {
|
|
176
|
+
"created": created.isoformat(),
|
|
177
|
+
"updated": updated.isoformat(),
|
|
178
|
+
},
|
|
179
|
+
"authors": authors
|
|
180
|
+
}
|
|
181
|
+
|
|
166
182
|
# 检查是否需要排除
|
|
167
|
-
if is_excluded(rel_path, self.
|
|
183
|
+
if is_excluded(rel_path, self._exclude_patterns):
|
|
168
184
|
return markdown
|
|
169
185
|
|
|
170
186
|
# 生成日期和作者信息 HTML
|
|
@@ -187,7 +203,8 @@ class DocumentDatesPlugin(BasePlugin):
|
|
|
187
203
|
limit = recently_updated_config.get('limit', 10)
|
|
188
204
|
|
|
189
205
|
# 获取最近更新的文档数据
|
|
190
|
-
|
|
206
|
+
recent_exclude_patterns = compile_exclude_patterns(exclude_list)
|
|
207
|
+
recently_updated_docs = get_recently_updated_files(self.last_updated_dates, files, recent_exclude_patterns, limit, self.recent_enable)
|
|
191
208
|
|
|
192
209
|
# 将数据注入到 config['extra'] 中供全局访问
|
|
193
210
|
if 'extra' not in config:
|
|
@@ -198,6 +215,16 @@ class DocumentDatesPlugin(BasePlugin):
|
|
|
198
215
|
if self.recent_enable:
|
|
199
216
|
self.recent_docs_html = self._render_recently_updated_html(recently_updated_docs)
|
|
200
217
|
|
|
218
|
+
# # 便捷访问日期数据函数
|
|
219
|
+
# def mdd_access(page, domain):
|
|
220
|
+
# return (
|
|
221
|
+
# page.meta.get("_mx", {})
|
|
222
|
+
# .get("document_dates", {})
|
|
223
|
+
# .get(domain, {})
|
|
224
|
+
# )
|
|
225
|
+
|
|
226
|
+
# env.globals["mdd"] = mdd_access
|
|
227
|
+
|
|
201
228
|
return env
|
|
202
229
|
|
|
203
230
|
def on_post_page(self, output, page, config):
|
|
@@ -477,4 +504,4 @@ class DocumentDatesPlugin(BasePlugin):
|
|
|
477
504
|
|
|
478
505
|
pos = next_newline + 1
|
|
479
506
|
|
|
480
|
-
return '', length
|
|
507
|
+
return '', length
|
|
Binary file
|
|
@@ -68,6 +68,7 @@
|
|
|
68
68
|
display: flex;
|
|
69
69
|
align-items: center;
|
|
70
70
|
flex-shrink: 0;
|
|
71
|
+
margin-right: 1.4rem;
|
|
71
72
|
}
|
|
72
73
|
.dd-item {
|
|
73
74
|
display: inline-flex;
|
|
@@ -142,8 +143,8 @@
|
|
|
142
143
|
display: block;
|
|
143
144
|
|
|
144
145
|
/* Fix bug in Safari: rounded corners may blink to show square corners */
|
|
145
|
-
will-change: transform;
|
|
146
146
|
transform: translateZ(0);
|
|
147
|
+
will-change: transform;
|
|
147
148
|
}
|
|
148
149
|
.avatar-wrapper:hover {
|
|
149
150
|
transform: scale(1.08);
|
|
@@ -163,16 +163,9 @@ function applyTimeagoToTimes(timeNodes, rawLocale) {
|
|
|
163
163
|
|
|
164
164
|
// 处理数据加载
|
|
165
165
|
function processDataLoading() {
|
|
166
|
-
// 获取 locale,优先级:用户主动选择 > 服务端显式配置 > 用户浏览器语言 > 站点HTML语言 > 默认英语
|
|
167
|
-
const rawLocale =
|
|
168
|
-
ddUtils.getSavedLanguage() ||
|
|
169
|
-
// ddpEl.getAttribute('locale') ||
|
|
170
|
-
navigator.language ||
|
|
171
|
-
navigator.userLanguage ||
|
|
172
|
-
document.documentElement.lang ||
|
|
173
|
-
'en';
|
|
174
|
-
|
|
175
166
|
document.querySelectorAll('.document-dates-plugin').forEach(ddpEl => {
|
|
167
|
+
const rawLocale = ddUtils.getCurrentLocale(ddpEl);
|
|
168
|
+
|
|
176
169
|
// 处理 time 元素(使用 timeago 时)
|
|
177
170
|
applyTimeagoToTimes(ddpEl.querySelectorAll('time'), rawLocale);
|
|
178
171
|
|
|
@@ -192,6 +185,7 @@ function processDataLoading() {
|
|
|
192
185
|
});
|
|
193
186
|
|
|
194
187
|
// 处理其他 timeago 时间
|
|
188
|
+
const rawLocale = ddUtils.getCurrentLocale();
|
|
195
189
|
applyTimeagoToTimes(document.querySelectorAll('time.dd-timeago'), rawLocale);
|
|
196
190
|
}
|
|
197
191
|
|
|
@@ -386,13 +380,13 @@ function initLayoutSwitcher() {
|
|
|
386
380
|
grid.classList.toggle('is-list', savedLayout === 'list');
|
|
387
381
|
grid.classList.toggle('is-detail', savedLayout === 'detail');
|
|
388
382
|
|
|
383
|
+
|
|
389
384
|
// 查找或创建切换器容器
|
|
390
385
|
let switcher = grid.previousElementSibling;
|
|
391
386
|
if (!switcher || !switcher.classList.contains('article-layout-switcher')) {
|
|
392
387
|
// 如果模板中没写,可以动态注入,但建议写在模板里以保证 UI 一致性
|
|
393
388
|
return;
|
|
394
389
|
}
|
|
395
|
-
|
|
396
390
|
const listBtn = switcher.querySelector('.layout-list-btn');
|
|
397
391
|
const detailBtn = switcher.querySelector('.layout-detail-btn');
|
|
398
392
|
const gridBtn = switcher.querySelector('.layout-grid-btn');
|
|
@@ -402,9 +396,9 @@ function initLayoutSwitcher() {
|
|
|
402
396
|
if (detailBtn) detailBtn.classList.toggle('is-active', layout === 'detail');
|
|
403
397
|
if (gridBtn) gridBtn.classList.toggle('is-active', layout === 'grid');
|
|
404
398
|
};
|
|
405
|
-
|
|
406
399
|
updateActiveBtn(savedLayout);
|
|
407
400
|
|
|
401
|
+
|
|
408
402
|
const setLayout = (layout) => {
|
|
409
403
|
grid.classList.remove('is-list', 'is-detail');
|
|
410
404
|
if (layout !== 'grid') {
|
|
@@ -413,7 +407,6 @@ function initLayoutSwitcher() {
|
|
|
413
407
|
localStorage.setItem('dd_recent_docs_layout', layout);
|
|
414
408
|
updateActiveBtn(layout);
|
|
415
409
|
};
|
|
416
|
-
|
|
417
410
|
if (listBtn) {
|
|
418
411
|
listBtn.onclick = () => {
|
|
419
412
|
setLayout('list');
|
|
@@ -44,6 +44,18 @@ window.ddUtils = {
|
|
|
44
44
|
}
|
|
45
45
|
},
|
|
46
46
|
|
|
47
|
+
// 获取当前语言环境,优先级:用户选择 > 元素配置 > 浏览器语言 > 页面语言 > 默认 'en'
|
|
48
|
+
getCurrentLocale(el) {
|
|
49
|
+
return (
|
|
50
|
+
this.getSavedLanguage() ||
|
|
51
|
+
(el ? el.getAttribute('locale') : null) ||
|
|
52
|
+
navigator.language ||
|
|
53
|
+
navigator.userLanguage ||
|
|
54
|
+
document.documentElement.lang ||
|
|
55
|
+
'en'
|
|
56
|
+
);
|
|
57
|
+
},
|
|
58
|
+
|
|
47
59
|
// 清除保存的语言设置
|
|
48
60
|
clearLanguage() {
|
|
49
61
|
try {
|