rework python scripts to support Python 2 & 3 We run the unittests in both python versions to maintain coverage, and we run things through `cros lint` during upload to help prevent regressions. We also switch the default to Python 3 to keep people on their toes. BUG=chromium:982465 TEST=running unittests against python2 & python3 pass TEST=`./fmap.py bin/example.bin` through python2 & python3 works Change-Id: I79f0ce59664ea42dfa18e45ccde0dffc0c18227d Reviewed-on: https://chromium-review.googlesource.com/1693888 Tested-by: Mike Frysinger <vapier@chromium.org> Commit-Ready: Mike Frysinger <vapier@chromium.org> Legacy-Commit-Queue: Commit Bot <commit-bot@chromium.org> Reviewed-by: Duncan Laurie <dlaurie@google.com>
diff --git a/PRESUBMIT.cfg b/PRESUBMIT.cfg index 8238211..2150455 100644 --- a/PRESUBMIT.cfg +++ b/PRESUBMIT.cfg
@@ -2,6 +2,8 @@ [Hook Scripts] fmap_unittest py2 = python2 ./fmap_unittest.py +fmap_unittest py3 = python3 ./fmap_unittest.py +cros lint = cros lint ${PRESUBMIT_FILES} [Hook Overrides] cros_license_check: false
diff --git a/fmap.py b/fmap.py index a5ec8ef..0ef9f40 100755 --- a/fmap.py +++ b/fmap.py
@@ -1,4 +1,5 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- # # Copyright 2010, Google Inc. # All rights reserved. @@ -49,8 +50,10 @@ tuple of decoded area flags. """ +from __future__ import print_function import argparse +import copy import logging import pprint import struct @@ -58,7 +61,7 @@ # constants imported from lib/fmap.h -FMAP_SIGNATURE = '__FMAP__' +FMAP_SIGNATURE = b'__FMAP__' FMAP_VER_MAJOR = 1 FMAP_VER_MINOR_MIN = 0 FMAP_VER_MINOR_MAX = 1 @@ -112,7 +115,15 @@ raise struct.error('Incompatible version') # convert null-terminated names - header['name'] = header['name'].strip(chr(0)) + header['name'] = header['name'].strip(b'\x00') + + # In Python 2, binary==string, so we don't need to convert. + if sys.version_info.major >= 3: + # Do the decode after verifying it to avoid decode errors due to corruption. + for name in FMAP_HEADER_NAMES: + if hasattr(header[name], 'decode'): + header[name] = header[name].decode('utf-8') + return (header, struct.calcsize(FMAP_HEADER_FORMAT)) @@ -123,9 +134,16 @@ struct.unpack_from(FMAP_AREA_FORMAT, blob, offset)): area[name] = value # convert null-terminated names - area['name'] = area['name'].strip(chr(0)) + area['name'] = area['name'].strip(b'\x00') # add a (readonly) readable FLAGS area['FLAGS'] = _fmap_decode_area_flags(area['flags']) + + # In Python 2, binary==string, so we don't need to convert. + if sys.version_info.major >= 3: + for name in FMAP_AREA_NAMES: + if hasattr(area[name], 'decode'): + area[name] = area[name].decode('utf-8') + return (area, struct.calcsize(FMAP_AREA_FORMAT)) @@ -171,7 +189,7 @@ align *= 2 while align >= FMAP_SEARCH_STRIDE: - for offset in xrange(align, lim + 1, align * 2): + for offset in range(align, lim + 1, align * 2): if not blob.startswith(FMAP_SIGNATURE, offset): continue try: @@ -214,12 +232,24 @@ def _fmap_encode_header(obj): """(internal) Encodes a FMAP header""" + # Convert strings to bytes. + obj = copy.deepcopy(obj) + for name in FMAP_HEADER_NAMES: + if hasattr(obj[name], 'encode'): + obj[name] = obj[name].encode('utf-8') + values = [obj[name] for name in FMAP_HEADER_NAMES] return struct.pack(FMAP_HEADER_FORMAT, *values) def _fmap_encode_area(obj): """(internal) Encodes a FMAP area entry""" + # Convert strings to bytes. + obj = copy.deepcopy(obj) + for name in FMAP_AREA_NAMES: + if hasattr(obj[name], 'encode'): + obj[name] = obj[name].encode('utf-8') + values = [obj[name] for name in FMAP_AREA_NAMES] return struct.pack(FMAP_AREA_FORMAT, *values)
diff --git a/fmap_unittest.py b/fmap_unittest.py index 4a5bffa..91b346b 100755 --- a/fmap_unittest.py +++ b/fmap_unittest.py
@@ -1,10 +1,14 @@ -#!/usr/bin/python +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- # # Copyright 2017 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. + """Unit test for fmap module.""" +from __future__ import print_function + import struct import unittest @@ -54,7 +58,7 @@ maxDiff = None def setUp(self): - with open('bin/example.bin') as f: + with open('bin/example.bin', 'rb') as f: self.example_blob = f.read() def testDecode(self):