Class: Jekyll::GitMetadata::Generator

Inherits:
Jekyll::Generator
  • Object
show all
Defined in:
lib/jekyll/git_metadata/generator.rb

Instance Method Summary collapse

Instance Method Details

#authors(file = nil) ⇒ Object



83
84
85
86
87
88
89
90
91
92
93
# File 'lib/jekyll/git_metadata/generator.rb', line 83

def authors(file = nil)
  results = []
  cmd = 'git shortlog -se HEAD'
  cmd << " -- #{file}" if file
  result = %x{ #{cmd} }
  result.lines.each do |line|
    commits, name, email = line.scan(/(.*)\t(.*)<(.*)>/).first.map(&:strip)
    results << { 'commits' => commits.to_i, 'name' => name, 'email' => email }
  end
  results
end

#commit(sha) ⇒ Object



110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
# File 'lib/jekyll/git_metadata/generator.rb', line 110

def commit(sha)
  result = %x{ git show --format=fuller --name-only #{sha} }
  long_sha, author_name, author_email, author_date, commit_name, commit_email, commit_date, message, changed_files = result.scan(/commit (.*)\nAuthor:(.*)<(.*)>\nAuthorDate:(.*)\nCommit:(.*)<(.*)>\nCommitDate:(.*)\n\n((?:\s\s\s\s[^\r\n]*\n)*)\n(.*)/m).first.map(&:strip)
  {
    'short_sha' => sha,
    'long_sha' => long_sha,
    'author_name' => author_name,
    'author_email' => author_email,
    'author_date' => author_date,
    'commit_name' => commit_name,
    'commit_email' => commit_email,
    'commit_date' => Time.strptime(commit_date, '%a %b %d %H:%M:%S %Y %z'),
    'message' => message.gsub(/    /, ''),
    'changed_files' => changed_files.split("\n")
  }
end

#files_countObject



135
136
137
# File 'lib/jekyll/git_metadata/generator.rb', line 135

def files_count
  %x{ git ls-tree -r HEAD }.lines.count
end

#generate(site) ⇒ Object



9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# File 'lib/jekyll/git_metadata/generator.rb', line 9

def generate(site)
  raise "Git is not installed" unless git_installed?

  Dir.chdir(site.source) do
    data = (site)
    site.config['git'] = data['site_data']
    jekyll_items(site).each do |page|
      if page.is_a?(Jekyll::Page)
        path = page.path
      else
        path = page.relative_path
      end
      page.data['git'] = data['pages_data'][path]
    end
  end
end

#git_installed?Boolean

Returns:

  • (Boolean)


139
140
141
142
# File 'lib/jekyll/git_metadata/generator.rb', line 139

def git_installed?
  null = RbConfig::CONFIG['host_os'] =~ /msdos|mswin|djgpp|mingw/ ? 'NUL' : '/dev/null'
  system "git --version >>#{null} 2>&1"
end

#lines(file = nil) ⇒ Object



95
96
97
98
99
100
101
102
103
104
105
106
107
108
# File 'lib/jekyll/git_metadata/generator.rb', line 95

def lines(file = nil)
  cmd = "git log --numstat --format=%h"
  cmd << " -- #{file}" if file
  result = %x{ #{cmd} }
  results = result.scan(/(.*)\n\n((?:.*\t.*\t.*\n)*)/)
  results.map do |line|
    files = line[1].scan(/(.*)\t(.*)\t(.*)\n/)
    line[1] = files.inject(0){|s,a| s+=a[0].to_i}
    line[2] = files.inject(0){|s,a| s+=a[1].to_i}
  end
  results.map do |line|
    { 'sha' => line[0], 'additions' => line[1], 'subtractions' => line[2] }
  end
end

#load_git_metadata(site) ⇒ Object



26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
# File 'lib/jekyll/git_metadata/generator.rb', line 26

def (site)

  current_sha = %x{ git rev-parse HEAD }.strip

  cache_dir = site.source + '/.git-metadata'
  FileUtils.mkdir_p(cache_dir) unless File.directory?(cache_dir)
  cache_file = cache_dir + "/#{current_sha}.json"

  if File.exist?(cache_file)
    cached = JSON.parse(IO.read(cache_file))
#           deserialize dates into Time objects
    new_commits = cached['site_data']['commits'].map do |commit|
      commit.merge('commit_date' => Time.parse(commit['commit_date']))
    end
    cached['site_data']['commits'] = new_commits
    return cached
  end

  pages_data = {}
  jekyll_items(site).each do |page|
    if page.is_a?(Jekyll::Page)
      path = page.path
    else
      path = page.relative_path
    end
    pages_data[path] = page_data(path)
  end
  data = { 'site_data' => site_data, 'pages_data' => pages_data }

  File.open(cache_file, 'w') { |f| f.write(data.to_json) }

  data
end

#page_data(relative_path = nil) ⇒ Object



67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
# File 'lib/jekyll/git_metadata/generator.rb', line 67

def page_data(relative_path = nil)
  return if relative_path && !tracked_files.include?(relative_path)

  authors = self.authors(relative_path)
  lines = self.lines(relative_path)
  {
    'authors' => authors,
    'total_commits' => authors.inject(0) { |sum, h| sum += h['commits'] },
    'total_additions' => lines.inject(0) { |sum, h| sum += h['additions'] },
    'total_subtractions' => lines.inject(0) { |sum, h| sum += h['subtractions'] },
    'commits' => lines.map { |line| commit(line['sha']) }, # Get commit data for each line
    'first_commit' => commit(lines.last['sha']),
    'last_commit' => commit(lines.first['sha'])
  }
end

#project_nameObject



131
132
133
# File 'lib/jekyll/git_metadata/generator.rb', line 131

def project_name
  File.basename(%x{ git rev-parse --show-toplevel }.strip)
end

#site_dataObject



60
61
62
63
64
65
# File 'lib/jekyll/git_metadata/generator.rb', line 60

def site_data
  {
    'project_name' => project_name,
    'files_count' => files_count,
  }.merge!(page_data)
end

#tracked_filesObject



127
128
129
# File 'lib/jekyll/git_metadata/generator.rb', line 127

def tracked_files
  @tracked_files ||= %x{ git ls-tree --full-tree -r --name-only HEAD }.split("\n")
end