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):