mirror of
https://github.com/KevinMidboe/linguist.git
synced 2025-10-29 17:50:22 +00:00
142 lines
3.3 KiB
Ruby
Executable File
142 lines
3.3 KiB
Ruby
Executable File
#!/usr/bin/env ruby
|
|
|
|
require 'linguist'
|
|
require 'rugged'
|
|
require 'optparse'
|
|
require 'json'
|
|
require 'tmpdir'
|
|
require 'zlib'
|
|
|
|
class GitLinguist
|
|
attr_reader :repo_path
|
|
attr_reader :commit_oid
|
|
attr_reader :incremental
|
|
|
|
def initialize(path, commit_oid, incremental = true)
|
|
@repo_path = path
|
|
@commit_oid = commit_oid || rugged.head.target_id
|
|
@incremental = incremental
|
|
end
|
|
|
|
def linguist
|
|
repo = Linguist::Repository.new(rugged, commit_oid)
|
|
|
|
if incremental && stats = load_language_stats
|
|
old_commit_oid, old_stats = stats
|
|
|
|
# A cache with NULL oid means that we want to froze
|
|
# these language stats in place and stop computing
|
|
# them (for performance reasons)
|
|
return old_stats if old_commit_oid == NULL_OID
|
|
repo.load_existing_stats(old_commit_oid, old_stats)
|
|
end
|
|
|
|
result = yield repo
|
|
|
|
save_language_stats(commit_oid, repo.cache)
|
|
result
|
|
end
|
|
|
|
def load_language_stats
|
|
version, commit_oid, stats = load_cache
|
|
if version == LANGUAGE_STATS_CACHE_VERSION && commit_oid && stats
|
|
[commit_oid, stats]
|
|
end
|
|
end
|
|
|
|
def save_language_stats(commit_oid, stats)
|
|
cache = [LANGUAGE_STATS_CACHE_VERSION, commit_oid, stats]
|
|
write_cache(cache)
|
|
end
|
|
|
|
def clear_language_stats
|
|
File.unlink(cache_file)
|
|
end
|
|
|
|
def disable_language_stats
|
|
save_language_stats(NULL_OID, {})
|
|
end
|
|
|
|
protected
|
|
NULL_OID = ("0" * 40).freeze
|
|
|
|
LANGUAGE_STATS_CACHE = 'language-stats.cache'
|
|
LANGUAGE_STATS_CACHE_VERSION = "v3:#{Linguist::VERSION}"
|
|
|
|
def rugged
|
|
@rugged ||= Rugged::Repository.bare(repo_path)
|
|
end
|
|
|
|
def cache_file
|
|
File.join(repo_path, LANGUAGE_STATS_CACHE)
|
|
end
|
|
|
|
def write_cache(object)
|
|
tmp_path = Dir::Tmpname.make_tmpname(cache_file, nil)
|
|
|
|
File.open(tmp_path, "wb") do |f|
|
|
marshal = Marshal.dump(object)
|
|
f.write(Zlib::Deflate.deflate(marshal))
|
|
end
|
|
|
|
File.rename(tmp_path, cache_file)
|
|
tmp_path = nil
|
|
ensure
|
|
(File.unlink(tmp_path) rescue nil) if tmp_path
|
|
end
|
|
|
|
def load_cache
|
|
marshal = File.open(cache_file, "rb") { |f| Zlib::Inflate.inflate(f.read) }
|
|
Marshal.load(marshal)
|
|
rescue SystemCallError, ::Zlib::DataError, ::Zlib::BufError, TypeError
|
|
nil
|
|
end
|
|
end
|
|
|
|
|
|
def git_linguist(args)
|
|
incremental = true
|
|
commit = nil
|
|
git_dir = nil
|
|
|
|
parser = OptionParser.new do |opts|
|
|
opts.banner = "Usage: git-linguist [OPTIONS] stats|breakdown|dump-cache|clear|disable"
|
|
|
|
opts.on("-f", "--force", "Force a full rescan") { incremental = false }
|
|
opts.on("--git-dir=DIR", "Path to the git repository") { |v| git_dir = v }
|
|
opts.on("--commit=COMMIT", "Commit to index") { |v| commit = v}
|
|
end
|
|
|
|
parser.parse!(args)
|
|
|
|
git_dir ||= begin
|
|
pwd = Dir.pwd
|
|
dotgit = File.join(pwd, ".git")
|
|
File.directory?(dotgit) ? dotgit : pwd
|
|
end
|
|
|
|
wrapper = GitLinguist.new(git_dir, commit, incremental)
|
|
|
|
case args.pop
|
|
when "stats"
|
|
wrapper.linguist do |linguist|
|
|
puts JSON.dump(linguist.languages)
|
|
end
|
|
when "breakdown"
|
|
wrapper.linguist do |linguist|
|
|
puts JSON.dump(linguist.breakdown_by_file)
|
|
end
|
|
when "dump-cache"
|
|
puts JSON.dump(wrapper.load_language_stats)
|
|
when "clear"
|
|
wrapper.clear_language_stats
|
|
when "disable"
|
|
wrapper.disable_language_stats
|
|
else
|
|
$stderr.print(parser.help)
|
|
exit 1
|
|
end
|
|
end
|
|
|
|
git_linguist(ARGV)
|