#!/usr/bin/env python # -*- coding: utf-8 -*- # Runs the daily build of the Python docs on dinsdale.python.org. # # Usages: # # dailybuild.py [-q] # # without any arguments builds docs for all branches configured in the global # BRANCHES value. -q selects "quick build", which means to build only HTML. # # dailybuild.py [-q] [-d] # # builds one version, where is an SVN checkout directory of the # Python branch to build docs for, and is the directory where the # result should be placed. If -d is given, the docs are built even if the # branch is in development mode (i.e. version contains a, b or c). # # This script is not run from the checkout, so if you want to change how the # daily build is run, you must replace it on dinsdale. This is necessary, for # example, after the release of a new minor version. # # 03/2010, Georg Brandl import os import sys import getopt BUILDROOT = '/home/gbrandl/docbuild' SPHINXBUILD = os.path.join(BUILDROOT, 'sphinx-env/bin/sphinx-build') WWWROOT = '/data/ftp.python.org/pub/docs.python.org' BRANCHES = [ # checkout, target, isdev (BUILDROOT + '/python34', WWWROOT + '/3.4', False), (BUILDROOT + '/python35', WWWROOT + '/3.5', True), (BUILDROOT + '/python27', WWWROOT + '/2.7', False), ] def _files_changed(old, new): with open(old, 'rb') as fp1, open(new, 'rb') as fp2: st1 = os.fstat(fp1.fileno()) st2 = os.fstat(fp2.fileno()) if st1.st_size != st2.st_size: return False if st1.st_mtime >= st2.st_mtime: return True while True: one = fp1.read(4096) two = fp2.read(4096) if one != two: return False if one == '': break return True def build_one(checkout, target, isdev, quick): print 'Doc autobuild started in %s' % checkout os.chdir(checkout) print 'Running hg pull --update' os.system('hg pull --update') print 'Running make autobuild' maketarget = 'autobuild-' + ('html' if quick else ('dev' if isdev else 'stable')) if os.WEXITSTATUS(os.system('cd Doc; make SPHINXBUILD=%s %s' % (SPHINXBUILD, maketarget))) == 2: print '*' * 80 return print('Computing changed files') changed = [] for dirpath, dirnames, filenames in os.walk('Doc/build/html/'): dir_rel = dirpath[len('Doc/build/html/'):] for fn in filenames: local_path = os.path.join(dirpath, fn) rel_path = os.path.join(dir_rel, fn) target_path = os.path.join(target, rel_path) if (os.path.exists(target_path) and not _files_changed(target_path, local_path)): changed.append(rel_path) print 'Copying HTML files to %s' % target os.system('cp -a Doc/build/html/* %s' % target) if not quick: print 'Copying dist files' os.system('mkdir -p %s/archives' % target) os.system('cp -a Doc/dist/* %s/archives' % target) changed.append('archives/') for fn in os.listdir(os.path.join(target, 'archives')): changed.append('archives/' + fn) print '%s files changed' % len(changed) if changed: target_ino = os.stat(target).st_ino targets_dir = os.path.dirname(target) prefixes = [] for fn in os.listdir(targets_dir): if os.stat(os.path.join(targets_dir, fn)).st_ino == target_ino: prefixes.append(fn) to_purge = [] for prefix in prefixes: to_purge.extend(prefix + "/" + p for p in changed) purge_cmd = 'curl -X PURGE "https://docs.python.org/{%s}"' % ','.join(to_purge) print("Running CDN purge") os.system(purge_cmd) print 'Finished' print '=' * 80 def usage(): print 'Usage:' print ' %s' % sys.argv[0] print 'or' print ' %s [-d] ' % sys.argv[0] sys.exit(1) if __name__ == '__main__': try: opts, args = getopt.getopt(sys.argv[1:], 'dq') except getopt.error: usage() quick = devel = False for opt, _ in opts: if opt == '-q': quick = True if opt == '-d': devel = True if devel and not args: usage() if args: if len(args) != 2: usage() build_one(os.path.abspath(args[0]), os.path.abspath(args[1]), devel, quick) else: for checkout, dest, devel in BRANCHES: build_one(checkout, dest, devel, quick)