summaryrefslogtreecommitdiff
path: root/scripts/packages-formatter.py
blob: 4449111e46b7a86b250f2e15d808df745c52932d (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
#!/usr/bin/env python3
"""\
This module formats the package version and copyright information for the
viewer and its dependent packages.

$LicenseInfo:firstyear=2014&license=viewerlgpl$
Second Life Viewer Source Code
Copyright (C) 2014, Linden Research, Inc.

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation;
version 2.1 of the License only.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
$/LicenseInfo$
"""
import os
import sys
import errno
import re
import subprocess
import argparse

parser = argparse.ArgumentParser(description='Format dependency version and copyright information for the viewer About box content')
parser.add_argument('channel', help='viewer channel name')
parser.add_argument('version', help='viewer version number')
parser.add_argument('install_dir', help="install dir of packages")
args = parser.parse_args()

_autobuild=os.getenv('AUTOBUILD', 'autobuild')
_autobuild_env=os.environ.copy()
# Coerce stdout encoding to utf-8 as cygwin's will be detected as cp1252 otherwise.
_autobuild_env["PYTHONIOENCODING"] = "utf-8"

pkg_line=re.compile('^([\w-]+):\s+(.*)$')

def autobuild(*args):
    """
    Launch autobuild with specified command-line arguments.
    Return its stdout pipe from which the caller can read.
    """
    # subprocess wants a list, not a tuple
    command = [_autobuild] + list(args)
    try:
        child = subprocess.Popen(command,
                                 stdin=None, stdout=subprocess.PIPE,
                                 universal_newlines=True, env=_autobuild_env)
    except OSError as err:
        if err.errno != errno.ENOENT:
            # Don't attempt to interpret anything but ENOENT
            raise
        # Here it's ENOENT: subprocess can't find the autobuild executable.
        sys.exit("packages-formatter on %s: can't run autobuild:\n%s\n%s" % \
                 (sys.platform, ' '.join(command), err))

    # no exceptions yet, let caller read stdout
    return child.stdout

info=dict(versions={},    copyrights={})
dups=dict(versions=set(), copyrights=set())

def add_info(key, pkg, lines):
    if pkg not in info[key]:
        info[key][pkg] = '\n'.join(lines)
    else:
        dups[key].add(pkg)

versions=autobuild('install', '--versions', '--install-dir', args.install_dir)
copyrights=autobuild('install', '--copyrights', '--install-dir', args.install_dir)
viewer_copyright = copyrights.readline() # first line is the copyright for the viewer itself

# Two different autobuild outputs, but we treat them essentially the same way:
# populating each into a dict; each a subdict of 'info'.
for key, rawdata in ("versions", versions), ("copyrights", copyrights):
    lines = iter(rawdata)
    try:
        line = next(lines)
    except StopIteration:
        # rawdata is completely empty? okay...
        pass
    else:
        pkg_info = pkg_line.match(line)
        # The first line for each package must match pkg_line.
        if not pkg_info:
            sys.exit("Unrecognized --%s output: %r" % (key, line))
        # Only the very first line in rawdata MUST match; for the rest of
        # rawdata, matching the regexp is how we recognize the start of the
        # next package.
        while True:                     # iterate over packages in rawdata
            pkg = pkg_info.group(1)
            pkg_lines = [pkg_info.group(2).strip()]
            for line in lines:
                pkg_info = pkg_line.match(line)
                if pkg_info:
                    # we hit the start of the next package data
                    add_info(key, pkg, pkg_lines)
                    break
                else:
                    # no package prefix: additional line for same package
                    pkg_lines.append(line.rstrip())
            else:
                # last package in the output -- finished 'lines'
                add_info(key, pkg, pkg_lines)
                break

# Now that we've run through all of both outputs -- are there duplicates?
if any(pkgs for pkgs in list(dups.values())):
    for key, pkgs in list(dups.items()):
        if pkgs:
            print("Duplicate %s for %s" % (key, ", ".join(pkgs)), file=sys.stderr)
    sys.exit(1)

print("%s %s" % (args.channel, args.version))
print(viewer_copyright)
version = list(info['versions'].items())
version.sort()
for pkg, pkg_version in version:
    print(': '.join([pkg, pkg_version]))
    try:
        print(info['copyrights'][pkg])
    except KeyError:
        sys.exit("No copyright for %s" % pkg)
    print()