Zine

open source content publishing system


source: scripts/create-package @ 1279:088d2f519391

Revision 1279:088d2f519391, 5.2 KB checked in by Georg Brandl <georg@…>, 2 years ago (diff)

Update copyright notices.

  • Property exe set to *
Line 
1#!/usr/bin/env python
2"""
3    Create Package
4    ~~~~~~~~~~~~~~
5
6    This script dumps Zine with all files required files into a .tar.gz
7    and .zip archive for distribution.
8
9    :copyright: (c) 2010 by the Zine Team, see AUTHORS for more details.
10    :license: BSD, see LICENSE for more details.
11"""
12import re
13import os
14import sys
15import shutil
16import tempfile
17import subprocess
18from optparse import OptionParser
19
20
21IGNORED = map(re.compile, r'''
22^artwork/
23^\.hgignore$
24'''.strip().splitlines())
25
26EXTRA_RST = 'README INSTALL'.split()
27
28_documented_plugin_re = re.compile(r'^zine/plugins/([^/]+)/docs/')
29
30
31def is_ignored(filename):
32    for rule in IGNORED:
33        if rule.search(filename):
34            return True
35    return False
36
37
38class BuildError(Exception):
39    pass
40
41
42def find_files(force):
43    allowed_states = frozenset('CI?')
44    tracked_states = frozenset('CM')
45    client = subprocess.Popen(['hg', 'status', '-A'], stdout=subprocess.PIPE)
46    for line in client.communicate()[0].splitlines():
47        line = line.split(None, 1)
48        if len(line) != 2:
49            continue
50        status, filename = line
51        if not force and status not in allowed_states:
52            raise BuildError('hg unclean. Uncommited modifications?')
53        if status in tracked_states and not is_ignored(filename):
54            yield filename
55
56
57def get_zine_version():
58    from zine import __version__ as rv
59    return rv
60
61
62def run_script(dir, script, args=None):
63    subprocess.call([os.path.join(dir, 'scripts', script)] + list(args or ()))
64
65
66def delete_pycs(folder):
67    for dirname, folders, files in os.walk(folder):
68        for filename in files:
69            if filename.endswith('.pyc'):
70                filename = os.path.join(folder, dirname, filename)
71                os.remove(filename)
72
73
74def build(dst_dir, build_dir, options):
75    zine_version = get_zine_version()
76    release_name = 'Zine-%s' % '-'.join(zine_version.split())
77    archive_base = os.path.join(dst_dir, release_name)
78
79    # create a subfolder for this release
80    release_dir = os.path.join(build_dir, release_name)
81    os.mkdir(release_dir)
82
83    documented_plugins = set()
84
85    # copy all tracked files into the build dir
86    print 'Bootstrapping build directory [%s]' % build_dir
87    for filename in find_files(options.force):
88        target_folder = os.path.join(release_dir, os.path.dirname(filename))
89        if not os.path.exists(target_folder):
90            os.makedirs(target_folder)
91        shutil.copy(filename, target_folder)
92        print filename
93        match = _documented_plugin_re.match(filename)
94        if match is not None:
95            documented_plugins.add(match.group(1))
96
97    print 'The following plugins are documented:'
98    for plugin in sorted(documented_plugins):
99        print '  *', plugin
100
101    # build translations
102    run_script(release_dir, 'compile-translations')
103
104    # and the documentation for everything
105    run_script(release_dir, 'build-documentation')
106    for plugin in documented_plugins:
107        run_script(release_dir, 'build-documentation',
108                   [os.path.join(release_dir, 'zine', 'plugins', plugin)])
109
110    # build extra rst files into .html files
111    old_dir = os.getcwd()
112    try:
113        os.chdir(release_dir)
114        for filename in EXTRA_RST:
115            subprocess.call(['rst2html.py', filename, filename + '.html'])
116    finally:
117        os.chdir(old_dir)
118
119    # delete .pyc files the documentation builder might have created
120    delete_pycs(release_dir)
121
122    # now create the archives
123    messages = []
124    old_dir = os.getcwd()
125    try:
126        os.chdir(build_dir)
127        if options.tar:
128            tarball_filename = archive_base + '.tar.gz'
129            subprocess.call(['tar', 'vczf', tarball_filename, release_name])
130            messages.append('Created tarball in %s' % tarball_filename)
131        if options.zip:
132            zip_filename = archive_base + '.zip'
133            subprocess.call(['zip', '-r', zip_filename, release_name])
134            messages.append('Created zip file in %s' % zip_filename)
135    finally:
136        os.chdir(old_dir)
137
138    print '-' * 60
139    print 'Summary'
140    for message in messages:
141        print message
142
143
144def main():
145    parser = OptionParser(usage='%prog [options] destination')
146    parser.add_option('--no-zip', dest='zip', action='store_false',
147                      default=True, help='Do not generate a .zip file')
148    parser.add_option('--no-tar', dest='tar', action='store_false',
149                      default=True, help='Do not generate a tarball')
150    parser.add_option('-f', '--force', dest='force', action='store_true',
151                      default=False, help='Force build, even if local '
152                      'modifications exist.')
153    options, args = parser.parse_args()
154    if len(args) != 1:
155        parser.error('incorrect number of arguments')
156    dst = args[0]
157
158    if not os.path.exists(dst):
159        os.makedirs(dst)
160
161    try:
162        build_dir = tempfile.mkdtemp(prefix='zine')
163        try:
164            build(os.path.abspath(dst), build_dir, options)
165        finally:
166            shutil.rmtree(build_dir, ignore_errors=True)
167    except BuildError, e:
168        print >> sys.stderr, e
169
170
171if __name__ == '__main__':
172    base_dir = os.path.join(os.path.dirname(__file__), '..')
173    os.chdir(base_dir)
174    sys.path.insert(0, base_dir)
175    main()
Note: See TracBrowser for help on using the repository browser.