summaryrefslogtreecommitdiff
blob: 36b90a327fde6fd9054183bd245086715c047776 (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
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
# Copyright 1999-2024 Gentoo Authors
# Distributed under the terms of the GNU General Public License v2

# @ECLASS: texlive-common.eclass
# @MAINTAINER:
# tex@gentoo.org
# @AUTHOR:
# Original Author: Alexis Ballier <aballier@gentoo.org>
# @SUPPORTED_EAPIS: 7 8
# @BLURB: Provide various functions used by both texlive-core and texlive modules
# @DESCRIPTION:
# Purpose: Provide various functions used by both texlive-core and texlive
# modules.
#
# Note that this eclass *must* not assume the presence of any standard tex too

case ${EAPI} in
	7)
		inherit eapi8-dosym
		;;
	8) ;;
	*) die "${ECLASS}: EAPI ${EAPI:-0} not supported" ;;
esac

inherit edo

if [[ -z ${_TEXLIVE_COMMON_ECLASS} ]]; then
_TEXLIVE_COMMON_ECLASS=1

# @ECLASS_VARIABLE: CTAN_MIRROR_URL
# @USER_VARIABLE
# @DESCRIPTION:
# This variable can be used to set the CTAN mirror that will be used to fetch
# CTAN artifacts. Note that this mirror is usually only used as fallback
# in case the Gentoo mirrors do not hold the requested files.
#
# Only Gentoo TeX developers may want to set this.
#
# Example:
# @CODE
# CTAN_MIRROR_URL='https://ftp.fau.de/ctan/' emerge -1v app-text/texlive-core
# @CODE
: "${CTAN_MIRROR_URL:="https://mirrors.ctan.org"}"

# @ECLASS_VARIABLE: TEXLIVE_SCRIPTS_W_FILE_EXT
# @DEFAULT_UNSET
# @DESCRIPTION:
# If set, contains a space separated list of script names that should be
# linked including their file extensions, i.e., without stripping
# potentially existing filename extensions from the link's name.

# @FUNCTION: texlive-common_handle_config_files
# @DESCRIPTION:
# Has to be called in src_install after having installed the files in ${D}
# This function will move the relevant files to /etc/texmf and symlink them
# from their original location. This is to allow easy update of texlive's
# configuration.
# Called by app-text/texlive-core and texlive-module.eclass.
texlive-common_handle_config_files() {
	local texmf_path
	# Starting with TeX Live 2023, we install in texmf-dist, where a
	# distribution-provided TeX Live installation is supposed to be,
	# instead of texmf.
	if ver_test -ge 2023; then
		texmf_path=/usr/share/texmf-dist
	else
		texmf_path=/usr/share/texmf
	fi

	# Handle config files properly
	[[ -d ${ED}${texmf_path} ]] || return
	cd "${ED}${texmf_path}" || die

	while read -r f; do
		if [[ ${f#*config} != "${f}" || ${f#doc} != "${f}" || ${f#source} != "${f}" || ${f#tex} != "${f}" ]] ; then
			continue
		fi
		local rel_dir
		rel_dir="$(dirname "${f}")"

		dodir "/etc/texmf/${rel_dir}.d"
		einfo "Moving (and symlinking) ${EPREFIX}${texmf_path}/${f} to ${EPREFIX}/etc/texmf/${rel_dir}.d"
		mv "${ED}/${texmf_path}/${f}" "${ED}/etc/texmf/${rel_dir}.d" || die "mv ${f} failed."

		local dosym=dosym
		[[ ${EAPI} == 7 ]] && dosym=dosym8
		${dosym} -r "/etc/texmf/${rel_dir}.d/$(basename "${f}")" "${texmf_path}/${f}"
	done < <(find . -name '*.cnf' -type f -o -name '*.cfg' -type f | sed -e "s:\./::g")
}

# @FUNCTION: texlive-common_is_file_present_in_texmf
# @DESCRIPTION:
# Return if a file is present in the texmf tree
# Call it from the directory containing texmf and texmf-dist
# Called by app-text/texlive-core.
texlive-common_is_file_present_in_texmf() {
	local mark="${T}/${1}.found"
	if [[ -d texmf ]]; then
		find texmf -name "${1}" -exec touch "${mark}" {} + || die
	fi

	if [[ -d texmf-dist ]]; then
		find texmf-dist -name "${1}" -exec touch "${mark}" {} + || die
	fi
	[ -f "${mark}" ]
}

# @FUNCTION: texlive-common_do_symlinks
# @USAGE: <src> <dest>
# @DESCRIPTION:
# Mimic the install_link function of texlinks
#
# Should have the same behavior as the one in /usr/bin/texlinks
# except that it is under the control of the package manager
# Note that $1 corresponds to $src and $2 to $dest in this function
# ( Arguments are switched because texlinks main function sends them switched )
# This function should not be called from an ebuild, prefer etexlinks that will
# also do the fmtutil file parsing.
# Called by texlive-common.eclass and texlive-module.eclass.
texlive-common_do_symlinks() {
	while [[ ${#} != 0 ]]; do
		case ${1} in
			cont-??|metafun|mptopdf)
				einfo "Symlink ${1} skipped (special case)"
				;;
			mf)
				einfo "Symlink ${1} -> ${2} skipped (texlive-core takes care of it)"
				;;
			*)
				if [[ ${1} == "${2}" ]]; then
					einfo "Symlink ${1} -> ${2} skipped"
				elif [[ -e ${ED}/usr/bin/${1} || -L ${ED}/usr/bin/${1} ]]; then
					einfo "Symlink ${1} skipped (file exists)"
				else
					einfo "Making symlink from ${1} to ${2}"
					dosym "${2}" "/usr/bin/${1}"
				fi
				;;
		esac
		shift; shift;
	done
}

# @FUNCTION: etexlinks
# @USAGE: <file>
# @DESCRIPTION:
# Mimic texlinks on a fmtutil format file
#
# $1 has to be a fmtutil format file like fmtutil.cnf
# etexlinks foo will install the symlinks that texlinks --cnffile foo would have
# created. We cannot use texlinks with portage as it is not DESTDIR aware.
# (It would not fail but will not create the symlinks if the target is not in
# the same dir as the source)
# Also, as this eclass must not depend on a tex distribution to be installed we
# cannot use texlinks from here.
# Called by texlive-module.eclass.
etexlinks() {
	# Install symlinks from formats to engines
	texlive-common_do_symlinks $(sed '/^[      ]*#/d; /^[      ]*$/d' "$1" | awk '{print $1, $2}')
}

# @FUNCTION: dobin_texmf_scripts
# @USAGE: <file1> [file2] ...
# @DESCRIPTION:
# Symlinks a script from the texmf tree to /usr/bin. Requires permissions to be
# correctly set for the file that it will point to.
# Called by app-text/epspdf and texlive-module.eclass.
dobin_texmf_scripts() {
	while [[ ${#} -gt 0 ]] ; do
		# -l: TexLive target links are always lowercase.
		local -l trg

		# Get the basename of the script.
		trg="${1##*/}"

		# Only strip the filename extensions if trg is not listed in TEXLIVE_SCRIPTS_W_FILE_EXT.
		if ! has "${trg}" ${TEXLIVE_SCRIPTS_W_FILE_EXT}; then
			trg="${trg%.*}"
		fi

		einfo "Installing ${1} as ${trg} bin wrapper"
		[[ -x ${ED}/usr/share/${1} ]] || die "Trying to install a non existing or non executable symlink to /usr/bin: ${1}"
		dosym "../share/${1}" "/usr/bin/${trg}"
		shift
	done
}

# @FUNCTION: etexmf-update
# @DESCRIPTION:
# Runs texmf-update if it is available and prints a warning otherwise. This
# function helps in factorizing some code.  Useful in ebuilds' pkg_postinst and
# pkg_postrm phases.
# Called by app-text/dvipsk, app-text/texlive-core, dev-libs/kpathsea, and
# texlive-module.eclass.
etexmf-update() {
	if has_version 'app-text/texlive-core' ; then
		if [[ -z ${ROOT} && -x "${EPREFIX}"/usr/sbin/texmf-update ]] ; then
			"${EPREFIX}"/usr/sbin/texmf-update
			local res="${?}"
			if [[ "${res}" -ne 0 ]] &&
				   { [[ ${CATEGORY} != dev-texlive ]] || ver_test -ge 2023; } then
				die -n "texmf-update returned non-zero exit status ${res}"
			fi
		else
			ewarn "Cannot run texmf-update for some reason."
			ewarn "Your texmf tree might be inconsistent with your configuration"
			ewarn "Please try to figure what has happened"
		fi
	fi
}

# @FUNCTION: efmtutil-sys
# @DESCRIPTION:
# Runs fmtutil-sys if it is available and prints a warning otherwise. This
# function helps in factorizing some code. Used in ebuilds' pkg_postinst to
# force a rebuild of TeX formats.
efmtutil-sys() {
	if has_version 'app-text/texlive-core' ; then
		if [[ -z ${ROOT} && -x "${EPREFIX}"/usr/bin/fmtutil-sys ]] ; then
			edob -m "Rebuilding TexLive formats" \
				 -l fmtutils-sys-all \
				 "${EPREFIX}"/usr/bin/fmtutil-sys --all
		else
			ewarn "Cannot run fmtutil-sys for some reason."
			ewarn "Your formats might be inconsistent with your installed ${PN} version"
			ewarn "Please try to figure what has happened"
		fi
	fi
}

# @FUNCTION: texlive-common_append_to_src_uri
# @DESCRIPTION:
# Takes the name of a variable as input.  The variable must contain a
# list of texlive packages.  Every texlive package in the variable is
# transformed to an URL and appended to SRC_URI.
texlive-common_append_to_src_uri() {
	local tl_uri=( ${!1} )

	# Starting from TeX Live 2009, upstream provides .tar.xz modules.
	local tl_pkgext=tar.xz

	local tl_uri_prefix="https://dev.gentoo.org/~@dev@/distfiles/texlive/tl-"
	local tl_2023_uri_prefix="https://dev.gentoo.org/~@dev@/distfiles/texlive/"

	local tl_dev
	# If the version is less than 2023 and the package is the
	# dev-texlive category, we fallback to the old SRC_URI layout. With
	# the 2023 bump, packages outside the dev-texlive category start to
	# inherit texlive-common.eclass.
	if ver_test -lt 2023 && [[ ${CATEGORY} == dev-texlive ]]; then
		local texlive_lt_2023_devs=( zlogene dilfridge sam )
		local tl_uri_suffix="-${PV}.${tl_pkgext}"

		tl_uri=( "${tl_uri[@]/%/${tl_uri_suffix}}" )
		for tl_dev in "${texlive_lt_2023_devs[@]}"; do
			SRC_URI+=" ${tl_uri[*]/#/${tl_uri_prefix/@dev@/${tl_dev}}}"
		done
	else
		local texlive_ge_2023_devs=( flow )
		local tl_mirror="${CTAN_MIRROR_URL%/}/systems/texlive/tlnet/archive/"

		tl_uri=( "${tl_uri[@]/%/.${tl_pkgext}}" )
		SRC_URI+=" ${tl_uri[*]/#/${tl_mirror}}"
		for tl_dev in "${texlive_ge_2023_devs[@]}"; do
			SRC_URI+=" ${tl_uri[*]/#/${tl_2023_uri_prefix/@dev@/${tl_dev}}}"
		done
	fi
}

# @FUNCTION: texlive-common_update_tlpdb
# @DESCRIPTION:
# Update the TexLive package database at /usr/share/tlpkg/texlive.tlpdb.
texlive-common_update_tlpdb() {
	[[ -v TL_PV && ${TL_PV} -lt 2023 ]] && return

	# If we are updating this package, then there is no need to update
	# the tlpdb in postrm, as it will be again updated in postinst.
	[[ ${EBUILD_PHASE} == postrm && -n ${REPLACED_BY_VERSION} ]] && return

	local tlpkg="${EROOT}"/usr/share/tlpkg
	local tlpobj="${tlpkg}"/tlpobj
	local tlpdb="${tlpkg}"/texlive.tlpdb

	ebegin "Regenerating TexLive package database"

	local new_tlpdb="${T}"/texlive.tlpdb

	touch "${new_tlpdb}" || die

	if [[ -d "${tlpobj}" ]]; then
		# The "sed -s '$G' below concatenates all tlpobj files separated
		# by a newline.
		find "${tlpobj}" -maxdepth 1 -type f -name "*.tlpobj" -print0 |
			sort -z |
			xargs -0 --no-run-if-empty sed -s '$G' >> "${new_tlpdb}"
		assert "generating tlpdb failed"
	fi

	if [[ -f ${tlpdb} ]]; then
		cmp -s "${new_tlpdb}" "${tlpdb}"
		local ret=$?
		case ${ret} in
			# content equal
			0)
				# Nothing to do, return.
				eend 0
				return
				;;
			# content differs
			1)
				;;
			# cmp failed with an error
			*)
				eend ${ret} "comparing new and existing tlpdb failed (exit status: ${ret})"
				die
				;;
		esac
	fi

	mv "${new_tlpdb}" "${tlpdb}"
	eend $? "moving tlpdb into position failed (exit status: ${?})" || die

	if [[ ! -s ${tlpdb} ]]; then
		rm "${tlpdb}" || die
	fi
}

fi