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