File: pg-release.py

package info (click to toggle)
python-pyqtgraph 0.13.7-5
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 8,068 kB
  • sloc: python: 54,043; makefile: 129; ansic: 40; sh: 2
file content (256 lines) | stat: -rw-r--r-- 8,955 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
#!/usr/bin/python
import os, sys, argparse, random
from shell import shell, ssh



description="Build release packages for pyqtgraph."

epilog = """
Package build is done in several steps:

    * Attempt to clone branch release-x.y.z from source-repo
    * Merge release branch into master
    * Write new version numbers into the source
    * Roll over unreleased CHANGELOG entries
    * Commit and tag new release
    * Build HTML documentation
    * Build source package
    * Build deb packages (if running on Linux)
    * Build Windows exe installers

Release packages may be published by using the --publish flag:

    * Uploads release files to website
    * Pushes tagged git commit to github
    * Uploads source package to pypi

Building source packages requires:

    * 
    * 
    * python-sphinx

Building deb packages requires several dependencies:

    * build-essential
    * python-all, python3-all
    * python-stdeb, python3-stdeb
    
Note: building windows .exe files should be possible on any OS. However, 
Debian/Ubuntu systems do not include the necessary wininst*.exe files; these
must be manually copied from the Python source to the distutils/command 
submodule path (/usr/lib/pythonX.X/distutils/command). Additionally, it may be
necessary to rename (or copy / link) wininst-9.0-amd64.exe to 
wininst-6.0-amd64.exe.

"""

path = os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))
build_dir = os.path.join(path, 'release-build')
pkg_dir = os.path.join(path, 'release-packages')

ap = argparse.ArgumentParser(description=description, epilog=epilog, formatter_class=argparse.RawDescriptionHelpFormatter)
ap.add_argument('version', help='The x.y.z version to generate release packages for. '
                                'There must be a corresponding pyqtgraph-x.y.z branch in the source repository.')
ap.add_argument('--publish', metavar='', help='Publish previously built package files (must be stored in pkg-dir/version) and tagged release commit (from build-dir).', action='store_const', const=True, default=False)
ap.add_argument('--source-repo', metavar='', help='Repository from which release and master branches will be cloned. Default is the repo containing this script.', default=path)
ap.add_argument('--build-dir', metavar='', help='Directory where packages will be staged and built. Default is source_root/release-build.', default=build_dir)
ap.add_argument('--pkg-dir', metavar='', help='Directory where packages will be stored. Default is source_root/release-packages.', default=pkg_dir)
ap.add_argument('--skip-pip-test', metavar='', help='Skip testing pip install.', action='store_const', const=True, default=False)
ap.add_argument('--no-deb', metavar='', help='Skip building Debian packages.', action='store_const', const=True, default=False)
ap.add_argument('--no-exe', metavar='', help='Skip building Windows exe installers.', action='store_const', const=True, default=False)



def build(args):
    if os.path.exists(args.build_dir):
        sys.stderr.write("Please remove the build directory %s before proceeding, or specify a different path with --build-dir.\n" % args.build_dir)
        sys.exit(-1)
    if os.path.exists(args.pkg_dir):
        sys.stderr.write("Please remove the package directory %s before proceeding, or specify a different path with --pkg-dir.\n" % args.pkg_dir)
        sys.exit(-1)
        
    # Clone source repository and tag the release branch
    shell('''
        # Clone and merge release branch into previous master
        mkdir -p {build_dir}
        cd {build_dir}
        rm -rf pyqtgraph
        git clone --depth 1 --branch master --single-branch {source_repo} pyqtgraph
        cd pyqtgraph
        git checkout -b release-{version}
        git pull {source_repo} release-{version}
        git checkout master
        git merge --no-ff --no-commit release-{version}
        
        # Write new version number into the source
        sed -i "s/__version__ = .*/__version__ = '{version}'/" pyqtgraph/__init__.py
        sed -i "s/version = .*/version = '{version}'/" doc/source/conf.py
        sed -i "s/release = .*/release = '{version}'/" doc/source/conf.py
        
        # make sure changelog mentions unreleased changes
        grep "pyqtgraph-{version}.*unreleased.*" CHANGELOG    
        sed -i "s/pyqtgraph-{version}.*unreleased.*/pyqtgraph-{version}/" CHANGELOG

        # Commit and tag new release
        git commit -a -m "PyQtGraph release {version}"
        git tag pyqtgraph-{version}

        # Build HTML documentation
        cd doc
            make clean
            make html
        cd ..
        find ./ -name "*.pyc" -delete

        # package source distribution
        python setup.py sdist

        mkdir -p {pkg_dir}
        cp dist/*.tar.gz {pkg_dir}

        # source package build complete.
    '''.format(**args.__dict__))

        
    if args.skip_pip_test:
        args.pip_test = 'skipped'
    else:
        shell('''
            # test pip install source distribution
            rm -rf release-{version}-virtenv
            virtualenv --system-site-packages release-{version}-virtenv
            . release-{version}-virtenv/bin/activate
            echo "PATH: $PATH"
            echo "ENV: $VIRTUAL_ENV" 
            pip install --no-index --no-deps dist/pyqtgraph-{version}.tar.gz
            deactivate
            
            # pip install test passed
        '''.format(**args.__dict__))
        args.pip_test = 'passed'


    if 'linux' in sys.platform and not args.no_deb: 
        shell('''
            # build deb packages
            cd {build_dir}/pyqtgraph
            python setup.py --command-packages=stdeb.command sdist_dsc
            cd deb_dist/pyqtgraph-{version}
            sed -i "s/^Depends:.*/Depends: python (>= 2.6), python-qt4 | python-pyside, python-numpy/" debian/control    
            dpkg-buildpackage
            cd ../../
            mv deb_dist {pkg_dir}/pyqtgraph-{version}-deb
            
            # deb package build complete.
        '''.format(**args.__dict__))
        args.deb_status = 'built'
    else:
        args.deb_status = 'skipped'
        

    if not args.no_exe:
        shell("""
            # Build windows executables
            cd {build_dir}/pyqtgraph
            python setup.py build bdist_wininst --plat-name=win32
            python setup.py build bdist_wininst --plat-name=win-amd64
            cp dist/*.exe {pkg_dir}
        """.format(**args.__dict__))
        args.exe_status = 'built'    
    else:
        args.exe_status = 'skipped'


    print(unindent("""

    ======== Build complete. =========

      * Source package:     built
      * Pip install test:   {pip_test}
      * Debian packages:    {deb_status}
      * Windows installers: {exe_status}
      * Package files in    {pkg_dir}

    Next steps to publish:
    
      * Test all packages
      * Run script again with --publish

    """).format(**args.__dict__))


def publish(args):


    if not os.path.isfile(os.path.expanduser('~/.pypirc')):
        print(unindent("""
            Missing ~/.pypirc file. Should look like:
            -----------------------------------------

                [distutils]
                index-servers =
                    pypi

                [pypi]
                username:your_username
                password:your_password

        """))
        sys.exit(-1)

    ### Upload everything to server
    shell("""
        cd {build_dir}/pyqtgraph
        
        # Uploading documentation..  (disabled; now hosted by readthedocs.io)
        #rsync -rv doc/build/* pyqtgraph.org:/www/code/pyqtgraph/pyqtgraph/documentation/build/

        # Uploading release packages to website
        rsync -v {pkg_dir} pyqtgraph.org:/www/code/pyqtgraph/downloads/

        # Push master to github
        git push https://github.com/pyqtgraph/pyqtgraph master:master
        
        # Push tag to github
        git push https://github.com/pyqtgraph/pyqtgraph pyqtgraph-{version}

        # Upload to pypi..
        python setup.py sdist upload

    """.format(**args.__dict__))

    print(unindent("""

    ======== Upload complete. =========

    Next steps to publish:
        - update website
        - mailing list announcement
        - new conda recipe (http://conda.pydata.org/docs/build.html)
        - contact deb maintainer (gianfranco costamagna)
        - other package maintainers?

    """).format(**args.__dict__))


def unindent(msg):
    ind = 1e6
    lines = msg.split('\n')
    for line in lines:
        if len(line.strip()) == 0:
            continue
        ind = min(ind, len(line) - len(line.lstrip()))
    return '\n'.join([line[ind:] for line in lines])


if __name__ == '__main__':
    args = ap.parse_args()
    args.build_dir = os.path.abspath(args.build_dir)
    args.pkg_dir = os.path.join(os.path.abspath(args.pkg_dir), args.version)

    if args.publish:
        publish(args)
    else:
        build(args)