1 #!/usr/bin/env ruby |
|
2 exit if ENV['CTAGS_SKIP'] |
|
3 running_hook = ENV['CTAGS_HOOK'] || false |
|
4 ctags_cmd = ENV['CTAGS_CMD'] || 'ctags' |
|
5 |
|
6 case ARGV[0] |
|
7 when 'help' |
|
8 exec 'perldoc', '-T', $0 |
|
9 when 'hook' |
|
10 running_hook = true |
|
11 end |
|
12 |
|
13 if (dir = `git rev-parse --show-toplevel 2>/dev/null`.chomp) != '' |
|
14 list_cmd = 'git ls-files' |
|
15 conf = "#{dir}/.git/ctags.conf" |
|
16 elsif (dir = `hg root 2>/dev/null`.chomp) != '' |
|
17 list_cmd = 'hg stat -Aqn' |
|
18 conf = "#{dir}/.hg/ctags.conf" |
|
19 else |
|
20 abort 'not an hg or git repository' |
|
21 end |
|
22 |
|
23 target = "#{dir}/.tags" |
|
24 tmp = "#{dir}/.tags.#{$$}~" |
|
25 opts = File.exists?(conf) ? "--options=#{conf}" : '' |
|
26 |
|
27 if running_hook |
|
28 fork and exit |
|
29 [STDIN, STDOUT, STDERR].each {|p| p.reopen '/dev/null'} |
|
30 sleep 5 |
|
31 end |
|
32 |
|
33 open(target, File::RDONLY|File::CREAT, 0644) do |f| |
|
34 if running_hook |
|
35 exit unless f.flock(File::LOCK_EX|File::LOCK_NB) |
|
36 exit unless f.size == 0 || (Time.now - f.mtime) > 60 |
|
37 end |
|
38 |
|
39 system(<<-CMD) or exit $?.exitstatus |
|
40 #{list_cmd} \ |
|
41 | #{ctags_cmd} --tag-relative -L - -f"#{tmp}" #{opts} \ |
|
42 && mv #{tmp} #{target} |
|
43 CMD |
|
44 end |
|
45 |
|
46 exit 0 |
|
47 |
|
48 __END__ |
|
49 =head1 NAME |
|
50 |
|
51 git-ctags - run ctags on git tracked files |
|
52 |
|
53 =head1 SYNOPSIS |
|
54 |
|
55 git ctags |
|
56 |
|
57 echo 'git ctags hook 2>/dev/null' >> .git/hooks/post-checkout && |
|
58 chmod +x $_ |
|
59 |
|
60 git checkout some/branch |
|
61 CTAGS_SKIP=1 git checkout some/branch |
|
62 |
|
63 =head1 DESCRIPTION |
|
64 |
|
65 Create a .tags file (target) using git's list of tracked files. If |
|
66 C<.git/ctags.conf> exists in the repo it is passed to the ctags invocation. |
|
67 |
|
68 When run with the C<hook> argument or C<CTAGS_HOOK> set, additional behavior is |
|
69 enabled to avoid excess re-runs during multiple VCS operations, and the work is |
|
70 moved to background as well. |
|
71 |
|
72 =head2 Mercurial |
|
73 |
|
74 Mercurial repositories are supported too, with git taking priority when finding |
|
75 a repo root. To add a hook, in the repository C<.hg/hgrc>, add: |
|
76 |
|
77 [hooks] |
|
78 update = git ctags hook |
|
79 |
|
80 In a Mercurial repo, additional options can be put in C<.hg/ctags.conf>. |
|
81 |
|
82 =head1 ENVIRONMENT |
|
83 |
|
84 =head2 CTAGS_SKIP |
|
85 |
|
86 If defined, exit immediately. |
|
87 |
|
88 =head2 CTAGS_HOOK |
|
89 |
|
90 If defined, run as a VCS hook. This causes git-ctags to fork and exit, wait five |
|
91 seconds, then try to lock and update the tags file if it hasn't been updated in |
|
92 the last minute. |
|
93 |
|
94 =head2 CTAGS_CMD |
|
95 |
|
96 If defined, use this to invoke ctags rather than assuming C<ctags> can be found in |
|
97 path. |
|
98 |
|
99 =cut |
|