Fri, 20 Jan 2017 10:23:27 -0500
no background
#!/usr/bin/env ruby exit if ENV['CTAGS_SKIP'] running_hook = ENV['CTAGS_HOOK'] || false ctags_cmd = ENV['CTAGS_CMD'] || 'ctags' case ARGV[0] when 'help' exec 'perldoc', '-T', $0 when 'hook' running_hook = true end if (dir = `git rev-parse --show-toplevel 2>/dev/null`.chomp) != '' list_cmd = 'git ls-files' conf = "#{dir}/.git/ctags.conf" elsif (dir = `hg root 2>/dev/null`.chomp) != '' list_cmd = 'hg stat -Aqn' conf = "#{dir}/.hg/ctags.conf" else abort 'not an hg or git repository' end target = "#{dir}/.tags" tmp = "#{dir}/.tags.#{$$}~" opts = File.exists?(conf) ? "--options=#{conf}" : '' if running_hook fork and exit sleep 5 end open(target, File::RDONLY|File::CREAT, 0644) do |f| if running_hook exit unless f.flock(File::LOCK_EX|File::LOCK_NB) exit unless (Time.now - f.mtime) > 60 end system(<<-CMD) or exit $?.exitstatus #{list_cmd} \ | #{ctags_cmd} --tag-relative -L - -f"#{tmp}" #{opts} \ && mv #{tmp} #{target} CMD end exit 0 __END__ =head1 NAME git-ctags - run ctags on git tracked files =head1 SYNOPSIS git ctags echo 'git ctags hook 2>/dev/null' >> .git/hooks/post-checkout git checkout some/branch CTAGS_SKIP=1 git checkout some/branch =head1 DESCRIPTION Create a .tags file (target) using git's list of tracked files. If C<.git/ctags.conf> exists in the repo it is passed to the ctags invocation. When run with the C<hook> argument or C<CTAGS_HOOK> set, additional behavior is enabled to avoid excess re-runs during multiple VCS operations, and the work is moved to background as well. =head2 Mercurial Mercurial repositories are supported too, with git taking priority when finding a repo root. To add a hook, in the repository C<.hg/hgrc>, add: [hooks] update = git ctags hook In a Mercurial repo, additional options can be put in C<.hg/ctags.conf>. =head1 ENVIRONMENT =head2 CTAGS_SKIP If defined, exit immediately. =head2 CTAGS_HOOK If defined, run as a VCS hook. This causes git-ctags to fork and exit, wait five seconds, then try to lock and update the tags file if it hasn't been updated in the last minute. =head2 CTAGS_CMD If defined, use this to invoke ctags rather than assuming C<ctags> can be found in path. =cut