Initial checkin.
[bpt/emacs.git] / admin / quick-install-emacs
1 #!/bin/sh
2 # quick-install-emacs -- do a halfway-decent job of installing emacs quickly
3 # Written by Miles Bader <miles@gnu.org>
4
5 # This script is mainly intended for emacs maintainer or pretesters who
6 # install emacs very often. See the --help output for more details.
7
8 PUBLIC_LIBSRC_BINARIES='b2m emacsclient etags ctags ebrowse'
9 PUBLIC_LIBSRC_SCRIPTS='grep-changelog rcs-checkin'
10
11 AVOID="CVS -DIC README COPYING ChangeLog ~ Makefile makefile stamp-subdir .cvsignore \.[cho]$ make-docfile testfile test-distrib"
12
13 # Prune old binaries lying around in the source tree
14 PRUNE=no
15 # Re-install files even if they already exist
16 FORCE=no
17 # Command verbose flag
18 VERBOSE=''
19
20 me="`basename $0`"
21
22 # Install commands (these commands are also expected to understand the
23 # GNU -v (--verbose) option)
24 LINK='cp -lf'
25 COPY='cp -f'
26 REMOVE='rm -r'
27
28 # Used to execute commands once once we create them
29 EXEC='sh'
30 MKDIR='mkdir --verbose -p'
31
32 NAWK=/usr/bin/nawk
33
34 # Some messages
35 USAGE="Usage: $me [OPTION...] BUILD_TREE [PREFIX]"
36 TRY="Try "\`"$me --help' for more information."
37
38 # Parse command-line options
39 while :; do
40 case "$1" in
41 -n|--dry-run)
42 EXEC=cat; shift;;
43 -p|--prune)
44 PRUNE=yes; shift;;
45 -P|--no-prune)
46 PRUNE=no; shift;;
47 --prune-only)
48 PRUNE=only; shift;;
49 -f|--force)
50 FORCE=yes; shift;;
51 -v|--verbose)
52 VERBOSE="-v"; shift;;
53 --help)
54 cat <<EOF
55 $USAGE
56 Install emacs quickly
57
58 -n, --dry-run print installation commands instead of
59 executing them
60
61 -f, --force install even files that haven't changed
62 -v, --verbose print messages describing what is done
63
64 -p, --prune prune old generated files
65 -P, --no-prune don't prune old generated files (default)
66 --prune-only prune old generated files, but don't install
67
68 --help display this help and exit
69 --version output version information and exit
70
71 $me install emacs \`incrementally,' that is, it will
72 install only those files that have changed since the last time it was
73 invoked, and remove any obsolete files from the installation
74 directories. It also uses hard-links into the source and build trees to
75 do the install, so it uses much less space than the default Makefile
76 install target; however, this also means that $me can
77 not install onto a disk partition other than the one on which the source
78 and build directories reside.
79
80 Optionally, $me can also remove old versions of
81 automatically generated files that are version-specific (such as the
82 versioned emacs executables in the \`src' directory, and the DOC-* files
83 in the \`etc' directory). The latter action is called \`pruning,' and
84 can be enabled using the \`-p' or \`--prune' options.
85 EOF
86 exit 0
87 ;;
88 --version)
89 cat <<EOF
90 $me 1.5
91
92 Written by Miles Bader <miles@gnu.org>
93 EOF
94 exit 0
95 ;;
96 -[^-]?*)
97 # split concatenated single-letter options apart
98 FIRST="$1"; shift
99 set -- `echo $FIRST | sed 's/-\(.\)\(.*\)/-\1 -\2/'` "$@"
100 ;;
101 -*)
102 echo 1>&2 "$me: unrecognized option "\`"$1'"
103 echo 1>&2 "$TRY"
104 exit 1
105 ;;
106 *)
107 break;
108 esac
109 done
110
111 LINK_CMD="$LINK $VERBOSE"
112 REMOVE_CMD="$REMOVE $VERBOSE"
113
114 case $# in
115 1) BUILD="$1";;
116 2) BUILD="$1"; prefix="$2";;
117 *)
118 echo 1>&2 "$USAGE"
119 echo 1>&2 "$TRY"
120 exit 1
121 ;;
122 esac
123
124 if test ! -d "$BUILD"; then
125 echo 1>&2 "$me: $BUILD: Build tree not found"
126 exit 2
127 elif test ! -r "$BUILD/config.status"; then
128 echo 1>&2 "$me: $BUILD: Not a proper build tree, config.status not found"
129 exit 2
130 fi
131
132 CONFIG_STATUS="$BUILD/config.status"
133 function get_config_var () {
134 if ! $NAWK -F% '$2 == "@'$1'@" { print $3; ok=1; exit; }; END { exit(!ok); }' $CONFIG_STATUS
135 then
136 echo 1>&2 "$me: $1: Configuration variable not found in $CONFIG_STATUS"
137 exit 4
138 fi
139 }
140
141 test x"$SRC" = x && SRC="`get_config_var srcdir`"
142 test x"$prefix" = x && prefix="`get_config_var prefix`"
143 test x"$VERSION" = x && VERSION="`get_config_var version`"
144 test x"$ARCH" = x && ARCH="`get_config_var host`"
145
146 DST_SHARE="$prefix/share/emacs/$VERSION"
147 DST_BIN="$prefix/bin"
148 DST_LIBEXEC="$prefix/libexec/emacs/$VERSION/$ARCH"
149 DST_INFO="$prefix/info"
150
151 function maybe_mkdir () {
152 if ! test -d "$1"; then
153 $MKDIR "$1" 2>&1 | sed "s/^mkdir:/$me:/" 1>&2
154 fi
155 }
156
157 maybe_mkdir "$DST_BIN"
158 maybe_mkdir "$DST_SHARE"
159 maybe_mkdir "$DST_SHARE/site-lisp"
160 maybe_mkdir "$DST_LIBEXEC"
161 maybe_mkdir "$DST_INFO"
162
163 ( # start of command-generating sub-shell
164
165 PRUNED=""
166 if test x"$PRUNE" != xno; then
167 for D in `ls -1t $BUILD/etc/DOC-* | tail +2`; do
168 echo $REMOVE_CMD $D
169 PRUNED="$PRUNED $D"
170 done
171 for D in `ls -1t $BUILD/src/emacs-$VERSION.* | tail +2`; do
172 echo $REMOVE_CMD $D
173 PRUNED="$PRUNED $D"
174 done
175 for D in `ls -1t $BUILD/lib-src/fns-* | tail +2`; do
176 echo $REMOVE_CMD $D
177 PRUNED="$PRUNED $D"
178 done
179 fi
180
181 test x"$PRUNE" = xonly && exit 0
182
183 function maybe_emit_copy () {
184 if test "$FORCE" = yes || ! cmp -s $1 $2; then
185 echo $LINK_CMD $1 $2
186 fi
187 }
188
189 maybe_emit_copy $BUILD/src/emacs $DST_BIN/emacs
190 maybe_emit_copy $BUILD/src/emacs $DST_BIN/emacs-$VERSION
191
192 for F in $PUBLIC_LIBSRC_BINARIES; do
193 maybe_emit_copy $BUILD/lib-src/$F $DST_BIN/$F
194 done
195 for F in $PUBLIC_LIBSRC_SCRIPTS; do
196 maybe_emit_copy $SRC/lib-src/$F $DST_BIN/$F
197 done
198
199 if test x"$SRC" = x"$BUILD"; then
200 PFXS="$BUILD"
201 else
202 PFXS="$SRC $BUILD"
203 fi
204
205 for SUBDIR in lisp leim etc lib-src info; do
206 # defaults
207 SHARED=no
208 FORCED=''
209 AVOID_PAT="`echo "($AVOID)" | tr ' ' '|'`"
210
211 # Set subdir-specific values
212 case $SUBDIR in
213 lisp|leim)
214 DST="$DST_SHARE/$SUBDIR"
215 ;;
216 etc)
217 DST="$DST_SHARE/$SUBDIR"
218 # COPYING is in the avoid list, but there should be a copy of it in
219 # the install etc dir, so make that here.
220 FORCED="$DST/COPYING"
221 ;;
222 lib-src)
223 DST="$DST_LIBEXEC"
224 AVOID_PAT="`echo "($AVOID ($PUBLIC_LIBSRC_BINARIES $PUBLIC_LIBSRC_SCRIPTS)\$)" | tr ' ' '|'`"
225 ;;
226 info)
227 DST="$DST_INFO"
228 SHARED=yes
229 ;;
230 esac
231
232 for PFX in $PFXS; do
233 if [ -d $PFX/$SUBDIR ]; then
234 for DIR in `(cd $PFX/$SUBDIR; find . -type d -print | sed 's@^./@@')`; do
235 if [ -d $DST/$DIR ]; then
236 echo Directory $DST/$DIR exists
237 else
238 echo Directory $DST/$DIR non-existant
239 if [ "`echo $DIR | egrep -v "$AVOID_PAT"`" ]; then
240 maybe_mkdir $DST/$DIR
241 fi
242 fi
243 done
244 diff -sqr $PFX/$SUBDIR $DST
245 fi
246 done | $NAWK '
247 BEGIN {
248 src_pat = "^'"$SRC"'/'"$SUBDIR"'/"
249 build_pat = "^'"$BUILD"'/'"$SUBDIR"'/"
250 dst_pat = "^'"$DST"'/"
251 dst_pfx = "'"$DST"'/"
252 avoid_pat = "'"$AVOID_PAT"'"
253 force = ("'"$FORCE"'" == "yes")
254 shared = ("'"$SHARED"'" == "yes")
255 init_bool_array(pruned, "'"$PRUNED"'")
256 init_bool_array(forced, "'"$FORCED"'")
257 }
258 function init_bool_array(array, string, a,k)
259 {
260 split (string, a)
261 for (k in a)
262 array[a[k]] = 1
263 }
264 function install(src, dst)
265 {
266 if (! (src in pruned)) {
267 cp[src] = dst;
268 from[dst] = src;
269 delete rm[dst];
270 }
271 }
272 function update(src, dst, copy)
273 {
274 if (src in pruned) {
275 rm[dst] = 1;
276 delete from[dst]
277 } else {
278 if (copy)
279 cp[src] = dst;
280 from[dst] = src;
281 delete rm[dst];
282 }
283 }
284 function uninstall(dst)
285 {
286 if (!(dst in from))
287 rm[dst] = 1;
288 }
289 /^Directory / {
290 if ($2 ~ avoid_pat) {
291 if ($NF == "exists")
292 uninstall($2)
293 } else
294 update(0, $2, 0)
295 next
296 }
297 /^Files / {
298 if ($4 ~ avoid_pat && !($4 in forced))
299 uninstall($4)
300 else if ($NF == "identical")
301 update($2, $4, force)
302 else
303 update($2, $4, 1)
304 next
305 }
306 /^Only / {
307 pfx = $3
308 sub (/:$/, "/", pfx)
309
310 if (pfx ~ dst_pat) {
311 if (! shared)
312 uninstall(pfx $4)
313 } else {
314 subdir = pfx
315 if (subdir ~ src_pat)
316 sub (src_pat, "", subdir)
317 else
318 sub (build_pat, "", subdir)
319
320 dst = dst_pfx subdir $4
321 if (! (dst ~ avoid_pat))
322 install(pfx $4, dst)
323 }
324 next
325 }
326 END {
327 for (f in rm)
328 print "'"$REMOVE_CMD"' " f
329 for (f in cp)
330 print "'"$LINK_CMD"' " f " " cp[f]
331 }
332 '
333 done
334
335 ) | eval $EXEC