mkdocs-document-dates 3.4.1__tar.gz → 3.4.5__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.
Files changed (38) hide show
  1. {mkdocs_document_dates-3.4.1/mkdocs_document_dates.egg-info → mkdocs_document_dates-3.4.5}/PKG-INFO +7 -8
  2. {mkdocs_document_dates-3.4.1 → mkdocs_document_dates-3.4.5}/README.md +6 -7
  3. {mkdocs_document_dates-3.4.1 → mkdocs_document_dates-3.4.5}/mkdocs_document_dates/cache_manager.py +2 -2
  4. {mkdocs_document_dates-3.4.1 → mkdocs_document_dates-3.4.5}/mkdocs_document_dates/hooks_installer.py +14 -3
  5. {mkdocs_document_dates-3.4.1 → mkdocs_document_dates-3.4.5}/mkdocs_document_dates/plugin.py +20 -16
  6. {mkdocs_document_dates-3.4.1 → mkdocs_document_dates-3.4.5}/mkdocs_document_dates/utils.py +88 -52
  7. {mkdocs_document_dates-3.4.1 → mkdocs_document_dates-3.4.5/mkdocs_document_dates.egg-info}/PKG-INFO +7 -8
  8. {mkdocs_document_dates-3.4.1 → mkdocs_document_dates-3.4.5}/setup.py +1 -1
  9. {mkdocs_document_dates-3.4.1 → mkdocs_document_dates-3.4.5}/LICENSE +0 -0
  10. {mkdocs_document_dates-3.4.1 → mkdocs_document_dates-3.4.5}/MANIFEST.in +0 -0
  11. {mkdocs_document_dates-3.4.1 → mkdocs_document_dates-3.4.5}/mkdocs_document_dates/__init__.py +0 -0
  12. {mkdocs_document_dates-3.4.1 → mkdocs_document_dates-3.4.5}/mkdocs_document_dates/hooks/pre-commit +0 -0
  13. {mkdocs_document_dates-3.4.1 → mkdocs_document_dates-3.4.5}/mkdocs_document_dates/static/config/user.config.css +0 -0
  14. {mkdocs_document_dates-3.4.1 → mkdocs_document_dates-3.4.5}/mkdocs_document_dates/static/config/user.config.js +0 -0
  15. {mkdocs_document_dates-3.4.1 → mkdocs_document_dates-3.4.5}/mkdocs_document_dates/static/core/core.css +0 -0
  16. {mkdocs_document_dates-3.4.1 → mkdocs_document_dates-3.4.5}/mkdocs_document_dates/static/core/core.js +0 -0
  17. {mkdocs_document_dates-3.4.1 → mkdocs_document_dates-3.4.5}/mkdocs_document_dates/static/core/default.config.js +0 -0
  18. {mkdocs_document_dates-3.4.1 → mkdocs_document_dates-3.4.5}/mkdocs_document_dates/static/core/timeago.full.min.js +0 -0
  19. {mkdocs_document_dates-3.4.1 → mkdocs_document_dates-3.4.5}/mkdocs_document_dates/static/core/timeago.min.js +0 -0
  20. {mkdocs_document_dates-3.4.1 → mkdocs_document_dates-3.4.5}/mkdocs_document_dates/static/core/utils.js +0 -0
  21. {mkdocs_document_dates-3.4.1 → mkdocs_document_dates-3.4.5}/mkdocs_document_dates/static/fonts/material-icons.css +0 -0
  22. {mkdocs_document_dates-3.4.1 → mkdocs_document_dates-3.4.5}/mkdocs_document_dates/static/fonts/materialicons.woff2 +0 -0
  23. {mkdocs_document_dates-3.4.1 → mkdocs_document_dates-3.4.5}/mkdocs_document_dates/static/templates/recently_updated.html +0 -0
  24. {mkdocs_document_dates-3.4.1 → mkdocs_document_dates-3.4.5}/mkdocs_document_dates/static/tippy/backdrop.css +0 -0
  25. {mkdocs_document_dates-3.4.1 → mkdocs_document_dates-3.4.5}/mkdocs_document_dates/static/tippy/light.css +0 -0
  26. {mkdocs_document_dates-3.4.1 → mkdocs_document_dates-3.4.5}/mkdocs_document_dates/static/tippy/material.css +0 -0
  27. {mkdocs_document_dates-3.4.1 → mkdocs_document_dates-3.4.5}/mkdocs_document_dates/static/tippy/popper.min.js +0 -0
  28. {mkdocs_document_dates-3.4.1 → mkdocs_document_dates-3.4.5}/mkdocs_document_dates/static/tippy/scale.css +0 -0
  29. {mkdocs_document_dates-3.4.1 → mkdocs_document_dates-3.4.5}/mkdocs_document_dates/static/tippy/shift-away.css +0 -0
  30. {mkdocs_document_dates-3.4.1 → mkdocs_document_dates-3.4.5}/mkdocs_document_dates/static/tippy/tippy.css +0 -0
  31. {mkdocs_document_dates-3.4.1 → mkdocs_document_dates-3.4.5}/mkdocs_document_dates/static/tippy/tippy.umd.min.js +0 -0
  32. {mkdocs_document_dates-3.4.1 → mkdocs_document_dates-3.4.5}/mkdocs_document_dates.egg-info/SOURCES.txt +0 -0
  33. {mkdocs_document_dates-3.4.1 → mkdocs_document_dates-3.4.5}/mkdocs_document_dates.egg-info/dependency_links.txt +0 -0
  34. {mkdocs_document_dates-3.4.1 → mkdocs_document_dates-3.4.5}/mkdocs_document_dates.egg-info/entry_points.txt +0 -0
  35. {mkdocs_document_dates-3.4.1 → mkdocs_document_dates-3.4.5}/mkdocs_document_dates.egg-info/requires.txt +0 -0
  36. {mkdocs_document_dates-3.4.1 → mkdocs_document_dates-3.4.5}/mkdocs_document_dates.egg-info/top_level.txt +0 -0
  37. {mkdocs_document_dates-3.4.1 → mkdocs_document_dates-3.4.5}/pyproject.toml +0 -0
  38. {mkdocs_document_dates-3.4.1 → mkdocs_document_dates-3.4.5}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mkdocs-document-dates
3
- Version: 3.4.1
3
+ Version: 3.4.5
4
4
  Summary: A new generation MkDocs plugin for displaying exact creation time, last update time, authors, email of documents
5
5
  Home-page: https://github.com/jaywhj/mkdocs-document-dates
6
6
  Author: Aaron Wang
@@ -36,14 +36,14 @@ A new generation MkDocs plugin for displaying exact **creation time, last update
36
36
 
37
37
  ## Features
38
38
 
39
- - [x] Always display **exact** meta-info of the document for any environment (no-Git, Git, all CI/CD build systems, etc.)
39
+ - [x] Always displays **exact** meta information of the document and works in any environment (no Git, Git environments, Docker containers, all CI/CD build systems, etc.)
40
40
  - [x] Support for manually specifying time and author in `Front Matter`
41
41
  - [x] Support for multiple time formats (date, datetime, timeago)
42
42
  - [x] Support for multiple author modes (avatar, text, hidden)
43
43
  - [x] Flexible display position (top or bottom)
44
44
  - [x] Elegant styling (fully customizable)
45
45
  - [x] Smart Tooltip Hover Tips
46
- - [x] Supports display of recently updated documents in an overall list
46
+ - [x] Support list display of recently updated documents
47
47
  - [x] Multi-language support, localization support, intelligent recognition of user language, automatic adaptation
48
48
  - [x] Cross-platform support (Windows, macOS, Linux)
49
49
  - [x] **Ultimate build efficiency**: O(1), no need to set env vars to distinguish runs
@@ -53,7 +53,6 @@ A new generation MkDocs plugin for displaying exact **creation time, last update
53
53
  | git-revision-date-localized | > 3 s | > 30 s | O(n) |
54
54
  | document-dates | < 0.1 s | < 0.15 s | O(1) |
55
55
 
56
-
57
56
  ## Installation
58
57
 
59
58
  ```bash
@@ -77,9 +76,9 @@ plugins:
77
76
  position: top # Display position: top(after title) bottom(end of document)
78
77
  type: date # Date type: date datetime timeago, default: date
79
78
  exclude: # List of excluded files
80
- - temp.md # Exclude specific file
81
- - drafts/* # Exclude all files in drafts folder, including subfolders
82
- date_format: '%Y-%m-%d' # Date format strings, e.g., %Y-%m-%d, %b %d, %Y
79
+ - temp.md # Example: exclude the specified file
80
+ - blog/* # Example: exclude all files in blog folder, including subfolders
81
+ date_format: '%Y-%m-%d' # Date format strings (e.g., %Y-%m-%d, %b %d, %Y)
83
82
  time_format: '%H:%M:%S' # Time format strings (valid only if type=datetime)
84
83
  show_author: true # Author display mode: true(avatar) text(text) false(hidden)
85
84
  recently-updated: true # Whether to turn on recently updated data, default: false
@@ -96,7 +95,7 @@ In addition to the above basic configuration, the plug-in also provides a wealth
96
95
  - [Add Localization Language](https://jaywhj.netlify.app/document-dates-en#Add-Localization-Language): More localization languages for `timeago` and `tooltip`
97
96
  - [Use Template Variables](https://jaywhj.netlify.app/document-dates-en#Use-Template-Variables): Can be used to optimize `sitemap.xml` for site SEO, can be used to re-customize plug-ins, etc.
98
97
  - [Add Recently Updated Module](https://jaywhj.netlify.app/document-dates-en#Add-Recently-Updated-Module): Enable list of recently updated documents
99
- - [Other Tips](https://jaywhj.netlify.app/document-dates-en#Other-Tips): Introduction to technical principles, caching mechanisms
98
+ - [Other Tips](https://jaywhj.netlify.app/document-dates-en#Other-Tips): Introduction to technical principles, caching mechanisms, and how to use it in Docker
100
99
  - [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
101
100
 
102
101
  See the documentation for details: https://jaywhj.netlify.app/document-dates-en
@@ -10,14 +10,14 @@ A new generation MkDocs plugin for displaying exact **creation time, last update
10
10
 
11
11
  ## Features
12
12
 
13
- - [x] Always display **exact** meta-info of the document for any environment (no-Git, Git, all CI/CD build systems, etc.)
13
+ - [x] Always displays **exact** meta information of the document and works in any environment (no Git, Git environments, Docker containers, all CI/CD build systems, etc.)
14
14
  - [x] Support for manually specifying time and author in `Front Matter`
15
15
  - [x] Support for multiple time formats (date, datetime, timeago)
16
16
  - [x] Support for multiple author modes (avatar, text, hidden)
17
17
  - [x] Flexible display position (top or bottom)
18
18
  - [x] Elegant styling (fully customizable)
19
19
  - [x] Smart Tooltip Hover Tips
20
- - [x] Supports display of recently updated documents in an overall list
20
+ - [x] Support list display of recently updated documents
21
21
  - [x] Multi-language support, localization support, intelligent recognition of user language, automatic adaptation
22
22
  - [x] Cross-platform support (Windows, macOS, Linux)
23
23
  - [x] **Ultimate build efficiency**: O(1), no need to set env vars to distinguish runs
@@ -27,7 +27,6 @@ A new generation MkDocs plugin for displaying exact **creation time, last update
27
27
  | git-revision-date-localized | > 3 s | > 30 s | O(n) |
28
28
  | document-dates | < 0.1 s | < 0.15 s | O(1) |
29
29
 
30
-
31
30
  ## Installation
32
31
 
33
32
  ```bash
@@ -51,9 +50,9 @@ plugins:
51
50
  position: top # Display position: top(after title) bottom(end of document)
52
51
  type: date # Date type: date datetime timeago, default: date
53
52
  exclude: # List of excluded files
54
- - temp.md # Exclude specific file
55
- - drafts/* # Exclude all files in drafts folder, including subfolders
56
- date_format: '%Y-%m-%d' # Date format strings, e.g., %Y-%m-%d, %b %d, %Y
53
+ - temp.md # Example: exclude the specified file
54
+ - blog/* # Example: exclude all files in blog folder, including subfolders
55
+ date_format: '%Y-%m-%d' # Date format strings (e.g., %Y-%m-%d, %b %d, %Y)
57
56
  time_format: '%H:%M:%S' # Time format strings (valid only if type=datetime)
58
57
  show_author: true # Author display mode: true(avatar) text(text) false(hidden)
59
58
  recently-updated: true # Whether to turn on recently updated data, default: false
@@ -70,7 +69,7 @@ In addition to the above basic configuration, the plug-in also provides a wealth
70
69
  - [Add Localization Language](https://jaywhj.netlify.app/document-dates-en#Add-Localization-Language): More localization languages for `timeago` and `tooltip`
71
70
  - [Use Template Variables](https://jaywhj.netlify.app/document-dates-en#Use-Template-Variables): Can be used to optimize `sitemap.xml` for site SEO, can be used to re-customize plug-ins, etc.
72
71
  - [Add Recently Updated Module](https://jaywhj.netlify.app/document-dates-en#Add-Recently-Updated-Module): Enable list of recently updated documents
73
- - [Other Tips](https://jaywhj.netlify.app/document-dates-en#Other-Tips): Introduction to technical principles, caching mechanisms
72
+ - [Other Tips](https://jaywhj.netlify.app/document-dates-en#Other-Tips): Introduction to technical principles, caching mechanisms, and how to use it in Docker
74
73
  - [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
75
74
 
76
75
  See the documentation for details: https://jaywhj.netlify.app/document-dates-en
@@ -11,7 +11,7 @@ def find_mkdocs_projects():
11
11
  try:
12
12
  git_root = Path(subprocess.check_output(
13
13
  ['git', 'rev-parse', '--show-toplevel'],
14
- text=True, encoding='utf-8'
14
+ encoding='utf-8'
15
15
  ).strip())
16
16
 
17
17
  # 遍历 git_root 及子目录, 寻找 mkdocs.yml 文件
@@ -65,7 +65,7 @@ def update_cache():
65
65
 
66
66
  # 获取docs目录下已跟踪(tracked)的markdown文件
67
67
  cmd = ["git", "ls-files", "*.md"]
68
- result = subprocess.run(cmd, cwd=docs_dir, capture_output=True, text=True)
68
+ result = subprocess.run(cmd, cwd=docs_dir, capture_output=True, encoding='utf-8')
69
69
  tracked_files = result.stdout.splitlines() if result.stdout else []
70
70
 
71
71
  if not tracked_files:
@@ -12,13 +12,20 @@ def get_config_dir():
12
12
  if platform.system().lower().startswith('win'):
13
13
  return Path(os.getenv('APPDATA', str(Path.home() / 'AppData' / 'Roaming')))
14
14
  else:
15
- return Path.home() / '.config'
15
+ # 优先级:XDG_CONFIG_HOME > $HOME/.config > cwd/.config
16
+ xdg_config = os.getenv('XDG_CONFIG_HOME')
17
+ if xdg_config:
18
+ return Path(xdg_config)
19
+ home = os.getenv('HOME')
20
+ if home:
21
+ return Path(home) / '.config'
22
+ return Path.cwd() / '.config'
16
23
 
17
24
  def check_python_version(interpreter):
18
25
  try:
19
26
  result = subprocess.run(
20
27
  [interpreter, "-c", "import sys; print(sys.version_info >= (3, 7))"],
21
- capture_output=True, text=True)
28
+ capture_output=True, encoding='utf-8')
22
29
  if result.returncode == 0 and result.stdout.strip().lower() == 'true':
23
30
  return True
24
31
  else:
@@ -44,7 +51,11 @@ def setup_hooks_directory():
44
51
  os.chmod(config_dir, 0o755)
45
52
  return config_dir
46
53
  except PermissionError:
47
- logger.error(f"No permission to create directory: {config_dir}")
54
+ logger.error(
55
+ f"No permission to create directory: {config_dir}\n"
56
+ "If running inside Docker, please set environment variable HOME=/docs "
57
+ "or XDG_CONFIG_HOME to a writable path."
58
+ )
48
59
  except Exception as e:
49
60
  logger.error(f"Failed to create directory {config_dir}: {str(e)}")
50
61
  return None
@@ -9,7 +9,7 @@ from mkdocs.plugins import BasePlugin
9
9
  from mkdocs.config import config_options
10
10
  from mkdocs.structure.pages import Page
11
11
  from urllib.parse import urlparse
12
- from .utils import get_file_creation_time, load_git_cache, read_jsonl_cache,is_excluded, get_recently_modified_files
12
+ from .utils import get_file_creation_time, load_git_cache, read_jsonl_cache,is_excluded, get_recently_updated_files
13
13
 
14
14
  logger = logging.getLogger("mkdocs.plugins.document_dates")
15
15
  logger.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, CRITICAL
@@ -41,8 +41,8 @@ class DocumentDatesPlugin(BasePlugin):
41
41
  ('time_format', config_options.Type(str, default='%H:%M:%S')),
42
42
  ('position', config_options.Type(str, default='top')),
43
43
  ('exclude', config_options.Type(list, default=[])),
44
- ('created_field_names', config_options.Type(list, default=['created', 'date', 'creation'])),
45
- ('modified_field_names', config_options.Type(list, default=['modified', 'updated', 'last_modified', 'last_updated'])),
44
+ ('created_field_names', config_options.Type(list, default=['created', 'date'])),
45
+ ('modified_field_names', config_options.Type(list, default=['modified', 'updated'])),
46
46
  ('show_author', config_options.Choice((True, False, 'text'), default=True)),
47
47
  ('recently-updated', config_options.Type((dict, bool), default={}))
48
48
  )
@@ -50,6 +50,7 @@ class DocumentDatesPlugin(BasePlugin):
50
50
  def __init__(self):
51
51
  super().__init__()
52
52
  self.dates_cache = {}
53
+ self.last_updated_dates = {}
53
54
  self.authors_yml = {}
54
55
  self.github_username = None
55
56
  self.recent_docs_html = None
@@ -145,10 +146,9 @@ class DocumentDatesPlugin(BasePlugin):
145
146
 
146
147
  def on_nav(self, nav, config, files):
147
148
  recently_updated_config = self.config.get('recently-updated')
148
- if not recently_updated_config:
149
- return nav
149
+ if recently_updated_config:
150
+ self.recent_enable = True
150
151
 
151
- self.recent_enable = True
152
152
  # 兼容 true 配置
153
153
  if recently_updated_config is True:
154
154
  recently_updated_config = {}
@@ -156,19 +156,20 @@ class DocumentDatesPlugin(BasePlugin):
156
156
  # 获取配置
157
157
  exclude_list = recently_updated_config.get('exclude', [])
158
158
  limit = recently_updated_config.get('limit', 10)
159
- template_path = recently_updated_config.get("template")
159
+ template_path = recently_updated_config.get('template')
160
160
 
161
- # 获取 docs 目录下最近更新的文档
162
- recently_modified_files = get_recently_modified_files(files, exclude_list, limit)
161
+ # 获取最近更新日期和最近更新的文档数据
162
+ docs_dir = Path(config['docs_dir'])
163
+ self.last_updated_dates, recently_updated_docs = get_recently_updated_files(docs_dir, files, exclude_list, limit, self.recent_enable)
163
164
 
164
165
  # 将数据注入到 config['extra'] 中供全局访问
165
166
  if 'extra' not in config:
166
167
  config['extra'] = {}
167
- config['extra']['recently_updated_docs'] = recently_modified_files
168
+ config['extra']['recently_updated_docs'] = recently_updated_docs
168
169
 
169
170
  # 渲染HTML
170
- docs_dir = Path(config['docs_dir'])
171
- self.recent_docs_html = self._render_recently_updated_html(docs_dir, template_path, recently_modified_files)
171
+ if self.recent_enable:
172
+ self.recent_docs_html = self._render_recently_updated_html(docs_dir, template_path, recently_updated_docs)
172
173
 
173
174
  return nav
174
175
 
@@ -210,7 +211,7 @@ class DocumentDatesPlugin(BasePlugin):
210
211
  if not created:
211
212
  created = self._get_file_creation_time(file_path, rel_path)
212
213
  if not modified:
213
- modified = self._get_file_modification_time(file_path)
214
+ modified = self._get_file_modification_time(file_path, rel_path)
214
215
 
215
216
  # 获取作者信息
216
217
  authors = self._get_author_info(rel_path, page, config)
@@ -221,8 +222,8 @@ class DocumentDatesPlugin(BasePlugin):
221
222
  page.meta['document_dates_authors'] = authors
222
223
 
223
224
  # 占位符替换
224
- if self.recent_enable and '<!-- RECENTLY_UPDATED_DOCS -->' in markdown:
225
- markdown = markdown.replace('<!-- RECENTLY_UPDATED_DOCS -->', self.recent_docs_html or '')
225
+ if self.recent_enable and '\n<!-- RECENTLY_UPDATED_DOCS -->' in markdown:
226
+ markdown = markdown.replace('\n<!-- RECENTLY_UPDATED_DOCS -->', self.recent_docs_html or '')
226
227
 
227
228
  # 检查是否需要排除
228
229
  if is_excluded(rel_path, self.config['exclude']):
@@ -293,7 +294,10 @@ class DocumentDatesPlugin(BasePlugin):
293
294
  # 从文件系统获取
294
295
  return get_file_creation_time(file_path).astimezone()
295
296
 
296
- def _get_file_modification_time(self, file_path):
297
+ def _get_file_modification_time(self, file_path, rel_path):
298
+ # 优先从缓存中读取
299
+ if rel_path in self.last_updated_dates:
300
+ return datetime.fromtimestamp(self.last_updated_dates[rel_path]).astimezone()
297
301
  # 从文件系统获取最后修改时间
298
302
  stat = os.stat(file_path)
299
303
  return datetime.fromtimestamp(stat.st_mtime).astimezone()
@@ -1,11 +1,13 @@
1
1
  import os
2
2
  import platform
3
3
  import json
4
+ import heapq
4
5
  import logging
5
6
  import subprocess
6
7
  from pathlib import Path
7
8
  from datetime import datetime
8
9
  from collections import defaultdict
10
+ from mkdocs.structure.files import Files
9
11
 
10
12
  logger = logging.getLogger("mkdocs.plugins.document_dates")
11
13
  logger.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, CRITICAL
@@ -27,7 +29,7 @@ def get_git_first_commit_time(file_path):
27
29
  try:
28
30
  # git log --reverse --format="%aI" -- {file_path} | head -n 1
29
31
  cmd_list = ['git', 'log', '--reverse', '--format=%aI', '--', file_path]
30
- process = subprocess.run(cmd_list, capture_output=True, text=True)
32
+ process = subprocess.run(cmd_list, capture_output=True, encoding='utf-8')
31
33
  if process.returncode == 0 and process.stdout.strip():
32
34
  first_line = process.stdout.partition('\n')[0].strip()
33
35
  return datetime.fromisoformat(first_line)
@@ -38,18 +40,15 @@ def get_git_first_commit_time(file_path):
38
40
  def load_git_cache(docs_dir_path: Path):
39
41
  dates_cache = {}
40
42
  try:
41
- cmd = ['git', 'log', '--reverse', '--no-merges', '--name-only', '--format=%an|%ae|%aI', '--', '*.md']
42
- process = subprocess.run(cmd, cwd=docs_dir_path, capture_output=True, text=True)
43
+ git_root = Path(subprocess.check_output(
44
+ ['git', 'rev-parse', '--show-toplevel'],
45
+ cwd=docs_dir_path, encoding='utf-8'
46
+ ).strip())
47
+ rel_docs_path = docs_dir_path.relative_to(git_root).as_posix()
48
+
49
+ cmd = ['git', 'log', '--reverse', '--no-merges', '--use-mailmap', '--name-only', '--format=%aN|%aE|%aI', f'--relative={rel_docs_path}', '--', '*.md']
50
+ process = subprocess.run(cmd, cwd=docs_dir_path, capture_output=True, encoding='utf-8')
43
51
  if process.returncode == 0:
44
- git_root = Path(subprocess.check_output(
45
- ['git', 'rev-parse', '--show-toplevel'],
46
- cwd=docs_dir_path,
47
- text=True, encoding='utf-8'
48
- ).strip())
49
- docs_prefix = docs_dir_path.relative_to(git_root).as_posix()
50
- docs_prefix_with_slash = docs_prefix + '/'
51
- prefix_len = len(docs_prefix_with_slash)
52
-
53
52
  authors_dict = defaultdict(dict)
54
53
  first_commit = {}
55
54
  current_commit = None
@@ -59,24 +58,21 @@ def load_git_cache(docs_dir_path: Path):
59
58
  if not line:
60
59
  continue
61
60
  if '|' in line:
62
- name, email, created = line.split('|', 2)
63
61
  # 使用元组,更轻量
64
- current_commit = (name, email, created)
62
+ current_commit = tuple(line.split('|', 2))
65
63
  elif line.endswith('.md') and current_commit:
66
- if line.startswith(docs_prefix_with_slash):
67
- line = line[prefix_len:]
68
- # 解构元组,避免字典查找
69
64
  name, email, created = current_commit
70
- # 使用有序去重结构,保持作者首次出现顺序
65
+ # 使用 defaultdict(dict)结构,有序去重,保持作者首次出现的顺序
66
+ # a.巧用 Python 字典的 setdefault 特性来去重(setdefault 为不存在的键提供初始值,不会覆盖已有值)
67
+ # b.巧用 Python 3.7+ 字典的插入顺序特性来保留内容插入顺序(Python 3.7+ 字典会保持插入顺序)
71
68
  authors_dict[line].setdefault((name, email), None)
72
- if line not in first_commit:
73
- first_commit[line] = created
69
+ first_commit.setdefault(line, created)
74
70
 
75
71
  # 构建最终的缓存数据
76
72
  for file_path in first_commit:
77
73
  authors_list = [
78
74
  {'name': name, 'email': email}
79
- for name, email in authors_dict[file_path].keys()
75
+ for name, email in authors_dict[file_path].keys() # 这里的 keys() 是有序的
80
76
  ]
81
77
  dates_cache[file_path] = {
82
78
  'created': first_commit[file_path],
@@ -103,43 +99,83 @@ def get_file_creation_time(file_path):
103
99
  logger.error(f"Failed to get file creation time for {file_path}: {e}")
104
100
  return datetime.now()
105
101
 
106
- def get_recently_modified_files(files, exclude_list: list, limit: int = 10):
107
- if not files:
108
- return []
109
- temp_results = []
110
- for file in files:
111
- if not file.src_path.endswith('.md'):
112
- continue
113
- rel_path = getattr(file, 'src_uri', file.src_path)
114
- if os.sep != '/':
115
- rel_path = rel_path.replace(os.sep, '/')
116
- if is_excluded(rel_path, exclude_list):
117
- continue
118
-
119
- # 过滤没有配置进导航里的文档
120
- if file.page:
121
- if not file.page.title:
102
+ def get_recently_updated_files(docs_dir_path: Path, files: Files, exclude_list: list, limit: int = 10, recent_enable: bool = False):
103
+ doc_mtime_map = {}
104
+ try:
105
+ # 1. 获取 git 信息,只记录已跟踪的文件首次出现的信息(最近一次提交时间)
106
+ git_root = Path(subprocess.check_output(
107
+ ['git', 'rev-parse', '--show-toplevel'],
108
+ cwd=docs_dir_path, encoding='utf-8'
109
+ ).strip())
110
+ rel_docs_path = docs_dir_path.relative_to(git_root).as_posix()
111
+
112
+ cmd = ['git', 'log', '--no-merges', '--use-mailmap', '--format=%aN|%aE|%at', '--name-only', f'--relative={rel_docs_path}', '--', '*.md']
113
+ process = subprocess.run(cmd, cwd=docs_dir_path, capture_output=True, encoding='utf-8')
114
+ if process.returncode == 0:
115
+ result = subprocess.run(
116
+ ["git", "ls-files", "*.md"],
117
+ cwd=docs_dir_path, capture_output=True, encoding='utf-8'
118
+ )
119
+ tracked_files = set(result.stdout.splitlines()) if result.stdout else set()
120
+
121
+ ts = None
122
+ for line in process.stdout.splitlines():
123
+ line = line.strip()
124
+ if not line:
125
+ continue
126
+ if '|' in line: # commit header
127
+ ts = float(line.split('|')[2])
128
+ elif line.endswith('.md') and line in tracked_files and ts:
129
+ # 只记录第一次出现的文件,即最近一次提交(setdefault 机制不会覆盖已有值)
130
+ doc_mtime_map.setdefault(line, ts)
131
+ except Exception as e:
132
+ logger.info(f"Error getting git tracked files in {docs_dir_path}: {e}")
133
+
134
+ # 2. 构建所有文档的元数据
135
+ recently_updated_results = []
136
+ if recent_enable:
137
+ files_meta = []
138
+ for file in files:
139
+ if not file.src_path.endswith('.md'):
122
140
  continue
123
- title, url = file.page.title, file.page.url
124
- else:
125
- title, url = file.name, file.url
141
+ rel_path = getattr(file, 'src_uri', file.src_path)
142
+ if os.sep != '/':
143
+ rel_path = rel_path.replace(os.sep, '/')
144
+ if is_excluded(rel_path, exclude_list):
145
+ continue
146
+
147
+ # 获取文档标题和 URL
148
+ if file.page:
149
+ # 过滤没有配置进导航里的文档
150
+ if not file.page.title:
151
+ continue
152
+ title, url = file.page.title, file.page.url
153
+ else:
154
+ title, url = file.name, file.url
155
+
156
+ # 获取 git 记录的 mtime,没有则 fallback 到文件系统 mtime
157
+ mtime = doc_mtime_map.get(rel_path, os.path.getmtime(file.abs_src_path))
158
+
159
+ # 存储信息
160
+ files_meta.append((mtime, rel_path, title, url))
161
+ doc_mtime_map[rel_path] = mtime
126
162
 
127
- mtime = os.path.getmtime(file.abs_src_path)
128
- temp_results.append((mtime, rel_path, title, url))
163
+ # 3. 构建最近更新列表
164
+ if files_meta:
165
+ # heapq 取 top limit
166
+ top_results = heapq.nlargest(limit, files_meta, key=lambda x: x[0])
167
+ recently_updated_results = [
168
+ (datetime.fromtimestamp(mtime).strftime("%Y-%m-%d %H:%M:%S"), *rest)
169
+ for mtime, *rest in top_results
170
+ ]
129
171
 
130
- # 按修改时间倒序
131
- temp_results.sort(key=lambda x: x[0], reverse=True)
132
- results = [
133
- (datetime.fromtimestamp(mtime).strftime("%Y-%m-%d %H:%M:%S"), *rest)
134
- for mtime, *rest in temp_results
135
- ]
136
- return results[:limit]
172
+ return doc_mtime_map, recently_updated_results
137
173
 
138
174
  def read_json_cache(cache_file: Path):
139
175
  dates_cache = {}
140
176
  if cache_file.exists():
141
177
  try:
142
- with open(cache_file, "r", encoding='utf-8') as f:
178
+ with open(cache_file, 'r', encoding='utf-8') as f:
143
179
  dates_cache = json.load(f)
144
180
  except (IOError, json.JSONDecodeError) as e:
145
181
  logger.warning(f"Error reading from '.dates_cache.json': {str(e)}")
@@ -149,7 +185,7 @@ def read_jsonl_cache(jsonl_file: Path):
149
185
  dates_cache = {}
150
186
  if jsonl_file.exists():
151
187
  try:
152
- with open(jsonl_file, "r", encoding='utf-8') as f:
188
+ with open(jsonl_file, 'r', encoding='utf-8') as f:
153
189
  for line in f:
154
190
  try:
155
191
  entry = json.loads(line.strip())
@@ -166,7 +202,7 @@ def write_jsonl_cache(jsonl_file: Path, dates_cache, tracked_files):
166
202
  try:
167
203
  # 使用临时文件写入,然后替换原文件,避免写入过程中的问题
168
204
  temp_file = jsonl_file.with_suffix('.jsonl.tmp')
169
- with open(temp_file, "w", encoding='utf-8') as f:
205
+ with open(temp_file, 'w', encoding='utf-8') as f:
170
206
  for file_path in tracked_files:
171
207
  if file_path in dates_cache:
172
208
  entry = {file_path: dates_cache[file_path]}
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mkdocs-document-dates
3
- Version: 3.4.1
3
+ Version: 3.4.5
4
4
  Summary: A new generation MkDocs plugin for displaying exact creation time, last update time, authors, email of documents
5
5
  Home-page: https://github.com/jaywhj/mkdocs-document-dates
6
6
  Author: Aaron Wang
@@ -36,14 +36,14 @@ A new generation MkDocs plugin for displaying exact **creation time, last update
36
36
 
37
37
  ## Features
38
38
 
39
- - [x] Always display **exact** meta-info of the document for any environment (no-Git, Git, all CI/CD build systems, etc.)
39
+ - [x] Always displays **exact** meta information of the document and works in any environment (no Git, Git environments, Docker containers, all CI/CD build systems, etc.)
40
40
  - [x] Support for manually specifying time and author in `Front Matter`
41
41
  - [x] Support for multiple time formats (date, datetime, timeago)
42
42
  - [x] Support for multiple author modes (avatar, text, hidden)
43
43
  - [x] Flexible display position (top or bottom)
44
44
  - [x] Elegant styling (fully customizable)
45
45
  - [x] Smart Tooltip Hover Tips
46
- - [x] Supports display of recently updated documents in an overall list
46
+ - [x] Support list display of recently updated documents
47
47
  - [x] Multi-language support, localization support, intelligent recognition of user language, automatic adaptation
48
48
  - [x] Cross-platform support (Windows, macOS, Linux)
49
49
  - [x] **Ultimate build efficiency**: O(1), no need to set env vars to distinguish runs
@@ -53,7 +53,6 @@ A new generation MkDocs plugin for displaying exact **creation time, last update
53
53
  | git-revision-date-localized | > 3 s | > 30 s | O(n) |
54
54
  | document-dates | < 0.1 s | < 0.15 s | O(1) |
55
55
 
56
-
57
56
  ## Installation
58
57
 
59
58
  ```bash
@@ -77,9 +76,9 @@ plugins:
77
76
  position: top # Display position: top(after title) bottom(end of document)
78
77
  type: date # Date type: date datetime timeago, default: date
79
78
  exclude: # List of excluded files
80
- - temp.md # Exclude specific file
81
- - drafts/* # Exclude all files in drafts folder, including subfolders
82
- date_format: '%Y-%m-%d' # Date format strings, e.g., %Y-%m-%d, %b %d, %Y
79
+ - temp.md # Example: exclude the specified file
80
+ - blog/* # Example: exclude all files in blog folder, including subfolders
81
+ date_format: '%Y-%m-%d' # Date format strings (e.g., %Y-%m-%d, %b %d, %Y)
83
82
  time_format: '%H:%M:%S' # Time format strings (valid only if type=datetime)
84
83
  show_author: true # Author display mode: true(avatar) text(text) false(hidden)
85
84
  recently-updated: true # Whether to turn on recently updated data, default: false
@@ -96,7 +95,7 @@ In addition to the above basic configuration, the plug-in also provides a wealth
96
95
  - [Add Localization Language](https://jaywhj.netlify.app/document-dates-en#Add-Localization-Language): More localization languages for `timeago` and `tooltip`
97
96
  - [Use Template Variables](https://jaywhj.netlify.app/document-dates-en#Use-Template-Variables): Can be used to optimize `sitemap.xml` for site SEO, can be used to re-customize plug-ins, etc.
98
97
  - [Add Recently Updated Module](https://jaywhj.netlify.app/document-dates-en#Add-Recently-Updated-Module): Enable list of recently updated documents
99
- - [Other Tips](https://jaywhj.netlify.app/document-dates-en#Other-Tips): Introduction to technical principles, caching mechanisms
98
+ - [Other Tips](https://jaywhj.netlify.app/document-dates-en#Other-Tips): Introduction to technical principles, caching mechanisms, and how to use it in Docker
100
99
  - [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
101
100
 
102
101
  See the documentation for details: https://jaywhj.netlify.app/document-dates-en
@@ -23,7 +23,7 @@ class CustomInstallCommand(install):
23
23
  install.run(self)
24
24
 
25
25
 
26
- VERSION = '3.4.1'
26
+ VERSION = '3.4.5'
27
27
 
28
28
  setup(
29
29
  name="mkdocs-document-dates",