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
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
|
# Copyright 1999-2024 Gentoo Authors
# Distributed under the terms of the GNU General Public License v2
# @ECLASS: cvs.eclass
# @MAINTAINER:
# vapier@gentoo.org (and anyone who wants to help)
# @SUPPORTED_EAPIS: 7 8
# @BLURB: This eclass provides generic cvs fetching functions
# @DESCRIPTION:
# This eclass provides the generic cvs fetching functions. To use this from an
# ebuild, set the ECLASS VARIABLES as specified below in your ebuild before
# inheriting. Then either leave the default src_unpack or extend over
# cvs_src_unpack. If you find that you need to call the cvs_* functions
# directly, I'd be interested to hear about it.
case ${EAPI} in
7|8) ;;
*) die "${ECLASS}: EAPI ${EAPI:-0} not supported" ;;
esac
if [[ -z ${_CVS_ECLASS} ]]; then
_CVS_ECLASS=1
# TODO:
# Implement more auth types (gserver?, kserver?)
# Support additional remote shells with `ext' authentication (does
# anyone actually need to use it with anything other than SSH?)
# Users shouldn't change these settings! The ebuild/eclass inheriting
# this eclass will take care of that. If you want to set the global
# KDE cvs ebuilds' settings, see the comments in kde-source.eclass.
# @ECLASS_VARIABLE: ECVS_CVS_COMPRESS
# @DESCRIPTION:
# Set the default compression level. Has no effect when ECVS_CVS_COMMAND
# is defined by ebuild/user.
: "${ECVS_CVS_COMPRESS:=-z1}"
# @ECLASS_VARIABLE: ECVS_CVS_OPTIONS
# @DESCRIPTION:
# Additional options to the cvs commands. Has no effect when ECVS_CVS_COMMAND
# is defined by ebuild/user.
: "${ECVS_CVS_OPTIONS:=-q -f}"
# @ECLASS_VARIABLE: ECVS_CVS_COMMAND
# @DESCRIPTION:
# CVS command to run
#
# You can set, for example, "cvs -t" for extensive debug information
# on the cvs connection. The default of "cvs -q -f -z4" means to be
# quiet, to disregard the ~/.cvsrc config file and to use maximum
# compression.
: "${ECVS_CVS_COMMAND:=cvs ${ECVS_CVS_OPTIONS} ${ECVS_CVS_COMPRESS}}"
# @ECLASS_VARIABLE: ECVS_UP_OPTS
# @DESCRIPTION:
# CVS options given after the cvs update command. Don't remove "-dP" or things
# won't work.
: "${ECVS_UP_OPTS:=-dP}"
# @ECLASS_VARIABLE: ECVS_CO_OPTS
# @DEFAULT_UNSET
# @DESCRIPTION:
# CVS options given after the cvs checkout command.
# @ECLASS_VARIABLE: ECVS_OFFLINE
# @USER_VARIABLE
# @DESCRIPTION:
# Set this variable to a non-empty value to disable the automatic updating of
# a CVS source tree. This is intended to be set outside the cvs source
# tree by users.
: "${ECVS_OFFLINE:=${EVCS_OFFLINE}}"
# @ECLASS_VARIABLE: ECVS_LOCAL
# @DEFAULT_UNSET
# @DESCRIPTION:
# If this is set, the CVS module will be fetched non-recursively.
# Refer to the information in the CVS man page regarding the -l
# command option (not the -l global option).
# @ECLASS_VARIABLE: ECVS_LOCALNAME
# @DEFAULT_UNSET
# @DESCRIPTION:
# Local name of checkout directory
#
# This is useful if the module on the server is called something
# common like 'driver' or is nested deep in a tree, and you don't like
# useless empty directories.
#
# WARNING: Set this only from within ebuilds! If set in your shell or
# some such, things will break because the ebuild won't expect it and
# have e.g. a wrong $S setting.
# @ECLASS_VARIABLE: ECVS_TOP_DIR
# @DESCRIPTION:
# The directory under which CVS modules are checked out.
: "${ECVS_TOP_DIR:="${PORTAGE_ACTUAL_DISTDIR-${DISTDIR}}/cvs-src"}"
# @ECLASS_VARIABLE: ECVS_SERVER
# @DESCRIPTION:
# CVS path
#
# The format is "server:/dir", e.g. "anoncvs.kde.org:/home/kde".
# Remove the other parts of the full CVSROOT, which might look like
# ":pserver:anonymous@anoncvs.kde.org:/home/kde"; this is generated
# using other settings also.
#
# Set this to "offline" to disable fetching (i.e. to assume the module
# is already checked out in ECVS_TOP_DIR).
: "${ECVS_SERVER:="offline"}"
# @ECLASS_VARIABLE: ECVS_MODULE
# @REQUIRED
# @DESCRIPTION:
# The name of the CVS module to be fetched
#
# This must be set when cvs_src_unpack is called. This can include
# several directory levels, i.e. "foo/bar/baz"
#[[ -z ${ECVS_MODULE} ]] && die "$ECLASS: error: ECVS_MODULE not set, cannot continue"
# @ECLASS_VARIABLE: ECVS_DATE
# @DEFAULT_UNSET
# @DESCRIPTION:
# The date of the checkout. See the -D date_spec option in the cvs
# man page for more details.
# @ECLASS_VARIABLE: ECVS_BRANCH
# @DEFAULT_UNSET
# @DESCRIPTION:
# The name of the branch/tag to use
#
# The default is "HEAD". The following default _will_ reset your
# branch checkout to head if used.
#: ${ECVS_BRANCH:="HEAD"}
# @ECLASS_VARIABLE: ECVS_AUTH
# @PRE_INHERIT
# @DESCRIPTION:
# Authentication method to use
#
# Possible values are "pserver" and "ext". If `ext' authentication is
# used, the remote shell to use can be specified in CVS_RSH (SSH is
# used by default). Currently, the only supported remote shell for
# `ext' authentication is SSH.
#
# Armando Di Cianno <fafhrd@gentoo.org> 2004/09/27
# - Added "no" as a server type, which uses no AUTH method, nor
# does it login
# e.g.
# "cvs -danoncvs@savannah.gnu.org:/cvsroot/backbone co System"
# ( from gnustep-apps/textedit )
: "${ECVS_AUTH:="pserver"}"
# @ECLASS_VARIABLE: ECVS_USER
# @DESCRIPTION:
# Username to use for authentication on the remote server.
: "${ECVS_USER:="anonymous"}"
# @ECLASS_VARIABLE: ECVS_PASS
# @DEFAULT_UNSET
# @DESCRIPTION:
# Password to use for authentication on the remote server
# @ECLASS_VARIABLE: ECVS_SSH_HOST_KEY
# @DEFAULT_UNSET
# @DESCRIPTION:
# If SSH is used for `ext' authentication, use this variable to
# specify the host key of the remote server. The format of the value
# should be the same format that is used for the SSH known hosts file.
#
# WARNING: If a SSH host key is not specified using this variable, the
# remote host key will not be verified.
# @ECLASS_VARIABLE: ECVS_SSH_EXTRA_OPTS
# @DEFAULT_UNSET
# @DESCRIPTION:
# If SSH is used for "ext" authentication, this array variable can be
# used to pass additional options to the SSH command.
# @ECLASS_VARIABLE: ECVS_CLEAN
# @DEFAULT_UNSET
# @DESCRIPTION:
# Set this to get a clean copy when updating (passes the
# -C option to cvs update)
PROPERTIES+=" live"
# add cvs to deps
# ssh is used for ext auth
BDEPEND="dev-vcs/cvs"
if [[ ${ECVS_AUTH} == "ext" ]] ; then
#default to ssh
[[ -z ${CVS_RSH} ]] && export CVS_RSH="ssh"
if [[ ${CVS_RSH} != "ssh" ]] ; then
die "Support for ext auth with clients other than ssh has not been implemented yet"
fi
BDEPEND+=" >=net-misc/openssh-8.4"
fi
# @FUNCTION: cvs_fetch
# @DESCRIPTION:
# Fetch sources from a CVS repository. Called from cvs_src_unpack.
cvs_fetch() {
# Make these options local variables so that the global values are
# not affected by modifications in this function.
local ECVS_COMMAND=${ECVS_COMMAND}
local ECVS_UP_OPTS=${ECVS_UP_OPTS}
local ECVS_CO_OPTS=${ECVS_CO_OPTS}
debug-print-function ${FUNCNAME} "$@"
# Update variables that are modified by ebuild parameters, which
# should be effective every time cvs_fetch is called, and not just
# every time cvs.eclass is inherited
# Handle parameter for local (non-recursive) fetching
if [[ -n ${ECVS_LOCAL} ]] ; then
ECVS_UP_OPTS+=" -l"
ECVS_CO_OPTS+=" -l"
fi
# Handle ECVS_BRANCH option
#
# Because CVS auto-switches branches, we just have to pass the
# correct -rBRANCH option when updating.
if [[ -n ${ECVS_BRANCH} ]] ; then
ECVS_UP_OPTS+=" -r${ECVS_BRANCH}"
ECVS_CO_OPTS+=" -r${ECVS_BRANCH}"
fi
# Handle ECVS_LOCALNAME, which specifies the local directory name
# to use. Note that the -d command option is not equivalent to
# the global -d option.
if [[ ${ECVS_LOCALNAME} != "${ECVS_MODULE}" ]] ; then
ECVS_CO_OPTS+=" -d ${ECVS_LOCALNAME}"
fi
if [[ -n ${ECVS_CLEAN} ]] ; then
ECVS_UP_OPTS+=" -C"
fi
if [[ -n ${ECVS_DATE} ]] ; then
ECVS_CO_OPTS+=" -D ${ECVS_DATE}"
ECVS_UP_OPTS+=" -D ${ECVS_DATE}"
fi
# Create the top dir if needed
if [[ ! -d ${ECVS_TOP_DIR} ]] ; then
# Note that the addwrite statements in this block are only
# there to allow creating ECVS_TOP_DIR; we allow writing
# inside it separately.
# This is because it's simpler than trying to find out the
# parent path of the directory, which would need to be the
# real path and not a symlink for things to work (so we can't
# just remove the last path element in the string)
debug-print "${FUNCNAME}: checkout mode. creating cvs directory"
(
addwrite /
mkdir -p "${ECVS_TOP_DIR}" || die "mkdir ${ECVS_TOP_DIR} failed"
)
fi
# In case ECVS_TOP_DIR is a symlink to a dir, get the real path,
# otherwise addwrite() doesn't work.
cd -P "${ECVS_TOP_DIR}" >/dev/null || die
ECVS_TOP_DIR=$(pwd)
# Disable the sandbox for this dir
addwrite "${ECVS_TOP_DIR}"
# Determine the CVS command mode (checkout or update)
local mode
if [[ ! -d ${ECVS_TOP_DIR}/${ECVS_LOCALNAME}/CVS ]] ; then
mode=checkout
else
mode=update
fi
# Our server string (i.e. CVSROOT) without the password so it can
# be put in Root
local connection="${ECVS_AUTH}"
if [[ ${ECVS_AUTH} == "no" ]] ; then
local server="${ECVS_USER}@${ECVS_SERVER}"
else
[[ -n ${ECVS_PROXY} ]] && connection+=";proxy=${ECVS_PROXY}"
[[ -n ${ECVS_PROXY_PORT} ]] && connection+=";proxyport=${ECVS_PROXY_PORT}"
local server=":${connection}:${ECVS_USER}@${ECVS_SERVER}"
fi
# Switch servers automagically if needed
if [[ ${mode} == "update" ]] ; then
cd "/${ECVS_TOP_DIR}/${ECVS_LOCALNAME}" || die
local oldserver=$(cat CVS/Root || die)
if [[ ${server} != "${oldserver}" ]] ; then
einfo "Changing the CVS server from ${oldserver} to ${server}:"
debug-print "${FUNCNAME}: Changing the CVS server from ${oldserver} to ${server}:"
einfo "Searching for CVS directories ..."
local cvsdirs=$(find . -iname CVS -print || die)
debug-print "${FUNCNAME}: CVS directories found:"
debug-print "${cvsdirs}"
einfo "Modifying CVS directories ..."
local x
for x in ${cvsdirs} ; do
debug-print "In ${x}"
echo "${server}" > "${x}/Root" || die
done
fi
fi
# Prepare a cvspass file just for this session, we don't want to
# mess with ~/.cvspass
local -x CVS_PASSFILE="${T}/cvspass"
touch "${CVS_PASSFILE}" || die
# The server string with the password in it, for login (only used for pserver)
local cvsroot_pass=":${connection}:${ECVS_USER}:${ECVS_PASS}@${ECVS_SERVER}"
# Ditto without the password, for checkout/update after login, so
# that the CVS/Root files don't contain the password in plaintext
local cvsroot_nopass
if [[ ${ECVS_AUTH} == "no" ]] ; then
cvsroot_nopass="${ECVS_USER}@${ECVS_SERVER}"
else
cvsroot_nopass=":${connection}:${ECVS_USER}@${ECVS_SERVER}"
fi
# Commands to run
local cmdlogin=(
${ECVS_CVS_COMMAND} -d "${cvsroot_pass}" login
)
local cmdupdate=(
${ECVS_CVS_COMMAND} -d "${cvsroot_nopass}" update
${ECVS_UP_OPTS} ${ECVS_LOCALNAME}
)
local cmdcheckout=(
${ECVS_CVS_COMMAND} -d "${cvsroot_nopass}" checkout
${ECVS_CO_OPTS} ${ECVS_MODULE}
)
# Execute commands
cd "${ECVS_TOP_DIR}" || die
if [[ ${ECVS_AUTH} == "pserver" ]] ; then
einfo "Running ${cmdlogin[*]}"
"${cmdlogin[@]}" || die "cvs login command failed"
if [[ ${mode} == "update" ]] ; then
einfo "Running ${cmdupdate[*]}"
"${cmdupdate[@]}" || die "cvs update command failed"
elif [[ ${mode} == "checkout" ]] ; then
einfo "Running ${cmdcheckout[*]}"
"${cmdcheckout[@]}" || die "cvs checkout command failed"
fi
elif [[ ${ECVS_AUTH} == "ext" || ${ECVS_AUTH} == "no" ]] ; then
# Hack to support SSH password authentication
if [[ ${CVS_RSH} == "ssh" ]] ; then
# Handle SSH host key checking
local known_hosts_file="${T}/cvs_ssh_known_hosts"
local strict_host_key_checking
if [[ -z ${ECVS_SSH_HOST_KEY} ]] ; then
ewarn "Warning: The SSH host key of the remote server will not be verified."
einfo "A temporary known hosts list will be used."
strict_host_key_checking="no"
touch "${known_hosts_file}" || die
else
strict_host_key_checking="yes"
echo "${ECVS_SSH_HOST_KEY}" > "${known_hosts_file}" || die
fi
local i quoted_opts=()
for i in "${!ECVS_SSH_EXTRA_OPTS[@]}"; do
printf -v "quoted_opts[i]" "%q" "${ECVS_SSH_EXTRA_OPTS[i]}"
done
# Create a wrapper script to pass additional options to SSH
# Disable X11 forwarding which causes .xauth access violations
local -x CVS_RSH="${T}/cvs_sshwrapper"
cat > "${CVS_RSH}" <<-EOF || die
#!${BROOT}/bin/bash
exec "${BROOT}/usr/bin/ssh" \\
-oStrictHostKeyChecking=${strict_host_key_checking} \\
-oUserKnownHostsFile="${known_hosts_file}" \\
-oForwardX11=no \\
-oClearAllForwardings=yes \\
${quoted_opts[*]} \\
"\$@"
EOF
chmod a+x "${CVS_RSH}" || die
# Create a dummy executable to echo ${ECVS_PASS}
local -x SSH_ASKPASS="${T}/cvs_sshechopass"
local -x SSH_ASKPASS_REQUIRE="force"
if [[ ${ECVS_AUTH} != "no" ]] ; then
echo -en "#!${BROOT}/bin/bash\necho \"${ECVS_PASS}\"\n" \
> "${SSH_ASKPASS}" || die
else
echo -en "#!${BROOT}/bin/bash\nreturn\n" \
> "${SSH_ASKPASS}" || die
fi
chmod a+x "${SSH_ASKPASS}" || die
fi
if [[ ${mode} == "update" ]] ; then
einfo "Running ${cmdupdate[*]}"
"${cmdupdate[@]}" || die "cvs update command failed"
elif [[ ${mode} == "checkout" ]] ; then
einfo "Running ${cmdcheckout[*]}"
"${cmdcheckout[@]}" || die "cvs checkout command failed"
fi
fi
}
# @FUNCTION: cvs_src_unpack
# @DESCRIPTION:
# The cvs src_unpack function, which will be exported
cvs_src_unpack() {
debug-print-function ${FUNCNAME} "$@"
debug-print "${FUNCNAME}: init:
ECVS_CVS_COMMAND=${ECVS_CVS_COMMAND}
ECVS_UP_OPTS=${ECVS_UP_OPTS}
ECVS_CO_OPTS=${ECVS_CO_OPTS}
ECVS_TOP_DIR=${ECVS_TOP_DIR}
ECVS_SERVER=${ECVS_SERVER}
ECVS_USER=${ECVS_USER}
ECVS_PASS=${ECVS_PASS}
ECVS_MODULE=${ECVS_MODULE}
ECVS_LOCAL=${ECVS_LOCAL}
ECVS_LOCALNAME=${ECVS_LOCALNAME}"
[[ -z ${ECVS_MODULE} ]] && die "ERROR: CVS module not set, cannot continue."
local ECVS_LOCALNAME=${ECVS_LOCALNAME:-${ECVS_MODULE}}
local sanitized_pn=$(echo "${PN}" | LC_ALL=C sed -e 's:[^A-Za-z0-9_]:_:g')
local offline_pkg_var="ECVS_OFFLINE_${sanitized_pn}"
if [[ -n ${!offline_pkg_var}${ECVS_OFFLINE} ]] || [[ ${ECVS_SERVER} == "offline" ]] ; then
# We're not required to fetch anything; the module already
# exists and shouldn't be updated.
if [[ -d ${ECVS_TOP_DIR}/${ECVS_LOCALNAME} ]] ; then
debug-print "${FUNCNAME}: offline mode"
else
debug-print "${FUNCNAME}: Offline mode specified but directory ${ECVS_TOP_DIR}/${ECVS_LOCALNAME} not found, exiting with error"
die "ERROR: Offline mode specified, but directory ${ECVS_TOP_DIR}/${ECVS_LOCALNAME} not found. Aborting."
fi
elif [[ -n ${ECVS_SERVER} ]] ; then # ECVS_SERVER!=offline --> real fetching mode
einfo "Fetching CVS module ${ECVS_MODULE} into ${ECVS_TOP_DIR} ..."
cvs_fetch
else # ECVS_SERVER not set
die "ERROR: CVS server not specified, cannot continue."
fi
einfo "Copying ${ECVS_MODULE} from ${ECVS_TOP_DIR} ..."
debug-print "Copying module ${ECVS_MODULE} local_mode=${ECVS_LOCAL} from ${ECVS_TOP_DIR} ..."
# This is probably redundant, but best to make sure.
mkdir -p "${WORKDIR}/${ECVS_LOCALNAME}" || die
if [[ -n ${ECVS_LOCAL} ]] ; then
cp -f "${ECVS_TOP_DIR}/${ECVS_LOCALNAME}"/* \
"${WORKDIR}/${ECVS_LOCALNAME}" || die
else
cp -Rf "${ECVS_TOP_DIR}/${ECVS_LOCALNAME}" \
"${WORKDIR}/${ECVS_LOCALNAME}/.." || die
fi
# Not exactly perfect, but should be pretty close #333773
export ECVS_VERSION=$(
find "${ECVS_TOP_DIR}/${ECVS_LOCALNAME}/" -ipath '*/CVS/Entries' -exec cat {} + | \
LC_ALL=C sort | \
sha1sum | \
awk '{print $1}'
assert
)
# If the directory is empty, remove it; empty directories cannot
# exist in cvs. This happens when, for example, kde-source
# requests module/doc/subdir which doesn't exist. Still create
# the empty directory in workdir though.
if [[ $(ls -A "${ECVS_TOP_DIR}/${ECVS_LOCALNAME}") == "CVS" ]] ; then
debug-print "${FUNCNAME}: removing empty CVS directory ${ECVS_LOCALNAME}"
rm -rf "${ECVS_TOP_DIR}/${ECVS_LOCALNAME}" || die
fi
einfo "CVS module ${ECVS_MODULE} is now in ${WORKDIR}"
}
fi
EXPORT_FUNCTIONS src_unpack
|