summaryrefslogtreecommitdiff
path: root/wscript
blob: c1ee262fae55ef1ad68a24bd451e3417c69b9360 (plain)
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
APPNAME = 'wheel'
WHEEL_TAG = 'py2.py3-none-any'
VERSION = '0.24.0'

top = '.'
out = 'build'

from waflib import Utils

def options(opt):
    opt.load('python')

def configure(ctx):
    ctx.load('python')
    ctx.check_python_version()

def build(bld):
    bld(features='py',
        source=bld.path.ant_glob('wheel/**/*.py', excl="wheel/test"),
        install_from='.')

    # build the wheel:

    DIST_INFO = '%s-%s.dist-info' % (APPNAME, VERSION)

    node = bld.path.get_bld().make_node(DIST_INFO)
    if not os.path.exists(node.abspath()):
        os.mkdir(node.abspath())

    metadata = node.make_node('METADATA')

    import codecs, string
    README = codecs.open('README.txt', encoding='utf8').read()
    CHANGES = codecs.open('CHANGES.txt', encoding='utf8').read()
    METADATA = codecs.open('METADATA.in', encoding='utf8').read()
    METADATA = string.Template(METADATA).substitute(
            VERSION=VERSION,
            DESCRIPTION='\n\n'.join((README, CHANGES))
            )

    bld(source='METADATA.in',
        target=metadata,
        rule=lambda tsk: Utils.writef(tsk.outputs[0].abspath(), METADATA))

    wheel = node.make_node('WHEEL')

    WHEEL="""Wheel-Version: 1.0
Generator: waf (0.0.1)
Root-Is-Purelib: true
Tag: py2-none-any
Tag: py3-none-any
"""
    bld(target=wheel,
       rule=lambda tsk: Utils.writef(tsk.outputs[0].abspath(), WHEEL))

    # globs don't work, since here the files may not exist:
    bld.install_files('${PYTHONDIR}/'+DIST_INFO, [DIST_INFO+'/WHEEL', DIST_INFO+'/METADATA'])

    # only if entry_points.txt exists:
    bld.install_files('${PYTHONDIR}/'+DIST_INFO, ['entry_points.txt'])

import shutil, os, base64

def urlsafe_b64encode(data):
    """urlsafe_b64encode without padding"""
    return base64.urlsafe_b64encode(data).rstrip(b'=')

from waflib import Scripting
class WheelDist(Scripting.Dist):
    def manifest(self):
        """
        Add the wheel manifest.
        """
        import hashlib
        files = self.get_files()
        lines = []
        for f in files:
            print("File: %s" % f.relpath())
            size = os.stat(f.abspath()).st_size
            digest = hashlib.sha256(open(f.abspath(), 'rb').read()).digest()
            digest = "sha256="+(urlsafe_b64encode(digest).decode('ascii'))
            lines.append("%s,%s,%s" % (f.path_from(self.base_path).replace(',', ',,'), digest, size))

        record_path = '%s-%s.dist-info/RECORD' % (APPNAME, VERSION)
        lines.append(record_path+',,')
        RECORD = '\n'.join(lines)

        import zipfile
        zip = zipfile.ZipFile(self.get_arch_name(), 'a')
        zip.writestr(record_path, RECORD, zipfile.ZIP_DEFLATED)
        zip.close()

from waflib import Build
class package_cls(Build.InstallContext):
    cmd = 'package'
    fun = 'build'

    def init_dirs(self, *k, **kw):
        super(package_cls, self).init_dirs(*k, **kw)
        self.tmp = self.bldnode.make_node('package_tmp_dir')
        try:
            shutil.rmtree(self.tmp.abspath())
        except:
            pass
        if os.path.exists(self.tmp.abspath()):
            self.fatal('Could not remove the temporary directory %r' % self.tmp)
        self.tmp.mkdir()
        self.options.destdir = self.tmp.abspath()

    def execute(self, *k, **kw):
        back = self.options.destdir
        try:
            super(package_cls, self).execute(*k, **kw)
        finally:
            self.options.destdir = back

        files = self.tmp.ant_glob('**', excl=" **/*.pyc **/*.pyo")

        # we could mess with multiple inheritance but this is probably unnecessary
        ctx = WheelDist()
        ctx.algo = 'zip'
        ctx.arch_name = '%s-%s-%s.whl' % (APPNAME, VERSION, WHEEL_TAG)
        ctx.files = files
        ctx.tar_prefix = ''
        ctx.base_path = self.tmp
        ctx.base_name = ''
        ctx.archive()

        # add manifest...
        ctx.manifest()

        shutil.rmtree(self.tmp.abspath())