浏览代码

create filetime_from_git plugin

Zhang Cheng 10 年之前
父节点
当前提交
7ec231c3f8
共有 3 个文件被更改,包括 114 次插入0 次删除
  1. 56 0
      filetime_from_git/README.rst
  2. 1 0
      filetime_from_git/__init__.py
  3. 57 0
      filetime_from_git/filetime_from_git.py

+ 56 - 0
filetime_from_git/README.rst

@@ -0,0 +1,56 @@
+Use git commit to determine page date
+======================================
+
+If the blog content is managed by git repo, this plugin will set articles'
+and pages' ``metadata['date']`` according to git commit. This plugin depends
+on python package ``gitpython``, install::
+
+    pip install gitpython
+
+The determine logic will works so:
+
+* if a file is not tracked by git, or a file is staged but never commited
+    - metadata['date'] = fs time
+    - metadata['updated'] = fs time
+* if a file is tracked, but no changes in stage area or work dir
+    - metadata['date'] = first commit time
+    - metadata['updated'] = last commit time
+* if a file is tracked, and has changes in stage area or work dir
+    - metadata['date'] = first commit time
+    - metadata['updated'] = fs time
+
+When this module is enabled, ``date`` and ``updated`` will be set automatically
+by git status, no need to manually set in article/page's metadata. And
+operations like copy, move will not affect the generated results.
+
+Some notes on git
+~~~~~~~~~~~~~~~~~~
+
+* How to check if a file is managed?
+
+.. code-block:: sh
+
+   git ls-files $file --error-unmatch
+
+* How to check if a file has changes?
+
+.. code-block:: sh
+
+   git diff $file            # compare staged area with working directory
+   git diff --cached $file   # compare HEAD with staged area
+   git diff HEAD $file       # compare HEAD with working directory
+
+* How to get commits related to a file?
+
+.. code-block:: sh
+
+   git status $file
+
+with ``gitpython`` package, it's easier to parse commited time:
+
+.. code-block:: python
+
+   repo = Git.repo('/path/to/repo')
+   commits = repo.commits(path='path/to/file')
+   commits[-1].committed_date    # oldest commit time
+   commits[0].committed_date     # latest commit time

+ 1 - 0
filetime_from_git/__init__.py

@@ -0,0 +1 @@
+from .filetime_from_git import *

+ 57 - 0
filetime_from_git/filetime_from_git.py

@@ -0,0 +1,57 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+import os
+from git import Git, Repo, InvalidGitRepositoryError
+from pelican import signals, contents
+from datetime import datetime
+from time import mktime, altzone
+
+try:
+    repo = Repo(os.path.abspath('.'))
+    git = Git(os.path.abspath('.'))
+except InvalidGitRepositoryError as e:
+    repo = None
+
+def filetime_from_git(content):
+    if isinstance(content, contents.Static) or repo is None:
+        return
+    # 1. file is not managed by git
+    #    date: fs time
+    # 2. file is staged, but has no commits
+    #    date: fs time
+    # 3. file is managed, and clean
+    #    date: first commit time, update: last commit time or None
+    # 4. file is managed, but dirty
+    #    date: first commit time, update: fs time
+    path = content.source_path
+    metadata = content.metadata
+    status, stdout, stderr = git.execute(['git', 'ls-files', path, '--error-unmatch'],
+            with_extended_output=True, with_exceptions=False)
+    if status != 0:
+        # file is not managed by git
+        metadata['date'] = datetime.fromtimestamp(os.stat(path).st_ctime)
+    else:
+        # file is managed by git
+        commits = repo.commits(path=path)
+        if len(commits) == 0:
+            # never commited, but staged
+            metadata['date'] = datetime.fromtimestamp(os.stat(path).st_ctime)
+        else:
+            # has commited
+            metadata['date'] = datetime.fromtimestamp(mktime(commits[-1].committed_date) - altzone)
+
+            status, stdout, stderr = git.execute(['git', 'diff', '--quiet', 'HEAD', path],
+                    with_extended_output=True, with_exceptions=False)
+            if status != 0:
+                # file has changed
+                metadata['updated'] = datetime.fromtimestamp(os.stat(path).st_ctime)
+            else:
+                # file is not changed
+                if len(commits) > 1:
+                    metadata['updated'] = datetime.fromtimestamp(mktime(commits[0].committed_date) - altzone)
+    if not metadata.has_key('updated'):
+        metadata['updated'] = metadata['date']
+
+def register():
+    signals.content_object_init.connect(filetime_from_git)