File: create_bundle_manifest.py

package info (click to toggle)
python-pbcommand 2.1.1%2Bgit20231020.28d1635-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 1,016 kB
  • sloc: python: 7,676; makefile: 220; sh: 73
file content (193 lines) | stat: -rw-r--r-- 5,844 bytes parent folder | download | duplicates (3)
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
#!/usr/bin/python3
# Tool to generate the manifest.xml will the correct datetime of bundle
# creation as well as add git sha and bamboo build metadata

import argparse
import datetime
import json
import os.path as op
import os
import subprocess
import sys
from xml.dom import minidom
from xml.etree.ElementTree import Element, SubElement, tostring

__version__ = "0.3.0"


class Constants:
    # there's an Id versus name issue here
    NAME = "SMRT Link Software Update"
    AUTHOR = "build"


def get_parser():
    desc = "Update the manifest.xml"
    p = argparse.ArgumentParser(description=desc,
                                formatter_class=argparse.ArgumentDefaultsHelpFormatter)
    p.add_argument("bundle_id", help="ID of the software bundle")
    p.add_argument("version",
                   help="Version string or path to filename that contains it")
    p.add_argument("-o", dest="output_manifest_xml", default="manifest.xml",
                   help="Path to the version.txt file. Must have a single line with Major.Minor.Tiny format")
    p.add_argument(
        "-j",
        dest="pacbio_manifest_json",
        default="pacbio-manifest.json",
        help="Output path output manifest JSON used by SMRT Link")
    p.add_argument(
        '--author',
        dest="author",
        default=Constants.AUTHOR,
        help="Bundle creation Author")
    p.add_argument("--name", dest="name", default=Constants.NAME,
                   help="Name of software bundle")
    p.add_argument("--desc", dest="description", default="No Description",
                   help="Description to appear in the manifest")
    return p


def git_short_sha():
    args = "git rev-parse --short HEAD".split()
    return subprocess.check_output(args, encoding="utf-8").strip()


def git_branch():
    args = "git rev-parse --abbrev-ref HEAD".split()
    return subprocess.check_output(args, encoding="utf-8").strip()


def get_bamboo_buildnumber(default=0):
    return int(os.environ.get('bamboo_globalBuildNumber', default))


def to_semver(major, minor, patch, git_sha,
              build_number=None, prerelease_tag=None):
    """Convert to semver format"""
    base = ".".join(str(i) for i in (major, minor, patch))
    prerelease = "" if prerelease_tag is None else "-{}".format(prerelease_tag)
    # need the trailing . as the sep for the other metadata
    number = "" if build_number is None else str(build_number) + "."
    metadata = "+{b}{s}".format(b=number, s=git_sha[:7])
    return "{b}{p}{m}".format(b=base, p=prerelease, m=metadata)


def to_undocumented_pacbio_version_format(major, minor, tiny, other):
    return ".".join([str(i) for i in (major, minor, tiny, other)])


def get_version(major, minor, tiny):
    build_number = get_bamboo_buildnumber()
    git_sha = git_short_sha()
    # The build number is being abused for the patch version
    return to_semver(major, minor, tiny, git_sha, build_number=None)


def read_version_txt(version):
    if op.isfile(version):
        with open(version, 'r') as f:
            x = f.readline()
    else:
        x = version
    major, minor, patch = [int(i) for i in x.split(".")[:3]]
    return major, minor, patch


def to_pacbio_manifest_d(bundle_id, version, name, desc):
    return dict(id=bundle_id,
                name=name,
                version=version,
                description=desc,
                dependencies=[])


def prettify(elem):
    return minidom.parseString(
        tostring(elem, 'utf-8')).toprettyxml(indent="  ")


def write_manifest_xml(bundle_id, version, name,
                       description, author, manifest_xml):

    root = Element("Manifest")

    def sub(n, value_):
        e = SubElement(root, n)
        e.text = value_
        return e

    sub("Package", bundle_id)
    sub("Name", name)
    sub("Version", version)
    sub("Created", datetime.datetime.utcnow().isoformat())
    sub("Author", author)
    sub("Description", description)

    with open(manifest_xml, 'w') as f:
        f.write(prettify(root))

    return root


def write_pacbio_manifest_json(bundle_id, version, name, desc, output_json):
    with open(output_json, 'w') as f:
        f.write(
            json.dumps(
                to_pacbio_manifest_d(
                    bundle_id,
                    version,
                    name,
                    desc),
                indent=True))


def runner(bundle_id, version, output_manifest_xml,
           pacbio_manifest_json, author, name, desc):

    major, minor, patch = read_version_txt(version)
    sem_ver = get_version(major, minor, patch)
    branch = git_branch()
    other = get_bamboo_buildnumber()
    if not (branch.startswith("master") or branch.startswith("release")):
        other = "SNAPSHOT" + str(other)
    version_str = to_undocumented_pacbio_version_format(
        major, minor, patch, other)

    # this is to get the git SHA1 and build number propagated to SL services
    # data model
    author = "User {} created {} bundle {}".format(
        Constants.AUTHOR, bundle_id, sem_ver)

    # there's some tragic duplication of models between ICS and Secondary
    # hence this duplication of these very similar ideas
    write_manifest_xml(
        bundle_id,
        version_str,
        name,
        desc,
        author,
        output_manifest_xml)
    write_pacbio_manifest_json(
        bundle_id,
        version_str,
        name,
        desc,
        pacbio_manifest_json)

    return 0


def main(argv_):
    p = get_parser()
    args = p.parse_args(argv_)
    return runner(args.bundle_id,
                  args.version,
                  args.output_manifest_xml,
                  args.pacbio_manifest_json,
                  args.author,
                  args.name,
                  args.description)


if __name__ == '__main__':
    sys.exit(main(sys.argv[1:]))