blob: e031e0c7927d87c88a1583813f27aec84372ec76 [file] [log] [blame]
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Copyright 2020 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Create the package information file in JSON format.
To get the package information, use the library at
https://cos.googlesource.com/cos/tools/+/refs/heads/master/src/pkg/cos/pkg_info.go
instead of accessing the JSON file directly.
For information on the JSON format, see http://go/cos-package-list-design .
"""
from __future__ import print_function
import collections
import getopt
import json
import re
import sys
# The following regular expresssions are used for extracting the category name,
# the package name, the package version without the revision, and the package
# revision from a string that looks like
#
# category_name/package_name-1.2.3.4_beta1_rc2-r1
#
# These regular expressions follow the Gentoo package manager specification at
# https://www.gentoo.org/proj/en/qa/pms.xml . They are similar to what SplitPV
# function (in chromite/lib/portage_util.py) uses.
CATEGORY_RE = r'(?P<category>\w[\w\+\.\-]*)'
PACKAGE_RE = r'(?P<package>\w[\w+-]*)'
VERSION_NUMLETTER_RE = r'\d+(\.\d+)*[a-z]?'
VERSION_SUFFIX_RE = r'_(pre|p|beta|alpha|rc)\d*'
VERSION_NO_REV_RE = r'(?P<version_no_rev>%s(%s)*)' % (VERSION_NUMLETTER_RE,
VERSION_SUFFIX_RE)
REVISION_RE = r'-r(?P<revision>\d+)'
CPV_RE = r'^%s\/%s-%s(%s)?$' % (CATEGORY_RE, PACKAGE_RE,
VERSION_NO_REV_RE, REVISION_RE)
OVERLAY_RE = r'(?P<overlay>overlay:\w[\w+-]*)'
USE_FLAGS_RE = r'(?P<use_flags>use_flags:[(-|+)\w+-_,]*)'
DEBUG_CPV_RE = r'^%s\/%s-%s(%s)?(\s)?(%s)?(\s)?(\s)?(%s)?$' % (CATEGORY_RE, PACKAGE_RE,
VERSION_NO_REV_RE, REVISION_RE,
OVERLAY_RE, USE_FLAGS_RE)
def PrintHelp():
print('usage: create_pkg_list.py --input=<comma separated list '
'of pkg_type:pkg_info_file> --build-id=<build id> '
'--output=<output file> --debug')
def CreateList(input_lines, debug):
if debug:
cpv_re = re.compile(DEBUG_CPV_RE, re.VERBOSE)
else:
cpv_re = re.compile(CPV_RE, re.VERBOSE)
package_list = []
for line in input_lines:
match = cpv_re.match(line.strip())
if match is not None:
package_list.append(match.groupdict())
return package_list
def WriteJson(pkg_info, build_id, output_file, debug):
result = {}
for pkg_type, pkg_list in pkg_info.items():
packages = []
for p in pkg_list:
package_info = collections.OrderedDict(
[('category', p['category']),
('name', p['package']),
('version', build_id),
('ebuild_version', p['version_no_rev'])
]
)
if 'revision' in p and p['revision'] is not None:
package_info['ebuild_version'] += '-r' + p['revision']
if debug:
if 'overlay' in p and p['overlay'] is not None:
package_info['overlay'] = p['overlay'].replace('overlay:', '')
if 'use_flags' in p and p['use_flags'] is not None:
package_info['use_flags'] = p['use_flags'].replace('use_flags:', '')
packages.append(package_info)
result[pkg_type] = packages
json.dump(result, output_file, indent=4)
return 0
def main(argv):
input_fn = ''
output_fn = ''
build_id = ''
debug = False
try:
opts, args_left = getopt.getopt(argv, '', ['help', 'input=', 'output=', 'build-id=', 'debug'])
except getopt.GetoptError:
PrintHelp()
return -1
if len(args_left) != 0:
PrintHelp()
return -1
for opt, arg in opts:
if opt == '--help':
PrintHelp()
elif opt == '--input':
input_fn = arg
elif opt == '--output':
output_fn = arg
elif opt == '--build-id':
build_id = arg
elif opt == '--debug':
debug = True
if input_fn == '' or output_fn == '':
PrintHelp()
return -1
inputs = input_fn.split(',')
pkg_info = {}
for i in inputs:
# <pkg_type>:<pkg_info_file>
pkg_type, pkg_info_file = i.split(':', 1)
input_lines = []
try:
with open(pkg_info_file) as input_file:
input_lines = input_file.readlines()
except OSError:
print('error: Failed to open input file: %s' % pkg_info_file)
return -1
if len(input_lines) == 0:
print('warning: No input lines')
continue
package_list = CreateList(input_lines, debug)
if len(package_list) == 0:
print('warning: Empty package list')
continue
pkg_info[pkg_type] = package_list
try:
with open(output_fn, 'w') as output_file:
ret = WriteJson(pkg_info, build_id, output_file, debug)
if ret != 0:
print('error: Failed to write package info')
return ret
except OSError:
print('error: Failed to open output file: %s' % output_fn)
return -1
return 0
if __name__ == '__main__':
sys.exit(main(sys.argv[1:]))