Files
textmate/bin/gen_credits.rb
Allan Odgaard aa50c31636 Workaround for ruby’s YAML.load
JSON should be a subset of YAML so we use ruby’s YAML parser to parse GitHub’s JSON. This however leads to syntax errors reported by the parser (as noted in issue #637) but if the JSON is “pretty printed” it seems to parse it fine (seems to be the extra white space for associative array pairs).

We can trick GitHub into pretty printing the JSON result by setting the user agent to be curl, so that is all this workaround does.
2013-01-04 02:07:50 +01:00

133 lines
4.4 KiB
Ruby
Executable File

#!/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/bin/ruby -wKU
# == Synopsis
#
# Module to assist in building the Contributors page using git commit history.
#
require 'getoptlong'
require 'rdoc/usage'
require 'digest/md5'
require 'net/https'
require 'uri'
require 'cgi'
require 'dbm'
require 'date'
require 'yaml'
# Helper class to handle searching for GitHub users
# by their email address. Caches mappings to a file
# to avoid exhausting the GitHub API rate limits for
# anonymous requests.
class GitHubLookup
def self.initialize(dbm_file)
@db = DBM.new(dbm_file)
# seed with some contributors that don't have an email
# address assigned publicly in their account
@db['1178ce2f664a6cee9a05a3e11af5d8d2'] = 'aaronbrethorst'
@db['3b0ef5e2a5f1aa3ccf3f23a20adf8873'] = 'Hoverbear'
@db['ff3502050b3b1b00cb6c810d5c41ffc9'] = 'bradchoate'
@db['ee646002e51a3c83e01db85ae42187ff'] = 'dmcdougall'
@db['85af9ad71af2dc0166b7c0c5780fa086'] = 'caldwell'
@db['fa64968e4a3c8e20364bb92ba7511ff9'] = 'dvennink'
@db['0669ff1e3ada91e7f1e7714f6f9a67f6'] = 'etienne'
@db['49ed289f3de94dbcd7c10392bcc40b53'] = 'fernando82'
@db['7b3ae2214891a47b26b4db98949c1bb0'] = 'gknops'
@db['34820bca697fbf1598774b393c5ca4fe'] = 'whitlockjc'
@db['ec9254734cd341f1b104d558dc4fc36a'] = 'joachimm'
@db['09c16a631eeba332147a8d620e1369cc'] = 'muellerj'
@db['6890db3146e20bfb99be3bc7bc3bfeec'] = 'lczekaj'
@db['e34425c11547a48a4701c9d1720dadf8'] = 'infininight'
@db['65efe3355478c8db96bc82f22fd3aa20'] = 'nathanieltagg'
@db['4e89e196a1f8fa34a6bdc6d165f75e5e'] = 'Ralle'
@db['ccc5b318408880a67eeebf0d18177fb5'] = 'rhencke'
@db['4cf620221f7e622260f8424b8142451f'] = 'ryanmaxwell'
@db['5780111eb4b5565816d9388b091e1057'] = 'youngrok'
ObjectSpace.define_finalizer(@db, proc {|id| db.close })
end
def self.user_by_email(email)
emailhash = Digest::MD5.hexdigest(email)
if @db.has_key?(emailhash)
return @db[emailhash]
end
url = 'https://api.github.com/legacy/user/email/' + email
uri = URI.parse(url)
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
# issue request
request = Net::HTTP::Get.new(uri.request_uri, {'User-Agent' => 'curl'})
response = http.request(request)
# could be a 404, return nil if so
if response.code == '404'
return @db[emailhash] = nil
end
user = YAML.load(response.body)
# save result to k/v store
return @db[emailhash] = user['user']['login']
end
end
def generate_credits(dbm_file)
GitHubLookup.initialize(dbm_file)
# use git's log command to pull out basic info:
# git hash, author name, email address, author date, commit summary
cmd = 'git log -z --date=iso --pretty=format:"%H%n%an%n%ae%n%ad%n%s%n%B"'
`#{cmd}`.split(/\x00/s).each {|commit|
fields = commit.split(/\n/, 6)
# omit commits from Allan; he gets enough credit already ;)
if fields[1] != 'Allan Odgaard' then
# hash email address for referencing Gravatar userpics
emailhash = Digest::MD5.hexdigest(fields[2])
# escape user-supplied bits like name and subject
hash = fields[0]
name = CGI.escapeHTML(fields[1])
# locate the GitHub login for the author's email address
user = GitHubLookup.user_by_email(fields[2])
date = DateTime.parse(fields[3])
subject = CGI.escapeHTML(fields[4])
body = CGI.escapeHTML(fields[5].sub(fields[4], '').sub(/[\s\x00]+$/s, '').sub(/^[\s\x00]+/s, ''))
userpic = "http://www.gravatar.com/avatar/#{emailhash}?s=48&d=https://a248.e.akamai.net/assets.github.com%2Fimages%2Fgravatars%2Fgravatar-user-420.png"
# if we have a github username, populate a link to their
# profile.
if !user || user == ''
user = nil
STDERR << "WARNING: failed to find GitHub user for #{name} <#{fields[2]}>\n";
end
yield(hash, name, subject, body, userpic, date, user)
end
}
end
__END__
# Contributions
See [commits at GitHub][1].
<table width="100%">
<tr>
<th width="20%">Author</th>
<th width="60%">Contribution</th>
<th width="20%">Date</th>
</tr>
<%
require 'bin/gen_credits'
credits = generate_credits(File.expand_path('~/Library/Caches/com.macromates.TextMate/githubcredits'))
%>
<%= credits %>
</table>
[1]: https://github.com/textmate/textmate/commits/master