summaryrefslogtreecommitdiff
blob: 30c227d457cfb69c8c9e1175d3c280d70bf33f32 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
# -*-eselect-*-
# Copyright 2005-2012 Gentoo Foundation
# Distributed under the terms of the GNU GPL version 2 or later
#
# DOCUMENTATION
# Following actions possible
# * show		do_show()
# * list		do_list()
# * set			do_set()
# * update		do_update()
#
# Behaviour:
# do_show():
#	Checks if /usr/bin/ctags is a link and if the target exists,
#	if yes, it outputs the currently linked ctags implementation.
#	If it is no symlink, the user is told so, the same if there is
#	no /usr/bin/ctags or the target does not exist.
# do_list(): List all available ctags implementations.
# do_set(): Set a version to be target of the symlink.
# do_update(): Set the target to the "best" available version. See below.

# This module is used for ctags and etags.
# Determine our name from ESELECT_MODULE_NAME, with BASH_SOURCE as fallback.
#CTAGS=${ESELECT_MODULE_NAME:-$(basename "${BASH_SOURCE[0]%.*}")}
CTAGS=ctags

DESCRIPTION="Manage /usr/bin/${CTAGS} implementations"
MAINTAINER="emacs@gentoo.org"
VERSION="1.14"

find_targets() {
	# Return the list of available ctags implementations

	# (X)Emacs: offer only one ctags implementation, namely for the
	# currently active Emacs version (selected by emacs.eselect)
	# The logic here is the same as in emacs.eselect, don't change it!
	local emacs
	if [[ -L ${EROOT}/usr/bin/emacs && -e ${EROOT}/usr/bin/emacs ]]; then
		emacs=$(basename "$(readlink "${EROOT}/usr/bin/emacs")")
		[[ -f ${EROOT}/usr/bin/${CTAGS}-${emacs} ]] && echo "${CTAGS}-${emacs}"
	elif [[ -f ${EROOT}/usr/bin/xemacs ]]; then
		[[ -f ${EROOT}/usr/bin/${CTAGS}-xemacs ]] && echo "${CTAGS}-xemacs"
	elif [[ ${CTAGS} = etags ]]; then
		# We are called as etags module, but no (X)Emacs is installed.
		# Return an empty list in this case, because we don't want
		# exuberant-ctags as default for etags (for ctags it's fine).
		# Also, vi purists wouldn't want an etags symlink.
		return
	fi

	# Exuberant ctags
	[[ -f ${EROOT}/usr/bin/exuberant-ctags ]] && echo exuberant-ctags
}

remove_symlinks() {
	# Remove existing symlinks to binary and man page
	rm -f "${EROOT}/usr/bin/${CTAGS}" "${EROOT}"/usr/share/man/man1/${CTAGS}.1*
}

set_bin_symlinks() {
	# Set symlink to binary
	local target=$1
	ln -s "${target}" "${EROOT}/usr/bin/${CTAGS}" \
		|| die "Couldn't set ${target} ${EROOT}/usr/bin/${CTAGS} symlink"
}

set_man_symlinks() {
	# Set symlink to man page
	local target=$1 extension i
	for i in "${EROOT}"/usr/share/man/man1/${target}.1*; do
		if [[ -f ${i} ]]; then
			# target file exists; determine compress extension
			extension=${i##*/${target}.1}
			ln -s "${target}.1${extension}" \
				"${EROOT}/usr/share/man/man1/${CTAGS}.1${extension}"
		fi
	done
}

set_symlinks() {
	# Set symlinks to binary and man page
	local target=$1 targets
	# target may be specified by its name or its index
	if is_number "${target}"; then
		# numeric index, find the target's name
		targets=( $(find_targets) )
		[[ ${target} -ge 1 && ${target} -le ${#targets[@]} ]] \
			|| die -q "Number out of range: $1"
		target=${targets[target-1]}
	fi

	# is the target valid, i.e. does a ctags binary with this name exist?
	[[ -f ${EROOT}/usr/bin/${target} ]] \
		|| die -q "Target \"$1\" doesn't appear to be valid!"

	echo "Switching ${CTAGS} to ${target} ..."
	remove_symlinks || die -q "Couldn't remove existing symlink"
	set_bin_symlinks "${target}"
	set_man_symlinks "${target}"
	return 0
}

test_for_root() {
	# checks if the user has rights to modify /usr/bin/
	[[ -w ${EROOT}/usr/bin ]] || die -q "You need root privileges!"
}

### show action ###

describe_show() {
	echo "Show the current target of the ${CTAGS} symlink"
}

do_show() {
	[[ $# -gt 0 ]] && die -q "Too many parameters"

	write_list_start "Current target of ${CTAGS} symlink:"
	if [[ -L ${EROOT}/usr/bin/${CTAGS} && -e ${EROOT}/usr/bin/${CTAGS} ]]
	then
		write_kv_list_entry \
			"$(basename "$(readlink "${EROOT}/usr/bin/${CTAGS}")")" ""
	elif [[ -e ${EROOT}/usr/bin/${CTAGS} ]]; then
		write_kv_list_entry \
			"(not a symlink or target of symlink does not exist)" ""
	else
		write_kv_list_entry "(unset)" ""
	fi
}

### list action ###

describe_list() {
	echo "List available ${CTAGS} symlink targets"
}

do_list() {
	[[ $# -gt 0 ]] && die -q "Too many parameters"

	local i targets
	targets=( $(find_targets) )

	for (( i = 0; i < ${#targets[@]}; i++ )); do
		# Highlight the currently chosen version
		[[ ${targets[i]} = \
			"$(basename "$(readlink "${EROOT}/usr/bin/${CTAGS}")")" ]] \
			&& targets[i]=$(highlight_marker "${targets[i]}")
	done
	write_list_start "Available ${CTAGS} symlink targets:"
	write_numbered_list -m "(none found)" "${targets[@]}"
}

### set action ###

describe_set() {
	echo "Set a new ${CTAGS} symlink"
}

describe_set_options() {
	echo "target : Target name or number (from 'list' action)"
}

describe_set_parameters() {
	echo "<target>"
}

do_set() {
	[[ -z $1 ]] && die -q "You didn't tell me what to set the symlink to"
	[[ $# -gt 1 ]] && die -q "Too many parameters"
	test_for_root

	if [[ -e ${EROOT}/usr/bin/${CTAGS} && ! -L ${EROOT}/usr/bin/${CTAGS} ]]
	then
		die -q "${EROOT}/usr/bin/${CTAGS} exists but is not a symlink"
	fi

	set_symlinks "$1" || die -q "Couldn't set a new symlink"
}

### update action ###

describe_update() {
	echo "Automatically update the ${CTAGS} symlink"
}

describe_update_options() {
	echo "ifunset : Do not override currently set version"
}

do_update() {
	[[ -z $1 || $1 = ifunset || $1 = --if-unset ]] || die -q "Usage error"
	[[ -z $2 || $2 = norecursion ]] || die -q "Usage error"
	[[ $# -gt 2 ]] && die -q "Too many parameters"
	test_for_root

	if ! [[ $1 == *if*unset \
		&& -L ${EROOT}/usr/bin/${CTAGS} && -e ${EROOT}/usr/bin/${CTAGS} ]]
	then
		local current=""
		if [[ -L ${EROOT}/usr/bin/${CTAGS} ]]; then
			current=$(basename "$(readlink "${EROOT}/usr/bin/${CTAGS}")")
			if [[ ! -e ${EROOT}/usr/bin/${CTAGS} ]]; then
				# clean up dead symlinks
				remove_symlinks || die -q "Couldn't remove existing symlink"
			fi
		elif [[ -e ${EROOT}/usr/bin/${CTAGS} ]]; then
			if ! [[ ${CTAGS} = ctags && $(uname) = FreeBSD ]]; then
				die -q "${EROOT}/usr/bin/${CTAGS} exists but is not a symlink"
			fi
			# On FreeBSD ctags is a real file, installed by freebsd-ubin
			current=nolink
		fi

		# For an "update" only the version should be changed, but not the
		# provider (i.e. Emacs vs Exuberant). At the moment only (X)Emacs
		# offers several concurrent versions.

		local i target targets=( $(find_targets) )
		if [[ ${#targets[@]} -gt 0 && ${current} != nolink ]]; then
			target=${targets[0]}
			[[ ${current} == ${CTAGS}-*emacs* ]] && current=${CTAGS}-*emacs*
			for i in ${targets[@]}; do
				[[ ${i} == ${current} ]] && target=${i}
			done
			set_symlinks "${target}" || die -q "Couldn't set a new symlink"
		fi
	fi

	# Call "eselect etags update" from the ctags module and vice versa
	[[ $2 = norecursion ]] && return
	case ${CTAGS} in
		ctags) CTAGS=etags do_update "$1" norecursion ;;
		etags) CTAGS=ctags do_update "$1" norecursion ;;
	esac
}