bin/git-ctags

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

mercurial