summaryrefslogtreecommitdiff
path: root/experimental/firefox-esr
diff options
context:
space:
mode:
authorA. Wilcox <AWilcox@Wilcox-Tech.com>2018-10-26 22:21:04 +0000
committerA. Wilcox <AWilcox@Wilcox-Tech.com>2018-10-26 22:22:59 +0000
commite4650554521c89f1f774bdd143b1359141091e15 (patch)
tree1b9a12209af70b90916182b405f01ac155264178 /experimental/firefox-esr
parent954c88d73be84cad6a6cf0b3f2d71ae544190120 (diff)
downloadpackages-e4650554521c89f1f774bdd143b1359141091e15.tar.gz
packages-e4650554521c89f1f774bdd143b1359141091e15.tar.bz2
packages-e4650554521c89f1f774bdd143b1359141091e15.tar.xz
packages-e4650554521c89f1f774bdd143b1359141091e15.zip
experimental/firefox-esr: add ESR 60, which does not work [https://bugzilla.mozilla.org/1499121]
Diffstat (limited to 'experimental/firefox-esr')
-rw-r--r--experimental/firefox-esr/5-e6b5aa19e999.patch22
-rw-r--r--experimental/firefox-esr/APKBUILD175
-rw-r--r--experimental/firefox-esr/bad-google-code.patch49
-rw-r--r--experimental/firefox-esr/cmsghdr.patch11
-rw-r--r--experimental/firefox-esr/endian-gfx.patch32
-rw-r--r--experimental/firefox-esr/endianness-js.patch144
-rw-r--r--experimental/firefox-esr/firefox-safe.desktop11
-rw-r--r--experimental/firefox-esr/firefox.desktop81
-rw-r--r--experimental/firefox-esr/fix-arm-atomics-grsec.patch306
-rw-r--r--experimental/firefox-esr/fix-arm-version-detect.patch13
-rw-r--r--experimental/firefox-esr/fix-bug-1261392.patch25
-rw-r--r--experimental/firefox-esr/fix-fortify-inline.patch11
-rw-r--r--experimental/firefox-esr/fix-mutex-build.patch20
-rw-r--r--experimental/firefox-esr/fix-seccomp-bpf.patch14
-rw-r--r--experimental/firefox-esr/fix-stack-overflow.patch45
-rw-r--r--experimental/firefox-esr/mallinfo.patch20
-rw-r--r--experimental/firefox-esr/missing-header-s390x.patch12
-rw-r--r--experimental/firefox-esr/mozconfig28
-rw-r--r--experimental/firefox-esr/mozilla-build-arm.patch11
-rw-r--r--experimental/firefox-esr/musl-pthread-setname.patch14
-rw-r--r--experimental/firefox-esr/proper-system-hunspell.patch22
-rw-r--r--experimental/firefox-esr/python3.patch10397
-rw-r--r--experimental/firefox-esr/rust-config.patch20
-rw-r--r--experimental/firefox-esr/skia.patch132
-rw-r--r--experimental/firefox-esr/stab.h71
-rw-r--r--experimental/firefox-esr/stackwalk-x86-ppc.patch16
-rw-r--r--experimental/firefox-esr/webrtc-broken.patch30
27 files changed, 11732 insertions, 0 deletions
diff --git a/experimental/firefox-esr/5-e6b5aa19e999.patch b/experimental/firefox-esr/5-e6b5aa19e999.patch
new file mode 100644
index 000000000..d33914b78
--- /dev/null
+++ b/experimental/firefox-esr/5-e6b5aa19e999.patch
@@ -0,0 +1,22 @@
+# HG changeset patch
+# User A. Wilcox <AWilcox@Wilcox-Tech.com>
+# Date 1539810007 0
+# Wed Oct 17 21:00:07 2018 +0000
+# Node ID e6b5aa19e9990adaddb2b80061620f3ceb7335e0
+# Parent 34f9863ef26ae1f8e494b3fc8e87fb7e26a480b3
+NOT FOR INBOUND: fix u2fhid on ppc64/musl
+
+diff -r 34f9863ef26a -r e6b5aa19e999 dom/webauthn/u2f-hid-rs/src/linux/hidraw.rs
+--- a/dom/webauthn/u2f-hid-rs/src/linux/hidraw.rs Wed Oct 17 20:59:47 2018 +0000
++++ b/dom/webauthn/u2f-hid-rs/src/linux/hidraw.rs Wed Oct 17 21:00:07 2018 +0000
+@@ -41,10 +41,7 @@
+ | (($nr as u32) << NRSHIFT)
+ | ((size as u32) << SIZESHIFT);
+
+- #[cfg(not(target_env = "musl"))]
+ type IocType = libc::c_ulong;
+- #[cfg(target_env = "musl")]
+- type IocType = libc::c_int;
+
+ from_unix_result(libc::ioctl(fd, ioc as IocType, val))
+ }
diff --git a/experimental/firefox-esr/APKBUILD b/experimental/firefox-esr/APKBUILD
new file mode 100644
index 000000000..8a518d222
--- /dev/null
+++ b/experimental/firefox-esr/APKBUILD
@@ -0,0 +1,175 @@
+# Contributor: William Pitcock <nenolod@dereferenced.org>
+# Maintainer: A. Wilcox <awilfox@adelielinux.org>
+pkgname=firefox-esr
+pkgver=60.3.0
+_pkgver=$pkgver
+_xulver=$pkgver
+pkgrel=0
+pkgdesc="Firefox web browser"
+url="https://www.mozilla.org/en-US/firefox/organizations/faq/"
+arch="all"
+options="!check" # Tests disabled
+license="GPL LGPL MPL"
+depends=""
+depends_dev="alsa-lib-dev bzip2-dev dbus-glib-dev gconf-dev gtk+2.0-dev
+ gtk+3.0-dev hunspell-dev icu-dev libevent-dev libidl-dev
+ libjpeg-turbo-dev libnotify-dev libogg-dev libtheora-dev libvorbis-dev
+ libxt-dev libxcomposite-dev mesa-dev nspr-dev nss-dev
+ pulseaudio-dev sqlite-dev startup-notification-dev wireless-tools-dev"
+makedepends="$depends_dev autoconf2.13 automake libtool
+ bsd-compat-headers cmd:which nss-static openssl-dev sed yasm zip
+ cargo clang llvm6-dev rust"
+subpackages=""
+source="https://ftp.mozilla.org/pub/firefox/releases/${pkgver}esr/source/firefox-${pkgver}esr.source.tar.xz
+ mozconfig
+ stab.h
+
+ fix-fortify-inline.patch
+ fix-seccomp-bpf.patch
+ mallinfo.patch
+ musl-pthread-setname.patch
+
+ fix-arm-atomics-grsec.patch
+ fix-arm-version-detect.patch
+ mozilla-build-arm.patch
+ missing-header-s390x.patch
+
+ bad-google-code.patch
+ cmsghdr.patch
+ endian-gfx.patch
+ endianness-js.patch
+ fix-bug-1261392.patch
+ fix-mutex-build.patch
+ proper-system-hunspell.patch
+ rust-config.patch
+ skia.patch
+ stackwalk-x86-ppc.patch
+ webrtc-broken.patch
+
+ firefox.desktop
+ firefox-safe.desktop"
+
+builddir="$srcdir"/firefox-$pkgver
+_mozappdir=/usr/lib/firefox
+
+# help our shared-object scanner to find the libs
+ldpath="$_mozappdir"
+
+unpack() {
+ default_unpack
+ [ -z $SKIP_PYTHON ] || return 0
+ msg "Killing all remaining hope for humanity and building Python 2..."
+ cd "$srcdir"
+ [ -d python ] && rm -r python
+ mkdir python
+ cd python
+ # 19:39 <+solar> just make the firefox build process build its own py2 copy
+ curl -O https://www.python.org/ftp/python/2.7.15/Python-2.7.15.tar.xz
+ tar xJf Python-2.7.15.tar.xz
+ cd Python-2.7.15
+ # 20:03 <calvin> TheWilfox: there's always violence
+ ./configure --prefix="$srcdir/python"
+ make -j $JOBS
+ # 6 tests failed:
+ # test__locale test_os test_posix test_re test_strptime test_time
+ # make test
+ make -j $JOBS install
+}
+
+prepare() {
+ cd "$builddir"
+ default_prepare
+ cp "$srcdir"/stab.h toolkit/crashreporter/google-breakpad/src/
+ cp "$srcdir"/mozconfig "$builddir"/mozconfig
+ echo "ac_add_options --enable-optimize=\"$CFLAGS\"" >> "$builddir"/mozconfig
+ echo "ac_add_options --host=\"$CHOST\"" >> "$builddir"/mozconfig
+ echo "ac_add_options --target=\"$CTARGET\"" >> "$builddir"/mozconfig
+ # too much memory
+ if [ -z "$JOBS" -o $JOBS -gt 32 ]; then
+ echo "mk_add_options MOZ_MAKE_FLAGS=\"-j32\"" >> "$builddir"/mozconfig
+ fi
+}
+
+build() {
+ cd "$builddir"
+
+ export SHELL=/bin/sh
+ export BUILD_OFFICIAL=1
+ export MOZILLA_OFFICIAL=1
+ export USE_SHORT_LIBNAME=1
+ # gcc 6
+ export CXXFLAGS="-fno-delete-null-pointer-checks -fno-schedule-insns2"
+
+ # set rpath so linker finds the libs
+ export LDFLAGS="$LDFLAGS -Wl,-rpath,${_mozappdir}"
+
+ local extra_flags=""
+ [ "$CARCH" = "s390x" ] && extra_flags="--disable-startupcache"
+
+ export PATH="$srcdir/python/bin:$PATH"
+ ./mach build
+}
+
+package() {
+ cd "$builddir"
+ export PATH="$srcdir/python/bin:$PATH"
+ DESTDIR="$pkgdir" ./mach install
+
+ install -m755 -d ${pkgdir}/usr/share/applications
+ install -m755 -d ${pkgdir}/usr/share/pixmaps
+
+ local png
+ for png in browser/branding/official/default*.png; do
+ local i=${_png%.png}
+ i=${i##*/default}
+ install -D -m644 "$png" \
+ "$pkgdir"/usr/share/icons/hicolor/${i}x${i}/apps/firefox.png
+ done
+
+ install -m644 "$builddir"/browser/branding/official/default48.png \
+ ${pkgdir}/usr/share/pixmaps/firefox.png
+ install -m644 ${startdir}/firefox.desktop \
+ ${pkgdir}/usr/share/applications/firefox.desktop
+ install -m644 ${startdir}/firefox-safe.desktop \
+ ${pkgdir}/usr/share/applications/firefox-safe.desktop
+
+ # install our vendor prefs
+ install -d "$pkgdir"/$_mozappdir/browser/defaults/preferences
+
+ cat >> "$pkgdir"/$_mozappdir/browser/defaults/preferences/firefox-branding.js <<- EOF
+ // Use LANG environment variable to choose locale
+ pref("intl.locale.matchOS", true);
+
+ // Disable default browser checking.
+ pref("browser.shell.checkDefaultBrowser", false);
+
+ // Don't disable our bundled extensions in the application directory
+ pref("extensions.autoDisableScopes", 11);
+ pref("extensions.shownSelectionUI", true);
+ EOF
+}
+
+sha512sums="7ded25a38835fbd73a58085e24ad83308afee1784a3bf853d75093c1500ad46988f5865c106abdae938cfbd1fb10746cc1795ece7994fd7eba8a002158cf1bcd firefox-60.3.0esr.source.tar.xz
+76e3e6f64f4dd1206106b2b73cca3ccd312a8d907010c382ab9e2f0a497fed297abf0654d4dd90c563e6dde6403e3f9084ce927bb275fec95be87bed8adf9257 mozconfig
+0b3f1e4b9fdc868e4738b5c81fd6c6128ce8885b260affcb9a65ff9d164d7232626ce1291aaea70132b3e3124f5e13fef4d39326b8e7173e362a823722a85127 stab.h
+09bc32cf9ee81b9cc6bb58ddbc66e6cc5c344badff8de3435cde5848e5a451e0172153231db85c2385ff05b5d9c20760cb18e4138dfc99060a9e960de2befbd5 fix-fortify-inline.patch
+70863b985427b9653ce5e28d6064f078fb6d4ccf43dd1b68e72f97f44868fc0ce063161c39a4e77a0a1a207b7365d5dc7a7ca5e68c726825eba814f2b93e2f5d fix-seccomp-bpf.patch
+bdcd1b402d2ec94957ba5d08cbad7b1a7f59c251c311be9095208491a05abb05a956c79f27908e1f26b54a3679387b2f33a51e945b650671ad85c0a2d59a5a29 mallinfo.patch
+3f535b1e4e9a5a0506ef6f6d9427a84fae1efa3c8e8d6b25b21046d2d04c132bde1a7a98e415067e5c542f699d89249b8cc3d925e0be4e96db498037429691ef musl-pthread-setname.patch
+ed0d344c66fc8e1cc83a11e9858b32c42e841cbeedd9eb9438811e9fcc3593dc824a8336d00058d55836cedc970aeadd6a82c6dcd7bc0fb746e564d8b478cc6c fix-arm-atomics-grsec.patch
+015e1ff6dbf920033982b5df95d869a0b7bf56c6964e45e50649ddf46d1ce09563458e45240c3ecb92808662b1300b67507f7af272ba184835d91068a9e7d5b0 fix-arm-version-detect.patch
+e61664bc93eadce5016a06a4d0684b34a05074f1815e88ef2613380d7b369c6fd305fb34f83b5eb18b9e3138273ea8ddcfdcb1084fdcaa922a1e5b30146a3b18 mozilla-build-arm.patch
+6beba471b6a7fc229a9c105d58137f80cec07219e52bb9a666c787b37ca88635d6ec2eba651eccb5096429c2965709c9475c89839c255c3545f8c96c5d40f403 missing-header-s390x.patch
+ace7492f4fb0523c7340fdc09c831906f74fddad93822aff367135538dacd3f56288b907f5a04f53f94c76e722ba0bab73e28d83ec12d3e672554712e6b08613 bad-google-code.patch
+61c7117345b4bcb045ce0287aa368d90dffd7331347021ff345d5a7c46097ffd2575f38711309ce7bdbbbec15561e03fdabcb16235ed8a325ccc8c9d5bba35a6 cmsghdr.patch
+83b233e279846474bfb662d066e31f80be9055a022b126c638453ced46f70d3904dc114dbabd44800221a1bf3164350ea8c557c25d5e770e8871b7f2932c2427 endian-gfx.patch
+31f0cf9663443410a996002ed0357c2ea21692ce965a30d8bfb65d0f1827173da8d8b5c831ccbc199ecbe7a577613be0dd54a09db08e620fe37e1ce977a7afb0 endianness-js.patch
+a50b412edf9573a0bd04a43578b1c927967a616b73a5995eefb15bfa78fd2bd14e36ec05315a0703f6370ecd524e6bcb012e7285beb1245e9add9b8553acb79e fix-bug-1261392.patch
+d5d3ec190b1916d5c06f466a72124a3d438d90ea40d54e894105a9faf2aa2a6ce9cc21a0a80bd4408f7be867e5a660ee3d8aed40c8d1fb511cfb947739f45240 fix-mutex-build.patch
+1a88c21c39d5878e2018463fe08dd3a960cdf10e650e06ef3e4f089a431800b50267d8749a7acde196bb47c45aa66058a6ed4fb4d60de2ab69e8a48cd5a109bc proper-system-hunspell.patch
+fd3b165e26ab931dd7eaf220d578c30b8772eab0a870710d59403c9823c2233ef941cd7eb25d1625d705de9e8a7138d0e8c4e227a185e9b687553132da96d81a rust-config.patch
+8ef2bc4404601f66c7505f3e0a2f6d1d11e8f11e5a888dce4942cf27c86fbdbcdd66cb3d98738b7d9e25538793986140e75d51a893d22c70714ed98ef50a9894 skia.patch
+d12ce112b97cbdba0748c5734a024b13032c5e0696efbd499764246e031d477b0f0a966aedc7b3bedd166bcdc2cc24d45bb9da5f678de9cff547bc6aa231cd16 stackwalk-x86-ppc.patch
+76409619464259e3ba52e38d640c5b6210a7fecdc75cf124c185ef356507d4d266a845e9fcdeb7766dcd547f70748123c4fa1670f6e52aadd001a3c866dc2d51 webrtc-broken.patch
+f3b7c3e804ce04731012a46cb9e9a6b0769e3772aef9c0a4a8c7520b030fdf6cd703d5e9ff49275f14b7d738fe82a0a4fde3bc3219dff7225d5db0e274987454 firefox.desktop
+5dcb6288d0444a8a471d669bbaf61cdb1433663eff38b72ee5e980843f5fc07d0d60c91627a2c1159215d0ad77ae3f115dcc5fdfe87e64ca704b641aceaa44ed firefox-safe.desktop"
diff --git a/experimental/firefox-esr/bad-google-code.patch b/experimental/firefox-esr/bad-google-code.patch
new file mode 100644
index 000000000..e214af432
--- /dev/null
+++ b/experimental/firefox-esr/bad-google-code.patch
@@ -0,0 +1,49 @@
+--- firefox-esr-60.2.1/toolkit/crashreporter/google-breakpad/src/common/linux/dump_symbols.cc
++++ firefox-esr-60.2.1/toolkit/crashreporter/google-breakpad/src/common/linux/dump_symbols.cc
+@@ -45,6 +45,7 @@
+ #include <sys/mman.h>
+ #include <sys/stat.h>
+ #include <unistd.h>
++#include <libgen.h>
+
+ #include <iostream>
+ #include <set>
+--- firefox-esr-60.2.1/toolkit/crashreporter/google-breakpad/src/common/stabs_reader.cc
++++ firefox-esr-60.2.1/toolkit/crashreporter/google-breakpad/src/common/stabs_reader.cc
+@@ -41,6 +41,10 @@
+
+ #include "common/using_std_string.h"
+
++#ifndef N_UNDF
++#define N_UNDF 0
++#endif
++
+ using std::vector;
+
+ namespace google_breakpad {
+--- firefox-esr-60.2.1/toolkit/crashreporter/google-breakpad/src/common/stabs_reader.h
++++ firefox-esr-60.2.1/toolkit/crashreporter/google-breakpad/src/common/stabs_reader.h
+@@ -55,7 +55,7 @@
+
+ #ifdef HAVE_MACH_O_NLIST_H
+ #include <mach-o/nlist.h>
+-#elif defined(HAVE_A_OUT_H)
++#elif 0
+ #include <a.out.h>
+ #endif
+
+--- firefox-esr-60.2.1/toolkit/crashreporter/google-breakpad/src/third_party/lss/linux_syscall_support.h
++++ firefox-esr-60.2.1/toolkit/crashreporter/google-breakpad/src/third_party/lss/linux_syscall_support.h
+@@ -1134,6 +1134,12 @@ struct kernel_statfs {
+ #ifndef __NR_fallocate
+ #define __NR_fallocate 285
+ #endif
++
++#undef __NR_pread
++#define __NR_pread __NR_pread64
++#undef __NR_pwrite
++#define __NR_pwrite __NR_pwrite64
++
+ /* End of x86-64 definitions */
+ #elif defined(__mips__)
+ #if _MIPS_SIM == _MIPS_SIM_ABI32
diff --git a/experimental/firefox-esr/cmsghdr.patch b/experimental/firefox-esr/cmsghdr.patch
new file mode 100644
index 000000000..5fdc38353
--- /dev/null
+++ b/experimental/firefox-esr/cmsghdr.patch
@@ -0,0 +1,11 @@
+diff -Naur firefox-60.0.orig/media/audioipc/audioipc/src/cmsg.rs firefox-60.0/media/audioipc/audioipc/src/cmsg.rs
+--- firefox-60.0.orig/media/audioipc/audioipc/src/cmsg.rs 2018-05-13 18:05:51.713781232 -0700
++++ firefox-60.0/media/audioipc/audioipc/src/cmsg.rs 2018-05-13 17:33:39.536856530 -0700
+@@ -108,6 +108,7 @@
+
+ let cmsghdr = cmsghdr {
+ cmsg_len: cmsg_len as _,
++ __pad1: 0,
+ cmsg_level: level,
+ cmsg_type: kind,
+ };
diff --git a/experimental/firefox-esr/endian-gfx.patch b/experimental/firefox-esr/endian-gfx.patch
new file mode 100644
index 000000000..ec81a9cee
--- /dev/null
+++ b/experimental/firefox-esr/endian-gfx.patch
@@ -0,0 +1,32 @@
+
+# HG changeset patch
+# User Lee Salzman <lsalzman@mozilla.com>
+# Date 1540234148 14400
+# Node ID f0f7573deea111d97bc96aa6b33e2518ee89da3a
+# Parent 2ce8f6d1a64ef8ee845c595bc441234af72422fe
+Bug 1500709 - fix big-endian RGBBitShift in Swizzle. r=me
+CLOSED TREE
+
+diff --git a/gfx/2d/Swizzle.cpp b/gfx/2d/Swizzle.cpp
+--- a/gfx/2d/Swizzle.cpp
++++ b/gfx/2d/Swizzle.cpp
+@@ -82,17 +82,17 @@ AlphaByteIndex(SurfaceFormat aFormat)
+
+ // The endian-dependent bit shift to access RGB of a UINT32 pixel.
+ static constexpr uint32_t
+ RGBBitShift(SurfaceFormat aFormat)
+ {
+ #if MOZ_LITTLE_ENDIAN
+ return 8 * RGBByteIndex(aFormat);
+ #else
+- return 24 - 8 * RGBByteIndex(aFormat);
++ return 8 - 8 * RGBByteIndex(aFormat);
+ #endif
+ }
+
+ // The endian-dependent bit shift to access alpha of a UINT32 pixel.
+ static constexpr uint32_t
+ AlphaBitShift(SurfaceFormat aFormat)
+ {
+ return (RGBBitShift(aFormat) + 24) % 32;
+
diff --git a/experimental/firefox-esr/endianness-js.patch b/experimental/firefox-esr/endianness-js.patch
new file mode 100644
index 000000000..98e1bd092
--- /dev/null
+++ b/experimental/firefox-esr/endianness-js.patch
@@ -0,0 +1,144 @@
+# HG changeset patch
+# User Steve Fink <sfink@mozilla.com>
+# Date 1536603384 25200
+# Mon Sep 10 11:16:24 2018 -0700
+# Node ID f598dceb588d1adf503d30acf4e0915d07d34006
+# Parent b7dd3969261896020d7a9449d22f350a97e3517a
+# EXP-Topic b1488552.enD
+Bug 1488552 - JSString flags bit must alias the low 32 bits of JSObject.group_, not the high 32. r=tcampbell
+
+diff --git a/js/src/gc/RelocationOverlay.h b/js/src/gc/RelocationOverlay.h
+--- a/js/src/gc/RelocationOverlay.h
++++ b/js/src/gc/RelocationOverlay.h
+@@ -29,24 +29,35 @@ struct Cell;
+ * This structure overlays a Cell that has been moved and provides a way to find
+ * its new location. It's used during generational and compacting GC.
+ */
+ class RelocationOverlay
+ {
+ /* See comment in js/public/HeapAPI.h. */
+ static const uint32_t Relocated = js::gc::Relocated;
+
++#if MOZ_LITTLE_ENDIAN
+ /*
+- * Keep the low 32 bits untouched. Use them to distinguish strings from
++ * Keep the first 32 bits untouched. Use them to distinguish strings from
+ * objects in the nursery.
+ */
+ uint32_t preserve_;
+
+ /* Set to Relocated when moved. */
+ uint32_t magic_;
++#elif JS_BITS_PER_WORD == 64
++ /*
++ * On big-endian, we need to reorder to keep preserve_ lined up with the
++ * low 32 bits of the aligned group_ pointer in JSObject.
++ */
++ uint32_t magic_;
++ uint32_t preserve_;
++#else
++# error "Support for 32-bit big-endian architectures is untested. See bug 1488552."
++#endif
+
+ /* The location |this| was moved to. */
+ Cell* newLocation_;
+
+ /* A list entry to track all relocated things. */
+ RelocationOverlay* next_;
+
+ public:
+diff --git a/js/src/vm/StringType.h b/js/src/vm/StringType.h
+--- a/js/src/vm/StringType.h
++++ b/js/src/vm/StringType.h
+@@ -2,16 +2,17 @@
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+ #ifndef vm_StringType_h
+ #define vm_StringType_h
+
++#include "mozilla/EndianUtils.h"
+ #include "mozilla/MemoryReporting.h"
+ #include "mozilla/PodOperations.h"
+ #include "mozilla/Range.h"
+
+ #include "jsapi.h"
+ #include "jsfriendapi.h"
+
+ #include "builtin/String.h"
+@@ -161,18 +162,30 @@ class JSString : public js::gc::Cell
+ static const size_t NUM_INLINE_CHARS_LATIN1 = 2 * sizeof(void*) / sizeof(JS::Latin1Char);
+ static const size_t NUM_INLINE_CHARS_TWO_BYTE = 2 * sizeof(void*) / sizeof(char16_t);
+
+ /* Fields only apply to string types commented on the right. */
+ struct Data
+ {
+ union {
+ struct {
++#if MOZ_LITTLE_ENDIAN
+ uint32_t flags; /* JSString */
+ uint32_t length; /* JSString */
++#elif JS_BITS_PER_WORD == 64
++ /*
++ * On big-endian, we need to reorder to keep flags lined up
++ * with the low 32 bits of the aligned group_ pointer in
++ * JSObject.
++ */
++ uint32_t length; /* JSString */
++ uint32_t flags; /* JSString */
++#else
++# error "Support for 32-bit big-endian architectures is untested. See bug 1488552."
++#endif
+ };
+ uintptr_t flattenData; /* JSRope (temporary while flattening) */
+ } u1;
+ union {
+ union {
+ /* JS(Fat)InlineString */
+ JS::Latin1Char inlineStorageLatin1[NUM_INLINE_CHARS_LATIN1];
+ char16_t inlineStorageTwoByte[NUM_INLINE_CHARS_TWO_BYTE];
+--- thunderbird-60.2.1/js/src/gc/Marking-inl.h.old 2018-10-01 14:51:12.000000000 +0000
++++ thunderbird-60.2.1/js/src/gc/Marking-inl.h 2018-10-12 19:08:28.260000000 +0000
+@@ -92,10 +92,10 @@
+ MOZ_ASSERT(!isForwarded());
+ // The location of magic_ is important because it must never be valid to see
+ // the value Relocated there in a GC thing that has not been moved.
+- static_assert(offsetof(RelocationOverlay, magic_) == offsetof(JSObject, group_) + sizeof(uint32_t),
+- "RelocationOverlay::magic_ is in the wrong location");
+- static_assert(offsetof(RelocationOverlay, magic_) == offsetof(js::Shape, base_) + sizeof(uint32_t),
+- "RelocationOverlay::magic_ is in the wrong location");
++ //static_assert(offsetof(RelocationOverlay, magic_) == offsetof(JSObject, group_) + sizeof(uint32_t),
++ // "RelocationOverlay::magic_ is in the wrong location");
++ //static_assert(offsetof(RelocationOverlay, magic_) == offsetof(js::Shape, base_) + sizeof(uint32_t),
++ // "RelocationOverlay::magic_ is in the wrong location");
+ static_assert(offsetof(RelocationOverlay, magic_) == offsetof(JSString, d.u1.length),
+ "RelocationOverlay::magic_ is in the wrong location");
+ magic_ = Relocated;
+--- thunderbird-60.2.1/js/src/jsfriendapi.h.old 2018-10-01 14:51:13.000000000 +0000
++++ thunderbird-60.2.1/js/src/jsfriendapi.h 2018-10-12 19:12:06.190000000 +0000
+@@ -9,6 +9,7 @@
+
+ #include "mozilla/Atomics.h"
+ #include "mozilla/Casting.h"
++#include "mozilla/EndianUtils.h"
+ #include "mozilla/Maybe.h"
+ #include "mozilla/MemoryReporting.h"
+ #include "mozilla/UniquePtr.h"
+@@ -640,8 +641,15 @@
+ static const uint32_t LATIN1_CHARS_BIT = JS_BIT(6);
+ static const uint32_t EXTERNAL_FLAGS = LINEAR_BIT | NON_ATOM_BIT | JS_BIT(5);
+ static const uint32_t TYPE_FLAGS_MASK = JS_BIT(6) - 1;
++#if MOZ_LITTLE_ENDIAN
+ uint32_t flags;
+ uint32_t length;
++#elif JS_BITS_PER_WORD == 64
++ uint32_t length;
++ uint32_t flags;
++#else
++# error "Support for 32-bit big-endian architectures is untested. See bug 1488552."
++#endif
+ union {
+ const JS::Latin1Char* nonInlineCharsLatin1;
+ const char16_t* nonInlineCharsTwoByte;
diff --git a/experimental/firefox-esr/firefox-safe.desktop b/experimental/firefox-esr/firefox-safe.desktop
new file mode 100644
index 000000000..1538fc674
--- /dev/null
+++ b/experimental/firefox-esr/firefox-safe.desktop
@@ -0,0 +1,11 @@
+[Desktop Entry]
+Encoding=UTF-8
+Exec=firefox -safe-mode %u
+Icon=firefox
+Type=Application
+Terminal=false
+MultipleArgs=false
+Name=Firefox - Safe Mode
+GenericName=Web Browser - Safe Mode
+StartupNotify=false
+Categories=Network;WebBrowser;
diff --git a/experimental/firefox-esr/firefox.desktop b/experimental/firefox-esr/firefox.desktop
new file mode 100644
index 000000000..d048ce46c
--- /dev/null
+++ b/experimental/firefox-esr/firefox.desktop
@@ -0,0 +1,81 @@
+[Desktop Entry]
+Exec=firefox %u
+Icon=firefox
+Type=Application
+Terminal=false
+Name=Firefox
+Name[bn]=ফায়ারফক্স3
+Name[eo]=Fajrovulpo3
+Name[fi]=Firefox3
+Name[pa]=ਫਾਇਰਫੋਕਸ3
+Name[tg]=Рӯбоҳи оташин3
+GenericName=Web Browser
+GenericName[af]=Web Blaaier
+GenericName[ar]=متصفح ويب
+GenericName[az]=Veb Səyyahı
+GenericName[bg]=Браузър
+GenericName[bn]=ওয়েব ব্রাউজার
+GenericName[br]=Furcher ar Gwiad
+GenericName[bs]=WWW Preglednik
+GenericName[ca]=Fullejador web
+GenericName[cs]=WWW prohlížeč
+GenericName[cy]=Porydd Gwe
+GenericName[da]=Browser
+GenericName[de]=Web-Browser
+GenericName[el]=Περιηγητής Ιστού
+GenericName[eo]=TTT-legilo
+GenericName[es]=Navegador web
+GenericName[et]=Veebilehitseja
+GenericName[eu]=Web arakatzailea
+GenericName[fa]=مرورگر وب
+GenericName[fi]=WWW-selain
+GenericName[fo]=Alnótsfar
+GenericName[fr]=Navigateur web
+GenericName[gl]=Navegador Web
+GenericName[he]=דפדפן אינטרנט
+GenericName[hi]=वेब ब्राउज़र
+GenericName[hr]=Web preglednik
+GenericName[hu]=Webböngésző
+GenericName[is]=Vafri
+GenericName[it]=Browser Web
+GenericName[ja]=ウェブブラウザ
+GenericName[ko]=웹 브라우저
+GenericName[lo]=ເວັບບຣາວເຊີ
+GenericName[lt]=Žiniatinklio naršyklė
+GenericName[lv]=Web Pārlūks
+GenericName[mk]=Прелистувач на Интернет
+GenericName[mn]=Веб-Хөтөч
+GenericName[nb]=Nettleser
+GenericName[nds]=Nettkieker
+GenericName[nl]=Webbrowser
+GenericName[nn]=Nettlesar
+GenericName[nso]=Seinyakisi sa Web
+GenericName[pa]=ਵੈਬ ਝਲਕਾਰਾ
+GenericName[pl]=Przeglądarka WWW
+GenericName[pt]=Navegador Web
+GenericName[pt_BR]=Navegador Web
+GenericName[ro]=Navigator de web
+GenericName[ru]=Веб-браузер
+GenericName[se]=Fierpmádatlogan
+GenericName[sk]=Webový prehliadač
+GenericName[sl]=Spletni brskalnik
+GenericName[sr]=Веб претраживач
+GenericName[sr@Latn]=Veb pretraživač
+GenericName[ss]=Ibrawuza yeWeb
+GenericName[sv]=Webbläsare
+GenericName[ta]=வலை உலாவி
+GenericName[tg]=Тафсиргари вэб
+GenericName[th]=เว็บบราวเซอร์
+GenericName[tr]=Web Tarayıcı
+GenericName[uk]=Навігатор Тенет
+GenericName[uz]=Веб-браузер
+GenericName[ven]=Buronza ya Webu
+GenericName[vi]=Trình duyệt Web
+GenericName[wa]=Betchteu waibe
+GenericName[xh]=Umkhangeli zincwadi we Web
+GenericName[zh_CN]=网页浏览器
+GenericName[zh_TW]=網頁瀏覽器
+GenericName[zu]=Umcingi we-Web
+MimeType=text/html;
+StartupNotify=true
+Categories=Network;WebBrowser;
diff --git a/experimental/firefox-esr/fix-arm-atomics-grsec.patch b/experimental/firefox-esr/fix-arm-atomics-grsec.patch
new file mode 100644
index 000000000..0eb58f093
--- /dev/null
+++ b/experimental/firefox-esr/fix-arm-atomics-grsec.patch
@@ -0,0 +1,306 @@
+--- mozilla-release/ipc/chromium/src/base/atomicops_internals_arm_gcc.h.orig
++++ mozilla-release/ipc/chromium/src/base/atomicops_internals_arm_gcc.h
+@@ -12,43 +35,194 @@
+ namespace base {
+ namespace subtle {
+
+-// 0xffff0fc0 is the hard coded address of a function provided by
+-// the kernel which implements an atomic compare-exchange. On older
+-// ARM architecture revisions (pre-v6) this may be implemented using
+-// a syscall. This address is stable, and in active use (hard coded)
+-// by at least glibc-2.7 and the Android C library.
+-typedef Atomic32 (*LinuxKernelCmpxchgFunc)(Atomic32 old_value,
+- Atomic32 new_value,
+- volatile Atomic32* ptr);
+-LinuxKernelCmpxchgFunc pLinuxKernelCmpxchg __attribute__((weak)) =
+- (LinuxKernelCmpxchgFunc) 0xffff0fc0;
++// Memory barriers on ARM are funky, but the kernel is here to help:
++//
++// * ARMv5 didn't support SMP, there is no memory barrier instruction at
++// all on this architecture, or when targeting its machine code.
++//
++// * Some ARMv6 CPUs support SMP. A full memory barrier can be produced by
++// writing a random value to a very specific coprocessor register.
++//
++// * On ARMv7, the "dmb" instruction is used to perform a full memory
++// barrier (though writing to the co-processor will still work).
++// However, on single core devices (e.g. Nexus One, or Nexus S),
++// this instruction will take up to 200 ns, which is huge, even though
++// it's completely un-needed on these devices.
++//
++// * There is no easy way to determine at runtime if the device is
++// single or multi-core. However, the kernel provides a useful helper
++// function at a fixed memory address (0xffff0fa0), which will always
++// perform a memory barrier in the most efficient way. I.e. on single
++// core devices, this is an empty function that exits immediately.
++// On multi-core devices, it implements a full memory barrier.
++//
++// * This source could be compiled to ARMv5 machine code that runs on a
++// multi-core ARMv6 or ARMv7 device. In this case, memory barriers
++// are needed for correct execution. Always call the kernel helper, even
++// when targeting ARMv5TE.
++//
+
+-typedef void (*LinuxKernelMemoryBarrierFunc)(void);
+-LinuxKernelMemoryBarrierFunc pLinuxKernelMemoryBarrier __attribute__((weak)) =
+- (LinuxKernelMemoryBarrierFunc) 0xffff0fa0;
++inline void MemoryBarrier() {
++#if defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) || \
++ defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__)
++ __asm__ __volatile__("dmb ish" ::: "memory");
++#elif defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || \
++ defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) || \
++ defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_6T2__)
++ __asm__ __volatile__("mcr p15,0,r0,c7,c10,5" ::: "memory");
++#elif defined(__linux__) || defined(__ANDROID__)
++ // Note: This is a function call, which is also an implicit compiler barrier.
++ typedef void (*KernelMemoryBarrierFunc)();
++ ((KernelMemoryBarrierFunc)0xffff0fa0)();
++#error MemoryBarrier() is not implemented on this platform.
++#endif
++}
+
++// An ARM toolchain would only define one of these depending on which
++// variant of the target architecture is being used. This tests against
++// any known ARMv6 or ARMv7 variant, where it is possible to directly
++// use ldrex/strex instructions to implement fast atomic operations.
++#if defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) || \
++ defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) || \
++ defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || \
++ defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) || \
++ defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_6T2__)
+
+ inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
+ Atomic32 old_value,
+ Atomic32 new_value) {
+- Atomic32 prev_value = *ptr;
++ Atomic32 prev_value;
++ int reloop;
+ do {
+- if (!pLinuxKernelCmpxchg(old_value, new_value,
+- const_cast<Atomic32*>(ptr))) {
+- return old_value;
+- }
+- prev_value = *ptr;
+- } while (prev_value == old_value);
++ // The following is equivalent to:
++ //
++ // prev_value = LDREX(ptr)
++ // reloop = 0
++ // if (prev_value != old_value)
++ // reloop = STREX(ptr, new_value)
++ __asm__ __volatile__(" ldrex %0, [%3]\n"
++ " mov %1, #0\n"
++ " cmp %0, %4\n"
++#ifdef __thumb2__
++ " it eq\n"
++#endif
++ " strexeq %1, %5, [%3]\n"
++ : "=&r"(prev_value), "=&r"(reloop), "+m"(*ptr)
++ : "r"(ptr), "r"(old_value), "r"(new_value)
++ : "cc", "memory");
++ } while (reloop != 0);
+ return prev_value;
+ }
+
++inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
++ Atomic32 old_value,
++ Atomic32 new_value) {
++ Atomic32 result = NoBarrier_CompareAndSwap(ptr, old_value, new_value);
++ MemoryBarrier();
++ return result;
++}
++
++inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
++ Atomic32 old_value,
++ Atomic32 new_value) {
++ MemoryBarrier();
++ return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
++}
++
++inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr,
++ Atomic32 increment) {
++ Atomic32 value;
++ int reloop;
++ do {
++ // Equivalent to:
++ //
++ // value = LDREX(ptr)
++ // value += increment
++ // reloop = STREX(ptr, value)
++ //
++ __asm__ __volatile__(" ldrex %0, [%3]\n"
++ " add %0, %0, %4\n"
++ " strex %1, %0, [%3]\n"
++ : "=&r"(value), "=&r"(reloop), "+m"(*ptr)
++ : "r"(ptr), "r"(increment)
++ : "cc", "memory");
++ } while (reloop);
++ return value;
++}
++
++inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr,
++ Atomic32 increment) {
++ // TODO(digit): Investigate if it's possible to implement this with
++ // a single MemoryBarrier() operation between the LDREX and STREX.
++ // See http://crbug.com/246514
++ MemoryBarrier();
++ Atomic32 result = NoBarrier_AtomicIncrement(ptr, increment);
++ MemoryBarrier();
++ return result;
++}
++
+ inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr,
+ Atomic32 new_value) {
+ Atomic32 old_value;
++ int reloop;
+ do {
++ // old_value = LDREX(ptr)
++ // reloop = STREX(ptr, new_value)
++ __asm__ __volatile__(" ldrex %0, [%3]\n"
++ " strex %1, %4, [%3]\n"
++ : "=&r"(old_value), "=&r"(reloop), "+m"(*ptr)
++ : "r"(ptr), "r"(new_value)
++ : "cc", "memory");
++ } while (reloop != 0);
++ return old_value;
++}
++
++// This tests against any known ARMv5 variant.
++#elif defined(__ARM_ARCH_5__) || defined(__ARM_ARCH_5T__) || \
++ defined(__ARM_ARCH_5TE__) || defined(__ARM_ARCH_5TEJ__)
++
++// The kernel also provides a helper function to perform an atomic
++// compare-and-swap operation at the hard-wired address 0xffff0fc0.
++// On ARMv5, this is implemented by a special code path that the kernel
++// detects and treats specially when thread pre-emption happens.
++// On ARMv6 and higher, it uses LDREX/STREX instructions instead.
++//
++// Note that this always perform a full memory barrier, there is no
++// need to add calls MemoryBarrier() before or after it. It also
++// returns 0 on success, and 1 on exit.
++//
++// Available and reliable since Linux 2.6.24. Both Android and ChromeOS
++// use newer kernel revisions, so this should not be a concern.
++namespace {
++
++inline int LinuxKernelCmpxchg(Atomic32 old_value,
++ Atomic32 new_value,
++ volatile Atomic32* ptr) {
++ typedef int (*KernelCmpxchgFunc)(Atomic32, Atomic32, volatile Atomic32*);
++ return ((KernelCmpxchgFunc)0xffff0fc0)(old_value, new_value, ptr);
++}
++
++} // namespace
++
++inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
++ Atomic32 old_value,
++ Atomic32 new_value) {
++ Atomic32 prev_value;
++ for (;;) {
++ prev_value = *ptr;
++ if (prev_value != old_value)
++ return prev_value;
++ if (!LinuxKernelCmpxchg(old_value, new_value, ptr))
++ return old_value;
++ }
++}
++
++inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr,
++ Atomic32 new_value) {
++ Atomic32 old_value;
++ do {
+ old_value = *ptr;
+- } while (pLinuxKernelCmpxchg(old_value, new_value,
+- const_cast<Atomic32*>(ptr)));
++ } while (LinuxKernelCmpxchg(old_value, new_value, ptr));
+ return old_value;
+ }
+
+@@ -63,36 +237,57 @@
+ // Atomic exchange the old value with an incremented one.
+ Atomic32 old_value = *ptr;
+ Atomic32 new_value = old_value + increment;
+- if (pLinuxKernelCmpxchg(old_value, new_value,
+- const_cast<Atomic32*>(ptr)) == 0) {
++ if (!LinuxKernelCmpxchg(old_value, new_value, ptr)) {
+ // The exchange took place as expected.
+ return new_value;
+ }
+ // Otherwise, *ptr changed mid-loop and we need to retry.
+ }
+-
+ }
+
+ inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
+ Atomic32 old_value,
+ Atomic32 new_value) {
+- return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
++ Atomic32 prev_value;
++ for (;;) {
++ prev_value = *ptr;
++ if (prev_value != old_value) {
++ // Always ensure acquire semantics.
++ MemoryBarrier();
++ return prev_value;
++ }
++ if (!LinuxKernelCmpxchg(old_value, new_value, ptr))
++ return old_value;
++ }
+ }
+
+ inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
+ Atomic32 old_value,
+ Atomic32 new_value) {
+- return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
++ // This could be implemented as:
++ // MemoryBarrier();
++ // return NoBarrier_CompareAndSwap();
++ //
++ // But would use 3 barriers per succesful CAS. To save performance,
++ // use Acquire_CompareAndSwap(). Its implementation guarantees that:
++ // - A succesful swap uses only 2 barriers (in the kernel helper).
++ // - An early return due to (prev_value != old_value) performs
++ // a memory barrier with no store, which is equivalent to the
++ // generic implementation above.
++ return Acquire_CompareAndSwap(ptr, old_value, new_value);
+ }
+
++#else
++# error "Your CPU's ARM architecture is not supported yet"
++#endif
++
++// NOTE: Atomicity of the following load and store operations is only
++// guaranteed in case of 32-bit alignement of |ptr| values.
++
+ inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) {
+ *ptr = value;
+ }
+
+-inline void MemoryBarrier() {
+- pLinuxKernelMemoryBarrier();
+-}
+-
+ inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) {
+ *ptr = value;
+ MemoryBarrier();
+@@ -103,9 +298,7 @@
+ *ptr = value;
+ }
+
+-inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) {
+- return *ptr;
+-}
++inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) { return *ptr; }
+
+ inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) {
+ Atomic32 value = *ptr;
+@@ -118,7 +311,6 @@
+ return *ptr;
+ }
+
+-} // namespace base::subtle
+-} // namespace base
++} } // namespace base::subtle
+
+ #endif // BASE_ATOMICOPS_INTERNALS_ARM_GCC_H_
diff --git a/experimental/firefox-esr/fix-arm-version-detect.patch b/experimental/firefox-esr/fix-arm-version-detect.patch
new file mode 100644
index 000000000..c0c2a2e83
--- /dev/null
+++ b/experimental/firefox-esr/fix-arm-version-detect.patch
@@ -0,0 +1,13 @@
+diff --git a/build/autoconf/arch.m4 b/build/autoconf/arch.m4
+index b62ea71..53179a7 100644
+--- a/build/autoconf/arch.m4
++++ b/build/autoconf/arch.m4
+@@ -215,7 +215,7 @@ if test "$CPU_ARCH" = "arm"; then
+
+ AC_MSG_CHECKING(ARM version support in compiler)
+ dnl Determine the target ARM architecture (5 for ARMv5, v5T, v5E, etc.; 6 for ARMv6, v6K, etc.)
+- ARM_ARCH=`${CC-cc} ${CFLAGS} -dM -E - < /dev/null | sed -n 's/.*__ARM_ARCH_\([[0-9]][[0-9]]*\).*/\1/p'`
++ ARM_ARCH=`${CC-cc} ${CFLAGS} -dM -E - < /dev/null | sed -n 's/.*__ARM_ARCH_\([[0-9]][[0-9]]*\).*/\1/p' | head -n 1`
+ AC_MSG_RESULT("$ARM_ARCH")
+
+ AC_MSG_CHECKING(for ARM NEON support in compiler)
diff --git a/experimental/firefox-esr/fix-bug-1261392.patch b/experimental/firefox-esr/fix-bug-1261392.patch
new file mode 100644
index 000000000..1f7a36af3
--- /dev/null
+++ b/experimental/firefox-esr/fix-bug-1261392.patch
@@ -0,0 +1,25 @@
+--- a/tools/profiler/core/platform.h 2017-05-27 11:44:06.733119794 +0000
++++ b/tools/profiler/core/platform.h 2017-05-27 11:46:16.004253520 +0000
+@@ -54,10 +54,11 @@
+ #include <vector>
+ #include "StackTop.h"
+
+-// We need a definition of gettid(), but glibc doesn't provide a
+-// wrapper for it.
+-#if defined(__GLIBC__)
++// We need a definition of gettid(), but Linux libc implementations don't
++// provide a wrapper for it (except for Bionic)
++#if defined(__linux__)
+ #include <unistd.h>
++#if !defined(__BIONIC__)
+ #include <sys/syscall.h>
+ static inline pid_t gettid()
+ {
+@@ -71,6 +72,7 @@
+ return (pid_t) syscall(SYS_thread_selfid);
+ }
+ #endif
++#endif
+
+ #ifdef XP_WIN
+ #include <windows.h>
diff --git a/experimental/firefox-esr/fix-fortify-inline.patch b/experimental/firefox-esr/fix-fortify-inline.patch
new file mode 100644
index 000000000..2498c57fc
--- /dev/null
+++ b/experimental/firefox-esr/fix-fortify-inline.patch
@@ -0,0 +1,11 @@
+--- a/media/webrtc/signaling/src/sdp/sipcc/sdp_os_defs.h
++++ b/media/webrtc/signaling/src/sdp/sipcc/sdp_os_defs.h
+@@ -27,8 +27,5 @@
+ typedef int16_t int16;
+ typedef unsigned short ushort;
+ typedef unsigned long ulong;
+-#ifndef __GNUC_STDC_INLINE__
+-#define inline
+-#endif
+
+ #endif /* _SDP_OS_DEFS_H_ */
diff --git a/experimental/firefox-esr/fix-mutex-build.patch b/experimental/firefox-esr/fix-mutex-build.patch
new file mode 100644
index 000000000..f5a2d1321
--- /dev/null
+++ b/experimental/firefox-esr/fix-mutex-build.patch
@@ -0,0 +1,20 @@
+--- firefox-60.3.0/memory/build/Mutex.h.old 2018-10-17 20:39:32.000000000 +0000
++++ firefox-60.3.0/memory/build/Mutex.h 2018-10-26 05:22:54.980000000 +0000
+@@ -39,7 +39,7 @@
+ }
+ #elif defined(XP_DARWIN)
+ mMutex = OS_SPINLOCK_INIT;
+-#elif defined(XP_LINUX) && !defined(ANDROID)
++#elif defined(XP_LINUX) && defined(__GLIBC__)
+ pthread_mutexattr_t attr;
+ if (pthread_mutexattr_init(&attr) != 0) {
+ return false;
+@@ -107,7 +107,7 @@
+
+ #if defined(XP_DARWIN)
+ #define STATIC_MUTEX_INIT OS_SPINLOCK_INIT
+-#elif defined(XP_LINUX) && !defined(ANDROID)
++#elif defined(XP_LINUX) && defined(__GLIBC__)
+ #define STATIC_MUTEX_INIT PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP
+ #else
+ #define STATIC_MUTEX_INIT PTHREAD_MUTEX_INITIALIZER
diff --git a/experimental/firefox-esr/fix-seccomp-bpf.patch b/experimental/firefox-esr/fix-seccomp-bpf.patch
new file mode 100644
index 000000000..47cde56c7
--- /dev/null
+++ b/experimental/firefox-esr/fix-seccomp-bpf.patch
@@ -0,0 +1,14 @@
+--- a/security/sandbox/chromium/sandbox/linux/seccomp-bpf/trap.cc.orig 2015-09-23 09:10:08.812740571 +0200
++++ b/security/sandbox/chromium/sandbox/linux/seccomp-bpf/trap.cc 2015-09-23 09:11:38.404746155 +0200
+@@ -23,6 +23,11 @@
+ #include "sandbox/linux/services/android_ucontext.h"
+ #endif
+
++// musl libc defines siginfo_t __si_fields instead of _sifields
++#if defined(OS_LINUX) && !defined(__GLIBC__)
++#define _sifields __si_fields
++#endif
++
+ namespace {
+
+ struct arch_sigsys {
diff --git a/experimental/firefox-esr/fix-stack-overflow.patch b/experimental/firefox-esr/fix-stack-overflow.patch
new file mode 100644
index 000000000..e164fc69b
--- /dev/null
+++ b/experimental/firefox-esr/fix-stack-overflow.patch
@@ -0,0 +1,45 @@
+https://bugs.alpinelinux.org/issues/5559
+https://bugzilla.mozilla.org/show_bug.cgi?id=1274732
+
+diff --git a/netwerk/streamconv/converters/nsHTTPCompressConv.cpp b/netwerk/streamconv/converters/nsHTTPCompressConv.cpp
+index 1193529..aeb96b5 100644
+--- a/netwerk/streamconv/converters/nsHTTPCompressConv.cpp
++++ b/netwerk/streamconv/converters/nsHTTPCompressConv.cpp
+@@ -165,9 +165,8 @@ nsHTTPCompressConv::BrotliHandler(nsIInputStream *stream, void *closure, const c
+ nsHTTPCompressConv *self = static_cast<nsHTTPCompressConv *>(closure);
+ *countRead = 0;
+
+- const uint32_t kOutSize = 128 * 1024; // just a chunk size, we call in a loop
+- unsigned char outBuffer[kOutSize];
+- unsigned char *outPtr;
++ const size_t kOutSize = 128 * 1024; // just a chunk size, we call in a loop
++ uint8_t *outPtr;
+ size_t outSize;
+ size_t avail = aAvail;
+ BrotliResult res;
+@@ -177,9 +176,15 @@ nsHTTPCompressConv::BrotliHandler(nsIInputStream *stream, void *closure, const c
+ return NS_OK;
+ }
+
++ auto outBuffer = MakeUniqueFallible<uint8_t[]>(kOutSize);
++ if (outBuffer == nullptr) {
++ self->mBrotli->mStatus = NS_ERROR_OUT_OF_MEMORY;
++ return self->mBrotli->mStatus;
++ }
++
+ do {
+ outSize = kOutSize;
+- outPtr = outBuffer;
++ outPtr = outBuffer.get();
+
+ // brotli api is documented in brotli/dec/decode.h and brotli/dec/decode.c
+ LOG(("nsHttpCompresssConv %p brotlihandler decompress %d\n", self, avail));
+@@ -210,7 +215,7 @@ nsHTTPCompressConv::BrotliHandler(nsIInputStream *stream, void *closure, const c
+ nsresult rv = self->do_OnDataAvailable(self->mBrotli->mRequest,
+ self->mBrotli->mContext,
+ self->mBrotli->mSourceOffset,
+- reinterpret_cast<const char *>(outBuffer),
++ reinterpret_cast<const char *>(outBuffer.get()),
+ outSize);
+ LOG(("nsHttpCompressConv %p BrotliHandler ODA rv=%x", self, rv));
+ if (NS_FAILED(rv)) {
diff --git a/experimental/firefox-esr/mallinfo.patch b/experimental/firefox-esr/mallinfo.patch
new file mode 100644
index 000000000..9959b52a4
--- /dev/null
+++ b/experimental/firefox-esr/mallinfo.patch
@@ -0,0 +1,20 @@
+diff --git a/xpcom/base/nsMemoryReporterManager.cpp b/xpcom/base/nsMemoryReporterManager.cpp
+index 89ee563..eab8cd7 100644
+--- a/xpcom/base/nsMemoryReporterManager.cpp
++++ b/xpcom/base/nsMemoryReporterManager.cpp
+@@ -153,6 +153,7 @@ ResidentUniqueDistinguishedAmount(int64_t* aN)
+ return GetProcSelfSmapsPrivate(aN);
+ }
+
++#ifdef __GLIBC__
+ #define HAVE_SYSTEM_HEAP_REPORTER 1
+ nsresult
+ SystemHeapSize(int64_t* aSizeOut)
+@@ -172,6 +173,7 @@ SystemHeapSize(int64_t* aSizeOut)
+ *aSizeOut = size_t(info.hblkhd) + size_t(info.uordblks);
+ return NS_OK;
+ }
++#endif
+
+ #elif defined(__DragonFly__) || defined(__FreeBSD__) \
+ || defined(__NetBSD__) || defined(__OpenBSD__) \
diff --git a/experimental/firefox-esr/missing-header-s390x.patch b/experimental/firefox-esr/missing-header-s390x.patch
new file mode 100644
index 000000000..39f4e2bc0
--- /dev/null
+++ b/experimental/firefox-esr/missing-header-s390x.patch
@@ -0,0 +1,12 @@
+diff --git a/dom/filesystem/compat/FileSystemDirectoryReader.h b/dom/filesystem/compat/FileSystemDirectoryReader.h
+index d568990..12265f9 100644
+--- a/dom/filesystem/compat/FileSystemDirectoryReader.h
++++ b/dom/filesystem/compat/FileSystemDirectoryReader.h
+@@ -11,6 +11,7 @@
+ #include "mozilla/ErrorResult.h"
+ #include "mozilla/dom/BindingDeclarations.h"
+ #include "nsCycleCollectionParticipant.h"
++#include "mozilla/dom/FileSystemDirectoryEntry.h"
+ #include "nsWrapperCache.h"
+
+ namespace mozilla {
diff --git a/experimental/firefox-esr/mozconfig b/experimental/firefox-esr/mozconfig
new file mode 100644
index 000000000..f1c15cc01
--- /dev/null
+++ b/experimental/firefox-esr/mozconfig
@@ -0,0 +1,28 @@
+ac_add_options --prefix=/usr
+ac_add_options --libdir=/usr/lib
+ac_add_options --disable-crashreporter
+ac_add_options --disable-install-strip
+ac_add_options --disable-jemalloc
+ac_add_options --disable-profiling
+ac_add_options --disable-strip
+ac_add_options --disable-tests
+ac_add_options --disable-updater
+ac_add_options --enable-alsa
+ac_add_options --enable-dbus
+ac_add_options --enable-default-toolkit=cairo-gtk3
+ac_add_options --enable-official-branding
+ac_add_options --enable-pie
+ac_add_options --enable-pulseaudio
+ac_add_options --enable-startup-notification
+ac_add_options --enable-system-ffi
+ac_add_options --enable-system-hunspell
+ac_add_options --with-pthreads
+ac_add_options --with-system-bz2
+ac_add_options --with-system-icu
+ac_add_options --with-system-jpeg
+ac_add_options --with-system-libevent
+ac_add_options --with-system-nspr
+ac_add_options --with-system-nss
+ac_add_options --with-system-pixman
+ac_add_options --with-system-png
+ac_add_options --with-system-zlib
diff --git a/experimental/firefox-esr/mozilla-build-arm.patch b/experimental/firefox-esr/mozilla-build-arm.patch
new file mode 100644
index 000000000..dcf2f6d8a
--- /dev/null
+++ b/experimental/firefox-esr/mozilla-build-arm.patch
@@ -0,0 +1,11 @@
+--- ./gfx/ycbcr/moz.build.orig 2014-04-03 13:50:38.990296661 +0000
++++ ./gfx/ycbcr/moz.build 2014-04-03 13:52:26.878268547 +0000
+@@ -59,7 +59,7 @@
+ 'yuv_row_other.cpp',
+ ]
+
+-if CONFIG['CPU_ARCH'] == 'arm' and CONFIG['HAVE_ARM_NEON']:
++if CONFIG['HAVE_ARM_NEON']:
+ SOURCES += [
+ 'yuv_row_arm.s',
+ ]
diff --git a/experimental/firefox-esr/musl-pthread-setname.patch b/experimental/firefox-esr/musl-pthread-setname.patch
new file mode 100644
index 000000000..3bf620219
--- /dev/null
+++ b/experimental/firefox-esr/musl-pthread-setname.patch
@@ -0,0 +1,14 @@
+--- a/js/src/threading/posix/Thread.cpp.orig 2016-09-20 22:19:46.368622126 +0200
++++ b/js/src/threading/posix/Thread.cpp 2016-09-20 22:23:35.495823534 +0200
+@@ -153,8 +153,10 @@
+ rv = 0;
+ #elif defined(__NetBSD__)
+ rv = pthread_setname_np(pthread_self(), "%s", (void*)name);
+-#else
++#elif defined(__GLIBC__)
+ rv = pthread_setname_np(pthread_self(), name);
++#else
++ rv = 0;
+ #endif
+ MOZ_RELEASE_ASSERT(!rv);
+ }
diff --git a/experimental/firefox-esr/proper-system-hunspell.patch b/experimental/firefox-esr/proper-system-hunspell.patch
new file mode 100644
index 000000000..056dacce6
--- /dev/null
+++ b/experimental/firefox-esr/proper-system-hunspell.patch
@@ -0,0 +1,22 @@
+moz seem to have no idea what their own damn build system is doing...
+
+--- thunderbird-52.6.0/extensions/spellcheck/hunspell/glue/moz.build 2018-01-24 03:06:15.000000000 +0000
++++ thunderbird-52.6.0/extensions/spellcheck/hunspell/glue/moz.build 2018-03-12 09:17:05.386773708 +0000
+@@ -16,6 +16,9 @@
+ if CONFIG['MOZ_SYSTEM_HUNSPELL']:
+ CXXFLAGS += CONFIG['MOZ_HUNSPELL_CFLAGS']
+ else:
++ # This variable is referenced in configure.in. Make sure to change that file
++ # too if you need to change this variable.
++ DEFINES['HUNSPELL_STATIC'] = True
+ LOCAL_INCLUDES += ['../src']
+
+ LOCAL_INCLUDES += [
+@@ -33,7 +36,3 @@
+ 'RemoteSpellCheckEngineChild.h',
+ 'RemoteSpellCheckEngineParent.h',
+ ]
+-
+-# This variable is referenced in configure.in. Make sure to change that file
+-# too if you need to change this variable.
+-DEFINES['HUNSPELL_STATIC'] = True
diff --git a/experimental/firefox-esr/python3.patch b/experimental/firefox-esr/python3.patch
new file mode 100644
index 000000000..b13be2229
--- /dev/null
+++ b/experimental/firefox-esr/python3.patch
@@ -0,0 +1,10397 @@
+--- firefox-52.9.0esr/python/mozbuild/dumbmake/dumbmake.py (original)
++++ firefox-52.9.0esr/python/mozbuild/dumbmake/dumbmake.py (refactored)
+@@ -2,7 +2,7 @@
+ # License, v. 2.0. If a copy of the MPL was not distributed with this
+ # file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+-from __future__ import absolute_import, unicode_literals
++
+
+ from collections import OrderedDict
+ from itertools import groupby
+@@ -36,7 +36,7 @@
+ deps = {}
+
+ for i, (indent, target) in enumerate(pairs):
+- if not deps.has_key(target):
++ if target not in deps:
+ deps[target] = []
+
+ for j in range(i+1, len(pairs)):
+@@ -68,7 +68,7 @@
+ del all_targets[dependency]
+ all_targets[dependency] = True
+
+- return all_targets.keys()
++ return list(all_targets.keys())
+
+ def get_components(path):
+ """Take a path and return all the components of the path."""
+@@ -114,7 +114,7 @@
+ make_dirs[make_dir] = True
+
+ all_components = []
+- for make_dir in make_dirs.iterkeys():
++ for make_dir in make_dirs.keys():
+ all_components.extend(get_components(make_dir))
+
+ for i in all_dependencies(*all_components, dependency_map=dependency_map):
+--- firefox-52.9.0esr/python/mozbuild/dumbmake/test/test_dumbmake.py (original)
++++ firefox-52.9.0esr/python/mozbuild/dumbmake/test/test_dumbmake.py (refactored)
+@@ -1,7 +1,7 @@
+ # This Source Code Form is subject to the terms of the Mozilla Public
+ # License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ # You can obtain one at http://mozilla.org/MPL/2.0/.
+-from __future__ import unicode_literals
++
+
+ import unittest
+
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/android_version_code.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/android_version_code.py (refactored)
+@@ -2,7 +2,7 @@
+ # License, v. 2.0. If a copy of the MPL was not distributed with this
+ # file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+-from __future__ import absolute_import, print_function
++
+
+ import argparse
+ import math
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/artifacts.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/artifacts.py (refactored)
+@@ -40,7 +40,7 @@
+ '''
+
+
+-from __future__ import absolute_import, print_function, unicode_literals
++
+
+ import collections
+ import functools
+@@ -57,7 +57,7 @@
+ import subprocess
+ import tarfile
+ import tempfile
+-import urlparse
++import urllib.parse
+ import zipfile
+
+ import pylru
+@@ -183,7 +183,7 @@
+
+ with JarWriter(file=processed_filename, optimize=False, compress_level=5) as writer:
+ reader = JarReader(filename)
+- for filename, entry in reader.entries.iteritems():
++ for filename, entry in reader.entries.items():
+ for pattern, (src_prefix, dest_prefix) in self.test_artifact_patterns:
+ if not mozpath.match(filename, pattern):
+ continue
+@@ -552,7 +552,7 @@
+
+ def print_cache(self):
+ with self:
+- for item in self._cache.items():
++ for item in list(self._cache.items()):
+ self.log(logging.INFO, 'artifact',
+ {'item': item},
+ '{item}')
+@@ -565,7 +565,7 @@
+ # We use the persisted LRU caches to our advantage. The first item is
+ # most recent.
+ with self:
+- item = next(self._cache.items(), None)
++ item = next(list(self._cache.items()), None)
+ if item is not None:
+ (name, args, sorted_kwargs), result = item
+ self.print_last_item(args, sorted_kwargs, result)
+@@ -593,10 +593,10 @@
+ 'changeset={changeset}&version=2&tipsonly=1')
+ req = requests.get(cset_url_tmpl.format(tree=tree, changeset=revision),
+ headers={'Accept': 'application/json'})
+- if req.status_code not in range(200, 300):
++ if req.status_code not in list(range(200, 300)):
+ raise ValueError
+ result = req.json()
+- [found_pushid] = result['pushes'].keys()
++ [found_pushid] = list(result['pushes'].keys())
+ return int(found_pushid)
+
+ @cachedmethod(operator.attrgetter('_cache'))
+@@ -609,7 +609,7 @@
+ headers={'Accept': 'application/json'})
+ result = req.json()
+ return [
+- p['changesets'][-1] for p in result['pushes'].values()
++ p['changesets'][-1] for p in list(result['pushes'].values())
+ ]
+
+ class TaskCache(CacheManager):
+@@ -847,7 +847,7 @@
+
+ candidate_pushheads = collections.defaultdict(list)
+
+- for tree, pushid in found_pushids.iteritems():
++ for tree, pushid in found_pushids.items():
+ end = pushid
+ start = pushid - NUM_PUSHHEADS_TO_QUERY_PER_PARENT
+
+@@ -1052,7 +1052,7 @@
+ """
+ if source and os.path.isfile(source):
+ return self.install_from_file(source, distdir)
+- elif source and urlparse.urlparse(source).scheme:
++ elif source and urllib.parse.urlparse(source).scheme:
+ return self.install_from_url(source, distdir)
+ else:
+ if source is None and 'MOZ_ARTIFACT_REVISION' in os.environ:
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/base.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/base.py (refactored)
+@@ -2,7 +2,7 @@
+ # License, v. 2.0. If a copy of the MPL was not distributed with this
+ # file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+-from __future__ import absolute_import, print_function, unicode_literals
++
+
+ import json
+ import logging
+@@ -482,7 +482,7 @@
+ for flag in flags:
+ if flag == '-j':
+ try:
+- flag = flags.next()
++ flag = next(flags)
+ except StopIteration:
+ break
+ try:
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/config_status.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/config_status.py (refactored)
+@@ -6,7 +6,7 @@
+ # drop-in replacement for autoconf 2.13's config.status, with features
+ # borrowed from autoconf > 2.5, and additional features.
+
+-from __future__ import absolute_import, print_function
++
+
+ import logging
+ import os
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/doctor.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/doctor.py (refactored)
+@@ -2,7 +2,7 @@
+ # License, v. 2.0. If a copy of the MPL was not distributed with this
+ # file, # You can obtain one at http://mozilla.org/MPL/2.0/.
+
+-from __future__ import absolute_import
++
+
+ import os
+ import subprocess
+@@ -83,7 +83,7 @@
+ valid = False
+ while not valid and limit > 0:
+ try:
+- choice = strtobool(raw_input(prompt + '[Y/N]\n'))
++ choice = strtobool(input(prompt + '[Y/N]\n'))
+ valid = True
+ except ValueError:
+ print("ERROR! Please enter a valid option!")
+@@ -103,11 +103,11 @@
+ if status == 'SKIPPED':
+ continue
+ self.results.append(result)
+- print('%s...\t%s\n' % (
++ print(('%s...\t%s\n' % (
+ result.get('desc', ''),
+ status
+ )
+- ).expandtabs(40)
++ ).expandtabs(40))
+
+ @property
+ def platform(self):
+@@ -212,7 +212,7 @@
+ fsutil_output = subprocess.check_output(command)
+ status = 'GOOD, FIXED'
+ desc = 'lastaccess disabled systemwide'
+- except subprocess.CalledProcessError, e:
++ except subprocess.CalledProcessError as e:
+ desc = 'lastaccess enabled systemwide'
+ if e.output.find('denied') != -1:
+ status = 'BAD, FIX DENIED'
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/dotproperties.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/dotproperties.py (refactored)
+@@ -5,7 +5,7 @@
+ # This file contains utility functions for reading .properties files, like
+ # region.properties.
+
+-from __future__ import absolute_import, unicode_literals
++
+
+ import codecs
+ import re
+@@ -14,7 +14,7 @@
+ if sys.version_info[0] == 3:
+ str_type = str
+ else:
+- str_type = basestring
++ str_type = str
+
+ class DotProperties:
+ r'''A thin representation of a key=value .properties file.'''
+@@ -52,7 +52,7 @@
+ if not prefix.endswith('.'):
+ prefix = prefix + '.'
+ indexes = []
+- for k, v in self._properties.iteritems():
++ for k, v in self._properties.items():
+ if not k.startswith(prefix):
+ continue
+ key = k[len(prefix):]
+@@ -73,7 +73,7 @@
+ if not prefix.endswith('.'):
+ prefix = prefix + '.'
+
+- D = dict((k[len(prefix):], v) for k, v in self._properties.iteritems()
++ D = dict((k[len(prefix):], v) for k, v in self._properties.items()
+ if k.startswith(prefix) and '.' not in k[len(prefix):])
+
+ for required_key in required_keys:
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/html_build_viewer.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/html_build_viewer.py (refactored)
+@@ -4,16 +4,16 @@
+
+ # This module contains code for running an HTTP server to view build info.
+
+-from __future__ import absolute_import, unicode_literals
+
+-import BaseHTTPServer
++
++import http.server
+ import json
+ import os
+
+ import requests
+
+
+-class HTTPHandler(BaseHTTPServer.BaseHTTPRequestHandler):
++class HTTPHandler(http.server.BaseHTTPRequestHandler):
+ def do_GET(self):
+ s = self.server.wrapper
+ p = self.path
+@@ -92,7 +92,7 @@
+ self.doc_root = doc_root
+ self.json_files = {}
+
+- self.server = BaseHTTPServer.HTTPServer((address, port), HTTPHandler)
++ self.server = http.server.HTTPServer((address, port), HTTPHandler)
+ self.server.wrapper = self
+ self.do_shutdown = False
+
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/jar.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/jar.py (refactored)
+@@ -8,7 +8,7 @@
+ See the documentation for jar.mn on MDC for further details on the format.
+ '''
+
+-from __future__ import absolute_import
++
+
+ import sys
+ import os
+@@ -17,7 +17,7 @@
+ import logging
+ from time import localtime
+ from MozZipFile import ZipFile
+-from cStringIO import StringIO
++from io import StringIO
+ from collections import defaultdict
+
+ from mozbuild.preprocessor import Preprocessor
+@@ -302,9 +302,9 @@
+ '''updateManifest replaces the % in the chrome registration entries
+ with the given chrome base path, and updates the given manifest file.
+ '''
+- myregister = dict.fromkeys(map(lambda s: s.replace('%',
+- chromebasepath), register))
+- addEntriesToListFile(manifestPath, myregister.iterkeys())
++ myregister = dict.fromkeys([s.replace('%',
++ chromebasepath) for s in register])
++ addEntriesToListFile(manifestPath, iter(myregister.keys()))
+
+ def makeJar(self, infile, jardir):
+ '''makeJar is the main entry point to JarMaker.
+@@ -322,7 +322,7 @@
+ elif self.relativesrcdir:
+ self.localedirs = \
+ self.generateLocaleDirs(self.relativesrcdir)
+- if isinstance(infile, basestring):
++ if isinstance(infile, str):
+ logging.info('processing ' + infile)
+ self.sourcedirs.append(_normpath(os.path.dirname(infile)))
+ pp = self.pp.clone()
+@@ -372,7 +372,7 @@
+ jarfilepath = jarfile + '.jar'
+ try:
+ os.makedirs(os.path.dirname(jarfilepath))
+- except OSError, error:
++ except OSError as error:
+ if error.errno != errno.EEXIST:
+ raise
+ jf = ZipFile(jarfilepath, 'a', lock=True)
+@@ -514,7 +514,7 @@
+ # remove previous link or file
+ try:
+ os.remove(out)
+- except OSError, e:
++ except OSError as e:
+ if e.errno != errno.ENOENT:
+ raise
+ return open(out, 'wb')
+@@ -525,7 +525,7 @@
+ if not os.path.isdir(outdir):
+ try:
+ os.makedirs(outdir)
+- except OSError, error:
++ except OSError as error:
+ if error.errno != errno.EEXIST:
+ raise
+ return out
+@@ -541,7 +541,7 @@
+ # remove previous link or file
+ try:
+ os.remove(out)
+- except OSError, e:
++ except OSError as e:
+ if e.errno != errno.ENOENT:
+ raise
+ if sys.platform != 'win32':
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/mach_commands.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/mach_commands.py (refactored)
+@@ -2,7 +2,7 @@
+ # License, v. 2.0. If a copy of the MPL was not distributed with this
+ # file, # You can obtain one at http://mozilla.org/MPL/2.0/.
+
+-from __future__ import absolute_import, print_function, unicode_literals
++
+
+ import argparse
+ import errno
+@@ -136,7 +136,7 @@
+ # terminal is a blessings.Terminal.
+ self._t = terminal
+ self._fh = sys.stdout
+- self.tiers = monitor.tiers.tier_status.viewitems()
++ self.tiers = monitor.tiers.tier_status.items()
+
+ def clear(self):
+ """Removes the footer from the current terminal."""
+@@ -802,7 +802,7 @@
+ dirpath = None
+
+ type_counts = database.type_counts(dirpath)
+- sorted_counts = sorted(type_counts.iteritems(),
++ sorted_counts = sorted(iter(type_counts.items()),
+ key=operator.itemgetter(1))
+
+ total = 0
+@@ -957,7 +957,7 @@
+ processes[i].run()
+
+ exit_code = 0
+- for process in processes.values():
++ for process in list(processes.values()):
+ status = process.wait()
+ if status:
+ exit_code = status
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/makeutil.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/makeutil.py (refactored)
+@@ -2,7 +2,7 @@
+ # License, v. 2.0. If a copy of the MPL was not distributed with this
+ # file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+-from __future__ import absolute_import
++
+
+ import os
+ import re
+@@ -66,7 +66,7 @@
+ self._list = []
+ self._set = set()
+
+- def __nonzero__(self):
++ def __bool__(self):
+ return bool(self._set)
+
+ def __iter__(self):
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/milestone.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/milestone.py (refactored)
+@@ -2,7 +2,7 @@
+ # License, v. 2.0. If a copy of the MPL was not distributed with this
+ # file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+-from __future__ import absolute_import, print_function, unicode_literals
++
+
+ import argparse
+ import os
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/mozconfig.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/mozconfig.py (refactored)
+@@ -2,7 +2,7 @@
+ # License, v. 2.0. If a copy of the MPL was not distributed with this
+ # file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+-from __future__ import absolute_import, unicode_literals
++
+
+ import filecmp
+ import os
+@@ -306,7 +306,7 @@
+
+ # Environment variables also appear as shell variables, but that's
+ # uninteresting duplication of information. Filter them out.
+- filt = lambda x, y: {k: v for k, v in x.items() if k not in y}
++ filt = lambda x, y: {k: v for k, v in list(x.items()) if k not in y}
+ result['vars'] = diff_vars(
+ filt(parsed['vars_before'], parsed['env_before']),
+ filt(parsed['vars_after'], parsed['env_after'])
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/mozinfo.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/mozinfo.py (refactored)
+@@ -5,7 +5,7 @@
+ # This module produces a JSON file that provides basic build info and
+ # configuration metadata.
+
+-from __future__ import absolute_import
++
+
+ import os
+ import re
+@@ -154,7 +154,7 @@
+ and what keys are produced.
+ """
+ build_conf = build_dict(config, env)
+- if isinstance(file, basestring):
++ if isinstance(file, str):
+ file = open(file, 'wb')
+
+ json.dump(build_conf, file, sort_keys=True, indent=4)
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/preprocessor.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/preprocessor.py (refactored)
+@@ -27,7 +27,8 @@
+ import re
+ from optparse import OptionParser
+ import errno
+-from makeutil import Makefile
++from .makeutil import Makefile
++from functools import reduce
+
+ # hack around win32 mangling our line endings
+ # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/65443
+@@ -56,7 +57,7 @@
+ self.__ignore_whitespace()
+ self.e = self.__get_logical_or()
+ if self.content:
+- raise Expression.ParseError, self
++ raise Expression.ParseError(self)
+
+ def __get_logical_or(self):
+ """
+@@ -157,7 +158,7 @@
+ if word_len:
+ rv = Expression.__ASTLeaf('string', self.content[:word_len])
+ else:
+- raise Expression.ParseError, self
++ raise Expression.ParseError(self)
+ self.__strip(word_len)
+ self.__ignore_whitespace()
+ return rv
+@@ -196,7 +197,7 @@
+ return left and right
+ elif tok[1].value == '||':
+ return left or right
+- raise Expression.ParseError, self
++ raise Expression.ParseError(self)
+
+ # Mapping from token types to evaluator functions
+ # Apart from (non-)equality, all these can be simple lambda forms.
+@@ -230,7 +231,7 @@
+ def __repr__(self):
+ return self.value.__repr__()
+
+- class ParseError(StandardError):
++ class ParseError(Exception):
+ """
+ Error raised when parsing fails.
+ It has two members, offset and content, which give the offset of the
+@@ -278,7 +279,7 @@
+ self.context = Context()
+ for k,v in {'FILE': '',
+ 'LINE': 0,
+- 'DIRECTORY': os.path.abspath('.')}.iteritems():
++ 'DIRECTORY': os.path.abspath('.')}.items():
+ self.context[k] = v
+ self.actionLevel = 0
+ self.disableLevel = 0
+@@ -292,21 +293,21 @@
+ self.cmds = {}
+ for cmd, level in {'define': 0,
+ 'undef': 0,
+- 'if': sys.maxint,
+- 'ifdef': sys.maxint,
+- 'ifndef': sys.maxint,
++ 'if': sys.maxsize,
++ 'ifdef': sys.maxsize,
++ 'ifndef': sys.maxsize,
+ 'else': 1,
+ 'elif': 1,
+ 'elifdef': 1,
+ 'elifndef': 1,
+- 'endif': sys.maxint,
++ 'endif': sys.maxsize,
+ 'expand': 0,
+ 'literal': 0,
+ 'filter': 0,
+ 'unfilter': 0,
+ 'include': 0,
+ 'includesubst': 0,
+- 'error': 0}.iteritems():
++ 'error': 0}.items():
+ self.cmds[cmd] = (level, getattr(self, 'do_' + cmd))
+ self.out = sys.stdout
+ self.setMarker(marker)
+@@ -469,7 +470,7 @@
+ raise Preprocessor.Error(self, "--depend doesn't work with stdout",
+ None)
+ try:
+- from makeutil import Makefile
++ from .makeutil import Makefile
+ except:
+ raise Preprocessor.Error(self, "--depend requires the "
+ "mozbuild.makeutil module", None)
+@@ -684,7 +685,7 @@
+ current = dict(self.filters)
+ for f in filters:
+ current[f] = getattr(self, 'filter_' + f)
+- filterNames = current.keys()
++ filterNames = list(current.keys())
+ filterNames.sort()
+ self.filters = [(fn, current[fn]) for fn in filterNames]
+ return
+@@ -694,7 +695,7 @@
+ for f in filters:
+ if f in current:
+ del current[f]
+- filterNames = current.keys()
++ filterNames = list(current.keys())
+ filterNames.sort()
+ self.filters = [(fn, current[fn]) for fn in filterNames]
+ return
+@@ -739,7 +740,7 @@
+ args can either be a file name, or a file-like object.
+ Files should be opened, and will be closed after processing.
+ """
+- isName = type(args) == str or type(args) == unicode
++ isName = type(args) == str or type(args) == str
+ oldCheckLineNumbers = self.checkLineNumbers
+ self.checkLineNumbers = False
+ if isName:
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/pythonutil.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/pythonutil.py (refactored)
+@@ -2,7 +2,7 @@
+ # License, v. 2.0. If a copy of the MPL was not distributed with this
+ # file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+-from __future__ import absolute_import
++
+
+ import os
+ import sys
+@@ -11,7 +11,7 @@
+ def iter_modules_in_path(*paths):
+ paths = [os.path.abspath(os.path.normcase(p)) + os.sep
+ for p in paths]
+- for name, module in sys.modules.items():
++ for name, module in list(sys.modules.items()):
+ if not hasattr(module, '__file__'):
+ continue
+
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/shellutil.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/shellutil.py (refactored)
+@@ -15,7 +15,7 @@
+ # which matches the pattern and captures it in a named match group.
+ # The group names and patterns are given as arguments.
+ all_tokens = '|'.join('(?P<%s>%s)' % (name, value)
+- for name, value in tokens.iteritems())
++ for name, value in tokens.items())
+ nonescaped = r'(?<!\\)(?:%s)' % all_tokens
+
+ # The final pattern matches either the above pattern, or an escaped
+@@ -96,7 +96,7 @@
+ self.cline = self.cline[m.end():]
+
+ match = {name: value
+- for name, value in m.groupdict().items() if value}
++ for name, value in list(m.groupdict().items()) if value}
+ if 'quote' in match:
+ # " or ' start a quoted string
+ if match['quote'] == '"':
+@@ -144,7 +144,7 @@
+ self._push(self.cline[:m.start()])
+ self.cline = self.cline[m.end():]
+ match = {name: value
+- for name, value in m.groupdict().items() if value}
++ for name, value in list(m.groupdict().items()) if value}
+ if 'quote' in match:
+ # a double quote ends the quoted string, so go back to
+ # unquoted parsing
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/sphinx.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/sphinx.py (refactored)
+@@ -2,7 +2,7 @@
+ # License, v. 2.0. If a copy of the MPL was not distributed with this
+ # file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+-from __future__ import absolute_import
++
+
+ import importlib
+ import os
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/testing.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/testing.py (refactored)
+@@ -2,9 +2,9 @@
+ # License, v. 2.0. If a copy of the MPL was not distributed with this
+ # file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+-from __future__ import absolute_import, unicode_literals
+-
+-import cPickle as pickle
++
++
++import pickle as pickle
+ import os
+ import sys
+
+@@ -62,7 +62,7 @@
+ if test_defaults:
+ with open(test_defaults, 'rb') as fh:
+ defaults = pickle.load(fh)
+- for path, tests in test_data.items():
++ for path, tests in list(test_data.items()):
+ for metadata in tests:
+ if defaults:
+ manifest = metadata['manifest']
+@@ -303,7 +303,7 @@
+ WEB_PLATFORM_TESTS_FLAVORS = ('web-platform-tests',)
+
+ def all_test_flavors():
+- return ([v[0] for v in TEST_MANIFESTS.values()] +
++ return ([v[0] for v in list(TEST_MANIFESTS.values())] +
+ list(REFTEST_FLAVORS) +
+ list(WEB_PLATFORM_TESTS_FLAVORS) +
+ ['python'])
+@@ -445,7 +445,7 @@
+ only a few tests need to be run.
+ """
+ flavor_info = {flavor: (root, prefix, install)
+- for (flavor, root, prefix, install) in TEST_MANIFESTS.values()}
++ for (flavor, root, prefix, install) in list(TEST_MANIFESTS.values())}
+ objdir_dest = mozpath.join(topobjdir, tests_root)
+
+ converter = SupportFilesConverter()
+@@ -527,7 +527,7 @@
+ paths_file = os.path.join(context.config.topsrcdir, "testing",
+ "web-platform", "tests", "tools", "localpaths.py")
+ _globals = {"__file__": paths_file}
+- execfile(paths_file, _globals)
++ exec(compile(open(paths_file).read(), paths_file, 'exec'), _globals)
+ import manifest as wptmanifest
+ finally:
+ sys.path = old_path
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/util.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/util.py (refactored)
+@@ -5,7 +5,7 @@
+ # This file contains miscellaneous utility functions that don't belong anywhere
+ # in particular.
+
+-from __future__ import absolute_import, unicode_literals, print_function
++
+
+ import argparse
+ import collections
+@@ -36,7 +36,7 @@
+ if sys.version_info[0] == 3:
+ str_type = str
+ else:
+- str_type = basestring
++ str_type = str
+
+ if sys.platform == 'win32':
+ _kernel32 = ctypes.windll.kernel32
+@@ -78,7 +78,7 @@
+ return h.hexdigest()
+
+
+-class EmptyValue(unicode):
++class EmptyValue(str):
+ """A dummy type that behaves like an empty string and sequence.
+
+ This type exists in order to support
+@@ -92,7 +92,7 @@
+ class ReadOnlyNamespace(object):
+ """A class for objects with immutable attributes set at initialization."""
+ def __init__(self, **kwargs):
+- for k, v in kwargs.iteritems():
++ for k, v in kwargs.items():
+ super(ReadOnlyNamespace, self).__setattr__(k, v)
+
+ def __delattr__(self, key):
+@@ -152,7 +152,7 @@
+ if d and not os.path.exists(path):
+ try:
+ os.makedirs(d)
+- except OSError, error:
++ except OSError as error:
+ if error.errno != errno.EEXIST:
+ raise
+
+@@ -224,7 +224,7 @@
+ self.mode = mode
+
+ def write(self, buf):
+- if isinstance(buf, unicode):
++ if isinstance(buf, str):
+ buf = buf.encode('utf-8')
+ BytesIO.write(self, buf)
+
+@@ -381,7 +381,7 @@
+ def __add__(self, other):
+ # Allow None and EmptyValue is a special case because it makes undefined
+ # variable references in moz.build behave better.
+- other = [] if isinstance(other, (types.NoneType, EmptyValue)) else other
++ other = [] if isinstance(other, (type(None), EmptyValue)) else other
+ if not isinstance(other, list):
+ raise ValueError('Only lists can be appended to lists.')
+
+@@ -390,7 +390,7 @@
+ return new_list
+
+ def __iadd__(self, other):
+- other = [] if isinstance(other, (types.NoneType, EmptyValue)) else other
++ other = [] if isinstance(other, (type(None), EmptyValue)) else other
+ if not isinstance(other, list):
+ raise ValueError('Only lists can be appended to lists.')
+
+@@ -542,14 +542,14 @@
+ functions below.
+ """
+ assert isinstance(flags, dict)
+- assert all(isinstance(v, type) for v in flags.values())
++ assert all(isinstance(v, type) for v in list(flags.values()))
+
+ class Flags(object):
+- __slots__ = flags.keys()
++ __slots__ = list(flags.keys())
+ _flags = flags
+
+ def update(self, **kwargs):
+- for k, v in kwargs.iteritems():
++ for k, v in kwargs.items():
+ setattr(self, k, v)
+
+ def __getattr__(self, name):
+@@ -1080,14 +1080,14 @@
+ # issue. So we do a little dance to filter it out ourselves.
+ dummy_fill_value = ("dummy",)
+ def filter_out_dummy(iterable):
+- return itertools.ifilter(lambda x: x != dummy_fill_value,
++ return filter(lambda x: x != dummy_fill_value,
+ iterable)
+
+ # From the itertools documentation, slightly modified:
+ def grouper(n, iterable):
+ "grouper(3, 'ABCDEFG', 'x') --> ABC DEF Gxx"
+ args = [iter(iterable)] * n
+- return itertools.izip_longest(fillvalue=dummy_fill_value, *args)
++ return itertools.zip_longest(fillvalue=dummy_fill_value, *args)
+
+ for i, unified_group in enumerate(grouper(files_per_unified_file,
+ files)):
+@@ -1104,7 +1104,7 @@
+ [(1,2), (3,4), (5,6)]
+ '''
+ i = iter(iterable)
+- return itertools.izip_longest(i, i)
++ return itertools.zip_longest(i, i)
+
+
+ VARIABLES_RE = re.compile('\$\((\w+)\)')
+@@ -1122,7 +1122,7 @@
+ value = variables.get(name)
+ if not value:
+ continue
+- if not isinstance(value, types.StringTypes):
++ if not isinstance(value, (str,)):
+ value = ' '.join(value)
+ result += value
+ return result
+@@ -1149,7 +1149,7 @@
+ pass
+
+
+-class EnumString(unicode):
++class EnumString(str):
+ '''A string type that only can have a limited set of values, similarly to
+ an Enum, and can only be compared against that set of values.
+
+@@ -1185,19 +1185,18 @@
+ # quoting could be done with either ' or ".
+ if c == "'":
+ return "\\'"
+- return unicode(c.encode('unicode_escape'))
++ return str(c.encode('unicode_escape'))
+
+ # Mapping table between raw characters below \x80 and their escaped
+ # counterpart, when they differ
+ _INDENTED_REPR_TABLE = {
+ c: e
+- for c, e in map(lambda x: (x, _escape_char(x)),
+- map(unichr, range(128)))
++ for c, e in [(x, _escape_char(x)) for x in list(map(chr, list(range(128))))]
+ if c != e
+ }
+ # Regexp matching all characters to escape.
+ _INDENTED_REPR_RE = re.compile(
+- '([' + ''.join(_INDENTED_REPR_TABLE.values()) + ']+)')
++ '([' + ''.join(list(_INDENTED_REPR_TABLE.values())) + ']+)')
+
+
+ def indented_repr(o, indent=4):
+@@ -1223,7 +1222,7 @@
+ elif isinstance(o, bytes):
+ yield 'b'
+ yield repr(o)
+- elif isinstance(o, unicode):
++ elif isinstance(o, str):
+ yield "'"
+ # We want a readable string (non escaped unicode), but some
+ # special characters need escaping (e.g. \n, \t, etc.)
+@@ -1253,11 +1252,11 @@
+ if isinstance(obj, dict):
+ return {
+ encode(k, encoding): encode(v, encoding)
+- for k, v in obj.iteritems()
++ for k, v in obj.items()
+ }
+ if isinstance(obj, bytes):
+ return obj
+- if isinstance(obj, unicode):
++ if isinstance(obj, str):
+ return obj.encode(encoding)
+ if isinstance(obj, Iterable):
+ return [encode(i, encoding) for i in obj]
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/vendor_rust.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/vendor_rust.py (refactored)
+@@ -2,7 +2,7 @@
+ # License, v. 2.0. If a copy of the MPL was not distributed with this
+ # file, # You can obtain one at http://mozilla.org/MPL/2.0/.
+
+-from __future__ import absolute_import, print_function, unicode_literals
++
+
+ from distutils.version import LooseVersion
+ import logging
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/virtualenv.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/virtualenv.py (refactored)
+@@ -5,7 +5,7 @@
+ # This file contains code for populating the virtualenv environment for
+ # Mozilla's build system. It is typically called as part of configure.
+
+-from __future__ import absolute_import, print_function, unicode_literals
++
+
+ import distutils.sysconfig
+ import os
+@@ -461,8 +461,8 @@
+ and call .ensure() and .activate() to make the virtualenv active.
+ """
+
+- execfile(self.activate_path, dict(__file__=self.activate_path))
+- if isinstance(os.environ['PATH'], unicode):
++ exec(compile(open(self.activate_path).read(), self.activate_path, 'exec'), dict(__file__=self.activate_path))
++ if isinstance(os.environ['PATH'], str):
+ os.environ['PATH'] = os.environ['PATH'].encode('utf-8')
+
+ def install_pip_package(self, package):
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/action/buildlist.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/action/buildlist.py (refactored)
+@@ -7,7 +7,7 @@
+
+ Usage: buildlist.py <filename> <entry> [<entry> ...]
+ '''
+-from __future__ import absolute_import, print_function
++
+
+ import sys
+ import os
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/action/cl.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/action/cl.py (refactored)
+@@ -2,7 +2,7 @@
+ # License, v. 2.0. If a copy of the MPL was not distributed with this
+ # file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+-from __future__ import absolute_import
++
+
+ import ctypes
+ import os
+@@ -55,7 +55,7 @@
+ break
+
+ if target is None:
+- print >>sys.stderr, "No target set"
++ print("No target set", file=sys.stderr)
+ return 1
+
+ # Assume the source file is the last argument
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/action/dump_env.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/action/dump_env.py (refactored)
+@@ -6,5 +6,5 @@
+ # native paths printed on Windows so that these paths can be incorporated
+ # into Python configure's environment.
+ import os
+-for key, value in os.environ.items():
+- print('%s=%s' % (key, value))
++for key, value in list(os.environ.items()):
++ print(('%s=%s' % (key, value)))
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/action/explode_aar.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/action/explode_aar.py (refactored)
+@@ -2,7 +2,7 @@
+ # License, v. 2.0. If a copy of the MPL was not distributed with this
+ # file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+-from __future__ import absolute_import, print_function, unicode_literals
++
+
+ import argparse
+ import errno
+@@ -44,7 +44,7 @@
+ assets = mozpath.join(destdir, 'assets')
+ try:
+ os.rmdir(assets)
+- except OSError, e:
++ except OSError as e:
+ if e.errno in (errno.ENOTEMPTY, errno.ENOENT):
+ pass
+ else:
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/action/file_generate.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/action/file_generate.py (refactored)
+@@ -6,7 +6,7 @@
+ # the arguments that can be used to generate the output file, call the
+ # script's |main| method with appropriate arguments.
+
+-from __future__ import absolute_import, print_function
++
+
+ import argparse
+ import imp
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/action/generate_suggestedsites.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/action/generate_suggestedsites.py (refactored)
+@@ -26,7 +26,7 @@
+ directory e.g. raw/suggestedsites.json, raw-pt-rBR/suggestedsites.json.
+ '''
+
+-from __future__ import absolute_import, print_function
++
+
+ import argparse
+ import copy
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/action/generate_symbols_file.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/action/generate_symbols_file.py (refactored)
+@@ -2,12 +2,12 @@
+ # License, v. 2.0. If a copy of the MPL was not distributed with this
+ # file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+-from __future__ import absolute_import, print_function, unicode_literals
++
+
+ import argparse
+ import buildconfig
+ import os
+-from StringIO import StringIO
++from io import StringIO
+ from mozbuild.preprocessor import Preprocessor
+ from mozbuild.util import DefinesAction
+
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/action/jar_maker.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/action/jar_maker.py (refactored)
+@@ -2,7 +2,7 @@
+ # License, v. 2.0. If a copy of the MPL was not distributed with this
+ # file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+-from __future__ import absolute_import
++
+
+ import sys
+
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/action/make_dmg.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/action/make_dmg.py (refactored)
+@@ -2,7 +2,7 @@
+ # License, v. 2.0. If a copy of the MPL was not distributed with this
+ # file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+-from __future__ import print_function
++
+
+ from mozbuild.base import MozbuildObject
+ from mozpack import dmg
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/action/output_searchplugins_list.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/action/output_searchplugins_list.py (refactored)
+@@ -18,4 +18,4 @@
+ else:
+ engines = searchinfo["default"]["visibleDefaultEngines"]
+
+-print '\n'.join(engines)
++print('\n'.join(engines))
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/action/package_fennec_apk.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/action/package_fennec_apk.py (refactored)
+@@ -6,7 +6,7 @@
+ Script to produce an Android package (.apk) for Fennec.
+ '''
+
+-from __future__ import absolute_import, print_function
++
+
+ import argparse
+ import buildconfig
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/action/preprocessor.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/action/preprocessor.py (refactored)
+@@ -2,7 +2,7 @@
+ # License, v. 2.0. If a copy of the MPL was not distributed with this
+ # file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+-from __future__ import absolute_import
++
+
+ import sys
+
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/action/process_define_files.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/action/process_define_files.py (refactored)
+@@ -2,7 +2,7 @@
+ # License, v. 2.0. If a copy of the MPL was not distributed with this
+ # file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+-from __future__ import absolute_import, print_function, unicode_literals
++
+
+ import argparse
+ import os
+@@ -55,7 +55,7 @@
+ 'CONFIGURE_DEFINE_FILE')
+ defines = '\n'.join(sorted(
+ '#define %s %s' % (name, val)
+- for name, val in config.defines.iteritems()
++ for name, val in config.defines.items()
+ if name not in config.non_global_defines))
+ l = l[:m.start('cmd') - 1] \
+ + defines + l[m.end('name'):]
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/action/process_install_manifest.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/action/process_install_manifest.py (refactored)
+@@ -2,7 +2,7 @@
+ # License, v. 2.0. If a copy of the MPL was not distributed with this
+ # file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+-from __future__ import absolute_import, print_function, unicode_literals
++
+
+ import argparse
+ import os
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/action/test_archive.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/action/test_archive.py (refactored)
+@@ -8,7 +8,7 @@
+ # It is defined inline because this was easiest to make test archive
+ # generation faster.
+
+-from __future__ import absolute_import, print_function, unicode_literals
++
+
+ import argparse
+ import itertools
+@@ -433,7 +433,7 @@
+ # "common" is our catch all archive and it ignores things from other archives.
+ # Verify nothing sneaks into ARCHIVE_FILES without a corresponding exclusion
+ # rule in the "common" archive.
+-for k, v in ARCHIVE_FILES.items():
++for k, v in list(ARCHIVE_FILES.items()):
+ # Skip mozharness because it isn't staged.
+ if k in ('common', 'mozharness'):
+ continue
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/action/webidl.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/action/webidl.py (refactored)
+@@ -2,7 +2,7 @@
+ # License, v. 2.0. If a copy of the MPL was not distributed with this
+ # file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+-from __future__ import absolute_import
++
+
+ import sys
+
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/action/xpccheck.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/action/xpccheck.py (refactored)
+@@ -8,7 +8,7 @@
+ Usage: xpccheck.py <directory> [<directory> ...]
+ '''
+
+-from __future__ import absolute_import
++
+
+ import sys
+ import os
+@@ -40,7 +40,7 @@
+ break
+
+ if not found:
+- print >>sys.stderr, "TEST-UNEXPECTED-FAIL | xpccheck | test %s is missing from test manifest %s!" % (name, os.path.join(directory, 'xpcshell.ini'))
++ print("TEST-UNEXPECTED-FAIL | xpccheck | test %s is missing from test manifest %s!" % (name, os.path.join(directory, 'xpcshell.ini')), file=sys.stderr)
+ sys.exit(1)
+
+ def verifyIniFile(initests, directory):
+@@ -60,12 +60,12 @@
+ break
+
+ if not found:
+- print >>sys.stderr, "TEST-UNEXPECTED-FAIL | xpccheck | found %s in xpcshell.ini and not in directory '%s'" % (name, directory)
++ print("TEST-UNEXPECTED-FAIL | xpccheck | found %s in xpcshell.ini and not in directory '%s'" % (name, directory), file=sys.stderr)
+ sys.exit(1)
+
+ def main(argv):
+ if len(argv) < 2:
+- print >>sys.stderr, "Usage: xpccheck.py <topsrcdir> <directory> [<directory> ...]"
++ print("Usage: xpccheck.py <topsrcdir> <directory> [<directory> ...]", file=sys.stderr)
+ sys.exit(1)
+
+ topsrcdir = argv[0]
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/action/xpidl-process.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/action/xpidl-process.py (refactored)
+@@ -7,7 +7,7 @@
+ # input IDL file(s). It's purpose is to directly support the build
+ # system. The API will change to meet the needs of the build system.
+
+-from __future__ import absolute_import
++
+
+ import argparse
+ import os
+@@ -58,7 +58,7 @@
+
+ # TODO use FileAvoidWrite once it supports binary mode.
+ xpt_path = os.path.join(xpt_dir, '%s.xpt' % module)
+- xpt_link(xpts.values()).write(xpt_path)
++ xpt_link(list(xpts.values())).write(xpt_path)
+
+ rule.add_targets([xpt_path])
+ if deps_dir:
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/action/zip.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/action/zip.py (refactored)
+@@ -5,7 +5,7 @@
+ # This script creates a zip file, but will also strip any binaries
+ # it finds before adding them to the zip.
+
+-from __future__ import absolute_import
++
+
+ from mozpack.files import FileFinder
+ from mozpack.copier import Jarrer
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/backend/android_eclipse.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/backend/android_eclipse.py (refactored)
+@@ -2,7 +2,7 @@
+ # License, v. 2.0. If a copy of the MPL was not distributed with this
+ # file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+-from __future__ import absolute_import, unicode_literals
++
+
+ import itertools
+ import os
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/backend/base.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/backend/base.py (refactored)
+@@ -2,7 +2,7 @@
+ # License, v. 2.0. If a copy of the MPL was not distributed with this
+ # file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+-from __future__ import absolute_import, unicode_literals
++
+
+ from abc import (
+ ABCMeta,
+@@ -30,15 +30,13 @@
+ from mozbuild.base import ExecutionSummary
+
+
+-class BuildBackend(LoggingMixin):
++class BuildBackend(LoggingMixin, metaclass=ABCMeta):
+ """Abstract base class for build backends.
+
+ A build backend is merely a consumer of the build configuration (the output
+ of the frontend processing). It does something with said data. What exactly
+ is the discretion of the specific implementation.
+ """
+-
+- __metaclass__ = ABCMeta
+
+ def __init__(self, environment):
+ assert isinstance(environment, ConfigEnvironment)
+@@ -252,7 +250,7 @@
+ srcdir = mozpath.dirname(obj.input_path)
+ pp.context.update({
+ k: ' '.join(v) if isinstance(v, list) else v
+- for k, v in obj.config.substs.iteritems()
++ for k, v in obj.config.substs.items()
+ })
+ pp.context.update(
+ top_srcdir=obj.topsrcdir,
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/backend/common.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/backend/common.py (refactored)
+@@ -2,9 +2,9 @@
+ # License, v. 2.0. If a copy of the MPL was not distributed with this
+ # file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+-from __future__ import absolute_import, unicode_literals
+-
+-import cPickle as pickle
++
++
++import pickle as pickle
+ import itertools
+ import json
+ import os
+@@ -194,11 +194,11 @@
+ def add_defaults(self, manifest):
+ if not hasattr(manifest, 'manifest_defaults'):
+ return
+- for sub_manifest, defaults in manifest.manifest_defaults.items():
++ for sub_manifest, defaults in list(manifest.manifest_defaults.items()):
+ self.manifest_defaults[sub_manifest] = defaults
+
+ def add_installs(self, obj, topsrcdir):
+- for src, (dest, _) in obj.installs.iteritems():
++ for src, (dest, _) in obj.installs.items():
+ key = src[len(topsrcdir)+1:]
+ self.installs_by_path[key].append((src, dest))
+ for src, pat, dest in obj.pattern_installs:
+@@ -379,7 +379,7 @@
+
+ path = mozpath.join(self.environment.topobjdir, 'test-installs.pkl')
+ with self._write_file(path, mode='rb') as fh:
+- pickle.dump({k: v for k, v in self._test_manager.installs_by_path.items()
++ pickle.dump({k: v for k, v in list(self._test_manager.installs_by_path.items())
+ if k in self._test_manager.deferred_installs},
+ fh,
+ protocol=2)
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/backend/configenvironment.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/backend/configenvironment.py (refactored)
+@@ -2,7 +2,7 @@
+ # License, v. 2.0. If a copy of the MPL was not distributed with this
+ # file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+-from __future__ import absolute_import
++
+
+ import os
+ import sys
+@@ -17,7 +17,7 @@
+
+
+ if sys.version_info.major == 2:
+- text_type = unicode
++ text_type = str
+ else:
+ text_type = str
+
+@@ -176,7 +176,7 @@
+ except UnicodeDecodeError:
+ return v.decode('utf-8', 'replace')
+
+- for k, v in self.substs.items():
++ for k, v in list(self.substs.items()):
+ if not isinstance(v, StringTypes):
+ if isinstance(v, Iterable):
+ type(v)(decode(i) for i in v)
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/backend/cpp_eclipse.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/backend/cpp_eclipse.py (refactored)
+@@ -2,7 +2,7 @@
+ # License, v. 2.0. If a copy of the MPL was not distributed with this
+ # file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+-from __future__ import absolute_import
++
+
+ import errno
+ import random
+@@ -218,12 +218,12 @@
+ cproject_header = cproject_header.replace('@MACH_COMMAND@', os.path.join(self.environment.topsrcdir, 'mach'))
+ fh.write(cproject_header)
+
+- for path, defines in self._paths_to_defines.items():
++ for path, defines in list(self._paths_to_defines.items()):
+ folderinfo = CPROJECT_TEMPLATE_FOLDER_INFO_HEADER
+ folderinfo = folderinfo.replace('@FOLDER_ID@', str(random.randint(1000000, 99999999999)))
+ folderinfo = folderinfo.replace('@FOLDER_NAME@', 'tree/' + path)
+ fh.write(folderinfo)
+- for k, v in defines.items():
++ for k, v in list(defines.items()):
+ define = ET.Element('listOptionValue')
+ define.set('builtIn', 'false')
+ define.set('value', str(k) + "=" + str(v))
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/backend/fastermake.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/backend/fastermake.py (refactored)
+@@ -2,7 +2,7 @@
+ # License, v. 2.0. If a copy of the MPL was not distributed with this
+ # file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+-from __future__ import absolute_import, unicode_literals, print_function
++
+
+ from mozbuild.backend.base import PartialBackend
+ from mozbuild.backend.common import CommonBackend
+@@ -130,12 +130,12 @@
+ if value is not None:
+ mk.add_statement('%s = %s' % (var, value))
+
+- install_manifests_bases = self._install_manifests.keys()
++ install_manifests_bases = list(self._install_manifests.keys())
+
+ # Add information for chrome manifest generation
+ manifest_targets = []
+
+- for target, entries in self._manifest_entries.iteritems():
++ for target, entries in self._manifest_entries.items():
+ manifest_targets.append(target)
+ install_target = mozpath.basedir(target, install_manifests_bases)
+ self._install_manifests[install_target].add_content(
+@@ -144,16 +144,16 @@
+
+ # Add information for install manifests.
+ mk.add_statement('INSTALL_MANIFESTS = %s'
+- % ' '.join(self._install_manifests.keys()))
++ % ' '.join(list(self._install_manifests.keys())))
+
+ # Add dependencies we infered:
+- for target, deps in self._dependencies.iteritems():
++ for target, deps in self._dependencies.items():
+ mk.create_rule([target]).add_dependencies(
+ '$(TOPOBJDIR)/%s' % d for d in deps)
+
+ mk.add_statement('include $(TOPSRCDIR)/config/faster/rules.mk')
+
+- for base, install_manifest in self._install_manifests.iteritems():
++ for base, install_manifest in self._install_manifests.items():
+ with self._write_file(
+ mozpath.join(self.environment.topobjdir, 'faster',
+ 'install_%s' % base.replace('/', '_'))) as fh:
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/backend/mach_commands.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/backend/mach_commands.py (refactored)
+@@ -2,7 +2,7 @@
+ # License, v. 2.0. If a copy of the MPL was not distributed with this
+ # file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+-from __future__ import absolute_import, print_function, unicode_literals
++
+
+ import argparse
+ import os
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/backend/recursivemake.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/backend/recursivemake.py (refactored)
+@@ -2,7 +2,7 @@
+ # License, v. 2.0. If a copy of the MPL was not distributed with this
+ # file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+-from __future__ import absolute_import, unicode_literals
++
+
+ import logging
+ import os
+@@ -12,7 +12,7 @@
+ defaultdict,
+ namedtuple,
+ )
+-from StringIO import StringIO
++from io import StringIO
+ from itertools import chain
+
+ from mozpack.manifests import (
+@@ -74,6 +74,7 @@
+ )
+ from ..makeutil import Makefile
+ from mozbuild.shellutil import quote as shell_quote
++from functools import reduce
+
+ MOZBUILD_VARIABLES = [
+ b'ANDROID_APK_NAME',
+@@ -214,7 +215,7 @@
+ self.fh.write(buf)
+
+ def write_once(self, buf):
+- if isinstance(buf, unicode):
++ if isinstance(buf, str):
+ buf = buf.encode('utf-8')
+ if b'\n' + buf not in self.fh.getvalue():
+ self.write(buf)
+@@ -283,8 +284,8 @@
+ Helper function to call a filter from compute_dependencies and
+ traverse.
+ """
+- return filter(current, self._traversal.get(current,
+- self.SubDirectories()))
++ return list(filter(current, self._traversal.get(current,
++ self.SubDirectories())))
+
+ def compute_dependencies(self, filter=None):
+ """
+@@ -638,7 +639,7 @@
+ convenience variables, and the other dependency definitions for a
+ hopefully proper directory traversal.
+ """
+- for tier, no_skip in self._no_skip.items():
++ for tier, no_skip in list(self._no_skip.items()):
+ self.log(logging.DEBUG, 'fill_root_mk', {
+ 'number': len(no_skip), 'tier': tier
+ }, 'Using {number} directories during {tier}')
+@@ -684,7 +685,7 @@
+ for tier, filter in filters:
+ main, all_deps = \
+ self._traversal.compute_dependencies(filter)
+- for dir, deps in all_deps.items():
++ for dir, deps in list(all_deps.items()):
+ if deps is not None or (dir in self._idl_dirs \
+ and tier == 'export'):
+ rule = root_deps_mk.create_rule(['%s/%s' % (dir, tier)])
+@@ -697,7 +698,7 @@
+ rule.add_dependencies('%s/%s' % (d, tier) for d in main)
+
+ all_compile_deps = reduce(lambda x,y: x|y,
+- self._compile_graph.values()) if self._compile_graph else set()
++ list(self._compile_graph.values())) if self._compile_graph else set()
+ compile_roots = set(self._compile_graph.keys()) - all_compile_deps
+
+ rule = root_deps_mk.create_rule(['recurse_compile'])
+@@ -839,7 +840,7 @@
+ self._fill_root_mk()
+
+ # Make the master test manifest files.
+- for flavor, t in self._test_manifests.items():
++ for flavor, t in list(self._test_manifests.items()):
+ install_prefix, manifests = t
+ manifest_stem = mozpath.join(install_prefix, '%s.ini' % flavor)
+ self._write_master_test_manifest(mozpath.join(
+@@ -945,7 +946,7 @@
+ for p in ('Makefile', 'backend.mk', '.deps/.mkdir.done'):
+ build_files.add_optional_exists(p)
+
+- for idl in manager.idls.values():
++ for idl in list(manager.idls.values()):
+ self._install_manifests['dist_idl'].add_symlink(idl['source'],
+ idl['basename'])
+ self._install_manifests['dist_include'].add_optional_exists('%s.h'
+@@ -992,7 +993,7 @@
+
+ interfaces_manifests = []
+ dist_dir = mozpath.join(self.environment.topobjdir, 'dist')
+- for manifest, entries in manager.interface_manifests.items():
++ for manifest, entries in list(manager.interface_manifests.items()):
+ interfaces_manifests.append(mozpath.join('$(DEPTH)', manifest))
+ for xpt in sorted(entries):
+ registered_xpt_files.add(mozpath.join(
+@@ -1052,7 +1053,7 @@
+ # Don't allow files to be defined multiple times unless it is allowed.
+ # We currently allow duplicates for non-test files or test files if
+ # the manifest is listed as a duplicate.
+- for source, (dest, is_test) in obj.installs.items():
++ for source, (dest, is_test) in list(obj.installs.items()):
+ try:
+ self._install_manifests['_test_files'].add_symlink(source, dest)
+ except ValueError:
+@@ -1386,7 +1387,7 @@
+ man_dir = mozpath.join(self.environment.topobjdir, '_build_manifests',
+ dest)
+
+- for k, manifest in manifests.items():
++ for k, manifest in list(manifests.items()):
+ with self._write_file(mozpath.join(man_dir, k)) as fh:
+ manifest.write(fileobj=fh)
+
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/backend/tup.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/backend/tup.py (refactored)
+@@ -2,7 +2,7 @@
+ # License, v. 2.0. If a copy of the MPL was not distributed with this
+ # file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+-from __future__ import absolute_import, unicode_literals
++
+
+ import os
+
+@@ -253,7 +253,7 @@
+ backend_file = self._get_backend_file('xpcom/xpidl')
+ backend_file.export_shell()
+
+- for module, data in sorted(manager.modules.iteritems()):
++ for module, data in sorted(manager.modules.items()):
+ dest, idls = data
+ cmd = [
+ '$(PYTHON_PATH)',
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/backend/visualstudio.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/backend/visualstudio.py (refactored)
+@@ -5,7 +5,7 @@
+ # This file contains a build backend for generating Visual Studio project
+ # files.
+
+-from __future__ import absolute_import, unicode_literals
++
+
+ import errno
+ import os
+@@ -218,7 +218,7 @@
+ includes = [os.path.normpath(i) for i in includes]
+
+ defines = []
+- for k, v in self._paths_to_defines.get(path, {}).items():
++ for k, v in list(self._paths_to_defines.get(path, {}).items()):
+ if v is True:
+ defines.append(k)
+ else:
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/codecoverage/chrome_map.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/codecoverage/chrome_map.py (refactored)
+@@ -5,7 +5,7 @@
+ from collections import defaultdict
+ import json
+ import os
+-import urlparse
++import urllib.parse
+
+ from mach.config import ConfigSettings
+ from mach.logging import LoggingManager
+@@ -42,7 +42,7 @@
+ if isinstance(entry, (ManifestChrome, ManifestResource)):
+ if isinstance(entry, ManifestResource):
+ dest = entry.target
+- url = urlparse.urlparse(dest)
++ url = urllib.parse.urlparse(dest)
+ if not url.scheme:
+ dest = mozpath.normpath(mozpath.join(entry.base, dest))
+ if url.scheme == 'file':
+@@ -99,7 +99,7 @@
+ chrome_mapping = self.manifest_handler.chrome_mapping
+ overrides = self.manifest_handler.overrides
+ json.dump([
+- {k: list(v) for k, v in chrome_mapping.iteritems()},
++ {k: list(v) for k, v in chrome_mapping.items()},
+ overrides,
+ self._install_mapping,
+ ], fh, sort_keys=True, indent=2)
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/codecoverage/packager.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/codecoverage/packager.py (refactored)
+@@ -2,7 +2,7 @@
+ # License, v. 2.0. If a copy of the MPL was not distributed with this
+ # file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+-from __future__ import absolute_import, print_function
++
+
+ import argparse
+ import sys
+@@ -12,7 +12,7 @@
+
+ def package_gcno_tree(root, output_file):
+ # XXX JarWriter doesn't support unicode strings, see bug 1056859
+- if isinstance(root, unicode):
++ if isinstance(root, str):
+ root = root.encode('utf-8')
+
+ finder = FileFinder(root)
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/compilation/codecomplete.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/compilation/codecomplete.py (refactored)
+@@ -4,7 +4,7 @@
+
+ # This modules provides functionality for dealing with code completion.
+
+-from __future__ import absolute_import
++
+
+ import os
+
+@@ -59,5 +59,5 @@
+ # Drop the first flag since that is the pathname of the compiler.
+ flags = (shell_split(build_vars[cc]) + shell_split(build_vars[name]))[1:]
+
+- print(' '.join(shell_quote(arg)
+- for arg in util.sanitize_cflags(flags)))
++ print((' '.join(shell_quote(arg)
++ for arg in util.sanitize_cflags(flags))))
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/compilation/database.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/compilation/database.py (refactored)
+@@ -118,7 +118,7 @@
+
+ db = []
+
+- for (directory, filename), cmd in self._db.iteritems():
++ for (directory, filename), cmd in self._db.items():
+ env = self._envs[directory]
+ cmd = list(cmd)
+ cmd.append(filename)
+@@ -151,7 +151,7 @@
+ a = expand_variables(a, variables).split()
+ if not a:
+ continue
+- if isinstance(a, types.StringTypes):
++ if isinstance(a, (str,)):
+ c.append(a)
+ else:
+ c.extend(a)
+@@ -216,7 +216,7 @@
+ value = cenv.substs.get(name)
+ if not value:
+ return
+- if isinstance(value, types.StringTypes):
++ if isinstance(value, (str,)):
+ value = value.split()
+ db.extend(value)
+
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/compilation/warnings.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/compilation/warnings.py (refactored)
+@@ -4,7 +4,7 @@
+
+ # This modules provides functionality for dealing with compiler warnings.
+
+-from __future__ import absolute_import, unicode_literals
++
+
+ import errno
+ import json
+@@ -123,18 +123,18 @@
+
+ def __len__(self):
+ i = 0
+- for value in self._files.values():
++ for value in list(self._files.values()):
+ i += len(value['warnings'])
+
+ return i
+
+ def __iter__(self):
+- for value in self._files.values():
++ for value in list(self._files.values()):
+ for warning in value['warnings']:
+ yield warning
+
+ def __contains__(self, item):
+- for value in self._files.values():
++ for value in list(self._files.values()):
+ for warning in value['warnings']:
+ if warning == item:
+ return True
+@@ -144,7 +144,7 @@
+ @property
+ def warnings(self):
+ """All the CompilerWarning instances in this database."""
+- for value in self._files.values():
++ for value in list(self._files.values()):
+ for w in value['warnings']:
+ yield w
+
+@@ -152,7 +152,7 @@
+ """Returns a mapping of warning types to their counts."""
+
+ types = {}
+- for value in self._files.values():
++ for value in list(self._files.values()):
+ for warning in value['warnings']:
+ if dirpath and not mozpath.normsep(warning['filename']).startswith(dirpath):
+ continue
+@@ -210,7 +210,7 @@
+ """
+
+ # Need to calculate up front since we are mutating original object.
+- filenames = self._files.keys()
++ filenames = list(self._files.keys())
+ for filename in filenames:
+ if not os.path.exists(filename):
+ del self._files[filename]
+@@ -229,10 +229,10 @@
+ obj = {'files': {}}
+
+ # All this hackery because JSON can't handle sets.
+- for k, v in self._files.iteritems():
++ for k, v in self._files.items():
+ obj['files'][k] = {}
+
+- for k2, v2 in v.iteritems():
++ for k2, v2 in v.items():
+ normalized = v2
+
+ if k2 == 'warnings':
+@@ -249,8 +249,8 @@
+ self._files = obj['files']
+
+ # Normalize data types.
+- for filename, value in self._files.iteritems():
+- for k, v in value.iteritems():
++ for filename, value in self._files.items():
++ for k, v in value.items():
+ if k != 'warnings':
+ continue
+
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/configure/__init__.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/configure/__init__.py (refactored)
+@@ -2,7 +2,7 @@
+ # License, v. 2.0. If a copy of the MPL was not distributed with this
+ # file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+-from __future__ import absolute_import, print_function, unicode_literals
++
+
+ import inspect
+ import logging
+@@ -193,7 +193,7 @@
+ for b in ('None', 'False', 'True', 'int', 'bool', 'any', 'all', 'len',
+ 'list', 'tuple', 'set', 'dict', 'isinstance', 'getattr',
+ 'hasattr', 'enumerate', 'range', 'zip')
+- }, __import__=forbidden_import, str=unicode)
++ }, __import__=forbidden_import, str=str)
+
+ # Expose a limited set of functions from os.path
+ OS = ReadOnlyNamespace(path=ReadOnlyNamespace(**{
+@@ -333,7 +333,7 @@
+ if path:
+ self.include_file(path)
+
+- for option in self._options.itervalues():
++ for option in self._options.values():
+ # All options must be referenced by some @depends function
+ if option not in self._seen:
+ raise ConfigureError(
+@@ -437,7 +437,7 @@
+ value = PositiveOptionValue()
+ elif value is False or value == ():
+ value = NegativeOptionValue()
+- elif isinstance(value, types.StringTypes):
++ elif isinstance(value, (str,)):
+ value = PositiveOptionValue((value,))
+ elif isinstance(value, tuple):
+ value = PositiveOptionValue(value)
+@@ -477,7 +477,7 @@
+ return value
+
+ def _dependency(self, arg, callee_name, arg_name=None):
+- if isinstance(arg, types.StringTypes):
++ if isinstance(arg, (str,)):
+ prefix, name, values = Option.split_option(arg)
+ if values != ():
+ raise ConfigureError("Option must not contain an '='")
+@@ -541,7 +541,7 @@
+ '''
+ when = self._normalize_when(kwargs.get('when'), 'option')
+ args = [self._resolve(arg) for arg in args]
+- kwargs = {k: self._resolve(v) for k, v in kwargs.iteritems()
++ kwargs = {k: self._resolve(v) for k, v in kwargs.items()
+ if k != 'when'}
+ option = Option(*args, **kwargs)
+ if when:
+@@ -622,7 +622,7 @@
+ with self.only_when_impl(when):
+ what = self._resolve(what)
+ if what:
+- if not isinstance(what, types.StringTypes):
++ if not isinstance(what, (str,)):
+ raise TypeError("Unexpected type: '%s'" % type(what).__name__)
+ self.include_file(what)
+
+@@ -640,7 +640,7 @@
+ (k[:-len('_impl')], getattr(self, k))
+ for k in dir(self) if k.endswith('_impl') and k != 'template_impl'
+ )
+- glob.update((k, v) for k, v in self.iteritems() if k not in glob)
++ glob.update((k, v) for k, v in self.items() if k not in glob)
+
+ # Any function argument to the template must be prepared to be sandboxed.
+ # If the template itself returns a function (in which case, it's very
+@@ -664,7 +664,7 @@
+ def wrapper(*args, **kwargs):
+ args = [maybe_prepare_function(arg) for arg in args]
+ kwargs = {k: maybe_prepare_function(v)
+- for k, v in kwargs.iteritems()}
++ for k, v in kwargs.items()}
+ ret = template(*args, **kwargs)
+ if isfunction(ret):
+ # We can't expect the sandboxed code to think about all the
+@@ -696,7 +696,7 @@
+ for value, required in (
+ (_import, True), (_from, False), (_as, False)):
+
+- if not isinstance(value, types.StringTypes) and (
++ if not isinstance(value, (str,)) and (
+ required or value is not None):
+ raise TypeError("Unexpected type: '%s'" % type(value).__name__)
+ if value is not None and not self.RE_MODULE.match(value):
+@@ -759,7 +759,7 @@
+ name = self._resolve(name, need_help_dependency=False)
+ if name is None:
+ return
+- if not isinstance(name, types.StringTypes):
++ if not isinstance(name, (str,)):
+ raise TypeError("Unexpected type: '%s'" % type(name).__name__)
+ if name in data:
+ raise ConfigureError(
+@@ -849,7 +849,7 @@
+ if isinstance(possible_reasons[0], Option):
+ reason = possible_reasons[0]
+ if not reason and (isinstance(value, (bool, tuple)) or
+- isinstance(value, types.StringTypes)):
++ isinstance(value, (str,))):
+ # A reason can be provided automatically when imply_option
+ # is called with an immediate value.
+ _, filename, line, _, _, _ = inspect.stack()[1]
+@@ -884,10 +884,10 @@
+ if not inspect.isfunction(func):
+ raise TypeError("Unexpected type: '%s'" % type(func).__name__)
+ if func in self._prepared_functions:
+- return func, func.func_globals
++ return func, func.__globals__
+
+ glob = SandboxedGlobal(
+- (k, v) for k, v in func.func_globals.iteritems()
++ (k, v) for k, v in func.__globals__.items()
+ if (inspect.isfunction(v) and v not in self._templates) or (
+ inspect.isclass(v) and issubclass(v, Exception))
+ )
+@@ -908,20 +908,20 @@
+ # Note this is not entirely bullet proof (if the value is e.g. a list,
+ # the list contents could have changed), but covers the bases.
+ closure = None
+- if func.func_closure:
++ if func.__closure__:
+ def makecell(content):
+ def f():
+ content
+- return f.func_closure[0]
++ return f.__closure__[0]
+
+ closure = tuple(makecell(cell.cell_contents)
+- for cell in func.func_closure)
++ for cell in func.__closure__)
+
+ new_func = wraps(func)(types.FunctionType(
+- func.func_code,
++ func.__code__,
+ glob,
+ func.__name__,
+- func.func_defaults,
++ func.__defaults__,
+ closure
+ ))
+ @wraps(new_func)
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/configure/check_debug_ranges.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/configure/check_debug_ranges.py (refactored)
+@@ -6,7 +6,7 @@
+ # to a given compilation unit. This is used as a helper to find a bug in some
+ # versions of GNU ld.
+
+-from __future__ import absolute_import
++
+
+ import subprocess
+ import sys
+@@ -59,4 +59,4 @@
+
+
+ if __name__ == '__main__':
+- print main(*sys.argv[1:])
++ print(main(*sys.argv[1:]))
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/configure/constants.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/configure/constants.py (refactored)
+@@ -2,7 +2,7 @@
+ # License, v. 2.0. If a copy of the MPL was not distributed with this
+ # file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+-from __future__ import absolute_import, print_function, unicode_literals
++
+
+ from mozbuild.util import EnumString
+ from collections import OrderedDict
+@@ -56,7 +56,7 @@
+ 'x86_64': 64,
+ }
+
+-CPU = EnumString.subclass(*CPU_bitness.keys())
++CPU = EnumString.subclass(*list(CPU_bitness.keys()))
+
+ Endianness = EnumString.subclass(
+ 'big',
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/configure/help.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/configure/help.py (refactored)
+@@ -2,7 +2,7 @@
+ # License, v. 2.0. If a copy of the MPL was not distributed with this
+ # file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+-from __future__ import absolute_import, print_function, unicode_literals
++
+
+ import os
+ from mozbuild.configure.options import Option
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/configure/libstdcxx.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/configure/libstdcxx.py (refactored)
+@@ -13,7 +13,7 @@
+ # will be used from shell, we just print the two assignments and evaluate
+ # them from shell.
+
+-from __future__ import absolute_import
++
+
+ import os
+ import subprocess
+@@ -76,6 +76,6 @@
+
+ if __name__ == '__main__':
+ cxx_env = os.environ['CXX']
+- print 'MOZ_LIBSTDCXX_TARGET_VERSION=%s' % find_version(cxx_env)
++ print('MOZ_LIBSTDCXX_TARGET_VERSION=%s' % find_version(cxx_env))
+ host_cxx_env = os.environ.get('HOST_CXX', cxx_env)
+- print 'MOZ_LIBSTDCXX_HOST_VERSION=%s' % find_version(host_cxx_env)
++ print('MOZ_LIBSTDCXX_HOST_VERSION=%s' % find_version(host_cxx_env))
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/configure/lint.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/configure/lint.py (refactored)
+@@ -2,9 +2,9 @@
+ # License, v. 2.0. If a copy of the MPL was not distributed with this
+ # file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+-from __future__ import absolute_import, print_function, unicode_literals
+
+-from StringIO import StringIO
++
++from io import StringIO
+ from . import (
+ CombinedDependsFunction,
+ ConfigureError,
+@@ -42,7 +42,7 @@
+ # - don't use @imports
+ # - don't have a closure
+ # - don't use global variables
+- if func in self._imports or func.func_closure:
++ if func in self._imports or func.__closure__:
+ return True
+ for op, arg in disassemble_as_iter(func):
+ if op in ('LOAD_GLOBAL', 'STORE_GLOBAL'):
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/configure/lint_util.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/configure/lint_util.py (refactored)
+@@ -2,7 +2,7 @@
+ # License, v. 2.0. If a copy of the MPL was not distributed with this
+ # file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+-from __future__ import absolute_import, print_function, unicode_literals
++
+
+ import dis
+ import inspect
+@@ -12,9 +12,9 @@
+ # returns an iterator.
+ def disassemble_as_iter(co):
+ if inspect.ismethod(co):
+- co = co.im_func
++ co = co.__func__
+ if inspect.isfunction(co):
+- co = co.func_code
++ co = co.__code__
+ code = co.co_code
+ n = len(code)
+ i = 0
+@@ -30,7 +30,7 @@
+ extended_arg = 0
+ i += 2
+ if op == dis.EXTENDED_ARG:
+- extended_arg = arg * 65536L
++ extended_arg = arg * 65536
+ continue
+ if op in dis.hasconst:
+ yield opname, co.co_consts[arg]
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/configure/options.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/configure/options.py (refactored)
+@@ -2,7 +2,7 @@
+ # License, v. 2.0. If a copy of the MPL was not distributed with this
+ # file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+-from __future__ import absolute_import, print_function, unicode_literals
++
+
+ import os
+ import sys
+@@ -12,7 +12,7 @@
+
+ def istupleofstrings(obj):
+ return isinstance(obj, tuple) and len(obj) and all(
+- isinstance(o, types.StringTypes) for o in obj)
++ isinstance(o, (str,)) for o in obj)
+
+
+ class OptionValue(tuple):
+@@ -71,7 +71,7 @@
+ in the form of a tuple for when values are given to the option (in the form
+ --option=value[,value2...].
+ '''
+- def __nonzero__(self):
++ def __bool__(self):
+ return True
+
+
+@@ -96,7 +96,7 @@
+ if format_data:
+ message = message.format(**format_data)
+ super(ConflictingOptionError, self).__init__(message)
+- for k, v in format_data.iteritems():
++ for k, v in format_data.items():
+ setattr(self, k, v)
+
+
+@@ -132,7 +132,7 @@
+ 'At least an option name or an environment variable name must '
+ 'be given')
+ if name:
+- if not isinstance(name, types.StringTypes):
++ if not isinstance(name, (str,)):
+ raise InvalidOptionError('Option must be a string')
+ if not name.startswith('--'):
+ raise InvalidOptionError('Option must start with `--`')
+@@ -141,7 +141,7 @@
+ if not name.islower():
+ raise InvalidOptionError('Option must be all lowercase')
+ if env:
+- if not isinstance(env, types.StringTypes):
++ if not isinstance(env, (str,)):
+ raise InvalidOptionError(
+ 'Environment variable name must be a string')
+ if not env.isupper():
+@@ -151,8 +151,8 @@
+ isinstance(nargs, int) and nargs >= 0):
+ raise InvalidOptionError(
+ "nargs must be a positive integer, '?', '*' or '+'")
+- if (not isinstance(default, types.StringTypes) and
+- not isinstance(default, (bool, types.NoneType)) and
++ if (not isinstance(default, (str,)) and
++ not isinstance(default, (bool, type(None))) and
+ not istupleofstrings(default)):
+ raise InvalidOptionError(
+ 'default must be a bool, a string or a tuple of strings')
+@@ -224,7 +224,7 @@
+ ', '.join("'%s'" % c for c in choices))
+ elif has_choices:
+ maxargs = self.maxargs
+- if len(choices) < maxargs and maxargs != sys.maxint:
++ if len(choices) < maxargs and maxargs != sys.maxsize:
+ raise InvalidOptionError('Not enough `choices` for `nargs`')
+ self.choices = choices
+ self.help = help
+@@ -238,7 +238,7 @@
+ where prefix is one of 'with', 'without', 'enable' or 'disable'.
+ The '=values' part is optional. Values are separated with commas.
+ '''
+- if not isinstance(option, types.StringTypes):
++ if not isinstance(option, (str,)):
+ raise InvalidOptionError('Option must be a string')
+
+ elements = option.split('=', 1)
+@@ -291,7 +291,7 @@
+ def maxargs(self):
+ if isinstance(self.nargs, int):
+ return self.nargs
+- return 1 if self.nargs == '?' else sys.maxint
++ return 1 if self.nargs == '?' else sys.maxsize
+
+ def _validate_nargs(self, num):
+ minargs, maxargs = self.minargs, self.maxargs
+@@ -485,5 +485,5 @@
+
+ def __iter__(self):
+ for d in (self._args, self._extra_args):
+- for arg, pos in d.itervalues():
++ for arg, pos in d.values():
+ yield arg
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/configure/util.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/configure/util.py (refactored)
+@@ -2,7 +2,7 @@
+ # License, v. 2.0. If a copy of the MPL was not distributed with this
+ # file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+-from __future__ import absolute_import, print_function, unicode_literals
++
+
+ import codecs
+ import itertools
+@@ -52,7 +52,7 @@
+
+ def __cmp__(self, other):
+ # LooseVersion checks isinstance(StringType), so work around it.
+- if isinstance(other, unicode):
++ if isinstance(other, str):
+ other = other.encode('ascii')
+ return LooseVersion.__cmp__(self, other)
+
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/controller/building.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/controller/building.py (refactored)
+@@ -2,7 +2,7 @@
+ # License, v. 2.0. If a copy of the MPL was not distributed with this
+ # file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+-from __future__ import absolute_import, unicode_literals
++
+
+ import getpass
+ import json
+@@ -108,7 +108,7 @@
+ """
+ o = []
+
+- for tier, state in self.tiers.items():
++ for tier, state in list(self.tiers.items()):
+ t_entry = dict(
+ name=tier,
+ start=state['begin_time'],
+@@ -643,8 +643,8 @@
+
+ return '\n'.join(lines)
+
+- def __nonzero__(self):
+- relative_values = [v for k, v in self._values.items()
++ def __bool__(self):
++ relative_values = [v for k, v in list(self._values.items())
+ if k not in self.ABSOLUTE_KEYS]
+ return (all(v >= 0 for v in relative_values) and
+ any(v > 0 for v in relative_values))
+@@ -666,8 +666,8 @@
+ """Install test files."""
+
+ if self.is_clobber_needed():
+- print(INSTALL_TESTS_CLOBBER.format(
+- clobber_file=os.path.join(self.topobjdir, 'CLOBBER')))
++ print((INSTALL_TESTS_CLOBBER.format(
++ clobber_file=os.path.join(self.topobjdir, 'CLOBBER'))))
+ sys.exit(1)
+
+ if not test_objs:
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/controller/clobber.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/controller/clobber.py (refactored)
+@@ -2,7 +2,7 @@
+ # License, v. 2.0. If a copy of the MPL was not distributed with this
+ # file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+-from __future__ import absolute_import, print_function
++
+
+ r'''This module contains code for managing clobbering of the tree.'''
+
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/frontend/context.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/frontend/context.py (refactored)
+@@ -14,7 +14,7 @@
+ contain, you've come to the right place.
+ """
+
+-from __future__ import absolute_import, unicode_literals
++
+
+ import os
+
+@@ -234,15 +234,15 @@
+ This function is transactional: if setitem fails for one of the values,
+ the context is not updated at all."""
+ if isinstance(iterable, dict):
+- iterable = iterable.items()
++ iterable = list(iterable.items())
+
+ update = {}
+- for key, value in itertools.chain(iterable, kwargs.items()):
++ for key, value in itertools.chain(iterable, list(kwargs.items())):
+ stored_type = self._validate(key, value)
+ # Don't create an instance of stored_type if coercion is needed,
+ # until all values are validated.
+ update[key] = (value, stored_type)
+- for key, (value, stored_type) in update.items():
++ for key, (value, stored_type) in list(update.items()):
+ if not isinstance(value, stored_type):
+ update[key] = stored_type(value)
+ else:
+@@ -297,7 +297,7 @@
+ self.update(value)
+
+
+-class FinalTargetValue(ContextDerivedValue, unicode):
++class FinalTargetValue(ContextDerivedValue, str):
+ def __new__(cls, context, value=""):
+ if not value:
+ value = 'dist/'
+@@ -307,7 +307,7 @@
+ value += 'bin'
+ if context['DIST_SUBDIR']:
+ value += '/' + context['DIST_SUBDIR']
+- return unicode.__new__(cls, value)
++ return str.__new__(cls, value)
+
+
+ def Enum(*values):
+@@ -355,7 +355,7 @@
+ cls = SourcePath
+ return super(PathMeta, cls).__call__(context, value)
+
+-class Path(ContextDerivedValue, unicode):
++class Path(ContextDerivedValue, str, metaclass=PathMeta):
+ """Stores and resolves a source path relative to a given context
+
+ This class is used as a backing type for some of the sandbox variables.
+@@ -366,7 +366,6 @@
+ - '!objdir/relative/paths'
+ - '%/filesystem/absolute/paths'
+ """
+- __metaclass__ = PathMeta
+
+ def __new__(cls, context, value=None):
+ return super(Path, cls).__new__(cls, value)
+@@ -386,7 +385,7 @@
+ def __cmp__(self, other):
+ if isinstance(other, Path) and self.srcdir != other.srcdir:
+ return cmp(self.full_path, other.full_path)
+- return cmp(unicode(self), other)
++ return cmp(str(self), other)
+
+ # __cmp__ is not enough because unicode has __eq__, __ne__, etc. defined
+ # and __cmp__ is only used for those when they don't exist.
+@@ -544,7 +543,7 @@
+ __slots__ = tuple([name for name, _ in fields])
+
+ def __init__(self, context):
+- for fname, ftype in self._fields.items():
++ for fname, ftype in list(self._fields.items()):
+ if issubclass(ftype, ContextDerivedValue):
+ setattr(self, fname, self._fields[fname](context))
+ else:
+@@ -614,8 +613,8 @@
+ return _TypedListWithAction
+
+ WebPlatformTestManifest = TypedNamedTuple("WebPlatformTestManifest",
+- [("manifest_path", unicode),
+- ("test_root", unicode)])
++ [("manifest_path", str),
++ ("test_root", str)])
+ ManifestparserManifestList = OrderedListWithAction(read_manifestparser_manifest)
+ ReftestManifestList = OrderedListWithAction(read_reftest_manifest)
+ WptManifestList = TypedListWithAction(WebPlatformTestManifest, read_wpt_manifest)
+@@ -623,12 +622,12 @@
+ OrderedSourceList = ContextDerivedTypedList(SourcePath, StrictOrderingOnAppendList)
+ OrderedTestFlavorList = TypedList(Enum(*all_test_flavors()),
+ StrictOrderingOnAppendList)
+-OrderedStringList = TypedList(unicode, StrictOrderingOnAppendList)
++OrderedStringList = TypedList(str, StrictOrderingOnAppendList)
+ DependentTestsEntry = ContextDerivedTypedRecord(('files', OrderedSourceList),
+ ('tags', OrderedStringList),
+ ('flavors', OrderedTestFlavorList))
+ BugzillaComponent = TypedNamedTuple('BugzillaComponent',
+- [('product', unicode), ('component', unicode)])
++ [('product', str), ('component', str)])
+
+
+ class Files(SubContext):
+@@ -764,7 +763,7 @@
+ self.test_tags |= other.test_tags
+ self.test_flavors |= other.test_flavors
+
+- for k, v in other.items():
++ for k, v in list(other.items()):
+ if k == 'IMPACTED_TESTS':
+ self.test_files |= set(mozpath.relpath(e.full_path, e.context.config.topsrcdir)
+ for e in v.files)
+@@ -818,7 +817,7 @@
+
+ bug_components = Counter()
+
+- for f in files.values():
++ for f in list(files.values()):
+ bug_component = f.get('BUG_COMPONENT')
+ if bug_component:
+ bug_components[bug_component] += 1
+@@ -889,11 +888,11 @@
+ file.
+ """),
+
+- 'ANDROID_APK_NAME': (unicode, unicode,
++ 'ANDROID_APK_NAME': (str, str,
+ """The name of an Android APK file to generate.
+ """),
+
+- 'ANDROID_APK_PACKAGE': (unicode, unicode,
++ 'ANDROID_APK_PACKAGE': (str, str,
+ """The name of the Android package to generate R.java for, like org.mozilla.gecko.
+ """),
+
+@@ -962,7 +961,7 @@
+ """),
+
+ 'GENERATED_FILES': (StrictOrderingOnAppendListWithFlagsFactory({
+- 'script': unicode,
++ 'script': str,
+ 'inputs': list }), list,
+ """Generic generated files.
+
+@@ -1107,7 +1106,7 @@
+ """Like ``OBJDIR_FILES``, with preprocessing. Use sparingly.
+ """),
+
+- 'FINAL_LIBRARY': (unicode, unicode,
++ 'FINAL_LIBRARY': (str, str,
+ """Library in which the objects of the current directory will be linked.
+
+ This variable contains the name of a library, defined elsewhere with
+@@ -1158,7 +1157,7 @@
+ """A list of python unit tests.
+ """),
+
+- 'HOST_LIBRARY_NAME': (unicode, unicode,
++ 'HOST_LIBRARY_NAME': (str, str,
+ """Name of target library generated when cross compiling.
+ """),
+
+@@ -1176,7 +1175,7 @@
+ libraries that link into this library via FINAL_LIBRARY.
+ """),
+
+- 'LIBRARY_NAME': (unicode, unicode,
++ 'LIBRARY_NAME': (str, str,
+ """The code name of the library generated for a directory.
+
+ By default STATIC_LIBRARY_NAME and SHARED_LIBRARY_NAME take this name.
+@@ -1188,7 +1187,7 @@
+ ``example/components/xpcomsample.lib`` on Windows.
+ """),
+
+- 'SHARED_LIBRARY_NAME': (unicode, unicode,
++ 'SHARED_LIBRARY_NAME': (str, str,
+ """The name of the static library generated for a directory, if it needs to
+ differ from the library code name.
+
+@@ -1202,7 +1201,7 @@
+ Implies FORCE_SHARED_LIB.
+ """),
+
+- 'STATIC_LIBRARY_NAME': (unicode, unicode,
++ 'STATIC_LIBRARY_NAME': (str, str,
+ """The name of the static library generated for a directory, if it needs to
+ differ from the library code name.
+
+@@ -1238,37 +1237,37 @@
+
+ This variable contains a list of system libaries to link against.
+ """),
+- 'RCFILE': (unicode, unicode,
++ 'RCFILE': (str, str,
+ """The program .rc file.
+
+ This variable can only be used on Windows.
+ """),
+
+- 'RESFILE': (unicode, unicode,
++ 'RESFILE': (str, str,
+ """The program .res file.
+
+ This variable can only be used on Windows.
+ """),
+
+- 'RCINCLUDE': (unicode, unicode,
++ 'RCINCLUDE': (str, str,
+ """The resource script file to be included in the default .res file.
+
+ This variable can only be used on Windows.
+ """),
+
+- 'DEFFILE': (unicode, unicode,
++ 'DEFFILE': (str, str,
+ """The program .def (module definition) file.
+
+ This variable can only be used on Windows.
+ """),
+
+- 'LD_VERSION_SCRIPT': (unicode, unicode,
++ 'LD_VERSION_SCRIPT': (str, str,
+ """The linker version script for shared libraries.
+
+ This variable can only be used on Linux.
+ """),
+
+- 'SYMBOLS_FILE': (Path, unicode,
++ 'SYMBOLS_FILE': (Path, str,
+ """A file containing a list of symbols to export from a shared library.
+
+ The given file contains a list of symbols to be exported, and is
+@@ -1323,7 +1322,7 @@
+ ``BIN_SUFFIX``, the name will remain unchanged.
+ """),
+
+- 'SONAME': (unicode, unicode,
++ 'SONAME': (str, str,
+ """The soname of the shared object currently being linked
+
+ soname is the "logical name" of a shared object, often used to provide
+@@ -1379,7 +1378,7 @@
+ ``GENERATED_FILES``.
+ """),
+
+- 'PROGRAM' : (unicode, unicode,
++ 'PROGRAM' : (str, str,
+ """Compiled executable name.
+
+ If the configuration token ``BIN_SUFFIX`` is set, its value will be
+@@ -1387,7 +1386,7 @@
+ ``BIN_SUFFIX``, ``PROGRAM`` will remain unchanged.
+ """),
+
+- 'HOST_PROGRAM' : (unicode, unicode,
++ 'HOST_PROGRAM' : (str, str,
+ """Compiled host executable name.
+
+ If the configuration token ``HOST_BIN_SUFFIX`` is set, its value will be
+@@ -1425,7 +1424,7 @@
+ files.
+ """),
+
+- 'XPIDL_MODULE': (unicode, unicode,
++ 'XPIDL_MODULE': (str, str,
+ """XPCOM Interface Definition Module Name.
+
+ This is the name of the ``.xpt`` file that is created by linking
+@@ -1576,14 +1575,14 @@
+ """),
+
+ # The following variables are used to control the target of installed files.
+- 'XPI_NAME': (unicode, unicode,
++ 'XPI_NAME': (str, str,
+ """The name of an extension XPI to generate.
+
+ When this variable is present, the results of this directory will end up
+ being packaged into an extension instead of the main dist/bin results.
+ """),
+
+- 'DIST_SUBDIR': (unicode, unicode,
++ 'DIST_SUBDIR': (str, str,
+ """The name of an alternate directory to install files to.
+
+ When this variable is present, the results of this directory will end up
+@@ -1591,7 +1590,7 @@
+ otherwise be placed.
+ """),
+
+- 'FINAL_TARGET': (FinalTargetValue, unicode,
++ 'FINAL_TARGET': (FinalTargetValue, str,
+ """The name of the directory to install targets to.
+
+ The directory is relative to the top of the object directory. The
+@@ -1622,7 +1621,7 @@
+
+ 'GYP_DIRS': (StrictOrderingOnAppendListWithFlagsFactory({
+ 'variables': dict,
+- 'input': unicode,
++ 'input': str,
+ 'sandbox_vars': dict,
+ 'non_unified_sources': StrictOrderingOnAppendList,
+ }), list,
+@@ -1799,7 +1798,7 @@
+ }
+
+ # Sanity check: we don't want any variable above to have a list as storage type.
+-for name, (storage_type, input_types, docs) in VARIABLES.items():
++for name, (storage_type, input_types, docs) in list(VARIABLES.items()):
+ if storage_type == list:
+ raise RuntimeError('%s has a "list" storage type. Use "List" instead.'
+ % name)
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/frontend/data.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/frontend/data.py (refactored)
+@@ -15,7 +15,7 @@
+ structures.
+ """
+
+-from __future__ import absolute_import, unicode_literals
++
+
+ from mozbuild.util import StrictOrderingOnAppendList
+ from mozpack.chrome.manifest import ManifestEntry
+@@ -186,7 +186,7 @@
+ self.defines = defines
+
+ def get_defines(self):
+- for define, value in self.defines.iteritems():
++ for define, value in self.defines.items():
+ if value is True:
+ yield('-D%s' % define)
+ elif value is False:
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/frontend/emitter.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/frontend/emitter.py (refactored)
+@@ -2,7 +2,7 @@
+ # License, v. 2.0. If a copy of the MPL was not distributed with this
+ # file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+-from __future__ import absolute_import, unicode_literals
++
+
+ import itertools
+ import logging
+@@ -120,8 +120,8 @@
+ # arguments. This gross hack works around the problem until we
+ # rid ourselves of 2.6.
+ self.info = {}
+- for k, v in mozinfo.info.items():
+- if isinstance(k, unicode):
++ for k, v in list(mozinfo.info.items()):
++ if isinstance(k, str):
+ k = k.encode('ascii')
+ self.info[k] = v
+
+@@ -197,7 +197,7 @@
+
+ def _emit_libs_derived(self, contexts):
+ # First do FINAL_LIBRARY linkage.
+- for lib in (l for libs in self._libs.values() for l in libs):
++ for lib in (l for libs in list(self._libs.values()) for l in libs):
+ if not isinstance(lib, (StaticLibrary, RustLibrary)) or not lib.link_into:
+ continue
+ if lib.link_into not in self._libs:
+@@ -257,12 +257,12 @@
+ lib.link_into == outerlib.basename):
+ propagate_defines(lib, defines)
+
+- for lib in (l for libs in self._libs.values() for l in libs):
++ for lib in (l for libs in list(self._libs.values()) for l in libs):
+ if isinstance(lib, Library):
+ propagate_defines(lib, lib.lib_defines)
+ yield lib
+
+- for obj in self._binaries.values():
++ for obj in list(self._binaries.values()):
+ yield obj
+
+ LIBRARY_NAME_VAR = {
+@@ -321,7 +321,7 @@
+ libs[key] = l
+ if key not in libs:
+ libs[key] = l
+- candidates = libs.values()
++ candidates = list(libs.values())
+ if force_static and not candidates:
+ if dir:
+ raise SandboxValidationError(
+@@ -383,9 +383,9 @@
+
+ def _verify_deps(self, context, crate_dir, crate_name, dependencies, description='Dependency'):
+ """Verify that a crate's dependencies all specify local paths."""
+- for dep_crate_name, values in dependencies.iteritems():
++ for dep_crate_name, values in dependencies.items():
+ # A simple version number.
+- if isinstance(values, (str, unicode)):
++ if isinstance(values, str):
+ raise SandboxValidationError(
+ '%s %s of crate %s does not list a path' % (description, dep_crate_name, crate_name),
+ context)
+@@ -463,7 +463,7 @@
+ ' in [profile.%s] section') % (libname, profile_name),
+ context)
+
+- dependencies = set(config.get('dependencies', {}).iterkeys())
++ dependencies = set(config.get('dependencies', {}).keys())
+
+ return RustLibrary(context, libname, cargo_file, crate_type,
+ dependencies, **static_args)
+@@ -738,7 +738,7 @@
+ assert not gen_sources['UNIFIED_SOURCES']
+
+ no_pgo = context.get('NO_PGO')
+- no_pgo_sources = [f for f, flags in all_flags.iteritems()
++ no_pgo_sources = [f for f, flags in all_flags.items()
+ if flags.no_pgo]
+ if no_pgo:
+ if no_pgo_sources:
+@@ -765,7 +765,7 @@
+
+ # The inverse of the above, mapping suffixes to their canonical suffix.
+ canonicalized_suffix_map = {}
+- for suffix, alternatives in suffix_map.iteritems():
++ for suffix, alternatives in suffix_map.items():
+ alternatives.add(suffix)
+ for a in alternatives:
+ canonicalized_suffix_map[a] = suffix
+@@ -786,7 +786,7 @@
+ # a directory with mixed C and C++ source, but it's not that important.
+ cxx_sources = defaultdict(bool)
+
+- for variable, (klass, gen_klass, suffixes) in varmap.items():
++ for variable, (klass, gen_klass, suffixes) in list(varmap.items()):
+ allowed_suffixes = set().union(*[suffix_map[s] for s in suffixes])
+
+ # First ensure that we haven't been given filetypes that we don't
+@@ -812,7 +812,7 @@
+ obj = cls(*arglist)
+ yield obj
+
+- for f, flags in all_flags.iteritems():
++ for f, flags in all_flags.items():
+ if flags.flags:
+ ext = mozpath.splitext(f)[1]
+ yield PerSourceFlag(context, f, flags.flags)
+@@ -958,7 +958,7 @@
+ for obj in self._handle_linkables(context, passthru, generated_files):
+ yield obj
+
+- generated_files.update(['%s%s' % (k, self.config.substs.get('BIN_SUFFIX', '')) for k in self._binaries.keys()])
++ generated_files.update(['%s%s' % (k, self.config.substs.get('BIN_SUFFIX', '')) for k in list(self._binaries.keys())])
+
+ components = []
+ for var, cls in (
+@@ -1055,10 +1055,10 @@
+ for obj in self._process_jar_manifests(context):
+ yield obj
+
+- for name, jar in context.get('JAVA_JAR_TARGETS', {}).items():
++ for name, jar in list(context.get('JAVA_JAR_TARGETS', {}).items()):
+ yield ContextWrapped(context, jar)
+
+- for name, data in context.get('ANDROID_ECLIPSE_PROJECT_TARGETS', {}).items():
++ for name, data in list(context.get('ANDROID_ECLIPSE_PROJECT_TARGETS', {}).items()):
+ yield ContextWrapped(context, data)
+
+ if context.get('USE_YASM') is True:
+@@ -1127,7 +1127,7 @@
+ script = mozpath.join(mozpath.dirname(mozpath.dirname(__file__)),
+ 'action', 'process_define_files.py')
+ yield GeneratedFile(context, script, 'process_define_file',
+- unicode(path),
++ str(path),
+ [Path(context, path + '.in')])
+
+ generated_files = context.get('GENERATED_FILES')
+@@ -1170,7 +1170,7 @@
+ yield GeneratedFile(context, script, method, outputs, inputs)
+
+ def _process_test_manifests(self, context):
+- for prefix, info in TEST_MANIFESTS.items():
++ for prefix, info in list(TEST_MANIFESTS.items()):
+ for path, manifest in context.get('%s_MANIFESTS' % prefix, []):
+ for obj in self._process_test_manifest(context, info, path, manifest):
+ yield obj
+@@ -1261,7 +1261,7 @@
+
+ process_support_files(test)
+
+- for path, m_defaults in mpmanifest.manifest_defaults.items():
++ for path, m_defaults in list(mpmanifest.manifest_defaults.items()):
+ process_support_files(m_defaults)
+
+ # We also copy manifests into the output directory,
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/frontend/gyp_reader.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/frontend/gyp_reader.py (refactored)
+@@ -2,7 +2,7 @@
+ # License, v. 2.0. If a copy of the MPL was not distributed with this
+ # file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+-from __future__ import absolute_import, unicode_literals
++
+
+ import gyp
+ import sys
+@@ -69,7 +69,7 @@
+
+
+ def encode(value):
+- if isinstance(value, unicode):
++ if isinstance(value, str):
+ return value.encode('utf-8')
+ return value
+
+@@ -87,7 +87,7 @@
+ # gyp expects plain str instead of unicode. The frontend code gives us
+ # unicode strings, so convert them.
+ path = encode(path)
+- str_vars = dict((name, encode(value)) for name, value in vars.items())
++ str_vars = dict((name, encode(value)) for name, value in list(vars.items()))
+
+ params = {
+ b'parallel': False,
+@@ -222,7 +222,7 @@
+ if not f:
+ continue
+ # the result may be a string or a list.
+- if isinstance(f, types.StringTypes):
++ if isinstance(f, (str,)):
+ context[var].append(f)
+ else:
+ context[var].extend(f)
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/frontend/mach_commands.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/frontend/mach_commands.py (refactored)
+@@ -2,7 +2,7 @@
+ # License, v. 2.0. If a copy of the MPL was not distributed with this
+ # file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+-from __future__ import absolute_import, print_function, unicode_literals
++
+
+ from collections import defaultdict
+ import os
+@@ -105,13 +105,13 @@
+ """
+ components = defaultdict(set)
+ try:
+- for p, m in self._get_files_info(paths, rev=rev).items():
++ for p, m in list(self._get_files_info(paths, rev=rev).items()):
+ components[m.get('BUG_COMPONENT')].add(p)
+ except InvalidPathException as e:
+ print(e.message)
+ return 1
+
+- for component, files in sorted(components.items(), key=lambda x: (x is None, x)):
++ for component, files in sorted(list(components.items()), key=lambda x: (x is None, x)):
+ print('%s :: %s' % (component.product, component.component) if component else 'UNKNOWN')
+ for f in sorted(files):
+ print(' %s' % f)
+@@ -139,7 +139,7 @@
+ help='Paths whose data to query')
+ def file_info_test_deps(self, paths, rev=None):
+ try:
+- for p, m in self._get_files_info(paths, rev=rev).items():
++ for p, m in list(self._get_files_info(paths, rev=rev).items()):
+ print('%s:' % mozpath.relpath(p, self.topsrcdir))
+ if m.test_files:
+ print('\tTest file patterns:')
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/frontend/reader.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/frontend/reader.py (refactored)
+@@ -16,7 +16,7 @@
+ It does this by examining specific variables populated during execution.
+ """
+
+-from __future__ import absolute_import, print_function, unicode_literals
++
+
+ import ast
+ import inspect
+@@ -80,11 +80,12 @@
+ )
+
+ from mozbuild.base import ExecutionSummary
++from functools import reduce
+
+
+ if sys.version_info.major == 2:
+- text_type = unicode
+- type_type = types.TypeType
++ text_type = str
++ type_type = type
+ else:
+ text_type = str
+ type_type = type
+@@ -126,7 +127,7 @@
+ b'JS_STANDALONE': b'1',
+ })
+ udict = {}
+- for k, v in self.substs.items():
++ for k, v in list(self.substs.items()):
+ if isinstance(v, str):
+ udict[k.decode('utf-8')] = v.decode('utf-8')
+ else:
+@@ -338,7 +339,7 @@
+ raise Exception('`template` is a function decorator. You must '
+ 'use it as `@template` preceding a function declaration.')
+
+- name = func.func_name
++ name = func.__name__
+
+ if name in self.templates:
+ raise KeyError(
+@@ -417,7 +418,7 @@
+ klass = self._context.__class__
+ self._context.__class__ = TemplateContext
+ # The sandbox will do all the necessary checks for these merges.
+- for key, value in context.items():
++ for key, value in list(context.items()):
+ if isinstance(value, dict):
+ self[key].update(value)
+ elif isinstance(value, (list, HierarchicalStringList)):
+@@ -434,10 +435,10 @@
+
+ class TemplateFunction(object):
+ def __init__(self, func, sandbox):
+- self.path = func.func_code.co_filename
+- self.name = func.func_name
+-
+- code = func.func_code
++ self.path = func.__code__.co_filename
++ self.name = func.__name__
++
++ code = func.__code__
+ firstlineno = code.co_firstlineno
+ lines = sandbox._current_source.splitlines(True)
+ lines = inspect.getblock(lines[firstlineno - 1:])
+@@ -476,8 +477,8 @@
+ compile(func_ast, self.path, 'exec'),
+ glob,
+ self.name,
+- func.func_defaults,
+- func.func_closure,
++ func.__defaults__,
++ func.__closure__,
+ )
+ func()
+
+@@ -491,11 +492,11 @@
+ '__builtins__': sandbox._builtins
+ }
+ func = types.FunctionType(
+- self._func.func_code,
++ self._func.__code__,
+ glob,
+ self.name,
+- self._func.func_defaults,
+- self._func.func_closure
++ self._func.__defaults__,
++ self._func.__closure__
+ )
+ sandbox.exec_function(func, args, kwargs, self.path,
+ becomes_current_path=False)
+@@ -511,7 +512,7 @@
+ def visit_Str(self, node):
+ # String nodes we got from the AST parser are str, but we want
+ # unicode literals everywhere, so transform them.
+- node.s = unicode(node.s)
++ node.s = str(node.s)
+ return node
+
+ def visit_Name(self, node):
+@@ -644,7 +645,7 @@
+
+ for l in traceback.format_exception(type(self.other), self.other,
+ self.trace):
+- s.write(unicode(l))
++ s.write(str(l))
+
+ return s.getvalue()
+
+@@ -794,7 +795,7 @@
+ s.write(' %s\n' % inner.args[2])
+ s.write('\n')
+ close_matches = difflib.get_close_matches(inner.args[2],
+- VARIABLES.keys(), 2)
++ list(VARIABLES.keys()), 2)
+ if close_matches:
+ s.write('Maybe you meant %s?\n' % ' or '.join(close_matches))
+ s.write('\n')
+@@ -1196,7 +1197,7 @@
+
+ recurse_info[d][key] = dict(sandbox.metadata[key])
+
+- for path, child_metadata in recurse_info.items():
++ for path, child_metadata in list(recurse_info.items()):
+ child_path = path.join('moz.build').full_path
+
+ # Ensure we don't break out of the topsrcdir. We don't do realpath
+@@ -1288,7 +1289,7 @@
+ # There is room to improve this code (and the code in
+ # _find_relevant_mozbuilds) to better handle multiple files in the same
+ # directory. Bug 1136966 tracks.
+- for path, mbpaths in relevants.items():
++ for path, mbpaths in list(relevants.items()):
+ path_mozbuilds[path] = [mozpath.join(topsrcdir, p) for p in mbpaths]
+
+ for i, mbpath in enumerate(mbpaths[0:-1]):
+@@ -1325,7 +1326,7 @@
+ all_contexts.append(context)
+
+ result = {}
+- for path, paths in path_mozbuilds.items():
++ for path, paths in list(path_mozbuilds.items()):
+ result[path] = reduce(lambda x, y: x + y, (contexts[p] for p in paths), [])
+
+ return result, all_contexts
+@@ -1352,7 +1353,7 @@
+
+ r = {}
+
+- for path, ctxs in paths.items():
++ for path, ctxs in list(paths.items()):
+ flags = Files(Context())
+
+ for ctx in ctxs:
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/frontend/sandbox.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/frontend/sandbox.py (refactored)
+@@ -17,7 +17,7 @@
+ user-friendly error messages in the case of errors.
+ """
+
+-from __future__ import absolute_import, unicode_literals
++
+
+ import os
+ import sys
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/test/common.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/test/common.py (refactored)
+@@ -2,7 +2,7 @@
+ # License, v. 2.0. If a copy of the MPL was not distributed with this
+ # file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+-from __future__ import unicode_literals
++
+
+ from mach.logging import LoggingManager
+
+@@ -36,7 +36,7 @@
+ }, **extra_substs)
+
+ self.substs_unicode = ReadOnlyDict({k.decode('utf-8'): v.decode('utf-8',
+- 'replace') for k, v in self.substs.items()})
++ 'replace') for k, v in list(self.substs.items())})
+
+ self.defines = self.substs
+
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/test/test_base.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/test/test_base.py (refactored)
+@@ -2,7 +2,7 @@
+ # License, v. 2.0. If a copy of the MPL was not distributed with this
+ # file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+-from __future__ import unicode_literals
++
+
+ import json
+ import os
+@@ -12,7 +12,7 @@
+ import tempfile
+ import unittest
+
+-from cStringIO import StringIO
++from io import StringIO
+ from mozfile.mozfile import NamedTemporaryFile
+
+ from mozunit import main
+@@ -93,7 +93,7 @@
+ mozconfig = os.path.join(d, 'mozconfig')
+ with open(mozconfig, 'wt') as fh:
+ fh.write('mk_add_options MOZ_OBJDIR=@TOPSRCDIR@/foo/@CONFIG_GUESS@')
+- print('Wrote mozconfig %s' % mozconfig)
++ print(('Wrote mozconfig %s' % mozconfig))
+
+ topobjdir = os.path.join(d, 'foo', guess)
+ os.makedirs(topobjdir)
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/test/test_containers.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/test/test_containers.py (refactored)
+@@ -152,7 +152,7 @@
+
+ self.assertEqual(test['foo'], 1)
+
+- self.assertEqual(test.keys(), ['foo', 'bar' ])
++ self.assertEqual(list(test.keys()), ['foo', 'bar' ])
+
+ def test_defaults(self):
+ test = OrderedDefaultDict(bool, {'foo': 1 })
+@@ -161,7 +161,7 @@
+
+ self.assertEqual(test['qux'], False)
+
+- self.assertEqual(test.keys(), ['foo', 'qux' ])
++ self.assertEqual(list(test.keys()), ['foo', 'qux' ])
+
+
+ class TestKeyedDefaultDict(unittest.TestCase):
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/test/test_dotproperties.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/test/test_dotproperties.py (refactored)
+@@ -1,11 +1,11 @@
+ # -*- coding: utf-8 -*-
+
+-from __future__ import unicode_literals
++
+
+ import os
+ import unittest
+
+-from StringIO import StringIO
++from io import StringIO
+
+ import mozpack.path as mozpath
+
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/test/test_expression.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/test/test_expression.py (refactored)
+@@ -25,8 +25,8 @@
+
+ def test_in(self):
+ """test 'var in context' to not fall for fallback"""
+- self.assert_('FAIL' in self.c)
+- self.assert_('PASS' not in self.c)
++ self.assertTrue('FAIL' in self.c)
++ self.assertTrue('PASS' not in self.c)
+
+ class TestExpression(unittest.TestCase):
+ """
+@@ -48,16 +48,16 @@
+
+ def test_not(self):
+ """Test for the ! operator"""
+- self.assert_(Expression('!0').evaluate(self.c))
+- self.assert_(not Expression('!1').evaluate(self.c))
++ self.assertTrue(Expression('!0').evaluate(self.c))
++ self.assertTrue(not Expression('!1').evaluate(self.c))
+
+ def test_equals(self):
+ """ Test for the == operator"""
+- self.assert_(Expression('FAIL == PASS').evaluate(self.c))
++ self.assertTrue(Expression('FAIL == PASS').evaluate(self.c))
+
+ def test_notequals(self):
+ """ Test for the != operator"""
+- self.assert_(Expression('FAIL != 1').evaluate(self.c))
++ self.assertTrue(Expression('FAIL != 1').evaluate(self.c))
+
+ def test_logical_and(self):
+ """ Test for the && operator"""
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/test/test_jarmaker.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/test/test_jarmaker.py (refactored)
+@@ -2,14 +2,14 @@
+ # License, v. 2.0. If a copy of the MPL was not distributed with this
+ # file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+-from __future__ import print_function
++
+ import unittest
+
+ import os, sys, os.path, time, inspect
+ from filecmp import dircmp
+ from tempfile import mkdtemp
+ from shutil import rmtree, copy2
+-from StringIO import StringIO
++from io import StringIO
+ from zipfile import ZipFile
+ import mozunit
+
+@@ -117,12 +117,12 @@
+ """Helper to report rich results on difference between two directories.
+ """
+ def _fillDiff(self, dc, rv, basepath="{0}"):
+- rv['right_only'] += map(lambda l: basepath.format(l), dc.right_only)
+- rv['left_only'] += map(lambda l: basepath.format(l), dc.left_only)
+- rv['diff_files'] += map(lambda l: basepath.format(l), dc.diff_files)
+- rv['funny'] += map(lambda l: basepath.format(l), dc.common_funny)
+- rv['funny'] += map(lambda l: basepath.format(l), dc.funny_files)
+- for subdir, _dc in dc.subdirs.iteritems():
++ rv['right_only'] += [basepath.format(l) for l in dc.right_only]
++ rv['left_only'] += [basepath.format(l) for l in dc.left_only]
++ rv['diff_files'] += [basepath.format(l) for l in dc.diff_files]
++ rv['funny'] += [basepath.format(l) for l in dc.common_funny]
++ rv['funny'] += [basepath.format(l) for l in dc.funny_files]
++ for subdir, _dc in dc.subdirs.items():
+ self._fillDiff(_dc, rv, basepath.format(subdir + "/{0}"))
+ def allResults(self, left, right):
+ rv = {'right_only':[], 'left_only':[],
+@@ -295,7 +295,7 @@
+ ('hoge', 'foo', '2'): ('qux', 'foo', '2'),
+ ('hoge', 'baz'): ('qux', 'baz'),
+ }
+- for dest, src in expected_symlinks.iteritems():
++ for dest, src in expected_symlinks.items():
+ srcpath = os.path.join(self.srcdir, *src)
+ destpath = os.path.join(self.builddir, 'chrome', 'test', 'dir',
+ *dest)
+@@ -317,7 +317,7 @@
+ def test_en_US(self):
+ jm = self.jm
+ jm.makeJar(self.fake_empty_file, '/NO_OUTPUT_REQUIRED')
+- self.assertEquals(jm.localedirs,
++ self.assertEqual(jm.localedirs,
+ [
+ os.path.join(os.path.abspath('/TOPSOURCEDIR'),
+ 'browser/locales', 'en-US')
+@@ -326,13 +326,13 @@
+ jm = self.jm
+ jm.l10nbase = '/L10N_BASE'
+ jm.makeJar(self.fake_empty_file, '/NO_OUTPUT_REQUIRED')
+- self.assertEquals(jm.localedirs, [os.path.join('/L10N_BASE', 'browser')])
++ self.assertEqual(jm.localedirs, [os.path.join('/L10N_BASE', 'browser')])
+ def test_l10n_merge(self):
+ jm = self.jm
+ jm.l10nbase = '/L10N_BASE'
+ jm.l10nmerge = '/L10N_MERGE'
+ jm.makeJar(self.fake_empty_file, '/NO_OUTPUT_REQUIRED')
+- self.assertEquals(jm.localedirs,
++ self.assertEqual(jm.localedirs,
+ [os.path.join('/L10N_MERGE', 'browser'),
+ os.path.join('/L10N_BASE', 'browser'),
+ os.path.join(os.path.abspath('/TOPSOURCEDIR'),
+@@ -346,7 +346,7 @@
+ ''')
+ jarcontents.name = 'override.mn'
+ jm.makeJar(jarcontents, '/NO_OUTPUT_REQUIRED')
+- self.assertEquals(jm.localedirs,
++ self.assertEqual(jm.localedirs,
+ [
+ os.path.join(os.path.abspath('/TOPSOURCEDIR'),
+ 'dom/locales', 'en-US')
+@@ -360,7 +360,7 @@
+ ''')
+ jarcontents.name = 'override.mn'
+ jm.makeJar(jarcontents, '/NO_OUTPUT_REQUIRED')
+- self.assertEquals(jm.localedirs, [os.path.join('/L10N_BASE', 'dom')])
++ self.assertEqual(jm.localedirs, [os.path.join('/L10N_BASE', 'dom')])
+
+
+ if __name__ == '__main__':
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/test/test_line_endings.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/test/test_line_endings.py (refactored)
+@@ -1,6 +1,6 @@
+ import unittest
+
+-from StringIO import StringIO
++from io import StringIO
+ import os
+ import sys
+ import os.path
+@@ -30,17 +30,17 @@
+ def testMac(self):
+ self.createFile(['\x0D']*3)
+ self.pp.do_include(self.tempnam)
+- self.assertEquals(self.pp.out.getvalue(), 'a\nb\nc\n')
++ self.assertEqual(self.pp.out.getvalue(), 'a\nb\nc\n')
+
+ def testUnix(self):
+ self.createFile(['\x0A']*3)
+ self.pp.do_include(self.tempnam)
+- self.assertEquals(self.pp.out.getvalue(), 'a\nb\nc\n')
++ self.assertEqual(self.pp.out.getvalue(), 'a\nb\nc\n')
+
+ def testWindows(self):
+ self.createFile(['\x0D\x0A']*3)
+ self.pp.do_include(self.tempnam)
+- self.assertEquals(self.pp.out.getvalue(), 'a\nb\nc\n')
++ self.assertEqual(self.pp.out.getvalue(), 'a\nb\nc\n')
+
+ if __name__ == '__main__':
+ mozunit.main()
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/test/test_makeutil.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/test/test_makeutil.py (refactored)
+@@ -11,7 +11,7 @@
+ from mozunit import main
+ import os
+ import unittest
+-from StringIO import StringIO
++from io import StringIO
+
+
+ class TestMakefile(unittest.TestCase):
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/test/test_mozconfig.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/test/test_mozconfig.py (refactored)
+@@ -2,7 +2,7 @@
+ # License, v. 2.0. If a copy of the MPL was not distributed with this
+ # file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+-from __future__ import unicode_literals
++
+
+ import os
+ import unittest
+@@ -480,9 +480,9 @@
+
+ self.assertTrue(e.exception.message.startswith(
+ 'Evaluation of your mozconfig exited with an error'))
+- self.assertEquals(e.exception.path,
++ self.assertEqual(e.exception.path,
+ mozconfig.name.replace(os.sep, '/'))
+- self.assertEquals(e.exception.output, ['hello world'])
++ self.assertEqual(e.exception.output, ['hello world'])
+
+
+ if __name__ == '__main__':
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/test/test_mozinfo.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/test/test_mozinfo.py (refactored)
+@@ -8,7 +8,7 @@
+ import tempfile
+ import unittest
+
+-from StringIO import StringIO
++from io import StringIO
+
+ import mozunit
+
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/test/test_preprocessor.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/test/test_preprocessor.py (refactored)
+@@ -4,7 +4,7 @@
+
+ import unittest
+
+-from StringIO import StringIO
++from io import StringIO
+ import os
+ import shutil
+
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/test/test_pythonutil.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/test/test_pythonutil.py (refactored)
+@@ -12,7 +12,7 @@
+ def test_iter_modules_in_path(self):
+ mozbuild_path = os.path.normcase(os.path.dirname(os.path.dirname(__file__)))
+ paths = list(iter_modules_in_path(mozbuild_path))
+- self.assertEquals(sorted(paths), [
++ self.assertEqual(sorted(paths), [
+ os.path.join(os.path.abspath(mozbuild_path), '__init__.py'),
+ os.path.join(os.path.abspath(mozbuild_path), 'pythonutil.py'),
+ os.path.join(os.path.abspath(mozbuild_path), 'test', 'test_pythonutil.py'),
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/test/test_testing.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/test/test_testing.py (refactored)
+@@ -2,9 +2,9 @@
+ # License, v. 2.0. If a copy of the MPL was not distributed with this
+ # file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+-from __future__ import unicode_literals
+-
+-import cPickle as pickle
++
++
++import pickle as pickle
+ import os
+ import shutil
+ import tempfile
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/test/test_util.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/test/test_util.py (refactored)
+@@ -3,7 +3,7 @@
+ # License, v. 2.0. If a copy of the MPL was not distributed with this
+ # file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+-from __future__ import unicode_literals
++
+
+ import itertools
+ import hashlib
+@@ -110,7 +110,7 @@
+ '''
+ def __call__(self, name, mode):
+ if 'w' in mode:
+- raise Exception, 'Unexpected open with write mode'
++ raise Exception('Unexpected open with write mode')
+ return MockedOpen.__call__(self, name, mode)
+
+ with MyMockedOpen({'file': 'content'}):
+@@ -432,7 +432,7 @@
+ self.assertEqual(len(l), 0)
+ original = ['a', 'b', 'c']
+ l = ListWithAction(['a', 'b', 'c'], action=self.action)
+- expected = map(self.action, original)
++ expected = list(map(self.action, original))
+ self.assertSameList(expected, l)
+
+ with self.assertRaises(ValueError):
+@@ -445,7 +445,7 @@
+ l = ListWithAction(action=self.action)
+ original = ['a', 'b']
+ l.extend(original)
+- expected = map(self.action, original)
++ expected = list(map(self.action, original))
+ self.assertSameList(expected, l)
+
+ with self.assertRaises(ValueError):
+@@ -455,7 +455,7 @@
+ l = ListWithAction(action=self.action)
+ original = ['a', 'b']
+ l[:] = original
+- expected = map(self.action, original)
++ expected = list(map(self.action, original))
+ self.assertSameList(expected, l)
+
+ with self.assertRaises(ValueError):
+@@ -465,7 +465,7 @@
+ l = ListWithAction(action=self.action)
+ original = ['a', 'b']
+ l2 = l + original
+- expected = map(self.action, original)
++ expected = list(map(self.action, original))
+ self.assertSameList(expected, l2)
+
+ with self.assertRaises(ValueError):
+@@ -475,7 +475,7 @@
+ l = ListWithAction(action=self.action)
+ original = ['a', 'b']
+ l += original
+- expected = map(self.action, original)
++ expected = list(map(self.action, original))
+ self.assertSameList(expected, l)
+
+ with self.assertRaises(ValueError):
+@@ -524,7 +524,7 @@
+
+ def test_strict_ordering_on_append_list_with_flags_factory_extend(self):
+ FooList = StrictOrderingOnAppendListWithFlagsFactory({
+- 'foo': bool, 'bar': unicode
++ 'foo': bool, 'bar': str
+ })
+ foo = FooList(['a', 'b', 'c'])
+ foo['a'].foo = True
+@@ -532,7 +532,7 @@
+
+ # Don't allow extending lists with different flag definitions.
+ BarList = StrictOrderingOnAppendListWithFlagsFactory({
+- 'foo': unicode, 'baz': bool
++ 'foo': str, 'baz': bool
+ })
+ bar = BarList(['d', 'e', 'f'])
+ bar['d'].foo = 'foo'
+@@ -752,9 +752,9 @@
+
+ class TypedTestStrictOrderingOnAppendList(unittest.TestCase):
+ def test_init(self):
+- class Unicode(unicode):
++ class Unicode(str):
+ def __init__(self, other):
+- if not isinstance(other, unicode):
++ if not isinstance(other, str):
+ raise ValueError()
+ super(Unicode, self).__init__(other)
+
+@@ -776,14 +776,14 @@
+
+ class TestTypedNamedTuple(unittest.TestCase):
+ def test_simple(self):
+- FooBar = TypedNamedTuple('FooBar', [('foo', unicode), ('bar', int)])
++ FooBar = TypedNamedTuple('FooBar', [('foo', str), ('bar', int)])
+
+ t = FooBar(foo='foo', bar=2)
+- self.assertEquals(type(t), FooBar)
+- self.assertEquals(t.foo, 'foo')
+- self.assertEquals(t.bar, 2)
+- self.assertEquals(t[0], 'foo')
+- self.assertEquals(t[1], 2)
++ self.assertEqual(type(t), FooBar)
++ self.assertEqual(t.foo, 'foo')
++ self.assertEqual(t.bar, 2)
++ self.assertEqual(t[0], 'foo')
++ self.assertEqual(t[1], 2)
+
+ FooBar('foo', 2)
+
+@@ -796,7 +796,7 @@
+ # arguments.
+ t1 = ('foo', 3)
+ t2 = FooBar(t1)
+- self.assertEquals(type(t2), FooBar)
++ self.assertEqual(type(t2), FooBar)
+ self.assertEqual(FooBar(t1), FooBar('foo', 3))
+
+
+@@ -871,18 +871,18 @@
+ CompilerType = EnumString.subclass('msvc', 'gcc', 'clang', 'clang-cl')
+
+ type = CompilerType('msvc')
+- self.assertEquals(type, 'msvc')
+- self.assertNotEquals(type, 'gcc')
+- self.assertNotEquals(type, 'clang')
+- self.assertNotEquals(type, 'clang-cl')
++ self.assertEqual(type, 'msvc')
++ self.assertNotEqual(type, 'gcc')
++ self.assertNotEqual(type, 'clang')
++ self.assertNotEqual(type, 'clang-cl')
+ self.assertIn(type, ('msvc', 'clang-cl'))
+ self.assertNotIn(type, ('gcc', 'clang'))
+
+ with self.assertRaises(EnumStringComparisonError):
+- self.assertEquals(type, 'foo')
++ self.assertEqual(type, 'foo')
+
+ with self.assertRaises(EnumStringComparisonError):
+- self.assertNotEquals(type, 'foo')
++ self.assertNotEqual(type, 'foo')
+
+ with self.assertRaises(EnumStringComparisonError):
+ self.assertIn(type, ('foo', 'gcc'))
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/test/action/test_buildlist.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/test/action/test_buildlist.py (refactored)
+@@ -38,11 +38,11 @@
+ lines = [line.rstrip() for line in f.readlines()]
+ f.close()
+ for line in lines:
+- self.assert_(len(l) > 0,
++ self.assertTrue(len(l) > 0,
+ "ran out of expected lines! (expected '{0}', got '{1}')"
+ .format(l, lines))
+ self.assertEqual(line, l.pop(0))
+- self.assert_(len(l) == 0,
++ self.assertTrue(len(l) == 0,
+ "not enough lines in file! (expected '{0}',"
+ " got '{1}'".format(l, lines))
+
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/test/action/test_generate_browsersearch.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/test/action/test_generate_browsersearch.py (refactored)
+@@ -3,7 +3,7 @@
+ # Any copyright is dedicated to the Public Domain.
+ # http://creativecommons.org/publicdomain/zero/1.0/
+
+-from __future__ import unicode_literals
++
+
+ import json
+ import os
+@@ -43,8 +43,8 @@
+
+ def test_valid_unicode(self):
+ o = self._test_one('valid-zh-CN')
+- self.assertEquals(o['default'], '百度')
+- self.assertEquals(o['engines'], ['百度', 'Google'])
++ self.assertEqual(o['default'], '百度')
++ self.assertEqual(o['engines'], ['百度', 'Google'])
+
+ def test_invalid_unicode(self):
+ with self.assertRaises(UnicodeDecodeError):
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/test/action/test_package_fennec_apk.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/test/action/test_package_fennec_apk.py (refactored)
+@@ -3,7 +3,7 @@
+ # Any copyright is dedicated to the Public Domain.
+ # http://creativecommons.org/publicdomain/zero/1.0/
+
+-from __future__ import unicode_literals
++
+
+ import os
+ import unittest
+@@ -41,14 +41,14 @@
+ root_files=[data('root_file.txt')])
+
+ # omni.ja ends up in assets/omni.ja.
+- self.assertEquals(jarrer['assets/omni.ja'].open().read().strip(), 'omni.ja')
++ self.assertEqual(jarrer['assets/omni.ja'].open().read().strip(), 'omni.ja')
+
+ # Everything else is in place.
+ for name in ('classes.dex',
+ 'assets/asset.txt',
+ 'lib/lib.txt',
+ 'root_file.txt'):
+- self.assertEquals(jarrer[name].open().read().strip(), name)
++ self.assertEqual(jarrer[name].open().read().strip(), name)
+
+ def test_inputs(self):
+ # Language repacks take updated resources from an ap_ and pack them
+@@ -57,8 +57,8 @@
+ # overrides the first.
+ jarrer = package(inputs=[data('input2.apk'), data('input1.ap_')])
+
+- files1 = JarReader(data('input1.ap_')).entries.keys()
+- files2 = JarReader(data('input2.apk')).entries.keys()
++ files1 = list(JarReader(data('input1.ap_')).entries.keys())
++ files2 = list(JarReader(data('input2.apk')).entries.keys())
+ for name in files2:
+ self.assertTrue(name in files1 or
+ jarrer[name].open().read().startswith('input2/'))
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/test/backend/common.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/test/backend/common.py (refactored)
+@@ -2,7 +2,7 @@
+ # License, v. 2.0. If a copy of the MPL was not distributed with this
+ # file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+-from __future__ import unicode_literals
++
+
+ import os
+ import unittest
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/test/backend/test_android_eclipse.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/test/backend/test_android_eclipse.py (refactored)
+@@ -2,7 +2,7 @@
+ # License, v. 2.0. If a copy of the MPL was not distributed with this
+ # file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+-from __future__ import unicode_literals
++
+
+ import json
+ import os
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/test/backend/test_build.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/test/backend/test_build.py (refactored)
+@@ -2,7 +2,7 @@
+ # License, v. 2.0. If a copy of the MPL was not distributed with this
+ # file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+-from __future__ import unicode_literals, print_function
++
+
+ import buildconfig
+ import os
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/test/backend/test_configenvironment.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/test/backend/test_configenvironment.py (refactored)
+@@ -3,7 +3,7 @@
+ # file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+ import os, posixpath
+-from StringIO import StringIO
++from io import StringIO
+ import unittest
+ from mozunit import main, MockedOpen
+
+@@ -29,7 +29,7 @@
+ self.substs = ReadOnlyDict(d)
+
+ d = dict(self.substs_unicode)
+- d[u'top_srcdir'] = top_srcdir.decode('utf-8')
++ d['top_srcdir'] = top_srcdir.decode('utf-8')
+ self.substs_unicode = ReadOnlyDict(d)
+
+
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/test/backend/test_recursivemake.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/test/backend/test_recursivemake.py (refactored)
+@@ -2,9 +2,9 @@
+ # License, v. 2.0. If a copy of the MPL was not distributed with this
+ # file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+-from __future__ import unicode_literals
+-
+-import cPickle as pickle
++
++
++import pickle as pickle
+ import json
+ import os
+ import unittest
+@@ -331,7 +331,7 @@
+ ],
+ }
+
+- for var, val in expected.items():
++ for var, val in list(expected.items()):
+ # print("test_variable_passthru[%s]" % (var))
+ found = [str for str in lines if str.startswith(var)]
+ self.assertEqual(found, val)
+@@ -370,7 +370,7 @@
+ ],
+ }
+
+- for var, val in expected.items():
++ for var, val in list(expected.items()):
+ found = [str for str in lines if str.startswith(var)]
+ self.assertEqual(found, val)
+
+@@ -544,7 +544,7 @@
+
+ # This is not the most robust test in the world, but it gets the job
+ # done.
+- entries = [e for e in m._dests.keys() if '**' in e]
++ entries = [e for e in list(m._dests.keys()) if '**' in e]
+ self.assertEqual(len(entries), 1)
+ self.assertIn('support/**', entries[0])
+
+@@ -562,7 +562,7 @@
+ set(['child/test_sub.js',
+ 'child/data/**',
+ 'child/another-file.sjs']))
+- for key in test_installs.keys():
++ for key in list(test_installs.keys()):
+ self.assertIn(key, test_installs)
+
+ test_files_manifest = mozpath.join(env.topobjdir,
+@@ -576,7 +576,7 @@
+ # Then, synthesize one from the test-installs.pkl file. This should
+ # allow us to re-create a subset of the above.
+ synthesized_manifest = InstallManifest()
+- for item, installs in test_installs.items():
++ for item, installs in list(test_installs.items()):
+ for install_info in installs:
+ if len(install_info) == 3:
+ synthesized_manifest.add_pattern_symlink(*install_info)
+@@ -584,7 +584,7 @@
+ synthesized_manifest.add_symlink(*install_info)
+
+ self.assertEqual(len(synthesized_manifest), 3)
+- for item, info in synthesized_manifest._dests.items():
++ for item, info in list(synthesized_manifest._dests.items()):
+ self.assertIn(item, m)
+ self.assertEqual(info, m._dests[item])
+
+@@ -758,7 +758,7 @@
+ expected[mozpath.join(env.topobjdir, 'final-target')] = [
+ 'FINAL_TARGET = $(DEPTH)/random-final-target'
+ ]
+- for key, expected_rules in expected.iteritems():
++ for key, expected_rules in expected.items():
+ backend_path = mozpath.join(key, 'backend.mk')
+ lines = [l.strip() for l in open(backend_path, 'rt').readlines()[2:]]
+ found = [str for str in lines if
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/test/backend/test_visualstudio.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/test/backend/test_visualstudio.py (refactored)
+@@ -2,7 +2,7 @@
+ # License, v. 2.0. If a copy of the MPL was not distributed with this
+ # file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+-from __future__ import unicode_literals
++
+
+ from xml.dom.minidom import parse
+ import os
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/test/configure/common.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/test/configure/common.py (refactored)
+@@ -2,7 +2,7 @@
+ # License, v. 2.0. If a copy of the MPL was not distributed with this
+ # file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+-from __future__ import absolute_import, print_function, unicode_literals
++
+
+ import copy
+ import errno
+@@ -16,7 +16,7 @@
+ from mozbuild.util import ReadOnlyNamespace
+ from mozpack import path as mozpath
+
+-from StringIO import StringIO
++from io import StringIO
+ from which import WhichError
+
+ from buildconfig import (
+@@ -78,10 +78,10 @@
+ self._search_path = environ.get('PATH', '').split(os.pathsep)
+
+ self._subprocess_paths = {
+- mozpath.abspath(k): v for k, v in paths.iteritems() if v
++ mozpath.abspath(k): v for k, v in paths.items() if v
+ }
+
+- paths = paths.keys()
++ paths = list(paths.keys())
+
+ environ = dict(environ)
+ if 'CONFIG_SHELL' not in environ:
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/test/configure/lint.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/test/configure/lint.py (refactored)
+@@ -2,11 +2,11 @@
+ # License, v. 2.0. If a copy of the MPL was not distributed with this
+ # file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+-from __future__ import absolute_import, print_function, unicode_literals
++
+
+ import os
+ import unittest
+-from StringIO import StringIO
++from io import StringIO
+ from mozunit import main
+ from buildconfig import (
+ topobjdir,
+@@ -42,9 +42,7 @@
+ return type.__new__(mcs, name, bases, attrs)
+
+
+-class Lint(unittest.TestCase):
+- __metaclass__ = LintMeta
+-
++class Lint(unittest.TestCase, metaclass=LintMeta):
+ def setUp(self):
+ self._curdir = os.getcwd()
+ os.chdir(topobjdir)
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/test/configure/test_checks_configure.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/test/configure/test_checks_configure.py (refactored)
+@@ -2,9 +2,9 @@
+ # License, v. 2.0. If a copy of the MPL was not distributed with this
+ # file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+-from __future__ import absolute_import, print_function, unicode_literals
+-
+-from StringIO import StringIO
++
++
++from io import StringIO
+ import os
+ import sys
+ import textwrap
+@@ -447,7 +447,7 @@
+ checking for a... %s
+ ''' % self.OTHER_A))
+
+- dirs = map(mozpath.dirname, (self.OTHER_A, self.KNOWN_A))
++ dirs = list(map(mozpath.dirname, (self.OTHER_A, self.KNOWN_A)))
+ config, out, status = self.get_result(textwrap.dedent('''\
+ check_prog("A", ("known-a",), paths=["%s"])
+ ''' % os.pathsep.join(dirs)))
+@@ -457,7 +457,7 @@
+ checking for a... %s
+ ''' % self.OTHER_A))
+
+- dirs = map(mozpath.dirname, (self.KNOWN_A, self.KNOWN_B))
++ dirs = list(map(mozpath.dirname, (self.KNOWN_A, self.KNOWN_B)))
+ config, out, status = self.get_result(textwrap.dedent('''\
+ check_prog("A", ("known-a",), paths=["%s", "%s"])
+ ''' % (os.pathsep.join(dirs), self.OTHER_A)))
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/test/configure/test_compile_checks.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/test/configure/test_compile_checks.py (refactored)
+@@ -2,14 +2,14 @@
+ # License, v. 2.0. If a copy of the MPL was not distributed with this
+ # file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+-from __future__ import absolute_import, print_function, unicode_literals
++
+
+ import os
+ import textwrap
+ import unittest
+ import mozpack.path as mozpath
+
+-from StringIO import StringIO
++from io import StringIO
+
+ from buildconfig import topsrcdir
+ from common import ConfigureTestSandbox
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/test/configure/test_configure.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/test/configure/test_configure.py (refactored)
+@@ -2,9 +2,9 @@
+ # License, v. 2.0. If a copy of the MPL was not distributed with this
+ # file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+-from __future__ import absolute_import, print_function, unicode_literals
+-
+-from StringIO import StringIO
++
++
++from io import StringIO
+ import os
+ import sys
+ import textwrap
+@@ -43,7 +43,7 @@
+
+ if '--help' in options:
+ return out.getvalue(), config
+- self.assertEquals('', out.getvalue())
++ self.assertEqual('', out.getvalue())
+ return config
+
+ def moz_configure(self, source):
+@@ -55,7 +55,7 @@
+ def test_defaults(self):
+ config = self.get_config()
+ self.maxDiff = None
+- self.assertEquals({
++ self.assertEqual({
+ 'CHOICES': NegativeOptionValue(),
+ 'DEFAULTED': PositiveOptionValue(('not-simple',)),
+ 'IS_GCC': NegativeOptionValue(),
+@@ -71,9 +71,9 @@
+ def test_help(self):
+ help, config = self.get_config(['--help'], prog='configure')
+
+- self.assertEquals({}, config)
++ self.assertEqual({}, config)
+ self.maxDiff = None
+- self.assertEquals(
++ self.assertEqual(
+ 'Usage: configure [options]\n'
+ '\n'
+ 'Options: [defaults in brackets after descriptions]\n'
+@@ -109,7 +109,7 @@
+ ):
+ self.assertNotIn('ENABLED_SIMPLE', config)
+ self.assertIn('SIMPLE', config)
+- self.assertEquals(NegativeOptionValue(), config['SIMPLE'])
++ self.assertEqual(NegativeOptionValue(), config['SIMPLE'])
+
+ for config in (
+ self.get_config(['--enable-simple']),
+@@ -117,7 +117,7 @@
+ ):
+ self.assertIn('ENABLED_SIMPLE', config)
+ self.assertIn('SIMPLE', config)
+- self.assertEquals(PositiveOptionValue(), config['SIMPLE'])
++ self.assertEqual(PositiveOptionValue(), config['SIMPLE'])
+ self.assertIs(config['SIMPLE'], config['ENABLED_SIMPLE'])
+
+ # --enable-simple doesn't take values.
+@@ -135,7 +135,7 @@
+ env={'MOZ_WITH_ENV': '1'}),
+ ):
+ self.assertIn('WITH_ENV', config)
+- self.assertEquals(NegativeOptionValue(), config['WITH_ENV'])
++ self.assertEqual(NegativeOptionValue(), config['WITH_ENV'])
+
+ for config in (
+ self.get_config(['--enable-with-env']),
+@@ -145,7 +145,7 @@
+ env={'MOZ_WITH_ENV': ''}),
+ ):
+ self.assertIn('WITH_ENV', config)
+- self.assertEquals(PositiveOptionValue(), config['WITH_ENV'])
++ self.assertEqual(PositiveOptionValue(), config['WITH_ENV'])
+
+ with self.assertRaises(InvalidOptionError):
+ self.get_config(['--enable-with-env=value'])
+@@ -160,23 +160,23 @@
+ self.get_config(['--enable-values', '--disable-values']),
+ ):
+ self.assertIn(name, config)
+- self.assertEquals(NegativeOptionValue(), config[name])
++ self.assertEqual(NegativeOptionValue(), config[name])
+
+ for config in (
+ self.get_config(['--enable-values']),
+ self.get_config(['--disable-values', '--enable-values']),
+ ):
+ self.assertIn(name, config)
+- self.assertEquals(PositiveOptionValue(), config[name])
++ self.assertEqual(PositiveOptionValue(), config[name])
+
+ config = self.get_config(['--enable-values=foo'])
+ self.assertIn(name, config)
+- self.assertEquals(PositiveOptionValue(('foo',)), config[name])
++ self.assertEqual(PositiveOptionValue(('foo',)), config[name])
+
+ config = self.get_config(['--enable-values=foo,bar'])
+ self.assertIn(name, config)
+ self.assertTrue(config[name])
+- self.assertEquals(PositiveOptionValue(('foo', 'bar')), config[name])
++ self.assertEqual(PositiveOptionValue(('foo', 'bar')), config[name])
+
+ def test_values2(self):
+ self.test_values('VALUES2')
+@@ -187,12 +187,12 @@
+ def test_returned_default(self):
+ config = self.get_config(['--enable-simple'])
+ self.assertIn('DEFAULTED', config)
+- self.assertEquals(
++ self.assertEqual(
+ PositiveOptionValue(('simple',)), config['DEFAULTED'])
+
+ config = self.get_config(['--disable-simple'])
+ self.assertIn('DEFAULTED', config)
+- self.assertEquals(
++ self.assertEqual(
+ PositiveOptionValue(('not-simple',)), config['DEFAULTED'])
+
+ def test_returned_choices(self):
+@@ -200,13 +200,13 @@
+ config = self.get_config(
+ ['--enable-values=alpha', '--returned-choices=%s' % val])
+ self.assertIn('CHOICES', config)
+- self.assertEquals(PositiveOptionValue((val,)), config['CHOICES'])
++ self.assertEqual(PositiveOptionValue((val,)), config['CHOICES'])
+
+ for val in ('0', '1', '2'):
+ config = self.get_config(
+ ['--enable-values=numeric', '--returned-choices=%s' % val])
+ self.assertIn('CHOICES', config)
+- self.assertEquals(PositiveOptionValue((val,)), config['CHOICES'])
++ self.assertEqual(PositiveOptionValue((val,)), config['CHOICES'])
+
+ with self.assertRaises(InvalidOptionError):
+ self.get_config(['--enable-values=numeric',
+@@ -218,12 +218,12 @@
+ def test_included(self):
+ config = self.get_config(env={'CC': 'gcc'})
+ self.assertIn('IS_GCC', config)
+- self.assertEquals(config['IS_GCC'], True)
++ self.assertEqual(config['IS_GCC'], True)
+
+ config = self.get_config(
+ ['--enable-include=extra.configure', '--extra'])
+ self.assertIn('EXTRA', config)
+- self.assertEquals(PositiveOptionValue(), config['EXTRA'])
++ self.assertEqual(PositiveOptionValue(), config['EXTRA'])
+
+ with self.assertRaises(InvalidOptionError):
+ self.get_config(['--extra'])
+@@ -231,7 +231,7 @@
+ def test_template(self):
+ config = self.get_config(env={'CC': 'gcc'})
+ self.assertIn('CFLAGS', config)
+- self.assertEquals(config['CFLAGS'], ['-Werror=foobar'])
++ self.assertEqual(config['CFLAGS'], ['-Werror=foobar'])
+
+ config = self.get_config(env={'CC': 'clang'})
+ self.assertNotIn('CFLAGS', config)
+@@ -288,7 +288,7 @@
+ sandbox
+ )
+
+- import __builtin__
++ import builtins
+ self.assertIs(sandbox['foo'](), __builtin__)
+
+ exec_(textwrap.dedent('''
+@@ -300,7 +300,7 @@
+ )
+
+ f = sandbox['foo']()
+- self.assertEquals(f.name, os.devnull)
++ self.assertEqual(f.name, os.devnull)
+ f.close()
+
+ # This unlocks the sandbox
+@@ -336,8 +336,8 @@
+ self.assertIs(sandbox['foo'](), sandbox)
+
+ # Nothing leaked from the function being executed
+- self.assertEquals(sandbox.keys(), ['__builtins__', 'foo'])
+- self.assertEquals(sandbox['__builtins__'], ConfigureSandbox.BUILTINS)
++ self.assertEqual(list(sandbox.keys()), ['__builtins__', 'foo'])
++ self.assertEqual(sandbox['__builtins__'], ConfigureSandbox.BUILTINS)
+
+ exec_(textwrap.dedent('''
+ @template
+@@ -354,7 +354,7 @@
+ with self.assertRaises(NameError) as e:
+ sandbox._depends[sandbox['bar']].result
+
+- self.assertEquals(e.exception.message,
++ self.assertEqual(e.exception.message,
+ "global name 'sys' is not defined")
+
+ def test_apply_imports(self):
+@@ -380,28 +380,28 @@
+ sandbox
+ )
+
+- self.assertEquals(len(imports), 1)
++ self.assertEqual(len(imports), 1)
+
+ def test_os_path(self):
+ config = self.get_config(['--with-imports=%s' % __file__])
+ self.assertIn('HAS_ABSPATH', config)
+- self.assertEquals(config['HAS_ABSPATH'], True)
++ self.assertEqual(config['HAS_ABSPATH'], True)
+ self.assertIn('HAS_GETATIME', config)
+- self.assertEquals(config['HAS_GETATIME'], True)
++ self.assertEqual(config['HAS_GETATIME'], True)
+ self.assertIn('HAS_GETATIME2', config)
+- self.assertEquals(config['HAS_GETATIME2'], False)
++ self.assertEqual(config['HAS_GETATIME2'], False)
+
+ def test_template_call(self):
+ config = self.get_config(env={'CC': 'gcc'})
+ self.assertIn('TEMPLATE_VALUE', config)
+- self.assertEquals(config['TEMPLATE_VALUE'], 42)
++ self.assertEqual(config['TEMPLATE_VALUE'], 42)
+ self.assertIn('TEMPLATE_VALUE_2', config)
+- self.assertEquals(config['TEMPLATE_VALUE_2'], 21)
++ self.assertEqual(config['TEMPLATE_VALUE_2'], 21)
+
+ def test_template_imports(self):
+ config = self.get_config(['--enable-imports-in-template'])
+ self.assertIn('PLATFORM', config)
+- self.assertEquals(config['PLATFORM'], sys.platform)
++ self.assertEqual(config['PLATFORM'], sys.platform)
+
+ def test_decorators(self):
+ config = {}
+@@ -419,27 +419,27 @@
+ return self.get_config(*args, configure='set_config.configure')
+
+ help, config = get_config(['--help'])
+- self.assertEquals(config, {})
++ self.assertEqual(config, {})
+
+ config = get_config(['--set-foo'])
+ self.assertIn('FOO', config)
+- self.assertEquals(config['FOO'], True)
++ self.assertEqual(config['FOO'], True)
+
+ config = get_config(['--set-bar'])
+ self.assertNotIn('FOO', config)
+ self.assertIn('BAR', config)
+- self.assertEquals(config['BAR'], True)
++ self.assertEqual(config['BAR'], True)
+
+ config = get_config(['--set-value=qux'])
+ self.assertIn('VALUE', config)
+- self.assertEquals(config['VALUE'], 'qux')
++ self.assertEqual(config['VALUE'], 'qux')
+
+ config = get_config(['--set-name=hoge'])
+ self.assertIn('hoge', config)
+- self.assertEquals(config['hoge'], True)
++ self.assertEqual(config['hoge'], True)
+
+ config = get_config([])
+- self.assertEquals(config, {'BAR': False})
++ self.assertEqual(config, {'BAR': False})
+
+ with self.assertRaises(ConfigureError):
+ # Both --set-foo and --set-name=FOO are going to try to
+@@ -454,11 +454,11 @@
+ set_config('QUX', 'qux', when='--with-qux')
+ '''):
+ config = self.get_config()
+- self.assertEquals(config, {
++ self.assertEqual(config, {
+ 'FOO': 'foo',
+ })
+ config = self.get_config(['--with-qux'])
+- self.assertEquals(config, {
++ self.assertEqual(config, {
+ 'FOO': 'foo',
+ 'QUX': 'qux',
+ })
+@@ -468,27 +468,27 @@
+ return self.get_config(*args, configure='set_define.configure')
+
+ help, config = get_config(['--help'])
+- self.assertEquals(config, {'DEFINES': {}})
++ self.assertEqual(config, {'DEFINES': {}})
+
+ config = get_config(['--set-foo'])
+ self.assertIn('FOO', config['DEFINES'])
+- self.assertEquals(config['DEFINES']['FOO'], True)
++ self.assertEqual(config['DEFINES']['FOO'], True)
+
+ config = get_config(['--set-bar'])
+ self.assertNotIn('FOO', config['DEFINES'])
+ self.assertIn('BAR', config['DEFINES'])
+- self.assertEquals(config['DEFINES']['BAR'], True)
++ self.assertEqual(config['DEFINES']['BAR'], True)
+
+ config = get_config(['--set-value=qux'])
+ self.assertIn('VALUE', config['DEFINES'])
+- self.assertEquals(config['DEFINES']['VALUE'], 'qux')
++ self.assertEqual(config['DEFINES']['VALUE'], 'qux')
+
+ config = get_config(['--set-name=hoge'])
+ self.assertIn('hoge', config['DEFINES'])
+- self.assertEquals(config['DEFINES']['hoge'], True)
++ self.assertEqual(config['DEFINES']['hoge'], True)
+
+ config = get_config([])
+- self.assertEquals(config['DEFINES'], {'BAR': False})
++ self.assertEqual(config['DEFINES'], {'BAR': False})
+
+ with self.assertRaises(ConfigureError):
+ # Both --set-foo and --set-name=FOO are going to try to
+@@ -503,11 +503,11 @@
+ set_define('QUX', 'qux', when='--with-qux')
+ '''):
+ config = self.get_config()
+- self.assertEquals(config['DEFINES'], {
++ self.assertEqual(config['DEFINES'], {
+ 'FOO': 'foo',
+ })
+ config = self.get_config(['--with-qux'])
+- self.assertEquals(config['DEFINES'], {
++ self.assertEqual(config['DEFINES'], {
+ 'FOO': 'foo',
+ 'QUX': 'qux',
+ })
+@@ -518,19 +518,19 @@
+ *args, configure='imply_option/simple.configure')
+
+ help, config = get_config(['--help'])
+- self.assertEquals(config, {})
++ self.assertEqual(config, {})
+
+ config = get_config([])
+- self.assertEquals(config, {})
++ self.assertEqual(config, {})
+
+ config = get_config(['--enable-foo'])
+ self.assertIn('BAR', config)
+- self.assertEquals(config['BAR'], PositiveOptionValue())
++ self.assertEqual(config['BAR'], PositiveOptionValue())
+
+ with self.assertRaises(InvalidOptionError) as e:
+ get_config(['--enable-foo', '--disable-bar'])
+
+- self.assertEquals(
++ self.assertEqual(
+ e.exception.message,
+ "'--enable-bar' implied by '--enable-foo' conflicts with "
+ "'--disable-bar' from the command-line")
+@@ -541,31 +541,31 @@
+ *args, configure='imply_option/negative.configure')
+
+ help, config = get_config(['--help'])
+- self.assertEquals(config, {})
++ self.assertEqual(config, {})
+
+ config = get_config([])
+- self.assertEquals(config, {})
++ self.assertEqual(config, {})
+
+ config = get_config(['--enable-foo'])
+ self.assertIn('BAR', config)
+- self.assertEquals(config['BAR'], NegativeOptionValue())
++ self.assertEqual(config['BAR'], NegativeOptionValue())
+
+ with self.assertRaises(InvalidOptionError) as e:
+ get_config(['--enable-foo', '--enable-bar'])
+
+- self.assertEquals(
++ self.assertEqual(
+ e.exception.message,
+ "'--disable-bar' implied by '--enable-foo' conflicts with "
+ "'--enable-bar' from the command-line")
+
+ config = get_config(['--disable-hoge'])
+ self.assertIn('BAR', config)
+- self.assertEquals(config['BAR'], NegativeOptionValue())
++ self.assertEqual(config['BAR'], NegativeOptionValue())
+
+ with self.assertRaises(InvalidOptionError) as e:
+ get_config(['--disable-hoge', '--enable-bar'])
+
+- self.assertEquals(
++ self.assertEqual(
+ e.exception.message,
+ "'--disable-bar' implied by '--disable-hoge' conflicts with "
+ "'--enable-bar' from the command-line")
+@@ -576,23 +576,23 @@
+ *args, configure='imply_option/values.configure')
+
+ help, config = get_config(['--help'])
+- self.assertEquals(config, {})
++ self.assertEqual(config, {})
+
+ config = get_config([])
+- self.assertEquals(config, {})
++ self.assertEqual(config, {})
+
+ config = get_config(['--enable-foo=a'])
+ self.assertIn('BAR', config)
+- self.assertEquals(config['BAR'], PositiveOptionValue(('a',)))
++ self.assertEqual(config['BAR'], PositiveOptionValue(('a',)))
+
+ config = get_config(['--enable-foo=a,b'])
+ self.assertIn('BAR', config)
+- self.assertEquals(config['BAR'], PositiveOptionValue(('a','b')))
++ self.assertEqual(config['BAR'], PositiveOptionValue(('a','b')))
+
+ with self.assertRaises(InvalidOptionError) as e:
+ get_config(['--enable-foo=a,b', '--disable-bar'])
+
+- self.assertEquals(
++ self.assertEqual(
+ e.exception.message,
+ "'--enable-bar=a,b' implied by '--enable-foo' conflicts with "
+ "'--disable-bar' from the command-line")
+@@ -603,15 +603,15 @@
+ *args, configure='imply_option/infer.configure')
+
+ help, config = get_config(['--help'])
+- self.assertEquals(config, {})
++ self.assertEqual(config, {})
+
+ config = get_config([])
+- self.assertEquals(config, {})
++ self.assertEqual(config, {})
+
+ with self.assertRaises(InvalidOptionError) as e:
+ get_config(['--enable-foo', '--disable-bar'])
+
+- self.assertEquals(
++ self.assertEqual(
+ e.exception.message,
+ "'--enable-bar' implied by '--enable-foo' conflicts with "
+ "'--disable-bar' from the command-line")
+@@ -619,7 +619,7 @@
+ with self.assertRaises(ConfigureError) as e:
+ self.get_config([], configure='imply_option/infer_ko.configure')
+
+- self.assertEquals(
++ self.assertEqual(
+ e.exception.message,
+ "Cannot infer what implies '--enable-bar'. Please add a `reason` "
+ "to the `imply_option` call.")
+@@ -630,25 +630,25 @@
+ *args, configure='imply_option/imm.configure')
+
+ help, config = get_config(['--help'])
+- self.assertEquals(config, {})
++ self.assertEqual(config, {})
+
+ config = get_config([])
+- self.assertEquals(config, {})
++ self.assertEqual(config, {})
+
+ config_path = mozpath.abspath(
+ mozpath.join(test_data_path, 'imply_option', 'imm.configure'))
+
+- with self.assertRaisesRegexp(InvalidOptionError,
++ with self.assertRaisesRegex(InvalidOptionError,
+ "--enable-foo' implied by 'imply_option at %s:7' conflicts with "
+ "'--disable-foo' from the command-line" % config_path):
+ get_config(['--disable-foo'])
+
+- with self.assertRaisesRegexp(InvalidOptionError,
++ with self.assertRaisesRegex(InvalidOptionError,
+ "--enable-bar=foo,bar' implied by 'imply_option at %s:16' conflicts"
+ " with '--enable-bar=a,b,c' from the command-line" % config_path):
+ get_config(['--enable-bar=a,b,c'])
+
+- with self.assertRaisesRegexp(InvalidOptionError,
++ with self.assertRaisesRegex(InvalidOptionError,
+ "--enable-baz=BAZ' implied by 'imply_option at %s:25' conflicts"
+ " with '--enable-baz=QUUX' from the command-line" % config_path):
+ get_config(['--enable-baz=QUUX'])
+@@ -660,7 +660,7 @@
+ '''):
+ self.get_config()
+
+- self.assertEquals(e.exception.message,
++ self.assertEqual(e.exception.message,
+ "`--with-foo`, emitted from `%s` line 2, is unknown."
+ % mozpath.join(test_data_path, 'moz.configure'))
+
+@@ -675,7 +675,7 @@
+ '''):
+ self.get_config()
+
+- self.assertEquals(e.exception.message,
++ self.assertEqual(e.exception.message,
+ "Unexpected type: 'int'")
+
+ def test_imply_option_when(self):
+@@ -686,12 +686,12 @@
+ set_config('QUX', depends('--with-qux')(lambda x: x))
+ '''):
+ config = self.get_config()
+- self.assertEquals(config, {
++ self.assertEqual(config, {
+ 'QUX': NegativeOptionValue(),
+ })
+
+ config = self.get_config(['--with-foo'])
+- self.assertEquals(config, {
++ self.assertEqual(config, {
+ 'QUX': PositiveOptionValue(),
+ })
+
+@@ -700,7 +700,7 @@
+ with self.moz_configure('option("--with-foo", help="foo")'):
+ self.get_config()
+
+- self.assertEquals(
++ self.assertEqual(
+ e.exception.message,
+ 'Option `--with-foo` is not handled ; reference it with a @depends'
+ )
+@@ -712,7 +712,7 @@
+ '''):
+ self.get_config()
+
+- self.assertEquals(
++ self.assertEqual(
+ e.exception.message,
+ 'Option `--with-foo` already defined'
+ )
+@@ -724,7 +724,7 @@
+ '''):
+ self.get_config()
+
+- self.assertEquals(
++ self.assertEqual(
+ e.exception.message,
+ 'Option `MOZ_FOO` already defined'
+ )
+@@ -736,7 +736,7 @@
+ '''):
+ self.get_config()
+
+- self.assertEquals(
++ self.assertEqual(
+ e.exception.message,
+ 'Option `MOZ_FOO` already defined'
+ )
+@@ -748,7 +748,7 @@
+ '''):
+ self.get_config()
+
+- self.assertEquals(
++ self.assertEqual(
+ e.exception.message,
+ 'Option `MOZ_FOO` already defined'
+ )
+@@ -760,7 +760,7 @@
+ '''):
+ self.get_config()
+
+- self.assertEquals(
++ self.assertEqual(
+ e.exception.message,
+ 'Option `--with-foo` already defined'
+ )
+@@ -776,18 +776,18 @@
+ set_config('QUX', depends('--with-qux', when='--with-foo')(lambda x: x))
+ '''):
+ config = self.get_config()
+- self.assertEquals(config, {
++ self.assertEqual(config, {
+ 'FOO': NegativeOptionValue(),
+ })
+
+ config = self.get_config(['--with-foo'])
+- self.assertEquals(config, {
++ self.assertEqual(config, {
+ 'FOO': PositiveOptionValue(),
+ 'QUX': NegativeOptionValue(),
+ })
+
+ config = self.get_config(['--with-foo', '--with-qux'])
+- self.assertEquals(config, {
++ self.assertEqual(config, {
+ 'FOO': PositiveOptionValue(),
+ 'QUX': PositiveOptionValue(),
+ })
+@@ -795,7 +795,7 @@
+ with self.assertRaises(InvalidOptionError) as e:
+ self.get_config(['--with-bar'])
+
+- self.assertEquals(
++ self.assertEqual(
+ e.exception.message,
+ '--with-bar is not available in this configuration'
+ )
+@@ -803,7 +803,7 @@
+ with self.assertRaises(InvalidOptionError) as e:
+ self.get_config(['--with-qux'])
+
+- self.assertEquals(
++ self.assertEqual(
+ e.exception.message,
+ '--with-qux is not available in this configuration'
+ )
+@@ -811,18 +811,18 @@
+ with self.assertRaises(InvalidOptionError) as e:
+ self.get_config(['QUX=1'])
+
+- self.assertEquals(
++ self.assertEqual(
+ e.exception.message,
+ 'QUX is not available in this configuration'
+ )
+
+ config = self.get_config(env={'QUX': '1'})
+- self.assertEquals(config, {
++ self.assertEqual(config, {
+ 'FOO': NegativeOptionValue(),
+ })
+
+ help, config = self.get_config(['--help'])
+- self.assertEquals(help, textwrap.dedent('''\
++ self.assertEqual(help, textwrap.dedent('''\
+ Usage: configure [options]
+
+ Options: [defaults in brackets after descriptions]
+@@ -833,7 +833,7 @@
+ '''))
+
+ help, config = self.get_config(['--help', '--with-foo'])
+- self.assertEquals(help, textwrap.dedent('''\
++ self.assertEqual(help, textwrap.dedent('''\
+ Usage: configure [options]
+
+ Options: [defaults in brackets after descriptions]
+@@ -851,7 +851,7 @@
+ with self.assertRaises(ConfigureError) as e:
+ self.get_config()
+
+- self.assertEquals(e.exception.message,
++ self.assertEqual(e.exception.message,
+ '@depends function needs the same `when` as '
+ 'options it depends on')
+
+@@ -868,7 +868,7 @@
+ with self.assertRaises(ConfigureError) as e:
+ self.get_config()
+
+- self.assertEquals(e.exception.message,
++ self.assertEqual(e.exception.message,
+ '@depends function needs the same `when` as '
+ 'options it depends on')
+
+@@ -877,7 +877,7 @@
+ with self.moz_configure('include("../foo.configure")'):
+ self.get_config()
+
+- self.assertEquals(
++ self.assertEqual(
+ e.exception.message,
+ 'Cannot include `%s` because it is not in a subdirectory of `%s`'
+ % (mozpath.normpath(mozpath.join(test_data_path, '..',
+@@ -892,7 +892,7 @@
+ '''):
+ self.get_config()
+
+- self.assertEquals(
++ self.assertEqual(
+ e.exception.message,
+ 'Cannot include `%s` because it was included already.'
+ % mozpath.normpath(mozpath.join(test_data_path,
+@@ -905,7 +905,7 @@
+ '''):
+ self.get_config()
+
+- self.assertEquals(e.exception.message, "Unexpected type: 'int'")
++ self.assertEqual(e.exception.message, "Unexpected type: 'int'")
+
+ def test_include_when(self):
+ with MockedOpen({
+@@ -948,26 +948,26 @@
+ '''),
+ }):
+ config = self.get_config()
+- self.assertEquals(config, {})
++ self.assertEqual(config, {})
+
+ config = self.get_config(['--with-foo'])
+- self.assertEquals(config, {})
++ self.assertEqual(config, {})
+
+ config = self.get_config(['--with-bar'])
+- self.assertEquals(config, {
++ self.assertEqual(config, {
+ 'BAR': 'bar',
+ })
+
+ with self.assertRaises(InvalidOptionError) as e:
+ self.get_config(['--with-qux'])
+
+- self.assertEquals(
++ self.assertEqual(
+ e.exception.message,
+ '--with-qux is not available in this configuration'
+ )
+
+ config = self.get_config(['--with-foo', '--with-foo-really'])
+- self.assertEquals(config, {
++ self.assertEqual(config, {
+ 'FOO': 'foo',
+ 'FOO2': True,
+ })
+@@ -979,7 +979,7 @@
+ '''):
+ self.get_config()
+
+- self.assertEquals(e.exception.message, 'Cannot reassign builtins')
++ self.assertEqual(e.exception.message, 'Cannot reassign builtins')
+
+ with self.assertRaises(KeyError) as e:
+ with self.moz_configure('''
+@@ -987,7 +987,7 @@
+ '''):
+ self.get_config()
+
+- self.assertEquals(e.exception.message,
++ self.assertEqual(e.exception.message,
+ 'Cannot assign `foo` because it is neither a '
+ '@depends nor a @template')
+
+@@ -1000,7 +1000,7 @@
+ '''):
+ self.get_config()
+
+- self.assertEquals(e.exception.message,
++ self.assertEqual(e.exception.message,
+ "@depends needs at least one argument")
+
+ with self.assertRaises(ConfigureError) as e:
+@@ -1011,7 +1011,7 @@
+ '''):
+ self.get_config()
+
+- self.assertEquals(e.exception.message,
++ self.assertEqual(e.exception.message,
+ "'--with-foo' is not a known option. Maybe it's "
+ "declared too late?")
+
+@@ -1023,7 +1023,7 @@
+ '''):
+ self.get_config()
+
+- self.assertEquals(e.exception.message,
++ self.assertEqual(e.exception.message,
+ "Option must not contain an '='")
+
+ with self.assertRaises(TypeError) as e:
+@@ -1034,7 +1034,7 @@
+ '''):
+ self.get_config()
+
+- self.assertEquals(e.exception.message,
++ self.assertEqual(e.exception.message,
+ "Cannot use object of type 'int' as argument "
+ "to @depends")
+
+@@ -1046,7 +1046,7 @@
+ '''):
+ self.get_config()
+
+- self.assertEquals(e.exception.message,
++ self.assertEqual(e.exception.message,
+ "Cannot decorate generator functions with @depends")
+
+ with self.assertRaises(TypeError) as e:
+@@ -1055,7 +1055,7 @@
+ '''):
+ self.get_config()
+
+- self.assertEquals(e.exception.message,
++ self.assertEqual(e.exception.message,
+ "Unexpected type: 'int'")
+
+ with self.assertRaises(ConfigureError) as e:
+@@ -1069,7 +1069,7 @@
+ '''):
+ self.get_config()
+
+- self.assertEquals(e.exception.message,
++ self.assertEqual(e.exception.message,
+ "The `foo` function may not be called")
+
+ with self.assertRaises(TypeError) as e:
+@@ -1080,7 +1080,7 @@
+ '''):
+ self.get_config()
+
+- self.assertEquals(e.exception.message,
++ self.assertEqual(e.exception.message,
+ "depends_impl() got an unexpected keyword argument 'foo'")
+
+ def test_depends_when(self):
+@@ -1105,12 +1105,12 @@
+ set_config('QUX', qux)
+ '''):
+ config = self.get_config()
+- self.assertEquals(config, {
++ self.assertEqual(config, {
+ 'FOO': 'foo',
+ })
+
+ config = self.get_config(['--with-qux'])
+- self.assertEquals(config, {
++ self.assertEqual(config, {
+ 'FOO': 'foo',
+ 'QUX': 'qux',
+ })
+@@ -1125,7 +1125,7 @@
+ '''):
+ self.get_config()
+
+- self.assertEquals(e.exception.message,
++ self.assertEqual(e.exception.message,
+ '@imports must appear after @template')
+
+ with self.assertRaises(ConfigureError) as e:
+@@ -1138,7 +1138,7 @@
+ '''):
+ self.get_config()
+
+- self.assertEquals(e.exception.message,
++ self.assertEqual(e.exception.message,
+ '@imports must appear after @depends')
+
+ for import_ in (
+@@ -1155,7 +1155,7 @@
+ ''' % import_):
+ self.get_config()
+
+- self.assertEquals(e.exception.message, "Unexpected type: 'int'")
++ self.assertEqual(e.exception.message, "Unexpected type: 'int'")
+
+ with self.assertRaises(TypeError) as e:
+ with self.moz_configure('''
+@@ -1166,7 +1166,7 @@
+ '''):
+ self.get_config()
+
+- self.assertEquals(e.exception.message, "Unexpected type: 'int'")
++ self.assertEqual(e.exception.message, "Unexpected type: 'int'")
+
+ with self.assertRaises(ValueError) as e:
+ with self.moz_configure('''
+@@ -1176,7 +1176,7 @@
+ '''):
+ self.get_config()
+
+- self.assertEquals(e.exception.message,
++ self.assertEqual(e.exception.message,
+ "Invalid argument to @imports: 'os*'")
+
+ def test_only_when(self):
+@@ -1231,7 +1231,7 @@
+ with self.assertRaises(InvalidOptionError) as e:
+ self.get_config(['--foo'])
+
+- self.assertEquals(e.exception.message,
++ self.assertEqual(e.exception.message,
+ '--foo is not available in this configuration')
+
+ # Cannot depend on an option defined in a only_when block, because we
+@@ -1242,7 +1242,7 @@
+ with self.assertRaises(ConfigureError) as e:
+ self.get_config()
+
+- self.assertEquals(e.exception.message,
++ self.assertEqual(e.exception.message,
+ '@depends function needs the same `when` as '
+ 'options it depends on')
+
+@@ -1259,7 +1259,7 @@
+ with self.assertRaises(InvalidOptionError) as e:
+ self.get_config()
+
+- self.assertEquals(e.exception.message,
++ self.assertEqual(e.exception.message,
+ '--foo is not available in this configuration')
+
+ # And similarly doesn't fail when the condition is true.
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/test/configure/test_lint.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/test/configure/test_lint.py (refactored)
+@@ -2,9 +2,9 @@
+ # License, v. 2.0. If a copy of the MPL was not distributed with this
+ # file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+-from __future__ import absolute_import, print_function, unicode_literals
+
+-from StringIO import StringIO
++
++from io import StringIO
+ import os
+ import textwrap
+ import unittest
+@@ -62,7 +62,7 @@
+ '''):
+ self.lint_test()
+
+- self.assertEquals(e.exception.message,
++ self.assertEqual(e.exception.message,
+ "`bar` depends on '--help' and `foo`. "
+ "`foo` must depend on '--help'")
+
+@@ -85,7 +85,7 @@
+ '''):
+ self.lint_test()
+
+- self.assertEquals(e.exception.message,
++ self.assertEqual(e.exception.message,
+ "`bar` depends on '--help' and `foo`. "
+ "`foo` must depend on '--help'")
+
+@@ -111,7 +111,7 @@
+ '''):
+ self.lint_test()
+
+- self.assertEquals(e.exception.message,
++ self.assertEqual(e.exception.message,
+ "Missing @depends for `foo`: '--help'")
+
+ # There is a default restricted `os` module when there is no explicit
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/test/configure/test_moz_configure.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/test/configure/test_moz_configure.py (refactored)
+@@ -2,7 +2,7 @@
+ # License, v. 2.0. If a copy of the MPL was not distributed with this
+ # file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+-from __future__ import absolute_import, print_function, unicode_literals
++
+
+ from mozunit import main
+ from mozpack import path as mozpath
+@@ -23,10 +23,10 @@
+ shell = mozpath.abspath('/bin/sh')
+ return result.replace('CONFIG_SHELL=%s ' % shell, '')
+
+- self.assertEquals('--enable-application=browser',
++ self.assertEqual('--enable-application=browser',
+ get_value_for(['--enable-application=browser']))
+
+- self.assertEquals('--enable-application=browser '
++ self.assertEqual('--enable-application=browser '
+ 'MOZ_PROFILING=1',
+ get_value_for(['--enable-application=browser',
+ 'MOZ_PROFILING=1']))
+@@ -35,25 +35,25 @@
+ environ={'MOZ_PROFILING': '1'},
+ mozconfig='ac_add_options --enable-project=js')
+
+- self.assertEquals('--enable-project=js MOZ_PROFILING=1',
++ self.assertEqual('--enable-project=js MOZ_PROFILING=1',
+ value)
+
+ # --disable-js-shell is the default, so it's filtered out.
+- self.assertEquals('--enable-application=browser',
++ self.assertEqual('--enable-application=browser',
+ get_value_for(['--enable-application=browser',
+ '--disable-js-shell']))
+
+ # Normally, --without-foo would be filtered out because that's the
+ # default, but since it is a (fake) old-configure option, it always
+ # appears.
+- self.assertEquals('--enable-application=browser --without-foo',
++ self.assertEqual('--enable-application=browser --without-foo',
+ get_value_for(['--enable-application=browser',
+ '--without-foo']))
+- self.assertEquals('--enable-application=browser --with-foo',
++ self.assertEqual('--enable-application=browser --with-foo',
+ get_value_for(['--enable-application=browser',
+ '--with-foo']))
+
+- self.assertEquals("--enable-application=browser '--with-foo=foo bar'",
++ self.assertEqual("--enable-application=browser '--with-foo=foo bar'",
+ get_value_for(['--enable-application=browser',
+ '--with-foo=foo bar']))
+
+@@ -65,7 +65,7 @@
+ self.version = version
+
+ def __call__(self, stdin, args):
+- this.assertEquals(args, ('-version',))
++ this.assertEqual(args, ('-version',))
+ return 0, self.version, ''
+
+ def check_nsis_version(version):
+@@ -80,13 +80,13 @@
+ with self.assertRaises(SystemExit) as e:
+ check_nsis_version('v3.0a2')
+
+- self.assertEquals(check_nsis_version('v3.0b1'), '3.0b1')
+- self.assertEquals(check_nsis_version('v3.0b2'), '3.0b2')
+- self.assertEquals(check_nsis_version('v3.0rc1'), '3.0rc1')
+- self.assertEquals(check_nsis_version('v3.0'), '3.0')
+- self.assertEquals(check_nsis_version('v3.0-2'), '3.0')
+- self.assertEquals(check_nsis_version('v3.0.1'), '3.0')
+- self.assertEquals(check_nsis_version('v3.1'), '3.1')
++ self.assertEqual(check_nsis_version('v3.0b1'), '3.0b1')
++ self.assertEqual(check_nsis_version('v3.0b2'), '3.0b2')
++ self.assertEqual(check_nsis_version('v3.0rc1'), '3.0rc1')
++ self.assertEqual(check_nsis_version('v3.0'), '3.0')
++ self.assertEqual(check_nsis_version('v3.0-2'), '3.0')
++ self.assertEqual(check_nsis_version('v3.0.1'), '3.0')
++ self.assertEqual(check_nsis_version('v3.1'), '3.1')
+
+
+ if __name__ == '__main__':
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/test/configure/test_options.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/test/configure/test_options.py (refactored)
+@@ -2,7 +2,7 @@
+ # License, v. 2.0. If a copy of the MPL was not distributed with this
+ # file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+-from __future__ import absolute_import, print_function, unicode_literals
++
+
+ import unittest
+
+@@ -27,139 +27,139 @@
+ class TestOption(unittest.TestCase):
+ def test_option(self):
+ option = Option('--option')
+- self.assertEquals(option.prefix, '')
+- self.assertEquals(option.name, 'option')
+- self.assertEquals(option.env, None)
++ self.assertEqual(option.prefix, '')
++ self.assertEqual(option.name, 'option')
++ self.assertEqual(option.env, None)
+ self.assertFalse(option.default)
+
+ option = Option('--enable-option')
+- self.assertEquals(option.prefix, 'enable')
+- self.assertEquals(option.name, 'option')
+- self.assertEquals(option.env, None)
++ self.assertEqual(option.prefix, 'enable')
++ self.assertEqual(option.name, 'option')
++ self.assertEqual(option.env, None)
+ self.assertFalse(option.default)
+
+ option = Option('--disable-option')
+- self.assertEquals(option.prefix, 'disable')
+- self.assertEquals(option.name, 'option')
+- self.assertEquals(option.env, None)
++ self.assertEqual(option.prefix, 'disable')
++ self.assertEqual(option.name, 'option')
++ self.assertEqual(option.env, None)
+ self.assertTrue(option.default)
+
+ option = Option('--with-option')
+- self.assertEquals(option.prefix, 'with')
+- self.assertEquals(option.name, 'option')
+- self.assertEquals(option.env, None)
++ self.assertEqual(option.prefix, 'with')
++ self.assertEqual(option.name, 'option')
++ self.assertEqual(option.env, None)
+ self.assertFalse(option.default)
+
+ option = Option('--without-option')
+- self.assertEquals(option.prefix, 'without')
+- self.assertEquals(option.name, 'option')
+- self.assertEquals(option.env, None)
++ self.assertEqual(option.prefix, 'without')
++ self.assertEqual(option.name, 'option')
++ self.assertEqual(option.env, None)
+ self.assertTrue(option.default)
+
+ option = Option('--without-option-foo', env='MOZ_OPTION')
+- self.assertEquals(option.env, 'MOZ_OPTION')
++ self.assertEqual(option.env, 'MOZ_OPTION')
+
+ option = Option(env='MOZ_OPTION')
+- self.assertEquals(option.prefix, '')
+- self.assertEquals(option.name, None)
+- self.assertEquals(option.env, 'MOZ_OPTION')
++ self.assertEqual(option.prefix, '')
++ self.assertEqual(option.name, None)
++ self.assertEqual(option.env, 'MOZ_OPTION')
+ self.assertFalse(option.default)
+
+ with self.assertRaises(InvalidOptionError) as e:
+ Option('--option', nargs=0, default=('a',))
+- self.assertEquals(e.exception.message,
++ self.assertEqual(e.exception.message,
+ "The given `default` doesn't satisfy `nargs`")
+
+ with self.assertRaises(InvalidOptionError) as e:
+ Option('--option', nargs=1, default=())
+- self.assertEquals(
++ self.assertEqual(
+ e.exception.message,
+ 'default must be a bool, a string or a tuple of strings')
+
+ with self.assertRaises(InvalidOptionError) as e:
+ Option('--option', nargs=1, default=True)
+- self.assertEquals(e.exception.message,
++ self.assertEqual(e.exception.message,
+ "The given `default` doesn't satisfy `nargs`")
+
+ with self.assertRaises(InvalidOptionError) as e:
+ Option('--option', nargs=1, default=('a', 'b'))
+- self.assertEquals(e.exception.message,
++ self.assertEqual(e.exception.message,
+ "The given `default` doesn't satisfy `nargs`")
+
+ with self.assertRaises(InvalidOptionError) as e:
+ Option('--option', nargs=2, default=())
+- self.assertEquals(
++ self.assertEqual(
+ e.exception.message,
+ 'default must be a bool, a string or a tuple of strings')
+
+ with self.assertRaises(InvalidOptionError) as e:
+ Option('--option', nargs=2, default=True)
+- self.assertEquals(e.exception.message,
++ self.assertEqual(e.exception.message,
+ "The given `default` doesn't satisfy `nargs`")
+
+ with self.assertRaises(InvalidOptionError) as e:
+ Option('--option', nargs=2, default=('a',))
+- self.assertEquals(e.exception.message,
++ self.assertEqual(e.exception.message,
+ "The given `default` doesn't satisfy `nargs`")
+
+ with self.assertRaises(InvalidOptionError) as e:
+ Option('--option', nargs='?', default=('a', 'b'))
+- self.assertEquals(e.exception.message,
++ self.assertEqual(e.exception.message,
+ "The given `default` doesn't satisfy `nargs`")
+
+ with self.assertRaises(InvalidOptionError) as e:
+ Option('--option', nargs='+', default=())
+- self.assertEquals(
++ self.assertEqual(
+ e.exception.message,
+ 'default must be a bool, a string or a tuple of strings')
+
+ with self.assertRaises(InvalidOptionError) as e:
+ Option('--option', nargs='+', default=True)
+- self.assertEquals(e.exception.message,
++ self.assertEqual(e.exception.message,
+ "The given `default` doesn't satisfy `nargs`")
+
+ # --disable options with a nargs value that requires at least one
+ # argument need to be given a default.
+ with self.assertRaises(InvalidOptionError) as e:
+ Option('--disable-option', nargs=1)
+- self.assertEquals(e.exception.message,
++ self.assertEqual(e.exception.message,
+ "The given `default` doesn't satisfy `nargs`")
+
+ with self.assertRaises(InvalidOptionError) as e:
+ Option('--disable-option', nargs='+')
+- self.assertEquals(e.exception.message,
++ self.assertEqual(e.exception.message,
+ "The given `default` doesn't satisfy `nargs`")
+
+ # Test nargs inference from default value
+ option = Option('--with-foo', default=True)
+- self.assertEquals(option.nargs, 0)
++ self.assertEqual(option.nargs, 0)
+
+ option = Option('--with-foo', default=False)
+- self.assertEquals(option.nargs, 0)
++ self.assertEqual(option.nargs, 0)
+
+ option = Option('--with-foo', default='a')
+- self.assertEquals(option.nargs, '?')
++ self.assertEqual(option.nargs, '?')
+
+ option = Option('--with-foo', default=('a',))
+- self.assertEquals(option.nargs, '?')
++ self.assertEqual(option.nargs, '?')
+
+ option = Option('--with-foo', default=('a', 'b'))
+- self.assertEquals(option.nargs, '*')
++ self.assertEqual(option.nargs, '*')
+
+ option = Option(env='FOO', default=True)
+- self.assertEquals(option.nargs, 0)
++ self.assertEqual(option.nargs, 0)
+
+ option = Option(env='FOO', default=False)
+- self.assertEquals(option.nargs, 0)
++ self.assertEqual(option.nargs, 0)
+
+ option = Option(env='FOO', default='a')
+- self.assertEquals(option.nargs, '?')
++ self.assertEqual(option.nargs, '?')
+
+ option = Option(env='FOO', default=('a',))
+- self.assertEquals(option.nargs, '?')
++ self.assertEqual(option.nargs, '?')
+
+ option = Option(env='FOO', default=('a', 'b'))
+- self.assertEquals(option.nargs, '*')
++ self.assertEqual(option.nargs, '*')
+
+ def test_option_option(self):
+ for option in (
+@@ -169,70 +169,70 @@
+ '--with-option',
+ '--without-option',
+ ):
+- self.assertEquals(Option(option).option, option)
+- self.assertEquals(Option(option, env='FOO').option, option)
++ self.assertEqual(Option(option).option, option)
++ self.assertEqual(Option(option, env='FOO').option, option)
+
+ opt = Option(option, default=False)
+- self.assertEquals(opt.option,
++ self.assertEqual(opt.option,
+ option.replace('-disable-', '-enable-')
+ .replace('-without-', '-with-'))
+
+ opt = Option(option, default=True)
+- self.assertEquals(opt.option,
++ self.assertEqual(opt.option,
+ option.replace('-enable-', '-disable-')
+ .replace('-with-', '-without-'))
+
+- self.assertEquals(Option(env='FOO').option, 'FOO')
++ self.assertEqual(Option(env='FOO').option, 'FOO')
+
+ def test_option_choices(self):
+ with self.assertRaises(InvalidOptionError) as e:
+ Option('--option', nargs=3, choices=('a', 'b'))
+- self.assertEquals(e.exception.message,
++ self.assertEqual(e.exception.message,
+ 'Not enough `choices` for `nargs`')
+
+ with self.assertRaises(InvalidOptionError) as e:
+ Option('--without-option', nargs=1, choices=('a', 'b'))
+- self.assertEquals(e.exception.message,
++ self.assertEqual(e.exception.message,
+ 'A `default` must be given along with `choices`')
+
+ with self.assertRaises(InvalidOptionError) as e:
+ Option('--without-option', nargs='+', choices=('a', 'b'))
+- self.assertEquals(e.exception.message,
++ self.assertEqual(e.exception.message,
+ 'A `default` must be given along with `choices`')
+
+ with self.assertRaises(InvalidOptionError) as e:
+ Option('--without-option', default='c', choices=('a', 'b'))
+- self.assertEquals(e.exception.message,
++ self.assertEqual(e.exception.message,
+ "The `default` value must be one of 'a', 'b'")
+
+ with self.assertRaises(InvalidOptionError) as e:
+ Option('--without-option', default=('a', 'c',), choices=('a', 'b'))
+- self.assertEquals(e.exception.message,
++ self.assertEqual(e.exception.message,
+ "The `default` value must be one of 'a', 'b'")
+
+ with self.assertRaises(InvalidOptionError) as e:
+ Option('--without-option', default=('c',), choices=('a', 'b'))
+- self.assertEquals(e.exception.message,
++ self.assertEqual(e.exception.message,
+ "The `default` value must be one of 'a', 'b'")
+
+ option = Option('--with-option', nargs='+', choices=('a', 'b'))
+ with self.assertRaises(InvalidOptionError) as e:
+ option.get_value('--with-option=c')
+- self.assertEquals(e.exception.message, "'c' is not one of 'a', 'b'")
++ self.assertEqual(e.exception.message, "'c' is not one of 'a', 'b'")
+
+ value = option.get_value('--with-option=b,a')
+ self.assertTrue(value)
+- self.assertEquals(PositiveOptionValue(('b', 'a')), value)
++ self.assertEqual(PositiveOptionValue(('b', 'a')), value)
+
+ option = Option('--without-option', nargs='*', default='a',
+ choices=('a', 'b'))
+ with self.assertRaises(InvalidOptionError) as e:
+ option.get_value('--with-option=c')
+- self.assertEquals(e.exception.message, "'c' is not one of 'a', 'b'")
++ self.assertEqual(e.exception.message, "'c' is not one of 'a', 'b'")
+
+ value = option.get_value('--with-option=b,a')
+ self.assertTrue(value)
+- self.assertEquals(PositiveOptionValue(('b', 'a')), value)
++ self.assertEqual(PositiveOptionValue(('b', 'a')), value)
+
+ # Test nargs inference from choices
+ option = Option('--with-option', choices=('a', 'b'))
+@@ -243,71 +243,71 @@
+ choices=('a', 'b', 'c', 'd'))
+
+ value = option.get_value('--with-option=+d')
+- self.assertEquals(PositiveOptionValue(('b', 'c', 'd')), value)
++ self.assertEqual(PositiveOptionValue(('b', 'c', 'd')), value)
+
+ value = option.get_value('--with-option=-b')
+- self.assertEquals(PositiveOptionValue(('c',)), value)
++ self.assertEqual(PositiveOptionValue(('c',)), value)
+
+ value = option.get_value('--with-option=-b,+d')
+- self.assertEquals(PositiveOptionValue(('c','d')), value)
++ self.assertEqual(PositiveOptionValue(('c','d')), value)
+
+ # Adding something that is in the default is fine
+ value = option.get_value('--with-option=+b')
+- self.assertEquals(PositiveOptionValue(('b', 'c')), value)
++ self.assertEqual(PositiveOptionValue(('b', 'c')), value)
+
+ # Removing something that is not in the default is fine, as long as it
+ # is one of the choices
+ value = option.get_value('--with-option=-a')
+- self.assertEquals(PositiveOptionValue(('b', 'c')), value)
++ self.assertEqual(PositiveOptionValue(('b', 'c')), value)
+
+ with self.assertRaises(InvalidOptionError) as e:
+ option.get_value('--with-option=-e')
+- self.assertEquals(e.exception.message,
++ self.assertEqual(e.exception.message,
+ "'e' is not one of 'a', 'b', 'c', 'd'")
+
+ # Other "not a choice" errors.
+ with self.assertRaises(InvalidOptionError) as e:
+ option.get_value('--with-option=+e')
+- self.assertEquals(e.exception.message,
++ self.assertEqual(e.exception.message,
+ "'e' is not one of 'a', 'b', 'c', 'd'")
+
+ with self.assertRaises(InvalidOptionError) as e:
+ option.get_value('--with-option=e')
+- self.assertEquals(e.exception.message,
++ self.assertEqual(e.exception.message,
+ "'e' is not one of 'a', 'b', 'c', 'd'")
+
+ def test_option_value_format(self):
+ val = PositiveOptionValue()
+- self.assertEquals('--with-value', val.format('--with-value'))
+- self.assertEquals('--with-value', val.format('--without-value'))
+- self.assertEquals('--enable-value', val.format('--enable-value'))
+- self.assertEquals('--enable-value', val.format('--disable-value'))
+- self.assertEquals('--value', val.format('--value'))
+- self.assertEquals('VALUE=1', val.format('VALUE'))
++ self.assertEqual('--with-value', val.format('--with-value'))
++ self.assertEqual('--with-value', val.format('--without-value'))
++ self.assertEqual('--enable-value', val.format('--enable-value'))
++ self.assertEqual('--enable-value', val.format('--disable-value'))
++ self.assertEqual('--value', val.format('--value'))
++ self.assertEqual('VALUE=1', val.format('VALUE'))
+
+ val = PositiveOptionValue(('a',))
+- self.assertEquals('--with-value=a', val.format('--with-value'))
+- self.assertEquals('--with-value=a', val.format('--without-value'))
+- self.assertEquals('--enable-value=a', val.format('--enable-value'))
+- self.assertEquals('--enable-value=a', val.format('--disable-value'))
+- self.assertEquals('--value=a', val.format('--value'))
+- self.assertEquals('VALUE=a', val.format('VALUE'))
++ self.assertEqual('--with-value=a', val.format('--with-value'))
++ self.assertEqual('--with-value=a', val.format('--without-value'))
++ self.assertEqual('--enable-value=a', val.format('--enable-value'))
++ self.assertEqual('--enable-value=a', val.format('--disable-value'))
++ self.assertEqual('--value=a', val.format('--value'))
++ self.assertEqual('VALUE=a', val.format('VALUE'))
+
+ val = PositiveOptionValue(('a', 'b'))
+- self.assertEquals('--with-value=a,b', val.format('--with-value'))
+- self.assertEquals('--with-value=a,b', val.format('--without-value'))
+- self.assertEquals('--enable-value=a,b', val.format('--enable-value'))
+- self.assertEquals('--enable-value=a,b', val.format('--disable-value'))
+- self.assertEquals('--value=a,b', val.format('--value'))
+- self.assertEquals('VALUE=a,b', val.format('VALUE'))
++ self.assertEqual('--with-value=a,b', val.format('--with-value'))
++ self.assertEqual('--with-value=a,b', val.format('--without-value'))
++ self.assertEqual('--enable-value=a,b', val.format('--enable-value'))
++ self.assertEqual('--enable-value=a,b', val.format('--disable-value'))
++ self.assertEqual('--value=a,b', val.format('--value'))
++ self.assertEqual('VALUE=a,b', val.format('VALUE'))
+
+ val = NegativeOptionValue()
+- self.assertEquals('--without-value', val.format('--with-value'))
+- self.assertEquals('--without-value', val.format('--without-value'))
+- self.assertEquals('--disable-value', val.format('--enable-value'))
+- self.assertEquals('--disable-value', val.format('--disable-value'))
+- self.assertEquals('', val.format('--value'))
+- self.assertEquals('VALUE=', val.format('VALUE'))
++ self.assertEqual('--without-value', val.format('--with-value'))
++ self.assertEqual('--without-value', val.format('--without-value'))
++ self.assertEqual('--disable-value', val.format('--enable-value'))
++ self.assertEqual('--disable-value', val.format('--disable-value'))
++ self.assertEqual('', val.format('--value'))
++ self.assertEqual('VALUE=', val.format('VALUE'))
+
+ def test_option_value(self, name='option', nargs=0, default=None):
+ disabled = name.startswith(('disable-', 'without-'))
+@@ -324,28 +324,28 @@
+
+ if nargs in (0, '?', '*') or disabled:
+ value = option.get_value('--%s' % name, 'option')
+- self.assertEquals(value, posOptionValue())
+- self.assertEquals(value.origin, 'option')
++ self.assertEqual(value, posOptionValue())
++ self.assertEqual(value.origin, 'option')
+ else:
+ with self.assertRaises(InvalidOptionError) as e:
+ option.get_value('--%s' % name)
+ if nargs == 1:
+- self.assertEquals(e.exception.message,
++ self.assertEqual(e.exception.message,
+ '--%s takes 1 value' % name)
+ elif nargs == '+':
+- self.assertEquals(e.exception.message,
++ self.assertEqual(e.exception.message,
+ '--%s takes 1 or more values' % name)
+ else:
+- self.assertEquals(e.exception.message,
++ self.assertEqual(e.exception.message,
+ '--%s takes 2 values' % name)
+
+ value = option.get_value('')
+- self.assertEquals(value, defaultValue)
+- self.assertEquals(value.origin, 'default')
++ self.assertEqual(value, defaultValue)
++ self.assertEqual(value.origin, 'default')
+
+ value = option.get_value(None)
+- self.assertEquals(value, defaultValue)
+- self.assertEquals(value.origin, 'default')
++ self.assertEqual(value, defaultValue)
++ self.assertEqual(value.origin, 'default')
+
+ with self.assertRaises(AssertionError):
+ value = option.get_value('MOZ_OPTION=', 'environment')
+@@ -358,47 +358,47 @@
+
+ if nargs in (1, '?', '*', '+') and not disabled:
+ value = option.get_value('--%s=' % name, 'option')
+- self.assertEquals(value, PositiveOptionValue(('',)))
+- self.assertEquals(value.origin, 'option')
++ self.assertEqual(value, PositiveOptionValue(('',)))
++ self.assertEqual(value.origin, 'option')
+ else:
+ with self.assertRaises(InvalidOptionError) as e:
+ option.get_value('--%s=' % name)
+ if disabled:
+- self.assertEquals(e.exception.message,
++ self.assertEqual(e.exception.message,
+ 'Cannot pass a value to --%s' % name)
+ else:
+- self.assertEquals(e.exception.message,
++ self.assertEqual(e.exception.message,
+ '--%s takes %d values' % (name, nargs))
+
+ if nargs in (1, '?', '*', '+') and not disabled:
+ value = option.get_value('--%s=foo' % name, 'option')
+- self.assertEquals(value, PositiveOptionValue(('foo',)))
+- self.assertEquals(value.origin, 'option')
++ self.assertEqual(value, PositiveOptionValue(('foo',)))
++ self.assertEqual(value.origin, 'option')
+ else:
+ with self.assertRaises(InvalidOptionError) as e:
+ option.get_value('--%s=foo' % name)
+ if disabled:
+- self.assertEquals(e.exception.message,
++ self.assertEqual(e.exception.message,
+ 'Cannot pass a value to --%s' % name)
+ else:
+- self.assertEquals(e.exception.message,
++ self.assertEqual(e.exception.message,
+ '--%s takes %d values' % (name, nargs))
+
+ if nargs in (2, '*', '+') and not disabled:
+ value = option.get_value('--%s=foo,bar' % name, 'option')
+- self.assertEquals(value, PositiveOptionValue(('foo', 'bar')))
+- self.assertEquals(value.origin, 'option')
++ self.assertEqual(value, PositiveOptionValue(('foo', 'bar')))
++ self.assertEqual(value.origin, 'option')
+ else:
+ with self.assertRaises(InvalidOptionError) as e:
+ option.get_value('--%s=foo,bar' % name, 'option')
+ if disabled:
+- self.assertEquals(e.exception.message,
++ self.assertEqual(e.exception.message,
+ 'Cannot pass a value to --%s' % name)
+ elif nargs == '?':
+- self.assertEquals(e.exception.message,
++ self.assertEqual(e.exception.message,
+ '--%s takes 0 or 1 values' % name)
+ else:
+- self.assertEquals(e.exception.message,
++ self.assertEqual(e.exception.message,
+ '--%s takes %d value%s'
+ % (name, nargs, 's' if nargs != 1 else ''))
+
+@@ -406,59 +406,59 @@
+ default=default)
+ if nargs in (0, '?', '*') or disabled:
+ value = option.get_value('--%s' % name, 'option')
+- self.assertEquals(value, posOptionValue())
+- self.assertEquals(value.origin, 'option')
++ self.assertEqual(value, posOptionValue())
++ self.assertEqual(value.origin, 'option')
+ else:
+ with self.assertRaises(InvalidOptionError) as e:
+ option.get_value('--%s' % name)
+ if disabled:
+- self.assertEquals(e.exception.message,
++ self.assertEqual(e.exception.message,
+ 'Cannot pass a value to --%s' % name)
+ elif nargs == '+':
+- self.assertEquals(e.exception.message,
++ self.assertEqual(e.exception.message,
+ '--%s takes 1 or more values' % name)
+ else:
+- self.assertEquals(e.exception.message,
++ self.assertEqual(e.exception.message,
+ '--%s takes %d value%s'
+ % (name, nargs, 's' if nargs != 1 else ''))
+
+ value = option.get_value('')
+- self.assertEquals(value, defaultValue)
+- self.assertEquals(value.origin, 'default')
++ self.assertEqual(value, defaultValue)
++ self.assertEqual(value.origin, 'default')
+
+ value = option.get_value(None)
+- self.assertEquals(value, defaultValue)
+- self.assertEquals(value.origin, 'default')
++ self.assertEqual(value, defaultValue)
++ self.assertEqual(value.origin, 'default')
+
+ value = option.get_value('MOZ_OPTION=', 'environment')
+- self.assertEquals(value, NegativeOptionValue())
+- self.assertEquals(value.origin, 'environment')
++ self.assertEqual(value, NegativeOptionValue())
++ self.assertEqual(value.origin, 'environment')
+
+ if nargs in (0, '?', '*'):
+ value = option.get_value('MOZ_OPTION=1', 'environment')
+- self.assertEquals(value, PositiveOptionValue())
+- self.assertEquals(value.origin, 'environment')
++ self.assertEqual(value, PositiveOptionValue())
++ self.assertEqual(value.origin, 'environment')
+ elif nargs in (1, '+'):
+ value = option.get_value('MOZ_OPTION=1', 'environment')
+- self.assertEquals(value, PositiveOptionValue(('1',)))
+- self.assertEquals(value.origin, 'environment')
++ self.assertEqual(value, PositiveOptionValue(('1',)))
++ self.assertEqual(value.origin, 'environment')
+ else:
+ with self.assertRaises(InvalidOptionError) as e:
+ option.get_value('MOZ_OPTION=1', 'environment')
+- self.assertEquals(e.exception.message, 'MOZ_OPTION takes 2 values')
++ self.assertEqual(e.exception.message, 'MOZ_OPTION takes 2 values')
+
+ if nargs in (1, '?', '*', '+') and not disabled:
+ value = option.get_value('--%s=' % name, 'option')
+- self.assertEquals(value, PositiveOptionValue(('',)))
+- self.assertEquals(value.origin, 'option')
++ self.assertEqual(value, PositiveOptionValue(('',)))
++ self.assertEqual(value.origin, 'option')
+ else:
+ with self.assertRaises(InvalidOptionError) as e:
+ option.get_value('--%s=' % name, 'option')
+ if disabled:
+- self.assertEquals(e.exception.message,
++ self.assertEqual(e.exception.message,
+ 'Cannot pass a value to --%s' % name)
+ else:
+- self.assertEquals(e.exception.message,
++ self.assertEqual(e.exception.message,
+ '--%s takes %d values' % (name, nargs))
+
+ with self.assertRaises(AssertionError):
+@@ -466,26 +466,26 @@
+
+ if nargs in (1, '?', '*', '+'):
+ value = option.get_value('MOZ_OPTION=foo', 'environment')
+- self.assertEquals(value, PositiveOptionValue(('foo',)))
+- self.assertEquals(value.origin, 'environment')
++ self.assertEqual(value, PositiveOptionValue(('foo',)))
++ self.assertEqual(value.origin, 'environment')
+ else:
+ with self.assertRaises(InvalidOptionError) as e:
+ option.get_value('MOZ_OPTION=foo', 'environment')
+- self.assertEquals(e.exception.message,
++ self.assertEqual(e.exception.message,
+ 'MOZ_OPTION takes %d values' % nargs)
+
+ if nargs in (2, '*', '+'):
+ value = option.get_value('MOZ_OPTION=foo,bar', 'environment')
+- self.assertEquals(value, PositiveOptionValue(('foo', 'bar')))
+- self.assertEquals(value.origin, 'environment')
++ self.assertEqual(value, PositiveOptionValue(('foo', 'bar')))
++ self.assertEqual(value.origin, 'environment')
+ else:
+ with self.assertRaises(InvalidOptionError) as e:
+ option.get_value('MOZ_OPTION=foo,bar', 'environment')
+ if nargs == '?':
+- self.assertEquals(e.exception.message,
++ self.assertEqual(e.exception.message,
+ 'MOZ_OPTION takes 0 or 1 values')
+ else:
+- self.assertEquals(e.exception.message,
++ self.assertEqual(e.exception.message,
+ 'MOZ_OPTION takes %d value%s'
+ % (nargs, 's' if nargs != 1 else ''))
+
+@@ -497,26 +497,26 @@
+ env_option.get_value('--%s' % name)
+
+ value = env_option.get_value('')
+- self.assertEquals(value, defaultValue)
+- self.assertEquals(value.origin, 'default')
++ self.assertEqual(value, defaultValue)
++ self.assertEqual(value.origin, 'default')
+
+ value = env_option.get_value('MOZ_OPTION=', 'environment')
+- self.assertEquals(value, negOptionValue())
+- self.assertEquals(value.origin, 'environment')
++ self.assertEqual(value, negOptionValue())
++ self.assertEqual(value.origin, 'environment')
+
+ if nargs in (0, '?', '*'):
+ value = env_option.get_value('MOZ_OPTION=1', 'environment')
+- self.assertEquals(value, posOptionValue())
++ self.assertEqual(value, posOptionValue())
+ self.assertTrue(value)
+- self.assertEquals(value.origin, 'environment')
++ self.assertEqual(value.origin, 'environment')
+ elif nargs in (1, '+'):
+ value = env_option.get_value('MOZ_OPTION=1', 'environment')
+- self.assertEquals(value, PositiveOptionValue(('1',)))
+- self.assertEquals(value.origin, 'environment')
++ self.assertEqual(value, PositiveOptionValue(('1',)))
++ self.assertEqual(value.origin, 'environment')
+ else:
+ with self.assertRaises(InvalidOptionError) as e:
+ env_option.get_value('MOZ_OPTION=1', 'environment')
+- self.assertEquals(e.exception.message, 'MOZ_OPTION takes 2 values')
++ self.assertEqual(e.exception.message, 'MOZ_OPTION takes 2 values')
+
+ with self.assertRaises(AssertionError) as e:
+ env_option.get_value('--%s' % name)
+@@ -526,26 +526,26 @@
+
+ if nargs in (1, '?', '*', '+'):
+ value = env_option.get_value('MOZ_OPTION=foo', 'environment')
+- self.assertEquals(value, PositiveOptionValue(('foo',)))
+- self.assertEquals(value.origin, 'environment')
++ self.assertEqual(value, PositiveOptionValue(('foo',)))
++ self.assertEqual(value.origin, 'environment')
+ else:
+ with self.assertRaises(InvalidOptionError) as e:
+ env_option.get_value('MOZ_OPTION=foo', 'environment')
+- self.assertEquals(e.exception.message,
++ self.assertEqual(e.exception.message,
+ 'MOZ_OPTION takes %d values' % nargs)
+
+ if nargs in (2, '*', '+'):
+ value = env_option.get_value('MOZ_OPTION=foo,bar', 'environment')
+- self.assertEquals(value, PositiveOptionValue(('foo', 'bar')))
+- self.assertEquals(value.origin, 'environment')
++ self.assertEqual(value, PositiveOptionValue(('foo', 'bar')))
++ self.assertEqual(value.origin, 'environment')
+ else:
+ with self.assertRaises(InvalidOptionError) as e:
+ env_option.get_value('MOZ_OPTION=foo,bar', 'environment')
+ if nargs == '?':
+- self.assertEquals(e.exception.message,
++ self.assertEqual(e.exception.message,
+ 'MOZ_OPTION takes 0 or 1 values')
+ else:
+- self.assertEquals(e.exception.message,
++ self.assertEqual(e.exception.message,
+ 'MOZ_OPTION takes %d value%s'
+ % (nargs, 's' if nargs != 1 else ''))
+
+@@ -557,28 +557,28 @@
+ default=default)
+
+ value = option.get_value('--%s-option' % disable, 'option')
+- self.assertEquals(value, NegativeOptionValue())
+- self.assertEquals(value.origin, 'option')
++ self.assertEqual(value, NegativeOptionValue())
++ self.assertEqual(value.origin, 'option')
+
+ option = self.test_option_value('%s-option' % disable, nargs=nargs,
+ default=default)
+
+ if nargs in (0, '?', '*'):
+ value = option.get_value('--%s-option' % enable, 'option')
+- self.assertEquals(value, PositiveOptionValue())
+- self.assertEquals(value.origin, 'option')
++ self.assertEqual(value, PositiveOptionValue())
++ self.assertEqual(value.origin, 'option')
+ else:
+ with self.assertRaises(InvalidOptionError) as e:
+ option.get_value('--%s-option' % enable, 'option')
+ if nargs == 1:
+- self.assertEquals(e.exception.message,
++ self.assertEqual(e.exception.message,
+ '--%s-option takes 1 value' % enable)
+ elif nargs == '+':
+- self.assertEquals(e.exception.message,
++ self.assertEqual(e.exception.message,
+ '--%s-option takes 1 or more values'
+ % enable)
+ else:
+- self.assertEquals(e.exception.message,
++ self.assertEqual(e.exception.message,
+ '--%s-option takes 2 values' % enable)
+
+ def test_option_value_with(self):
+@@ -587,12 +587,12 @@
+ def test_option_value_invalid_nargs(self):
+ with self.assertRaises(InvalidOptionError) as e:
+ Option('--option', nargs='foo')
+- self.assertEquals(e.exception.message,
++ self.assertEqual(e.exception.message,
+ "nargs must be a positive integer, '?', '*' or '+'")
+
+ with self.assertRaises(InvalidOptionError) as e:
+ Option('--option', nargs=-2)
+- self.assertEquals(e.exception.message,
++ self.assertEqual(e.exception.message,
+ "nargs must be a positive integer, '?', '*' or '+'")
+
+ def test_option_value_nargs_1(self):
+@@ -603,7 +603,7 @@
+ # A default is required
+ with self.assertRaises(InvalidOptionError) as e:
+ Option('--disable-option', nargs=1)
+- self.assertEquals(e.exception.message,
++ self.assertEqual(e.exception.message,
+ "The given `default` doesn't satisfy `nargs`")
+
+ def test_option_value_nargs_2(self):
+@@ -614,7 +614,7 @@
+ # A default is required
+ with self.assertRaises(InvalidOptionError) as e:
+ Option('--disable-option', nargs=2)
+- self.assertEquals(e.exception.message,
++ self.assertEqual(e.exception.message,
+ "The given `default` doesn't satisfy `nargs`")
+
+ def test_option_value_nargs_0_or_1(self):
+@@ -641,7 +641,7 @@
+ # A default is required
+ with self.assertRaises(InvalidOptionError) as e:
+ Option('--disable-option', nargs='+')
+- self.assertEquals(e.exception.message,
++ self.assertEqual(e.exception.message,
+ "The given `default` doesn't satisfy `nargs`")
+
+
+@@ -649,109 +649,109 @@
+ def test_basic(self):
+ helper = CommandLineHelper({}, ['cmd', '--foo', '--bar'])
+
+- self.assertEquals(['--foo', '--bar'], list(helper))
++ self.assertEqual(['--foo', '--bar'], list(helper))
+
+ helper.add('--enable-qux')
+
+- self.assertEquals(['--foo', '--bar', '--enable-qux'], list(helper))
++ self.assertEqual(['--foo', '--bar', '--enable-qux'], list(helper))
+
+ value, option = helper.handle(Option('--bar'))
+- self.assertEquals(['--foo', '--enable-qux'], list(helper))
+- self.assertEquals(PositiveOptionValue(), value)
+- self.assertEquals('--bar', option)
++ self.assertEqual(['--foo', '--enable-qux'], list(helper))
++ self.assertEqual(PositiveOptionValue(), value)
++ self.assertEqual('--bar', option)
+
+ value, option = helper.handle(Option('--baz'))
+- self.assertEquals(['--foo', '--enable-qux'], list(helper))
+- self.assertEquals(NegativeOptionValue(), value)
+- self.assertEquals(None, option)
++ self.assertEqual(['--foo', '--enable-qux'], list(helper))
++ self.assertEqual(NegativeOptionValue(), value)
++ self.assertEqual(None, option)
+
+ def test_precedence(self):
+ foo = Option('--with-foo', nargs='*')
+ helper = CommandLineHelper({}, ['cmd', '--with-foo=a,b'])
+ value, option = helper.handle(foo)
+- self.assertEquals(PositiveOptionValue(('a', 'b')), value)
+- self.assertEquals('command-line', value.origin)
+- self.assertEquals('--with-foo=a,b', option)
++ self.assertEqual(PositiveOptionValue(('a', 'b')), value)
++ self.assertEqual('command-line', value.origin)
++ self.assertEqual('--with-foo=a,b', option)
+
+ helper = CommandLineHelper({}, ['cmd', '--with-foo=a,b',
+ '--without-foo'])
+ value, option = helper.handle(foo)
+- self.assertEquals(NegativeOptionValue(), value)
+- self.assertEquals('command-line', value.origin)
+- self.assertEquals('--without-foo', option)
++ self.assertEqual(NegativeOptionValue(), value)
++ self.assertEqual('command-line', value.origin)
++ self.assertEqual('--without-foo', option)
+
+ helper = CommandLineHelper({}, ['cmd', '--without-foo',
+ '--with-foo=a,b'])
+ value, option = helper.handle(foo)
+- self.assertEquals(PositiveOptionValue(('a', 'b')), value)
+- self.assertEquals('command-line', value.origin)
+- self.assertEquals('--with-foo=a,b', option)
++ self.assertEqual(PositiveOptionValue(('a', 'b')), value)
++ self.assertEqual('command-line', value.origin)
++ self.assertEqual('--with-foo=a,b', option)
+
+ foo = Option('--with-foo', env='FOO', nargs='*')
+ helper = CommandLineHelper({'FOO': ''}, ['cmd', '--with-foo=a,b'])
+ value, option = helper.handle(foo)
+- self.assertEquals(PositiveOptionValue(('a', 'b')), value)
+- self.assertEquals('command-line', value.origin)
+- self.assertEquals('--with-foo=a,b', option)
++ self.assertEqual(PositiveOptionValue(('a', 'b')), value)
++ self.assertEqual('command-line', value.origin)
++ self.assertEqual('--with-foo=a,b', option)
+
+ helper = CommandLineHelper({'FOO': 'a,b'}, ['cmd', '--without-foo'])
+ value, option = helper.handle(foo)
+- self.assertEquals(NegativeOptionValue(), value)
+- self.assertEquals('command-line', value.origin)
+- self.assertEquals('--without-foo', option)
++ self.assertEqual(NegativeOptionValue(), value)
++ self.assertEqual('command-line', value.origin)
++ self.assertEqual('--without-foo', option)
+
+ helper = CommandLineHelper({'FOO': ''}, ['cmd', '--with-bar=a,b'])
+ value, option = helper.handle(foo)
+- self.assertEquals(NegativeOptionValue(), value)
+- self.assertEquals('environment', value.origin)
+- self.assertEquals('FOO=', option)
++ self.assertEqual(NegativeOptionValue(), value)
++ self.assertEqual('environment', value.origin)
++ self.assertEqual('FOO=', option)
+
+ helper = CommandLineHelper({'FOO': 'a,b'}, ['cmd', '--without-bar'])
+ value, option = helper.handle(foo)
+- self.assertEquals(PositiveOptionValue(('a', 'b')), value)
+- self.assertEquals('environment', value.origin)
+- self.assertEquals('FOO=a,b', option)
++ self.assertEqual(PositiveOptionValue(('a', 'b')), value)
++ self.assertEqual('environment', value.origin)
++ self.assertEqual('FOO=a,b', option)
+
+ helper = CommandLineHelper({}, ['cmd', '--with-foo=a,b', 'FOO='])
+ value, option = helper.handle(foo)
+- self.assertEquals(NegativeOptionValue(), value)
+- self.assertEquals('command-line', value.origin)
+- self.assertEquals('FOO=', option)
++ self.assertEqual(NegativeOptionValue(), value)
++ self.assertEqual('command-line', value.origin)
++ self.assertEqual('FOO=', option)
+
+ helper = CommandLineHelper({}, ['cmd', '--without-foo', 'FOO=a,b'])
+ value, option = helper.handle(foo)
+- self.assertEquals(PositiveOptionValue(('a', 'b')), value)
+- self.assertEquals('command-line', value.origin)
+- self.assertEquals('FOO=a,b', option)
++ self.assertEqual(PositiveOptionValue(('a', 'b')), value)
++ self.assertEqual('command-line', value.origin)
++ self.assertEqual('FOO=a,b', option)
+
+ helper = CommandLineHelper({}, ['cmd', 'FOO=', '--with-foo=a,b'])
+ value, option = helper.handle(foo)
+- self.assertEquals(PositiveOptionValue(('a', 'b')), value)
+- self.assertEquals('command-line', value.origin)
+- self.assertEquals('--with-foo=a,b', option)
++ self.assertEqual(PositiveOptionValue(('a', 'b')), value)
++ self.assertEqual('command-line', value.origin)
++ self.assertEqual('--with-foo=a,b', option)
+
+ helper = CommandLineHelper({}, ['cmd', 'FOO=a,b', '--without-foo'])
+ value, option = helper.handle(foo)
+- self.assertEquals(NegativeOptionValue(), value)
+- self.assertEquals('command-line', value.origin)
+- self.assertEquals('--without-foo', option)
++ self.assertEqual(NegativeOptionValue(), value)
++ self.assertEqual('command-line', value.origin)
++ self.assertEqual('--without-foo', option)
+
+ def test_extra_args(self):
+ foo = Option('--with-foo', env='FOO', nargs='*')
+ helper = CommandLineHelper({}, ['cmd'])
+ helper.add('FOO=a,b,c', 'other-origin')
+ value, option = helper.handle(foo)
+- self.assertEquals(PositiveOptionValue(('a', 'b', 'c')), value)
+- self.assertEquals('other-origin', value.origin)
+- self.assertEquals('FOO=a,b,c', option)
++ self.assertEqual(PositiveOptionValue(('a', 'b', 'c')), value)
++ self.assertEqual('other-origin', value.origin)
++ self.assertEqual('FOO=a,b,c', option)
+
+ helper = CommandLineHelper({}, ['cmd'])
+ helper.add('FOO=a,b,c', 'other-origin')
+ helper.add('--with-foo=a,b,c', 'other-origin')
+ value, option = helper.handle(foo)
+- self.assertEquals(PositiveOptionValue(('a', 'b', 'c')), value)
+- self.assertEquals('other-origin', value.origin)
+- self.assertEquals('--with-foo=a,b,c', option)
++ self.assertEqual(PositiveOptionValue(('a', 'b', 'c')), value)
++ self.assertEqual('other-origin', value.origin)
++ self.assertEqual('--with-foo=a,b,c', option)
+
+ # Adding conflicting options is not allowed.
+ helper = CommandLineHelper({}, ['cmd'])
+@@ -771,9 +771,9 @@
+ # But adding the same is allowed.
+ helper.add('FOO=a,b,c', 'other-origin')
+ value, option = helper.handle(foo)
+- self.assertEquals(PositiveOptionValue(('a', 'b', 'c')), value)
+- self.assertEquals('other-origin', value.origin)
+- self.assertEquals('FOO=a,b,c', option)
++ self.assertEqual(PositiveOptionValue(('a', 'b', 'c')), value)
++ self.assertEqual('other-origin', value.origin)
++ self.assertEqual('FOO=a,b,c', option)
+
+ # The same rule as above applies when using the option form vs. the
+ # variable form. But we can't detect it when .add is called.
+@@ -799,9 +799,9 @@
+ helper.add('FOO=a,b,c', 'other-origin')
+ helper.add('--with-foo=a,b,c', 'other-origin')
+ value, option = helper.handle(foo)
+- self.assertEquals(PositiveOptionValue(('a', 'b', 'c')), value)
+- self.assertEquals('other-origin', value.origin)
+- self.assertEquals('--with-foo=a,b,c', option)
++ self.assertEqual(PositiveOptionValue(('a', 'b', 'c')), value)
++ self.assertEqual('other-origin', value.origin)
++ self.assertEqual('--with-foo=a,b,c', option)
+
+ # Conflicts are also not allowed against what is in the
+ # environment/on the command line.
+@@ -831,19 +831,19 @@
+ foo = Option('--foo',
+ possible_origins=('command-line',))
+ value, option = helper.handle(foo)
+- self.assertEquals(PositiveOptionValue(), value)
+- self.assertEquals('command-line', value.origin)
+- self.assertEquals('--foo', option)
++ self.assertEqual(PositiveOptionValue(), value)
++ self.assertEqual('command-line', value.origin)
++ self.assertEqual('--foo', option)
+
+ bar = Option('--bar',
+ possible_origins=('mozconfig',))
+- with self.assertRaisesRegexp(InvalidOptionError,
++ with self.assertRaisesRegex(InvalidOptionError,
+ "--bar can not be set by command-line. Values are accepted from: mozconfig"):
+ helper.handle(bar)
+
+ baz = Option(env='BAZ',
+ possible_origins=('implied',))
+- with self.assertRaisesRegexp(InvalidOptionError,
++ with self.assertRaisesRegex(InvalidOptionError,
+ "BAZ=1 can not be set by environment. Values are accepted from: implied"):
+ helper.handle(baz)
+
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/test/configure/test_toolchain_configure.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/test/configure/test_toolchain_configure.py (refactored)
+@@ -2,12 +2,12 @@
+ # License, v. 2.0. If a copy of the MPL was not distributed with this
+ # file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+-from __future__ import absolute_import, print_function, unicode_literals
++
+
+ import logging
+ import os
+
+-from StringIO import StringIO
++from io import StringIO
+
+ from mozunit import main
+
+@@ -291,9 +291,9 @@
+ compiler = sandbox._value_for(sandbox[var])
+ # Add var on both ends to make it clear which of the
+ # variables is failing the test when that happens.
+- self.assertEquals((var, compiler), (var, result))
++ self.assertEqual((var, compiler), (var, result))
+ except SystemExit:
+- self.assertEquals((var, result),
++ self.assertEqual((var, result),
+ (var, self.out.getvalue().strip()))
+ return
+
+@@ -471,7 +471,7 @@
+ # We'll try gcc and clang, but since there is no gcc (gcc-x.y doesn't
+ # count), find clang.
+ paths = {
+- k: v for k, v in self.PATHS.iteritems()
++ k: v for k, v in self.PATHS.items()
+ if os.path.basename(k) not in ('gcc', 'g++')
+ }
+ self.do_toolchain_test(paths, {
+@@ -506,7 +506,7 @@
+ # Even if there are gcc-x.y or clang-x.y compilers available, we
+ # don't try them. This could be considered something to improve.
+ paths = {
+- k: v for k, v in self.PATHS.iteritems()
++ k: v for k, v in self.PATHS.items()
+ if os.path.basename(k) not in ('gcc', 'g++', 'clang', 'clang++')
+ }
+ self.do_toolchain_test(paths, {
+@@ -687,7 +687,7 @@
+ def test_not_gcc(self):
+ # We won't pick GCC if it's the only thing available.
+ paths = {
+- k: v for k, v in self.PATHS.iteritems()
++ k: v for k, v in self.PATHS.items()
+ if os.path.basename(k) not in ('clang', 'clang++')
+ }
+ self.do_toolchain_test(paths, {
+@@ -851,7 +851,7 @@
+ def test_clang_cl(self):
+ # We'll pick clang-cl if msvc can't be found.
+ paths = {
+- k: v for k, v in self.PATHS.iteritems()
++ k: v for k, v in self.PATHS.items()
+ if os.path.basename(k) != 'cl'
+ }
+ self.do_toolchain_test(paths, {
+@@ -862,7 +862,7 @@
+ def test_gcc(self):
+ # We'll pick GCC if msvc and clang-cl can't be found.
+ paths = {
+- k: v for k, v in self.PATHS.iteritems()
++ k: v for k, v in self.PATHS.items()
+ if os.path.basename(k) not in ('cl', 'clang-cl')
+ }
+ self.do_toolchain_test(paths, {
+@@ -881,7 +881,7 @@
+ def test_clang(self):
+ # We'll pick clang if nothing else is found.
+ paths = {
+- k: v for k, v in self.PATHS.iteritems()
++ k: v for k, v in self.PATHS.items()
+ if os.path.basename(k) not in ('cl', 'clang-cl', 'gcc')
+ }
+ self.do_toolchain_test(paths, {
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/test/configure/test_toolchain_helpers.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/test/configure/test_toolchain_helpers.py (refactored)
+@@ -2,7 +2,7 @@
+ # License, v. 2.0. If a copy of the MPL was not distributed with this
+ # file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+-from __future__ import absolute_import, print_function, unicode_literals
++
+
+ import copy
+ import re
+@@ -10,7 +10,7 @@
+ import unittest
+
+ from fnmatch import fnmatch
+-from StringIO import StringIO
++from io import StringIO
+ from textwrap import dedent
+
+ from mozunit import (
+@@ -43,7 +43,7 @@
+ # Hack around it enough that the configure tests work properly.
+ context = self.context
+ def normalize_numbers(value):
+- if isinstance(value, types.StringTypes):
++ if isinstance(value, (str,)):
+ if value[-1:] == 'L' and value[:-1].isdigit():
+ value = int(value[:-1])
+ return value
+@@ -53,7 +53,7 @@
+ return self.HAS_FEATURE.sub(r'\1\2', expr)
+ self.context = self.Context(
+ (normalize_has_feature(k), normalize_numbers(v))
+- for k, v in context.iteritems()
++ for k, v in context.items()
+ )
+ try:
+ return Preprocessor.do_if(self, normalize_has_feature(expression),
+@@ -95,7 +95,7 @@
+ input.name = 'foo'
+ pp.do_include(input)
+
+- self.assertEquals(pp.out.getvalue(), '1 . 2 . c "D"')
++ self.assertEqual(pp.out.getvalue(), '1 . 2 . c "D"')
+
+ def test_condition(self):
+ pp = CompilerPreprocessor({
+@@ -125,7 +125,7 @@
+ input.name = 'foo'
+ pp.do_include(input)
+
+- self.assertEquals('IFDEF_A\nIF_A\nIF_B\nIF_NOT_C\n', pp.out.getvalue())
++ self.assertEqual('IFDEF_A\nIF_A\nIF_B\nIF_NOT_C\n', pp.out.getvalue())
+
+
+ class FakeCompiler(dict):
+@@ -164,9 +164,9 @@
+ '''
+ def __init__(self, *definitions):
+ for definition in definitions:
+- if all(not isinstance(d, dict) for d in definition.itervalues()):
++ if all(not isinstance(d, dict) for d in definition.values()):
+ definition = {None: definition}
+- for key, value in definition.iteritems():
++ for key, value in definition.items():
+ self.setdefault(key, {}).update(value)
+
+ def __call__(self, stdin, args):
+@@ -178,14 +178,14 @@
+ pp = CompilerPreprocessor(self[None])
+
+ def apply_defn(defn):
+- for k, v in defn.iteritems():
++ for k, v in defn.items():
+ if v is False:
+ if k in pp.context:
+ del pp.context[k]
+ else:
+ pp.context[k] = v
+
+- for glob, defn in self.iteritems():
++ for glob, defn in self.items():
+ if glob and not glob.startswith('-') and fnmatch(file, glob):
+ apply_defn(defn)
+
+@@ -216,7 +216,7 @@
+ 'A': '1',
+ 'B': '2',
+ })
+- self.assertEquals(compiler(None, ['-E', 'file']),
++ self.assertEqual(compiler(None, ['-E', 'file']),
+ (0, '1 2 C', ''))
+
+ compiler = FakeCompiler({
+@@ -238,25 +238,25 @@
+ 'B': '42',
+ },
+ })
+- self.assertEquals(compiler(None, ['-E', 'file']),
++ self.assertEqual(compiler(None, ['-E', 'file']),
+ (0, '1 2 C', ''))
+- self.assertEquals(compiler(None, ['-E', '-foo', 'file']),
++ self.assertEqual(compiler(None, ['-E', '-foo', 'file']),
+ (0, '1 2 foo', ''))
+- self.assertEquals(compiler(None, ['-E', '-bar', 'file']),
++ self.assertEqual(compiler(None, ['-E', '-bar', 'file']),
+ (0, '1 bar bar', ''))
+- self.assertEquals(compiler(None, ['-E', '-qux', 'file']),
++ self.assertEqual(compiler(None, ['-E', '-qux', 'file']),
+ (0, '1 B C', ''))
+- self.assertEquals(compiler(None, ['-E', '-foo', '-bar', 'file']),
++ self.assertEqual(compiler(None, ['-E', '-foo', '-bar', 'file']),
+ (0, '1 bar bar', ''))
+- self.assertEquals(compiler(None, ['-E', '-bar', '-foo', 'file']),
++ self.assertEqual(compiler(None, ['-E', '-bar', '-foo', 'file']),
+ (0, '1 bar foo', ''))
+- self.assertEquals(compiler(None, ['-E', '-bar', '-qux', 'file']),
++ self.assertEqual(compiler(None, ['-E', '-bar', '-qux', 'file']),
+ (0, '1 B bar', ''))
+- self.assertEquals(compiler(None, ['-E', '-qux', '-bar', 'file']),
++ self.assertEqual(compiler(None, ['-E', '-qux', '-bar', 'file']),
+ (0, '1 bar bar', ''))
+- self.assertEquals(compiler(None, ['-E', 'file.c']),
++ self.assertEqual(compiler(None, ['-E', 'file.c']),
+ (0, '1 42 C', ''))
+- self.assertEquals(compiler(None, ['-E', '-bar', 'file.c']),
++ self.assertEqual(compiler(None, ['-E', '-bar', 'file.c']),
+ (0, '1 bar bar', ''))
+
+ def test_multiple_definitions(self):
+@@ -267,7 +267,7 @@
+ 'C': 3,
+ })
+
+- self.assertEquals(compiler, {
++ self.assertEqual(compiler, {
+ None: {
+ 'A': 1,
+ 'B': 2,
+@@ -282,7 +282,7 @@
+ 'C': 3,
+ })
+
+- self.assertEquals(compiler, {
++ self.assertEqual(compiler, {
+ None: {
+ 'A': 1,
+ 'B': 4,
+@@ -302,7 +302,7 @@
+ },
+ })
+
+- self.assertEquals(compiler, {
++ self.assertEqual(compiler, {
+ None: {
+ 'A': 1,
+ 'B': 4,
+@@ -330,7 +330,7 @@
+ },
+ })
+
+- self.assertEquals(compiler, {
++ self.assertEqual(compiler, {
+ None: {
+ 'A': 1,
+ 'B': 2,
+@@ -370,7 +370,7 @@
+ def __add__(self, other):
+ assert isinstance(other, dict)
+ result = copy.deepcopy(self.__dict__)
+- for k, v in other.iteritems():
++ for k, v in other.items():
+ if k == 'flags':
+ result.setdefault(k, []).extend(v)
+ else:
+@@ -381,7 +381,7 @@
+ class TestCompilerResult(unittest.TestCase):
+ def test_compiler_result(self):
+ result = CompilerResult()
+- self.assertEquals(result.__dict__, {
++ self.assertEqual(result.__dict__, {
+ 'wrapper': [],
+ 'compiler': mozpath.abspath(''),
+ 'version': '',
+@@ -397,7 +397,7 @@
+ language='C',
+ flags=['-std=gnu99'],
+ )
+- self.assertEquals(result.__dict__, {
++ self.assertEqual(result.__dict__, {
+ 'wrapper': [],
+ 'compiler': mozpath.abspath('/usr/bin/gcc'),
+ 'version': '4.2.1',
+@@ -407,7 +407,7 @@
+ })
+
+ result2 = result + {'flags': ['-m32']}
+- self.assertEquals(result2.__dict__, {
++ self.assertEqual(result2.__dict__, {
+ 'wrapper': [],
+ 'compiler': mozpath.abspath('/usr/bin/gcc'),
+ 'version': '4.2.1',
+@@ -416,14 +416,14 @@
+ 'flags': ['-std=gnu99', '-m32'],
+ })
+ # Original flags are untouched.
+- self.assertEquals(result.flags, ['-std=gnu99'])
++ self.assertEqual(result.flags, ['-std=gnu99'])
+
+ result3 = result + {
+ 'compiler': '/usr/bin/gcc-4.7',
+ 'version': '4.7.3',
+ 'flags': ['-m32'],
+ }
+- self.assertEquals(result3.__dict__, {
++ self.assertEqual(result3.__dict__, {
+ 'wrapper': [],
+ 'compiler': mozpath.abspath('/usr/bin/gcc-4.7'),
+ 'version': '4.7.3',
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/test/configure/test_toolkit_moz_configure.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/test/configure/test_toolkit_moz_configure.py (refactored)
+@@ -2,7 +2,7 @@
+ # License, v. 2.0. If a copy of the MPL was not distributed with this
+ # file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+-from __future__ import absolute_import, print_function, unicode_literals
++
+
+ import os
+
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/test/configure/test_util.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/test/configure/test_util.py (refactored)
+@@ -2,7 +2,7 @@
+ # License, v. 2.0. If a copy of the MPL was not distributed with this
+ # file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+-from __future__ import absolute_import, print_function, unicode_literals
++
+
+ import logging
+ import os
+@@ -11,7 +11,7 @@
+ import unittest
+ import sys
+
+-from StringIO import StringIO
++from io import StringIO
+
+ from mozunit import main
+ from mozpack import path as mozpath
+@@ -434,11 +434,11 @@
+ except SystemExit as e:
+ status = e.code
+
+- self.assertEquals(status, 0)
++ self.assertEqual(status, 0)
+ quote_char = "'"
+ if getpreferredencoding().lower() == 'utf-8':
+ quote_char = '\u00B4'.encode('utf-8')
+- self.assertEquals(out.getvalue().strip(), quote_char)
++ self.assertEqual(out.getvalue().strip(), quote_char)
+
+
+ class TestVersion(unittest.TestCase):
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/test/controller/test_ccachestats.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/test/controller/test_ccachestats.py (refactored)
+@@ -2,7 +2,7 @@
+ # License, v. 2.0. If a copy of the MPL was not distributed with this
+ # file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+-from __future__ import unicode_literals
++
+
+ import unittest
+
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/test/controller/test_clobber.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/test/controller/test_clobber.py (refactored)
+@@ -2,14 +2,14 @@
+ # License, v. 2.0. If a copy of the MPL was not distributed with this
+ # file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+-from __future__ import unicode_literals
++
+
+ import os
+ import shutil
+ import tempfile
+ import unittest
+
+-from StringIO import StringIO
++from io import StringIO
+
+ from mozunit import main
+
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/test/frontend/test_context.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/test/frontend/test_context.py (refactored)
+@@ -36,7 +36,7 @@
+ 'baz': (dict, dict, ''),
+ })
+
+- self.assertEqual(test.keys(), [])
++ self.assertEqual(list(test.keys()), [])
+
+ self.assertEqual(test['foo'], 0)
+
+@@ -84,12 +84,12 @@
+ 'baz': (dict, list, ''),
+ })
+
+- self.assertEqual(test.keys(), [])
++ self.assertEqual(list(test.keys()), [])
+
+ with self.assertRaises(ValueError):
+ test.update(bar=True, foo={})
+
+- self.assertEqual(test.keys(), [])
++ self.assertEqual(list(test.keys()), [])
+
+ test.update(bar=True, foo=1)
+
+@@ -258,19 +258,19 @@
+ self.assertEqual(lines[-1].strip(), '')
+
+ def test_documentation_formatting(self):
+- for typ, inp, doc in VARIABLES.values():
++ for typ, inp, doc in list(VARIABLES.values()):
+ self._verify_doc(doc)
+
+- for attr, args, doc in FUNCTIONS.values():
++ for attr, args, doc in list(FUNCTIONS.values()):
+ self._verify_doc(doc)
+
+- for func, typ, doc in SPECIAL_VARIABLES.values():
++ for func, typ, doc in list(SPECIAL_VARIABLES.values()):
+ self._verify_doc(doc)
+
+- for name, cls in SUBCONTEXTS.items():
++ for name, cls in list(SUBCONTEXTS.items()):
+ self._verify_doc(cls.__doc__)
+
+- for name, v in cls.VARIABLES.items():
++ for name, v in list(cls.VARIABLES.items()):
+ self._verify_doc(v[2])
+
+
+@@ -631,7 +631,7 @@
+ class TestTypedRecord(unittest.TestCase):
+
+ def test_fields(self):
+- T = ContextDerivedTypedRecord(('field1', unicode),
++ T = ContextDerivedTypedRecord(('field1', str),
+ ('field2', list))
+ inst = T(None)
+ self.assertEqual(inst.field1, '')
+@@ -647,7 +647,7 @@
+ inst.field3 = []
+
+ def test_coercion(self):
+- T = ContextDerivedTypedRecord(('field1', unicode),
++ T = ContextDerivedTypedRecord(('field1', str),
+ ('field2', list))
+ inst = T(None)
+ inst.field1 = 3
+@@ -673,45 +673,45 @@
+ def test_single_bug_component(self):
+ c = Context({})
+ f = Files(c, pattern='**')
+- f['BUG_COMPONENT'] = (u'Product1', u'Component1')
++ f['BUG_COMPONENT'] = ('Product1', 'Component1')
+
+ files = {'moz.build': f}
+ self.assertEqual(Files.aggregate(files), {
+- 'bug_component_counts': [((u'Product1', u'Component1'), 1)],
+- 'recommended_bug_component': (u'Product1', u'Component1'),
++ 'bug_component_counts': [(('Product1', 'Component1'), 1)],
++ 'recommended_bug_component': ('Product1', 'Component1'),
+ })
+
+ def test_multiple_bug_components(self):
+ c = Context({})
+ f1 = Files(c, pattern='**')
+- f1['BUG_COMPONENT'] = (u'Product1', u'Component1')
++ f1['BUG_COMPONENT'] = ('Product1', 'Component1')
+
+ f2 = Files(c, pattern='**')
+- f2['BUG_COMPONENT'] = (u'Product2', u'Component2')
++ f2['BUG_COMPONENT'] = ('Product2', 'Component2')
+
+ files = {'a': f1, 'b': f2, 'c': f1}
+ self.assertEqual(Files.aggregate(files), {
+ 'bug_component_counts': [
+- ((u'Product1', u'Component1'), 2),
+- ((u'Product2', u'Component2'), 1),
++ (('Product1', 'Component1'), 2),
++ (('Product2', 'Component2'), 1),
+ ],
+- 'recommended_bug_component': (u'Product1', u'Component1'),
++ 'recommended_bug_component': ('Product1', 'Component1'),
+ })
+
+ def test_no_recommended_bug_component(self):
+ """If there is no clear count winner, we don't recommend a bug component."""
+ c = Context({})
+ f1 = Files(c, pattern='**')
+- f1['BUG_COMPONENT'] = (u'Product1', u'Component1')
++ f1['BUG_COMPONENT'] = ('Product1', 'Component1')
+
+ f2 = Files(c, pattern='**')
+- f2['BUG_COMPONENT'] = (u'Product2', u'Component2')
++ f2['BUG_COMPONENT'] = ('Product2', 'Component2')
+
+ files = {'a': f1, 'b': f2}
+ self.assertEqual(Files.aggregate(files), {
+ 'bug_component_counts': [
+- ((u'Product1', u'Component1'), 1),
+- ((u'Product2', u'Component2'), 1),
++ (('Product1', 'Component1'), 1),
++ (('Product2', 'Component2'), 1),
+ ],
+ 'recommended_bug_component': None,
+ })
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/test/frontend/test_emitter.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/test/frontend/test_emitter.py (refactored)
+@@ -2,7 +2,7 @@
+ # License, v. 2.0. If a copy of the MPL was not distributed with this
+ # file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+-from __future__ import unicode_literals
++
+
+ import os
+ import unittest
+@@ -204,7 +204,7 @@
+ def test_use_yasm(self):
+ # When yasm is not available, this should raise.
+ reader = self.reader('use-yasm')
+- with self.assertRaisesRegexp(SandboxValidationError,
++ with self.assertRaisesRegex(SandboxValidationError,
+ 'yasm is not available'):
+ self.read_topsrcdir(reader)
+
+@@ -267,25 +267,25 @@
+ o = objs[0]
+ self.assertIsInstance(o, GeneratedFile)
+ self.assertEqual(o.outputs, ('bar.c',))
+- self.assertRegexpMatches(o.script, 'script.py$')
++ self.assertRegex(o.script, 'script.py$')
+ self.assertEqual(o.method, 'make_bar')
+ self.assertEqual(o.inputs, [])
+
+ def test_generated_files_no_script(self):
+ reader = self.reader('generated-files-no-script')
+- with self.assertRaisesRegexp(SandboxValidationError,
++ with self.assertRaisesRegex(SandboxValidationError,
+ 'Script for generating bar.c does not exist'):
+ self.read_topsrcdir(reader)
+
+ def test_generated_files_no_inputs(self):
+ reader = self.reader('generated-files-no-inputs')
+- with self.assertRaisesRegexp(SandboxValidationError,
++ with self.assertRaisesRegex(SandboxValidationError,
+ 'Input for generating foo.c does not exist'):
+ self.read_topsrcdir(reader)
+
+ def test_generated_files_no_python_script(self):
+ reader = self.reader('generated-files-no-python-script')
+- with self.assertRaisesRegexp(SandboxValidationError,
++ with self.assertRaisesRegex(SandboxValidationError,
+ 'Script for generating bar.c does not end in .py'):
+ self.read_topsrcdir(reader)
+
+@@ -314,7 +314,7 @@
+ Missing files in EXPORTS is an error.
+ '''
+ reader = self.reader('exports-missing')
+- with self.assertRaisesRegexp(SandboxValidationError,
++ with self.assertRaisesRegex(SandboxValidationError,
+ 'File listed in EXPORTS does not exist:'):
+ self.read_topsrcdir(reader)
+
+@@ -323,7 +323,7 @@
+ An objdir file in EXPORTS that is not in GENERATED_FILES is an error.
+ '''
+ reader = self.reader('exports-missing-generated')
+- with self.assertRaisesRegexp(SandboxValidationError,
++ with self.assertRaisesRegex(SandboxValidationError,
+ 'Objdir file listed in EXPORTS not in GENERATED_FILES:'):
+ self.read_topsrcdir(reader)
+
+@@ -360,7 +360,7 @@
+
+ def test_test_harness_files_root(self):
+ reader = self.reader('test-harness-files-root')
+- with self.assertRaisesRegexp(SandboxValidationError,
++ with self.assertRaisesRegex(SandboxValidationError,
+ 'Cannot install files to the root of TEST_HARNESS_FILES'):
+ self.read_topsrcdir(reader)
+
+@@ -413,14 +413,14 @@
+ """A missing manifest file should result in an error."""
+ reader = self.reader('test-manifest-missing-manifest')
+
+- with self.assertRaisesRegexp(BuildReaderError, 'IOError: Missing files'):
++ with self.assertRaisesRegex(BuildReaderError, 'IOError: Missing files'):
+ self.read_topsrcdir(reader)
+
+ def test_empty_test_manifest_rejected(self):
+ """A test manifest without any entries is rejected."""
+ reader = self.reader('test-manifest-empty')
+
+- with self.assertRaisesRegexp(SandboxValidationError, 'Empty test manifest'):
++ with self.assertRaisesRegex(SandboxValidationError, 'Empty test manifest'):
+ self.read_topsrcdir(reader)
+
+
+@@ -428,7 +428,7 @@
+ """A test manifest with no tests but support-files is not supported."""
+ reader = self.reader('test-manifest-just-support')
+
+- with self.assertRaisesRegexp(SandboxValidationError, 'Empty test manifest'):
++ with self.assertRaisesRegex(SandboxValidationError, 'Empty test manifest'):
+ self.read_topsrcdir(reader)
+
+ def test_test_manifest_dupe_support_files(self):
+@@ -437,7 +437,7 @@
+ """
+ reader = self.reader('test-manifest-dupes')
+
+- with self.assertRaisesRegexp(SandboxValidationError, 'bar.js appears multiple times '
++ with self.assertRaisesRegex(SandboxValidationError, 'bar.js appears multiple times '
+ 'in a test manifest under a support-files field, please omit the duplicate entry.'):
+ self.read_topsrcdir(reader)
+
+@@ -454,7 +454,7 @@
+ mozpath.join(o.install_prefix, "absolute-support.ini"),
+ mozpath.join(o.install_prefix, "test_file.js"),
+ ]
+- paths = sorted([v[0] for v in o.installs.values()])
++ paths = sorted([v[0] for v in list(o.installs.values())])
+ self.assertEqual(paths, expected)
+
+ @unittest.skip('Bug 1304316 - Items in the second set but not the first')
+@@ -481,7 +481,7 @@
+ """A non-existent shared support file reference produces an error."""
+ reader = self.reader('test-manifest-shared-missing')
+
+- with self.assertRaisesRegexp(SandboxValidationError,
++ with self.assertRaisesRegex(SandboxValidationError,
+ 'entry in support-files not present in the srcdir'):
+ self.read_topsrcdir(reader)
+
+@@ -500,7 +500,7 @@
+ mozpath.normpath(mozpath.join(o.install_prefix, "subdir/support.txt")),
+ mozpath.normpath(mozpath.join(o.install_prefix, "subdir/test_foo.html")),
+ ]
+- paths = sorted([v[0] for v in o.installs.values()])
++ paths = sorted([v[0] for v in list(o.installs.values())])
+ self.assertEqual(paths, expected)
+
+ def test_test_manifest_install_includes(self):
+@@ -518,7 +518,7 @@
+ mozpath.normpath(mozpath.join(o.install_prefix, "subdir/mochitest.ini")),
+ mozpath.normpath(mozpath.join(o.install_prefix, "subdir/test_foo.html")),
+ ]
+- paths = sorted([v[0] for v in o.installs.values()])
++ paths = sorted([v[0] for v in list(o.installs.values())])
+ self.assertEqual(paths, expected)
+
+ def test_test_manifest_includes(self):
+@@ -541,7 +541,7 @@
+ def test_python_unit_test_missing(self):
+ """Missing files in PYTHON_UNIT_TESTS should raise."""
+ reader = self.reader('test-python-unit-test-missing')
+- with self.assertRaisesRegexp(SandboxValidationError,
++ with self.assertRaisesRegex(SandboxValidationError,
+ 'Path specified in PYTHON_UNIT_TESTS does not exist:'):
+ self.read_topsrcdir(reader)
+
+@@ -635,7 +635,7 @@
+ self.assertEqual(external_normalized, m.get('external', set()))
+
+ self.assertEqual(len(o.installs), len(m['installs']))
+- for path in o.installs.keys():
++ for path in list(o.installs.keys()):
+ self.assertTrue(path.startswith(o.directory))
+ relpath = path[len(o.directory)+1:]
+
+@@ -648,7 +648,7 @@
+ def test_test_manifest_unmatched_generated(self):
+ reader = self.reader('test-manifest-unmatched-generated')
+
+- with self.assertRaisesRegexp(SandboxValidationError,
++ with self.assertRaisesRegex(SandboxValidationError,
+ 'entry in generated-files not present elsewhere'):
+ self.read_topsrcdir(reader),
+
+@@ -672,7 +672,7 @@
+ """Missing test files should result in error."""
+ reader = self.reader('test-manifest-missing-test-file')
+
+- with self.assertRaisesRegexp(SandboxValidationError,
++ with self.assertRaisesRegex(SandboxValidationError,
+ 'lists test that does not exist: test_missing.html'):
+ self.read_topsrcdir(reader)
+
+@@ -680,7 +680,7 @@
+ """Missing test files should result in error, even when the test list is not filtered."""
+ reader = self.reader('test-manifest-missing-test-file-unfiltered')
+
+- with self.assertRaisesRegexp(SandboxValidationError,
++ with self.assertRaisesRegex(SandboxValidationError,
+ 'lists test that does not exist: missing.js'):
+ self.read_topsrcdir(reader)
+
+@@ -794,20 +794,20 @@
+ self.assertIsInstance(obj.path, Path)
+
+ def test_jar_manifests_multiple_files(self):
+- with self.assertRaisesRegexp(SandboxValidationError, 'limited to one value'):
++ with self.assertRaisesRegex(SandboxValidationError, 'limited to one value'):
+ reader = self.reader('jar-manifests-multiple-files')
+ self.read_topsrcdir(reader)
+
+ def test_xpidl_module_no_sources(self):
+ """XPIDL_MODULE without XPIDL_SOURCES should be rejected."""
+- with self.assertRaisesRegexp(SandboxValidationError, 'XPIDL_MODULE '
++ with self.assertRaisesRegex(SandboxValidationError, 'XPIDL_MODULE '
+ 'cannot be defined'):
+ reader = self.reader('xpidl-module-no-sources')
+ self.read_topsrcdir(reader)
+
+ def test_missing_local_includes(self):
+ """LOCAL_INCLUDES containing non-existent directories should be rejected."""
+- with self.assertRaisesRegexp(SandboxValidationError, 'Path specified in '
++ with self.assertRaisesRegex(SandboxValidationError, 'Path specified in '
+ 'LOCAL_INCLUDES does not exist'):
+ reader = self.reader('missing-local-includes')
+ self.read_topsrcdir(reader)
+@@ -852,7 +852,7 @@
+ '.S': ['g.S'],
+ '.s': ['h.s', 'i.asm'],
+ }
+- for suffix, files in expected.items():
++ for suffix, files in list(expected.items()):
+ sources = suffix_map[suffix]
+ self.assertEqual(
+ sources.files,
+@@ -905,7 +905,7 @@
+ '.S': ['g.S'],
+ '.s': ['h.s', 'i.asm'],
+ }
+- for suffix, files in expected.items():
++ for suffix, files in list(expected.items()):
+ sources = suffix_map[suffix]
+ self.assertEqual(
+ sources.files,
+@@ -931,7 +931,7 @@
+ '.c': ['d.c'],
+ '.mm': ['e.mm', 'f.mm'],
+ }
+- for suffix, files in expected.items():
++ for suffix, files in list(expected.items()):
+ sources = suffix_map[suffix]
+ self.assertEqual(
+ sources.files,
+@@ -956,7 +956,7 @@
+ '.mm': ['objc1.mm', 'objc2.mm'],
+ '.c': ['c1.c', 'c2.c'],
+ }
+- for suffix, files in expected.items():
++ for suffix, files in list(expected.items()):
+ sources = suffix_map[suffix]
+ self.assertEqual(
+ sources.files,
+@@ -982,7 +982,7 @@
+ '.mm': ['objc1.mm', 'objc2.mm'],
+ '.c': ['c1.c', 'c2.c'],
+ }
+- for suffix, files in expected.items():
++ for suffix, files in list(expected.items()):
+ sources = suffix_map[suffix]
+ self.assertEqual(
+ sources.files,
+@@ -1005,11 +1005,11 @@
+
+ expected = {'install.rdf', 'main.js'}
+ for f in files:
+- self.assertTrue(unicode(f) in expected)
++ self.assertTrue(str(f) in expected)
+
+ def test_missing_final_target_pp_files(self):
+ """Test that FINAL_TARGET_PP_FILES with missing files throws errors."""
+- with self.assertRaisesRegexp(SandboxValidationError, 'File listed in '
++ with self.assertRaisesRegex(SandboxValidationError, 'File listed in '
+ 'FINAL_TARGET_PP_FILES does not exist'):
+ reader = self.reader('dist-files-missing')
+ self.read_topsrcdir(reader)
+@@ -1017,49 +1017,49 @@
+ def test_final_target_pp_files_non_srcdir(self):
+ '''Test that non-srcdir paths in FINAL_TARGET_PP_FILES throws errors.'''
+ reader = self.reader('final-target-pp-files-non-srcdir')
+- with self.assertRaisesRegexp(SandboxValidationError,
++ with self.assertRaisesRegex(SandboxValidationError,
+ 'Only source directory paths allowed in FINAL_TARGET_PP_FILES:'):
+ self.read_topsrcdir(reader)
+
+ def test_rust_library_no_cargo_toml(self):
+ '''Test that defining a RustLibrary without a Cargo.toml fails.'''
+ reader = self.reader('rust-library-no-cargo-toml')
+- with self.assertRaisesRegexp(SandboxValidationError,
++ with self.assertRaisesRegex(SandboxValidationError,
+ 'No Cargo.toml file found'):
+ self.read_topsrcdir(reader)
+
+ def test_rust_library_name_mismatch(self):
+ '''Test that defining a RustLibrary that doesn't match Cargo.toml fails.'''
+ reader = self.reader('rust-library-name-mismatch')
+- with self.assertRaisesRegexp(SandboxValidationError,
++ with self.assertRaisesRegex(SandboxValidationError,
+ 'library.*does not match Cargo.toml-defined package'):
+ self.read_topsrcdir(reader)
+
+ def test_rust_library_no_lib_section(self):
+ '''Test that a RustLibrary Cargo.toml with no [lib] section fails.'''
+ reader = self.reader('rust-library-no-lib-section')
+- with self.assertRaisesRegexp(SandboxValidationError,
++ with self.assertRaisesRegex(SandboxValidationError,
+ 'Cargo.toml for.* has no \\[lib\\] section'):
+ self.read_topsrcdir(reader)
+
+ def test_rust_library_no_profile_section(self):
+ '''Test that a RustLibrary Cargo.toml with no [profile] section fails.'''
+ reader = self.reader('rust-library-no-profile-section')
+- with self.assertRaisesRegexp(SandboxValidationError,
++ with self.assertRaisesRegex(SandboxValidationError,
+ 'Cargo.toml for.* has no \\[profile\\.dev\\] section'):
+ self.read_topsrcdir(reader)
+
+ def test_rust_library_invalid_crate_type(self):
+ '''Test that a RustLibrary Cargo.toml has a permitted crate-type.'''
+ reader = self.reader('rust-library-invalid-crate-type')
+- with self.assertRaisesRegexp(SandboxValidationError,
++ with self.assertRaisesRegex(SandboxValidationError,
+ 'crate-type.* is not permitted'):
+ self.read_topsrcdir(reader)
+
+ def test_rust_library_non_abort_panic(self):
+ '''Test that a RustLibrary Cargo.toml has `panic = "abort" set'''
+ reader = self.reader('rust-library-non-abort-panic')
+- with self.assertRaisesRegexp(SandboxValidationError,
++ with self.assertRaisesRegex(SandboxValidationError,
+ 'does not specify `panic = "abort"`'):
+ self.read_topsrcdir(reader)
+
+@@ -1072,15 +1072,15 @@
+ self.assertEqual(len(objs), 1)
+ lib = objs[0]
+ self.assertIsInstance(lib, RustLibrary)
+- self.assertRegexpMatches(lib.lib_name, "random_crate")
+- self.assertRegexpMatches(lib.import_name, "random_crate")
+- self.assertRegexpMatches(lib.basename, "random-crate")
++ self.assertRegex(lib.lib_name, "random_crate")
++ self.assertRegex(lib.import_name, "random_crate")
++ self.assertRegex(lib.basename, "random-crate")
+
+ def test_multiple_rust_libraries(self):
+ '''Test that linking multiple Rust libraries throws an error'''
+ reader = self.reader('multiple-rust-libraries',
+ extra_substs=dict(RUST_TARGET='i686-pc-windows-msvc'))
+- with self.assertRaisesRegexp(LinkageMultipleRustLibrariesError,
++ with self.assertRaisesRegex(LinkageMultipleRustLibrariesError,
+ 'Cannot link multiple Rust libraries'):
+ self.read_topsrcdir(reader)
+
+@@ -1107,7 +1107,7 @@
+ mozpath.join(reader.config.topobjdir, 'dir2'),
+ '/dir3',
+ ]
+- self.assertEquals([p.full_path for p in objs[0].paths], expected)
++ self.assertEqual([p.full_path for p in objs[0].paths], expected)
+
+ def test_binary_components(self):
+ """Test that IS_COMPONENT/NO_COMPONENTS_MANIFEST work properly."""
+@@ -1163,7 +1163,7 @@
+ from GENERATED_FILES is an error.
+ """
+ reader = self.reader('test-symbols-file-objdir-missing-generated')
+- with self.assertRaisesRegexp(SandboxValidationError,
++ with self.assertRaisesRegex(SandboxValidationError,
+ 'Objdir file specified in SYMBOLS_FILE not in GENERATED_FILES:'):
+ self.read_topsrcdir(reader)
+
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/test/frontend/test_namespaces.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/test/frontend/test_namespaces.py (refactored)
+@@ -2,7 +2,7 @@
+ # License, v. 2.0. If a copy of the MPL was not distributed with this
+ # file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+-from __future__ import unicode_literals
++
+
+ import unittest
+
+@@ -29,7 +29,7 @@
+
+ class Piyo(ContextDerivedValue):
+ def __init__(self, context, value):
+- if not isinstance(value, unicode):
++ if not isinstance(value, str):
+ raise ValueError
+ self.context = context
+ self.value = value
+@@ -48,9 +48,9 @@
+
+
+ VARIABLES = {
+- 'HOGE': (unicode, unicode, None),
+- 'FUGA': (Fuga, unicode, None),
+- 'PIYO': (Piyo, unicode, None),
++ 'HOGE': (str, str, None),
++ 'FUGA': (Fuga, str, None),
++ 'PIYO': (Piyo, str, None),
+ 'HOGERA': (ContextDerivedTypedList(Piyo, StrictOrderingOnAppendList),
+ list, None),
+ 'HOGEHOGE': (ContextDerivedTypedListWithItems(
+@@ -104,7 +104,7 @@
+ self.assertEqual(e[1], 'set_type')
+ self.assertEqual(e[2], 'HOGE')
+ self.assertEqual(e[3], True)
+- self.assertEqual(e[4], unicode)
++ self.assertEqual(e[4], str)
+
+ def test_key_checking(self):
+ # Checking for existence of a key should not populate the key if it
+@@ -127,7 +127,7 @@
+ self.assertEqual(e[1], 'set_type')
+ self.assertEqual(e[2], 'FUGA')
+ self.assertEqual(e[3], False)
+- self.assertEqual(e[4], unicode)
++ self.assertEqual(e[4], str)
+
+ ns['FUGA'] = 'fuga'
+ self.assertIsInstance(ns['FUGA'], Fuga)
+@@ -150,7 +150,7 @@
+ self.assertEqual(e[1], 'set_type')
+ self.assertEqual(e[2], 'PIYO')
+ self.assertEqual(e[3], False)
+- self.assertEqual(e[4], unicode)
++ self.assertEqual(e[4], str)
+
+ ns['PIYO'] = 'piyo'
+ self.assertIsInstance(ns['PIYO'], Piyo)
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/test/frontend/test_reader.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/test/frontend/test_reader.py (refactored)
+@@ -2,7 +2,7 @@
+ # License, v. 2.0. If a copy of the MPL was not distributed with this
+ # file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+-from __future__ import unicode_literals
++
+
+ import os
+ import sys
+@@ -423,7 +423,7 @@
+ 'simple/base.cpp',
+ ])
+
+- for path, pattern_set in expected.items():
++ for path, pattern_set in list(expected.items()):
+ self.assertEqual(v[path].test_files,
+ expected[path])
+
+@@ -438,7 +438,7 @@
+ 'default/tests/reftests/**']),
+ }
+
+- for path, pattern_set in expected.items():
++ for path, pattern_set in list(expected.items()):
+ self.assertEqual(v[path].test_files,
+ expected[path])
+
+@@ -454,7 +454,7 @@
+ 'tagged/src/bar.jsm': set(['tagged/**.js']),
+ }
+
+- for path, pattern_set in expected_patterns.items():
++ for path, pattern_set in list(expected_patterns.items()):
+ self.assertEqual(v[path].test_files,
+ expected_patterns[path])
+
+@@ -462,7 +462,7 @@
+ 'tagged/src/submodule/foo.js': set(['submodule']),
+ 'tagged/src/bar.jsm': set([]),
+ }
+- for path, pattern_set in expected_tags.items():
++ for path, pattern_set in list(expected_tags.items()):
+ self.assertEqual(v[path].test_tags,
+ expected_tags[path])
+
+@@ -470,7 +470,7 @@
+ 'tagged/src/bar.jsm': set(['browser-chrome']),
+ 'tagged/src/submodule/foo.js': set([]),
+ }
+- for path, pattern_set in expected_flavors.items():
++ for path, pattern_set in list(expected_flavors.items()):
+ self.assertEqual(v[path].test_flavors,
+ expected_flavors[path])
+
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/test/frontend/test_sandbox.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/test/frontend/test_sandbox.py (refactored)
+@@ -2,7 +2,7 @@
+ # License, v. 2.0. If a copy of the MPL was not distributed with this
+ # file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+-from __future__ import unicode_literals
++
+
+ import os
+ import shutil
+@@ -345,7 +345,7 @@
+ sandbox = MozbuildSandbox(Context(VARIABLES, config))
+
+ self.assertEqual(sandbox['CONFIG']['BAD_UTF8'],
+- u'\ufffd\ufffd\ufffd\ufffd:')
++ '\ufffd\ufffd\ufffd\ufffd:')
+
+ def test_invalid_exports_set_base(self):
+ sandbox = self.sandbox()
+@@ -525,7 +525,7 @@
+ source = 'a = foo(1, 2)'
+ sandbox.exec_source(source, 'foo.mozbuild')
+
+- self.assertEquals(sandbox['a'], (Foo, int))
++ self.assertEqual(sandbox['a'], (Foo, int))
+ finally:
+ del FUNCTIONS['foo']
+
+--- firefox-52.9.0esr/python/mozbuild/mozpack/archive.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozpack/archive.py (refactored)
+@@ -2,7 +2,7 @@
+ # License, v. 2.0. If a copy of the MPL was not distributed with this
+ # file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+-from __future__ import absolute_import
++
+
+ import bz2
+ import gzip
+--- firefox-52.9.0esr/python/mozbuild/mozpack/copier.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozpack/copier.py (refactored)
+@@ -2,7 +2,7 @@
+ # License, v. 2.0. If a copy of the MPL was not distributed with this
+ # file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+-from __future__ import absolute_import
++
+
+ import os
+ import stat
+@@ -109,7 +109,7 @@
+ '''
+ Return all paths stored in the container, in the order they were added.
+ '''
+- return self._files.keys()
++ return list(self._files.keys())
+
+ def __len__(self):
+ '''
+@@ -142,7 +142,7 @@
+ for path, file in registry:
+ (...)
+ '''
+- return self._files.iteritems()
++ return iter(self._files.items())
+
+ def required_directories(self):
+ '''
+@@ -151,7 +151,7 @@
+ unspecified (virtual) root directory (and do not include said root
+ directory).
+ '''
+- return set(k for k, v in self._required_directories.items() if v > 0)
++ return set(k for k, v in list(self._required_directories.items()) if v > 0)
+
+
+ class FileRegistrySubtree(object):
+@@ -263,7 +263,7 @@
+
+ Returns a FileCopyResult that details what changed.
+ '''
+- assert isinstance(destination, basestring)
++ assert isinstance(destination, str)
+ assert not os.path.exists(destination) or os.path.isdir(destination)
+
+ result = FileCopyResult()
+@@ -531,7 +531,7 @@
+ def exists(self):
+ return self.deflater is not None
+
+- if isinstance(dest, basestring):
++ if isinstance(dest, str):
+ dest = Dest(dest)
+ assert isinstance(dest, Dest)
+
+--- firefox-52.9.0esr/python/mozbuild/mozpack/errors.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozpack/errors.py (refactored)
+@@ -2,7 +2,7 @@
+ # License, v. 2.0. If a copy of the MPL was not distributed with this
+ # file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+-from __future__ import absolute_import
++
+
+ import sys
+ from contextlib import contextmanager
+@@ -97,7 +97,7 @@
+ if self._count is None:
+ raise ErrorMessage(msg)
+ self._count += 1
+- print >>self.out, msg
++ print(msg, file=self.out)
+
+ def fatal(self, msg):
+ self._handle(self.FATAL, msg)
+--- firefox-52.9.0esr/python/mozbuild/mozpack/executables.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozpack/executables.py (refactored)
+@@ -2,7 +2,7 @@
+ # License, v. 2.0. If a copy of the MPL was not distributed with this
+ # file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+-from __future__ import absolute_import
++
+
+ import os
+ import struct
+--- firefox-52.9.0esr/python/mozbuild/mozpack/files.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozpack/files.py (refactored)
+@@ -2,7 +2,7 @@
+ # License, v. 2.0. If a copy of the MPL was not distributed with this
+ # file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+-from __future__ import absolute_import
++
+
+ import errno
+ import os
+@@ -57,7 +57,7 @@
+
+ def _copyfile(src, dest):
+ # False indicates `dest` should be overwritten if it exists already.
+- if isinstance(src, unicode) and isinstance(dest, unicode):
++ if isinstance(src, str) and isinstance(dest, str):
+ _CopyFileW(src, dest, False)
+ elif isinstance(src, str) and isinstance(dest, str):
+ _CopyFileA(src, dest, False)
+@@ -145,13 +145,13 @@
+ # - keep file type (e.g. S_IFREG)
+ ret = stat.S_IFMT(mode)
+ # - expand user read and execute permissions to everyone
+- if mode & 0400:
+- ret |= 0444
+- if mode & 0100:
+- ret |= 0111
++ if mode & 0o400:
++ ret |= 0o444
++ if mode & 0o100:
++ ret |= 0o111
+ # - keep user write permissions
+- if mode & 0200:
+- ret |= 0200
++ if mode & 0o200:
++ ret |= 0o200
+ # - leave away sticky bit, setuid, setgid
+ return ret
+
+@@ -164,7 +164,7 @@
+ disabled when skip_if_older is False.
+ Returns whether a copy was actually performed (True) or not (False).
+ '''
+- if isinstance(dest, basestring):
++ if isinstance(dest, str):
+ dest = Dest(dest)
+ else:
+ assert isinstance(dest, Dest)
+@@ -258,11 +258,11 @@
+ '''
+ def copy(self, dest, skip_if_older=True):
+ real_dest = dest
+- if not isinstance(dest, basestring):
++ if not isinstance(dest, str):
+ fd, dest = mkstemp()
+ os.close(fd)
+ os.remove(dest)
+- assert isinstance(dest, basestring)
++ assert isinstance(dest, str)
+ # If File.copy didn't actually copy because dest is newer, check the
+ # file sizes. If dest is smaller, it means it is already stripped and
+ # elfhacked, so we can skip.
+@@ -299,7 +299,7 @@
+ File.__init__(self, path)
+
+ def copy(self, dest, skip_if_older=True):
+- assert isinstance(dest, basestring)
++ assert isinstance(dest, str)
+
+ # The logic in this function is complicated by the fact that symlinks
+ # aren't universally supported. So, where symlinks aren't supported, we
+@@ -400,7 +400,7 @@
+ self.required = required
+
+ def copy(self, dest, skip_if_older=True):
+- if isinstance(dest, basestring):
++ if isinstance(dest, str):
+ dest = Dest(dest)
+ else:
+ assert isinstance(dest, Dest)
+@@ -432,7 +432,7 @@
+ '''
+ Invokes the preprocessor to create the destination file.
+ '''
+- if isinstance(dest, basestring):
++ if isinstance(dest, str):
+ dest = Dest(dest)
+ else:
+ assert isinstance(dest, Dest)
+@@ -563,7 +563,7 @@
+ the individual XPTs to link.
+ skip_if_older is ignored.
+ '''
+- if isinstance(dest, basestring):
++ if isinstance(dest, str):
+ dest = Dest(dest)
+ assert isinstance(dest, Dest)
+
+@@ -1014,7 +1014,7 @@
+ from mozpack.copier import FileRegistry
+ self.files = FileRegistry()
+
+- for base, finder in sorted(finders.iteritems()):
++ for base, finder in sorted(finders.items()):
+ if self.files.contains(base):
+ self.files.remove(base)
+ for p, f in finder.find(''):
+--- firefox-52.9.0esr/python/mozbuild/mozpack/hg.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozpack/hg.py (refactored)
+@@ -27,7 +27,7 @@
+ # do not wish to do so, delete this exception statement from your
+ # version.
+
+-from __future__ import absolute_import
++
+
+ import mercurial.error as error
+ import mercurial.hg as hg
+@@ -56,7 +56,7 @@
+
+ Accepts a Mercurial localrepo and changectx instance.
+ """
+- if isinstance(repo, (str, unicode)):
++ if isinstance(repo, str):
+ path = repo
+ repo = hg.repository(hgui.ui(), repo)
+ else:
+@@ -85,7 +85,7 @@
+ return self._get(path)
+
+ def _get(self, path):
+- if isinstance(path, unicode):
++ if isinstance(path, str):
+ path = path.encode('utf-8', 'replace')
+
+ try:
+--- firefox-52.9.0esr/python/mozbuild/mozpack/manifests.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozpack/manifests.py (refactored)
+@@ -2,7 +2,7 @@
+ # License, v. 2.0. If a copy of the MPL was not distributed with this
+ # file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+-from __future__ import absolute_import, unicode_literals
++
+
+ from contextlib import contextmanager
+ import json
+--- firefox-52.9.0esr/python/mozbuild/mozpack/mozjar.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozpack/mozjar.py (refactored)
+@@ -2,7 +2,7 @@
+ # License, v. 2.0. If a copy of the MPL was not distributed with this
+ # file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+-from __future__ import absolute_import
++
+
+ from io import BytesIO
+ import struct
+@@ -13,8 +13,9 @@
+ ZIP_DEFLATED,
+ )
+ from collections import OrderedDict
+-from urlparse import urlparse, ParseResult
++from urllib.parse import urlparse, ParseResult
+ import mozpack.path as mozpath
++from functools import reduce
+
+ JAR_STORED = ZIP_STORED
+ JAR_DEFLATED = ZIP_DEFLATED
+@@ -68,7 +69,7 @@
+ an instance with empty fields.
+ '''
+ assert self.MAGIC and isinstance(self.STRUCT, OrderedDict)
+- self.size_fields = set(t for t in self.STRUCT.itervalues()
++ self.size_fields = set(t for t in self.STRUCT.values()
+ if not t in JarStruct.TYPE_MAPPING)
+ self._values = {}
+ if data:
+@@ -90,7 +91,7 @@
+ # For all fields used as other fields sizes, keep track of their value
+ # separately.
+ sizes = dict((t, 0) for t in self.size_fields)
+- for name, t in self.STRUCT.iteritems():
++ for name, t in self.STRUCT.items():
+ if t in JarStruct.TYPE_MAPPING:
+ value, size = JarStruct.get_data(t, data[offset:])
+ else:
+@@ -109,7 +110,7 @@
+ Initialize an instance with empty fields.
+ '''
+ self.signature = self.MAGIC
+- for name, t in self.STRUCT.iteritems():
++ for name, t in self.STRUCT.items():
+ if name in self.size_fields:
+ continue
+ self._values[name] = 0 if t in JarStruct.TYPE_MAPPING else ''
+@@ -134,9 +135,9 @@
+ from self.STRUCT.
+ '''
+ serialized = struct.pack('<I', self.signature)
+- sizes = dict((t, name) for name, t in self.STRUCT.iteritems()
++ sizes = dict((t, name) for name, t in self.STRUCT.items()
+ if not t in JarStruct.TYPE_MAPPING)
+- for name, t in self.STRUCT.iteritems():
++ for name, t in self.STRUCT.items():
+ if t in JarStruct.TYPE_MAPPING:
+ format, size = JarStruct.TYPE_MAPPING[t]
+ if name in sizes:
+@@ -155,7 +156,7 @@
+ variable length fields.
+ '''
+ size = JarStruct.TYPE_MAPPING['uint32'][1]
+- for name, type in self.STRUCT.iteritems():
++ for name, type in self.STRUCT.items():
+ if type in JarStruct.TYPE_MAPPING:
+ size += JarStruct.TYPE_MAPPING[type][1]
+ else:
+@@ -176,7 +177,7 @@
+ return key in self._values
+
+ def __iter__(self):
+- return self._values.iteritems()
++ return iter(self._values.items())
+
+ def __repr__(self):
+ return "<%s %s>" % (self.__class__.__name__,
+@@ -374,7 +375,7 @@
+ preload = JarStruct.get_data('uint32', self._data)[0]
+ entries = OrderedDict()
+ offset = self._cdir_end['cdir_offset']
+- for e in xrange(self._cdir_end['cdir_entries']):
++ for e in range(self._cdir_end['cdir_entries']):
+ entry = JarCdirEntry(self._data[offset:])
+ offset += entry.size
+ # Creator host system. 0 is MSDOS, 3 is Unix
+@@ -385,7 +386,7 @@
+ xattr = entry['external_attr']
+ # Skip directories
+ if (host == 0 and xattr & 0x10) or (host == 3 and
+- xattr & (040000 << 16)):
++ xattr & (0o40000 << 16)):
+ continue
+ entries[entry['filename']] = entry
+ if entry['offset'] < preload:
+@@ -436,7 +437,7 @@
+ for file in jarReader:
+ ...
+ '''
+- for entry in self.entries.itervalues():
++ for entry in self.entries.values():
+ yield self._getreader(entry)
+
+ def __getitem__(self, name):
+@@ -529,7 +530,7 @@
+ headers = {}
+ preload_size = 0
+ # Prepare central directory entries
+- for entry, content in self._contents.itervalues():
++ for entry, content in self._contents.values():
+ header = JarLocalFileHeader()
+ for name in entry.STRUCT:
+ if name in header:
+@@ -544,7 +545,7 @@
+ end['disk_entries'] = len(self._contents)
+ end['cdir_entries'] = end['disk_entries']
+ end['cdir_size'] = reduce(lambda x, y: x + y[0].size,
+- self._contents.values(), 0)
++ list(self._contents.values()), 0)
+ # On optimized archives, store the preloaded size and the central
+ # directory entries, followed by the first end of central directory.
+ if self._optimize:
+@@ -553,18 +554,18 @@
+ if preload_size:
+ preload_size += offset
+ self._data.write(struct.pack('<I', preload_size))
+- for entry, _ in self._contents.itervalues():
++ for entry, _ in self._contents.values():
+ entry['offset'] += offset
+ self._data.write(entry.serialize())
+ self._data.write(end.serialize())
+ # Store local file entries followed by compressed data
+- for entry, content in self._contents.itervalues():
++ for entry, content in self._contents.values():
+ self._data.write(headers[entry].serialize())
+ self._data.write(content)
+ # On non optimized archives, store the central directory entries.
+ if not self._optimize:
+ end['cdir_offset'] = offset
+- for entry, _ in self._contents.itervalues():
++ for entry, _ in self._contents.values():
+ self._data.write(entry.serialize())
+ # Store the end of central directory.
+ self._data.write(end.serialize())
+@@ -599,7 +600,7 @@
+ deflater = data
+ else:
+ deflater = Deflater(compress, compress_level=self._compress_level)
+- if isinstance(data, basestring):
++ if isinstance(data, str):
+ deflater.write(data)
+ elif hasattr(data, 'read'):
+ if hasattr(data, 'seek'):
+@@ -615,7 +616,7 @@
+ # Set creator host system (upper byte of creator_version)
+ # to 3 (Unix) so mode is honored when there is one.
+ entry['creator_version'] |= 3 << 8
+- entry['external_attr'] = (mode & 0xFFFF) << 16L
++ entry['external_attr'] = (mode & 0xFFFF) << 16
+ if deflater.compressed:
+ entry['min_version'] = 20 # Version 2.0 supports deflated streams
+ entry['general_flag'] = 2 # Max compression
+--- firefox-52.9.0esr/python/mozbuild/mozpack/path.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozpack/path.py (refactored)
+@@ -2,7 +2,7 @@
+ # License, v. 2.0. If a copy of the MPL was not distributed with this
+ # file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+-from __future__ import absolute_import
++
+
+ import posixpath
+ import os
+--- firefox-52.9.0esr/python/mozbuild/mozpack/unify.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozpack/unify.py (refactored)
+@@ -2,7 +2,7 @@
+ # License, v. 2.0. If a copy of the MPL was not distributed with this
+ # file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+-from __future__ import absolute_import
++
+
+ from mozpack.files import (
+ BaseFinder,
+@@ -73,7 +73,7 @@
+ creating the instance.
+ skip_if_older is ignored.
+ '''
+- assert isinstance(dest, basestring)
++ assert isinstance(dest, str)
+ tmpfiles = []
+ try:
+ for e in self._executables:
+--- firefox-52.9.0esr/python/mozbuild/mozpack/chrome/flags.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozpack/chrome/flags.py (refactored)
+@@ -2,7 +2,7 @@
+ # License, v. 2.0. If a copy of the MPL was not distributed with this
+ # file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+-from __future__ import absolute_import
++
+
+ import re
+ from distutils.version import LooseVersion
+@@ -250,7 +250,7 @@
+ flags.match(application='foo', appversion='3.5') returns True
+ flags.match(application='foo', appversion='3.0') returns False
+ '''
+- for name, value in filter.iteritems():
++ for name, value in filter.items():
+ if not name in self:
+ continue
+ if not self[name].matches(value):
+--- firefox-52.9.0esr/python/mozbuild/mozpack/chrome/manifest.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozpack/chrome/manifest.py (refactored)
+@@ -2,11 +2,11 @@
+ # License, v. 2.0. If a copy of the MPL was not distributed with this
+ # file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+-from __future__ import absolute_import
++
+
+ import re
+ import os
+-from urlparse import urlparse
++from urllib.parse import urlparse
+ import mozpack.path as mozpath
+ from mozpack.chrome.flags import Flags
+ from mozpack.errors import errors
+@@ -321,7 +321,7 @@
+ return self.serialize(self.contractID, self.cid)
+
+ # All manifest classes by their type name.
+-MANIFESTS_TYPES = dict([(c.type, c) for c in globals().values()
++MANIFESTS_TYPES = dict([(c.type, c) for c in list(globals().values())
+ if type(c) == type and issubclass(c, ManifestEntry)
+ and hasattr(c, 'type') and c.type])
+
+--- firefox-52.9.0esr/python/mozbuild/mozpack/packager/__init__.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozpack/packager/__init__.py (refactored)
+@@ -2,7 +2,7 @@
+ # License, v. 2.0. If a copy of the MPL was not distributed with this
+ # file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+-from __future__ import absolute_import
++
+
+ from mozbuild.preprocessor import Preprocessor
+ import re
+@@ -50,7 +50,7 @@
+ '''
+ Split [1, 2, 3, 4, 5, 6, 7] into [(1, 2, 3), (4, 5, 6)].
+ '''
+- return zip(*[iter(lst)] * 3)
++ return list(zip(*[iter(lst)] * 3))
+
+ KEY_VALUE_RE = re.compile(r'''
+ \s* # optional whitespace.
+@@ -118,7 +118,7 @@
+ destdir = options.pop('destdir', '')
+ if options:
+ errors.fatal('Malformed manifest: options %s not recognized'
+- % options.keys())
++ % list(options.keys()))
+ return Component(name, destdir=destdir)
+
+
+@@ -328,7 +328,7 @@
+
+ bases = self.get_bases()
+ broken_bases = sorted(
+- m for m, includer in self._included_manifests.iteritems()
++ m for m, includer in self._included_manifests.items()
+ if mozpath.basedir(m, bases) != mozpath.basedir(includer, bases))
+ for m in broken_bases:
+ errors.fatal('"%s" is included from "%s", which is outside "%s"' %
+--- firefox-52.9.0esr/python/mozbuild/mozpack/packager/formats.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozpack/packager/formats.py (refactored)
+@@ -2,7 +2,7 @@
+ # License, v. 2.0. If a copy of the MPL was not distributed with this
+ # file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+-from __future__ import absolute_import
++
+
+ from mozpack.chrome.manifest import (
+ Manifest,
+@@ -11,7 +11,7 @@
+ ManifestBinaryComponent,
+ ManifestResource,
+ )
+-from urlparse import urlparse
++from urllib.parse import urlparse
+ import mozpack.path as mozpath
+ from mozpack.files import (
+ ManifestFile,
+@@ -89,7 +89,7 @@
+ Return the deepest base directory containing the given path.
+ '''
+ self._frozen_bases = True
+- base = mozpath.basedir(path, self._sub_formatter.keys())
++ base = mozpath.basedir(path, list(self._sub_formatter.keys()))
+ relpath = mozpath.relpath(path, base) if base else path
+ return base, relpath
+
+--- firefox-52.9.0esr/python/mozbuild/mozpack/packager/l10n.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozpack/packager/l10n.py (refactored)
+@@ -2,7 +2,7 @@
+ # License, v. 2.0. If a copy of the MPL was not distributed with this
+ # file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+-from __future__ import absolute_import
++
+
+ '''
+ Replace localized parts of a packaged directory with data from a langpack
+@@ -162,7 +162,7 @@
+ if not path:
+ continue
+ else:
+- base = mozpath.basedir(p, paths.keys())
++ base = mozpath.basedir(p, list(paths.keys()))
+ if base:
+ subpath = mozpath.relpath(p, base)
+ path = mozpath.normpath(mozpath.join(paths[base],
+@@ -206,7 +206,7 @@
+ formatter.add(p, f)
+
+ # Transplant jar preloading information.
+- for path, log in app_finder.jarlogs.iteritems():
++ for path, log in app_finder.jarlogs.items():
+ assert isinstance(copier[path], Jarrer)
+ copier[path].preload([l.replace(locale, l10n_locale) for l in log])
+
+@@ -237,7 +237,7 @@
+ finders = {
+ '': l10n_finder,
+ }
+- for base, path in extra_l10n.iteritems():
++ for base, path in extra_l10n.items():
+ finders[base] = UnpackFinder(path)
+ l10n_finder = ComposedFinder(finders)
+ copier = FileCopier()
+--- firefox-52.9.0esr/python/mozbuild/mozpack/packager/unpack.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozpack/packager/unpack.py (refactored)
+@@ -2,7 +2,7 @@
+ # License, v. 2.0. If a copy of the MPL was not distributed with this
+ # file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+-from __future__ import absolute_import
++
+
+ import mozpack.path as mozpath
+ from mozpack.files import (
+@@ -27,7 +27,7 @@
+ FlatFormatter,
+ STARTUP_CACHE_PATHS,
+ )
+-from urlparse import urlparse
++from urllib.parse import urlparse
+
+
+ class UnpackFinder(BaseFinder):
+@@ -149,7 +149,7 @@
+ if not any(f.compressed for f in jar):
+ self.compressed = False
+ if jar.last_preloaded:
+- jarlog = jar.entries.keys()
++ jarlog = list(jar.entries.keys())
+ self.jarlogs[path] = jarlog[:jarlog.index(jar.last_preloaded) + 1]
+ return jar
+
+--- firefox-52.9.0esr/python/mozbuild/mozpack/test/test_archive.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozpack/test/test_archive.py (refactored)
+@@ -2,7 +2,7 @@
+ # License, v. 2.0. If a copy of the MPL was not distributed with this
+ # file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+-from __future__ import absolute_import
++
+
+ import hashlib
+ import os
+@@ -69,7 +69,7 @@
+ try:
+ tp = os.path.join(d, 'test.tar')
+ with open(tp, 'wb') as fh:
+- with self.assertRaisesRegexp(ValueError, 'not a regular'):
++ with self.assertRaisesRegex(ValueError, 'not a regular'):
+ create_tar_from_files(fh, {'test': d})
+ finally:
+ shutil.rmtree(d)
+@@ -89,9 +89,9 @@
+
+ tp = os.path.join(d, 'test.tar')
+ with open(tp, 'wb') as fh:
+- with self.assertRaisesRegexp(ValueError, 'cannot add file with setuid'):
++ with self.assertRaisesRegex(ValueError, 'cannot add file with setuid'):
+ create_tar_from_files(fh, {'test': uid})
+- with self.assertRaisesRegexp(ValueError, 'cannot add file with setuid'):
++ with self.assertRaisesRegex(ValueError, 'cannot add file with setuid'):
+ create_tar_from_files(fh, {'test': gid})
+ finally:
+ shutil.rmtree(d)
+--- firefox-52.9.0esr/python/mozbuild/mozpack/test/test_chrome_manifest.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozpack/test/test_chrome_manifest.py (refactored)
+@@ -24,7 +24,7 @@
+ parse_manifest_line,
+ )
+ from mozpack.errors import errors, AccumulatedErrors
+-from test_errors import TestErrors
++from .test_errors import TestErrors
+
+
+ class TestManifest(unittest.TestCase):
+--- firefox-52.9.0esr/python/mozbuild/mozpack/test/test_copier.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozpack/test/test_copier.py (refactored)
+@@ -127,7 +127,7 @@
+ 'bar': [],
+ }
+ reg = FileRegistry()
+- for path, parts in cases.iteritems():
++ for path, parts in cases.items():
+ self.assertEqual(reg._partial_paths(path), parts)
+
+ def test_file_registry(self):
+@@ -414,7 +414,7 @@
+ self.assertTrue(stat.S_ISDIR(st.st_mode))
+
+ # What's worse, we have no record that dest was created.
+- self.assertEquals(len(result.updated_files), 0)
++ self.assertEqual(len(result.updated_files), 0)
+
+ # But we do have an erroneous record of an optional file
+ # existing when it does not.
+--- firefox-52.9.0esr/python/mozbuild/mozpack/test/test_errors.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozpack/test/test_errors.py (refactored)
+@@ -10,7 +10,7 @@
+ import unittest
+ import mozunit
+ import sys
+-from cStringIO import StringIO
++from io import StringIO
+
+
+ class TestErrors(object):
+@@ -30,14 +30,14 @@
+ errors.warn('foo')
+ self.assertRaises(ErrorMessage, errors.error, 'foo')
+ self.assertRaises(ErrorMessage, errors.fatal, 'foo')
+- self.assertEquals(self.get_output(), ['Warning: foo'])
++ self.assertEqual(self.get_output(), ['Warning: foo'])
+
+ def test_ignore_errors(self):
+ errors.ignore_errors()
+ errors.warn('foo')
+ errors.error('bar')
+ self.assertRaises(ErrorMessage, errors.fatal, 'foo')
+- self.assertEquals(self.get_output(), ['Warning: foo', 'Warning: bar'])
++ self.assertEqual(self.get_output(), ['Warning: foo', 'Warning: bar'])
+
+ def test_no_error(self):
+ with errors.accumulate():
+@@ -47,14 +47,14 @@
+ with self.assertRaises(AccumulatedErrors):
+ with errors.accumulate():
+ errors.error('1')
+- self.assertEquals(self.get_output(), ['Error: 1'])
++ self.assertEqual(self.get_output(), ['Error: 1'])
+
+ def test_error_loop(self):
+ with self.assertRaises(AccumulatedErrors):
+ with errors.accumulate():
+ for i in range(3):
+ errors.error('%d' % i)
+- self.assertEquals(self.get_output(),
++ self.assertEqual(self.get_output(),
+ ['Error: 0', 'Error: 1', 'Error: 2'])
+
+ def test_multiple_errors(self):
+@@ -67,7 +67,7 @@
+ else:
+ errors.error('%d' % i)
+ errors.error('bar')
+- self.assertEquals(self.get_output(),
++ self.assertEqual(self.get_output(),
+ ['Error: foo', 'Error: 0', 'Error: 1',
+ 'Warning: 2', 'Error: bar'])
+
+--- firefox-52.9.0esr/python/mozbuild/mozpack/test/test_files.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozpack/test/test_files.py (refactored)
+@@ -61,7 +61,7 @@
+ import mozpack.path as mozpath
+ from tempfile import mkdtemp
+ from io import BytesIO
+-from StringIO import StringIO
++from io import StringIO
+ from xpt import Typelib
+
+
+@@ -146,7 +146,7 @@
+ dest.write('qux')
+ self.assertEqual(dest.read(), 'qux')
+
+-rand = ''.join(random.choice(string.letters) for i in xrange(131597))
++rand = ''.join(random.choice(string.letters) for i in range(131597))
+ samples = [
+ '',
+ 'test',
+@@ -268,7 +268,7 @@
+ def test_absolute_relative(self):
+ AbsoluteSymlinkFile('/foo')
+
+- with self.assertRaisesRegexp(ValueError, 'Symlink target not absolute'):
++ with self.assertRaisesRegex(ValueError, 'Symlink target not absolute'):
+ AbsoluteSymlinkFile('./foo')
+
+ def test_symlink_file(self):
+@@ -477,7 +477,7 @@
+
+ class TestExistingFile(TestWithTmpDir):
+ def test_required_missing_dest(self):
+- with self.assertRaisesRegexp(ErrorMessage, 'Required existing file'):
++ with self.assertRaisesRegex(ErrorMessage, 'Required existing file'):
+ f = ExistingFile(required=True)
+ f.copy(self.tmppath('dest'))
+
+@@ -566,7 +566,7 @@
+ with JarWriter(src) as jar:
+ for content in samples:
+ name = ''.join(random.choice(string.letters)
+- for i in xrange(8))
++ for i in range(8))
+ jar.add(name, content, compress=True)
+ contents[name] = content
+
+--- firefox-52.9.0esr/python/mozbuild/mozpack/test/test_manifests.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozpack/test/test_manifests.py (refactored)
+@@ -2,7 +2,7 @@
+ # License, v. 2.0. If a copy of the MPL was not distributed with this
+ # file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+-from __future__ import unicode_literals
++
+
+ import os
+
+--- firefox-52.9.0esr/python/mozbuild/mozpack/test/test_mozjar.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozpack/test/test_mozjar.py (refactored)
+@@ -16,8 +16,8 @@
+ from mozpack.test.test_files import MockDest
+ import unittest
+ import mozunit
+-from cStringIO import StringIO
+-from urllib import pathname2url
++from io import StringIO
++from urllib.request import pathname2url
+ import mozpack.path as mozpath
+ import os
+
+--- firefox-52.9.0esr/python/mozbuild/mozpack/test/test_packager_formats.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozpack/test/test_packager_formats.py (refactored)
+@@ -128,7 +128,7 @@
+ 'foo': read_interfaces(foo2_xpt.open())['foo'],
+ 'bar': read_interfaces(bar_xpt.open())['bar'],
+ },
+- }.iteritems()
++ }.items()
+ })
+
+ RESULT_JAR = {
+@@ -174,7 +174,7 @@
+ },
+ 'addon1.xpi': {
+ mozpath.relpath(p, 'addon1'): f
+- for p, f in RESULT_FLAT.iteritems()
++ for p, f in RESULT_FLAT.items()
+ if p.startswith('addon1/')
+ },
+ })
+@@ -234,7 +234,7 @@
+ CONTENTS_WITH_BASE = {
+ 'bases': {
+ mozpath.join('base/root', b) if b else 'base/root': a
+- for b, a in CONTENTS['bases'].iteritems()
++ for b, a in CONTENTS['bases'].items()
+ },
+ 'manifests': [
+ m.move(mozpath.join('base/root', m.base))
+@@ -242,7 +242,7 @@
+ ],
+ 'files': {
+ mozpath.join('base/root', p): f
+- for p, f in CONTENTS['files'].iteritems()
++ for p, f in CONTENTS['files'].items()
+ },
+ }
+
+@@ -255,7 +255,7 @@
+ def result_with_base(results):
+ result = {
+ mozpath.join('base/root', p): v
+- for p, v in results.iteritems()
++ for p, v in results.items()
+ }
+ result.update(EXTRA_CONTENTS)
+ return result
+@@ -271,13 +271,13 @@
+
+
+ def fill_formatter(formatter, contents):
+- for base, is_addon in contents['bases'].items():
++ for base, is_addon in list(contents['bases'].items()):
+ formatter.add_base(base, is_addon)
+
+ for manifest in contents['manifests']:
+ formatter.add_manifest(manifest)
+
+- for k, v in contents['files'].iteritems():
++ for k, v in contents['files'].items():
+ if k.endswith('.xpt'):
+ formatter.add_interfaces(k, v)
+ else:
+--- firefox-52.9.0esr/python/mozbuild/mozpack/test/test_packager_l10n.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozpack/test/test_packager_l10n.py (refactored)
+@@ -4,7 +4,7 @@
+
+ import unittest
+ import mozunit
+-from test_packager import MockFinder
++from .test_packager import MockFinder
+ from mozpack.packager import l10n
+ from mozpack.files import (
+ GeneratedFile,
+@@ -118,7 +118,7 @@
+
+ self.assertEqual(
+ dict((p, f.open().read()) for p, f in copier),
+- dict((p, f.open().read()) for p, f in repacked.iteritems())
++ dict((p, f.open().read()) for p, f in repacked.items())
+ )
+
+
+--- firefox-52.9.0esr/python/mozbuild/mozpack/test/test_unify.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozpack/test/test_unify.py (refactored)
+@@ -13,7 +13,7 @@
+ from mozpack.files import FileFinder
+ from mozpack.mozjar import JarWriter
+ from mozpack.test.test_files import MockDest
+-from cStringIO import StringIO
++from io import StringIO
+ import os
+ import sys
+ from mozpack.errors import (
+--- firefox-52.9.0esr/python/mozbuild/mozpack/test/support/minify_js_verify.py (original)
++++ firefox-52.9.0esr/python/mozbuild/mozpack/test/support/minify_js_verify.py (refactored)
+@@ -2,7 +2,7 @@
+ # License, v. 2.0. If a copy of the MPL was not distributed with this
+ # file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+-from __future__ import print_function
++
+ import sys
+
+
+--- firefox-52.9.0esr/build/moz.configure/keyfiles.configure.old 2017-04-11 02:13:08.000000000 +0000
++++ firefox-52.9.0esr/build/moz.configure/keyfiles.configure 2018-07-10 07:57:16.030000000 +0000
+@@ -16,8 +16,8 @@
+
+ @depends('--with-%s-keyfile' % name)
+ @checking('for the %s key' % desc, lambda x: x and x is not no_key)
+- @imports(_from='__builtin__', _import='open')
+- @imports(_from='__builtin__', _import='IOError')
++ @imports(_from='builtins', _import='open')
++ @imports(_from='builtins', _import='IOError')
+ def keyfile(value):
+ if value:
+ try:
+--- firefox-52.9.0esr/build/moz.configure/windows.configure.old 2017-04-11 02:13:08.000000000 +0000
++++ firefox-52.9.0esr/build/moz.configure/windows.configure 2018-07-10 07:57:25.210000000 +0000
+@@ -19,7 +19,7 @@
+
+
+ @depends_win('--with-windows-version')
+-@imports(_from='__builtin__', _import='ValueError')
++@imports(_from='builtins', _import='ValueError')
+ def valid_windows_version(value):
+ if not value:
+ die('Cannot build with --without-windows-version')
+@@ -56,8 +56,8 @@
+ # 8.1.
+ @imports('os')
+ @imports('re')
+-@imports(_from='__builtin__', _import='sorted')
+-@imports(_from='__builtin__', _import='WindowsError')
++@imports(_from='builtins', _import='sorted')
++@imports(_from='builtins', _import='WindowsError')
+ def get_sdk_dirs(sdk, subdir):
+ def get_dirs_containing(sdk, stem, subdir):
+ base = os.path.join(sdk, stem)
+@@ -102,7 +102,7 @@
+ @depends_win(c_compiler, windows_sdk_dir, valid_windows_version,
+ 'WINDOWSSDKDIR')
+ @checking('for Windows SDK', valid_windows_sdk_dir_result)
+-@imports(_from='__builtin__', _import='sorted')
++@imports(_from='builtins', _import='sorted')
+ @imports(_from='textwrap', _import='dedent')
+ def valid_windows_sdk_dir(compiler, windows_sdk_dir, target_version,
+ windows_sdk_dir_env):
+@@ -179,7 +179,7 @@
+ @depends_win(windows_sdk_dir, 'WINDOWSSDKDIR')
+ @checking('for Universal CRT SDK', valid_ucrt_sdk_dir_result)
+ @imports('os')
+-@imports(_from='__builtin__', _import='sorted')
++@imports(_from='builtins', _import='sorted')
+ @imports(_import='mozpack.path', _as='mozpath')
+ def valid_ucrt_sdk_dir(windows_sdk_dir, windows_sdk_dir_env):
+ if windows_sdk_dir_env:
+--- firefox-52.9.0esr/build/moz.configure/toolchain.configure.old 2017-04-11 02:13:08.000000000 +0000
++++ firefox-52.9.0esr/build/moz.configure/toolchain.configure 2018-07-10 07:57:28.830000000 +0000
+@@ -395,7 +395,7 @@
+
+
+ @imports(_from='collections', _import='defaultdict')
+-@imports(_from='__builtin__', _import='sorted')
++@imports(_from='builtins', _import='sorted')
+ def get_vc_paths(base):
+ vc = defaultdict(lambda: defaultdict(dict))
+ subkey = r'Microsoft\VisualStudio\VC\*\*\*\Compiler'
+--- firefox-52.9.0esr/build/moz.configure/util.configure.old 2017-04-11 02:13:08.000000000 +0000
++++ firefox-52.9.0esr/build/moz.configure/util.configure 2018-07-10 07:57:31.540000000 +0000
+@@ -234,7 +234,7 @@
+ # ('19.0', 'x64', r'C:\...\amd64\cl.exe')
+ # ('19.0', 'x86', r'C:\...\amd64_x86\cl.exe')
+ @imports(_import='_winreg', _as='winreg')
+-@imports(_from='__builtin__', _import='WindowsError')
++@imports(_from='builtins', _import='WindowsError')
+ @imports(_from='fnmatch', _import='fnmatch')
+ def get_registry_values(pattern):
+ def enum_helper(func, key):
+--- firefox-52.9.0esr/build/moz.configure/checks.configure.old 2017-04-11 02:13:08.000000000 +0000
++++ firefox-52.9.0esr/build/moz.configure/checks.configure 2018-07-10 07:57:35.630000000 +0000
+@@ -12,7 +12,7 @@
+ # _declare_exceptions template, and add it to the return statement. Then
+ # destructure in the assignment below the function declaration.
+ @template
+-@imports(_from='__builtin__', _import='Exception')
++@imports(_from='builtins', _import='Exception')
+ def _declare_exceptions():
+ class FatalCheckError(Exception):
+ '''An exception to throw from a function decorated with @checking.
+--- firefox-52.9.0esr/build/moz.configure/old.configure.old 2017-04-11 02:13:08.000000000 +0000
++++ firefox-52.9.0esr/build/moz.configure/old.configure 2018-07-10 07:57:38.970000000 +0000
+@@ -61,8 +61,8 @@
+
+ @depends('OLD_CONFIGURE', mozconfig, autoconf, check_build_environment, shell,
+ old_configure_assignments, build_project)
+-@imports(_from='__builtin__', _import='open')
+-@imports(_from='__builtin__', _import='print')
++@imports(_from='builtins', _import='open')
++@imports(_from='builtins', _import='print')
+ @imports('glob')
+ @imports('itertools')
+ @imports('subprocess')
+@@ -302,8 +302,8 @@
+ '--enable-calendar',
+ '--enable-incomplete-external-linkage',
+ )
+-@imports(_from='__builtin__', _import='compile')
+-@imports(_from='__builtin__', _import='open')
++@imports(_from='builtins', _import='compile')
++@imports(_from='builtins', _import='open')
+ @imports('logging')
+ @imports('os')
+ @imports('subprocess')
+--- firefox-52.9.0esr/build/moz.configure/android-ndk.configure.old 2017-04-11 02:13:08.000000000 +0000
++++ firefox-52.9.0esr/build/moz.configure/android-ndk.configure 2018-07-10 07:57:41.120000000 +0000
+@@ -22,7 +22,7 @@
+ default=min_android_version)
+
+ @depends('--with-android-version', min_android_version)
+-@imports(_from='__builtin__', _import='ValueError')
++@imports(_from='builtins', _import='ValueError')
+ def android_version(value, min_version):
+ if not value:
+ # Someone has passed --without-android-version.
+--- firefox-52.9.0esr/build/moz.configure/init.configure.old 2017-04-11 02:13:08.000000000 +0000
++++ firefox-52.9.0esr/build/moz.configure/init.configure 2018-07-10 07:57:44.330000000 +0000
+@@ -636,7 +636,7 @@
+ # - otherwise, if we have "a" in GRE_MILESTONE, we're building Nightly or Aurora
+ # - otherwise, we're building Release/Beta (define RELEASE_OR_BETA)
+ @depends(check_build_environment, '--help')
+-@imports(_from='__builtin__', _import='open')
++@imports(_from='builtins', _import='open')
+ def milestone(build_env, _):
+ milestone_path = os.path.join(build_env.topsrcdir,
+ 'config',
+diff -aur firefox-52.9.0esr/config/mozunit.py mozjs-fixed/config/mozunit.py
+--- firefox-52.9.0esr/config/mozunit.py 2017-04-11 02:13:09.000000000 +0000
++++ mozjs-fixed/config/mozunit.py 2018-07-10 08:19:37.770000000 +0000
+@@ -5,7 +5,7 @@
+ from unittest import TextTestRunner as _TestRunner, TestResult as _TestResult
+ import unittest
+ import inspect
+-from StringIO import StringIO
++from io import StringIO
+ import os
+ import sys
+
+@@ -74,7 +74,7 @@
+
+ def printFail(self, test, err):
+ exctype, value, tb = err
+- message = value.message.splitlines()[0] if value.message else 'NO MESSAGE'
++ message = str(value).splitlines()[0] if str(value) else 'NO MESSAGE'
+ # Skip test runner traceback levels
+ while tb and self._is_relevant_tb_level(tb):
+ tb = tb.tb_next
+diff -aur firefox-52.9.0esr/python/mozbuild/mozbuild/backend/configenvironment.py mozjs-fixed/python/mozbuild/mozbuild/backend/configenvironment.py
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/backend/configenvironment.py 2018-07-10 08:24:43.150000000 +0000
++++ mozjs-fixed/python/mozbuild/mozbuild/backend/configenvironment.py 2018-07-10 08:15:12.650000000 +0000
+@@ -8,7 +8,8 @@
+ import sys
+
+ from collections import Iterable
+-from types import StringTypes, ModuleType
++from types import ModuleType
++StringTypes = (str,)
+
+ import mozpack.path as mozpath
+
+diff -aur firefox-52.9.0esr/python/mozbuild/mozbuild/makeutil.py mozjs-fixed/python/mozbuild/mozbuild/makeutil.py
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/makeutil.py 2018-07-10 08:24:43.150000000 +0000
++++ mozjs-fixed/python/mozbuild/mozbuild/makeutil.py 2018-07-10 08:20:05.230000000 +0000
+@@ -6,7 +6,6 @@
+
+ import os
+ import re
+-from types import StringTypes
+ from collections import Iterable
+
+
+@@ -103,19 +102,19 @@
+
+ def add_targets(self, targets):
+ '''Add additional targets to the rule.'''
+- assert isinstance(targets, Iterable) and not isinstance(targets, StringTypes)
++ assert isinstance(targets, Iterable) and not isinstance(targets, str)
+ self._targets.update(targets)
+ return self
+
+ def add_dependencies(self, deps):
+ '''Add dependencies to the rule.'''
+- assert isinstance(deps, Iterable) and not isinstance(deps, StringTypes)
++ assert isinstance(deps, Iterable) and not isinstance(deps, str)
+ self._dependencies.update(deps)
+ return self
+
+ def add_commands(self, commands):
+ '''Add commands to the rule.'''
+- assert isinstance(commands, Iterable) and not isinstance(commands, StringTypes)
++ assert isinstance(commands, Iterable) and not isinstance(commands, str)
+ self._commands.extend(commands)
+ return self
+
+diff -aur firefox-52.9.0esr/python/which/which.py mozjs-fixed/python/which/which.py
+--- firefox-52.9.0esr/python/which/which.py 2017-04-11 02:13:24.000000000 +0000
++++ mozjs-fixed/python/which/which.py 2018-07-10 08:11:01.570000000 +0000
+@@ -280,17 +280,17 @@
+ try:
+ optlist, args = getopt.getopt(argv[1:], 'haVvqp:e:',
+ ['help', 'all', 'version', 'verbose', 'quiet', 'path=', 'exts='])
+- except getopt.GetoptError, msg:
++ except getopt.GetoptError as msg:
+ sys.stderr.write("which: error: %s. Your invocation was: %s\n"\
+ % (msg, argv))
+ sys.stderr.write("Try 'which --help'.\n")
+ return 1
+ for opt, optarg in optlist:
+ if opt in ('-h', '--help'):
+- print _cmdlnUsage
++ print(_cmdlnUsage)
+ return 0
+ elif opt in ('-V', '--version'):
+- print "which %s" % __version__
++ print("which %s" % __version__)
+ return 0
+ elif opt in ('-a', '--all'):
+ all = 1
+@@ -318,9 +318,9 @@
+ nmatches = 0
+ for match in whichgen(arg, path=altpath, verbose=verbose, exts=exts):
+ if verbose:
+- print "%s (%s)" % match
++ print("%s (%s)" % match)
+ else:
+- print match
++ print(match)
+ nmatches += 1
+ if not all:
+ break
+diff -aur firefox-52.9.0esr/testing/mozbase/mozprocess/mozprocess/processhandler.py mozjs-fixed/testing/mozbase/mozprocess/mozprocess/processhandler.py
+--- firefox-52.9.0esr/testing/mozbase/mozprocess/mozprocess/processhandler.py 2017-04-11 02:13:06.000000000 +0000
++++ mozjs-fixed/testing/mozbase/mozprocess/mozprocess/processhandler.py 2018-07-10 08:13:15.440000000 +0000
+@@ -11,7 +11,7 @@
+ import threading
+ import time
+ import traceback
+-from Queue import Queue, Empty
++from queue import Queue, Empty
+ from datetime import datetime
+
+ __all__ = ['ProcessHandlerMixin', 'ProcessHandler', 'LogOutput',
+@@ -121,14 +121,14 @@
+ thread = threading.current_thread().name
+ print("DBG::MOZPROC PID:{} ({}) | {}".format(self.pid, thread, msg))
+
+- def __del__(self, _maxint=sys.maxint):
++ def __del__(self, _maxint=sys.maxsize):
+ if isWin:
+ handle = getattr(self, '_handle', None)
+ if handle:
+ if hasattr(self, '_internal_poll'):
+ self._internal_poll(_deadstate=_maxint)
+ else:
+- self.poll(_deadstate=sys.maxint)
++ self.poll(_deadstate=sys.maxsize)
+ if handle or self._job or self._io_port:
+ self._cleanup()
+ else:
+@@ -267,7 +267,7 @@
+ if not (can_create_job or can_nest_jobs):
+ # Since we've warned, we just log info here to inform you
+ # of the consequence of setting ignore_children = True
+- print "ProcessManager NOT managing child processes"
++ print("ProcessManager NOT managing child processes")
+
+ # create the process
+ hp, ht, pid, tid = winprocess.CreateProcess(
+@@ -534,11 +534,11 @@
+
+ if rc == winprocess.WAIT_TIMEOUT:
+ # The process isn't dead, so kill it
+- print "Timed out waiting for process to close, attempting TerminateProcess"
++ print("Timed out waiting for process to close, attempting TerminateProcess")
+ self.kill()
+ elif rc == winprocess.WAIT_OBJECT_0:
+ # We caught WAIT_OBJECT_0, which indicates all is well
+- print "Single process terminated successfully"
++ print("Single process terminated successfully")
+ self.returncode = winprocess.GetExitCodeProcess(self._handle)
+ else:
+ # An error occured we should probably throw
+diff -aur firefox-52.9.0esr/build/moz.configure/checks.configure mozjs-fixed/build/moz.configure/checks.configure
+--- firefox-52.9.0esr/build/moz.configure/checks.configure 2018-07-10 10:29:50.380000000 +0000
++++ mozjs-fixed/build/moz.configure/checks.configure 2018-07-10 10:27:45.350000000 +0000
+@@ -52,7 +52,7 @@
+ try:
+ ret = func(*args, **kwargs)
+ except FatalCheckError as e:
+- error = e.message
++ error = str(e)
+ display_ret = callback(ret) if callback else ret
+ if display_ret is True:
+ log.info('yes')
+diff -aur firefox-52.9.0esr/build/moz.configure/init.configure mozjs-fixed/build/moz.configure/init.configure
+--- firefox-52.9.0esr/build/moz.configure/init.configure 2018-07-10 10:29:50.380000000 +0000
++++ mozjs-fixed/build/moz.configure/init.configure 2018-07-10 10:23:19.960000000 +0000
+@@ -213,7 +213,7 @@
+ def early_options():
+ return set(
+ option.env
+- for option in __sandbox__._options.itervalues()
++ for option in list(__sandbox__._options.values())
+ if option.env
+ )
+ return early_options
+@@ -297,7 +297,7 @@
+ # There is also a quartet form:
+ # CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
+ # But we can consider the "KERNEL-OPERATING_SYSTEM" as one.
+- cpu, manufacturer, os = triplet.split('-', 2)
++ cpu, manufacturer, os = triplet.decode('utf-8').split('-', 2)
+
+ # Autoconf uses config.sub to validate and canonicalize those triplets,
+ # but the granularity of its results has never been satisfying to our
+@@ -727,7 +727,7 @@
+ def all_configure_options(_):
+ result = []
+ previous = None
+- for option in __sandbox__._options.itervalues():
++ for option in list(__sandbox__._options.values()):
+ # __sandbox__._options contains items for both option.name and
+ # option.env. But it's also an OrderedDict, meaning both are
+ # consecutive.
+diff -aur firefox-52.9.0esr/build/moz.configure/old.configure mozjs-fixed/build/moz.configure/old.configure
+--- firefox-52.9.0esr/build/moz.configure/old.configure 2018-07-10 10:29:50.380000000 +0000
++++ mozjs-fixed/build/moz.configure/old.configure 2018-07-10 10:19:19.880000000 +0000
+@@ -360,7 +360,7 @@
+ # Every variation of the exec() function I tried led to:
+ # SyntaxError: unqualified exec is not allowed in function 'main' it
+ # contains a nested function with free variables
+- exec code in raw_config
++ exec(code, raw_config)
+
+ # Ensure all the flags known to old-configure appear in the
+ # @old_configure_options above.
+diff -aur firefox-52.9.0esr/build/moz.configure/toolchain.configure mozjs-fixed/build/moz.configure/toolchain.configure
+--- firefox-52.9.0esr/build/moz.configure/toolchain.configure 2018-07-10 10:29:50.380000000 +0000
++++ mozjs-fixed/build/moz.configure/toolchain.configure 2018-07-10 10:28:13.020000000 +0000
+@@ -244,7 +244,7 @@
+ ('CPU', CPU_preprocessor_checks),
+ ('KERNEL', kernel_preprocessor_checks),
+ ):
+- for n, (value, condition) in enumerate(preprocessor_checks.iteritems()):
++ for n, (value, condition) in enumerate(preprocessor_checks.items()):
+ check += dedent('''\
+ #%(if)s %(condition)s
+ %%%(name)s "%(value)s"
+@@ -278,9 +278,9 @@
+ data = {}
+ for line in result.splitlines():
+ if line.startswith(b'%'):
+- k, _, v = line.partition(' ')
+- k = k.lstrip('%')
+- data[k] = v.replace(' ', '').lstrip('"').rstrip('"')
++ k, _, v = line.partition(b' ')
++ k = k.lstrip(b'%').decode('utf-8')
++ data[k] = v.replace(b' ', b'').lstrip(b'"').rstrip(b'"').decode('utf-8')
+ log.debug('%s = %s', k, data[k])
+
+ try:
+diff -aur firefox-52.9.0esr/build/moz.configure/util.configure mozjs-fixed/build/moz.configure/util.configure
+--- firefox-52.9.0esr/build/moz.configure/util.configure 2018-07-10 10:29:50.380000000 +0000
++++ mozjs-fixed/build/moz.configure/util.configure 2018-07-10 10:23:54.980000000 +0000
+@@ -299,6 +299,8 @@
+ @imports(_from='mozbuild.configure.util', _import='Version', _as='_Version')
+ def Version(v):
+ 'A version number that can be compared usefully.'
++ if isinstance(v, bytes):
++ v = v.decode('utf-8')
+ return _Version(v)
+
+ # Denotes a deprecated option. Combines option() and @depends:
+diff -aur firefox-52.9.0esr/python/mozbuild/mozbuild/configure/__init__.py mozjs-fixed/python/mozbuild/mozbuild/configure/__init__.py
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/configure/__init__.py 2018-07-10 10:29:50.350000000 +0000
++++ mozjs-fixed/python/mozbuild/mozbuild/configure/__init__.py 2018-07-10 10:24:33.200000000 +0000
+@@ -97,6 +97,9 @@
+ ', '.join(repr(d) for d in self.dependencies),
+ )
+
++ def __hash__(self):
++ return hash((str(self.func), tuple(self.dependencies), self.when))
++
+
+ class CombinedDependsFunction(DependsFunction):
+ def __init__(self, sandbox, func, dependencies):
+@@ -142,6 +145,9 @@
+ def __ne__(self, other):
+ return not self == other
+
++ def __hash__(self):
++ return hash((str(self.func), tuple(self.dependencies)))
++
+ class SandboxedGlobal(dict):
+ '''Identifiable dict type for use as function global'''
+
+@@ -192,7 +198,8 @@
+ b: __builtins__[b]
+ for b in ('None', 'False', 'True', 'int', 'bool', 'any', 'all', 'len',
+ 'list', 'tuple', 'set', 'dict', 'isinstance', 'getattr',
+- 'hasattr', 'enumerate', 'range', 'zip')
++ 'hasattr', 'enumerate', 'range', 'zip', '__build_class__',
++ 'bytes', 'exec')
+ }, __import__=forbidden_import, str=str)
+
+ # Expose a limited set of functions from os.path
+@@ -267,7 +274,7 @@
+ return method
+ def wrapped(*args, **kwargs):
+ out_args = [
+- arg.decode(encoding) if isinstance(arg, str) else arg
++ arg.decode(encoding) if isinstance(arg, bytes) else arg
+ for arg in args
+ ]
+ return method(*out_args, **kwargs)
+diff -aur firefox-52.9.0esr/python/mozbuild/mozbuild/configure/options.py mozjs-fixed/python/mozbuild/mozbuild/configure/options.py
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/configure/options.py 2018-07-10 10:29:50.350000000 +0000
++++ mozjs-fixed/python/mozbuild/mozbuild/configure/options.py 2018-07-10 10:15:41.760000000 +0000
+@@ -65,6 +65,9 @@
+ return '%s%s' % (self.__class__.__name__,
+ super(OptionValue, self).__repr__())
+
++ def __hash__(self):
++ return hash(str(self))
++
+
+ class PositiveOptionValue(OptionValue):
+ '''Represents the value for a positive option (--enable/--with/--foo)
+diff -aur firefox-52.9.0esr/python/mozbuild/mozbuild/configure/util.py mozjs-fixed/python/mozbuild/mozbuild/configure/util.py
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/configure/util.py 2018-07-10 10:29:50.350000000 +0000
++++ mozjs-fixed/python/mozbuild/mozbuild/configure/util.py 2018-07-10 09:04:28.150000000 +0000
+@@ -200,7 +200,7 @@
+ self._encoding = getpreferredencoding()
+
+ def write(self, buf):
+- if self._encoding and isinstance(buf, str):
++ if self._encoding and isinstance(buf, bytes):
+ buf = buf.decode(self._encoding)
+ lines = buf.splitlines()
+ if not lines:
+diff -aur firefox-52.9.0esr/python/mozbuild/mozbuild/virtualenv.py mozjs-fixed/python/mozbuild/mozbuild/virtualenv.py
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/virtualenv.py 2018-07-10 10:29:50.350000000 +0000
++++ mozjs-fixed/python/mozbuild/mozbuild/virtualenv.py 2018-07-10 10:11:47.710000000 +0000
+@@ -108,7 +108,7 @@
+ """
+ ver = subprocess.check_output([python, '-c', 'import sys; print(sys.hexversion)']).rstrip()
+ with open(self.exe_info_path, 'w') as fh:
+- fh.write("%s\n" % ver)
++ fh.write("%s\n" % ver.decode('utf-8'))
+ fh.write("%s\n" % os.path.getsize(python))
+
+ def up_to_date(self, python=sys.executable):
+@@ -207,7 +207,7 @@
+ return self.virtualenv_root
+
+ def packages(self):
+- with file(self.manifest_path, 'rU') as fh:
++ with open(self.manifest_path, 'rU') as fh:
+ packages = [line.rstrip().split(':')
+ for line in fh]
+ return packages
+@@ -530,9 +530,9 @@
+
+ our = LooseVersion('%d.%d.%d' % (major, minor, micro))
+
+- if major != MINIMUM_PYTHON_MAJOR or our < MINIMUM_PYTHON_VERSION:
+- log_handle.write('Python %s or greater (but not Python 3) is '
+- 'required to build. ' % MINIMUM_PYTHON_VERSION)
++ if our < MINIMUM_PYTHON_VERSION:
++ log_handle.write('Python %s or greater is required to build. '
++ % MINIMUM_PYTHON_VERSION)
+ log_handle.write('You are running Python %s.\n' % our)
+
+ if os.name in ('nt', 'ce'):
+diff -aur firefox-52.9.0esr/python/which/which.py mozjs-fixed/python/which/which.py
+--- firefox-52.9.0esr/python/which/which.py 2018-07-10 10:29:50.380000000 +0000
++++ mozjs-fixed/python/which/which.py 2018-07-10 10:20:16.770000000 +0000
+@@ -243,7 +243,7 @@
+ If no match is found for the command, a WhichError is raised.
+ """
+ try:
+- match = whichgen(command, path, verbose, exts).next()
++ match = next(whichgen(command, path, verbose, exts))
+ except StopIteration:
+ raise WhichError("Could not find '%s' on the path." % command)
+ return match
+--- firefox-52.9.0esr/build/moz.configure/old.configure.old 2018-07-10 10:32:48.550000000 +0000
++++ firefox-52.9.0esr/build/moz.configure/old.configure 2018-07-10 10:35:32.440000000 +0000
+@@ -107,7 +107,7 @@
+
+ # Make old-configure append to config.log, where we put our own log.
+ # This could be done with a m4 macro, but it's way easier this way
+- script = script.replace('>./config.log', '>>./config.log')
++ script = script.replace(b'>./config.log', b'>>./config.log')
+
+ with open(old_configure, 'wb') as fh:
+ fh.write(script)
+--- firefox-52.9.0esr/build/subconfigure.py.old 2017-04-11 02:13:09.000000000 +0000
++++ firefox-52.9.0esr/build/subconfigure.py 2018-07-10 10:38:08.910000000 +0000
+@@ -27,7 +27,7 @@
+ return super(Pool, cls).__new__(cls)
+
+ def imap_unordered(self, fn, iterable):
+- return itertools.imap(fn, iterable)
++ return map(fn, iterable)
+
+ def close(self):
+ pass
+@@ -131,11 +131,11 @@
+ is_set = cache.get('ac_cv_env_%s_set' % precious) == 'set'
+ value = cache.get('ac_cv_env_%s_value' % precious) if is_set else None
+ if value != env.get(precious):
+- print 'Removing %s because of %s value change from:' \
+- % (data['cache-file'], precious)
+- print ' %s' % (value if value is not None else 'undefined')
+- print 'to:'
+- print ' %s' % env.get(precious, 'undefined')
++ print('Removing %s because of %s value change from:' \
++ % (data['cache-file'], precious))
++ print(' %s' % (value if value is not None else 'undefined'))
++ print('to:')
++ print(' %s' % env.get(precious, 'undefined'))
+ os.remove(data['cache-file'])
+ return True
+ return False
+@@ -333,8 +333,8 @@
+ # We're going to run it ourselves.
+ command += ['--no-create']
+
+- print prefix_lines('configuring', relobjdir)
+- print prefix_lines('running %s' % ' '.join(command[:-1]), relobjdir)
++ print(prefix_lines('configuring', relobjdir))
++ print(prefix_lines('running %s' % ' '.join(command[:-1]), relobjdir))
+ sys.stdout.flush()
+ try:
+ output += subprocess.check_output(command,
+@@ -368,7 +368,7 @@
+
+ if not skip_config_status:
+ if skip_configure:
+- print prefix_lines('running config.status', relobjdir)
++ print(prefix_lines('running config.status', relobjdir))
+ sys.stdout.flush()
+ try:
+ output += subprocess.check_output([data['shell'], '-c',
+@@ -410,7 +410,7 @@
+ pool = Pool(len(subconfigures))
+ for relobjdir, returncode, output in \
+ pool.imap_unordered(run, subconfigures):
+- print prefix_lines(output, relobjdir)
++ print(prefix_lines(output, relobjdir))
+ sys.stdout.flush()
+ ret = max(returncode, ret)
+ if ret:
+--- firefox-52.9.0esr/build/moz.configure/old.configure.old 2018-07-10 10:38:53.530000000 +0000
++++ firefox-52.9.0esr/build/moz.configure/old.configure 2018-07-10 10:41:32.560000000 +0000
+@@ -394,7 +394,7 @@
+ def post_old_configure(raw_config):
+ for k, v in raw_config['substs']:
+ set_old_configure_config(
+- k[1:-1], v[1:-1] if isinstance(v, types.StringTypes) else v)
++ k[1:-1], v[1:-1] if isinstance(v, str) else v)
+
+- for k, v in dict(raw_config['defines']).iteritems():
++ for k, v in dict(raw_config['defines']).items():
+ set_old_configure_define(k[1:-1], v[1:-1])
+--- firefox-52.9.0esr/configure.py (original)
++++ firefox-52.9.0esr/configure.py (refactored)
+@@ -2,7 +2,7 @@
+ # License, v. 2.0. If a copy of the MPL was not distributed with this
+ # file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+-from __future__ import print_function, unicode_literals
++
+
+ import codecs
+ import os
+@@ -45,11 +45,11 @@
+
+ sanitized_config = {}
+ sanitized_config['substs'] = {
+- k: sanitized_bools(v) for k, v in config.iteritems()
++ k: sanitized_bools(v) for k, v in config.items()
+ if k not in ('DEFINES', 'non_global_defines', 'TOPSRCDIR', 'TOPOBJDIR')
+ }
+ sanitized_config['defines'] = {
+- k: sanitized_bools(v) for k, v in config['DEFINES'].iteritems()
++ k: sanitized_bools(v) for k, v in config['DEFINES'].items()
+ }
+ sanitized_config['non_global_defines'] = config['non_global_defines']
+ sanitized_config['topsrcdir'] = config['TOPSRCDIR']
+@@ -71,7 +71,7 @@
+ ''') % {'python': config['PYTHON'], 'encoding': encoding})
+ # A lot of the build backend code is currently expecting byte
+ # strings and breaks in subtle ways with unicode strings. (bug 1296508)
+- for k, v in sanitized_config.iteritems():
++ for k, v in sanitized_config.items():
+ fh.write('%s = encode(%s, encoding)\n' % (k, indented_repr(v)))
+ fh.write("__all__ = ['topobjdir', 'topsrcdir', 'defines', "
+ "'non_global_defines', 'substs', 'mozconfig']")
+@@ -88,7 +88,7 @@
+ # executable permissions.
+ os.chmod('config.status', 0o755)
+ if config.get('MOZ_BUILD_APP') != 'js' or config.get('JS_STANDALONE'):
+- os.environ[b'WRITE_MOZINFO'] = b'1'
++ os.environ['WRITE_MOZINFO'] = '1'
+ from mozbuild.config_status import config_status
+
+ # Some values in sanitized_config also have more complex types, such as
+--- firefox-52.9.0esr/python/blessings/blessings/__init__.py.old 2017-04-11 02:13:23.000000000 +0000
++++ firefox-52.9.0esr/python/blessings/blessings/__init__.py 2018-07-10 10:56:52.820000000 +0000
+@@ -333,7 +333,7 @@
+ 'shadow', 'standout', 'subscript', 'superscript']))
+
+
+-class ParametrizingString(unicode):
++class ParametrizingString(str):
+ """A Unicode string which can be called to parametrize it as a terminal capability"""
+ def __new__(cls, formatting, normal=None):
+ """Instantiate.
+@@ -343,7 +343,7 @@
+ "normal" capability.
+
+ """
+- new = unicode.__new__(cls, formatting)
++ new = str.__new__(cls, formatting)
+ new._normal = normal
+ return new
+
+@@ -375,10 +375,10 @@
+ raise
+
+
+-class FormattingString(unicode):
++class FormattingString(str):
+ """A Unicode string which can be called upon a piece of text to wrap it in formatting"""
+ def __new__(cls, formatting, normal):
+- new = unicode.__new__(cls, formatting)
++ new = str.__new__(cls, formatting)
+ new._normal = normal
+ return new
+
+@@ -393,7 +393,7 @@
+ return self + text + self._normal
+
+
+-class NullCallableString(unicode):
++class NullCallableString(str):
+ """A dummy class to stand in for ``FormattingString`` and ``ParametrizingString``
+
+ A callable bytestring that returns an empty Unicode when called with an int
+@@ -402,7 +402,7 @@
+
+ """
+ def __new__(cls):
+- new = unicode.__new__(cls, u'')
++ new = str.__new__(cls, u'')
+ return new
+
+ def __call__(self, arg):
+--- firefox-52.9.0esr/testing/mozbase/mozfile/mozfile/mozfile.py (original)
++++ firefox-52.9.0esr/testing/mozbase/mozfile/mozfile/mozfile.py (refactored)
+@@ -6,7 +6,7 @@
+
+ # We don't import all modules at the top for performance reasons. See Bug 1008943
+
+-from __future__ import absolute_import
++
+
+ from contextlib import contextmanager
+ import errno
+@@ -55,7 +55,7 @@
+ try:
+ bundle = zipfile.ZipFile(src)
+ except Exception:
+- print "src: %s" % src
++ print("src: %s" % src)
+ raise
+
+ namelist = bundle.namelist()
+@@ -161,8 +161,8 @@
+
+ retry_count += 1
+
+- print '%s() failed for "%s". Reason: %s (%s). Retrying...' % \
+- (func.__name__, args, e.strerror, e.errno)
++ print('%s() failed for "%s". Reason: %s (%s). Retrying...' % \
++ (func.__name__, args, e.strerror, e.errno))
+ time.sleep(retry_count * retry_delay)
+ else:
+ # If no exception has been thrown it should be done
+@@ -420,9 +420,9 @@
+ Return True if thing looks like a URL.
+ """
+
+- import urlparse
+-
+- parsed = urlparse.urlparse(thing)
++ import urllib.parse
++
++ parsed = urllib.parse.urlparse(thing)
+ if 'scheme' in parsed:
+ return len(parsed.scheme) >= 2
+ else:
+@@ -436,7 +436,7 @@
+ result of urllib2.urlopen()
+ """
+
+- import urllib2
++ import urllib.request, urllib.error, urllib.parse
+
+ # handle file URLs separately due to python stdlib limitations
+ if resource.startswith('file://'):
+@@ -446,4 +446,4 @@
+ # if no scheme is given, it is a file path
+- return file(resource)
++ return open(resource)
+
+- return urllib2.urlopen(resource)
++ return urllib.request.urlopen(resource)
+--- firefox-52.9.0esr/testing/mozbase/mozinfo/mozinfo/mozinfo.py (original)
++++ firefox-52.9.0esr/testing/mozbase/mozinfo/mozinfo/mozinfo.py (refactored)
+@@ -8,7 +8,7 @@
+ # linux) to the information; I certainly wouldn't want anyone parsing this
+ # information and having behaviour depend on it
+
+-from __future__ import absolute_import
++
+
+ import os
+ import platform
+@@ -24,7 +24,7 @@
+ class unknown(object):
+ """marker class for unknown information"""
+
+- def __nonzero__(self):
++ def __bool__(self):
+ return False
+
+ def __str__(self):
+@@ -184,7 +184,7 @@
+ to a json file containing the new info.
+ """
+
+- if isinstance(new_info, basestring):
++ if isinstance(new_info, str):
+ # lazy import
+ import mozfile
+ import json
+@@ -246,7 +246,7 @@
+ update({})
+
+ # exports
+-__all__ = info.keys()
++__all__ = list(info.keys())
+ __all__ += ['is' + os_name.title() for os_name in choices['os']]
+ __all__ += [
+ 'info',
+@@ -284,17 +284,17 @@
+
+ # print out choices if requested
+ flag = False
+- for key, value in options.__dict__.items():
++ for key, value in list(options.__dict__.items()):
+ if value is True:
+- print '%s choices: %s' % (key, ' '.join([str(choice)
+- for choice in choices[key]]))
++ print('%s choices: %s' % (key, ' '.join([str(choice)
++ for choice in choices[key]])))
+ flag = True
+ if flag:
+ return
+
+ # otherwise, print out all info
+- for key, value in info.items():
+- print '%s: %s' % (key, value)
++ for key, value in list(info.items()):
++ print('%s: %s' % (key, value))
+
+ if __name__ == '__main__':
+ main()
+--- firefox-52.9.0esr/testing/mozbase/mozinfo/mozinfo/string_version.py.old 2017-04-11 02:13:06.000000000 +0000
++++ firefox-52.9.0esr/testing/mozbase/mozinfo/mozinfo/string_version.py 2018-07-10 11:10:56.140000000 +0000
+@@ -10,8 +10,10 @@
+ A string version that can be compared with comparison operators.
+ """
+
++ def __new__(cls, value):
++ return str.__new__(cls, value)
++
+ def __init__(self, vstring):
+- str.__init__(self, vstring)
+ self.version = LooseVersion(vstring)
+
+ def __repr__(self):
+--- firefox-52.9.0esr/testing/mozbase/manifestparser/manifestparser/manifestparser.py (original)
++++ firefox-52.9.0esr/testing/mozbase/manifestparser/manifestparser/manifestparser.py (refactored)
+@@ -2,7 +2,7 @@
+ # License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ # You can obtain one at http://mozilla.org/MPL/2.0/.
+
+-from StringIO import StringIO
++from io import StringIO
+ import json
+ import fnmatch
+ import os
+@@ -21,7 +21,7 @@
+ __all__ = ['ManifestParser', 'TestManifest', 'convert']
+
+ relpath = os.path.relpath
+-string = (basestring,)
++string = (str,)
+
+
+ # path normalization
+@@ -178,7 +178,7 @@
+
+ # otherwise an item
+ # apply ancestor defaults, while maintaining current file priority
+- data = dict(self._ancestor_defaults.items() + data.items())
++ data = dict(list(self._ancestor_defaults.items()) + list(data.items()))
+
+ test = data
+ test['name'] = section
+@@ -306,19 +306,19 @@
+ # make some check functions
+ if inverse:
+ def has_tags(test):
+- return not tags.intersection(test.keys())
++ return not tags.intersection(list(test.keys()))
+
+ def dict_query(test):
+- for key, value in kwargs.items():
++ for key, value in list(kwargs.items()):
+ if test.get(key) == value:
+ return False
+ return True
+ else:
+ def has_tags(test):
+- return tags.issubset(test.keys())
++ return tags.issubset(list(test.keys()))
+
+ def dict_query(test):
+- for key, value in kwargs.items():
++ for key, value in list(kwargs.items()):
+ if test.get(key) != value:
+ return False
+ return True
+@@ -340,7 +340,7 @@
+ """
+ if tests is None:
+ # Make sure to return all the manifests, even ones without tests.
+- return self.manifest_defaults.keys()
++ return list(self.manifest_defaults.keys())
+
+ manifests = []
+ for test in tests:
+@@ -373,8 +373,8 @@
+ raise IOError("Strict mode enabled, test paths must exist. "
+ "The following test(s) are missing: %s" %
+ json.dumps(missing_paths, indent=2))
+- print >> sys.stderr, "Warning: The following test(s) are missing: %s" % \
+- json.dumps(missing_paths, indent=2)
++ print("Warning: The following test(s) are missing: %s" % \
++ json.dumps(missing_paths, indent=2), file=sys.stderr)
+ return missing
+
+ def verifyDirectory(self, directories, pattern=None, extensions=None):
+@@ -385,7 +385,7 @@
+ """
+
+ files = set([])
+- if isinstance(directories, basestring):
++ if isinstance(directories, str):
+ directories = [directories]
+
+ # get files in directories
+@@ -449,12 +449,12 @@
+
+ # print the .ini manifest
+ if global_tags or global_kwargs:
+- print >> fp, '[DEFAULT]'
++ print('[DEFAULT]', file=fp)
+ for tag in global_tags:
+- print >> fp, '%s =' % tag
+- for key, value in global_kwargs.items():
+- print >> fp, '%s = %s' % (key, value)
+- print >> fp
++ print('%s =' % tag, file=fp)
++ for key, value in list(global_kwargs.items()):
++ print('%s = %s' % (key, value), file=fp)
++ print(file=fp)
+
+ for test in tests:
+ test = test.copy() # don't overwrite
+@@ -465,7 +465,7 @@
+ if self.rootdir:
+ path = relpath(test['path'], self.rootdir)
+ path = denormalize_path(path)
+- print >> fp, '[%s]' % path
++ print('[%s]' % path, file=fp)
+
+ # reserved keywords:
+ reserved = ['path', 'name', 'here', 'manifest', 'relpath', 'ancestor-manifest']
+@@ -476,8 +476,8 @@
+ continue
+ if key in global_tags and not test[key]:
+ continue
+- print >> fp, '%s = %s' % (key, test[key])
+- print >> fp
++ print('%s = %s' % (key, test[key]), file=fp)
++ print(file=fp)
+
+ if close:
+ # close the created file
+@@ -565,7 +565,7 @@
+ message = "Missing test: '%s' does not exist!"
+ if self.strict:
+ raise IOError(message)
+- print >> sys.stderr, message + " Skipping."
++ print(message + " Skipping.", file=sys.stderr)
+ continue
+ destination = os.path.join(rootdir, _relpath)
+ shutil.copy(source, destination)
+@@ -578,7 +578,7 @@
+ internal function to import directories
+ """
+
+- if isinstance(pattern, basestring):
++ if isinstance(pattern, str):
+ patterns = [pattern]
+ else:
+ patterns = pattern
+@@ -670,9 +670,9 @@
+ if (dirnames or filenames) and not (os.path.exists(manifest_path) and overwrite):
+ with file(manifest_path, 'w') as manifest:
+ for dirname in dirnames:
+- print >> manifest, '[include:%s]' % os.path.join(dirname, filename)
++ print('[include:%s]' % os.path.join(dirname, filename), file=manifest)
+ for _filename in filenames:
+- print >> manifest, '[%s]' % _filename
++ print('[%s]' % _filename, file=manifest)
+
+ # add to list of manifests
+ manifest_dict.setdefault(directory, manifest_path)
+@@ -722,8 +722,8 @@
+ for filename in filenames]
+
+ # write to manifest
+- print >> write, '\n'.join(['[%s]' % denormalize_path(filename)
+- for filename in filenames])
++ print('\n'.join(['[%s]' % denormalize_path(filename)
++ for filename in filenames]), file=write)
+
+ cls._walk_directories(directories, callback, pattern=pattern, ignore=ignore)
+
+--- firefox-52.9.0esr/testing/mozbase/manifestparser/manifestparser/cli.py (original)
++++ firefox-52.9.0esr/testing/mozbase/manifestparser/manifestparser/cli.py (refactored)
+@@ -81,7 +81,7 @@
+ # parse the arguments
+ try:
+ kwargs, tags, args = parse_args(args)
+- except ParserError, e:
++ except ParserError as e:
+ self._parser.error(e.message)
+
+ # make sure we have some manifests, otherwise it will
+@@ -132,7 +132,7 @@
+ manifest = convert(args, pattern=options.pattern, ignore=options.ignore,
+ write=options.in_place)
+ if manifest:
+- print manifest
++ print(manifest)
+
+
+ class WriteCLI(CLICommand):
+@@ -146,7 +146,7 @@
+ # parse the arguments
+ try:
+ kwargs, tags, args = parse_args(args)
+- except ParserError, e:
++ except ParserError as e:
+ self._parser.error(e.message)
+
+ # make sure we have some manifests, otherwise it will
+@@ -175,9 +175,9 @@
+ commands[args[0]](self._parser).parser().print_help()
+ else:
+ self._parser.print_help()
+- print '\nCommands:'
++ print('\nCommands:')
+ for command in sorted(commands):
+- print ' %s : %s' % (command, commands[command].__doc__.strip())
++ print(' %s : %s' % (command, commands[command].__doc__.strip()))
+
+
+ class UpdateCLI(CLICommand):
+@@ -190,7 +190,7 @@
+ # parse the arguments
+ try:
+ kwargs, tags, args = parse_args(args)
+- except ParserError, e:
++ except ParserError as e:
+ self._parser.error(e.message)
+
+ # make sure we have some manifests, otherwise it will
+--- firefox-52.9.0esr/testing/mozbase/manifestparser/manifestparser/expression.py (original)
++++ firefox-52.9.0esr/testing/mozbase/manifestparser/manifestparser/expression.py (refactored)
+@@ -275,7 +275,7 @@
+ """
+ if not isinstance(self.token, expected):
+ raise Exception("Unexpected token!")
+- self.token = self.iter.next()
++ self.token = next(self.iter)
+
+ def expression(self, rbp=0):
+ """
+@@ -283,11 +283,11 @@
+ right binding power greater than rbp is encountered.
+ """
+ t = self.token
+- self.token = self.iter.next()
++ self.token = next(self.iter)
+ left = t.nud(self)
+ while rbp < self.token.lbp:
+ t = self.token
+- self.token = self.iter.next()
++ self.token = next(self.iter)
+ left = t.led(self, left)
+ return left
+
+@@ -299,7 +299,7 @@
+ """
+ try:
+ self.iter = self._tokenize()
+- self.token = self.iter.next()
++ self.token = next(self.iter)
+ return self.expression()
+ except:
+ extype, ex, tb = sys.exc_info()
+@@ -307,7 +307,7 @@
+ raise ParseError("could not parse: "
+ "%s\nexception: %svariables: %s" % (self.text,
+ formatted,
+- self.valuemapping)), None, tb
++ self.valuemapping)).with_traceback(tb)
+
+ __call__ = parse
+
+--- firefox-52.9.0esr/testing/mozbase/manifestparser/manifestparser/filters.py (original)
++++ firefox-52.9.0esr/testing/mozbase/manifestparser/manifestparser/filters.py (refactored)
+@@ -92,7 +92,7 @@
+ def __init__(self, *args, **kwargs):
+ self.fmt_args = ', '.join(itertools.chain(
+ [str(a) for a in args],
+- ['{}={}'.format(k, v) for k, v in kwargs.iteritems()]))
++ ['{}={}'.format(k, v) for k, v in kwargs.items()]))
+
+ def __eq__(self, other):
+ if self.unique:
+@@ -249,7 +249,7 @@
+ # be yielded for reporting purposes. Put them all in chunk 1 for
+ # simplicity.
+ if self.this_chunk == 1:
+- disabled_dirs = [v for k, v in tests_by_dir.iteritems()
++ disabled_dirs = [v for k, v in tests_by_dir.items()
+ if k not in ordered_dirs]
+ for disabled_test in itertools.chain(*disabled_dirs):
+ yield disabled_test
+@@ -326,7 +326,7 @@
+
+ def __init__(self, tags):
+ InstanceFilter.__init__(self, tags)
+- if isinstance(tags, basestring):
++ if isinstance(tags, str):
+ tags = [tags]
+ self.tags = tags
+
+@@ -349,7 +349,7 @@
+
+ def __init__(self, paths):
+ InstanceFilter.__init__(self, paths)
+- if isinstance(paths, basestring):
++ if isinstance(paths, str):
+ paths = [paths]
+ self.paths = paths
+
+--- firefox-52.9.0esr/testing/mozbase/manifestparser/manifestparser/ini.py (original)
++++ firefox-52.9.0esr/testing/mozbase/manifestparser/manifestparser/ini.py (refactored)
+@@ -27,7 +27,7 @@
+ sections = []
+ key = value = None
+ section_names = set()
+- if isinstance(fp, basestring):
+- fp = file(fp)
++ if isinstance(fp, str):
++ fp = open(fp)
+
+ # read the lines
+@@ -131,7 +131,7 @@
+ 'support-files': '%s %s',
+ }
+ final_mapping = global_vars.copy()
+- for field_name, value in local_vars.items():
++ for field_name, value in list(local_vars.items()):
+ if field_name not in field_patterns or field_name not in global_vars:
+ final_mapping[field_name] = value
+ continue
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/util.py.old 2018-07-10 11:16:10.690000000 +0000
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/util.py 2018-07-10 23:36:02.250000000 +0000
+@@ -1254,10 +1254,10 @@
+ encode(k, encoding): encode(v, encoding)
+ for k, v in obj.items()
+ }
+- if isinstance(obj, bytes):
+- return obj
+ if isinstance(obj, str):
+- return obj.encode(encoding)
++ return obj
++ if isinstance(obj, bytes):
++ return obj.decode(encoding)
+ if isinstance(obj, Iterable):
+ return [encode(i, encoding) for i in obj]
+ return obj
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/util.py.old 2018-07-10 23:36:33.980000000 +0000
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/util.py 2018-07-10 23:41:51.900000000 +0000
+@@ -1179,6 +1179,9 @@
+ POSSIBLE_VALUES = possible_values
+ return EnumStringSubclass
+
++ def __hash__(self):
++ return hash(str(self))
++
+
+ def _escape_char(c):
+ # str.encode('unicode_espace') doesn't escape quotes, presumably because
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/mozinfo.py.old 2018-07-10 23:42:19.390000000 +0000
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/mozinfo.py 2018-07-11 01:45:57.930000000 +0000
+@@ -155,6 +155,6 @@
+ """
+ build_conf = build_dict(config, env)
+ if isinstance(file, str):
+- file = open(file, 'wb')
++ file = open(file, 'w')
+
+ json.dump(build_conf, file, sort_keys=True, indent=4)
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/jar.py.old 2018-07-11 01:46:26.540000000 +0000
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/jar.py 2018-07-11 02:02:36.010000000 +0000
+@@ -16,7 +16,7 @@
+ import re
+ import logging
+ from time import localtime
+-from MozZipFile import ZipFile
++from zipfile import ZipFile
+ from io import StringIO
+ from collections import defaultdict
+
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/util.py.old 2018-07-11 02:05:38.530000000 +0000
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/util.py 2018-07-11 02:08:21.020000000 +0000
+@@ -987,8 +987,6 @@
+ 'got %s, expected %s' % (fname,
+ type(value), ftype))
+
+- super(TypedTuple, self).__init__(*args, **kwargs)
+-
+ TypedTuple._fields = fields
+
+ return TypedTuple
+--- firefox-52.9.0esr/build/moz.configure/init.configure.old 2018-07-11 02:08:50.000000000 +0000
++++ firefox-52.9.0esr/build/moz.configure/init.configure 2018-07-11 04:04:26.600000000 +0000
+@@ -297,7 +297,9 @@
+ # There is also a quartet form:
+ # CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
+ # But we can consider the "KERNEL-OPERATING_SYSTEM" as one.
+- cpu, manufacturer, os = triplet.decode('utf-8').split('-', 2)
++ if isinstance(triplet, bytes):
++ triplet = triplet.decode('utf-8')
++ cpu, manufacturer, os = triplet.split('-', 2)
+
+ # Autoconf uses config.sub to validate and canonicalize those triplets,
+ # but the granularity of its results has never been satisfying to our
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/frontend/reader.py.old 2018-07-11 04:25:33.980000000 +0000
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/frontend/reader.py 2018-07-11 04:24:50.630000000 +0000
+@@ -441,6 +441,8 @@
+ code = func.__code__
+ firstlineno = code.co_firstlineno
+ lines = sandbox._current_source.splitlines(True)
++ if len(lines) and isinstance(lines[0], bytes):
++ lines = [l.decode('utf-8') for l in lines]
+ lines = inspect.getblock(lines[firstlineno - 1:])
+
+ # The code lines we get out of inspect.getsourcelines look like
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/frontend/reader.py.old 2018-07-11 04:25:57.090000000 +0000
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/frontend/reader.py 2018-07-11 04:29:46.140000000 +0000
+@@ -460,7 +460,7 @@
+ # actually never calls __getitem__ and __setitem__, so we need to
+ # modify the AST so that accesses to globals are properly directed
+ # to a dict.
+- self._global_name = b'_data' # AST wants str for this, not unicode
++ self._global_name = '_data' # AST wants str for this, not unicode
+ # In case '_data' is a name used for a variable in the function code,
+ # prepend more underscores until we find an unused name.
+ while (self._global_name in code.co_names or
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/frontend/context.py.old 2018-07-11 04:30:06.590000000 +0000
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/frontend/context.py 2018-07-11 04:35:38.670000000 +0000
+@@ -384,8 +384,8 @@
+
+ def __cmp__(self, other):
+ if isinstance(other, Path) and self.srcdir != other.srcdir:
+- return cmp(self.full_path, other.full_path)
+- return cmp(str(self), other)
++ return self.full_path == other.full_path
++ return str(self) == other
+
+ # __cmp__ is not enough because unicode has __eq__, __ne__, etc. defined
+ # and __cmp__ is only used for those when they don't exist.
+--- firefox-52.9.0esr/mozglue/build/moz.build.old 2018-07-11 04:40:17.930000000 +0000
++++ firefox-52.9.0esr/mozglue/build/moz.build 2018-07-11 04:42:00.830000000 +0000
+@@ -4,20 +4,15 @@
+ # License, v. 2.0. If a copy of the MPL was not distributed with this
+ # file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+-# Build mozglue as a shared lib on Windows, OSX and Android.
++# Build mozglue as a shared lib on Windows and OSX.
+ # If this is ever changed, update MOZ_SHARED_MOZGLUE in browser/installer/Makefile.in
+-if CONFIG['OS_TARGET'] in ('WINNT', 'Darwin', 'Android'):
++if CONFIG['OS_TARGET'] in ('WINNT', 'Darwin'):
+ SharedLibrary('mozglue')
+ else:
+ Library('mozglue')
+
+ SDK_LIBRARY = True
+
+-if CONFIG['OS_TARGET'] == 'Android':
+- SOURCES += [
+- 'BionicGlue.cpp',
+- ]
+-
+ if CONFIG['MOZ_ASAN']:
+ SOURCES += [
+ 'AsanOptions.cpp',
+--- firefox-52.9.0esr/js/src/moz.build.old 2017-04-11 02:13:16.000000000 +0000
++++ firefox-52.9.0esr/js/src/moz.build 2018-07-11 04:43:59.920000000 +0000
+@@ -707,7 +707,7 @@
+ CXXFLAGS += ['-wd4577']
+ CXXFLAGS += ['-wd4312']
+
+-if CONFIG['OS_ARCH'] not in ('WINNT', 'HP-UX'):
++if CONFIG['OS_ARCH'] != 'WINNT':
+ OS_LIBS += [
+ 'm',
+ ]
+@@ -722,13 +722,13 @@
+ 'dl',
+ ]
+
+-if CONFIG['OS_ARCH'] == 'SunOS':
+- OS_LIBS += [
+- 'posix4',
+- 'dl',
+- 'nsl',
+- 'socket',
+- ]
++#if CONFIG['OS_ARCH'] == 'SunOS':
++# OS_LIBS += [
++# 'posix4',
++# 'dl',
++# 'nsl',
++# 'socket',
++# ]
+
+ OS_LIBS += CONFIG['REALTIME_LIBS']
+
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/util.py.old 2018-07-11 04:44:24.900000000 +0000
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/util.py 2018-07-11 04:46:47.310000000 +0000
+@@ -267,6 +267,10 @@
+ if 'b' in self.mode:
+ writemode += 'b'
+ with open(self.name, writemode) as file:
++ if 'b' in self.mode and isinstance(buf, str):
++ buf = buf.encode('utf-8')
++ elif 'b' not in self.mode and isinstance(buf, bytes):
++ buf = buf.decode('utf-8')
+ file.write(buf)
+
+ if self._capture_diff:
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/backend/recursivemake.py.old 2018-07-11 04:47:15.020000000 +0000
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/backend/recursivemake.py 2018-07-11 04:53:51.750000000 +0000
+@@ -77,86 +77,86 @@
+ from functools import reduce
+
+ MOZBUILD_VARIABLES = [
+- b'ANDROID_APK_NAME',
+- b'ANDROID_APK_PACKAGE',
+- b'ANDROID_ASSETS_DIRS',
+- b'ANDROID_EXTRA_PACKAGES',
+- b'ANDROID_EXTRA_RES_DIRS',
+- b'ANDROID_GENERATED_RESFILES',
+- b'ANDROID_RES_DIRS',
+- b'ASFLAGS',
+- b'CMSRCS',
+- b'CMMSRCS',
+- b'CPP_UNIT_TESTS',
+- b'DIRS',
+- b'DIST_INSTALL',
+- b'EXTRA_DSO_LDOPTS',
+- b'EXTRA_JS_MODULES',
+- b'EXTRA_PP_COMPONENTS',
+- b'EXTRA_PP_JS_MODULES',
+- b'FORCE_SHARED_LIB',
+- b'FORCE_STATIC_LIB',
+- b'FINAL_LIBRARY',
+- b'HOST_CFLAGS',
+- b'HOST_CSRCS',
+- b'HOST_CMMSRCS',
+- b'HOST_CXXFLAGS',
+- b'HOST_EXTRA_LIBS',
+- b'HOST_LIBRARY_NAME',
+- b'HOST_PROGRAM',
+- b'HOST_SIMPLE_PROGRAMS',
+- b'IS_COMPONENT',
+- b'JAR_MANIFEST',
+- b'JAVA_JAR_TARGETS',
+- b'LD_VERSION_SCRIPT',
+- b'LIBRARY_NAME',
+- b'LIBS',
+- b'MAKE_FRAMEWORK',
+- b'MODULE',
+- b'NO_DIST_INSTALL',
+- b'NO_EXPAND_LIBS',
+- b'NO_INTERFACES_MANIFEST',
+- b'NO_JS_MANIFEST',
+- b'OS_LIBS',
+- b'PARALLEL_DIRS',
+- b'PREF_JS_EXPORTS',
+- b'PROGRAM',
+- b'PYTHON_UNIT_TESTS',
+- b'RESOURCE_FILES',
+- b'SDK_HEADERS',
+- b'SDK_LIBRARY',
+- b'SHARED_LIBRARY_LIBS',
+- b'SHARED_LIBRARY_NAME',
+- b'SIMPLE_PROGRAMS',
+- b'SONAME',
+- b'STATIC_LIBRARY_NAME',
+- b'TEST_DIRS',
+- b'TOOL_DIRS',
++ 'ANDROID_APK_NAME',
++ 'ANDROID_APK_PACKAGE',
++ 'ANDROID_ASSETS_DIRS',
++ 'ANDROID_EXTRA_PACKAGES',
++ 'ANDROID_EXTRA_RES_DIRS',
++ 'ANDROID_GENERATED_RESFILES',
++ 'ANDROID_RES_DIRS',
++ 'ASFLAGS',
++ 'CMSRCS',
++ 'CMMSRCS',
++ 'CPP_UNIT_TESTS',
++ 'DIRS',
++ 'DIST_INSTALL',
++ 'EXTRA_DSO_LDOPTS',
++ 'EXTRA_JS_MODULES',
++ 'EXTRA_PP_COMPONENTS',
++ 'EXTRA_PP_JS_MODULES',
++ 'FORCE_SHARED_LIB',
++ 'FORCE_STATIC_LIB',
++ 'FINAL_LIBRARY',
++ 'HOST_CFLAGS',
++ 'HOST_CSRCS',
++ 'HOST_CMMSRCS',
++ 'HOST_CXXFLAGS',
++ 'HOST_EXTRA_LIBS',
++ 'HOST_LIBRARY_NAME',
++ 'HOST_PROGRAM',
++ 'HOST_SIMPLE_PROGRAMS',
++ 'IS_COMPONENT',
++ 'JAR_MANIFEST',
++ 'JAVA_JAR_TARGETS',
++ 'LD_VERSION_SCRIPT',
++ 'LIBRARY_NAME',
++ 'LIBS',
++ 'MAKE_FRAMEWORK',
++ 'MODULE',
++ 'NO_DIST_INSTALL',
++ 'NO_EXPAND_LIBS',
++ 'NO_INTERFACES_MANIFEST',
++ 'NO_JS_MANIFEST',
++ 'OS_LIBS',
++ 'PARALLEL_DIRS',
++ 'PREF_JS_EXPORTS',
++ 'PROGRAM',
++ 'PYTHON_UNIT_TESTS',
++ 'RESOURCE_FILES',
++ 'SDK_HEADERS',
++ 'SDK_LIBRARY',
++ 'SHARED_LIBRARY_LIBS',
++ 'SHARED_LIBRARY_NAME',
++ 'SIMPLE_PROGRAMS',
++ 'SONAME',
++ 'STATIC_LIBRARY_NAME',
++ 'TEST_DIRS',
++ 'TOOL_DIRS',
+ # XXX config/Makefile.in specifies this in a make invocation
+ #'USE_EXTENSION_MANIFEST',
+- b'XPCSHELL_TESTS',
+- b'XPIDL_MODULE',
++ 'XPCSHELL_TESTS',
++ 'XPIDL_MODULE',
+ ]
+
+ DEPRECATED_VARIABLES = [
+- b'ANDROID_RESFILES',
+- b'EXPORT_LIBRARY',
+- b'EXTRA_LIBS',
+- b'HOST_LIBS',
+- b'LIBXUL_LIBRARY',
+- b'MOCHITEST_A11Y_FILES',
+- b'MOCHITEST_BROWSER_FILES',
+- b'MOCHITEST_BROWSER_FILES_PARTS',
+- b'MOCHITEST_CHROME_FILES',
+- b'MOCHITEST_FILES',
+- b'MOCHITEST_FILES_PARTS',
+- b'MOCHITEST_METRO_FILES',
+- b'MOCHITEST_ROBOCOP_FILES',
+- b'MODULE_OPTIMIZE_FLAGS',
+- b'MOZ_CHROME_FILE_FORMAT',
+- b'SHORT_LIBNAME',
+- b'TESTING_JS_MODULES',
+- b'TESTING_JS_MODULE_DIR',
++ 'ANDROID_RESFILES',
++ 'EXPORT_LIBRARY',
++ 'EXTRA_LIBS',
++ 'HOST_LIBS',
++ 'LIBXUL_LIBRARY',
++ 'MOCHITEST_A11Y_FILES',
++ 'MOCHITEST_BROWSER_FILES',
++ 'MOCHITEST_BROWSER_FILES_PARTS',
++ 'MOCHITEST_CHROME_FILES',
++ 'MOCHITEST_FILES',
++ 'MOCHITEST_FILES_PARTS',
++ 'MOCHITEST_METRO_FILES',
++ 'MOCHITEST_ROBOCOP_FILES',
++ 'MODULE_OPTIMIZE_FLAGS',
++ 'MOZ_CHROME_FILE_FORMAT',
++ 'SHORT_LIBNAME',
++ 'TESTING_JS_MODULES',
++ 'TESTING_JS_MODULE_DIR',
+ ]
+
+ MOZBUILD_VARIABLES_MESSAGE = 'It should only be defined in moz.build files.'
+@@ -758,7 +758,7 @@
+ rule.add_dependencies(['$(CURDIR)/%: %'])
+
+ def _check_blacklisted_variables(self, makefile_in, makefile_content):
+- if b'EXTERNALLY_MANAGED_MAKE_FILE' in makefile_content:
++ if 'EXTERNALLY_MANAGED_MAKE_FILE' in makefile_content:
+ # Bypass the variable restrictions for externally managed makefiles.
+ return
+
+@@ -765,7 +765,7 @@
+ for l in makefile_content.splitlines():
+ l = l.strip()
+ # Don't check comments
+- if l.startswith(b'#'):
++ if l.startswith('#'):
+ continue
+ for x in chain(MOZBUILD_VARIABLES, DEPRECATED_VARIABLES):
+ if x not in l:
+@@ -822,11 +822,11 @@
+ # Skip every directory but those with a Makefile
+ # containing a tools target, or XPI_PKGNAME or
+ # INSTALL_EXTENSION_ID.
+- for t in (b'XPI_PKGNAME', b'INSTALL_EXTENSION_ID',
+- b'tools'):
++ for t in ('XPI_PKGNAME', 'INSTALL_EXTENSION_ID',
++ 'tools'):
+ if t not in content:
+ continue
+- if t == b'tools' and not re.search('(?:^|\s)tools.*::', content, re.M):
++ if t == 'tools' and not re.search('(?:^|\s)tools.*::', content, re.M):
+ continue
+ if objdir == self.environment.topobjdir:
+ continue
+@@ -1422,20 +1422,20 @@
+ pp.context.update(extra)
+ if not pp.context.get('autoconfmk', ''):
+ pp.context['autoconfmk'] = 'autoconf.mk'
+- pp.handleLine(b'# THIS FILE WAS AUTOMATICALLY GENERATED. DO NOT MODIFY BY HAND.\n');
+- pp.handleLine(b'DEPTH := @DEPTH@\n')
+- pp.handleLine(b'topobjdir := @topobjdir@\n')
+- pp.handleLine(b'topsrcdir := @top_srcdir@\n')
+- pp.handleLine(b'srcdir := @srcdir@\n')
+- pp.handleLine(b'VPATH := @srcdir@\n')
+- pp.handleLine(b'relativesrcdir := @relativesrcdir@\n')
+- pp.handleLine(b'include $(DEPTH)/config/@autoconfmk@\n')
++ pp.handleLine('# THIS FILE WAS AUTOMATICALLY GENERATED. DO NOT MODIFY BY HAND.\n');
++ pp.handleLine('DEPTH := @DEPTH@\n')
++ pp.handleLine('topobjdir := @topobjdir@\n')
++ pp.handleLine('topsrcdir := @top_srcdir@\n')
++ pp.handleLine('srcdir := @srcdir@\n')
++ pp.handleLine('VPATH := @srcdir@\n')
++ pp.handleLine('relativesrcdir := @relativesrcdir@\n')
++ pp.handleLine('include $(DEPTH)/config/@autoconfmk@\n')
+ if not stub:
+ pp.do_include(obj.input_path)
+ # Empty line to avoid failures when last line in Makefile.in ends
+ # with a backslash.
+- pp.handleLine(b'\n')
+- pp.handleLine(b'include $(topsrcdir)/config/recurse.mk\n')
++ pp.handleLine('\n')
++ pp.handleLine('include $(topsrcdir)/config/recurse.mk\n')
+ if not stub:
+ # Adding the Makefile.in here has the desired side-effect
+ # that if the Makefile.in disappears, this will force
+--- firefox-52.9.0esr/python/mozbuild/mozpack/manifests.py.old 2018-07-11 04:54:39.260000000 +0000
++++ firefox-52.9.0esr/python/mozbuild/mozpack/manifests.py 2018-07-11 04:57:31.710000000 +0000
+@@ -115,7 +115,7 @@
+ self._source_files = set()
+
+ if path or fileobj:
+- with _auto_fileobj(path, fileobj, 'rb') as fh:
++ with _auto_fileobj(path, fileobj, 'r') as fh:
+ self._source_files.add(fh.name)
+ self._load_from_fileobj(fh)
+
+@@ -174,7 +174,7 @@
+ dest, content = fields[1:]
+
+ self.add_content(
+- self._decode_field_entry(content).encode('utf-8'), dest)
++ self._decode_field_entry(content), dest)
+ continue
+
+ # Don't fail for non-actionable items, allowing
+@@ -236,7 +236,7 @@
+
+ It is an error if both are specified.
+ """
+- with _auto_fileobj(path, fileobj, 'wb') as fh:
++ with _auto_fileobj(path, fileobj, 'w') as fh:
+ fh.write('%d\n' % self.CURRENT_VERSION)
+
+ for dest in sorted(self._dests):
+@@ -244,8 +244,7 @@
+
+ parts = ['%d' % entry[0], dest]
+ parts.extend(entry[1:])
+- fh.write('%s\n' % self.FIELD_SEPARATOR.join(
+- p.encode('utf-8') for p in parts))
++ fh.write('%s\n' % self.FIELD_SEPARATOR.join(parts))
+
+ def add_symlink(self, source, dest):
+ """Add a symlink to this manifest.
+@@ -391,7 +390,7 @@
+ if install_type == self.CONTENT:
+ # GeneratedFile expect the buffer interface, which the unicode
+ # type doesn't have, so encode to a str.
+- content = self._decode_field_entry(entry[1]).encode('utf-8')
++ content = self._decode_field_entry(entry[1])
+ registry.add(dest, GeneratedFile(content))
+ continue
+
+--- firefox-52.9.0esr/config/MozZipFile.py (original)
++++ firefox-52.9.0esr/config/MozZipFile.py (refactored)
+@@ -18,7 +18,7 @@
+ def __init__(self, file, mode="r", compression=zipfile.ZIP_STORED,
+ lock = False):
+ if lock:
+- assert isinstance(file, basestring)
++ assert isinstance(file, str)
+ self.lockfile = lock_file(file + '.lck')
+ else:
+ self.lockfile = None
+@@ -46,7 +46,7 @@
+ date_time=time.localtime(time.time()))
+ zinfo.compress_type = self.compression
+ # Add some standard UNIX file access permissions (-rw-r--r--).
+- zinfo.external_attr = (0x81a4 & 0xFFFF) << 16L
++ zinfo.external_attr = (0x81a4 & 0xFFFF) << 16
+ else:
+ zinfo = zinfo_or_arcname
+
+@@ -58,7 +58,7 @@
+ # as the old, reuse the existing entry.
+
+ doSeek = False # store if we need to seek to the eof after overwriting
+- if self.NameToInfo.has_key(zinfo.filename):
++ if zinfo.filename in self.NameToInfo:
+ # Find the last ZipInfo with our name.
+ # Last, because that's catching multiple overwrites
+ i = len(self.filelist)
+@@ -109,14 +109,14 @@
+ # adjust file mode if we originally just wrote, now we rewrite
+ self.fp.close()
+ self.fp = open(self.filename, 'r+b')
+- all = map(lambda zi: (zi, True), self.filelist) + \
+- map(lambda zi: (zi, False), self._remove)
++ all = [(zi, True) for zi in self.filelist] + \
++ [(zi, False) for zi in self._remove]
+ all.sort(lambda l, r: cmp(l[0].header_offset, r[0].header_offset))
+ # empty _remove for multiple closes
+ self._remove = []
+
+ lengths = [all[i+1][0].header_offset - all[i][0].header_offset
+- for i in xrange(len(all)-1)]
++ for i in range(len(all)-1)]
+ lengths.append(self.end - all[-1][0].header_offset)
+ to_pos = 0
+ for (zi, keep), length in zip(all, lengths):
+--- firefox-52.9.0esr/config/check_spidermonkey_style.py (original)
++++ firefox-52.9.0esr/config/check_spidermonkey_style.py (refactored)
+@@ -35,7 +35,7 @@
+ # isolation, but don't try to do any order checking between such blocks.
+ #----------------------------------------------------------------------------
+
+-from __future__ import print_function
++
+
+ import difflib
+ import os
+@@ -270,7 +270,7 @@
+ edges[inclname] = set()
+
+ # Process all the JS files.
+- for filename in js_names.keys():
++ for filename in list(js_names.keys()):
+ inclname = js_names[filename]
+ file_kind = FileKind.get(filename)
+ if file_kind == FileKind.C or file_kind == FileKind.CPP or \
+--- firefox-52.9.0esr/config/expandlibs.py (original)
++++ firefox-52.9.0esr/config/expandlibs.py (refactored)
+@@ -26,7 +26,7 @@
+ descriptor contains. And for each of these LIBS, also apply the same
+ rules.
+ '''
+-from __future__ import with_statement
++
+ import sys, os, errno
+ import expandlibs_config as conf
+
+@@ -36,7 +36,7 @@
+ if dir and not os.path.exists(dir):
+ try:
+ os.makedirs(dir)
+- except OSError, error:
++ except OSError as error:
+ if error.errno != errno.EEXIST:
+ raise
+
+@@ -140,4 +140,4 @@
+ return [relativize(arg)]
+
+ if __name__ == '__main__':
+- print " ".join(ExpandArgs(sys.argv[1:]))
++ print(" ".join(ExpandArgs(sys.argv[1:])))
+--- firefox-52.9.0esr/config/expandlibs_exec.py (original)
++++ firefox-52.9.0esr/config/expandlibs_exec.py (refactored)
+@@ -20,7 +20,7 @@
+ relevant linker options to change the order in which the linker puts the
+ symbols appear in the resulting binary. Only works for ELF targets.
+ '''
+-from __future__ import with_statement
++
+ import sys
+ import os
+ from expandlibs import (
+@@ -304,11 +304,11 @@
+ return syms
+
+ def print_command(out, args):
+- print >>out, "Executing: " + " ".join(args)
++ print("Executing: " + " ".join(args), file=out)
+ for tmp in [f for f in args.tmp if os.path.isfile(f)]:
+- print >>out, tmp + ":"
++ print(tmp + ":", file=out)
+ with open(tmp) as file:
+- print >>out, "".join([" " + l for l in file.readlines()])
++ print("".join([" " + l for l in file.readlines()]), file=out)
+ out.flush()
+
+ def main(args, proc_callback=None):
+@@ -338,8 +338,8 @@
+ proc = subprocess.Popen(args, stdout = subprocess.PIPE, stderr = subprocess.STDOUT)
+ if proc_callback:
+ proc_callback(proc)
+- except Exception, e:
+- print >>sys.stderr, 'error: Launching', args, ':', e
++ except Exception as e:
++ print('error: Launching', args, ':', e, file=sys.stderr)
+ raise e
+ (stdout, stderr) = proc.communicate()
+ if proc.returncode and not options.verbose:
+--- firefox-52.9.0esr/config/expandlibs_gen.py (original)
++++ firefox-52.9.0esr/config/expandlibs_gen.py (refactored)
+@@ -5,7 +5,7 @@
+ '''Given a list of object files and library names, prints a library
+ descriptor to standard output'''
+
+-from __future__ import with_statement
++
+ import sys
+ import os
+ import expandlibs_config as conf
+@@ -38,4 +38,4 @@
+
+ ensureParentDir(options.output)
+ with open(options.output, 'w') as outfile:
+- print >>outfile, generate(args)
++ print(generate(args), file=outfile)
+--- firefox-52.9.0esr/config/find_OOM_errors.py (original)
++++ firefox-52.9.0esr/config/find_OOM_errors.py (refactored)
+@@ -2,7 +2,7 @@
+ # This Source Code Form is subject to the terms of the Mozilla Public
+ # License, v. 2.0. If a copy of the MPL was not distributed with this
+ # file, You can obtain one at http://mozilla.org/MPL/2.0/.
+-from __future__ import print_function
++
+
+ usage = """%prog: A test for OOM conditions in the shell.
+
+@@ -95,12 +95,12 @@
+ """Keep track of the amount of times individual lines occur, in order to
+ prioritize the errors which occur most frequently."""
+ counts = {}
+- for string,count in blacklist.items():
++ for string,count in list(blacklist.items()):
+ for line in string.split("\n"):
+ counts[line] = counts.get(line, 0) + count
+
+ lines = []
+- for k,v in counts.items():
++ for k,v in list(counts.items()):
+ lines.append("{0:6}: {1}".format(v, k))
+
+ lines.sort()
+--- firefox-52.9.0esr/config/link.py (original)
++++ firefox-52.9.0esr/config/link.py (refactored)
+@@ -18,7 +18,7 @@
+ time.sleep(0.5)
+ idleTime += 0.5
+ if idleTime > 20 * 60:
+- print "Still linking, 20 minutes passed..."
++ print("Still linking, 20 minutes passed...")
+ sys.stdout.flush()
+ idleTime = 0
+
+@@ -42,6 +42,6 @@
+
+ if __name__ == "__main__":
+ if len(sys.argv) < 2:
+- print >>sys.stderr, "Usage: link.py <commandline>"
++ print("Usage: link.py <commandline>", file=sys.stderr)
+ sys.exit(1)
+ sys.exit(wrap_linker(sys.argv[1:]))
+--- firefox-52.9.0esr/config/mozunit.py (original)
++++ firefox-52.9.0esr/config/mozunit.py (refactored)
+@@ -140,7 +140,7 @@
+ '''
+ def __init__(self, files = {}):
+ self.files = {}
+- for name, content in files.iteritems():
++ for name, content in files.items():
+ self.files[normcase(os.path.abspath(name))] = content
+
+ def __call__(self, name, mode = 'r'):
+@@ -158,19 +158,19 @@
+ return file
+
+ def __enter__(self):
+- import __builtin__
+- self.open = __builtin__.open
++ import builtins
++ self.open = builtins.open
+ self._orig_path_exists = os.path.exists
+ self._orig_path_isdir = os.path.isdir
+ self._orig_path_isfile = os.path.isfile
+- __builtin__.open = self
++ builtins.open = self
+ os.path.exists = self._wrapped_exists
+ os.path.isdir = self._wrapped_isdir
+ os.path.isfile = self._wrapped_isfile
+
+ def __exit__(self, type, value, traceback):
+- import __builtin__
+- __builtin__.open = self.open
++ import builtins
++ builtins.open = self.open
+ os.path.exists = self._orig_path_exists
+ os.path.isdir = self._orig_path_isdir
+ os.path.isfile = self._orig_path_isfile
+--- firefox-52.9.0esr/config/nsinstall.py (original)
++++ firefox-52.9.0esr/config/nsinstall.py (refactored)
+@@ -9,7 +9,7 @@
+ # a full build environment set up.
+ # The basic limitation is, it doesn't even try to link and ignores
+ # all related options.
+-from __future__ import print_function
++
+ from optparse import OptionParser
+ import mozfile
+ import os
+@@ -149,7 +149,7 @@
+
+ # nsinstall as a native command is always UTF-8
+ def nsinstall(argv):
+- return _nsinstall_internal([unicode(arg, "utf-8") for arg in argv])
++ return _nsinstall_internal([str(arg, "utf-8") for arg in argv])
+
+ if __name__ == '__main__':
+ # sys.argv corrupts characters outside the system code page on Windows
+@@ -175,8 +175,8 @@
+ else:
+ # For consistency, do it on Unix as well
+ if sys.stdin.encoding is not None:
+- argv = [unicode(arg, sys.stdin.encoding) for arg in sys.argv]
++ argv = [str(arg, sys.stdin.encoding) for arg in sys.argv]
+ else:
+- argv = [unicode(arg) for arg in sys.argv]
++ argv = [str(arg) for arg in sys.argv]
+
+ sys.exit(_nsinstall_internal(argv[1:]))
+--- firefox-52.9.0esr/config/printconfigsetting.py (original)
++++ firefox-52.9.0esr/config/printconfigsetting.py (refactored)
+@@ -5,12 +5,12 @@
+ import configobj
+ import sys
+ import re
+-from StringIO import StringIO
++from io import StringIO
+
+ try:
+ (file, section, key) = sys.argv[1:]
+ except ValueError:
+- print "Usage: printconfigsetting.py <file> <section> <setting>"
++ print("Usage: printconfigsetting.py <file> <section> <setting>")
+ sys.exit(1)
+
+ with open(file) as fh:
+@@ -21,11 +21,11 @@
+ try:
+ s = c[section]
+ except KeyError:
+- print >>sys.stderr, "Section [%s] not found." % section
++ print("Section [%s] not found." % section, file=sys.stderr)
+ sys.exit(1)
+
+ try:
+- print s[key]
++ print(s[key])
+ except KeyError:
+- print >>sys.stderr, "Key %s not found." % key
++ print("Key %s not found." % key, file=sys.stderr)
+ sys.exit(1)
+--- firefox-52.9.0esr/config/pythonpath.py (original)
++++ firefox-52.9.0esr/config/pythonpath.py (refactored)
+@@ -9,7 +9,7 @@
+
+ def main(args):
+ def usage():
+- print >>sys.stderr, "pythonpath.py -I directory script.py [args...]"
++ print("pythonpath.py -I directory script.py [args...]", file=sys.stderr)
+ sys.exit(150)
+
+ paths = []
+@@ -45,7 +45,7 @@
+ frozenglobals['__name__'] = '__main__'
+ frozenglobals['__file__'] = script
+
+- execfile(script, frozenglobals)
++ exec(compile(open(script).read(), script, 'exec'), frozenglobals)
+
+ # Freeze scope here ... why this makes things work I have no idea ...
+ frozenglobals = globals()
+--- firefox-52.9.0esr/config/rebuild_check.py (original)
++++ firefox-52.9.0esr/config/rebuild_check.py (refactored)
+@@ -18,7 +18,7 @@
+ deps = args[1:]
+ t = mtime(target)
+ if t < 0:
+- print target
++ print(target)
+ return
+
+ newer = []
+@@ -31,13 +31,13 @@
+ newer.append(dep)
+
+ if newer and removed:
+- print 'Rebuilding %s because %s changed and %s was removed' % (target, ', '.join(newer), ', '.join(removed))
++ print('Rebuilding %s because %s changed and %s was removed' % (target, ', '.join(newer), ', '.join(removed)))
+ elif newer:
+- print 'Rebuilding %s because %s changed' % (target, ', '.join(newer))
++ print('Rebuilding %s because %s changed' % (target, ', '.join(newer)))
+ elif removed:
+- print 'Rebuilding %s because %s was removed' % (target, ', '.join(removed))
++ print('Rebuilding %s because %s was removed' % (target, ', '.join(removed)))
+ else:
+- print 'Rebuilding %s for an unknown reason' % target
++ print('Rebuilding %s for an unknown reason' % target)
+
+ if __name__ == '__main__':
+ import sys
+--- firefox-52.9.0esr/config/tests/unit-expandlibs.py (original)
++++ firefox-52.9.0esr/config/tests/unit-expandlibs.py (refactored)
+@@ -7,7 +7,7 @@
+ from shutil import rmtree
+ import mozunit
+
+-from UserString import UserString
++from collections import UserString
+ # Create a controlled configuration for use by expandlibs
+ config_win = {
+ 'AR': 'lib',
+@@ -120,8 +120,7 @@
+ del dict[name]
+ return type.__new__(cls, clsName, bases, dict)
+
+-class TestCaseWithTmpDir(unittest.TestCase):
+- __metaclass__ = ReplicateTests
++class TestCaseWithTmpDir(unittest.TestCase, metaclass=ReplicateTests):
+ def init(self):
+ self.tmpdir = os.path.abspath(mkdtemp(dir=os.curdir))
+
+--- firefox-52.9.0esr/config/tests/unit-nsinstall.py (original)
++++ firefox-52.9.0esr/config/tests/unit-nsinstall.py (refactored)
+@@ -28,9 +28,9 @@
+ # Unicode strings means non-ASCII children can be deleted properly on
+ # Windows
+ if sys.stdin.encoding is None:
+- tmpdir = unicode(self.tmpdir)
++ tmpdir = str(self.tmpdir)
+ else:
+- tmpdir = unicode(self.tmpdir, sys.stdin.encoding)
++ tmpdir = str(self.tmpdir, sys.stdin.encoding)
+ rmtree(tmpdir)
+
+ # utility methods for tests
+@@ -50,14 +50,14 @@
+ "Test nsinstall -D <dir>"
+ testdir = os.path.join(self.tmpdir, "test")
+ self.assertEqual(nsinstall(["-D", testdir]), 0)
+- self.assert_(os.path.isdir(testdir))
++ self.assertTrue(os.path.isdir(testdir))
+
+ def test_nsinstall_basic(self):
+ "Test nsinstall <file> <dir>"
+ testfile = self.touch("testfile")
+ testdir = self.mkdirs("testdir")
+ self.assertEqual(nsinstall([testfile, testdir]), 0)
+- self.assert_(os.path.isfile(os.path.join(testdir, "testfile")))
++ self.assertTrue(os.path.isfile(os.path.join(testdir, "testfile")))
+
+ def test_nsinstall_basic_recursive(self):
+ "Test nsinstall <dir> <dest dir>"
+@@ -76,12 +76,12 @@
+ '-X', Xdir]), 0)
+
+ testdir = os.path.join(destdir, "sourcedir")
+- self.assert_(os.path.isdir(testdir))
+- self.assert_(os.path.isfile(os.path.join(testdir, "testfile")))
+- self.assert_(not os.path.exists(os.path.join(testdir, "Xfile")))
+- self.assert_(os.path.isdir(os.path.join(testdir, "copieddir")))
+- self.assert_(os.path.isfile(os.path.join(testdir, "copieddir", "testfile2")))
+- self.assert_(not os.path.exists(os.path.join(testdir, "Xdir")))
++ self.assertTrue(os.path.isdir(testdir))
++ self.assertTrue(os.path.isfile(os.path.join(testdir, "testfile")))
++ self.assertTrue(not os.path.exists(os.path.join(testdir, "Xfile")))
++ self.assertTrue(os.path.isdir(os.path.join(testdir, "copieddir")))
++ self.assertTrue(os.path.isfile(os.path.join(testdir, "copieddir", "testfile2")))
++ self.assertTrue(not os.path.exists(os.path.join(testdir, "Xdir")))
+
+ def test_nsinstall_multiple(self):
+ "Test nsinstall <three files> <dest dir>"
+@@ -91,7 +91,7 @@
+ testdir = self.mkdirs("testdir")
+ self.assertEqual(nsinstall(testfiles + [testdir]), 0)
+ for f in testfiles:
+- self.assert_(os.path.isfile(os.path.join(testdir,
++ self.assertTrue(os.path.isfile(os.path.join(testdir,
+ os.path.basename(f))))
+
+ def test_nsinstall_dir_exists(self):
+@@ -99,7 +99,7 @@
+ srcdir = self.mkdirs("test")
+ destdir = self.mkdirs("testdir/test")
+ self.assertEqual(nsinstall([srcdir, os.path.dirname(destdir)]), 0)
+- self.assert_(os.path.isdir(destdir))
++ self.assertTrue(os.path.isdir(destdir))
+
+ def test_nsinstall_t(self):
+ "Test that nsinstall -t works (preserve timestamp)"
+@@ -110,7 +110,7 @@
+ os.utime(testfile, (t, t))
+ self.assertEqual(nsinstall(["-t", testfile, testdir]), 0)
+ destfile = os.path.join(testdir, "testfile")
+- self.assert_(os.path.isfile(destfile))
++ self.assertTrue(os.path.isfile(destfile))
+ self.assertEqual(os.stat(testfile).st_mtime,
+ os.stat(destfile).st_mtime)
+
+@@ -125,7 +125,7 @@
+ self.assertEqual(nsinstall(["-m", "{0:04o}"
+ .format(mode), testfile, testdir]), 0)
+ destfile = os.path.join(testdir, "testfile")
+- self.assert_(os.path.isfile(destfile))
++ self.assertTrue(os.path.isfile(destfile))
+ self.assertEqual(os.stat(testfile).st_mode,
+ os.stat(destfile).st_mode)
+
+@@ -136,25 +136,25 @@
+ testdir = self.mkdirs("testdir")
+ destdir = os.path.join(testdir, "subdir")
+ self.assertEqual(nsinstall(["-d", testfile, destdir]), 0)
+- self.assert_(os.path.isdir(os.path.join(destdir, "testfile")))
++ self.assertTrue(os.path.isdir(os.path.join(destdir, "testfile")))
+
+ if RUN_NON_ASCII_TESTS:
+ def test_nsinstall_non_ascii(self):
+ "Test that nsinstall handles non-ASCII files"
+- filename = u"\u2325\u3452\u2415\u5081"
++ filename = "\u2325\u3452\u2415\u5081"
+ testfile = self.touch(filename)
+- testdir = self.mkdirs(u"\u4241\u1D04\u1414")
++ testdir = self.mkdirs("\u4241\u1D04\u1414")
+ self.assertEqual(nsinstall([testfile.encode("utf-8"),
+ testdir.encode("utf-8")]), 0)
+
+ destfile = os.path.join(testdir, filename)
+- self.assert_(os.path.isfile(destfile))
++ self.assertTrue(os.path.isfile(destfile))
+
+ def test_nsinstall_non_ascii_subprocess(self):
+ "Test that nsinstall as a subprocess handles non-ASCII files"
+- filename = u"\u2325\u3452\u2415\u5081"
++ filename = "\u2325\u3452\u2415\u5081"
+ testfile = self.touch(filename)
+- testdir = self.mkdirs(u"\u4241\u1D04\u1414")
++ testdir = self.mkdirs("\u4241\u1D04\u1414")
+ # We don't use subprocess because it can't handle Unicode on
+ # Windows <http://bugs.python.org/issue1759845>. mozprocess calls
+ # CreateProcessW directly so it's perfect.
+@@ -166,7 +166,7 @@
+
+ self.assertEqual(rv, 0)
+ destfile = os.path.join(testdir, filename)
+- self.assert_(os.path.isfile(destfile))
++ self.assertTrue(os.path.isfile(destfile))
+
+ #TODO: implement -R, -l, -L and test them!
+
+--- firefox-52.9.0esr/config/tests/unitMozZipFile.py (original)
++++ firefox-52.9.0esr/config/tests/unitMozZipFile.py (refactored)
+@@ -11,6 +11,7 @@
+ import random
+ import copy
+ from string import letters
++from functools import reduce
+
+ '''
+ Test case infrastructure for MozZipFile.
+@@ -38,7 +39,7 @@
+ 'firstdir/oneleaf',
+ 'seconddir/twoleaf',
+ 'thirddir/with/sub/threeleaf')
+-_lengths = map(lambda n: n * 64, [16, 64, 80])
++_lengths = [n * 64 for n in [16, 64, 80]]
+ lengths = 3
+ writes = 5
+
+@@ -71,7 +72,7 @@
+ def getContent(length):
+ 'Get pseudo random content of given length.'
+ rv = [None] * length
+- for i in xrange(length):
++ for i in range(length):
+ rv[i] = random.choice(letters)
+ return ''.join(rv)
+
+@@ -133,13 +134,13 @@
+ def _verifyZip(self):
+ zf = zipfile.ZipFile(self.f)
+ badEntry = zf.testzip()
+- self.failIf(badEntry, badEntry)
++ self.assertFalse(badEntry, badEntry)
+ zlist = zf.namelist()
+ zlist.sort()
+- vlist = self.ref.keys()
++ vlist = list(self.ref.keys())
+ vlist.sort()
+ self.assertEqual(zlist, vlist)
+- for leaf, content in self.ref.iteritems():
++ for leaf, content in self.ref.items():
+ zcontent = zf.read(leaf)
+ self.assertEqual(content, zcontent)
+
+@@ -158,16 +159,16 @@
+ open(self.leaf('stage', leaf), 'w').write(content)
+
+ # all leafs in all lengths
+-atomics = list(prod(xrange(len(leafs)), xrange(lengths)))
++atomics = list(prod(range(len(leafs)), range(lengths)))
+
+ # populate TestExtensiveStore with testcases
+-for w in xrange(writes):
++for w in range(writes):
+ # Don't iterate over all files for the the first n passes,
+ # those are redundant as long as w < lengths.
+ # There are symmetries in the trailing end, too, but I don't know
+ # how to reduce those out right now.
+- nonatomics = [list(prod(range(min(i,len(leafs))), xrange(lengths)))
+- for i in xrange(1, w+1)] + [atomics]
++ nonatomics = [list(prod(list(range(min(i,len(leafs)))), range(lengths)))
++ for i in range(1, w+1)] + [atomics]
+ for descs in prod(*nonatomics):
+ suffix = getid(descs)
+ dicts = [dict(leaf=leaf, length=length) for leaf, length in descs]
+@@ -181,9 +182,9 @@
+ # and then write all atomics again.
+ # This should catch more or less all artifacts generated
+ # by the final ordering step when closing the jar.
+-files = [list(prod([i], xrange(lengths))) for i in xrange(len(leafs))]
++files = [list(prod([i], range(lengths))) for i in range(len(leafs))]
+ allfiles = reduce(lambda l,r:l+r,
+- [list(prod(*files[:(i+1)])) for i in xrange(len(leafs))])
++ [list(prod(*files[:(i+1)])) for i in range(len(leafs))])
+
+ for first in allfiles:
+ testbasename = 'test{0}_'.format(getid(first))
+--- firefox-52.9.0esr/config/expandlibs_exec.py.old 2018-07-11 05:07:18.280000000 +0000
++++ firefox-52.9.0esr/config/expandlibs_exec.py 2018-07-11 05:08:45.670000000 +0000
+@@ -344,7 +344,7 @@
+ (stdout, stderr) = proc.communicate()
+ if proc.returncode and not options.verbose:
+ print_command(sys.stderr, args)
+- sys.stderr.write(stdout)
++ sys.stderr.write(stdout.decode('utf-8'))
+ sys.stderr.flush()
+ if proc.returncode:
+ return proc.returncode
+--- firefox-52.9.0esr/js/src/jsautokw.py.old 2017-04-11 02:13:16.000000000 +0000
++++ firefox-52.9.0esr/js/src/jsautokw.py 2018-07-11 05:11:27.080000000 +0000
+@@ -80,14 +80,14 @@
+ per_column = column_dict.setdefault(keyword[column], [])
+ per_column.append(item)
+
+- return sorted(column_dict.items(), key=lambda (char, keyword): ord(char))
++ return sorted(list(column_dict.items()), key=lambda char_keyword: ord(char_keyword[0]))
+
+ def generate_letter_switch(opt, unprocessed_columns, keyword_list,
+ columns=None):
+ assert(len(keyword_list) != 0);
+
+ if not columns:
+- columns = range(0, unprocessed_columns)
++ columns = list(range(0, unprocessed_columns))
+
+ if len(keyword_list) == 1:
+ index, keyword = keyword_list[0]
+@@ -161,7 +161,7 @@
+ per_length = length_dict.setdefault(len(keyword), [])
+ per_length.append(item)
+
+- return sorted(length_dict.items(), key=lambda (length, keyword): length)
++ return sorted(list(length_dict.items()), key=lambda length_keyword: length_keyword[0])
+
+ def generate_switch(opt, keyword_list):
+ assert(len(keyword_list) != 0);
+--- firefox-52.9.0esr/js/src/builtin/embedjs.py (original)
++++ firefox-52.9.0esr/js/src/builtin/embedjs.py (refactored)
+@@ -36,7 +36,7 @@
+ #
+ # It uses the C preprocessor to process its inputs.
+
+-from __future__ import with_statement
++
+ import re, sys, os, subprocess
+ import shlex
+ import which
+@@ -109,7 +109,7 @@
+
+ with open(tmpIn, 'wb') as input:
+ input.write(source)
+- print(' '.join(cxx + outputArg + args + [tmpIn]))
++ print((' '.join(cxx + outputArg + args + [tmpIn])))
+ result = subprocess.Popen(cxx + outputArg + args + [tmpIn]).wait()
+ if (result != 0):
+ sys.exit(result);
+@@ -132,7 +132,7 @@
+
+ def get_config_defines(buildconfig):
+ # Collect defines equivalent to ACDEFINES and add MOZ_DEBUG_DEFINES.
+- env = {key: value for key, value in buildconfig.defines.iteritems()
++ env = {key: value for key, value in buildconfig.defines.items()
+ if key not in buildconfig.non_global_defines}
+ for define in buildconfig.substs['MOZ_DEBUG_DEFINES']:
+ env[define] = 1
+--- firefox-52.9.0esr/js/src/builtin/embedjs.py.old 2018-07-11 05:13:28.920000000 +0000
++++ firefox-52.9.0esr/js/src/builtin/embedjs.py 2018-07-11 05:15:15.390000000 +0000
+@@ -107,7 +107,7 @@
+ tmpOut = 'self-hosting-preprocessed.pp';
+ outputArg = shlex.split(preprocessorOption + tmpOut)
+
+- with open(tmpIn, 'wb') as input:
++ with open(tmpIn, 'w') as input:
+ input.write(source)
+ print((' '.join(cxx + outputArg + args + [tmpIn])))
+ result = subprocess.Popen(cxx + outputArg + args + [tmpIn]).wait()
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/preprocessor.py.old 2018-07-11 05:15:42.900000000 +0000
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/preprocessor.py 2018-07-11 05:23:10.870000000 +0000
+@@ -451,7 +451,7 @@
+ except OSError as error:
+ if error.errno != errno.EEXIST:
+ raise
+- return open(path, 'wb')
++ return open(path, 'w')
+
+ p = self.getCommandLineParser()
+ options, args = p.parse_args(args=args)
+--- firefox-52.9.0esr/js/src/builtin/embedjs.py.old 2018-07-11 05:15:42.950000000 +0000
++++ firefox-52.9.0esr/js/src/builtin/embedjs.py 2018-07-11 05:20:14.280000000 +0000
+@@ -53,7 +53,7 @@
+ def ToCArray(lines):
+ result = []
+ for chr in lines:
+- result.append(str(ord(chr)))
++ result.append(str(chr))
+ return ", ".join(result)
+
+ HEADER_TEMPLATE = """\
+@@ -87,7 +87,7 @@
+
+ js_out.write(processed)
+ import zlib
+- compressed = zlib.compress(processed)
++ compressed = zlib.compress(processed.encode('utf-8'))
+ data = ToCArray(compressed)
+ c_out.write(HEADER_TEMPLATE % {
+ 'sources_type': 'unsigned char',
+--- firefox-52.9.0esr/build/mach_bootstrap.py.old 2018-06-29 23:00:39.000000000 +0000
++++ firefox-52.9.0esr/build/mach_bootstrap.py 2018-07-26 00:41:17.740000000 +0000
+@@ -12,7 +12,7 @@
+ import subprocess
+ import sys
+ import uuid
+-import __builtin__
++import builtins
+
+ from types import ModuleType
+
+@@ -187,10 +187,10 @@
+ # Ensure we are running Python 2.7+. We put this check here so we generate a
+ # user-friendly error message rather than a cryptic stack trace on module
+ # import.
+- if sys.version_info[0] != 2 or sys.version_info[1] < 7:
+- print('Python 2.7 or above (but not Python 3) is required to run mach.')
+- print('You are running Python', platform.python_version())
+- sys.exit(1)
++ #if sys.version_info[0] != 2 or sys.version_info[1] < 7:
++ # print('Python 2.7 or above (but not Python 3) is required to run mach.')
++ # print('You are running Python', platform.python_version())
++ # sys.exit(1)
+
+ # Global build system and mach state is stored in a central directory. By
+ # default, this is ~/.mozbuild. However, it can be defined via an
+@@ -410,4 +410,4 @@
+
+
+ # Install our hook
+-__builtin__.__import__ = ImportHook(__builtin__.__import__)
++builtins.__import__ = ImportHook(builtins.__import__)
+--- firefox-52.9.0esr/python/mach/mach/config.py (original)
++++ firefox-52.9.0esr/python/mach/mach/config.py (refactored)
+@@ -163,7 +163,7 @@
+ return func(*args, **kwargs)
+ except KeyError:
+ exc_class, exc, tb = sys.exc_info()
+- raise AttributeError().__class__, exc, tb
++ raise AttributeError().__class__(exc).with_traceback(tb)
+ return _
+
+
+@@ -357,7 +357,7 @@
+ extra -- A dict of additional key/value pairs to add to the
+ setting metadata.
+ """
+- if isinstance(type_cls, basestring):
++ if isinstance(type_cls, str_type):
+ type_cls = TYPE_CLASSES[type_cls]
+
+ meta = {
+@@ -397,10 +397,10 @@
+ meta = self._format_metadata(provider, section, option, *setting[1:])
+ config_settings[section][option] = meta
+
+- for section_name, settings in config_settings.items():
++ for section_name, settings in list(config_settings.items()):
+ section = self._settings.get(section_name, {})
+
+- for k, v in settings.items():
++ for k, v in list(settings.items()):
+ if k in section:
+ raise ConfigException('Setting already registered: %s.%s' %
+ section_name, k)
+@@ -432,7 +432,7 @@
+ if self._finalized:
+ return
+
+- for section, settings in self._settings.items():
++ for section, settings in list(self._settings.items()):
+ s = ConfigSettings.ConfigSection(self._config, section, settings)
+ self._sections[section] = s
+
+@@ -445,7 +445,7 @@
+ def __iter__(self):
+ self._finalize()
+
+- return iter(self._sections.keys())
++ return iter(list(self._sections.keys()))
+
+ def __contains__(self, k):
+ return k in self._settings
+--- firefox-52.9.0esr/python/mach/mach/dispatcher.py (original)
++++ firefox-52.9.0esr/python/mach/mach/dispatcher.py (refactored)
+@@ -243,7 +243,7 @@
+ r = self._mach_registrar
+ disabled_commands = []
+
+- cats = [(k, v[2]) for k, v in r.categories.items()]
++ cats = [(k, v[2]) for k, v in list(r.categories.items())]
+ sorted_cats = sorted(cats, key=itemgetter(1), reverse=True)
+ for category, priority in sorted_cats:
+ group = None
+@@ -375,7 +375,7 @@
+ ' subcommand [subcommand arguments]'
+ group = parser.add_argument_group('Sub Commands')
+
+- for subcommand, subhandler in sorted(handler.subcommand_handlers.iteritems()):
++ for subcommand, subhandler in sorted(handler.subcommand_handlers.items()):
+ group.add_argument(subcommand, help=subhandler.description,
+ action='store_true')
+
+@@ -406,7 +406,7 @@
+
+ def _suggest_command(self, command):
+ # Make sure we don't suggest any deprecated commands.
+- names = [h.name for h in self._mach_registrar.command_handlers.values()
++ names = [h.name for h in list(self._mach_registrar.command_handlers.values())
+ if h.cls.__name__ != 'DeprecatedCommands']
+ # We first try to look for a valid command that is very similar to the given command.
+ suggested_commands = difflib.get_close_matches(command, names, cutoff=0.8)
+@@ -437,13 +437,13 @@
+ if not docstring:
+ return ''
+ lines = docstring.expandtabs().splitlines()
+- indent = sys.maxint
++ indent = sys.maxsize
+ for line in lines[1:]:
+ stripped = line.lstrip()
+ if stripped:
+ indent = min(indent, len(line) - len(stripped))
+ trimmed = [lines[0].strip()]
+- if indent < sys.maxint:
++ if indent < sys.maxsize:
+ for line in lines[1:]:
+ trimmed.append(line[indent:].rstrip())
+ while trimmed and not trimmed[-1]:
+--- firefox-52.9.0esr/python/mach/mach/main.py (original)
++++ firefox-52.9.0esr/python/mach/mach/main.py (refactored)
+@@ -528,7 +528,7 @@
+
+ machrc, .machrc
+ """
+- if isinstance(paths, basestring):
++ if isinstance(paths, str):
+ paths = [paths]
+
+ valid_names = ('machrc', '.machrc')
+@@ -541,8 +541,8 @@
+ if os.path.isfile(path):
+ return path
+
+- files = map(find_in_dir, self.settings_paths)
+- files = filter(bool, files)
++ files = list(map(find_in_dir, self.settings_paths))
++ files = list(filter(bool, files))
+
+ self.settings.load_files(files)
+
+--- firefox-52.9.0esr/python/mach/mach/registrar.py (original)
++++ firefox-52.9.0esr/python/mach/mach/registrar.py (refactored)
+@@ -90,7 +90,7 @@
+ result = fn(**kwargs)
+
+ result = result or 0
+- assert isinstance(result, (int, long))
++ assert isinstance(result, int)
+
+ if context:
+ postrun = getattr(context, 'post_dispatch_handler', None)
+--- firefox-52.9.0esr/python/mach/mach/terminal.py (original)
++++ firefox-52.9.0esr/python/mach/mach/terminal.py (refactored)
+@@ -59,7 +59,7 @@
+ self.fh = sys.stdout
+
+ def _clear_lines(self, n):
+- for i in xrange(n):
++ for i in range(n):
+ self.fh.write(self.t.move_x(0))
+ self.fh.write(self.t.clear_eol())
+ self.fh.write(self.t.move_up())
+--- firefox-52.9.0esr/python/mach/mach/main.py.old 2018-07-26 00:55:29.330000000 +0000
++++ firefox-52.9.0esr/python/mach/mach/main.py 2018-07-26 00:57:01.260000000 +0000
+@@ -256,9 +256,9 @@
+ if module_name is None:
+ # Ensure parent module is present otherwise we'll (likely) get
+ # an error due to unknown parent.
+- if b'mach.commands' not in sys.modules:
+- mod = imp.new_module(b'mach.commands')
+- sys.modules[b'mach.commands'] = mod
++ if 'mach.commands' not in sys.modules:
++ mod = imp.new_module('mach.commands')
++ sys.modules['mach.commands'] = mod
+
+ module_name = 'mach.commands.%s' % uuid.uuid1().get_hex()
+
+@@ -347,7 +347,7 @@
+ # is a TTY. This provides a mechanism to allow said processes to
+ # enable emitting code codes, for example.
+ if os.isatty(orig_stdout.fileno()):
+- os.environ[b'MACH_STDOUT_ISATTY'] = b'1'
++ os.environ['MACH_STDOUT_ISATTY'] = '1'
+
+ return self._run(argv)
+ except KeyboardInterrupt:
+--- firefox-52.9.0esr/toolkit/moz.configure.old 2017-04-11 02:13:23.000000000 +0000
++++ firefox-52.9.0esr/toolkit/moz.configure 2018-07-26 05:32:08.590000000 +0000
+@@ -690,7 +690,7 @@
+ # ==============================================================
+ @depends(check_build_environment, '--help')
+ @imports('os')
+-@imports(_from='__builtin__', _import='sorted')
++@imports(_from='builtins', _import='sorted')
+ def all_necko_protocols(build_env, _):
+ basedir = os.path.join(build_env.topsrcdir, 'netwerk', 'protocol')
+ return tuple(sorted(p for p in os.listdir(basedir)
+@@ -744,7 +744,7 @@
+ __sandbox__.set_define_impl(p, True)
+
+ @depends('--enable-network-protocols')
+-@imports(_from='__builtin__', _import='sorted')
++@imports(_from='builtins', _import='sorted')
+ def necko_protocols(protocols):
+ return tuple(sorted(protocols))
+
+--- firefox-52.9.0esr/build/moz.configure/pkg.configure.old 2017-04-11 02:13:08.000000000 +0000
++++ firefox-52.9.0esr/build/moz.configure/pkg.configure 2018-07-26 05:36:10.990000000 +0000
+@@ -84,6 +84,8 @@
+ @checking('%s_LIBS' % var, callback=lambda t: ' '.join(t))
+ def pkg_libs(pkg_config, package_desc):
+ libs = check_cmd_output(pkg_config, '--libs', package_desc)
++ if isinstance(libs, bytes):
++ libs = libs.decode('utf-8')
+ # Remove evil flags like -Wl,--export-dynamic
+ return tuple(libs.replace('-Wl,--export-dynamic', '').split())
+
+--- firefox-52.9.0esr/build/moz.configure/pkg.configure.old 2018-07-26 05:37:14.580000000 +0000
++++ firefox-52.9.0esr/build/moz.configure/pkg.configure 2018-07-26 05:38:48.750000000 +0000
+@@ -78,6 +78,8 @@
+ @checking('%s_CFLAGS' % var, callback=lambda t: ' '.join(t))
+ def pkg_cflags(pkg_config, package_desc):
+ flags = check_cmd_output(pkg_config, '--cflags', package_desc)
++ if isinstance(flags, bytes):
++ flags = flags.decode('utf-8')
+ return tuple(flags.split())
+
+ @depends_when(pkg_config, package_desc, when=package)
+--- firefox-52.9.0esr/build/subconfigure.py.old 2018-07-26 05:39:27.360000000 +0000
++++ firefox-52.9.0esr/build/subconfigure.py 2018-07-26 09:58:41.110000000 +0000
+@@ -39,7 +39,7 @@
+ class File(object):
+ def __init__(self, path):
+ self._path = path
+- self._content = open(path, 'rb').read()
++ self._content = open(path, 'r').read()
+ stat = os.stat(path)
+ self._times = (stat.st_atime, stat.st_mtime)
+
+@@ -60,7 +60,7 @@
+
+ modified = True
+ if os.path.exists(self._path):
+- if open(self._path, 'rb').read() == self._content:
++ if open(self._path, 'r').read() == self._content:
+ modified = False
+ self._modified = modified
+ return modified
+@@ -221,7 +221,7 @@
+ environ[var] = os.environ[var]
+ args = data['args']
+ else:
+- environ = os.environ
++ environ = dict(os.environ)
+
+ args, others = parser.parse_known_args(args)
+
+@@ -260,7 +260,7 @@
+
+ def run(objdir):
+ ret = 0
+- output = ''
++ output = b''
+
+ with open(os.path.join(objdir, CONFIGURE_DATA), 'rb') as f:
+ data = pickle.load(f)
+@@ -381,7 +381,7 @@
+ for f in contents:
+ f.update_time()
+
+- return relobjdir, ret, output
++ return relobjdir, ret, output.decode('utf-8')
+
+
+ def subconfigure(args):
+@@ -395,9 +395,9 @@
+ args, others = parser.parse_known_args(args)
+ subconfigures = args.subconfigures
+ if args.list:
+- subconfigures.extend(open(args.list, 'rb').read().splitlines())
++ subconfigures.extend(open(args.list, 'r').read().splitlines())
+ if args.skip:
+- skips = set(open(args.skip, 'rb').read().splitlines())
++ skips = set(open(args.skip, 'r').read().splitlines())
+ subconfigures = [s for s in subconfigures if s not in skips]
+
+ if not subconfigures:
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/util.py.old 2018-07-26 10:43:58.540000000 +0000
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/util.py 2018-07-26 10:57:09.100000000 +0000
+@@ -1228,7 +1228,7 @@
+ yield 'b'
+ yield repr(o)
+ elif isinstance(o, str):
+- yield "'"
++ yield "'''"
+ # We want a readable string (non escaped unicode), but some
+ # special characters need escaping (e.g. \n, \t, etc.)
+ for i, s in enumerate(_INDENTED_REPR_RE.split(o)):
+@@ -1237,7 +1237,7 @@
+ yield _INDENTED_REPR_TABLE[c]
+ else:
+ yield s
+- yield "'"
++ yield "'''"
+ elif hasattr(o, '__iter__'):
+ yield '[\n'
+ for i in o:
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/configure/util.py.old 2018-07-26 10:43:58.540000000 +0000
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/configure/util.py 2018-07-26 10:49:10.780000000 +0000
+@@ -148,6 +148,8 @@
+ self._stdout.flush()
+ stream = self._stderr
+ msg = '%s\n' % self.format(record)
++ if isinstance(msg, bytes):
++ msg = msg.decode('utf-8')
+ stream.write(msg)
+ stream.flush()
+ except (KeyboardInterrupt, SystemExit):
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/configure/util.py.old 2018-07-26 10:58:24.910000000 +0000
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/configure/util.py 2018-07-26 11:08:15.430000000 +0000
+@@ -89,8 +89,8 @@
+ return codecs.getwriter(encoding)(fh)
+ return fh
+
+- self._stdout = fix_encoding(stdout)
+- self._stderr = fix_encoding(stderr) if stdout != stderr else self._stdout
++ self._stdout = stdout
++ self._stderr = stderr if stdout != stderr else self._stdout
+ try:
+ fd1 = self._stdout.fileno()
+ fd2 = self._stderr.fileno()
+@@ -148,8 +148,6 @@
+ self._stdout.flush()
+ stream = self._stderr
+ msg = '%s\n' % self.format(record)
+- if isinstance(msg, bytes):
+- msg = msg.decode('utf-8')
+ stream.write(msg)
+ stream.flush()
+ except (KeyboardInterrupt, SystemExit):
+--- firefox-52.9.0esr/build/mach_bootstrap.py.old 2018-07-26 10:58:24.910000000 +0000
++++ firefox-52.9.0esr/build/mach_bootstrap.py 2018-07-26 11:09:30.620000000 +0000
+@@ -361,7 +361,7 @@
+ self._modules = set()
+
+ def __call__(self, name, globals=None, locals=None, fromlist=None,
+- level=-1):
++ level=0):
+ # name might be a relative import. Instead of figuring out what that
+ # resolves to, which is complex, just rely on the real import.
+ # Since we don't know the full module name, we can't check sys.modules,
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/configure/check_debug_ranges.py.old 2018-07-26 11:10:15.820000000 +0000
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/configure/check_debug_ranges.py 2018-07-26 11:14:51.180000000 +0000
+@@ -45,6 +45,7 @@
+ def main(bin, compilation_unit):
+ p = subprocess.Popen(['objdump', '-W', bin], stdout = subprocess.PIPE, stderr = subprocess.PIPE)
+ (out, err) = p.communicate()
++ out = out.decode('utf-8')
+ sections = re.split('\n(Contents of the|The section) ', out)
+ debug_info = [s for s in sections if s.startswith('.debug_info')]
+ debug_ranges = [s for s in sections if s.startswith('.debug_ranges')]
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/configure/constants.py.old 2018-07-26 11:10:15.820000000 +0000
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/configure/constants.py 2018-07-26 11:18:03.750000000 +0000
+@@ -28,6 +28,7 @@
+ )
+
+ Kernel = EnumString.subclass(
++ 'Android',
+ 'Darwin',
+ 'DragonFly',
+ 'FreeBSD',
+@@ -90,6 +91,7 @@
+ assert sorted(CPU_preprocessor_checks.keys()) == sorted(CPU.POSSIBLE_VALUES)
+
+ kernel_preprocessor_checks = {
++ 'Android': '__BIONIC__',
+ 'Darwin': '__APPLE__',
+ 'DragonFly': '__DragonFly__',
+ 'FreeBSD': '__FreeBSD__',
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/configure/constants.py.old 2018-07-26 11:18:54.630000000 +0000
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/configure/constants.py 2018-07-26 23:46:48.880000000 +0000
+@@ -28,6 +28,7 @@
+ )
+
+ Kernel = EnumString.subclass(
++ 'AIX',
+ 'Android',
+ 'Darwin',
+ 'DragonFly',
+@@ -91,6 +92,7 @@
+ assert sorted(CPU_preprocessor_checks.keys()) == sorted(CPU.POSSIBLE_VALUES)
+
+ kernel_preprocessor_checks = {
++ 'AIX': '_AIX',
+ 'Android': '__BIONIC__',
+ 'Darwin': '__APPLE__',
+ 'DragonFly': '__DragonFly__',
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/configure/constants.py.old 2018-07-26 23:47:39.060000000 +0000
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/configure/constants.py 2018-07-26 23:53:25.260000000 +0000
+@@ -37,6 +37,8 @@
+ 'Linux',
+ 'NetBSD',
+ 'OpenBSD',
++ 'SunOS',
++ 'HP-UX',
+ 'WINNT',
+ )
+
+@@ -93,14 +94,16 @@
+
+ kernel_preprocessor_checks = {
+ 'AIX': '_AIX',
+- 'Android': '__BIONIC__',
++ 'Android': '__ANDROID__',
+ 'Darwin': '__APPLE__',
+ 'DragonFly': '__DragonFly__',
+ 'FreeBSD': '__FreeBSD__',
++ 'HP-UX': '_hpux',
+ 'kFreeBSD': '__FreeBSD_kernel__',
+ 'Linux': '__linux__',
+ 'NetBSD': '__NetBSD__',
+ 'OpenBSD': '__OpenBSD__',
++ 'SunOS': '__sun || sun',
+ 'WINNT': '_WIN32 || __CYGWIN__',
+ }
+
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/configure/constants.py.old 2018-07-26 23:55:19.000000000 +0000
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/configure/constants.py 2018-07-26 23:58:36.750000000 +0000
+@@ -33,12 +33,15 @@
+ 'Darwin',
+ 'DragonFly',
+ 'FreeBSD',
++ 'GNU',
++ 'GNU/kFreeBSD',
++ 'GNU_kFreeBSD',
++ 'HP-UX',
+ 'kFreeBSD',
+ 'Linux',
+ 'NetBSD',
+ 'OpenBSD',
+ 'SunOS',
+- 'HP-UX',
+ 'WINNT',
+ )
+
+@@ -99,6 +102,9 @@
+ 'Darwin': '__APPLE__',
+ 'DragonFly': '__DragonFly__',
+ 'FreeBSD': '__FreeBSD__',
++ 'GNU': '__gnu_hurd__',
++ 'GNU/kFreeBSD': '__FreeBSD_kernel_ && __GLIBC__',
++ 'GNU_kFreeBSD': '__FreeBSD_kernel_ && __GLIBC__',
+ 'HP-UX': '_hpux',
+ 'kFreeBSD': '__FreeBSD_kernel__',
+ 'Linux': '__linux__',
+--- firefox-52.9.0esr/testing/mozbase/manifestparser/manifestparser/ini.py.old 2018-07-26 23:55:18.990000000 +0000
++++ firefox-52.9.0esr/testing/mozbase/manifestparser/manifestparser/ini.py 2018-07-27 00:04:47.460000000 +0000
+@@ -33,7 +33,7 @@
+ # read the lines
+ for (linenum, line) in enumerate(fp.read().splitlines(), start=1):
+
+- stripped = line.strip()
++ stripped = line.strip().decode('utf-8')
+
+ # ignore blank lines
+ if not stripped:
+--- firefox-52.9.0esr/testing/mozbase/manifestparser/manifestparser/ini.py.old 2018-07-27 00:09:00.850000000 +0000
++++ firefox-52.9.0esr/testing/mozbase/manifestparser/manifestparser/ini.py 2018-07-27 00:12:03.920000000 +0000
+@@ -31,9 +31,9 @@
+ fp = open(fp)
+
+ # read the lines
+- for (linenum, line) in enumerate(fp.read().splitlines(), start=1):
++ for (linenum, line) in enumerate(fp.read().decode('utf-8').splitlines(), start=1):
+
+- stripped = line.strip().decode('utf-8')
++ stripped = line.strip()
+
+ # ignore blank lines
+ if not stripped:
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/frontend/sandbox.py.old 2018-07-27 00:12:52.240000000 +0000
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/frontend/sandbox.py 2018-07-27 00:18:00.010000000 +0000
+@@ -39,7 +39,8 @@
+ """sorted() replacement for the sandbox, ordering alphabetically by
+ default.
+ """
+- return sorted(iterable, cmp, key, reverse)
++ ### XXX what do we do with cmp?
++ return sorted(iterable, key=key, reverse=reverse)
+
+
+ class SandboxError(Exception):
+--- firefox-52.9.0esr/python/mozbuild/mozbuild/frontend/emitter.py.old 2018-07-27 00:32:50.870000000 +0000
++++ firefox-52.9.0esr/python/mozbuild/mozbuild/frontend/emitter.py 2018-07-27 00:32:28.770000000 +0000
+@@ -1399,7 +1399,8 @@
+ # declared anywhere (they were discovered). This will detect people
+ # relying on the old behavior.
+ if os.path.exists(os.path.join(context.srcdir, 'jar.mn')):
+- if 'jar.mn' not in jar_manifests:
++ if 'jar.mn' not in jar_manifests and \
++ SourcePath(context, 'jar.mn') not in jar_manifests:
+ raise SandboxValidationError('A jar.mn exists but it '
+ 'is not referenced in the moz.build file. '
+ 'Please define JAR_MANIFESTS.', context)
diff --git a/experimental/firefox-esr/rust-config.patch b/experimental/firefox-esr/rust-config.patch
new file mode 100644
index 000000000..4dbddc2a9
--- /dev/null
+++ b/experimental/firefox-esr/rust-config.patch
@@ -0,0 +1,20 @@
+look, another reason to hate google: fuchsia's triplets confuse the hell out of poor mozconfig
+
+meanwhile, make -foxkit- more important than -unknown-
+
+--- thunderbird-60.2.1/build/moz.configure/rust.configure.old 2018-10-01 14:51:04.000000000 +0000
++++ thunderbird-60.2.1/build/moz.configure/rust.configure 2018-10-11 23:13:15.370000000 +0000
+@@ -119,9 +119,13 @@
+ ambiguous = set()
+ per_raw_os = {}
+ for t in out:
++ if 'fuchsia' in t: continue
+ t = split_triplet(t, allow_unknown=True)
+ key = (t.cpu, t.endianness, t.os)
+ if key in per_os:
++ # hax to allow Adélie toolchains to work
++ if 'foxkit' in per_os[key].alias:
++ continue
+ previous = per_os[key]
+ per_raw_os[(previous.cpu, previous.endianness,
+ previous.raw_os)] = previous
diff --git a/experimental/firefox-esr/skia.patch b/experimental/firefox-esr/skia.patch
new file mode 100644
index 000000000..a44ef76ed
--- /dev/null
+++ b/experimental/firefox-esr/skia.patch
@@ -0,0 +1,132 @@
+# HG changeset patch
+# User Lee Salzman <lsalzman@mozilla.com>
+# Date 1527131721 14400
+# Wed May 23 23:15:21 2018 -0400
+# Node ID a8d83bebeab4c07a850711aa2c241a56f784613e
+# Parent 50fbb3e601fef35e2a673895cb0b3bc05374458a
+fix big-endian Skia builds
+
+MozReview-Commit-ID: JQivGBE45qy
+
+diff --git a/gfx/skia/skia/include/core/SkColorPriv.h b/gfx/skia/skia/include/core/SkColorPriv.h
+--- a/gfx/skia/skia/include/core/SkColorPriv.h
++++ b/gfx/skia/skia/include/core/SkColorPriv.h
+@@ -50,27 +50,20 @@ static inline U8CPU SkUnitScalarClampToB
+ * For easier compatibility with Skia's GPU backend, we further restrict these
+ * to either (in memory-byte-order) RGBA or BGRA. Note that this "order" does
+ * not directly correspond to the same shift-order, since we have to take endianess
+ * into account.
+ *
+ * Here we enforce this constraint.
+ */
+
+-#ifdef SK_CPU_BENDIAN
+- #define SK_RGBA_R32_SHIFT 24
+- #define SK_RGBA_G32_SHIFT 16
+- #define SK_RGBA_B32_SHIFT 8
+- #define SK_RGBA_A32_SHIFT 0
+-#else
+- #define SK_RGBA_R32_SHIFT 0
+- #define SK_RGBA_G32_SHIFT 8
+- #define SK_RGBA_B32_SHIFT 16
+- #define SK_RGBA_A32_SHIFT 24
+-#endif
++#define SK_RGBA_R32_SHIFT 0
++#define SK_RGBA_G32_SHIFT 8
++#define SK_RGBA_B32_SHIFT 16
++#define SK_RGBA_A32_SHIFT 24
+
+ #define SkGetPackedA32(packed) ((uint32_t)((packed) << (24 - SK_A32_SHIFT)) >> 24)
+ #define SkGetPackedR32(packed) ((uint32_t)((packed) << (24 - SK_R32_SHIFT)) >> 24)
+ #define SkGetPackedG32(packed) ((uint32_t)((packed) << (24 - SK_G32_SHIFT)) >> 24)
+ #define SkGetPackedB32(packed) ((uint32_t)((packed) << (24 - SK_B32_SHIFT)) >> 24)
+
+ #define SkA32Assert(a) SkASSERT((unsigned)(a) <= SK_A32_MASK)
+ #define SkR32Assert(r) SkASSERT((unsigned)(r) <= SK_R32_MASK)
+diff --git a/gfx/skia/skia/include/core/SkImageInfo.h b/gfx/skia/skia/include/core/SkImageInfo.h
+--- a/gfx/skia/skia/include/core/SkImageInfo.h
++++ b/gfx/skia/skia/include/core/SkImageInfo.h
+@@ -79,17 +79,17 @@ enum SkColorType {
+
+ kLastEnum_SkColorType = kRGBA_F16_SkColorType,
+
+ #if SK_PMCOLOR_BYTE_ORDER(B,G,R,A)
+ kN32_SkColorType = kBGRA_8888_SkColorType,
+ #elif SK_PMCOLOR_BYTE_ORDER(R,G,B,A)
+ kN32_SkColorType = kRGBA_8888_SkColorType,
+ #else
+- #error "SK_*32_SHIFT values must correspond to BGRA or RGBA byte order"
++ kN32_SkColorType = kBGRA_8888_SkColorType,
+ #endif
+ };
+
+ /**
+ * Returns the number of bytes-per-pixel for the specified colortype, or 0 if invalid.
+ */
+ SK_API int SkColorTypeBytesPerPixel(SkColorType ct);
+
+diff --git a/gfx/skia/skia/include/gpu/GrTypes.h b/gfx/skia/skia/include/gpu/GrTypes.h
+--- a/gfx/skia/skia/include/gpu/GrTypes.h
++++ b/gfx/skia/skia/include/gpu/GrTypes.h
+@@ -339,25 +339,22 @@ enum GrPixelConfig {
+ kPrivateConfig4_GrPixelConfig,
+ kPrivateConfig5_GrPixelConfig,
+
+ kLast_GrPixelConfig = kPrivateConfig5_GrPixelConfig
+ };
+ static const int kGrPixelConfigCnt = kLast_GrPixelConfig + 1;
+
+ // Aliases for pixel configs that match skia's byte order.
+-#ifndef SK_CPU_LENDIAN
+- #error "Skia gpu currently assumes little endian"
+-#endif
+ #if SK_PMCOLOR_BYTE_ORDER(B,G,R,A)
+ static const GrPixelConfig kSkia8888_GrPixelConfig = kBGRA_8888_GrPixelConfig;
+ #elif SK_PMCOLOR_BYTE_ORDER(R,G,B,A)
+ static const GrPixelConfig kSkia8888_GrPixelConfig = kRGBA_8888_GrPixelConfig;
+ #else
+- #error "SK_*32_SHIFT values must correspond to GL_BGRA or GL_RGBA format."
++ static const GrPixelConfig kSkia8888_GrPixelConfig = kBGRA_8888_GrPixelConfig;
+ #endif
+
+ /**
+ * Optional bitfield flags that can be set on GrSurfaceDesc (below).
+ */
+ enum GrSurfaceFlags {
+ kNone_GrSurfaceFlags = 0x0,
+ /**
+diff --git a/gfx/skia/skia/src/core/SkColorData.h b/gfx/skia/skia/src/core/SkColorData.h
+--- a/gfx/skia/skia/src/core/SkColorData.h
++++ b/gfx/skia/skia/src/core/SkColorData.h
+@@ -27,27 +27,20 @@
+ * For easier compatibility with Skia's GPU backend, we further restrict these
+ * to either (in memory-byte-order) RGBA or BGRA. Note that this "order" does
+ * not directly correspond to the same shift-order, since we have to take endianess
+ * into account.
+ *
+ * Here we enforce this constraint.
+ */
+
+-#ifdef SK_CPU_BENDIAN
+- #define SK_BGRA_B32_SHIFT 24
+- #define SK_BGRA_G32_SHIFT 16
+- #define SK_BGRA_R32_SHIFT 8
+- #define SK_BGRA_A32_SHIFT 0
+-#else
+- #define SK_BGRA_B32_SHIFT 0
+- #define SK_BGRA_G32_SHIFT 8
+- #define SK_BGRA_R32_SHIFT 16
+- #define SK_BGRA_A32_SHIFT 24
+-#endif
++#define SK_BGRA_B32_SHIFT 0
++#define SK_BGRA_G32_SHIFT 8
++#define SK_BGRA_R32_SHIFT 16
++#define SK_BGRA_A32_SHIFT 24
+
+ #if defined(SK_PMCOLOR_IS_RGBA) && defined(SK_PMCOLOR_IS_BGRA)
+ #error "can't define PMCOLOR to be RGBA and BGRA"
+ #endif
+
+ #define LOCAL_PMCOLOR_SHIFTS_EQUIVALENT_TO_RGBA \
+ (SK_A32_SHIFT == SK_RGBA_A32_SHIFT && \
+ SK_R32_SHIFT == SK_RGBA_R32_SHIFT && \
diff --git a/experimental/firefox-esr/stab.h b/experimental/firefox-esr/stab.h
new file mode 100644
index 000000000..6f70af398
--- /dev/null
+++ b/experimental/firefox-esr/stab.h
@@ -0,0 +1,71 @@
+/* $OpenBSD: stab.h,v 1.3 2003/06/02 19:34:12 millert Exp $ */
+/* $NetBSD: stab.h,v 1.4 1994/10/26 00:56:25 cgd Exp $ */
+
+/*-
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)stab.h 5.2 (Berkeley) 4/4/91
+ */
+
+#ifndef _STAB_H_
+#define _STAB_H_
+
+/*
+ * The following are symbols used by various debuggers and by the Pascal
+ * compiler. Each of them must have one (or more) of the bits defined by
+ * the N_STAB mask set.
+ */
+
+#define N_GSYM 0x20 /* global symbol */
+#define N_FNAME 0x22 /* F77 function name */
+#define N_FUN 0x24 /* procedure name */
+#define N_STSYM 0x26 /* data segment variable */
+#define N_LCSYM 0x28 /* bss segment variable */
+#define N_MAIN 0x2a /* main function name */
+#define N_PC 0x30 /* global Pascal symbol */
+#define N_RSYM 0x40 /* register variable */
+#define N_SLINE 0x44 /* text segment line number */
+#define N_DSLINE 0x46 /* data segment line number */
+#define N_BSLINE 0x48 /* bss segment line number */
+#define N_SSYM 0x60 /* structure/union element */
+#define N_SO 0x64 /* main source file name */
+#define N_LSYM 0x80 /* stack variable */
+#define N_BINCL 0x82 /* include file beginning */
+#define N_SOL 0x84 /* included source file name */
+#define N_PSYM 0xa0 /* parameter variable */
+#define N_EINCL 0xa2 /* include file end */
+#define N_ENTRY 0xa4 /* alternate entry point */
+#define N_LBRAC 0xc0 /* left bracket */
+#define N_EXCL 0xc2 /* deleted include file */
+#define N_RBRAC 0xe0 /* right bracket */
+#define N_BCOMM 0xe2 /* begin common */
+#define N_ECOMM 0xe4 /* end common */
+#define N_ECOML 0xe8 /* end common (local name) */
+#define N_LENG 0xfe /* length of preceding entry */
+
+#endif /* !_STAB_H_ */
diff --git a/experimental/firefox-esr/stackwalk-x86-ppc.patch b/experimental/firefox-esr/stackwalk-x86-ppc.patch
new file mode 100644
index 000000000..5a4189847
--- /dev/null
+++ b/experimental/firefox-esr/stackwalk-x86-ppc.patch
@@ -0,0 +1,16 @@
+--- thunderbird-52.6.0/mozglue/misc/StackWalk.cpp
++++ thunderbird-52.6.0/mozglue/misc/StackWalk.cpp
+@@ -41,13 +41,7 @@ static CriticalAddress gCriticalAddress;
+ #define MOZ_STACKWALK_SUPPORTS_MACOSX 0
+ #endif
+
+-#if (defined(linux) && \
+- ((defined(__GNUC__) && (defined(__i386) || defined(PPC))) || \
+- defined(HAVE__UNWIND_BACKTRACE)))
+-#define MOZ_STACKWALK_SUPPORTS_LINUX 1
+-#else
+ #define MOZ_STACKWALK_SUPPORTS_LINUX 0
+-#endif
+
+ #if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 1)
+ #define HAVE___LIBC_STACK_END 1
diff --git a/experimental/firefox-esr/webrtc-broken.patch b/experimental/firefox-esr/webrtc-broken.patch
new file mode 100644
index 000000000..593942fef
--- /dev/null
+++ b/experimental/firefox-esr/webrtc-broken.patch
@@ -0,0 +1,30 @@
+diff -Naur firefox-60.0.orig/media/webrtc/trunk/webrtc/system_wrappers/source/cpu_features_linux.c firefox-60.0/media/webrtc/trunk/webrtc/system_wrappers/source/cpu_features_linux.c
+--- firefox-60.0.orig/media/webrtc/trunk/webrtc/system_wrappers/source/cpu_features_linux.c 2018-05-13 17:33:55.266855917 -0700
++++ firefox-60.0/media/webrtc/trunk/webrtc/system_wrappers/source/cpu_features_linux.c 2018-05-13 20:21:08.158464933 -0700
+@@ -11,7 +11,7 @@
+ #include <stdlib.h>
+ #include <string.h>
+ #include <features.h>
+-#if __GLIBC_PREREQ(2, 16)
++#if __linux__
+ #include <sys/auxv.h>
+ #else
+ #include <fcntl.h>
+@@ -29,7 +29,7 @@
+ int architecture = 0;
+ unsigned long hwcap = 0;
+ const char* platform = NULL;
+-#if __GLIBC_PREREQ(2, 16)
++#if __linux__
+ hwcap = getauxval(AT_HWCAP);
+ platform = (const char*)getauxval(AT_PLATFORM);
+ #else
+@@ -53,7 +53,7 @@
+ }
+ close(fd);
+ }
+-#endif // __GLIBC_PREREQ(2,16)
++#endif // __linux__
+ #if defined(__aarch64__)
+ architecture = 8;
+ if ((hwcap & HWCAP_FP) != 0)