#!/usr/bin/env bash ### update_autogen - update some auto-generated files in the Emacs tree ## Copyright (C) 2011-2017 Free Software Foundation, Inc. ## Author: Glenn Morris ## This file is part of GNU Emacs. ## GNU Emacs is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## GNU Emacs is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## You should have received a copy of the GNU General Public License ## along with GNU Emacs. If not, see . ### Commentary: ## This is a helper script to update some generated files in the Emacs ## repository. This is suitable for running from cron. ## Only Emacs maintainers need use this, so it uses bash features. ## ## By default, it updates the versioned loaddefs-like files in lisp, ## except ldefs-boot.el. ### Code: die () # write error to stderr and exit { [ $# -gt 0 ] && echo "$PN: $@" >&2 exit 1 } PN=${0##*/} # basename of script PD=${0%/*} [ "$PD" = "$0" ] && PD=. # if PATH includes PWD ## This should be the admin directory. cd $PD cd ../ [ -d admin ] || die "Could not locate admin directory" if [ -d .bzr ]; then vcs=bzr elif [ -e .git ]; then vcs=git else die "Cannot determine vcs" fi usage () { cat 1>&2 < /dev/null" EXIT while getopts ":hcfqA:HCIL" option ; do case $option in (h) usage ;; (c) commit=1 ;; (f) force=1 ;; (q) quiet=1 ;; (A) autogendir=$OPTARG [ -d "$autogendir" ] || die "No autogen directory: $autogendir" ;; (C) clean=1 ;; (H) changelog_flag=1 ;; (I) info_flag=1 ;; (L) lboot_flag=1 ;; (\?) die "Bad option -$OPTARG" ;; (:) die "Option -$OPTARG requires an argument" ;; (*) die "getopts error" ;; esac done shift $(( --OPTIND )) OPTIND=1 ## Does not work 100% because a lot of Emacs batch output comes on stderr (?). [ "$quiet" ] && exec 1> /dev/null ## Run status on inputs, list modified files on stdout. status () { local statflag="-S" [ "$vcs" = "git" ] && statflag="-s" $vcs status $statflag "$@" >| $tempfile || die "$vcs status error for $@" local stat file modified while read stat file; do [ "$stat" != "M" ] && \ die "Unexpected status ($stat) for generated $file" modified="$modified $file" done < $tempfile echo "$modified" return 0 } # function status echo "Checking input file status..." ## The lisp portion could be more permissive, eg only care about .el files. modified=$(status ${autogendir:+$sources} ${ldefs_flag:+lisp} ${info_flag:+doc}) || die [ "$modified" ] && { echo "Locally modified: $modified" [ "$force" ] || die "There are local modifications" } ## Probably this is overkill, and there's no need to "bootstrap" just ## for making autoloads. [ "$clean" ] && { echo "Running 'make maintainer-clean'..." make maintainer-clean #|| die "Cleaning error" rm -f $ldefs_in } echo "Running autoreconf..." autoreconf ${clean:+-f} -i -I m4 2>| $tempfile retval=$? ## Annoyingly, autoreconf puts the "installing `./foo' messages on stderr. if [ "$quiet" ]; then grep -v 'installing `\.' $tempfile 1>&2 else cat "$tempfile" 1>&2 fi [ $retval -ne 0 ] && die "autoreconf error" ## Uses global $commit. commit () { local type=$1 shift [ $# -gt 0 ] || { echo "No files were modified" return 0 } echo "Modified file(s): $@" [ "$commit" ] || return 0 echo "Committing..." $vcs commit -m "; Auto-commit of $type files." "$@" || return $? [ "$vcs" = "git" ] && { $vcs push || return $? } echo "Committed files: $@" } # function commit ## No longer used since info/dir is now generated at install time if needed, ## and is not in the repository any more. info_dir () { local basefile=build-aux/dir_top outfile=info/dir echo "Regenerating info/dir..." ## Header contains non-printing characters, so this is more ## reliable than using echo. rm -f $outfile cp $basefile $outfile local topic file dircat dirent ## FIXME inefficient looping. for topic in "Texinfo documentation system" "Emacs" "GNU Emacs Lisp" \ "Emacs editing modes" "Emacs network features" "Emacs misc features" \ "Emacs lisp libraries"; do cat - <> $outfile $topic EOF ## Bit faster than doc/*/*.texi. for file in doc/emacs/emacs.texi doc/lispintro/*.texi \ doc/lispref/elisp.texi doc/misc/*.texi; do ## FIXME do not ignore w32 if OS is w32. case $file in *-xtra.texi|*efaq-w32.texi) continue ;; esac dircat=$(sed -n -e 's/@value{emacsname}/Emacs/' -e 's/^@dircategory //p' $file) ## TODO warn about unknown topics (check-info in top-level ## Makefile does this). [ "$dircat" = "$topic" ] || continue sed -n -e 's/@value{emacsname}/Emacs/' \ -e 's/@acronym{\([A-Z]*\)}/\1/' \ -e '/^@direntry/,/^@end direntry/ s/^\([^@]\)/\1/p' \ $file >> $outfile done done local modified modified=$(status $outfile) || die commit "info/dir" $modified || die "commit error" } # function info_dir [ "$autogendir" ] && { oldpwd=$PWD cp $genfiles $autogendir/ cd $autogendir || die "cd error for $autogendir" echo "Checking status of generated files..." modified=$(status $basegen) || die commit "generated" $modified || die "commit error" exit 0 } # $autogendir [ "$info_flag" ] && info_dir [ "$ldefs_flag" ] || exit 0 echo "Finding loaddef targets..." find lisp -name '*.el' -exec grep '^;.*generated-autoload-file:' {} + | \ sed -e '/loaddefs\|esh-groups/d' -e 's|/[^/]*: "|/|' -e 's/"//g' \ >| $tempfile || die "Error finding targets" genfiles= while read genfile; do ## Or we can just use sort -u when making tempfile... case " $genfiles " in *" $genfile "*) continue ;; esac [ -r $genfile ] || die "Unable to read $genfile" genfiles="$genfiles $genfile" done < $tempfile [ "$genfiles" ] || die "Error setting genfiles" [ -e Makefile ] || { echo "Running ./configure..." ## Minimize required packages. ./configure --without-x || die "configure error" } ## Build the minimum needed to get the autoloads. echo "Running lib/ make..." make -C lib "$@" all || die "make lib error" echo "Running src/ make..." make -C src "$@" bootstrap-emacs || die "make src error" echo "Running lisp/ make..." make -C lisp "$@" autoloads EMACS=../src/bootstrap-emacs || die "make src error" ## Ignore comment differences. [ ! "$lboot_flag" ] || \ diff -q -I '^;' $ldefs_in $ldefs_out || \ cp $ldefs_in $ldefs_out || die "cp ldefs_boot error" echo "Checking status of loaddef files..." ## It probably would be fine to just check+commit lisp/, since ## making autoloads should not effect any other files. But better ## safe than sorry. modified=$(status $genfiles $ldefs_out) || die commit "loaddefs" $modified || die "commit error" ## Less important than the other stuff, so do it last. [ ! "$changelog_flag" ] || { make change-history-nocommit || die "make change-history error" modified=$(status $changelog_files) || die commit "ChangeLog" $modified || die "commit error" } exit 0 ### update_autogen ends here