# Makefile for /var/www # Copyright Peter Maydell 09/1998 # # The primary purpose of this makefile is to keep this directory # and the public website on chiark in sync. # The directory $(MIRROR) is a place to keep timestamps which # are updated when the files are copied to chiark. # Unless the .tstamp file exists no copying will occur... # The secondary purpose is to see how clever we can be with Make # (is it Turing-complete, incidentally?) # Usage: # make FILE=filename add # marks the file for adding to the remote tree. It will be transferred # at the next 'make all'. NB: only files can be added; directories # will be added as required if you say 'make FILE=dir/dir/filename add' # make FILE=filename remove # removes the local copy of the file and marks it for deletion from # the remote tree at the next 'make all'. You can specify directories # here: they will be recursively deleted! Caution is recommended. # make FILE=filename nomirror # like remove, but doesn't delete the local copy of the file. # The file will not be mirrored in future. # make lint # run weblint on any *.html files being mirrored. # (Actually, there's a hack which means that excludes bookmarks.html...) # make FILE=filename lint # run weblint only on the specified file or files # make # make all # synchronise remote tree with local tree. This is the only command # that requires communication with the remote host. # make disablesync # causes 'make all' and 'make' to fail without syncing. This is # useful if you automatically run make when a PPP connection is # made, and want to temporarily disable this. # make enablesync # allow sync to work again # # NB: mixing add and remove on a single file without calling make all in # the middle might have odd effects(?) # This makefile is sufficiently complex that I don't guarantee that # it will work with anything other than GNU Make :-> # Improvements: perhaps rather than running ssh many times, we could # add commands to a script file and then # cat script | ssh 'cat >/tmp/script && chmod 755 /tmp/script && /tmp/script' # (this is no longer so vital now we don't repeat mkdir all the time) # Allow 'make help' to print a usage message # Make it easier to work with remote systems where we can't do mkdir -p # and rm -rf equivalents by having two versions of add/remove? ### configuration variables ### # name of the subdirectory used to hold timestamp files MIRROR := chiarkmirror # Args to pass to weblint. These are very pedantic indeed :-> WEBLINTARGS := -pedantic -e upper-case # Files not to bother weblinting. Netscape's bookmarks file is # never going to pass :-> DONTLINT := bookmarks.html taomarks.html # These three are only used by the ssh macros below RHOSTNAME := login.chiark.greenend.org.uk REMOTEHOST := pmaydell@$(RHOSTNAME) REMOTEDIR := public-html # These variables define how to talk to the remote system. # Here are settings for using ssh/scp: # (you can say SSHPROTO=-1 if you need to) # Start the connection; nothing needed here for ssh RSTARTUP=true # Ensure that the directory hierarchy $* exists: RADDDIR=ssh $(SSHPROTO) $(REMOTEHOST) 'mkdir -p $(REMOTEDIR)/$*' # Ensure that $* (may be file or directory tree) is removed: RRMTREE=ssh $(SSHPROTO) $(REMOTEHOST) 'rm -rf $(REMOTEDIR)/$*' # Copy $< to the remote system: RCPFILE=scp $(SSHPROTO) $< $(REMOTEHOST):$(REMOTEDIR)/$< # Check that we can contact the remote system; must be a command # that returns true only if we can talk to the remote system. # If you don't have fping then just say 'RPING=true' to disable the test. # This is a 1-second timeout RPING=fping -t1000 -q $(RHOSTNAME) # Tidy up the connection and complete anything outstanding; no-op for ssh RSHUTDOWN=true #### end of configuration variables #### # We do some sanity checking on the user-specified goals. # add and remove may only be used as the single goal, and # if they are used then the user must set FILE. # We set ERROR and then the errorcheck target succeeds or fails accordingly. ifneq (,$(filter add,$(MAKECMDGOALS))) # add is a goal: must be only one, FILE must be set ifndef FILE ERROR="FILE not given: use 'make FILE=filename add'" endif ifneq ($(MAKECMDGOALS),add) ERROR="add must be the only goal specified" endif endif ifneq (,$(filter remove,$(MAKECMDGOALS))) # remove is a goal: must be only one, FILE must be set ifndef FILE ERROR="FILE not given: use 'make FILE=filename remove'" endif ifneq ($(MAKECMDGOALS),remove) ERROR="remove must be the only goal specified" endif endif # Set TSTAMPS to a list of all the .tstamp files in the mirror directory # and HTMLFILES to a list of .html files to be weblinted. TSTAMPS := $(shell find $(MIRROR) -name '*.tstamp') HTMLFILES := $(filter $(MIRROR)/%.html.tstamp, $(TSTAMPS)) HTMLFILES := $(patsubst $(MIRROR)/%.html.tstamp,%.html,$(HTMLFILES)) # Remove the files on the excludes-list: HTMLFILES := $(filter-out $(DONTLINT), $(HTMLFILES)) # RMSTAMPS is a list of files/dirs to be deleted from the remote site RMSTAMPS := $(shell find $(MIRROR) -name '*.remove') # ADDSTAMPS is a list of directories to be created on the remote site ADDSTAMPS := $(shell find $(MIRROR) -name '.add') .PHONY: all lint add remove nomirror rmlocal errorcheck synccheck startup shutdown # all target requires remote link to be up. First we create any new # directories, then we mirror the files, then we delete any files that # are to be removed. all: errorcheck synccheck startup $(ADDSTAMPS) $(TSTAMPS) $(RMSTAMPS) shutdown # To make a $(MIRROR)/foobar.tstamp file (which depends on foobar) # we scp foobar to chiark's public-html directory and # touch $(MIRROR)/foobar.tstamp. $(TSTAMPS) : $(MIRROR)/%.tstamp : % $(RCPFILE) && touch $@ # To handle a $(MIRROR)/foobar.remove file we need to # ssh $(REMOTEHOST) 'rm -rf $(REMOTEDIR)/file' # and then remove the .remove file from the mirrordir. # The errorcheck dependency means the commands are always run. $(RMSTAMPS) : $(MIRROR)/%.remove : errorcheck $(RRMTREE) rm $@ # Handle $(MIRROR)/dir/dir/.add by ensuring that # the directories exist and deleting the .add file. # Actual file transfer will be done by the TSTAMP rule. $(ADDSTAMPS) : $(MIRROR)/%.add : errorcheck $(RADDDIR) rm $@ # run weblint on all the .html files lint: errorcheck ifdef FILE weblint $(WEBLINTARGS) $(FILE) else weblint $(WEBLINTARGS) $(HTMLFILES) endif # Idea about how to handle removing files: have a target remove # such that saying 'make remove index.html' does: # * rm -rf index.html # * if [ -f $(MIRROR).index.html.tstamp ]; then # rm $(MIRROR)/index.html.tstamp; else # rm -rf $(MIRROR)/index.html; fi # (this is so that we can say 'make remove directory' too) # * touch $(MIRROR)/index.html.remove # And then have the all target look for $(MIRROR)/*.remove # files, and do a ssh REMOTEHOST 'rm -rf $REMOTEDIR/file' # and then remove the .remove file so that we don't do it again next time... # To remove a file, remove from mirror site and then delete the local copy remove: errorcheck nomirror rmlocal # don't mirror this file/directory in future. Deletes remote copy. nomirror: errorcheck # remove file/dir from the mirror directory if [ -f $(MIRROR)/$(FILE).tstamp ]; then \ rm $(MIRROR)/$(FILE).tstamp; \ else rm -rf $(MIRROR)/$(FILE); fi touch $(MIRROR)/$(FILE).remove # Just remove the local copy of the file/directory. Succeeds even if it # doesn't exist, so we can do things like: # mv foo bar; make FILE=foo remove; make FILE=bar add rmlocal: errorcheck rm -rf $(FILE) # Similarly we allow 'make add dir/dir/index.html' which will # * create directories if required # * touch dir/dir/file.tstamp and file # * touch dir/dir/.add # and make the all target do a mkdir -p on the remote system for # every .add file in $(MIRROR), and then remove the .add files add: errorcheck mkdir -p $(dir $(FILE)) mkdir -p $(MIRROR)/$(dir $(FILE)) touch $(MIRROR)/$(dir $(FILE)).add # We could improve efficiency by deleting here .add files # for any parent directories of $(dir $(FILE)), since we'll # effectively do a mkdir -p anyway. # # Note that the tstamp must be older in case the user # has already created the file before doing the make add... touch -d '1 Jan 1971' $(MIRROR)/$(FILE).tstamp touch $(FILE) # Simple rules to allow us to turn the upload on/off disablesync: touch $(MIRROR)/.nosync enablesync: rm -f $(MIRROR)/.nosync #Trivial startup/shutdown rules startup: $(RSTARTUP) shutdown: $(RSHUTDOWN) # This rule checks to see if we should be trying to sync the # remote system or not. It fails with an appropriate error if not. synccheck: @if [ -e $(MIRROR)/.nosync ]; then echo 'Sync disabled'; false; fi @if $(RPING); then echo 'Remote host is alive'; else echo 'ERROR: Remote host unreachable'; false; fi # This rule checks to see if some conditional has set ERROR. If so # it prints the message and causes make to stop (because false will # always 'fail'). -k defeats this, of course. # Unfortunately I can't see how to get make to always do the errorcheck # target first, so it has to be listed as a dependency of add/all/lint/etc. errorcheck: ifdef ERROR @echo ERROR: $(ERROR) @false else @true endif