bin/git-ctags

changeset 875
be7ff50ed819
parent 874
dc834fea1a3f
child 876
9702221eb0f6
equal deleted inserted replaced
874:dc834fea1a3f 875:be7ff50ed819
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

mercurial