Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 49d23ab

Browse files
committed
1 parent 90c5823 commit 49d23ab

File tree

18 files changed

+468
-180
lines changed

18 files changed

+468
-180
lines changed

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
PY?=python
1+
PY?=python3
22
PELICAN?=pelican
33
PELICANOPTS=
44

plugins/code_include/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
from code_include import *
1+
from .code_include import *

plugins/filetime_from_git/README.rst

Lines changed: 38 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,71 +1,60 @@
1-
Use git commit to determine page date
1+
Use Git commit to determine page date
22
======================================
3-
43
If the blog content is managed by git repo, this plugin will set articles'
54
and pages' ``metadata['date']`` according to git commit. This plugin depends
65
on python package ``gitpython``, install::
76

87
pip install gitpython
98

10-
The determine logic will works so:
9+
The date is determined via the following logic:
1110

12-
* if a file is not tracked by git, or a file is staged but never commited
13-
- metadata['date'] = fs time
14-
- metadata['updated'] = fs time
15-
* if a file is tracked, but no changes in stage area or work dir
11+
* if a file is not tracked by Git, or a file is staged but never committed
12+
- metadata['date'] = filesystem time
13+
- metadata['modified'] = filesystem time
14+
* if a file is tracked, but no changes in staging area or working directory
1615
- metadata['date'] = first commit time
17-
- metadata['updated'] = last commit time
18-
* if a file is tracked, and has changes in stage area or work dir
16+
- metadata['modified'] = last commit time
17+
* if a file is tracked, and has changes in stage area or working directory
1918
- metadata['date'] = first commit time
20-
- metadata['updated'] = fs time
19+
- metadata['modified'] = filesystem time
20+
21+
When this module is enabled, ``date`` and ``modified`` will be determined
22+
by Git status; no need to manually set in article/page metadata. And
23+
operations like copy and move will not affect the generated results.
2124

22-
When this module is enabled, ``date`` and ``updated`` will be set automatically
23-
by git status, no need to manually set in article/page's metadata. And
24-
operations like copy, move will not affect the generated results.
25+
If you don't want a given article or page to use the Git time, set the
26+
metadata to ``gittime: off`` to disable it.
2527

26-
If some article or page doesn't like to use git time, set a ``gittime: off``
27-
metadata to disable it.
28+
Other options
29+
-------------
2830

29-
You can also set GIT_FILETIME_FOLLOW to True in your pelican config to
31+
### GIT_HISTORY_FOLLOWS_RENAME (default True)
32+
You can also set GIT_HISTORY_FOLLOWS_RENAME to True in your pelican config to
3033
make the plugin follow file renames i.e. ensure the creation date matches
3134
the original file creation date, not the date is was renamed.
3235

33-
FAQ
34-
---
35-
36-
### Q. I get a GitCommandError: 'git rev-list ...' when I run the plugin. What's up?
37-
Be sure to use the correct gitpython module for your distros git binary.
38-
Using the GIT_FILETIME_FOLLOW option to True may also make your problem go away as it uses
39-
a different method to find commits.
40-
41-
Some notes on git
42-
~~~~~~~~~~~~~~~~~~
43-
44-
* How to check if a file is managed?
36+
### GIT_GENERATE_PERMALINK (default False)
37+
Use in combination with permalink plugin to generate permalinks using the original
38+
commit sha
4539

46-
.. code-block:: sh
40+
### GIT_SHA_METADATA (default True)
41+
Adds sha of current and oldest commit to metadata
4742

48-
git ls-files $file --error-unmatch
43+
### GIT_FILETIME_FROM_GIT (default True)
44+
Enable filetime from git behaviour
4945

50-
* How to check if a file has changes?
46+
Content specific options
47+
------------------------
48+
Adding metadata `gittime` = False will prevent the plugin trying to setting filetime for this
49+
content.
5150

52-
.. code-block:: sh
51+
Adding metadata `git_permalink` = False will prevent the plugin from adding permalink for this
52+
content.
5353

54-
git diff $file # compare staged area with working directory
55-
git diff --cached $file # compare HEAD with staged area
56-
git diff HEAD $file # compare HEAD with working directory
57-
58-
* How to get commits related to a file?
59-
60-
.. code-block:: sh
61-
62-
git status $file
63-
64-
with ``gitpython`` package, it's easier to parse commited time:
65-
66-
.. code-block:: python
54+
FAQ
55+
---
6756

68-
repo = Git.repo('/path/to/repo')
69-
commits = repo.commits(path='path/to/file')
70-
commits[-1].committed_date # oldest commit time
71-
commits[0].committed_date # latest commit time
57+
### Q. I get a GitCommandError: 'git rev-list ...' when I run the plugin. What's up?
58+
Be sure to use the correct gitpython module for your distros git binary.
59+
Using the GIT_HISTORY_FOLLOWS_RENAME option to True may also make your problem go away as it uses
60+
a different method to find commits.

plugins/filetime_from_git/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
from .filetime_from_git import *
1+
from .registration import *

plugins/filetime_from_git/actions.py

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
# -*- coding: utf-8 -*-
2+
import base64
3+
import hashlib
4+
import logging
5+
import os
6+
7+
from pelican.utils import strftime
8+
9+
from .registration import content_git_object_init
10+
from .utils import datetime_from_timestamp
11+
from .utils import string_to_bool
12+
13+
14+
logger = logging.getLogger(__name__)
15+
16+
17+
@content_git_object_init.connect
18+
def filetime_from_git(content, git_content):
19+
'''
20+
Update modification and creation times from git
21+
'''
22+
if not content.settings['GIT_FILETIME_FROM_GIT']:
23+
# Disabled for everything
24+
return
25+
26+
if not string_to_bool(content.metadata.get('gittime', 'yes')):
27+
# Disable for this content
28+
return
29+
30+
path = content.source_path
31+
fs_creation_time = datetime_from_timestamp(os.stat(path).st_ctime, content)
32+
fs_modified_time = datetime_from_timestamp(os.stat(path).st_mtime, content)
33+
34+
# 1. file is not managed by git
35+
# date: fs time
36+
# 2. file is staged, but has no commits
37+
# date: fs time
38+
# 3. file is managed, and clean
39+
# date: first commit time, update: last commit time or None
40+
# 4. file is managed, but dirty
41+
# date: first commit time, update: fs time
42+
if git_content.is_managed_by_git():
43+
if git_content.is_committed():
44+
content.date = git_content.get_oldest_commit_date()
45+
46+
if git_content.is_modified():
47+
content.modified = fs_modified_time
48+
else:
49+
content.modified = git_content.get_newest_commit_date()
50+
else:
51+
# File isn't committed
52+
content.date = fs_creation_time
53+
else:
54+
# file is not managed by git
55+
content.date = fs_creation_time
56+
57+
# Clean up content attributes
58+
if not hasattr(content, 'modified'):
59+
content.modified = content.date
60+
61+
if hasattr(content, 'date'):
62+
content.locale_date = strftime(content.date, content.date_format)
63+
64+
if hasattr(content, 'modified'):
65+
content.locale_modified = strftime(
66+
content.modified, content.date_format)
67+
68+
69+
@content_git_object_init.connect
70+
def git_sha_metadata(content, git_content):
71+
'''
72+
Add sha metadata to content
73+
'''
74+
if not content.settings['GIT_SHA_METADATA']:
75+
return
76+
77+
if not git_content.is_committed():
78+
return
79+
80+
content.metadata['gitsha_newest'] = str(git_content.get_newest_commit())
81+
content.metadata['gitsha_oldest'] = str(git_content.get_oldest_commit())
82+
83+
84+
def update_hash_from_str(hsh, str_input):
85+
"""
86+
Convert a str to object supporting buffer API and update a hash with it.
87+
"""
88+
byte_input = str(str_input).encode("UTF-8")
89+
hsh.update(byte_input)
90+
91+
92+
@content_git_object_init.connect
93+
def git_permalink(content, git_content):
94+
'''
95+
Add git based permalink id to content metadata
96+
'''
97+
if not content.settings['GIT_GENERATE_PERMALINK']:
98+
return
99+
100+
if not string_to_bool(content.metadata.get('git_permalink', 'yes')):
101+
# Disable for this content
102+
return
103+
104+
if not git_content.is_committed():
105+
return
106+
107+
permalink_hash = hashlib.sha1()
108+
update_hash_from_str(permalink_hash, git_content.get_oldest_commit())
109+
update_hash_from_str(permalink_hash, git_content.get_oldest_filename())
110+
git_permalink_id_raw = base64.urlsafe_b64encode(permalink_hash.digest())
111+
git_permalink_id = git_permalink_id_raw.decode("UTF-8")
112+
permalink_id_metadata_key = content.settings['PERMALINK_ID_METADATA_KEY']
113+
114+
if permalink_id_metadata_key in content.metadata:
115+
content.metadata[permalink_id_metadata_key] = (
116+
','.join((
117+
content.metadata[permalink_id_metadata_key], git_permalink_id))
118+
)
119+
else:
120+
content.metadata[permalink_id_metadata_key] = git_permalink_id
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
# -*- coding: utf-8 -*-
2+
"""
3+
Wraps a content object to provide some git information
4+
"""
5+
import logging
6+
from pelican.utils import memoized
7+
from .git_wrapper import git_wrapper
8+
9+
DEV_LOGGER = logging.getLogger(__name__)
10+
11+
12+
class GitContentAdapter(object):
13+
"""
14+
Wraps a content object to provide some git information
15+
"""
16+
def __init__(self, content):
17+
self.content = content
18+
self.git = git_wrapper('.')
19+
self.tz_name = content.settings.get('TIMEZONE', None)
20+
self.follow = content.settings['GIT_HISTORY_FOLLOWS_RENAME']
21+
22+
@memoized
23+
def is_committed(self):
24+
'''
25+
Is committed
26+
'''
27+
return len(self.get_commits()) > 0
28+
29+
@memoized
30+
def is_modified(self):
31+
'''
32+
Has content been modified since last commit
33+
'''
34+
return self.git.is_file_modified(self.content.source_path)
35+
36+
@memoized
37+
def is_managed_by_git(self):
38+
'''
39+
Is content stored in a file managed by git
40+
'''
41+
return self.git.is_file_managed_by_git(self.content.source_path)
42+
43+
@memoized
44+
def get_commits(self):
45+
'''
46+
Get all commits involving this filename
47+
:returns: List of commits newest to oldest
48+
'''
49+
if not self.is_managed_by_git():
50+
return []
51+
return self.git.get_commits(self.content.source_path, self.follow)
52+
53+
@memoized
54+
def get_oldest_commit(self):
55+
'''
56+
Get oldest commit involving this file
57+
58+
:returns: Oldest commit
59+
'''
60+
return self.git.get_commits(self.content.source_path, self.follow)[-1]
61+
62+
@memoized
63+
def get_newest_commit(self):
64+
'''
65+
Get oldest commit involving this file
66+
67+
:returns: Newest commit
68+
'''
69+
return self.git.get_commits(self.content.source_path, follow=False)[0]
70+
71+
@memoized
72+
def get_oldest_filename(self):
73+
'''
74+
Get the original filename of this content. Implies follow
75+
'''
76+
commit_and_name_iter = self.git.get_commits_and_names_iter(
77+
self.content.source_path)
78+
_commit, name = next(commit_and_name_iter)
79+
return name
80+
81+
@memoized
82+
def get_oldest_commit_date(self):
83+
'''
84+
Get datetime of oldest commit involving this file
85+
86+
:returns: Datetime of oldest commit
87+
'''
88+
oldest_commit = self.get_oldest_commit()
89+
return self.git.get_commit_date(oldest_commit, self.tz_name)
90+
91+
@memoized
92+
def get_newest_commit_date(self):
93+
'''
94+
Get datetime of newest commit involving this file
95+
96+
:returns: Datetime of newest commit
97+
'''
98+
newest_commit = self.get_newest_commit()
99+
return self.git.get_commit_date(newest_commit, self.tz_name)

0 commit comments

Comments
 (0)