filetime_from_git.py 2.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374
  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. import os
  4. from git import Git, Repo, InvalidGitRepositoryError
  5. from pelican import signals, contents
  6. from datetime import datetime
  7. from time import mktime, altzone
  8. from pelican.utils import strftime, set_date_tzinfo
  9. try:
  10. repo = Repo(os.path.abspath('.'))
  11. git = Git(os.path.abspath('.'))
  12. except InvalidGitRepositoryError as e:
  13. repo = None
  14. def datetime_from_timestamp(timestamp, content):
  15. """
  16. Helper function to add timezone information to datetime,
  17. so that datetime is comparable to other datetime objects in recent versions
  18. that now also have timezone information.
  19. """
  20. return set_date_tzinfo(datetime.fromtimestamp(timestamp), tz_name=content.settings.get('TIMEZONE', None))
  21. def filetime_from_git(content):
  22. if isinstance(content, contents.Static) or repo is None:
  23. return
  24. gittime = content.metadata.get('gittime', 'yes').lower()
  25. gittime = gittime.replace("false", "no").replace("off", "no")
  26. if gittime == "no":
  27. return
  28. # 1. file is not managed by git
  29. # date: fs time
  30. # 2. file is staged, but has no commits
  31. # date: fs time
  32. # 3. file is managed, and clean
  33. # date: first commit time, update: last commit time or None
  34. # 4. file is managed, but dirty
  35. # date: first commit time, update: fs time
  36. path = content.source_path
  37. status, stdout, stderr = git.execute(['git', 'ls-files', path, '--error-unmatch'],
  38. with_extended_output=True, with_exceptions=False)
  39. if status != 0:
  40. # file is not managed by git
  41. content.date = datetime_from_timestamp(os.stat(path).st_ctime, content)
  42. else:
  43. # file is managed by git
  44. commits = repo.commits(path=path)
  45. if len(commits) == 0:
  46. # never commited, but staged
  47. content.date = datetime_from_timestamp(os.stat(path).st_ctime, content)
  48. else:
  49. # has commited
  50. content.date = datetime_from_timestamp(mktime(commits[-1].committed_date) - altzone, content)
  51. status, stdout, stderr = git.execute(['git', 'diff', '--quiet', 'HEAD', path],
  52. with_extended_output=True, with_exceptions=False)
  53. if status != 0:
  54. # file has changed
  55. content.modified = datetime_from_timestamp(os.stat(path).st_ctime, content)
  56. else:
  57. # file is not changed
  58. if len(commits) > 1:
  59. content.modified = datetime_from_timestamp(mktime(commits[0].committed_date) - altzone, content)
  60. if not hasattr(content, 'modified'):
  61. content.modified = content.date
  62. if hasattr(content, 'date'):
  63. content.locale_date = strftime(content.date, content.date_format)
  64. if hasattr(content, 'modified'):
  65. content.locale_modified = strftime(content.modified, content.date_format)
  66. def register():
  67. signals.content_object_init.connect(filetime_from_git)