1 |
On Thu, Nov 19, 2020 at 2:32 AM Ulrich Müller <ulm@g.o> wrote: |
2 |
|
3 |
> This implements the dosym command proposed for EAPI 8 (called dosym8 |
4 |
> because we cannot use the same name as the package-manager builtin). |
5 |
> |
6 |
> "dosym -r <target> <link>" will expand the (apparent) path of <target> |
7 |
> relative to the (apparent) path of the directory containing <link>. |
8 |
> The main aim of this is to allow for an absolute path to be specified |
9 |
> as the link target, and the function will count path components and |
10 |
> convert it into a relative path. |
11 |
> |
12 |
> Since we're inside ED at this point but the image will finally be |
13 |
> installed in EROOT, we don't try to resolve any pre-existing symlinks |
14 |
> in <target> or <link>. In other words, path expansion only looks at |
15 |
> the specified apparent paths, without touching any actual files in ED |
16 |
> or EROOT. |
17 |
> |
18 |
> Signed-off-by: Ulrich Müller <ulm@g.o> |
19 |
> --- |
20 |
> eclass/eapi8-dosym.eclass | 108 ++++++++++++++++++++++++++++++++++++++ |
21 |
> 1 file changed, 108 insertions(+) |
22 |
> create mode 100644 eclass/eapi8-dosym.eclass |
23 |
> |
24 |
> diff --git a/eclass/eapi8-dosym.eclass b/eclass/eapi8-dosym.eclass |
25 |
> new file mode 100644 |
26 |
> index 000000000000..52f0ffe3e62b |
27 |
> --- /dev/null |
28 |
> +++ b/eclass/eapi8-dosym.eclass |
29 |
> @@ -0,0 +1,108 @@ |
30 |
> +# Copyright 2020 Gentoo Authors |
31 |
> +# Distributed under the terms of the GNU General Public License v2 |
32 |
> + |
33 |
> +# @ECLASS: eapi8-dosym.eclass |
34 |
> +# @MAINTAINER: |
35 |
> +# PMS team <pms@g.o> |
36 |
> +# @AUTHOR: |
37 |
> +# Ulrich Müller <ulm@g.o> |
38 |
> +# @SUPPORTED_EAPIS: 5 6 7 |
39 |
> +# @BLURB: Testing implementation of EAPI 8 dosym -r option |
40 |
> +# @DESCRIPTION: |
41 |
> +# A stand-alone implementation of the dosym command aimed for EAPI 8. |
42 |
> +# Intended to be used for wider testing of the proposed option and to |
43 |
> +# allow ebuilds to switch to the new model early, with minimal change |
44 |
> +# needed for actual EAPI 8. |
45 |
> +# |
46 |
> +# https://bugs.gentoo.org/708360 |
47 |
> + |
48 |
> +case ${EAPI} in |
49 |
> + 5|6|7) ;; |
50 |
> + *) die "${ECLASS}: EAPI=${EAPI:-0} not supported" ;; |
51 |
> +esac |
52 |
> + |
53 |
> +# @FUNCTION: _dosym8_canonicalize |
54 |
> +# @USAGE: <path> |
55 |
> +# @INTERNAL |
56 |
> +# @DESCRIPTION: |
57 |
> +# Transparent bash-only replacement for GNU "realpath -m -s". |
58 |
> +# Resolve references to "/./", "/../" and remove extra "/" characters |
59 |
> +# from <path>, without touching any actual file. |
60 |
> |
61 |
|
62 |
Take this as a nit, but do we have any way to test this function |
63 |
(particularly around edge cases.) |
64 |
I see eclass/tests exists, could we add a couple for this? |
65 |
|
66 |
|
67 |
> +_dosym8_canonicalize() { |
68 |
> |
69 |
|
70 |
in dosym8() you save and restore IFS, but you don't here, is there a reason |
71 |
for that? |
72 |
|
73 |
|
74 |
> + local path slash i prev out IFS=/ |
75 |
> + |
76 |
> + path=( $1 ) |
77 |
> + [[ $1 == /* ]] && slash=/ |
78 |
> + |
79 |
> + while true; do |
80 |
> + # Find first instance of non-".." path component followed |
81 |
> by "..", |
82 |
> + # or as a special case, "/.." at the beginning of the path. |
83 |
> + # Also drop empty and "." path components as we go along. |
84 |
> + prev= |
85 |
> + for i in ${!path[@]}; do |
86 |
> + if [[ -z ${path[i]} || ${path[i]} == . ]]; then |
87 |
> + unset "path[i]" |
88 |
> + elif [[ ${path[i]} != .. ]]; then |
89 |
> + prev=${i} |
90 |
> + elif [[ ${prev} || ${slash} ]]; then |
91 |
> + # Found, remove path components and |
92 |
> reiterate |
93 |
> + [[ ${prev} ]] && unset "path[prev]" |
94 |
> + unset "path[i]" |
95 |
> + continue 2 |
96 |
> + fi |
97 |
> + done |
98 |
> + # No (further) instance found, so we're done |
99 |
> + break |
100 |
> + done |
101 |
> + |
102 |
> + out="${slash}${path[*]}" |
103 |
> + echo "${out:-.}" |
104 |
> +} |
105 |
> + |
106 |
> +# @FUNCTION: dosym8 |
107 |
> +# @USAGE: [-r] <target> <link> |
108 |
> +# @DESCRIPTION: |
109 |
> +# Create a symbolic link <link>, pointing to <target>. If the |
110 |
> +# directory containing the new link does not exist, create it. |
111 |
> +# |
112 |
> +# If called with option -r, expand <target> relative to the apparent |
113 |
> +# path of the directory containing <link>. For example, "dosym8 -r |
114 |
> +# /bin/foo /usr/bin/foo" will create a link named "../../bin/foo". |
115 |
> +dosym8() { |
116 |
> + local option_r |
117 |
> + |
118 |
> + case $1 in |
119 |
> + -r) option_r=t; shift ;; |
120 |
> + esac |
121 |
> + |
122 |
> + [[ $# -eq 2 ]] || die "${FUNCNAME}: bad number of arguments" |
123 |
> + |
124 |
> + local target=$1 link=$2 |
125 |
> + |
126 |
> + if [[ ${option_r} ]]; then |
127 |
> + local linkdir comp |
128 |
> + |
129 |
> + # Expansion makes sense only for an absolute target path |
130 |
> + [[ ${target} == /* ]] \ |
131 |
> + || die "${FUNCNAME}: -r specified but no absolute |
132 |
> target path" |
133 |
> + |
134 |
> + target=$(_dosym8_canonicalize "${target}") |
135 |
> + linkdir=$(_dosym8_canonicalize "/${link#/}") |
136 |
> + linkdir=${linkdir%/*} # poor man's dirname(1) |
137 |
> + linkdir=${linkdir:-/} # always keep the initial "/" |
138 |
> + |
139 |
> + local ifs_save=${IFS-$' \t\n'} IFS=/ |
140 |
> + for comp in ${linkdir}; do |
141 |
> + if [[ ${target%%/*} == "${comp}" ]]; then |
142 |
> + target=${target#"${comp}"} |
143 |
> + target=${target#/} |
144 |
> + else |
145 |
> + target=..${target:+/}${target} |
146 |
> + fi |
147 |
> + done |
148 |
> + IFS=${ifs_save} |
149 |
> + target=${target:-.} |
150 |
> + fi |
151 |
> + |
152 |
> + dosym "${target}" "${link}" |
153 |
> +} |
154 |
> -- |
155 |
> 2.29.2 |
156 |
> |
157 |
> |
158 |
> |