3 # This Source Code Form is subject to the terms of the Mozilla Public
4 # License, v. 2.0. If a copy of the MPL was not distributed with this
5 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
13 from argparse
import ArgumentParser
15 def getFileHashAndSize(filename
):
16 sha512Hash
= 'UNKNOWN'
20 # open in binary mode to make sure we get consistent results
21 # across all platforms
22 f
= open(filename
, "rb")
23 shaObj
= hashlib
.sha512(f
.read())
24 sha512Hash
= shaObj
.hexdigest()
26 size
= os
.path
.getsize(filename
)
30 return (sha512Hash
, size
)
32 def getMarProperties(filename
, partial
=False):
33 if not os
.path
.exists(filename
):
35 (mar_hash
, mar_size
) = getFileHashAndSize(filename
)
36 martype
= 'partial' if partial
else 'complete'
38 '%sMarFilename' % martype
: os
.path
.basename(filename
),
39 '%sMarSize' % martype
: mar_size
,
40 '%sMarHash' % martype
: mar_hash
,
43 def getUrlProperties(filename
):
44 # let's create a switch case using name-spaces/dict
45 # rather than a long if/else with duplicate code
46 property_conditions
= [
47 # key: property name, value: condition
48 ('symbolsUrl', lambda m
: m
.endswith('crashreporter-symbols.zip') or
49 m
.endswith('crashreporter-symbols-full.zip')),
50 ('testsUrl', lambda m
: m
.endswith(('tests.tar.bz2', 'tests.zip'))),
51 ('unsignedApkUrl', lambda m
: m
.endswith('apk') and
52 'unsigned-unaligned' in m
),
53 ('robocopApkUrl', lambda m
: m
.endswith('apk') and 'robocop' in m
),
54 ('jsshellUrl', lambda m
: 'jsshell-' in m
and m
.endswith('.zip')),
55 ('completeMarUrl', lambda m
: m
.endswith('.complete.mar')),
56 ('partialMarUrl', lambda m
: m
.endswith('.mar') and '.partial.' in m
),
57 ('codeCoverageURL', lambda m
: m
.endswith('code-coverage-gcno.zip')),
58 # packageUrl must be last!
59 ('packageUrl', lambda m
: True),
61 url_re
= re
.compile(r
'''^(https?://.*?\.(?:tar\.bz2|dmg|zip|apk|rpm|mar|tar\.gz))$''')
65 with
open(filename
) as f
:
67 m
= url_re
.match(line
)
70 for prop
, condition
in property_conditions
:
72 properties
.update({prop
: m
})
75 if e
.errno
!= errno
.ENOENT
:
77 properties
= {prop
: 'UNKNOWN' for prop
, condition
in property_conditions
}
80 def getPartialInfo(props
):
82 "from_buildid": props
.get("previous_buildid"),
83 "size": props
.get("partialMarSize"),
84 "hash": props
.get("partialMarHash"),
85 "url": props
.get("partialMarUrl"),
88 if __name__
== '__main__':
89 parser
= ArgumentParser(description
='Generate mach_build_properties.json for automation builds.')
90 parser
.add_argument("--complete-mar-file", required
=True,
91 action
="store", dest
="complete_mar_file",
92 help="Path to the complete MAR file, relative to the objdir.")
93 parser
.add_argument("--partial-mar-file", required
=False,
94 action
="store", dest
="partial_mar_file",
95 help="Path to the partial MAR file, relative to the objdir.")
96 parser
.add_argument("--upload-output", required
=True,
97 action
="store", dest
="upload_output",
98 help="Path to the text output of 'make upload'")
99 parser
.add_argument("--upload-files", required
=True, nargs
="+",
100 action
="store", dest
="upload_files",
101 help="List of files to be uploaded.")
102 args
= parser
.parse_args()
104 json_data
= getMarProperties(args
.complete_mar_file
)
105 json_data
.update(getUrlProperties(args
.upload_output
))
106 if args
.partial_mar_file
:
107 json_data
.update(getMarProperties(args
.partial_mar_file
, partial
=True))
109 # Pull the previous buildid from the partial mar filename.
110 res
= re
.match(r
'.*\.([0-9]+)-[0-9]+.mar', args
.partial_mar_file
)
112 json_data
['previous_buildid'] = res
.group(1)
114 # Set partialInfo to be a collection of the partial mar properties
116 json_data
['partialInfo'] = getPartialInfo(json_data
)
118 json_data
['uploadFiles'] = args
.upload_files
120 with
open('mach_build_properties.json', 'w') as outfile
:
121 json
.dump(json_data
, outfile
, indent
=4)