Merge mozilla-central to autoland. CLOSED TREE
authorMihai Alexandru Michis <malexandru@mozilla.com>
Fri, 17 May 2019 12:36:07 +0300
changeset 474311 57c801a17dd68d815240cd760336aee21d247717
parent 474310 139abe6b4223b612cde09672f384f5f7fad7e53b (current diff)
parent 474306 839cdad764d741ab4438b6feabeec749a22b34d5 (diff)
child 474312 4bcfd40cc3a89763d88abafcf71f8bdacd765f67
push id113144
push usershindli@mozilla.com
push dateFri, 17 May 2019 16:44:55 +0000
treeherdermozilla-inbound@f4c4b796f845 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone68.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge mozilla-central to autoland. CLOSED TREE
layout/printing/nsPrintPreviewListener.cpp
layout/printing/nsPrintPreviewListener.h
media/libcubeb/disable-device-switching.patch
netwerk/sctp/datachannel/DataChannel.h
python/mozbuild/mozbuild/vendor_rust.py
toolkit/components/telemetry/tests/marionette/moz.build
--- a/.flake8
+++ b/.flake8
@@ -20,16 +20,17 @@ exclude =
     layout/style,
     media/libdav1d/generate_source.py,
     moz.configure,
     netwerk/dns/prepare_tlds.py,
     netwerk/protocol/http/make_incoming_tables.py,
     python/devtools/migrate-l10n/migrate/main.py,
     python/l10n/fluent_migrations,
     python/mozbuild/dumbmake,
+    python/mozbuild/mozbuild,
     servo/components/style,
     testing/jsshell/benchmark.py,
     testing/marionette/mach_commands.py,
     testing/mozharness/docs,
     testing/mozharness/examples,
     testing/mozharness/external_tools,
     testing/mozharness/mach_commands.py,
     testing/mozharness/manifestparser,
@@ -63,17 +64,16 @@ exclude =
     ipc/chromium/src/third_party/,
     js/*.configure,
     gfx/angle/,
     gfx/harfbuzz,
     gfx/skia/,
     memory/moz.configure,
     mobile/android/*.configure,
     node_modules,
-    python/mozbuild/mozbuild/test/configure/data,
     security/nss/,
     testing/marionette/harness/marionette_harness/runner/mixins,
     testing/marionette/harness/marionette_harness/tests,
     testing/mochitest/pywebsocket,
     testing/mozharness/configs/test/test_malformed.py,
     tools/lint/test/files,
     tools/infer/test/*.configure,
     tools/crashreporter/*.configure,
@@ -87,13 +87,11 @@ ignore =
     F632, F633, F811, E117, W504, W605, W606,
     # These are intentionally disabled (not necessarily for good reason).
     #   F723: syntax error in type comment
     #       text contains quotes which breaks our custom JSON formatter
     F723, E121, E123, E126, E129, E133, E226, E241, E242, E402, E704, E741, W503,
 
 per-file-ignores =
     ipc/ipdl/*: F403, F405
-    # cpp_eclipse has a lot of multi-line embedded XML which exceeds line length
-    python/mozbuild/mozbuild/backend/cpp_eclipse.py: E501
     testing/firefox-ui/**/__init__.py: F401
     testing/marionette/**/__init__.py: F401
     testing/mozharness/configs/*: E124, E127, E128, E131, E231, E261, E265, E266, E501, W391
--- a/devtools/client/netmonitor/test/browser.ini
+++ b/devtools/client/netmonitor/test/browser.ini
@@ -39,16 +39,19 @@ support-files =
   html_sorting-test-page.html
   html_statistics-test-page.html
   html_status-codes-test-page.html
   html_tracking-protection.html
   html_api-calls-test-page.html
   html_copy-as-curl.html
   html_curl-utils.html
   html_open-request-in-tab.html
+  html_worker-test-page.html
+  js_worker-test.js
+  js_worker-test2.js
   sjs_content-type-test-server.sjs
   sjs_cors-test-server.sjs
   sjs_https-redirect-test-server.sjs
   sjs_hsts-test-server.sjs
   sjs_json-test-server.sjs
   sjs_method-test-server.sjs
   sjs_set-cookie-same-site.sjs
   sjs_simple-test-server.sjs
@@ -216,8 +219,9 @@ skip-if = true # Bug 1373558
 [browser_net_timeline_ticks.js]
 skip-if = true # TODO: fix the test
 [browser_net_timing-division.js]
 [browser_net_tracking-resources.js]
 [browser_net_truncate-post-data.js]
 [browser_net_truncate.js]
 [browser_net_view-source-debugger.js]
 [browser_net_waterfall-click.js]
+[browser_net_worker_stacks.js]
--- a/devtools/client/netmonitor/test/browser_net_cause.js
+++ b/devtools/client/netmonitor/test/browser_net_cause.js
@@ -88,71 +88,33 @@ add_task(async function() {
   // all the requests the page is making, not only the XHRs.
   // We can't use about:blank here, because initNetMonitor checks that the
   // page has actually made at least one request.
   const { tab, monitor } = await initNetMonitor(SIMPLE_URL);
 
   const { document, store, windowRequire, connector } = monitor.panelWin;
   const Actions = windowRequire("devtools/client/netmonitor/src/actions/index");
   const {
-    getDisplayedRequests,
     getSortedRequests,
   } = windowRequire("devtools/client/netmonitor/src/selectors/index");
 
   store.dispatch(Actions.batchEnable(false));
 
   const wait = waitForNetworkEvents(monitor, EXPECTED_REQUESTS.length);
   BrowserTestUtils.loadURI(tab.linkedBrowser, CAUSE_URL);
   await wait;
 
   const requests = getSortedRequests(store.getState());
   await Promise.all(requests.map(requestItem =>
     connector.requestData(requestItem.id, "stackTrace")));
 
   is(store.getState().requests.requests.size, EXPECTED_REQUESTS.length,
     "All the page events should be recorded.");
 
-  EXPECTED_REQUESTS.forEach((spec, i) => {
-    const { method, url, causeType, causeUri, stack } = spec;
-
-    const requestItem = getSortedRequests(store.getState()).get(i);
-    verifyRequestItemTarget(
-      document,
-      getDisplayedRequests(store.getState()),
-      requestItem,
-      method,
-      url,
-      { cause: { type: causeType, loadingDocumentUri: causeUri } }
-    );
-
-    const stacktrace = requestItem.stacktrace;
-    const stackLen = stacktrace ? stacktrace.length : 0;
-
-    if (stack) {
-      ok(stacktrace, `Request #${i} has a stacktrace`);
-      ok(stackLen > 0,
-        `Request #${i} (${causeType}) has a stacktrace with ${stackLen} items`);
-
-      // if "stack" is array, check the details about the top stack frames
-      if (Array.isArray(stack)) {
-        stack.forEach((frame, j) => {
-          is(stacktrace[j].functionName, frame.fn,
-            `Request #${i} has the correct function on JS stack frame #${j}`);
-          is(stacktrace[j].filename.split("/").pop(), frame.file,
-            `Request #${i} has the correct file on JS stack frame #${j}`);
-          is(stacktrace[j].lineNumber, frame.line,
-            `Request #${i} has the correct line number on JS stack frame #${j}`);
-          is(stacktrace[j].asyncCause, frame.asyncCause,
-            `Request #${i} has the correct async cause on JS stack frame #${j}`);
-        });
-      }
-    } else {
-      is(stackLen, 0, `Request #${i} (${causeType}) has an empty stacktrace`);
-    }
-  });
+  validateRequests(EXPECTED_REQUESTS, monitor);
 
   // Sort the requests by cause and check the order
   EventUtils.sendMouseEvent({ type: "click" },
     document.querySelector("#requests-list-cause-button"));
   const expectedOrder = EXPECTED_REQUESTS.map(r => r.causeType).sort();
   expectedOrder.forEach((expectedCause, i) => {
     const cause = getSortedRequests(store.getState()).get(i).cause.type;
     is(cause, expectedCause, `The request #${i} has the expected cause after sorting`);
new file mode 100644
--- /dev/null
+++ b/devtools/client/netmonitor/test/browser_net_worker_stacks.js
@@ -0,0 +1,100 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test that we get stack traces for the network requests made when starting or
+// running worker threads.
+
+const TOP_FILE_NAME = "html_worker-test-page.html";
+const TOP_URL = EXAMPLE_URL + TOP_FILE_NAME;
+const WORKER_FILE_NAME = "js_worker-test.js";
+const WORKER_URL = EXAMPLE_URL + WORKER_FILE_NAME;
+
+const EXPECTED_REQUESTS = [
+  {
+    method: "GET",
+    url: TOP_URL,
+    causeType: "document",
+    causeUri: null,
+    stack: true,
+  },
+  {
+    method: "GET",
+    url: WORKER_URL,
+    causeType: "script",
+    causeUri: TOP_URL,
+    stack: [
+      { fn: "startWorkerInner", file: TOP_FILE_NAME, line: 11 },
+      { fn: "startWorker", file: TOP_FILE_NAME, line: 8 },
+      { file: TOP_FILE_NAME, line: 4 },
+    ],
+  },
+  {
+    method: "GET",
+    url: EXAMPLE_URL + "missing1.js",
+    causeType: "script",
+    causeUri: TOP_URL,
+    stack: [
+      { fn: "importScriptsFromWorker", file: WORKER_FILE_NAME, line: 14 },
+      { file: WORKER_FILE_NAME, line: 10 },
+    ],
+  },
+  {
+    method: "GET",
+    url: EXAMPLE_URL + "missing2.js",
+    causeType: "script",
+    causeUri: TOP_URL,
+    stack: [
+      { fn: "importScriptsFromWorker", file: WORKER_FILE_NAME, line: 14 },
+      { file: WORKER_FILE_NAME, line: 10 },
+    ],
+  },
+  {
+    method: "GET",
+    url: EXAMPLE_URL + "js_worker-test2.js",
+    causeType: "script",
+    causeUri: TOP_URL,
+    stack: [
+      { fn: "startWorkerFromWorker", file: WORKER_FILE_NAME, line: 7 },
+      { file: WORKER_FILE_NAME, line: 3 },
+    ],
+  },
+  {
+    method: "GET",
+    url: EXAMPLE_URL + "missing.json",
+    causeType: "xhr",
+    causeUri: TOP_URL,
+    stack: [
+      { fn: "createJSONRequest", file: WORKER_FILE_NAME, line: 22 },
+      { file: WORKER_FILE_NAME, line: 18 },
+    ],
+  },
+];
+
+add_task(async function() {
+  // Load a different URL first to instantiate the network monitor before we
+  // load the page we're really interested in.
+  const { tab, monitor } = await initNetMonitor(SIMPLE_URL);
+
+  const { store, windowRequire, connector } = monitor.panelWin;
+  const {
+    getSortedRequests,
+  } = windowRequire("devtools/client/netmonitor/src/selectors/index");
+
+  BrowserTestUtils.loadURI(tab.linkedBrowser, TOP_URL);
+
+  await waitForNetworkEvents(monitor, EXPECTED_REQUESTS.length);
+
+  is(store.getState().requests.requests.size, EXPECTED_REQUESTS.length,
+    "All the page events should be recorded.");
+
+  // Wait for stack traces from all requests.
+  const requests = getSortedRequests(store.getState());
+  await Promise.all(requests.map(requestItem =>
+    connector.requestData(requestItem.id, "stackTrace")));
+
+  validateRequests(EXPECTED_REQUESTS, monitor);
+
+  await teardown(monitor);
+});
--- a/devtools/client/netmonitor/test/head.js
+++ b/devtools/client/netmonitor/test/head.js
@@ -864,16 +864,63 @@ function queryTelemetryEvents(query) {
     event[2] === query.method &&
     event[3] === object
   );
 
   // Return the `extra` field (which is event[5]e).
   return filtersChangedEvents.map(event => event[5]);
 }
 
+function validateRequests(requests, monitor) {
+  const { document, store, windowRequire } = monitor.panelWin;
+
+  const {
+    getDisplayedRequests,
+  } = windowRequire("devtools/client/netmonitor/src/selectors/index");
+
+  requests.forEach((spec, i) => {
+    const { method, url, causeType, causeUri, stack } = spec;
+
+    const requestItem = getSortedRequests(store.getState()).get(i);
+    verifyRequestItemTarget(
+      document,
+      getDisplayedRequests(store.getState()),
+      requestItem,
+      method,
+      url,
+      { cause: { type: causeType, loadingDocumentUri: causeUri } }
+    );
+
+    const stacktrace = requestItem.stacktrace;
+    const stackLen = stacktrace ? stacktrace.length : 0;
+
+    if (stack) {
+      ok(stacktrace, `Request #${i} has a stacktrace`);
+      ok(stackLen > 0,
+        `Request #${i} (${causeType}) has a stacktrace with ${stackLen} items`);
+
+      // if "stack" is array, check the details about the top stack frames
+      if (Array.isArray(stack)) {
+        stack.forEach((frame, j) => {
+          is(stacktrace[j].functionName, frame.fn,
+            `Request #${i} has the correct function on JS stack frame #${j}`);
+          is(stacktrace[j].filename.split("/").pop(), frame.file,
+            `Request #${i} has the correct file on JS stack frame #${j}`);
+          is(stacktrace[j].lineNumber, frame.line,
+            `Request #${i} has the correct line number on JS stack frame #${j}`);
+          is(stacktrace[j].asyncCause, frame.asyncCause,
+            `Request #${i} has the correct async cause on JS stack frame #${j}`);
+        });
+      }
+    } else {
+      is(stackLen, 0, `Request #${i} (${causeType}) has an empty stacktrace`);
+    }
+  });
+}
+
 /**
  * Retrieve the context menu element corresponding to the provided id, for the provided
  * netmonitor instance.
  */
 function getContextMenuItem(monitor, id) {
   const Menu = require("devtools/client/framework/menu");
   return Menu.getMenuElementById(id, monitor.panelWin.document);
 }
new file mode 100644
--- /dev/null
+++ b/devtools/client/netmonitor/test/html_worker-test-page.html
@@ -0,0 +1,13 @@
+<script>
+/* eslint-disable no-unused-vars */
+"use strict";
+startWorker();
+
+var w;
+function startWorker() {
+  startWorkerInner();
+}
+function startWorkerInner() {
+  w = new Worker("js_worker-test.js");
+}
+</script>
new file mode 100644
--- /dev/null
+++ b/devtools/client/netmonitor/test/js_worker-test.js
@@ -0,0 +1,24 @@
+/* eslint-disable no-unused-vars, no-undef */
+"use strict";
+startWorkerFromWorker();
+
+var w;
+function startWorkerFromWorker() {
+  w = new Worker("js_worker-test2.js");
+}
+
+importScriptsFromWorker();
+
+function importScriptsFromWorker() {
+  try {
+    importScripts("missing1.js", "missing2.js");
+  } catch (e) {}
+}
+
+createJSONRequest();
+
+function createJSONRequest() {
+  const request = new XMLHttpRequest();
+  request.open("GET", "missing.json", true);
+  request.send(null);
+}
new file mode 100644
--- /dev/null
+++ b/devtools/client/netmonitor/test/js_worker-test2.js
@@ -0,0 +1,3 @@
+"use strict";
+
+console.log("I AM A WORKER");
--- a/devtools/server/actors/network-monitor/stack-trace-collector.js
+++ b/devtools/server/actors/network-monitor/stack-trace-collector.js
@@ -20,65 +20,110 @@ function StackTraceCollector(filters, ne
   this.filters = filters;
   this.stacktracesById = new Map();
   this.netmonitors = netmonitors;
 }
 
 StackTraceCollector.prototype = {
   init() {
     Services.obs.addObserver(this, "http-on-opening-request");
+    Services.obs.addObserver(this, "network-monitor-alternate-stack");
     ChannelEventSinkFactory.getService().registerCollector(this);
     this.onGetStack = this.onGetStack.bind(this);
     for (const { messageManager } of this.netmonitors) {
       messageManager.addMessageListener("debug:request-stack:request", this.onGetStack);
     }
   },
 
   destroy() {
     Services.obs.removeObserver(this, "http-on-opening-request");
+    Services.obs.removeObserver(this, "network-monitor-alternate-stack");
     ChannelEventSinkFactory.getService().unregisterCollector(this);
     for (const { messageManager } of this.netmonitors) {
       messageManager.removeMessageListener("debug:request-stack:request",
         this.onGetStack);
     }
   },
 
   _saveStackTrace(channel, stacktrace) {
+    if (this.stacktracesById.has(channel.channelId)) {
+      // We can get up to two stack traces for the same channel: one each from
+      // the two observer topics we are listening to. Use the first stack trace
+      // which is specified, and ignore any later one.
+      return;
+    }
     for (const { messageManager } of this.netmonitors) {
       messageManager.sendAsyncMessage("debug:request-stack-available", {
         channelId: channel.channelId,
         stacktrace: stacktrace && stacktrace.length > 0,
       });
     }
     this.stacktracesById.set(channel.channelId, stacktrace);
   },
 
-  observe(subject) {
+  observe(subject, topic, data) {
     const channel = subject.QueryInterface(Ci.nsIHttpChannel);
 
     if (!matchRequest(channel, this.filters)) {
       return;
     }
 
-    // Convert the nsIStackFrame XPCOM objects to a nice JSON that can be
-    // passed around through message managers etc.
-    let frame = components.stack;
     const stacktrace = [];
-    if (frame && frame.caller) {
-      frame = frame.caller;
-      while (frame) {
-        stacktrace.push({
-          filename: frame.filename,
-          lineNumber: frame.lineNumber,
-          columnNumber: frame.columnNumber,
-          functionName: frame.name,
-          asyncCause: frame.asyncCause,
-        });
-        frame = frame.caller || frame.asyncCaller;
+    switch (topic) {
+      case "http-on-opening-request": {
+        // The channel is being opened on the main thread, associate the current
+        // stack with it.
+        //
+        // Convert the nsIStackFrame XPCOM objects to a nice JSON that can be
+        // passed around through message managers etc.
+        let frame = components.stack;
+        if (frame && frame.caller) {
+          frame = frame.caller;
+          while (frame) {
+            stacktrace.push({
+              filename: frame.filename,
+              lineNumber: frame.lineNumber,
+              columnNumber: frame.columnNumber,
+              functionName: frame.name,
+              asyncCause: frame.asyncCause,
+            });
+            frame = frame.caller || frame.asyncCaller;
+          }
+        }
+        break;
       }
+      case "network-monitor-alternate-stack": {
+        // An alternate stack trace is being specified for this channel.
+        // The topic data is the JSON for the saved frame stack we should use,
+        // so convert this into the expected format.
+        //
+        // This topic is used in the following cases:
+        //
+        // - The HTTP channel is opened asynchronously or on a different thread
+        //   from the code which triggered its creation, in which case the stack
+        //   from components.stack will be empty. The alternate stack will be
+        //   for the point we want to associate with the channel.
+        //
+        // - The channel is not a nsIHttpChannel, and we will receive no
+        //   opening request notification for it.
+        let frame = JSON.parse(data);
+        while (frame) {
+          stacktrace.push({
+            filename: frame.source,
+            lineNumber: frame.line,
+            columnNumber: frame.column,
+            functionName: frame.functionDisplayName,
+            asyncCause: frame.asyncCause,
+          });
+          frame = frame.parent || frame.asyncParent;
+        }
+        break;
+      }
+      default:
+        throw new Error("Unexpected observe() topic");
     }
 
     this._saveStackTrace(channel, stacktrace);
   },
 
   // eslint-disable-next-line no-shadow
   onChannelRedirect(oldChannel, newChannel, flags) {
     // We can be called with any nsIChannel, but are interested only in HTTP channels
--- a/dom/base/nsDOMDataChannel.cpp
+++ b/dom/base/nsDOMDataChannel.cpp
@@ -137,16 +137,18 @@ mozilla::dom::Nullable<uint16_t> nsDOMDa
     const {
   return mDataChannel->GetMaxPacketLifeTime();
 }
 
 mozilla::dom::Nullable<uint16_t> nsDOMDataChannel::GetMaxRetransmits() const {
   return mDataChannel->GetMaxRetransmits();
 }
 
+bool nsDOMDataChannel::Negotiated() const { return mDataChannel->GetNegotiated(); }
+
 bool nsDOMDataChannel::Ordered() const { return mDataChannel->GetOrdered(); }
 
 RTCDataChannelState nsDOMDataChannel::ReadyState() const {
   return static_cast<RTCDataChannelState>(mDataChannel->GetReadyState());
 }
 
 uint32_t nsDOMDataChannel::BufferedAmount() const {
   if (!mSentClose) {
--- a/dom/base/nsDOMDataChannel.h
+++ b/dom/base/nsDOMDataChannel.h
@@ -69,16 +69,17 @@ class nsDOMDataChannel final : public mo
     mBinaryType = static_cast<DataChannelBinaryType>(static_cast<int>(aType));
   }
   void Send(const nsAString& aData, mozilla::ErrorResult& aRv);
   void Send(mozilla::dom::Blob& aData, mozilla::ErrorResult& aRv);
   void Send(const mozilla::dom::ArrayBuffer& aData, mozilla::ErrorResult& aRv);
   void Send(const mozilla::dom::ArrayBufferView& aData,
             mozilla::ErrorResult& aRv);
 
+  bool Negotiated() const;
   bool Ordered() const;
   mozilla::dom::Nullable<uint16_t> GetId() const;
 
   nsresult DoOnMessageAvailable(const nsACString& aMessage, bool aBinary);
 
   virtual nsresult OnMessageAvailable(nsISupports* aContext,
                                       const nsACString& aMessage) override;
 
--- a/dom/webidl/RTCDataChannel.webidl
+++ b/dom/webidl/RTCDataChannel.webidl
@@ -12,16 +12,17 @@ enum RTCDataChannelState {
 enum RTCDataChannelType {
   "arraybuffer",
   "blob"
 };
 
 interface RTCDataChannel : EventTarget
 {
   readonly attribute DOMString label;
+  readonly attribute boolean negotiated;
   readonly attribute boolean ordered;
   readonly attribute boolean reliable;
   readonly attribute unsigned short? maxPacketLifeTime;
   readonly attribute unsigned short? maxRetransmits;
   readonly attribute USVString protocol;
   readonly attribute unsigned short? id;
   readonly attribute RTCDataChannelState readyState;
   readonly attribute unsigned long bufferedAmount;
rename from layout/printing/nsPrintPreviewListener.cpp
rename to layout/printing/PrintPreviewUserEventSuppressor.cpp
--- a/layout/printing/nsPrintPreviewListener.cpp
+++ b/layout/printing/PrintPreviewUserEventSuppressor.cpp
@@ -1,76 +1,59 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* 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/. */
 
-#include "nsPrintPreviewListener.h"
+#include "PrintPreviewUserEventSuppressor.h"
 
 #include "mozilla/TextEvents.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/Event.h"  // for Event
 #include "nsIDOMWindow.h"
 #include "nsPIDOMWindow.h"
 #include "mozilla/dom/Document.h"
 #include "nsIDocShell.h"
 #include "nsPresContext.h"
 #include "nsFocusManager.h"
 #include "nsLiteralString.h"
 
-using namespace mozilla;
 using namespace mozilla::dom;
 
-NS_IMPL_ISUPPORTS(nsPrintPreviewListener, nsIDOMEventListener)
-
-//
-// nsPrintPreviewListener ctor
-//
-nsPrintPreviewListener::nsPrintPreviewListener(EventTarget* aTarget)
-    : mEventTarget(aTarget) {
-  NS_ADDREF_THIS();
-}  // ctor
+namespace mozilla {
 
-nsPrintPreviewListener::~nsPrintPreviewListener() {}
+PrintPreviewUserEventSuppressor::PrintPreviewUserEventSuppressor(
+    EventTarget* aTarget)
+    : mEventTarget(aTarget) {
+  AddListeners();
+}
 
-//-------------------------------------------------------
-//
-// AddListeners
-//
-// Subscribe to the events that will allow us to track various events.
-//
-nsresult nsPrintPreviewListener::AddListeners() {
+NS_IMPL_ISUPPORTS(PrintPreviewUserEventSuppressor, nsIDOMEventListener)
+
+void PrintPreviewUserEventSuppressor::AddListeners() {
   if (mEventTarget) {
     mEventTarget->AddEventListener(NS_LITERAL_STRING("click"), this, true);
     mEventTarget->AddEventListener(NS_LITERAL_STRING("contextmenu"), this,
                                    true);
     mEventTarget->AddEventListener(NS_LITERAL_STRING("keydown"), this, true);
     mEventTarget->AddEventListener(NS_LITERAL_STRING("keypress"), this, true);
     mEventTarget->AddEventListener(NS_LITERAL_STRING("keyup"), this, true);
     mEventTarget->AddEventListener(NS_LITERAL_STRING("mousedown"), this, true);
     mEventTarget->AddEventListener(NS_LITERAL_STRING("mousemove"), this, true);
     mEventTarget->AddEventListener(NS_LITERAL_STRING("mouseout"), this, true);
     mEventTarget->AddEventListener(NS_LITERAL_STRING("mouseover"), this, true);
     mEventTarget->AddEventListener(NS_LITERAL_STRING("mouseup"), this, true);
 
     mEventTarget->AddSystemEventListener(NS_LITERAL_STRING("keydown"), this,
                                          true);
   }
-
-  return NS_OK;
 }
 
-//-------------------------------------------------------
-//
-// RemoveListeners
-//
-// Unsubscribe from all the various events that we were listening to.
-//
-nsresult nsPrintPreviewListener::RemoveListeners() {
+void PrintPreviewUserEventSuppressor::RemoveListeners() {
   if (mEventTarget) {
     mEventTarget->RemoveEventListener(NS_LITERAL_STRING("click"), this, true);
     mEventTarget->RemoveEventListener(NS_LITERAL_STRING("contextmenu"), this,
                                       true);
     mEventTarget->RemoveEventListener(NS_LITERAL_STRING("keydown"), this, true);
     mEventTarget->RemoveEventListener(NS_LITERAL_STRING("keypress"), this,
                                       true);
     mEventTarget->RemoveEventListener(NS_LITERAL_STRING("keyup"), this, true);
@@ -82,34 +65,27 @@ nsresult nsPrintPreviewListener::RemoveL
                                       true);
     mEventTarget->RemoveEventListener(NS_LITERAL_STRING("mouseover"), this,
                                       true);
     mEventTarget->RemoveEventListener(NS_LITERAL_STRING("mouseup"), this, true);
 
     mEventTarget->RemoveSystemEventListener(NS_LITERAL_STRING("keydown"), this,
                                             true);
   }
-
-  return NS_OK;
 }
 
-//-------------------------------------------------------
-//
-// GetActionForEvent
-//
-// Helper function to let certain key events through
-//
 enum eEventAction {
   eEventAction_Tab,
   eEventAction_ShiftTab,
   eEventAction_Propagate,
   eEventAction_Suppress,
   eEventAction_StopPropagation
 };
 
+// Helper function to let certain key events through
 static eEventAction GetActionForEvent(Event* aEvent) {
   WidgetKeyboardEvent* keyEvent = aEvent->WidgetEventPtr()->AsKeyboardEvent();
   if (!keyEvent) {
     return eEventAction_Suppress;
   }
 
   if (keyEvent->mFlags.mInSystemGroup) {
     NS_ASSERTION(keyEvent->mMessage == eKeyDown,
@@ -145,21 +121,21 @@ static eEventAction GetActionForEvent(Ev
       return eEventAction_Propagate;
     }
   }
 
   return eEventAction_Suppress;
 }
 
 NS_IMETHODIMP
-nsPrintPreviewListener::HandleEvent(Event* aEvent) {
+PrintPreviewUserEventSuppressor::HandleEvent(Event* aEvent) {
   nsCOMPtr<nsIContent> content =
       do_QueryInterface(aEvent ? aEvent->GetOriginalTarget() : nullptr);
   if (content && !content->IsXULElement()) {
-    eEventAction action = ::GetActionForEvent(aEvent);
+    eEventAction action = GetActionForEvent(aEvent);
     switch (action) {
       case eEventAction_Tab:
       case eEventAction_ShiftTab: {
         nsAutoString eventString;
         aEvent->GetType(eventString);
         if (eventString.EqualsLiteral("keydown")) {
           // Handle tabbing explicitly here since we don't want focus ending up
           // inside the content document, bug 244128.
@@ -168,20 +144,19 @@ nsPrintPreviewListener::HandleEvent(Even
 
           Document* parentDoc = doc->GetParentDocument();
           NS_ASSERTION(parentDoc, "no parent document");
 
           nsCOMPtr<nsPIDOMWindowOuter> win = parentDoc->GetWindow();
 
           nsIFocusManager* fm = nsFocusManager::GetFocusManager();
           if (fm && win) {
-            dom::Element* fromElement =
-                parentDoc->FindContentForSubDocument(doc);
+            Element* fromElement = parentDoc->FindContentForSubDocument(doc);
             bool forward = (action == eEventAction_Tab);
-            RefPtr<dom::Element> result;
+            RefPtr<Element> result;
             fm->MoveFocus(win, fromElement,
                           forward ? nsIFocusManager::MOVEFOCUS_FORWARD
                                   : nsIFocusManager::MOVEFOCUS_BACKWARD,
                           nsIFocusManager::FLAG_BYKEY, getter_AddRefs(result));
           }
         }
       }
         MOZ_FALLTHROUGH;
@@ -194,8 +169,10 @@ nsPrintPreviewListener::HandleEvent(Even
         break;
       case eEventAction_Propagate:
         // intentionally empty
         break;
     }
   }
   return NS_OK;
 }
+
+}  // namespace mozilla
rename from layout/printing/nsPrintPreviewListener.h
rename to layout/printing/PrintPreviewUserEventSuppressor.h
--- a/layout/printing/nsPrintPreviewListener.h
+++ b/layout/printing/PrintPreviewUserEventSuppressor.h
@@ -1,51 +1,53 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* 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 nsPrintPreviewListener_h__
-#define nsPrintPreviewListener_h__
+#ifndef mozilla_PrintPreviewUserEventSuppressor_h
+#define mozilla_PrintPreviewUserEventSuppressor_h
 
-// Interfaces needed to be included
+#include "nsCOMPtr.h"
 #include "nsIDOMEventListener.h"
-// Helper Classes
-#include "nsCOMPtr.h"
 #include "mozilla/Attributes.h"
 
 namespace mozilla {
+
 namespace dom {
 class EventTarget;
 }  // namespace dom
-}  // namespace mozilla
 
-//
-// class nsPrintPreviewListener
-//
-// The class that listens to the chrome events and tells the embedding
-// chrome to show context menus, as appropriate. Handles registering itself
-// with the DOM with AddChromeListeners() and removing itself with
-// RemoveChromeListeners().
-//
-class nsPrintPreviewListener final : public nsIDOMEventListener
-
-{
+/**
+ * A class that filters out certain user events targeted at the given event
+ * target (a document).  Intended for use with the Print Preview document to
+ * stop users from doing anything that would break printing invariants.  (For
+ * example, blocks opening of the context menu, interaction with form controls,
+ * content selection, etc.)
+ */
+class PrintPreviewUserEventSuppressor final : public nsIDOMEventListener {
  public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIDOMEVENTLISTENER
 
-  explicit nsPrintPreviewListener(mozilla::dom::EventTarget* aTarget);
+  explicit PrintPreviewUserEventSuppressor(dom::EventTarget* aTarget);
 
-  // Add/remove the relevant listeners, based on what interfaces
-  // the embedding chrome implements.
-  nsresult AddListeners();
-  nsresult RemoveListeners();
+  /**
+   * Must be called before releasing this object in order to break the strong
+   * reference cycle between ourselves and the document we're listening to,
+   * or else the objects in the cylce will be leaked (since this class does
+   * not participate in cycle collection).
+   */
+  void StopSuppressing() { RemoveListeners(); }
 
  private:
-  ~nsPrintPreviewListener();
+  ~PrintPreviewUserEventSuppressor() { RemoveListeners(); }
+
+  void AddListeners();
+  void RemoveListeners();
 
   nsCOMPtr<mozilla::dom::EventTarget> mEventTarget;
+};
 
-};  // class nsPrintPreviewListener
+}  // namespace mozilla
 
-#endif /* nsPrintPreviewListener_h__ */
+#endif  // mozilla_PrintPreviewUserEventSuppressor_h
--- a/layout/printing/moz.build
+++ b/layout/printing/moz.build
@@ -23,17 +23,17 @@ XPIDL_MODULE = 'layout_printing'
 UNIFIED_SOURCES += [
     'DrawEventRecorder.cpp',
     'ipc/RemotePrintJobChild.cpp',
     'ipc/RemotePrintJobParent.cpp',
     'nsPagePrintTimer.cpp',
     'nsPrintData.cpp',
     'nsPrintJob.cpp',
     'nsPrintObject.cpp',
-    'nsPrintPreviewListener.cpp',
+    'PrintPreviewUserEventSuppressor.cpp',
     'PrintTranslator.cpp',
 ]
 
 include('/ipc/chromium/chromium-config.mozbuild')
 
 FINAL_LIBRARY = 'xul'
 LOCAL_INCLUDES += [
     '../base',
--- a/layout/printing/nsPrintData.cpp
+++ b/layout/printing/nsPrintData.cpp
@@ -5,19 +5,19 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsPrintData.h"
 
 #include "nsIStringBundle.h"
 #include "nsIServiceManager.h"
 #include "nsIWidget.h"
 #include "nsPrintObject.h"
-#include "nsPrintPreviewListener.h"
 #include "nsIWebProgressListener.h"
 #include "mozilla/Services.h"
+#include "PrintPreviewUserEventSuppressor.h"
 
 //-----------------------------------------------------
 // PR LOGGING
 #include "mozilla/Logging.h"
 
 static mozilla::LazyLogModule gPrintingLog("printing");
 
 #define PR_PL(_p1) MOZ_LOG(gPrintingLog, mozilla::LogLevel::Debug, _p1);
@@ -33,18 +33,17 @@ nsPrintData::nsPrintData(ePrintDataType 
       mOnStartSent(false),
       mIsAborted(false),
       mPreparingForPrint(false),
       mDocWasToBeDestroyed(false),
       mShrinkToFit(false),
       mPrintFrameType(nsIPrintSettings::kFramesAsIs),
       mNumPrintablePages(0),
       mNumPagesPrinted(0),
-      mShrinkRatio(1.0),
-      mPPEventListeners(nullptr) {
+      mShrinkRatio(1.0) {
   nsCOMPtr<nsIStringBundle> brandBundle;
   nsCOMPtr<nsIStringBundleService> svc =
       mozilla::services::GetStringBundleService();
   if (svc) {
     svc->CreateBundle("chrome://branding/locale/brand.properties",
                       getter_AddRefs(brandBundle));
     if (brandBundle) {
       brandBundle->GetStringFromName("brandShortName", mBrandName);
@@ -52,20 +51,19 @@ nsPrintData::nsPrintData(ePrintDataType 
   }
 
   if (mBrandName.IsEmpty()) {
     mBrandName.AssignLiteral(u"Mozilla Document");
   }
 }
 
 nsPrintData::~nsPrintData() {
-  // remove the event listeners
-  if (mPPEventListeners) {
-    mPPEventListeners->RemoveListeners();
-    NS_RELEASE(mPPEventListeners);
+  if (mPPEventSuppressor) {
+    mPPEventSuppressor->StopSuppressing();
+    mPPEventSuppressor = nullptr;
   }
 
   // Only Send an OnEndPrinting if we have started printing
   if (mOnStartSent && mType != eIsPrintPreview) {
     OnEndPrinting();
   }
 
   if (mPrintDC) {
--- a/layout/printing/nsPrintData.h
+++ b/layout/printing/nsPrintData.h
@@ -13,36 +13,41 @@
 // Interfaces
 #include "nsDeviceContext.h"
 #include "nsIPrintProgressParams.h"
 #include "nsIPrintSettings.h"
 #include "nsISupportsImpl.h"
 #include "nsTArray.h"
 #include "nsCOMArray.h"
 
-// Classes
 class nsPrintObject;
-class nsPrintPreviewListener;
 class nsIWebProgressListener;
 
+namespace mozilla {
+class PrintPreviewUserEventSuppressor;
+}  // namespace mozilla
+
 //------------------------------------------------------------------------
 // nsPrintData Class
 //
 // mPreparingForPrint - indicates that we have started Printing but
 //   have not gone to the timer to start printing the pages. It gets turned
 //   off right before we go to the timer.
 //
 // mDocWasToBeDestroyed - Gets set when "someone" tries to unload the document
 //   while we were prparing to Print. This typically happens if a user starts
 //   to print while a page is still loading. If they start printing and pause
 //   at the print dialog and then the page comes in, we then abort printing
 //   because the document is no longer stable.
 //
 //------------------------------------------------------------------------
 class nsPrintData {
+  typedef mozilla::PrintPreviewUserEventSuppressor
+      PrintPreviewUserEventSuppressor;
+
  public:
   typedef enum { eIsPrinting, eIsPrintPreview } ePrintDataType;
 
   explicit nsPrintData(ePrintDataType aType);
 
   NS_INLINE_DECL_REFCOUNTING(nsPrintData)
 
   // Listener Helper Methods
@@ -77,17 +82,17 @@ class nsPrintData {
   bool mDocWasToBeDestroyed;  // see comments above
   bool mShrinkToFit;
   int16_t mPrintFrameType;
   int32_t mNumPrintablePages;
   int32_t mNumPagesPrinted;
   float mShrinkRatio;
 
   nsCOMPtr<nsIPrintSettings> mPrintSettings;
-  nsPrintPreviewListener* mPPEventListeners;
+  RefPtr<PrintPreviewUserEventSuppressor> mPPEventSuppressor;
 
   nsString mBrandName;  //  needed as a substitute name for a document
 
  private:
   nsPrintData() = delete;
   nsPrintData& operator=(const nsPrintData& aOther) = delete;
 
   ~nsPrintData();  // non-virtual
--- a/layout/printing/nsPrintJob.cpp
+++ b/layout/printing/nsPrintJob.cpp
@@ -33,18 +33,16 @@
 #include "nsIServiceManager.h"
 #include "nsGkAtoms.h"
 #include "nsXPCOM.h"
 #include "nsISupportsPrimitives.h"
 
 static const char sPrintSettingsServiceContractID[] =
     "@mozilla.org/gfx/printsettings-service;1";
 
-// Printing Events
-#include "nsPrintPreviewListener.h"
 #include "nsThreadUtils.h"
 
 // Printing
 #include "nsIWebBrowserPrint.h"
 
 // Print Preview
 #include "imgIContainer.h"  // image animation mode constants
 
@@ -111,16 +109,17 @@ static const char kPrintingPromptService
 #include "nsFocusManager.h"
 #include "nsRange.h"
 #include "nsIURIFixup.h"
 #include "mozilla/Components.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/HTMLFrameElement.h"
 #include "nsContentList.h"
 #include "nsIChannel.h"
+#include "PrintPreviewUserEventSuppressor.h"
 #include "xpcpublic.h"
 #include "nsVariant.h"
 #include "mozilla/ServoStyleSet.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 //-----------------------------------------------------
@@ -566,27 +565,26 @@ nsresult nsPrintJob::Cancelled() {
   return NS_ERROR_FAILURE;
 }
 
 //-------------------------------------------------------
 // Install our event listeners on the document to prevent
 // some events from being processed while in PrintPreview
 //
 // No return code - if this fails, there isn't much we can do
-void nsPrintJob::InstallPrintPreviewListener() {
-  if (!mPrt->mPPEventListeners) {
+void nsPrintJob::SuppressPrintPreviewUserEvents() {
+  if (!mPrt->mPPEventSuppressor) {
     nsCOMPtr<nsIDocShell> docShell = do_QueryReferent(mContainer);
     if (!docShell) {
       return;
     }
 
     if (nsPIDOMWindowOuter* win = docShell->GetWindow()) {
       nsCOMPtr<EventTarget> target = win->GetFrameElementInternal();
-      mPrt->mPPEventListeners = new nsPrintPreviewListener(target);
-      mPrt->mPPEventListeners->AddListeners();
+      mPrt->mPPEventSuppressor = new PrintPreviewUserEventSuppressor(target);
     }
   }
 }
 
 //-----------------------------------------------------------------
 nsresult nsPrintJob::GetSeqFrameAndCountPages(nsIFrame*& aSeqFrame,
                                               int32_t& aCount) {
   MOZ_ASSERT(mPrtPreview);
@@ -1002,17 +1000,17 @@ nsresult nsPrintJob::DoCommonPrint(bool 
   if (aIsPrintPreview) {
     bool notifyOnInit = false;
     ShowPrintProgress(false, notifyOnInit);
 
     // Very important! Turn Off scripting
     TurnScriptingOn(false);
 
     if (!notifyOnInit) {
-      InstallPrintPreviewListener();
+      SuppressPrintPreviewUserEvents();
       rv = InitPrintDocConstruction(false);
     } else {
       rv = NS_OK;
     }
   } else {
     bool doNotify;
     ShowPrintProgress(true, doNotify);
     if (!doNotify) {
--- a/layout/printing/nsPrintJob.h
+++ b/layout/printing/nsPrintJob.h
@@ -104,17 +104,23 @@ class nsPrintJob final : public nsIObser
   bool PrintDocContent(const mozilla::UniquePtr<nsPrintObject>& aPO,
                        nsresult& aStatus);
   nsresult DoPrint(const mozilla::UniquePtr<nsPrintObject>& aPO);
 
   void SetPrintPO(nsPrintObject* aPO, bool aPrint);
 
   void TurnScriptingOn(bool aDoTurnOn);
   bool CheckDocumentForPPCaching();
-  void InstallPrintPreviewListener();
+
+  /**
+   * Filters out certain user events while Print Preview is open to prevent
+   * the user from interacting with the Print Preview document and breaking
+   * printing invariants.
+   */
+  void SuppressPrintPreviewUserEvents();
 
   // nsIDocumentViewerPrint Printing Methods
   bool HasPrintCallbackCanvas();
   bool PrePrintPage();
   bool PrintPage(nsPrintObject* aPOect, bool& aInRange);
   bool DonePrintingPages(nsPrintObject* aPO, nsresult aResult);
 
   //---------------------------------------------------------------------
--- a/layout/reftests/display-list/reftest.list
+++ b/layout/reftests/display-list/reftest.list
@@ -36,9 +36,9 @@ skip-if(!asyncPan) == 1437374-1.html 143
 == 1453541-2.html 1453541-ref.html
 == 1452805-1.html 1452805-ref.html
 == 1461231-1.html about:blank
 fuzzy(0-2,0-40000) skip-if(!asyncPan) == 1464288-1.html 1464288-ref.html
 == 1482403-1.html 1482403-1-ref.html
 == 1504233-1.html 1504233-1-ref.html
 == 1533317-1.html 1533317-1-ref.html
 == 1544948-1.html 1544948-1-ref.html
-skip-if(retainedDisplayList) == 1551053-1.html 1551053-1-ref.html
+== 1551053-1.html 1551053-1-ref.html
--- a/layout/reftests/w3c-css/submitted/contain/reftest.list
+++ b/layout/reftests/w3c-css/submitted/contain/reftest.list
@@ -43,16 +43,16 @@ fuzzy-if(webrender&&winWidget,0-24,0-2) 
 == contain-layout-formatting-context-margin-001.html contain-layout-formatting-context-margin-001-ref.html
 == contain-layout-containing-block-fixed-001.html contain-paint-containing-block-fixed-001-ref.html
 == contain-layout-containing-block-absolute-001.html contain-paint-containing-block-absolute-001-ref.html
 == contain-layout-ignored-cases-ib-split-001.html contain-layout-ignored-cases-ib-split-001-ref.html
 == contain-layout-ignored-cases-no-principal-box-001.html contain-paint-ignored-cases-no-principal-box-001-ref.html
 == contain-layout-ignored-cases-no-principal-box-002.html contain-layout-ignored-cases-no-principal-box-002-ref.html
 == contain-layout-ignored-cases-no-principal-box-003.html contain-layout-ignored-cases-no-principal-box-003-ref.html
 == contain-layout-suppress-baseline-001.html contain-layout-suppress-baseline-001-ref.html
-fails == contain-layout-suppress-baseline-002.html contain-layout-suppress-baseline-002-ref.html # bug 1508441
+fails == contain-layout-suppress-baseline-002.html contain-layout-suppress-baseline-002-ref.html # bug 1552287
 
 # The following lines are duplicates of other lines from further up in this
 # manifest. They're listed again here so we can re-run these tests with
 # column-span enabled. These lines can be removed once the pref becomes
 # default-enabled (Bug 1426010).
 pref(layout.css.column-span.enabled,true) == contain-size-multicol-002.html contain-size-multicol-002-ref.html
 pref(layout.css.column-span.enabled,true) == contain-size-multicol-003.html contain-size-multicol-003-ref.html
deleted file mode 100644
--- a/media/libcubeb/disable-device-switching.patch
+++ /dev/null
@@ -1,79 +0,0 @@
-diff --git a/media/libcubeb/src/cubeb_wasapi.cpp b/media/libcubeb/src/cubeb_wasapi.cpp
---- a/media/libcubeb/src/cubeb_wasapi.cpp
-+++ b/media/libcubeb/src/cubeb_wasapi.cpp
-@@ -1829,21 +1829,26 @@ wasapi_stream_init(cubeb * context, cube
-        assert that the lock is held in the function. */
-     auto_lock lock(stm->stream_reset_lock);
-     rv = setup_wasapi_stream(stm.get());
-   }
-   if (rv != CUBEB_OK) {
-     return rv;
-   }
- 
--  HRESULT hr = register_notification_client(stm.get());
--  if (FAILED(hr)) {
--    /* this is not fatal, we can still play audio, but we won't be able
--       to keep using the default audio endpoint if it changes. */
--    LOG("failed to register notification client, %lx", hr);
-+  if (!((input_stream_params ?
-+         (input_stream_params->prefs & CUBEB_STREAM_PREF_DISABLE_DEVICE_SWITCHING) : 0) ||
-+        (output_stream_params ?
-+         (output_stream_params->prefs & CUBEB_STREAM_PREF_DISABLE_DEVICE_SWITCHING) : 0))) {
-+    HRESULT hr = register_notification_client(stm.get());
-+    if (FAILED(hr)) {
-+      /* this is not fatal, we can still play audio, but we won't be able
-+         to keep using the default audio endpoint if it changes. */
-+      LOG("failed to register notification client, %lx", hr);
-+    }
-   }
- 
-   *stream = stm.release();
- 
-   LOG("Stream init succesfull (%p)", *stream);
-   return CUBEB_OK;
- }
- 
-@@ -1879,17 +1884,19 @@ void wasapi_stream_destroy(cubeb_stream 
-   // Only free stm->emergency_bailout if we could join the thread.
-   // If we could not join the thread, stm->emergency_bailout is true
-   // and is still alive until the thread wakes up and exits cleanly.
-   if (stop_and_join_render_thread(stm)) {
-     delete stm->emergency_bailout.load();
-     stm->emergency_bailout = nullptr;
-   }
- 
--  unregister_notification_client(stm);
-+  if (stm->notification_client) {
-+    unregister_notification_client(stm);
-+  }
- 
-   CloseHandle(stm->reconfigure_event);
-   CloseHandle(stm->refill_event);
-   CloseHandle(stm->input_available_event);
- 
-   // The variables intialized in wasapi_stream_init,
-   // must be destroyed in wasapi_stream_destroy.
-   stm->linear_input_buffer.reset();
-diff --git a/media/libcubeb/include/cubeb.h b/media/libcubeb/include/cubeb.h
---- a/media/libcubeb/include/cubeb.h
-+++ a/media/libcubeb/include/cubeb.h
-@@ -222,16 +222,19 @@
- 
- /** Miscellaneous stream preferences. */
- typedef enum {
-   CUBEB_STREAM_PREF_NONE     = 0x00, /**< No stream preferences are requested. */
-   CUBEB_STREAM_PREF_LOOPBACK = 0x01, /**< Request a loopback stream. Should be
-                                          specified on the input params and an
-                                          output device to loopback from should
-                                          be passed in place of an input device. */
-+  CUBEB_STREAM_PREF_DISABLE_DEVICE_SWITCHING = 0x02, /**< Disable switching
-+                                                          default device on OS
-+                                                          changes. */
-   CUBEB_STREAM_PREF_VOICE = 0x04  /**< This stream is going to transport voice data.
-                                        Depending on the backend and platform, this can
-                                        change the audio input or output devices
-                                        selected, as well as the quality of the stream,
-                                        for example to accomodate bluetooth SCO modes on
-                                        bluetooth devices. */
- } cubeb_stream_prefs;
- 
--- a/media/libcubeb/moz.yaml
+++ b/media/libcubeb/moz.yaml
@@ -14,10 +14,10 @@ bugzilla:
 origin:
   name: "cubeb"
   description: "Cross platform audio library"
 
   url: "https://github.com/kinetiknz/cubeb"
   license: "ISC"
 
   # update.sh will update this value
-  release: "64aa80f330a3dc510b1e3ac0e92cc6bed129a9a6 (2019-04-25 17:32:33 +0200)"
+  release: "b9e2c50e51fc58b31b553b5364efacec24ebb76e (2019-05-17 09:21:59 +1200)"
 
--- a/media/libcubeb/update.sh
+++ b/media/libcubeb/update.sh
@@ -85,11 +85,8 @@ if [ -n "$rev" ]; then
   rm moz.yaml.bak
   [[ -n "$commits" ]] && echo -e "Pick commits:\n$commits"
 else
   echo "Remember to update moz.yaml with the version details."
 fi
 
 echo "Applying disable-assert.patch on top of $rev"
 patch -p3 < disable-assert.patch
-
-echo "Applying disable-device-switching.patch on top of $rev"
-patch -p3 < disable-device-switching.patch
--- a/netwerk/sctp/datachannel/DataChannel.h
+++ b/netwerk/sctp/datachannel/DataChannel.h
@@ -385,16 +385,17 @@ class DataChannel {
         mContext(aContext),
         mConnection(connection),
         mLabel(label),
         mProtocol(protocol),
         mState(state),
         mStream(stream),
         mPrPolicy(policy),
         mPrValue(value),
+        mNegotiated(negotiated),
         mOrdered(ordered),
         mFlags(0),
         mId(0),
         mIsRecvBinary(false),
         mBufferedThreshold(0),  // default from spec
         mBufferedAmount(0),
         mMainThreadEventTarget(connection->GetNeckoTarget()) {
     if (!ordered) {
@@ -440,16 +441,18 @@ class DataChannel {
   void SendBinaryBlob(dom::Blob& aBlob, ErrorResult& aRv);
 
   uint16_t GetType() { return mPrPolicy; }
 
   dom::Nullable<uint16_t> GetMaxPacketLifeTime() const;
 
   dom::Nullable<uint16_t> GetMaxRetransmits() const;
 
+  bool GetNegotiated() { return mNegotiated; }
+
   bool GetOrdered() { return mOrdered; }
 
   void IncrementBufferedAmount(uint32_t aSize, ErrorResult& aRv);
   void DecrementBufferedAmount(uint32_t aSize);
 
   // Amount of data buffered to send
   uint32_t GetBufferedAmount() {
     MOZ_ASSERT(NS_IsMainThread());
@@ -494,16 +497,17 @@ class DataChannel {
 
   RefPtr<DataChannelConnection> mConnection;
   nsCString mLabel;
   nsCString mProtocol;
   uint16_t mState;
   uint16_t mStream;
   uint16_t mPrPolicy;
   uint32_t mPrValue;
+  const bool mNegotiated;
   const bool mOrdered;
   uint32_t mFlags;
   uint32_t mId;
   bool mIsRecvBinary;
   size_t mBufferedThreshold;
   // Read/written on main only. Decremented via message-passing, because the
   // spec requires us to queue a task for this.
   size_t mBufferedAmount;
--- a/python/mozbuild/mozbuild/action/buildlist.py
+++ b/python/mozbuild/mozbuild/action/buildlist.py
@@ -12,42 +12,41 @@ from __future__ import absolute_import, 
 import sys
 import os
 
 from mozbuild.util import (
     ensureParentDir,
     lock_file,
 )
 
-
 def addEntriesToListFile(listFile, entries):
-    """Given a file |listFile| containing one entry per line,
-    add each entry in |entries| to the file, unless it is already
-    present."""
-    ensureParentDir(listFile)
-    lock = lock_file(listFile + ".lck")
-    try:
-        if os.path.exists(listFile):
-            f = open(listFile)
-            existing = set(x.strip() for x in f.readlines())
-            f.close()
-        else:
-            existing = set()
-        for e in entries:
-            if e not in existing:
-                existing.add(e)
-        with open(listFile, 'wb') as f:
-            f.write("\n".join(sorted(existing))+"\n")
-    finally:
-        del lock  # Explicitly release the lock_file to free it
+  """Given a file |listFile| containing one entry per line,
+  add each entry in |entries| to the file, unless it is already
+  present."""
+  ensureParentDir(listFile)
+  lock = lock_file(listFile + ".lck")
+  try:
+    if os.path.exists(listFile):
+      f = open(listFile)
+      existing = set(x.strip() for x in f.readlines())
+      f.close()
+    else:
+      existing = set()
+    for e in entries:
+      if e not in existing:
+        existing.add(e)
+    with open(listFile, 'wb') as f:
+      f.write("\n".join(sorted(existing))+"\n")
+  finally:
+    lock = None
 
 
 def main(args):
     if len(args) < 2:
         print("Usage: buildlist.py <list file> <entry> [<entry> ...]",
-              file=sys.stderr)
+            file=sys.stderr)
         return 1
 
     return addEntriesToListFile(args[0], args[1:])
 
 
 if __name__ == '__main__':
     sys.exit(main(sys.argv[1:]))
--- a/python/mozbuild/mozbuild/action/check_binary.py
+++ b/python/mozbuild/mozbuild/action/check_binary.py
@@ -1,13 +1,13 @@
 # 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 absolute_import, print_function, unicode_literals
+from __future__ import print_function, unicode_literals
 
 import argparse
 import os
 import re
 import subprocess
 import sys
 
 from distutils.version import StrictVersion as Version
@@ -275,24 +275,23 @@ def check_networking(binary):
     except Empty:
         raise RuntimeError('Could not parse llvm-objdump output?')
 
     basename = os.path.basename(binary)
     if bad_occurences_names:
         s = 'TEST-UNEXPECTED-FAIL | check_networking | {} | Identified {} ' + \
             'networking function(s) being imported in the rust static library ({})'
         print(s.format(basename, len(bad_occurences_names),
-                       ",".join(sorted(bad_occurences_names))),
-              file=sys.stderr)
+            ",".join(sorted(bad_occurences_names))),
+            file=sys.stderr)
         retcode = 1
     elif buildconfig.substs.get('MOZ_AUTOMATION'):
         print('TEST-PASS | check_networking | {}'.format(basename))
     return retcode
 
-
 def checks(target, binary):
     # The clang-plugin is built as target but is really a host binary.
     # Cheat and pretend we were passed the right argument.
     if 'clang-plugin' in binary:
         target = HOST
     checks = []
     if target['MOZ_LIBSTDCXX_VERSION']:
         checks.append(check_stdcxx)
@@ -341,17 +340,17 @@ def main(args):
 
     if options.host == options.target:
         print('Exactly one of --host or --target must be given',
               file=sys.stderr)
         return 1
 
     if options.networking and options.host:
         print('--networking is only valid with --target',
-              file=sys.stderr)
+               file=sys.stderr)
         return 1
 
     if options.networking:
         return check_networking(options.binary)
     elif options.host:
         return checks(HOST, options.binary)
     elif options.target:
         return checks(TARGET, options.binary)
--- a/python/mozbuild/mozbuild/action/download_wpt_manifest.py
+++ b/python/mozbuild/mozbuild/action/download_wpt_manifest.py
@@ -1,16 +1,15 @@
 # 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/.
 
 # This action is used to generate the wpt manifest
 
-from __future__ import absolute_import, print_function
-
+import os
 import sys
 
 import buildconfig
 
 
 def main():
     print("Downloading wpt manifest")
     sys.path.insert(0, buildconfig.topsrcdir)
--- a/python/mozbuild/mozbuild/action/dump_env.py
+++ b/python/mozbuild/mozbuild/action/dump_env.py
@@ -1,14 +1,12 @@
 # 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 absolute_import, print_function
-
 # We invoke a Python program to dump our environment in order to get
 # native paths printed on Windows so that these paths can be incorporated
 # into Python configure's environment.
 import os
 import sys
 
 sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
 
--- a/python/mozbuild/mozbuild/action/dumpsymbols.py
+++ b/python/mozbuild/mozbuild/action/dumpsymbols.py
@@ -6,17 +6,16 @@ from __future__ import absolute_import, 
 
 import argparse
 import buildconfig
 import subprocess
 import shutil
 import sys
 import os
 
-
 def dump_symbols(target, tracking_file, count_ctors=False):
     # Our tracking file, if present, will contain path(s) to the previously generated
     # symbols. Remove them in this case so we don't simply accumulate old symbols
     # during incremental builds.
     if os.path.isfile(os.path.normpath(tracking_file)):
         with open(tracking_file, 'r') as fh:
             files = fh.read().splitlines()
         dirs = set(os.path.dirname(f) for f in files)
@@ -54,33 +53,31 @@ def dump_symbols(target, tracking_file, 
                                                                      'dist_include'),
                                                         os.path.join(buildconfig.topobjdir,
                                                                      'dist',
                                                                      'include')))
     objcopy = buildconfig.substs.get('OBJCOPY')
     if objcopy:
         os.environ['OBJCOPY'] = objcopy
 
-    args = ([buildconfig.substs['PYTHON'],
-             os.path.join(buildconfig.topsrcdir, 'toolkit',
-                          'crashreporter', 'tools', 'symbolstore.py')] +
+    args = ([buildconfig.substs['PYTHON'], os.path.join(buildconfig.topsrcdir, 'toolkit',
+                                                       'crashreporter', 'tools', 'symbolstore.py')] +
             sym_store_args +
             ['-s', buildconfig.topsrcdir, dump_syms_bin, os.path.join(buildconfig.topobjdir,
                                                                       'dist',
                                                                       'crashreporter-symbols'),
              os.path.abspath(target)])
     if count_ctors:
         args.append('--count-ctors')
     print('Running: %s' % ' '.join(args))
     out_files = subprocess.check_output(args)
     with open(tracking_file, 'w') as fh:
         fh.write(out_files)
         fh.flush()
 
-
 def main(argv):
     parser = argparse.ArgumentParser(
         usage="Usage: dumpsymbols.py <library or program> <tracking file>")
     parser.add_argument("--count-ctors",
                         action="store_true", default=False,
                         help="Count static initializers")
     parser.add_argument("library_or_program",
                         help="Path to library or program")
--- a/python/mozbuild/mozbuild/action/exe_7z_archive.py
+++ b/python/mozbuild/mozbuild/action/exe_7z_archive.py
@@ -1,24 +1,23 @@
 # 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 absolute_import, print_function
+from __future__ import print_function
 
 import os
 import shutil
 import sys
 import subprocess
 import tempfile
 import mozpack.path as mozpath
 import buildconfig
 from mozbuild.base import BuildEnvironmentNotFoundException
 
-
 def archive_exe(pkg_dir, tagfile, sfx_package, package, use_upx):
     tmpdir = tempfile.mkdtemp(prefix='tmp')
     try:
         if pkg_dir:
             shutil.move(pkg_dir, 'core')
 
         if use_upx:
             final_sfx = mozpath.join(tmpdir, '7zSD.sfx')
@@ -26,35 +25,30 @@ def archive_exe(pkg_dir, tagfile, sfx_pa
         else:
             final_sfx = sfx_package
 
         try:
             sevenz = buildconfig.config.substs['7Z']
         except BuildEnvironmentNotFoundException:
             # configure hasn't been run, just use the default
             sevenz = '7z'
-        subprocess.check_call([
-            sevenz, 'a', '-r', '-t7z', mozpath.join(tmpdir, 'app.7z'), '-mx',
-            '-m0=BCJ2', '-m1=LZMA:d25', '-m2=LZMA:d19', '-m3=LZMA:d19', '-mb0:1',
-            '-mb0s1:2', '-mb0s2:3'])
+        subprocess.check_call([sevenz, 'a', '-r', '-t7z', mozpath.join(tmpdir, 'app.7z'), '-mx', '-m0=BCJ2', '-m1=LZMA:d25', '-m2=LZMA:d19', '-m3=LZMA:d19', '-mb0:1', '-mb0s1:2', '-mb0s2:3'])
 
         with open(package, 'wb') as o:
             for i in [final_sfx, tagfile, mozpath.join(tmpdir, 'app.7z')]:
                 shutil.copyfileobj(open(i, 'rb'), o)
         os.chmod(package, 0o0755)
     finally:
         if pkg_dir:
             shutil.move('core', pkg_dir)
         shutil.rmtree(tmpdir)
 
-
 def main(args):
     if len(args) != 4:
         print('Usage: exe_7z_archive.py <pkg_dir> <tagfile> <sfx_package> <package> <use_upx>',
               file=sys.stderr)
         return 1
     else:
         archive_exe(args[0], args[1], args[2], args[3], args[4])
         return 0
 
-
 if __name__ == '__main__':
     sys.exit(main(sys.argv[1:]))
--- a/python/mozbuild/mozbuild/action/exe_7z_extract.py
+++ b/python/mozbuild/mozbuild/action/exe_7z_extract.py
@@ -1,28 +1,25 @@
 # 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 absolute_import, print_function
+from __future__ import print_function
 
 import shutil
 import sys
 import subprocess
 
-
 def extract_exe(package, target):
     subprocess.check_call(['7z', 'x', package, 'core'])
     shutil.move('core', target)
 
-
 def main(args):
     if len(args) != 2:
         print('Usage: exe_7z_extract.py <package> <target>',
               file=sys.stderr)
         return 1
     else:
         extract_exe(args[0], args[1])
         return 0
 
-
 if __name__ == '__main__':
     sys.exit(main(sys.argv[1:]))
--- a/python/mozbuild/mozbuild/action/file_generate.py
+++ b/python/mozbuild/mozbuild/action/file_generate.py
@@ -64,17 +64,17 @@ def main(argv):
               file=sys.stderr)
         return 1
 
     ret = 1
     try:
         with FileAvoidWrite(args.output_file, mode='rb') as output:
             try:
                 ret = module.__dict__[method](output, *args.additional_arguments, **kwargs)
-            except Exception:
+            except:
                 # Ensure that we don't overwrite the file if the script failed.
                 output.avoid_writing_to_file()
                 raise
 
             # The following values indicate a statement of success:
             #  - a set() (see below)
             #  - 0
             #  - False
@@ -111,11 +111,10 @@ def main(argv):
                 output.avoid_writing_to_file()
 
     except IOError as e:
         print('Error opening file "{0}"'.format(e.filename), file=sys.stderr)
         traceback.print_exc()
         return 1
     return ret
 
-
 if __name__ == '__main__':
     sys.exit(main(sys.argv[1:]))
--- a/python/mozbuild/mozbuild/action/generate_searchjson.py
+++ b/python/mozbuild/mozbuild/action/generate_searchjson.py
@@ -1,76 +1,67 @@
 # 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 absolute_import, print_function
-
 import sys
 import json
 import copy
 
 engines = []
 
 locale = sys.argv[2]
 output_file = sys.argv[3]
 
 output = open(output_file, 'w')
 
 with open(sys.argv[1]) as f:
-    searchinfo = json.load(f)
+  searchinfo = json.load(f)
 
 # If we have a locale, use it, otherwise use the default
 if locale in searchinfo["locales"]:
-    localeSearchInfo = searchinfo["locales"][locale]
+  localeSearchInfo = searchinfo["locales"][locale]
 else:
-    localeSearchInfo = {}
-    localeSearchInfo["default"] = searchinfo["default"]
-
+  localeSearchInfo = {}
+  localeSearchInfo["default"] = searchinfo["default"]
 
 def validateDefault(key):
-    if key not in searchinfo["default"]:
-        print("Error: Missing default %s in list.json" % (key), file=sys.stderr)
-        sys.exit(1)
+  if (not key in searchinfo["default"]):
+    print >>sys.stderr, "Error: Missing default %s in list.json" % (key)
+    sys.exit(1)
 
-
-validateDefault("searchDefault")
-validateDefault("visibleDefaultEngines")
+validateDefault("searchDefault");
+validateDefault("visibleDefaultEngines");
 
 # If the selected locale doesn't have a searchDefault,
 # use the global one.
-if "searchDefault" not in localeSearchInfo["default"]:
-    localeSearchInfo["default"]["searchDefault"] = searchinfo["default"]["searchDefault"]
+if not "searchDefault" in localeSearchInfo["default"]:
+  localeSearchInfo["default"]["searchDefault"] = searchinfo["default"]["searchDefault"]
 
 # If the selected locale doesn't have a searchOrder,
 # use the global one if present.
 # searchOrder is NOT required.
-if (
-    "searchOrder" not in localeSearchInfo["default"]
-    and "searchOrder" in searchinfo["default"]
-):
+if not "searchOrder" in localeSearchInfo["default"] and "searchOrder" in searchinfo["default"]:
     localeSearchInfo["default"]["searchOrder"] = searchinfo["default"]["searchOrder"]
 
 # If we have region overrides, enumerate through them
 # and add the additional regions to the locale information.
 if "regionOverrides" in searchinfo:
-    regionOverrides = searchinfo["regionOverrides"]
+  regionOverrides = searchinfo["regionOverrides"]
 
-    for region in regionOverrides:
-        # Only add a new engine list if there is an engine that is overridden
-        enginesToOverride = set(regionOverrides[region].keys())
-        if region in localeSearchInfo and "visibleDefaultEngines" in localeSearchInfo[region]:
-            visibleDefaultEngines = localeSearchInfo[region]["visibleDefaultEngines"]
-        else:
-            visibleDefaultEngines = localeSearchInfo["default"]["visibleDefaultEngines"]
-        if set(visibleDefaultEngines) & enginesToOverride:
-            if region not in localeSearchInfo:
-                localeSearchInfo[region] = {}
-            localeSearchInfo[region]["visibleDefaultEngines"] = copy.deepcopy(
-                visibleDefaultEngines)
-            for i, engine in enumerate(localeSearchInfo[region]["visibleDefaultEngines"]):
-                if engine in regionOverrides[region]:
-                    localeSearchInfo[region]["visibleDefaultEngines"][i] = \
-                        regionOverrides[region][engine]
+  for region in regionOverrides:
+    # Only add a new engine list if there is an engine that is overridden
+    enginesToOverride = set(regionOverrides[region].keys())
+    if region in localeSearchInfo and "visibleDefaultEngines" in localeSearchInfo[region]:
+       visibleDefaultEngines = localeSearchInfo[region]["visibleDefaultEngines"]
+    else:
+       visibleDefaultEngines = localeSearchInfo["default"]["visibleDefaultEngines"]
+    if set(visibleDefaultEngines) & enginesToOverride:
+      if region not in localeSearchInfo:
+        localeSearchInfo[region] = {}
+      localeSearchInfo[region]["visibleDefaultEngines"] = copy.deepcopy(visibleDefaultEngines)
+      for i, engine in enumerate(localeSearchInfo[region]["visibleDefaultEngines"]):
+        if engine in regionOverrides[region]:
+          localeSearchInfo[region]["visibleDefaultEngines"][i] = regionOverrides[region][engine]
 
 output.write(json.dumps(localeSearchInfo, ensure_ascii=False).encode('utf8'))
 
-output.close()
+output.close();
--- a/python/mozbuild/mozbuild/action/generate_strings_xml.py
+++ b/python/mozbuild/mozbuild/action/generate_strings_xml.py
@@ -1,13 +1,13 @@
 # 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 absolute_import, print_function
+from __future__ import absolute_import
 
 import sys
 
 import buildconfig
 
 from mozbuild import preprocessor
 
 
--- a/python/mozbuild/mozbuild/action/generate_suggestedsites.py
+++ b/python/mozbuild/mozbuild/action/generate_suggestedsites.py
@@ -33,19 +33,23 @@ import copy
 import errno
 import json
 import sys
 import os
 
 from mozbuild.dotproperties import (
     DotProperties,
 )
+from mozbuild.util import (
+    FileAvoidWrite,
+)
 from mozpack.files import (
     FileFinder,
 )
+import mozpack.path as mozpath
 
 
 def merge_properties(paths):
     """Merges properties from the given paths."""
     properties = DotProperties()
     for path in paths:
         try:
             properties.update(path)
@@ -83,65 +87,59 @@ def main(output, *args, **kwargs):
         print('Fallback path {fallback} is not a file!'.format(fallback=opts.fallback))
         return 1
 
     # Use reversed order so that the first srcdir has higher priority to override keys.
     sources = [opts.fallback] + list(reversed(opts.inputs))
     properties = merge_properties(sources)
 
     # Keep these two in sync.
-    image_url_template = \
-        'android.resource://%s/drawable/suggestedsites_{name}' % opts.android_package_name
+    image_url_template = 'android.resource://%s/drawable/suggestedsites_{name}' % opts.android_package_name
     drawables_template = 'drawable*/suggestedsites_{name}.*'
 
     # Load properties corresponding to each site name and define their
     # respective image URL.
     sites = []
 
     def add_names(names, defaults={}):
         for name in names:
             site = copy.deepcopy(defaults)
-            site.update(properties.get_dict('browser.suggestedsites.{name}'.format(
-                name=name), required_keys=('title', 'url', 'bgcolor')))
+            site.update(properties.get_dict('browser.suggestedsites.{name}'.format(name=name), required_keys=('title', 'url', 'bgcolor')))
             site['imageurl'] = image_url_template.format(name=name)
             sites.append(site)
 
             # Now check for existence of an appropriately named drawable.  If none
             # exists, throw.  This stops a locale discovering, at runtime, that the
             # corresponding drawable was not added to en-US.
             if not opts.resources:
                 continue
             resources = os.path.abspath(opts.resources)
             finder = FileFinder(resources)
             matches = [p for p, _ in finder.find(drawables_template.format(name=name))]
             if not matches:
                 raise Exception("Could not find drawable in '{resources}' for '{name}'"
-                                .format(resources=resources, name=name))
+                    .format(resources=resources, name=name))
             else:
                 if opts.verbose:
                     print("Found {len} drawables in '{resources}' for '{name}': {matches}"
-                          .format(len=len(matches), resources=resources,
-                                  name=name, matches=matches)
-                          )
+                          .format(len=len(matches), resources=resources, name=name, matches=matches))
 
     # We want the lists to be ordered for reproducibility.  Each list has a
     # "default" JSON list item which will be extended by the properties read.
     lists = [
         ('browser.suggestedsites.list', {}),
         ('browser.suggestedsites.restricted.list', {'restricted': True}),
     ]
     if opts.verbose:
-        print('Reading {len} suggested site lists: {lists}'.format(
-            len=len(lists), lists=[list_name for list_name, _ in lists]))
+        print('Reading {len} suggested site lists: {lists}'.format(len=len(lists), lists=[list_name for list_name, _ in lists]))
 
     for (list_name, list_item_defaults) in lists:
         names = properties.get_list(list_name)
         if opts.verbose:
-            print('Reading {len} suggested sites from {list}: {names}'.format(
-                len=len(names), list=list_name, names=names))
+            print('Reading {len} suggested sites from {list}: {names}'.format(len=len(names), list=list_name, names=names))
         add_names(names, list_item_defaults)
 
     # We must define at least one site -- that's what the fallback is for.
     if not sites:
         print('No sites defined: searched in {}!'.format(sources))
         return 1
 
     json.dump(sites, output)
--- a/python/mozbuild/mozbuild/action/jar_maker.py
+++ b/python/mozbuild/mozbuild/action/jar_maker.py
@@ -1,13 +1,13 @@
 # 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 absolute_import, print_function
+from __future__ import absolute_import
 
 import sys
 
 import mozbuild.jar
 
 
 def main(args):
     return mozbuild.jar.main(args)
--- a/python/mozbuild/mozbuild/action/langpack_manifest.py
+++ b/python/mozbuild/mozbuild/action/langpack_manifest.py
@@ -3,17 +3,17 @@
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 ###
 # This script generates a web manifest JSON file based on the xpi-stage
 # directory structure. It extracts the data from defines.inc files from
 # the locale directory, chrome registry entries and other information
 # necessary to produce the complete manifest file for a language pack.
 ###
-from __future__ import absolute_import, print_function
+from __future__ import absolute_import
 
 import argparse
 import sys
 import os
 import json
 import io
 import datetime
 import requests
@@ -21,16 +21,17 @@ import mozversioncontrol
 import mozpack.path as mozpath
 from mozpack.chrome.manifest import (
     Manifest,
     ManifestLocale,
     parse_manifest,
 )
 from mozbuild.configure.util import Version
 from mozbuild.preprocessor import Preprocessor
+import buildconfig
 
 
 def write_file(path, content):
     with io.open(path, 'w', encoding='utf-8') as out:
         out.write(content + '\n')
 
 
 pushlog_api_url = "{0}/json-rev/{1}"
@@ -302,17 +303,17 @@ def parse_chrome_manifest(path, base_pat
 # Returns:
 #    str - Version to use, may include buildid
 #
 ###
 def get_version_maybe_buildid(min_version):
     version = str(min_version)
     buildid = os.environ.get('MOZ_BUILD_DATE')
     if buildid and len(buildid) != 14:
-        print('Ignoring invalid MOZ_BUILD_DATE: %s' % buildid, file=sys.stderr)
+        print >>sys.stderr, 'Ignoring invalid MOZ_BUILD_DATE: %s' % buildid
         buildid = None
     if buildid:
         version = version + "buildid" + buildid
     return version
 
 
 ###
 # Generates a new web manifest dict with values specific for a language pack.
--- a/python/mozbuild/mozbuild/action/make_dmg.py
+++ b/python/mozbuild/mozbuild/action/make_dmg.py
@@ -1,13 +1,13 @@
 # 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 absolute_import, print_function
+from __future__ import print_function
 
 from mozpack import dmg
 
 import argparse
 import sys
 
 
 def main(args):
--- a/python/mozbuild/mozbuild/action/make_unzip.py
+++ b/python/mozbuild/mozbuild/action/make_unzip.py
@@ -1,26 +1,23 @@
 # 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 absolute_import, print_function
+from __future__ import print_function
 
 import sys
 import subprocess
 
-
 def make_unzip(package):
     subprocess.check_call(['unzip', package])
 
-
 def main(args):
     if len(args) != 1:
         print('Usage: make_unzip.py <package>',
               file=sys.stderr)
         return 1
     else:
         make_unzip(args[0])
         return 0
 
-
 if __name__ == '__main__':
     sys.exit(main(sys.argv[1:]))
--- a/python/mozbuild/mozbuild/action/make_zip.py
+++ b/python/mozbuild/mozbuild/action/make_zip.py
@@ -1,26 +1,23 @@
 # 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 absolute_import, print_function
+from __future__ import print_function
 
 import sys
 import subprocess
 
-
 def make_zip(source, package):
     subprocess.check_call(['zip', '-r9D', package, source, '-x', '\*/.mkdir.done'])
 
-
 def main(args):
     if len(args) != 2:
         print('Usage: make_zip.py <source> <package>',
               file=sys.stderr)
         return 1
     else:
         make_zip(args[0], args[1])
         return 0
 
-
 if __name__ == '__main__':
     sys.exit(main(sys.argv[1:]))
--- a/python/mozbuild/mozbuild/action/output_searchplugins_list.py
+++ b/python/mozbuild/mozbuild/action/output_searchplugins_list.py
@@ -1,35 +1,33 @@
 # 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 absolute_import, print_function
-
 import sys
 import json
 
 engines = []
 
 locale = sys.argv[2]
 
 with open(sys.argv[1]) as f:
-    searchinfo = json.load(f)
+  searchinfo = json.load(f)
 
 # Get a list of the engines from the locale or the default
 engines = set()
 if locale in searchinfo["locales"]:
-    for region, table in searchinfo["locales"][locale].iteritems():
-        if "visibleDefaultEngines" in table:
-            engines.update(table["visibleDefaultEngines"])
+  for region, table in searchinfo["locales"][locale].iteritems():
+    if "visibleDefaultEngines" in table:
+      engines.update(table["visibleDefaultEngines"])
 
 if not engines:
-    engines.update(searchinfo["default"]["visibleDefaultEngines"])
+  engines.update(searchinfo["default"]["visibleDefaultEngines"])
 
 # Get additional engines from regionOverrides
 for region, overrides in searchinfo["regionOverrides"].iteritems():
-    for originalengine, replacement in overrides.iteritems():
-        if originalengine in engines:
-            # We add the engine because we still need the original
-            engines.add(replacement)
+  for originalengine, replacement in overrides.iteritems():
+    if originalengine in engines:
+      # We add the engine because we still need the original
+      engines.add(replacement)
 
 # join() will take an iterable, not just a list.
 print('\n'.join(engines))
--- a/python/mozbuild/mozbuild/action/package_fennec_apk.py
+++ b/python/mozbuild/mozbuild/action/package_fennec_apk.py
@@ -6,16 +6,17 @@
 Script to produce an Android package (.apk) for Fennec.
 '''
 
 from __future__ import absolute_import, print_function
 
 import argparse
 import buildconfig
 import os
+import subprocess
 import sys
 
 from mozpack.copier import Jarrer
 from mozpack.files import (
     DeflatedFile,
     File,
     FileFinder,
 )
@@ -64,17 +65,17 @@ def package_fennec_apk(inputs=[], omni_j
                 jarrer.remove(path)
             jarrer.add(path, DeflatedFile(file), compress=file.compressed)
 
     def add(path, file, compress=None):
         abspath = os.path.abspath(file.path)
         if verbose:
             print('Packaging %s from %s' % (path, file.path))
         if not os.path.exists(abspath):
-            raise ValueError('File %s not found (looked for %s)' %
+            raise ValueError('File %s not found (looked for %s)' % \
                              (file.path, abspath))
         if jarrer.contains(path):
             jarrer.remove(path)
         jarrer.add(path, file, compress=compress)
 
     for features_dir in features_dirs:
         finder = FileFinder(features_dir)
         for p, f in finder.find('**'):
--- a/python/mozbuild/mozbuild/action/package_generated_sources.py
+++ b/python/mozbuild/mozbuild/action/package_generated_sources.py
@@ -1,40 +1,40 @@
 # 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 absolute_import, print_function, unicode_literals
 
 import argparse
+import json
+import os.path
 import sys
 
 import buildconfig
 import mozpack.path as mozpath
 from mozpack.archive import create_tar_gz_from_files
 from mozpack.files import BaseFile
 from mozbuild.generated_sources import get_generated_sources
 
 
 def main(argv):
     parser = argparse.ArgumentParser(
         description='Produce archive of generated sources')
     parser.add_argument('outputfile', help='File to write output to')
     args = parser.parse_args(argv)
 
     objdir_abspath = mozpath.abspath(buildconfig.topobjdir)
-
     def is_valid_entry(entry):
         if isinstance(entry[1], BaseFile):
             entry_abspath = mozpath.abspath(entry[1].path)
         else:
             entry_abspath = mozpath.abspath(entry[1])
         if not entry_abspath.startswith(objdir_abspath):
-            print("Warning: omitting generated source [%s] from archive" % entry_abspath,
-                  file=sys.stderr)
+            print("Warning: omitting generated source [%s] from archive" % entry_abspath, file=sys.stderr)
             return False
         return True
 
     files = dict(filter(is_valid_entry, get_generated_sources()))
     with open(args.outputfile, 'wb') as fh:
         create_tar_gz_from_files(fh, files, compresslevel=5)
 
 
--- a/python/mozbuild/mozbuild/action/preprocessor.py
+++ b/python/mozbuild/mozbuild/action/preprocessor.py
@@ -1,25 +1,24 @@
 # 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 absolute_import, print_function
+from __future__ import absolute_import
 
 import sys
 
 from mozbuild.preprocessor import Preprocessor
 
 
 def generate(output, *args):
     pp = Preprocessor()
     pp.out = output
     pp.handleCommandLine(list(args), True)
     return set(pp.includes)
 
-
 def main(args):
     pp = Preprocessor()
     pp.handleCommandLine(args, True)
 
 
 if __name__ == "__main__":
-    main(sys.argv[1:])
+  main(sys.argv[1:])
--- a/python/mozbuild/mozbuild/action/process_define_files.py
+++ b/python/mozbuild/mozbuild/action/process_define_files.py
@@ -5,16 +5,17 @@
 from __future__ import absolute_import, print_function, unicode_literals
 
 import argparse
 import os
 import re
 import sys
 from buildconfig import topsrcdir, topobjdir
 from mozbuild.backend.configenvironment import PartialConfigEnvironment
+from mozbuild.util import FileAvoidWrite
 import mozpack.path as mozpath
 
 
 def process_define_file(output, input):
     '''Creates the given config header. A config header is generated by
     taking the corresponding source file and replacing some #define/#undef
     occurences:
         "#undef NAME" is turned into "#define NAME VALUE"
@@ -45,22 +46,21 @@ def process_define_file(output, input):
                 name = m.group('name')
                 value = m.group('value')
                 if name:
                     if name == 'ALLDEFINES':
                         if cmd == 'define':
                             raise Exception(
                                 '`#define ALLDEFINES` is not allowed in a '
                                 'CONFIGURE_DEFINE_FILE')
-
+                        # WebRTC files like to define WINVER and _WIN32_WINNT
+                        # via the command line, which raises a mass of macro
+                        # redefinition warnings.  Just handle those macros
+                        # specially here.
                         def define_for_name(name, val):
-                            """WebRTC files like to define WINVER and _WIN32_WINNT
-                            via the command line, which raises a mass of macro
-                            redefinition warnings.  Just handle those macros
-                            specially here."""
                             define = "#define {name} {val}".format(name=name, val=val)
                             if name in ('WINVER', '_WIN32_WINNT'):
                                 return '#if !defined({name})\n{define}\n#endif' \
                                     .format(name=name, define=define)
                             return define
                         defines = '\n'.join(sorted(
                             define_for_name(name, val)
                             for name, val in config.defines['ALLDEFINES'].iteritems()))
--- a/python/mozbuild/mozbuild/action/process_install_manifest.py
+++ b/python/mozbuild/mozbuild/action/process_install_manifest.py
@@ -24,91 +24,90 @@ from mozbuild.util import DefinesAction
 
 
 COMPLETE = 'Elapsed: {elapsed:.2f}s; From {dest}: Kept {existing} existing; ' \
     'Added/updated {updated}; ' \
     'Removed {rm_files} files and {rm_dirs} directories.'
 
 
 def process_manifest(destdir, paths, track,
-                     no_symlinks=False,
-                     defines={}):
+        no_symlinks=False,
+        defines={}):
 
     if os.path.exists(track):
         # We use the same format as install manifests for the tracking
         # data.
         manifest = InstallManifest(path=track)
         remove_unaccounted = FileRegistry()
         dummy_file = BaseFile()
 
         finder = FileFinder(destdir, find_dotfiles=True)
         for dest in manifest._dests:
             for p, f in finder.find(dest):
                 remove_unaccounted.add(p, dummy_file)
 
-        remove_empty_directories = True
-        remove_all_directory_symlinks = True
+        remove_empty_directories=True
+        remove_all_directory_symlinks=True
 
     else:
         # If tracking is enabled and there is no file, we don't want to
         # be removing anything.
         remove_unaccounted = False
-        remove_empty_directories = False
-        remove_all_directory_symlinks = False
+        remove_empty_directories=False
+        remove_all_directory_symlinks=False
 
     manifest = InstallManifest()
     for path in paths:
         manifest |= InstallManifest(path=path)
 
     copier = FileCopier()
     link_policy = "copy" if no_symlinks else "symlink"
     manifest.populate_registry(
         copier, defines_override=defines, link_policy=link_policy
     )
     result = copier.copy(destdir,
-                         remove_unaccounted=remove_unaccounted,
-                         remove_all_directory_symlinks=remove_all_directory_symlinks,
-                         remove_empty_directories=remove_empty_directories)
+        remove_unaccounted=remove_unaccounted,
+        remove_all_directory_symlinks=remove_all_directory_symlinks,
+        remove_empty_directories=remove_empty_directories)
 
     if track:
         # We should record files that we actually copied.
         # It is too late to expand wildcards when the track file is read.
         manifest.write(path=track, expand_pattern=True)
 
     return result
 
 
 def main(argv):
     parser = argparse.ArgumentParser(
         description='Process install manifest files.')
 
     parser.add_argument('destdir', help='Destination directory.')
     parser.add_argument('manifests', nargs='+', help='Path to manifest file(s).')
     parser.add_argument('--no-symlinks', action='store_true',
-                        help='Do not install symbolic links. Always copy files')
+        help='Do not install symbolic links. Always copy files')
     parser.add_argument('--track', metavar="PATH", required=True,
-                        help='Use installed files tracking information from the given path.')
+        help='Use installed files tracking information from the given path.')
     parser.add_argument('-D', action=DefinesAction,
-                        dest='defines', metavar="VAR[=VAL]",
-                        help='Define a variable to override what is specified in the manifest')
+        dest='defines', metavar="VAR[=VAL]",
+        help='Define a variable to override what is specified in the manifest')
 
     args = parser.parse_args(argv)
 
     start = time.time()
 
     result = process_manifest(args.destdir, args.manifests,
-                              track=args.track,
-                              no_symlinks=args.no_symlinks,
-                              defines=args.defines)
+        track=args.track,
+        no_symlinks=args.no_symlinks,
+        defines=args.defines)
 
     elapsed = time.time() - start
 
     print(COMPLETE.format(
         elapsed=elapsed,
         dest=args.destdir,
         existing=result.existing_files_count,
         updated=result.updated_files_count,
         rm_files=result.removed_files_count,
         rm_dirs=result.removed_directories_count))
 
-
 if __name__ == '__main__':
     main(sys.argv[1:])
--- a/python/mozbuild/mozbuild/action/symbols_archive.py
+++ b/python/mozbuild/mozbuild/action/symbols_archive.py
@@ -7,49 +7,45 @@ from __future__ import absolute_import, 
 import argparse
 import sys
 import os
 
 from mozpack.files import FileFinder
 from mozpack.mozjar import JarWriter
 import mozpack.path as mozpath
 
-
 def make_archive(archive_name, base, exclude, include):
     compress = ['**/*.sym']
     finder = FileFinder(base, ignore=exclude)
     if not include:
         include = ['*']
     archive_basename = os.path.basename(archive_name)
     with open(archive_name, 'wb') as fh:
         with JarWriter(fileobj=fh, compress_level=5) as writer:
             for pat in include:
                 for p, f in finder.find(pat):
                     print('  Adding to "%s":\n\t"%s"' % (archive_basename, p))
                     should_compress = any(mozpath.match(p, pat) for pat in compress)
                     writer.add(p.encode('utf-8'), f, mode=f.mode,
                                compress=should_compress, skip_duplicates=True)
 
-
 def main(argv):
     parser = argparse.ArgumentParser(description='Produce a symbols archive')
     parser.add_argument('archive', help='Which archive to generate')
     parser.add_argument('base', help='Base directory to package')
-    parser.add_argument('--full-archive', action='store_true',
-                        help='Generate a full symbol archive')
+    parser.add_argument('--full-archive', action='store_true', help='Generate a full symbol archive')
 
     args = parser.parse_args(argv)
 
     excludes = []
     includes = []
 
     if args.full_archive:
         # We allow symbols for tests to be included when building on try
         if os.environ.get('MH_BRANCH', 'unknown') != 'try':
             excludes = ['*test*', '*Test*']
     else:
         includes = ['**/*.sym']
 
     make_archive(args.archive, args.base, excludes, includes)
 
-
 if __name__ == '__main__':
     main(sys.argv[1:])
--- a/python/mozbuild/mozbuild/action/test_archive.py
+++ b/python/mozbuild/mozbuild/action/test_archive.py
@@ -637,17 +637,17 @@ if buildconfig.substs.get('commtopsrcdir
 # Verify nothing sneaks into ARCHIVE_FILES without a corresponding exclusion
 # rule in the "common" archive.
 for k, v in ARCHIVE_FILES.items():
     # Skip mozharness because it isn't staged.
     if k in ('common', 'mozharness'):
         continue
 
     ignores = set(itertools.chain(*(e.get('ignore', [])
-                                    for e in ARCHIVE_FILES['common'])))
+                                  for e in ARCHIVE_FILES['common'])))
 
     if not any(p.startswith('%s/' % k) for p in ignores):
         raise Exception('"common" ignore list probably should contain %s' % k)
 
 
 def find_generated_harness_files():
     # TEST_HARNESS_FILES end up in an install manifest at
     # $topsrcdir/_build_manifests/install/_tests.
--- a/python/mozbuild/mozbuild/action/tooltool.py
+++ b/python/mozbuild/mozbuild/action/tooltool.py
@@ -12,18 +12,16 @@
 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 # GNU General Public License for more details.
 #
 # You should have received a copy of the GNU General Public License
 # along with this program; if not, write to the Free Software
 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 # 02110-1301, USA.
 
-from __future__ import absolute_import, print_function
-
 # A manifest file specifies files in that directory that are stored
 # elsewhere. This file should only list files in the same directory
 # in which the manifest file resides and it should be called
 # 'manifest.tt'
 
 from __future__ import print_function
 
 import base64
@@ -745,17 +743,17 @@ CHECKSUM_SUFFIX = ".checksum"
 def _cache_checksum_matches(base_file, checksum):
     try:
         with open(base_file + CHECKSUM_SUFFIX, "rb") as f:
             prev_checksum = f.read().strip()
             if prev_checksum == checksum:
                 log.info("Cache matches, avoiding extracting in '%s'" % base_file)
                 return True
             return False
-    except IOError:
+    except IOError as e:
         return False
 
 
 def _compute_cache_checksum(filename):
     with open(filename, "rb") as f:
         return digest_file(f, "sha256")
 
 
@@ -1019,17 +1017,17 @@ def _authorize(req, auth_file):
         return
 
     is_taskcluster_auth = False
     with open(auth_file) as f:
         auth_file_content = f.read().strip()
         try:
             auth_file_content = json.loads(auth_file_content)
             is_taskcluster_auth = True
-        except Exception:
+        except:
             pass
 
     if is_taskcluster_auth:
         taskcluster_header = make_taskcluster_header(auth_file_content, req)
         log.debug("Using taskcluster credentials in %s" % auth_file)
         req.add_unredirected_header('Authorization', taskcluster_header)
     else:
         log.debug("Using Bearer token in %s" % auth_file)
@@ -1297,11 +1295,10 @@ def main(argv, _skip_logging=False):
     if options['algorithm'] != 'sha512':
         parser.error('only --algorithm sha512 is supported')
 
     if len(args) < 1:
         parser.error('You must specify a command')
 
     return 0 if process_command(options, args) else 1
 
-
 if __name__ == "__main__":  # pragma: no cover
     sys.exit(main(sys.argv))
--- a/python/mozbuild/mozbuild/action/unpack_dmg.py
+++ b/python/mozbuild/mozbuild/action/unpack_dmg.py
@@ -1,13 +1,13 @@
 # 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 absolute_import, print_function
+from __future__ import print_function
 
 from mozpack import dmg
 
 import argparse
 import sys
 
 
 def main(args):
--- a/python/mozbuild/mozbuild/action/webidl.py
+++ b/python/mozbuild/mozbuild/action/webidl.py
@@ -1,13 +1,13 @@
 # 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 absolute_import, print_function
+from __future__ import absolute_import
 
 import sys
 
 from mozwebidlcodegen import BuildSystemWebIDL
 
 
 def main(argv):
     """Perform WebIDL code generation required by the build system."""
--- a/python/mozbuild/mozbuild/action/wrap_rustc.py
+++ b/python/mozbuild/mozbuild/action/wrap_rustc.py
@@ -4,17 +4,16 @@
 
 from __future__ import absolute_import, print_function, unicode_literals
 
 import argparse
 import subprocess
 import sys
 import os
 
-
 def parse_outputs(crate_output, dep_outputs, pass_l_flag):
     env = {}
     args = []
 
     def parse_line(line):
         if line.startswith('cargo:'):
             return line[len('cargo:'):].split('=', 1)
 
@@ -55,26 +54,24 @@ def parse_outputs(crate_output, dep_outp
             elif key:
                 # Todo: Distinguish between direct and transitive
                 # dependencies so we can pass metadata environment
                 # variables correctly.
                 pass
 
     return env, args
 
-
 def wrap_rustc(args):
     parser = argparse.ArgumentParser()
     parser.add_argument('--crate-out', nargs='?')
     parser.add_argument('--deps-out', nargs='*')
     parser.add_argument('--cwd')
     parser.add_argument('--pass-l-flag', action='store_true')
     parser.add_argument('--cmd', nargs=argparse.REMAINDER)
     args = parser.parse_args(args)
 
     new_env, new_args = parse_outputs(args.crate_out, args.deps_out,
                                       args.pass_l_flag)
     os.environ.update(new_env)
     return subprocess.Popen(args.cmd + new_args, cwd=args.cwd).wait()
 
-
 if __name__ == '__main__':
     sys.exit(wrap_rustc(sys.argv[1:]))
--- a/python/mozbuild/mozbuild/action/xpccheck.py
+++ b/python/mozbuild/mozbuild/action/xpccheck.py
@@ -3,98 +3,81 @@
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 '''A generic script to verify all test files are in the
 corresponding .ini file.
 
 Usage: xpccheck.py <directory> [<directory> ...]
 '''
 
-from __future__ import absolute_import, print_function
+from __future__ import absolute_import
 
 import sys
 import os
 from glob import glob
 import manifestparser
 
-
 def getIniTests(testdir):
-    mp = manifestparser.ManifestParser(strict=False)
-    mp.read(os.path.join(testdir, 'xpcshell.ini'))
-    return mp.tests
-
+  mp = manifestparser.ManifestParser(strict=False)
+  mp.read(os.path.join(testdir, 'xpcshell.ini'))
+  return mp.tests
 
 def verifyDirectory(initests, directory):
-    files = glob(os.path.join(os.path.abspath(directory), "test_*"))
-    for f in files:
-        if (not os.path.isfile(f)):
-            continue
+  files = glob(os.path.join(os.path.abspath(directory), "test_*"))
+  for f in files:
+    if (not os.path.isfile(f)):
+      continue
 
-        name = os.path.basename(f)
-        if name.endswith('.in'):
-            name = name[:-3]
-
-        if not name.endswith('.js'):
-            continue
+    name = os.path.basename(f)
+    if name.endswith('.in'):
+      name = name[:-3]
 
-        found = False
-        for test in initests:
-            if os.path.join(os.path.abspath(directory), name) == test['path']:
-                found = True
-                break
+    if not name.endswith('.js'):
+      continue
 
-        if not found:
-            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)
-
+    found = False
+    for test in initests:
+      if os.path.join(os.path.abspath(directory), name) == test['path']:
+        found = True
+        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'))
+      sys.exit(1)
 
 def verifyIniFile(initests, directory):
-    files = glob(os.path.join(os.path.abspath(directory), "test_*"))
-    for test in initests:
-        name = test['path'].split('/')[-1]
+  files = glob(os.path.join(os.path.abspath(directory), "test_*"))
+  for test in initests:
+    name = test['path'].split('/')[-1]
 
-        found = False
-        for f in files:
-
-            fname = f.split('/')[-1]
-            if fname.endswith('.in'):
-                fname = '.in'.join(fname.split('.in')[:-1])
+    found = False
+    for f in files:
 
-            if os.path.join(os.path.abspath(directory), fname) == test['path']:
-                found = True
-                break
+      fname = f.split('/')[-1]
+      if fname.endswith('.in'):
+        fname = '.in'.join(fname.split('.in')[:-1])
 
-        if not found:
-            print(("TEST-UNEXPECTED-FAIL | xpccheck | found "
-                   "%s in xpcshell.ini and not in directory '%s'") % (
-                    name,
-                    directory,
-                    ),
-                  file=sys.stderr,
-                  )
-            sys.exit(1)
+      if os.path.join(os.path.abspath(directory), fname) == test['path']:
+        found = True
+        break
 
+    if not found:
+      print >>sys.stderr, "TEST-UNEXPECTED-FAIL | xpccheck | found %s in xpcshell.ini and not in directory '%s'" % (name, directory)
+      sys.exit(1)
 
 def main(argv):
-    if len(argv) < 2:
-        print("Usage: xpccheck.py <topsrcdir> <directory> [<directory> ...]",
-              file=sys.stderr)
-        sys.exit(1)
+  if len(argv) < 2:
+    print >>sys.stderr, "Usage: xpccheck.py <topsrcdir> <directory> [<directory> ...]"
+    sys.exit(1)
 
-    for d in argv[1:]:
-        # xpcshell-unpack is a copy of xpcshell sibling directory and in the Makefile
-        # we copy all files (including xpcshell.ini from the sibling directory.
-        if d.endswith('toolkit/mozapps/extensions/test/xpcshell-unpack'):
-            continue
+  topsrcdir = argv[0]
+  for d in argv[1:]:
+    # xpcshell-unpack is a copy of xpcshell sibling directory and in the Makefile
+    # we copy all files (including xpcshell.ini from the sibling directory.
+    if d.endswith('toolkit/mozapps/extensions/test/xpcshell-unpack'):
+      continue
 
-        initests = getIniTests(d)
-        verifyDirectory(initests, d)
-        verifyIniFile(initests, d)
-
+    initests = getIniTests(d)
+    verifyDirectory(initests, d)
+    verifyIniFile(initests, d)
 
 if __name__ == '__main__':
     main(sys.argv[1:])
--- a/python/mozbuild/mozbuild/action/xpidl-process.py
+++ b/python/mozbuild/mozbuild/action/xpidl-process.py
@@ -2,22 +2,24 @@
 # 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/.
 
 # This script is used to generate an output header and xpt file for
 # 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, print_function
+from __future__ import absolute_import
 
 import argparse
 import os
 import sys
 
+from io import BytesIO
+
 from xpidl import jsonxpt
 from buildconfig import topsrcdir
 from xpidl.header import print_header
 from xpidl.rust import print_rust_bindings
 from xpidl.rust_macros import print_rust_macros_bindings
 from xpidl.xpidl import IDLParser
 
 from mozbuild.makeutil import Makefile
@@ -80,38 +82,37 @@ def process(input_dirs, inc_paths, bindi
         deps_path = os.path.join(deps_dir, '%s.pp' % module)
         with FileAvoidWrite(deps_path) as fh:
             mk.dump(fh)
 
 
 def main(argv):
     parser = argparse.ArgumentParser()
     parser.add_argument('--cache-dir',
-                        help='Directory in which to find or write cached lexer data.')
+        help='Directory in which to find or write cached lexer data.')
     parser.add_argument('--depsdir',
-                        help='Directory in which to write dependency files.')
+        help='Directory in which to write dependency files.')
     parser.add_argument('--bindings-conf',
-                        help='Path to the WebIDL binding configuration file.')
+        help='Path to the WebIDL binding configuration file.')
     parser.add_argument('--input-dir', dest='input_dirs',
                         action='append', default=[],
                         help='Directory(ies) in which to find source .idl files.')
     parser.add_argument('headerdir',
-                        help='Directory in which to write header files.')
+        help='Directory in which to write header files.')
     parser.add_argument('xpcrsdir',
-                        help='Directory in which to write rust xpcom binding files.')
+        help='Directory in which to write rust xpcom binding files.')
     parser.add_argument('xptdir',
-                        help='Directory in which to write xpt file.')
+        help='Directory in which to write xpt file.')
     parser.add_argument('module',
-                        help='Final module name to use for linked output xpt file.')
+        help='Final module name to use for linked output xpt file.')
     parser.add_argument('idls', nargs='+',
-                        help='Source .idl file(s).')
+        help='Source .idl file(s).')
     parser.add_argument('-I', dest='incpath', action='append', default=[],
-                        help='Extra directories where to look for included .idl files.')
+        help='Extra directories where to look for included .idl files.')
 
     args = parser.parse_args(argv)
     incpath = [os.path.join(topsrcdir, p) for p in args.incpath]
     process(args.input_dirs, incpath, args.bindings_conf, args.cache_dir,
-            args.headerdir, args.xpcrsdir, args.xptdir, args.depsdir, args.module,
-            args.idls)
-
+        args.headerdir, args.xpcrsdir, args.xptdir, args.depsdir, args.module,
+        args.idls)
 
 if __name__ == '__main__':
     main(sys.argv[1:])
--- a/python/mozbuild/mozbuild/action/zip.py
+++ b/python/mozbuild/mozbuild/action/zip.py
@@ -1,16 +1,16 @@
 # 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/.
 
 # 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, print_function
+from __future__ import absolute_import
 
 from mozpack.files import FileFinder
 from mozpack.copier import Jarrer
 from mozpack.errors import errors
 from mozpack.path import match
 
 import argparse
 import mozpack.path as mozpath
--- a/python/mozbuild/mozbuild/analyze/graph.py
+++ b/python/mozbuild/mozbuild/analyze/graph.py
@@ -1,18 +1,15 @@
 # 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 absolute_import, print_function
-
 import os
 import sqlite3 as lite
 
-
 class Node(object):
 
     def __init__(self, graph, node_id):
         sql_result = graph.query_arg('SELECT id, dir, type, mtime, name \
             FROM node WHERE id=?', (node_id,)).fetchone()
         self.id, self.dir, self.type, self.mtime, self.name = sql_result
         children = graph.query_arg('SELECT to_id FROM \
             normal_link WHERE from_id=?', (self.id,)).fetchall()
@@ -37,22 +34,21 @@ class Node(object):
 
     def get_path(self, graph):
         if self.dir == 1:
             return self.name
         parent = graph.get_node(self.dir)
         return os.path.join(parent.get_path(graph), self.name)
 
     def calculate_mtime(self):
-        if self.type == 0:  # only files have meaningful costs
+        if self.type == 0: # only files have meaningful costs
             return sum(x.mtime for x in self.cmds)
         else:
             return None
 
-
 class Graph(object):
 
     def __init__(self, path=None, connect=None):
         self.connect = connect
         if path is not None:
             self.connect = lite.connect(path)
         elif self.connect is None:
             raise Exception
@@ -66,17 +62,17 @@ class Graph(object):
         tables = [x[0] for x in self.query_arg('SELECT name \
             FROM sqlite_master WHERE type=?', ('table',)).fetchall()]
         return ('node' in tables and 'normal_link' in tables)
 
     def close(self):
         self.connect.close()
 
     def query_arg(self, q, arg):
-        assert isinstance(arg, tuple)  # execute() requires tuple argument
+        assert isinstance(arg, tuple) #execute() requires tuple argument
         cursor = self.connect.cursor()
         cursor.execute(q, arg)
         return cursor
 
     def query(self, q):
         cursor = self.connect.cursor()
         cursor.execute(q)
         return cursor
@@ -89,17 +85,17 @@ class Graph(object):
         self.node_dict[k] = v
 
     def get_id(self, filepath):
         nodeid = 1
         for part in filepath.split('/'):
             ret = self.query_arg('SELECT id FROM node \
                 WHERE dir=? AND name=?', (nodeid, part)).fetchone()
             # fetchone should be ok bc dir and and name combo is unique
-            if ret is None:
+            if ret == None:
                 print ("\nCould not find id number for '%s'" % filepath)
                 return None
             nodeid = ret[0]
         return nodeid
 
     def get_node(self, node_id):
         if node_id is not None:
             node = self.node_dict.get(node_id)
@@ -111,24 +107,25 @@ class Graph(object):
     def file_summaries(self, files):
         for f in files:
             node = self.get_node(self.get_id(f))
             if node is not None:
                 sec = node.cost / 1000.0
                 m, s = sec / 60, sec % 60
                 print ("\n------ Summary for %s ------\
                     \nTotal Build Time (mm:ss) = %d:%d\nNum Downstream Commands = %d"
-                       % (f, m, s, node.num_cmds))
+                    % (f, m, s, node.num_cmds))
 
     def populate(self):
         # make nodes for files with downstream commands
         files = self.query('SELECT id FROM node WHERE type=0 AND id in \
             (SELECT DISTINCT from_id FROM normal_link)').fetchall()
         res = []
         for (i,) in files:
             node = self.get_node(i)
             res.append((node.path, node.cost))
         self.results = res
 
     def get_cost_dict(self):
         if self.results is None:
             self.populate()
-        return {k: v for k, v in self.results if v > 0}
+        return {k:v for k,v in self.results if v > 0}
+
--- a/python/mozbuild/mozbuild/analyze/hg.py
+++ b/python/mozbuild/mozbuild/analyze/hg.py
@@ -1,75 +1,66 @@
 # 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 absolute_import, print_function
-
 import bisect
 import gzip
 import json
 import math
 import requests
 
 from datetime import datetime, timedelta
 from collections import Counter
 
 import mozpack.path as mozpath
 
 PUSHLOG_CHUNK_SIZE = 500
 
 URL = 'https://hg.mozilla.org/mozilla-central/json-pushes?'
 
-
 def unix_epoch(date):
-    return (date - datetime(1970, 1, 1)).total_seconds()
-
+    return (date - datetime(1970,1,1)).total_seconds()
 
 def unix_from_date(n, today):
     return unix_epoch(today - timedelta(days=n))
 
-
 def get_lastpid(session):
     return session.get(URL+'&version=2').json()['lastpushid']
 
-
 def get_pushlog_chunk(session, start, end):
     # returns pushes sorted by date
     res = session.get(URL+'version=1&startID={0}&\
         endID={1}&full=1'.format(start, end)).json()
-    return sorted(res.items(), key=lambda x: x[1]['date'])
-
+    return sorted(res.items(), key = lambda x: x[1]['date'])
 
 def collect_data(session, date):
-    if date < 1206031764:  # first push
-        raise Exception("No pushes exist before March 20, 2008.")
+    if date < 1206031764: #first push
+        raise Exception ("No pushes exist before March 20, 2008.")
     lastpushid = get_lastpid(session)
     data = []
     start_id = lastpushid - PUSHLOG_CHUNK_SIZE
     end_id = lastpushid + 1
     while True:
         res = get_pushlog_chunk(session, start_id, end_id)
-        starting_date = res[0][1]['date']  # date of oldest push in chunk
+        starting_date = res[0][1]['date'] # date of oldest push in chunk
         dates = [x[1]['date'] for x in res]
         if starting_date < date:
             i = bisect.bisect_left(dates, date)
             data.append(res[i:])
             return data
         else:
             data.append(res)
             end_id = start_id + 1
             start_id = start_id - PUSHLOG_CHUNK_SIZE
 
-
 def get_data(epoch):
     session = requests.Session()
     data = collect_data(session, epoch)
-    return {k: v for sublist in data for (k, v) in sublist}
-
+    return {k:v for sublist in data for (k,v) in sublist}
 
 class Pushlog(object):
 
     def __init__(self, days):
         info = get_data(unix_from_date(days, datetime.today()))
         self.pushlog = info
         self.pids = self.get_pids()
         self.pushes = self.make_pushes()
@@ -82,25 +73,23 @@ class Pushlog(object):
         all_pushes = self.pushlog
         return [Push(pid, all_pushes[str(pid)]) for pid in pids]
 
     def get_pids(self):
         keys = self.pushlog.keys()
         keys.sort()
         return keys
 
-
 class Push(object):
 
     def __init__(self, pid, p_dict):
         self.id = pid
         self.date = p_dict['date']
         self.files = [f for x in p_dict['changesets'] for f in x['files']]
 
-
 class Report(object):
 
     def __init__(self, days, path=None, cost_dict=None):
         obj = Pushlog(days)
         self.file_set = obj.file_set
         self.file_count = obj.file_count
         self.name = str(days) + 'day_report'
         self.cost_dict = self.get_cost_dict(path, cost_dict)
@@ -118,17 +107,17 @@ class Report(object):
     def organize_data(self):
         costs = self.cost_dict
         counts = self.file_count
         res = []
         for f in self.file_set:
             cost = costs.get(f)
             count = counts.get(f)
             if cost is not None:
-                res.append((f, cost, count, round(cost*count, 3)))
+                res.append((f, cost, count, round(cost*count,3)))
         return res
 
     def get_sorted_report(self, format):
         res = self.organize_data()
         res.sort(key=(lambda x: x[3]), reverse=True)
 
         def ms_to_mins_secs(ms):
             secs = ms / 1000.0
@@ -149,26 +138,26 @@ class Report(object):
             return lst[:size]
 
     def generate_output(self, format, limit, dst):
         import tablib
         data = tablib.Dataset(headers=['FILE', 'TIME', 'CHANGES', 'TOTAL'])
         res = self.get_sorted_report(format)
         if limit is not None:
             res = self.cut(limit, res)
-        for x in res:
-            data.append(x)
+        for x in res: data.append(x)
         if format == 'pretty':
             print (data)
         else:
             file_name = self.name + '.' + format
             content = None
             data.export(format)
             if format == 'csv':
                 content = data.csv
             elif format == 'json':
                 content = data.json
             else:
                 content = data.html
             file_path = mozpath.join(dst, file_name)
             with open(file_path, 'wb') as f:
                 f.write(content)
             print ("Created report: %s" % file_path)
+
--- a/python/mozbuild/mozbuild/android_version_code.py
+++ b/python/mozbuild/mozbuild/android_version_code.py
@@ -6,18 +6,17 @@ from __future__ import absolute_import, 
 
 import argparse
 import math
 import sys
 import time
 
 # Builds before this build ID use the v0 version scheme.  Builds after this
 # build ID use the v1 version scheme.
-V1_CUTOFF = 20150801000000  # YYYYmmddHHMMSS
-
+V1_CUTOFF = 20150801000000 # YYYYmmddHHMMSS
 
 def android_version_code_v0(buildid, cpu_arch=None, min_sdk=0, max_sdk=0):
     base = int(str(buildid)[:10])
     # None is interpreted as arm.
     if not cpu_arch or cpu_arch == 'armeabi-v7a':
         # Increment by MIN_SDK_VERSION -- this adds 9 to every build ID as a
         # minimum.  Our split APK starts at 15.
         return base + min_sdk + 0
@@ -26,17 +25,16 @@ def android_version_code_v0(buildid, cpu
         # x86 phones that have ARM emulators, beating the 2-point advantage that
         # the v15+ ARMv7 APK has.  If we change our splits in the future, we'll
         # need to do this further still.
         return base + min_sdk + 3
     else:
         raise ValueError("Don't know how to compute android:versionCode "
                          "for CPU arch %s" % cpu_arch)
 
-
 def android_version_code_v1(buildid, cpu_arch=None, min_sdk=0, max_sdk=0):
     '''Generate a v1 android:versionCode.
 
     The important consideration is that version codes be monotonically
     increasing (per Android package name) for all published builds.  The input
     build IDs are based on timestamps and hence are always monotonically
     increasing.
 
@@ -131,17 +129,16 @@ def android_version_code_v1(buildid, cpu
         raise ValueError("Don't know how to compute android:versionCode "
                          "for CPU arch %s" % cpu_arch)
 
     # 'g' bit is currently always 1, but may depend on `min_sdk` in the future.
     version |= 1 << 0
 
     return version
 
-
 def android_version_code(buildid, *args, **kwargs):
     base = int(str(buildid))
     if base < V1_CUTOFF:
         return android_version_code_v0(buildid, *args, **kwargs)
     else:
         return android_version_code_v1(buildid, *args, **kwargs)
 
 
@@ -164,17 +161,17 @@ def main(argv):
     parser.add_argument('--with-android-max-sdk-version', dest='max_sdk',
                         type=int, default=0,
                         help='The maximum target SDK')
     parser.add_argument('buildid', type=int,
                         help='The input build ID')
 
     args = parser.parse_args(argv)
     code = android_version_code(args.buildid,
-                                cpu_arch=args.cpu_arch,
-                                min_sdk=args.min_sdk,
-                                max_sdk=args.max_sdk)
+        cpu_arch=args.cpu_arch,
+        min_sdk=args.min_sdk,
+        max_sdk=args.max_sdk)
     print(code)
     return 0
 
 
 if __name__ == '__main__':
     sys.exit(main(sys.argv[1:]))
--- a/python/mozbuild/mozbuild/artifact_builds.py
+++ b/python/mozbuild/mozbuild/artifact_builds.py
@@ -1,14 +1,12 @@
 # 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 absolute_import, print_function
-
 # The values correspond to entries at
 # https://tools.taskcluster.net/index/artifacts/#gecko.v2.mozilla-central.latest/gecko.v2.mozilla-central.latest
 JOB_CHOICES = {
     'android-api-16-opt',
     'android-api-16-debug',
     'android-x86-opt',
     'android-x86_64-opt',
     'android-x86_64-debug',
--- a/python/mozbuild/mozbuild/artifacts.py
+++ b/python/mozbuild/mozbuild/artifacts.py
@@ -72,18 +72,17 @@ from mozpack.files import (
 )
 from mozpack.mozjar import (
     JarReader,
     JarWriter,
 )
 from mozpack.packager.unpack import UnpackFinder
 import mozpack.path as mozpath
 
-# Number of candidate pushheads to cache per parent changeset.
-NUM_PUSHHEADS_TO_QUERY_PER_PARENT = 50
+NUM_PUSHHEADS_TO_QUERY_PER_PARENT = 50  # Number of candidate pushheads to cache per parent changeset.
 
 # Number of parent changesets to consider as possible pushheads.
 # There isn't really such a thing as a reasonable default here, because we don't
 # know how many pushheads we'll need to look at to find a build with our artifacts,
 # and we don't know how many changesets will be in each push. For now we assume
 # we'll find a build in the last 50 pushes, assuming each push contains 10 changesets.
 NUM_REVISIONS_TO_QUERY = 500
 
@@ -309,55 +308,51 @@ class AndroidArtifactJob(ArtifactJob):
         # Extract all .so files into the root, which will get copied into dist/bin.
         with JarWriter(file=processed_filename, compress_level=5) as writer:
             for p, f in UnpackFinder(JarFinder(filename, JarReader(filename))):
                 if not any(mozpath.match(p, pat) for pat in self.package_artifact_patterns):
                     continue
 
                 dirname, basename = os.path.split(p)
                 self.log(logging.INFO, 'artifact',
-                         {'basename': basename},
-                         'Adding {basename} to processed archive')
+                    {'basename': basename},
+                   'Adding {basename} to processed archive')
 
                 basedir = 'bin'
                 if not basename.endswith('.so'):
                     basedir = mozpath.join('bin', dirname.lstrip('assets/'))
                 basename = mozpath.join(basedir, basename)
                 writer.add(basename.encode('utf-8'), f.open())
 
     def process_symbols_archive(self, filename, processed_filename):
-        ArtifactJob.process_symbols_archive(
-            self, filename, processed_filename, skip_compressed=True)
+        ArtifactJob.process_symbols_archive(self, filename, processed_filename, skip_compressed=True)
 
         if self._symbols_archive_suffix != 'crashreporter-symbols-full.zip':
             return
 
         import gzip
 
         with JarWriter(file=processed_filename, compress_level=5) as writer:
             reader = JarReader(filename)
             for filename in reader.entries:
                 if not filename.endswith('.gz'):
                     continue
 
-                # Uncompress "libxul.so/D3271457813E976AE7BF5DAFBABABBFD0/libxul.so.dbg.gz"
-                # into "libxul.so.dbg".
+                # Uncompress "libxul.so/D3271457813E976AE7BF5DAFBABABBFD0/libxul.so.dbg.gz" into "libxul.so.dbg".
                 #
-                # After running `settings append target.debug-file-search-paths $file`,
-                # where file=/path/to/topobjdir/dist/crashreporter-symbols,
+                # After `settings append target.debug-file-search-paths /path/to/topobjdir/dist/crashreporter-symbols`,
                 # Android Studio's lldb (7.0.0, at least) will find the ELF debug symbol files.
                 #
                 # There are other paths that will work but none seem more desireable.  See
                 # https://github.com/llvm-mirror/lldb/blob/882670690ca69d9dd96b7236c620987b11894af9/source/Host/common/Symbols.cpp#L324.
                 basename = os.path.basename(filename).replace('.gz', '')
                 destpath = mozpath.join('crashreporter-symbols', basename)
                 self.log(logging.INFO, 'artifact',
                          {'destpath': destpath},
-                         'Adding uncompressed ELF debug symbol file '
-                         '{destpath} to processed archive')
+                         'Adding uncompressed ELF debug symbol file {destpath} to processed archive')
                 writer.add(destpath.encode('utf-8'),
                            gzip.GzipFile(fileobj=reader[filename].uncompressed_data))
 
 
 class LinuxArtifactJob(ArtifactJob):
     package_re = r'public/build/target\.tar\.bz2'
     product = 'firefox'
 
@@ -440,18 +435,18 @@ class MacArtifactJob(ArtifactJob):
         root, paths = self._paths_no_keep_path
         return (root, [p.format(product=self.product) for p in paths])
 
     def process_package_artifact(self, filename, processed_filename):
         tempdir = tempfile.mkdtemp()
         oldcwd = os.getcwd()
         try:
             self.log(logging.INFO, 'artifact',
-                     {'tempdir': tempdir},
-                     'Unpacking DMG into {tempdir}')
+                {'tempdir': tempdir},
+                'Unpacking DMG into {tempdir}')
             if self._substs['HOST_OS_ARCH'] == 'Linux':
                 # This is a cross build, use hfsplus and dmg tools to extract the dmg.
                 os.chdir(tempdir)
                 with open(os.devnull, 'wb') as devnull:
                     subprocess.check_call([
                         self._substs['DMG_TOOL'],
                         'extract',
                         filename,
@@ -486,18 +481,18 @@ class MacArtifactJob(ArtifactJob):
             ]
 
             with JarWriter(file=processed_filename, compress_level=5) as writer:
                 root, paths = self.paths_no_keep_path
                 finder = UnpackFinder(mozpath.join(source, root))
                 for path in paths:
                     for p, f in finder.find(path):
                         self.log(logging.INFO, 'artifact',
-                                 {'path': p},
-                                 'Adding {path} to processed archive')
+                            {'path': p},
+                            'Adding {path} to processed archive')
                         destpath = mozpath.join('bin', os.path.basename(p))
                         writer.add(destpath.encode('utf-8'), f, mode=f.mode)
 
                 for root, paths in paths_keep_path:
                     finder = UnpackFinder(mozpath.join(source, root))
                     for path in paths:
                         for p, f in finder.find(path):
                             self.log(logging.INFO, 'artifact',
@@ -507,18 +502,18 @@ class MacArtifactJob(ArtifactJob):
                             writer.add(destpath.encode('utf-8'), f.open(), mode=f.mode)
 
         finally:
             os.chdir(oldcwd)
             try:
                 shutil.rmtree(tempdir)
             except (OSError, IOError):
                 self.log(logging.WARN, 'artifact',
-                         {'tempdir': tempdir},
-                         'Unable to delete {tempdir}')
+                    {'tempdir': tempdir},
+                    'Unable to delete {tempdir}')
                 pass
 
 
 class WinArtifactJob(ArtifactJob):
     package_re = r'public/build/target\.(zip|tar\.gz)'
     product = 'firefox'
 
     _package_artifact_patterns = {
@@ -561,18 +556,18 @@ class WinArtifactJob(ArtifactJob):
             for p, f in UnpackFinder(JarFinder(filename, JarReader(filename))):
                 if not any(mozpath.match(p, pat) for pat in self.package_artifact_patterns):
                     continue
 
                 # strip off the relative "firefox/" bit from the path:
                 basename = mozpath.relpath(p, self.product)
                 basename = mozpath.join('bin', basename)
                 self.log(logging.INFO, 'artifact',
-                         {'basename': basename},
-                         'Adding {basename} to processed archive')
+                    {'basename': basename},
+                    'Adding {basename} to processed archive')
                 writer.add(basename.encode('utf-8'), f.open(), mode=f.mode)
                 added_entry = True
 
         if not added_entry:
             raise ValueError('Archive format changed! No pattern from "{patterns}"'
                              'matched an archive path.'.format(
                                  patterns=self.artifact_patterns))
 
@@ -654,83 +649,79 @@ def cachedmethod(cachefunc):
 class CacheManager(object):
     '''Maintain an LRU cache.  Provide simple persistence, including support for
     loading and saving the state using a "with" block.  Allow clearing the cache
     and printing the cache for debugging.
 
     Provide simple logging.
     '''
 
-    def __init__(self, cache_dir, cache_name, cache_size, cache_callback=None,
-                 log=None, skip_cache=False):
+    def __init__(self, cache_dir, cache_name, cache_size, cache_callback=None, log=None, skip_cache=False):
         self._skip_cache = skip_cache
         self._cache = pylru.lrucache(cache_size, callback=cache_callback)
         self._cache_filename = mozpath.join(cache_dir, cache_name + '-cache.pickle')
         self._log = log
         mkdir(cache_dir, not_indexed=True)
 
     def log(self, *args, **kwargs):
         if self._log:
             self._log(*args, **kwargs)
 
     def load_cache(self):
         if self._skip_cache:
             self.log(logging.INFO, 'artifact',
-                     {},
-                     'Skipping cache: ignoring load_cache!')
+                {},
+                'Skipping cache: ignoring load_cache!')
             return
 
         try:
             items = pickle.load(open(self._cache_filename, 'rb'))
             for key, value in items:
                 self._cache[key] = value
         except Exception as e:
             # Corrupt cache, perhaps?  Sadly, pickle raises many different
             # exceptions, so it's not worth trying to be fine grained here.
             # We ignore any exception, so the cache is effectively dropped.
             self.log(logging.INFO, 'artifact',
-                     {'filename': self._cache_filename, 'exception': repr(e)},
-                     'Ignoring exception unpickling cache file {filename}: {exception}')
+                {'filename': self._cache_filename, 'exception': repr(e)},
+                'Ignoring exception unpickling cache file {filename}: {exception}')
             pass
 
     def dump_cache(self):
         if self._skip_cache:
             self.log(logging.INFO, 'artifact',
-                     {},
-                     'Skipping cache: ignoring dump_cache!')
+                {},
+                'Skipping cache: ignoring dump_cache!')
             return
 
         ensureParentDir(self._cache_filename)
-        pickle.dump(list(reversed(list(self._cache.items()))),
-                    open(self._cache_filename, 'wb'), -1)
+        pickle.dump(list(reversed(list(self._cache.items()))), open(self._cache_filename, 'wb'), -1)
 
     def clear_cache(self):
         if self._skip_cache:
             self.log(logging.INFO, 'artifact',
-                     {},
-                     'Skipping cache: ignoring clear_cache!')
+                {},
+                'Skipping cache: ignoring clear_cache!')
             return
 
         with self:
             self._cache.clear()
 
     def __enter__(self):
         self.load_cache()
         return self
 
     def __exit__(self, type, value, traceback):
         self.dump_cache()
 
-
 class PushheadCache(CacheManager):
     '''Helps map tree/revision pairs to parent pushheads according to the pushlog.'''
 
     def __init__(self, cache_dir, log=None, skip_cache=False):
-        CacheManager.__init__(self, cache_dir, 'pushhead_cache',
-                              MAX_CACHED_TASKS, log=log, skip_cache=skip_cache)
+        CacheManager.__init__(self, cache_dir, 'pushhead_cache', MAX_CACHED_TASKS, log=log, skip_cache=skip_cache)
 
     @cachedmethod(operator.attrgetter('_cache'))
     def parent_pushhead_id(self, tree, revision):
         cset_url_tmpl = ('https://hg.mozilla.org/{tree}/json-pushes?'
                          '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):
@@ -747,23 +738,21 @@ class PushheadCache(CacheManager):
         req = requests.get(pushid_url_tmpl.format(tree=tree, start=start,
                                                   end=end),
                            headers={'Accept': 'application/json'})
         result = req.json()
         return [
             p['changesets'][-1] for p in result['pushes'].values()
         ]
 
-
 class TaskCache(CacheManager):
     '''Map candidate pushheads to Task Cluster task IDs and artifact URLs.'''
 
     def __init__(self, cache_dir, log=None, skip_cache=False):
-        CacheManager.__init__(self, cache_dir, 'artifact_url',
-                              MAX_CACHED_TASKS, log=log, skip_cache=skip_cache)
+        CacheManager.__init__(self, cache_dir, 'artifact_url', MAX_CACHED_TASKS, log=log, skip_cache=skip_cache)
 
     @cachedmethod(operator.attrgetter('_cache'))
     def artifacts(self, tree, job, artifact_job_class, rev):
         # Grab the second part of the repo name, which is generally how things
         # are indexed. Eg: 'integration/mozilla-inbound' is indexed as
         # 'mozilla-inbound'
         tree = tree.split('/')[1] if '/' in tree else tree
 
@@ -788,18 +777,17 @@ class TaskCache(CacheManager):
         self.log(logging.INFO, 'artifact',
                  {'namespace': namespace},
                  'Searching Taskcluster index with namespace: {namespace}')
         try:
             taskId = find_task_id(namespace)
         except KeyError:
             # Not all revisions correspond to pushes that produce the job we
             # care about; and even those that do may not have completed yet.
-            raise ValueError(
-                'Task for {namespace} does not exist (yet)!'.format(namespace=namespace))
+            raise ValueError('Task for {namespace} does not exist (yet)!'.format(namespace=namespace))
 
         return taskId, list_artifacts(taskId)
 
 
 class Artifacts(object):
     '''Maintain state to efficiently fetch build artifacts from a Firefox tree.'''
 
     def __init__(self, tree, substs, defines, job=None, log=None,
@@ -827,25 +815,23 @@ class Artifacts(object):
             cls = job_details[self._job]
             self._artifact_job = cls(log=self._log,
                                      download_tests=download_tests,
                                      download_symbols=download_symbols,
                                      download_host_bins=download_host_bins,
                                      substs=self._substs)
         except KeyError:
             self.log(logging.INFO, 'artifact',
-                     {'job': self._job},
-                     'Unknown job {job}')
+                {'job': self._job},
+                'Unknown job {job}')
             raise KeyError("Unknown job")
 
         self._task_cache = TaskCache(self._cache_dir, log=self._log, skip_cache=self._skip_cache)
-        self._artifact_cache = ArtifactCache(
-            self._cache_dir, log=self._log, skip_cache=self._skip_cache)
-        self._pushhead_cache = PushheadCache(
-            self._cache_dir, log=self._log, skip_cache=self._skip_cache)
+        self._artifact_cache = ArtifactCache(self._cache_dir, log=self._log, skip_cache=self._skip_cache)
+        self._pushhead_cache = PushheadCache(self._cache_dir, log=self._log, skip_cache=self._skip_cache)
 
     def log(self, *args, **kwargs):
         if self._log:
             self._log(*args, **kwargs)
 
     def _guess_artifact_job(self):
         # Add the "-debug" suffix to the guessed artifact job name
         # if MOZ_DEBUG is enabled.
@@ -959,22 +945,21 @@ class Artifacts(object):
                 num=NUM_REVISIONS_TO_QUERY)
         ], cwd=self._topsrcdir).splitlines()
 
         if len(last_revs) == 0:
             raise Exception("""\
 There are no public revisions.
 This can happen if the repository is created from bundle file and never pulled
 from remote.  Please run `hg pull` and build again.
-see https://developer.mozilla.org/en-US/docs/Mozilla/Developer_guide/Source_Code/Mercurial/Bundles\
-""")
+see https://developer.mozilla.org/en-US/docs/Mozilla/Developer_guide/Source_Code/Mercurial/Bundles""")
 
         self.log(logging.INFO, 'artifact',
-                 {'len': len(last_revs)},
-                 'hg suggested {len} candidate revisions')
+            {'len': len(last_revs)},
+            'hg suggested {len} candidate revisions')
 
         def to_pair(line):
             rev, node = line.split(':', 1)
             return (int(rev), node)
 
         pairs = map(to_pair, last_revs)
 
         # Python's tuple sort orders by first component: here, the (local)
@@ -1005,26 +990,24 @@ see https://developer.mozilla.org/en-US/
             if not rev:
                 continue
             if rev not in candidate_pushheads:
                 continue
             count += 1
             yield candidate_pushheads[rev], rev
 
         if not count:
-            raise Exception(
-                'Could not find any candidate pushheads in the last {num} revisions.\n'
-                'Search started with {rev}, which must be known to Mozilla automation.\n\n'
-                'see https://developer.mozilla.org/en-US/docs/Artifact_builds'.format(
-                    rev=last_revs[0], num=NUM_PUSHHEADS_TO_QUERY_PER_PARENT))
+            raise Exception('Could not find any candidate pushheads in the last {num} revisions.\n'
+                            'Search started with {rev}, which must be known to Mozilla automation.\n\n'
+                            'see https://developer.mozilla.org/en-US/docs/Artifact_builds'.format(
+                                rev=last_revs[0], num=NUM_PUSHHEADS_TO_QUERY_PER_PARENT))
 
     def find_pushhead_artifacts(self, task_cache, job, tree, pushhead):
         try:
-            taskId, artifacts = task_cache.artifacts(
-                tree, job, self._artifact_job.__class__, pushhead)
+            taskId, artifacts = task_cache.artifacts(tree, job, self._artifact_job.__class__, pushhead)
         except ValueError:
             return None
 
         urls = []
         for artifact_name in self._artifact_job.find_candidate_artifacts(artifacts):
             # We can easily extract the task ID from the URL.  We can't easily
             # extract the build ID; we use the .ini files embedded in the
             # downloaded artifact for this.
@@ -1035,70 +1018,69 @@ see https://developer.mozilla.org/en-US/
                      {'pushhead': pushhead,
                       'tree': tree},
                      'Installing from remote pushhead {pushhead} on {tree}')
             return urls
         return None
 
     def install_from_file(self, filename, distdir):
         self.log(logging.INFO, 'artifact',
-                 {'filename': filename},
-                 'Installing from {filename}')
+            {'filename': filename},
+            'Installing from {filename}')
 
         # Do we need to post-process?
         processed_filename = filename + PROCESSED_SUFFIX
 
         if self._skip_cache and os.path.exists(processed_filename):
             self.log(logging.INFO, 'artifact',
-                     {'path': processed_filename},
-                     'Skipping cache: removing cached processed artifact {path}')
+                {'path': processed_filename},
+                'Skipping cache: removing cached processed artifact {path}')
             os.remove(processed_filename)
 
         if not os.path.exists(processed_filename):
             self.log(logging.INFO, 'artifact',
-                     {'filename': filename},
-                     'Processing contents of {filename}')
+                {'filename': filename},
+                'Processing contents of {filename}')
             self.log(logging.INFO, 'artifact',
-                     {'processed_filename': processed_filename},
-                     'Writing processed {processed_filename}')
+                {'processed_filename': processed_filename},
+                'Writing processed {processed_filename}')
             self._artifact_job.process_artifact(filename, processed_filename)
 
         self._artifact_cache._persist_limit.register_file(processed_filename)
 
         self.log(logging.INFO, 'artifact',
-                 {'processed_filename': processed_filename},
-                 'Installing from processed {processed_filename}')
+            {'processed_filename': processed_filename},
+            'Installing from processed {processed_filename}')
 
         # Copy all .so files, avoiding modification where possible.
         ensureParentDir(mozpath.join(distdir, '.dummy'))
 
         with zipfile.ZipFile(processed_filename) as zf:
             for info in zf.infolist():
                 if info.filename.endswith('.ini'):
                     continue
                 n = mozpath.join(distdir, info.filename)
                 fh = FileAvoidWrite(n, mode='rb')
                 shutil.copyfileobj(zf.open(info), fh)
                 file_existed, file_updated = fh.close()
                 self.log(logging.INFO, 'artifact',
-                         {'updating': 'Updating' if file_updated else 'Not updating',
-                          'filename': n},
-                         '{updating} {filename}')
+                    {'updating': 'Updating' if file_updated else 'Not updating', 'filename': n},
+                    '{updating} {filename}')
                 if not file_existed or file_updated:
                     # Libraries and binaries may need to be marked executable,
                     # depending on platform.
-                    perms = info.external_attr >> 16  # See http://stackoverflow.com/a/434689.
-                    perms |= stat.S_IWUSR | stat.S_IRUSR | stat.S_IRGRP | stat.S_IROTH  # u+w, a+r.
+                    perms = info.external_attr >> 16 # See http://stackoverflow.com/a/434689.
+                    perms |= stat.S_IWUSR | stat.S_IRUSR | stat.S_IRGRP | stat.S_IROTH # u+w, a+r.
                     os.chmod(n, perms)
         return 0
 
     def install_from_url(self, url, distdir):
         self.log(logging.INFO, 'artifact',
-                 {'url': url},
-                 'Installing from {url}')
+            {'url': url},
+            'Installing from {url}')
         filename = self._artifact_cache.fetch(url)
         return self.install_from_file(filename, distdir)
 
     def _install_from_hg_pushheads(self, hg_pushheads, distdir):
         """Iterate pairs (hg_hash, {tree-set}) associating hg revision hashes
         and tree-sets they are known to be in, trying to download and
         install from each.
         """
@@ -1130,17 +1112,17 @@ see https://developer.mozilla.org/en-US/
         hg_pushheads = self._find_pushheads()
         return self._install_from_hg_pushheads(hg_pushheads, distdir)
 
     def install_from_revset(self, revset, distdir):
         revision = None
         try:
             if self._hg:
                 revision = subprocess.check_output([self._hg, 'log', '--template', '{node}\n',
-                                                    '-r', revset], cwd=self._topsrcdir).strip()
+                                                  '-r', revset], cwd=self._topsrcdir).strip()
             elif self._git:
                 revset = subprocess.check_output([
                     self._git, 'rev-parse', '%s^{commit}' % revset],
                     stderr=open(os.devnull, 'w'), cwd=self._topsrcdir).strip()
             else:
                 # Fallback to the exception handling case from both hg and git
                 raise subprocess.CalledProcessError()
         except subprocess.CalledProcessError:
@@ -1178,18 +1160,17 @@ see https://developer.mozilla.org/en-US/
         urls = []
         for artifact_name in self._artifact_job.find_candidate_artifacts(artifacts):
             # We can easily extract the task ID from the URL.  We can't easily
             # extract the build ID; we use the .ini files embedded in the
             # downloaded artifact for this.
             url = get_artifact_url(taskId, artifact_name)
             urls.append(url)
         if not urls:
-            raise ValueError(
-                'Task {taskId} existed, but no artifacts found!'.format(taskId=taskId))
+            raise ValueError('Task {taskId} existed, but no artifacts found!'.format(taskId=taskId))
         for url in urls:
             if self.install_from_url(url, distdir):
                 return 1
         return 0
 
     def install_from(self, source, distdir):
         """Install artifacts from a ``source`` into the given ``distdir``.
         """
@@ -1208,15 +1189,16 @@ see https://developer.mozilla.org/en-US/
                 'MOZ_ARTIFACT_TASK_%s' % self._job.upper().replace('-', '_'),
                 'MOZ_ARTIFACT_TASK',
             ):
                 if var in os.environ:
                     return self.install_from_task(os.environ[var], distdir)
 
             return self.install_from_recent(distdir)
 
+
     def clear_cache(self):
         self.log(logging.INFO, 'artifact',
-                 {},
-                 'Deleting cached artifacts and caches.')
+            {},
+            'Deleting cached artifacts and caches.')
         self._task_cache.clear_cache()
         self._artifact_cache.clear_cache()
         self._pushhead_cache.clear_cache()
--- a/python/mozbuild/mozbuild/backend/__init__.py
+++ b/python/mozbuild/mozbuild/backend/__init__.py
@@ -1,14 +1,12 @@
 # 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 absolute_import, print_function
-
 backends = {
     'ChromeMap': 'mozbuild.codecoverage.chrome_map',
     'CompileDB': 'mozbuild.compilation.database',
     'CppEclipse': 'mozbuild.backend.cpp_eclipse',
     'FasterMake': 'mozbuild.backend.fastermake',
     'FasterMake+RecursiveMake': None,
     'GnConfigGen': 'mozbuild.gn_processor',
     'GnMozbuildWriter': 'mozbuild.gn_processor',
--- a/python/mozbuild/mozbuild/backend/base.py
+++ b/python/mozbuild/mozbuild/backend/base.py
@@ -1,13 +1,13 @@
 # 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 absolute_import, print_function, unicode_literals
+from __future__ import absolute_import, unicode_literals
 
 from abc import (
     ABCMeta,
     abstractmethod,
 )
 
 import errno
 import itertools
--- a/python/mozbuild/mozbuild/backend/cargo_build_defs.py
+++ b/python/mozbuild/mozbuild/backend/cargo_build_defs.py
@@ -1,13 +1,13 @@
 # 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 absolute_import, print_function, unicode_literals
+from __future__ import absolute_import, unicode_literals
 
 cargo_extra_outputs = {
     'bindgen': [
         'tests.rs',
         'host-target.txt',
     ],
     'cssparser': [
         'tokenizer.rs',
--- a/python/mozbuild/mozbuild/backend/common.py
+++ b/python/mozbuild/mozbuild/backend/common.py
@@ -1,13 +1,13 @@
 # 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 absolute_import, print_function, unicode_literals
+from __future__ import absolute_import, unicode_literals
 
 import itertools
 import json
 import os
 
 from collections import defaultdict
 
 import mozpack.path as mozpath
@@ -28,16 +28,17 @@ from mozbuild.frontend.data import (
     Exports,
     FinalTargetPreprocessedFiles,
     FinalTargetFiles,
     GeneratedFile,
     GeneratedSources,
     GnProjectData,
     HostLibrary,
     HostGeneratedSources,
+    HostRustLibrary,
     IPDLCollection,
     LocalizedPreprocessedFiles,
     LocalizedFiles,
     RustLibrary,
     SharedLibrary,
     StaticLibrary,
     UnifiedSources,
     XPIDLModule,
@@ -47,20 +48,20 @@ from mozbuild.frontend.data import (
 from mozbuild.jar import (
     DeprecatedJarManifest,
     JarManifestParser,
 )
 from mozbuild.preprocessor import Preprocessor
 from mozpack.chrome.manifest import parse_manifest_line
 
 from mozbuild.util import (
+    group_unified_files,
     mkdir,
 )
 
-
 class XPIDLManager(object):
     """Helps manage XPCOM IDLs in the context of the build system."""
 
     class Module(object):
         def __init__(self):
             self.idl_files = set()
             self.directories = set()
             self._stems = set()
@@ -96,25 +97,23 @@ class XPIDLManager(object):
 
     def idl_stems(self):
         """Return an iterator of stems of the managed IDL files.
 
         The stem of an IDL file is the basename of the file with no .idl extension.
         """
         return itertools.chain(*[m.stems() for m in self.modules.itervalues()])
 
-
 class BinariesCollection(object):
     """Tracks state of binaries produced by the build."""
 
     def __init__(self):
         self.shared_libraries = []
         self.programs = []
 
-
 class CommonBackend(BuildBackend):
     """Holds logic common to all build backends."""
 
     def _init(self):
         self._idl_manager = XPIDLManager(self.environment)
         self._binaries = BinariesCollection()
         self._configs = set()
         self._generated_sources = set()
@@ -178,18 +177,17 @@ class CommonBackend(BuildBackend):
         elif isinstance(obj, GeneratedFile):
             if obj.required_for_compile:
                 for f in obj.required_for_compile:
                     fullpath = ObjDirPath(obj._context, '!' + f).full_path
                     self._handle_generated_sources([fullpath])
             return False
 
         elif isinstance(obj, Exports):
-            objdir_files = [f.full_path for path, files in obj.files.walk()
-                            for f in files if isinstance(f, ObjDirPath)]
+            objdir_files = [f.full_path for path, files in obj.files.walk() for f in files if isinstance(f, ObjDirPath)]
             if objdir_files:
                 self._handle_generated_sources(objdir_files)
             return False
 
         elif isinstance(obj, GnProjectData):
             # These are only handled by special purpose build backends,
             # ignore them here.
             return True
@@ -198,19 +196,19 @@ class CommonBackend(BuildBackend):
             return False
 
         return True
 
     def consume_finished(self):
         if len(self._idl_manager.modules):
             self._write_rust_xpidl_summary(self._idl_manager)
             self._handle_idl_manager(self._idl_manager)
-            self._handle_generated_sources(
-                mozpath.join(self.environment.topobjdir, 'dist/include/%s.h' % stem)
-                for stem in self._idl_manager.idl_stems())
+            self._handle_generated_sources(mozpath.join(self.environment.topobjdir, 'dist/include/%s.h' % stem)
+                                           for stem in self._idl_manager.idl_stems())
+
 
         for config in self._configs:
             self.backend_input_files.add(config.source)
 
         # Write out a machine-readable file describing binaries.
         topobjdir = self.environment.topobjdir
         with self._write_file(mozpath.join(topobjdir, 'binaries.json')) as fh:
             d = {
@@ -291,17 +289,17 @@ class CommonBackend(BuildBackend):
                     seen_libs.add(lib)
                     shared_libs.append(lib)
 
         for lib in input_bin.linked_system_libs:
             if lib not in seen_libs:
                 seen_libs.add(lib)
                 os_libs.append(lib)
 
-        return (objs, sorted(seen_pgo_gen_only_objs), no_pgo_objs,
+        return (objs, sorted(seen_pgo_gen_only_objs), no_pgo_objs, \
                 shared_libs, os_libs, static_libs)
 
     def _make_list_file(self, kind, objdir, objs, name):
         if not objs:
             return None
         if kind == 'target':
             list_style = self.environment.substs.get('EXPAND_LIBS_LIST_STYLE')
         else:
@@ -329,18 +327,17 @@ class CommonBackend(BuildBackend):
 
         mkdir(objdir)
         with self._write_file(list_file_path) as fh:
             fh.write(content)
 
         return ref
 
     def _handle_generated_sources(self, files):
-        self._generated_sources.update(mozpath.relpath(
-            f, self.environment.topobjdir) for f in files)
+        self._generated_sources.update(mozpath.relpath(f, self.environment.topobjdir) for f in files)
 
     def _handle_webidl_collection(self, webidls):
 
         bindings_dir = mozpath.join(self.environment.topobjdir, 'dom', 'bindings')
 
         all_inputs = set(webidls.all_static_sources())
         for s in webidls.all_non_static_basenames():
             all_inputs.add(mozpath.join(bindings_dir, s))
@@ -394,32 +391,32 @@ class CommonBackend(BuildBackend):
                             output_directory, poison_windows_h=False):
         with self._write_file(mozpath.join(output_directory, unified_file)) as f:
             f.write('#define MOZ_UNIFIED_BUILD\n')
             includeTemplate = '#include "%(cppfile)s"'
             if poison_windows_h:
                 includeTemplate += (
                     '\n'
                     '#if defined(_WINDOWS_) && !defined(MOZ_WRAPPED_WINDOWS_H)\n'
-                    '#pragma message("wrapper failure reason: " MOZ_WINDOWS_WRAPPER_DISABLED_REASON)\n'  # noqa
+                    '#pragma message("wrapper failure reason: " MOZ_WINDOWS_WRAPPER_DISABLED_REASON)\n'
                     '#error "%(cppfile)s included unwrapped windows.h"\n'
                     "#endif")
             includeTemplate += (
                 '\n'
                 '#ifdef PL_ARENA_CONST_ALIGN_MASK\n'
                 '#error "%(cppfile)s uses PL_ARENA_CONST_ALIGN_MASK, '
                 'so it cannot be built in unified mode."\n'
                 '#undef PL_ARENA_CONST_ALIGN_MASK\n'
                 '#endif\n'
                 '#ifdef INITGUID\n'
                 '#error "%(cppfile)s defines INITGUID, '
                 'so it cannot be built in unified mode."\n'
                 '#undef INITGUID\n'
                 '#endif')
-            f.write('\n'.join(includeTemplate % {"cppfile": s} for
+            f.write('\n'.join(includeTemplate % { "cppfile": s } for
                               s in source_filenames))
 
     def _write_unified_files(self, unified_source_mapping, output_directory,
                              poison_windows_h=False):
         for unified_file, source_filenames in unified_source_mapping:
             self._write_unified_file(unified_file, source_filenames,
                                      output_directory, poison_windows_h)
 
--- a/python/mozbuild/mozbuild/backend/configenvironment.py
+++ b/python/mozbuild/mozbuild/backend/configenvironment.py
@@ -1,13 +1,13 @@
 # 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 absolute_import, print_function
+from __future__ import absolute_import
 
 import os
 import sys
 import json
 
 from collections import Iterable, OrderedDict
 from types import StringTypes, ModuleType
 
@@ -44,17 +44,17 @@ class BuildConfig(object):
     @classmethod
     def from_config_status(cls, path):
         """Create an instance from a config.status file."""
         code_cache = cls._CODE_CACHE
         mtime = os.path.getmtime(path)
 
         # cache the compiled code as it can be reused
         # we cache it the first time, or if the file changed
-        if path not in code_cache or code_cache[path][0] != mtime:
+        if not path in code_cache or code_cache[path][0] != mtime:
             # Add config.status manually to sys.modules so it gets picked up by
             # iter_modules_in_path() for automatic dependencies.
             mod = ModuleType('config.status')
             mod.__file__ = path
             sys.modules['config.status'] = mod
 
             with open(path, 'rt') as fh:
                 source = fh.read()
@@ -113,17 +113,17 @@ class ConfigEnvironment(object):
 
     ConfigEnvironment expects a "top_srcdir" subst to be set with the top
     source directory, in msys format on windows. It is used to derive a
     "srcdir" subst when treating config files. It can either be an absolute
     path or a path relative to the topobjdir.
     """
 
     def __init__(self, topsrcdir, topobjdir, defines=None,
-                 non_global_defines=None, substs=None, source=None, mozconfig=None):
+        non_global_defines=None, substs=None, source=None, mozconfig=None):
 
         if not source:
             source = mozpath.join(topobjdir, 'config.status')
         self.source = source
         self.defines = ReadOnlyDict(defines or {})
         self.non_global_defines = non_global_defines or []
         self.substs = dict(substs or {})
         self.topsrcdir = mozpath.abspath(topsrcdir)
@@ -143,45 +143,30 @@ class ConfigEnvironment(object):
             self.import_prefix = self.lib_prefix
             self.import_suffix = '.%s' % self.substs['IMPORT_LIB_SUFFIX']
         else:
             self.import_prefix = self.dll_prefix
             self.import_suffix = self.dll_suffix
         self.bin_suffix = self.substs.get('BIN_SUFFIX', '')
 
         global_defines = [name for name in self.defines
-                          if name not in self.non_global_defines]
-        self.substs["ACDEFINES"] = ' '.join(
-            [
-                '-D%s=%s' % (name, shell_quote(self.defines[name]).replace('$', '$$'))
-                for name in sorted(global_defines)
-            ]
-        )
-
+            if not name in self.non_global_defines]
+        self.substs['ACDEFINES'] = ' '.join(['-D%s=%s' % (name,
+            shell_quote(self.defines[name]).replace('$', '$$'))
+            for name in sorted(global_defines)])
         def serialize(name, obj):
             if isinstance(obj, StringTypes):
                 return obj
             if isinstance(obj, Iterable):
                 return ' '.join(obj)
             raise Exception('Unhandled type %s for %s', type(obj), str(name))
-        self.substs['ALLSUBSTS'] = '\n'.join(
-            sorted([
-                '%s = %s' % (
-                    name,
-                    serialize(name, self.substs[name])
-                    )
-                for name in self.substs if self.substs[name]
-                ])
-            )
-        self.substs['ALLEMPTYSUBSTS'] = '\n'.join(
-            sorted([
-                '%s =' % name
-                for name in self.substs if not self.substs[name]
-                ])
-            )
+        self.substs['ALLSUBSTS'] = '\n'.join(sorted(['%s = %s' % (name,
+            serialize(name, self.substs[name])) for name in self.substs if self.substs[name]]))
+        self.substs['ALLEMPTYSUBSTS'] = '\n'.join(sorted(['%s =' % name
+            for name in self.substs if not self.substs[name]]))
 
         self.substs = ReadOnlyDict(self.substs)
 
         self.external_source_dir = None
         external = self.substs.get('EXTERNAL_SOURCE_DIR', '')
         if external:
             external = mozpath.normpath(external)
             if not os.path.isabs(external):
@@ -224,27 +209,26 @@ class ConfigEnvironment(object):
                          if name not in self.non_global_defines)
         return ReadOnlyDict(acdefines)
 
     @staticmethod
     def from_config_status(path):
         config = BuildConfig.from_config_status(path)
 
         return ConfigEnvironment(config.topsrcdir, config.topobjdir,
-                                 config.defines, config.non_global_defines, config.substs, path)
+            config.defines, config.non_global_defines, config.substs, path)
 
 
 class PartialConfigDict(object):
     """Facilitates mapping the config.statusd defines & substs with dict-like access.
 
     This allows a buildconfig client to use buildconfig.defines['FOO'] (and
     similar for substs), where the value of FOO is delay-loaded until it is
     needed.
     """
-
     def __init__(self, config_statusd, typ, environ_override=False):
         self._dict = {}
         self._datadir = mozpath.join(config_statusd, typ)
         self._config_track = mozpath.join(self._datadir, 'config.track')
         self._files = set()
         self._environ_override = environ_override
 
     def _load_config_track(self):
@@ -349,34 +333,33 @@ class PartialConfigEnvironment(object):
         preprocessor command lines. The order in which defines were given
         when creating the ConfigEnvironment is preserved.
 
     and one additional define from all the defines as a dictionary:
       - ALLDEFINES contains all of the global defines as a dictionary. This is
       intended to be used instead of the defines structure from config.status so
       that scripts can depend directly on its value.
     """
-
     def __init__(self, topobjdir):
         config_statusd = mozpath.join(topobjdir, 'config.statusd')
         self.substs = PartialConfigDict(config_statusd, 'substs', environ_override=True)
         self.defines = PartialConfigDict(config_statusd, 'defines')
         self.topobjdir = topobjdir
 
     def write_vars(self, config):
         substs = config['substs'].copy()
         defines = config['defines'].copy()
 
         global_defines = [
             name for name in config['defines']
             if name not in config['non_global_defines']
         ]
         acdefines = ' '.join(['-D%s=%s' % (name,
-                                           shell_quote(config['defines'][name]).replace('$', '$$'))
-                              for name in sorted(global_defines)])
+            shell_quote(config['defines'][name]).replace('$', '$$'))
+            for name in sorted(global_defines)])
         substs['ACDEFINES'] = acdefines
 
         all_defines = OrderedDict()
         for k in global_defines:
             all_defines[k] = config['defines'][k]
         defines['ALLDEFINES'] = all_defines
 
         self.substs._fill_group(substs)
--- a/python/mozbuild/mozbuild/backend/cpp_eclipse.py
+++ b/python/mozbuild/mozbuild/backend/cpp_eclipse.py
@@ -1,33 +1,36 @@
 # 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 absolute_import, print_function
+from __future__ import absolute_import
 
 import errno
 import glob
+import random
 import os
 import shutil
 import subprocess
+import types
 from xml.sax.saxutils import quoteattr
+import xml.etree.ElementTree as ET
 from .common import CommonBackend
 
 from ..frontend.data import (
     ComputedFlags,
+    Defines,
 )
 from mozbuild.base import ExecutionSummary
 
 # TODO Have ./mach eclipse generate the workspace and index it:
 # /Users/bgirard/mozilla/eclipse/eclipse/eclipse/eclipse -application org.eclipse.cdt.managedbuilder.core.headlessbuild -data $PWD/workspace -importAll $PWD/eclipse
 # Open eclipse:
 # /Users/bgirard/mozilla/eclipse/eclipse/eclipse/eclipse -data $PWD/workspace
 
-
 class CppEclipseBackend(CommonBackend):
     """Backend that generates Cpp Eclipse project files.
     """
 
     def __init__(self, environment):
         if os.name == 'nt':
             raise Exception('Eclipse is not supported on Windows. '
                             'Consider using Visual Studio instead.')
@@ -73,18 +76,17 @@ class CppEclipseBackend(CommonBackend):
         return os.path.join(srcdir_parent, workspace_dirname)
 
     def consume_object(self, obj):
         reldir = getattr(obj, 'relsrcdir', None)
 
         # Note that unlike VS, Eclipse' indexer seem to crawl the headers and
         # isn't picky about the local includes.
         if isinstance(obj, ComputedFlags):
-            args = self._args_for_dirs.setdefault(
-                'tree/' + reldir, {'includes': [], 'defines': []})
+            args = self._args_for_dirs.setdefault('tree/' + reldir, {'includes': [], 'defines': []})
             # use the same args for any objdirs we include:
             if reldir == 'dom/bindings':
                 self._args_for_dirs.setdefault('generated-webidl', args)
             if reldir == 'ipc/ipdl':
                 self._args_for_dirs.setdefault('generated-ipdl', args)
 
             includes = args["includes"]
             if "BASE_INCLUDES" in obj.flags and obj.flags["BASE_INCLUDES"]:
@@ -98,18 +100,17 @@ class CppEclipseBackend(CommonBackend):
             if "LIBRARY_DEFINES" in obj.flags and obj.flags["LIBRARY_DEFINES"]:
                 defs += obj.flags["LIBRARY_DEFINES"]
 
         return True
 
     def consume_finished(self):
         settings_dir = os.path.join(self._project_dir, '.settings')
         launch_dir = os.path.join(self._project_dir, 'RunConfigurations')
-        workspace_settings_dir = os.path.join(
-            self._workspace_dir, '.metadata/.plugins/org.eclipse.core.runtime/.settings')
+        workspace_settings_dir = os.path.join(self._workspace_dir, '.metadata/.plugins/org.eclipse.core.runtime/.settings')
 
         for dir_name in [self._project_dir, settings_dir, launch_dir, workspace_settings_dir, self._workspace_lang_dir]:
             try:
                 os.makedirs(dir_name)
             except OSError as e:
                 if e.errno != errno.EEXIST:
                     raise
 
@@ -123,80 +124,76 @@ class CppEclipseBackend(CommonBackend):
 
         language_path = os.path.join(settings_dir, 'language.settings.xml')
         with open(language_path, 'wb') as fh:
             self._write_language_settings(fh)
 
         workspace_language_path = os.path.join(self._workspace_lang_dir, 'language.settings.xml')
         with open(workspace_language_path, 'wb') as fh:
             workspace_lang_settings = WORKSPACE_LANGUAGE_SETTINGS_TEMPLATE
-            workspace_lang_settings = workspace_lang_settings.replace(
-                "@COMPILER_FLAGS@", self._cxx + " " + self._cppflags)
+            workspace_lang_settings = workspace_lang_settings.replace("@COMPILER_FLAGS@", self._cxx + " " + self._cppflags);
             fh.write(workspace_lang_settings)
 
         self._write_launch_files(launch_dir)
 
-        core_resources_prefs_path = os.path.join(
-            workspace_settings_dir, 'org.eclipse.core.resources.prefs')
+        core_resources_prefs_path = os.path.join(workspace_settings_dir, 'org.eclipse.core.resources.prefs')
         with open(core_resources_prefs_path, 'wb') as fh:
-            fh.write(STATIC_CORE_RESOURCES_PREFS)
+            fh.write(STATIC_CORE_RESOURCES_PREFS);
 
-        core_runtime_prefs_path = os.path.join(
-            workspace_settings_dir, 'org.eclipse.core.runtime.prefs')
+        core_runtime_prefs_path = os.path.join(workspace_settings_dir, 'org.eclipse.core.runtime.prefs')
         with open(core_runtime_prefs_path, 'wb') as fh:
-            fh.write(STATIC_CORE_RUNTIME_PREFS)
+            fh.write(STATIC_CORE_RUNTIME_PREFS);
 
         ui_prefs_path = os.path.join(workspace_settings_dir, 'org.eclipse.ui.prefs')
         with open(ui_prefs_path, 'wb') as fh:
-            fh.write(STATIC_UI_PREFS)
+            fh.write(STATIC_UI_PREFS);
 
         cdt_ui_prefs_path = os.path.join(workspace_settings_dir, 'org.eclipse.cdt.ui.prefs')
         cdt_ui_prefs = STATIC_CDT_UI_PREFS
         # Here we generate the code formatter that will show up in the UI with
         # the name "Mozilla".  The formatter is stored as a single line of XML
         # in the org.eclipse.cdt.ui.formatterprofiles pref.
         cdt_ui_prefs += """org.eclipse.cdt.ui.formatterprofiles=<?xml version\="1.0" encoding\="UTF-8" standalone\="no"?>\\n<profiles version\="1">\\n<profile kind\="CodeFormatterProfile" name\="Mozilla" version\="1">\\n"""
         XML_PREF_TEMPLATE = """<setting id\="@PREF_NAME@" value\="@PREF_VAL@"/>\\n"""
         for line in FORMATTER_SETTINGS.splitlines():
             [pref, val] = line.split("=")
-            cdt_ui_prefs += XML_PREF_TEMPLATE.replace("@PREF_NAME@",
-                                                      pref).replace("@PREF_VAL@", val)
+            cdt_ui_prefs += XML_PREF_TEMPLATE.replace("@PREF_NAME@", pref).replace("@PREF_VAL@", val)
         cdt_ui_prefs += "</profile>\\n</profiles>\\n"
         with open(cdt_ui_prefs_path, 'wb') as fh:
-            fh.write(cdt_ui_prefs)
+            fh.write(cdt_ui_prefs);
 
         cdt_core_prefs_path = os.path.join(workspace_settings_dir, 'org.eclipse.cdt.core.prefs')
         with open(cdt_core_prefs_path, 'wb') as fh:
             cdt_core_prefs = STATIC_CDT_CORE_PREFS
             # When we generated the code formatter called "Mozilla" above, we
             # also set it to be the active formatter.  When a formatter is set
             # as the active formatter all its prefs are set in this prefs file,
             # so we need add those now:
             cdt_core_prefs += FORMATTER_SETTINGS
-            fh.write(cdt_core_prefs)
+            fh.write(cdt_core_prefs);
 
-        editor_prefs_path = os.path.join(workspace_settings_dir, "org.eclipse.ui.editors.prefs")
+        editor_prefs_path = os.path.join(workspace_settings_dir, "org.eclipse.ui.editors.prefs");
         with open(editor_prefs_path, 'wb') as fh:
-            fh.write(EDITOR_SETTINGS)
+            fh.write(EDITOR_SETTINGS);
 
         # Now import the project into the workspace
         self._import_project()
 
     def _import_project(self):
         # If the workspace already exists then don't import the project again because
         # eclipse doesn't handle this properly
         if self._overwriting_workspace:
             return
 
         # We disable the indexer otherwise we're forced to index
         # the whole codebase when importing the project. Indexing the project can take 20 minutes.
         self._write_noindex()
 
         try:
-            subprocess.check_call(
+            process = subprocess.check_call(
                              ["eclipse", "-application", "-nosplash",
                               "org.eclipse.cdt.managedbuilder.core.headlessbuild",
                               "-data", self._workspace_dir, "-importAll", self._project_dir])
         except OSError as e:
             # Remove the workspace directory so we re-generate it and
             # try to import again when the backend is invoked again.
             shutil.rmtree(self._workspace_dir)
 
@@ -206,17 +203,17 @@ class CppEclipseBackend(CommonBackend):
             else:
                 raise
         finally:
             self._remove_noindex()
 
     def _write_noindex(self):
         noindex_path = os.path.join(self._project_dir, '.settings/org.eclipse.cdt.core.prefs')
         with open(noindex_path, 'wb') as fh:
-            fh.write(NOINDEX_TEMPLATE)
+            fh.write(NOINDEX_TEMPLATE);
 
     def _remove_noindex(self):
         # Below we remove the config file that temporarily disabled the indexer
         # while we were importing the project. Unfortunately, CDT doesn't
         # notice indexer settings changes in config files when it restarts. To
         # work around that we remove the index database here to force it to:
         for f in glob.glob(os.path.join(self._workspace_lang_dir, "Gecko.*.pdom")):
             os.remove(f)
@@ -255,18 +252,17 @@ class CppEclipseBackend(CommonBackend):
         # we add settings for.  (Fortunately that doesn't appear to have a
         # noticeable impact on the time it takes to open the generated Eclipse
         # project.)  We do that by generating a template here that we can then
         # use for each individual directory in the loop below.
         #
         dirsettings_template = LANGUAGE_SETTINGS_TEMPLATE_DIR_HEADER
 
         # Add OS_COMPILE_CXXFLAGS args (same as OS_COMPILE_CFLAGS):
-        dirsettings_template = dirsettings_template.replace('@PREINCLUDE_FILE_PATH@', os.path.join(
-            self.environment.topobjdir, 'dist/include/mozilla-config.h'))
+        dirsettings_template = dirsettings_template.replace('@PREINCLUDE_FILE_PATH@', os.path.join(self.environment.topobjdir, 'dist/include/mozilla-config.h'))
         dirsettings_template += add_define('MOZILLA_CLIENT', '1')
 
         # Add EXTRA_INCLUDES args:
         dirsettings_template += add_objdir_include_path('dist/include')
 
         # Add OS_INCLUDES args:
         # XXX media/webrtc/trunk/webrtc's moz.builds reset this.
         dirsettings_template += add_objdir_include_path('dist/include/nspr')
@@ -303,28 +299,27 @@ class CppEclipseBackend(CommonBackend):
                 dirsettings += add_abs_include_path(i)
             for d in args["defines"]:
                 assert(d[:2] == u"-D" or d[:2] == u"-U")
                 if d[:2] == u"-U":
                     # gfx/harfbuzz/src uses -UDEBUG, at least on Mac
                     # netwerk/sctp/src uses -U__APPLE__ on Mac
                     # XXX We should make this code smart enough to remove existing defines.
                     continue
-                d = d[2:]  # get rid of leading "-D"
+                d = d[2:] # get rid of leading "-D"
                 name_value = d.split("=", 1)
                 name = name_value[0]
                 value = ""
                 if len(name_value) == 2:
                     value = name_value[1]
                 dirsettings += add_define(name, str(value))
             dirsettings += LANGUAGE_SETTINGS_TEMPLATE_DIR_FOOTER
             fh.write(dirsettings)
 
-        fh.write(LANGUAGE_SETTINGS_TEMPLATE_FOOTER.replace(
-            "@COMPILER_FLAGS@", self._cxx + " " + self._cppflags))
+        fh.write(LANGUAGE_SETTINGS_TEMPLATE_FOOTER.replace("@COMPILER_FLAGS@", self._cxx + " " + self._cppflags))
 
     def _write_launch_files(self, launch_dir):
         bin_dir = os.path.join(self.environment.topobjdir, 'dist')
 
         # TODO Improve binary detection
         if self._macbundle:
             exe_path = os.path.join(bin_dir, self._macbundle, 'Contents/MacOS')
         else:
@@ -334,35 +329,31 @@ class CppEclipseBackend(CommonBackend):
 
         main_gecko_launch = os.path.join(launch_dir, 'gecko.launch')
         with open(main_gecko_launch, 'wb') as fh:
             launch = GECKO_LAUNCH_CONFIG_TEMPLATE
             launch = launch.replace('@LAUNCH_PROGRAM@', exe_path)
             launch = launch.replace('@LAUNCH_ARGS@', '-P -no-remote')
             fh.write(launch)
 
-        # TODO Add more launch configs (and delegate calls to mach)
+        #TODO Add more launch configs (and delegate calls to mach)
 
     def _write_project(self, fh):
-        project = PROJECT_TEMPLATE
+        project = PROJECT_TEMPLATE;
 
         project = project.replace('@PROJECT_NAME@', self._project_name)
         project = project.replace('@PROJECT_TOPSRCDIR@', self.environment.topsrcdir)
-        project = project.replace('@GENERATED_IPDL_FILES@', os.path.join(
-            self.environment.topobjdir, "ipc", "ipdl"))
-        project = project.replace('@GENERATED_WEBIDL_FILES@', os.path.join(
-            self.environment.topobjdir, "dom", "bindings"))
+        project = project.replace('@GENERATED_IPDL_FILES@', os.path.join(self.environment.topobjdir, "ipc", "ipdl"))
+        project = project.replace('@GENERATED_WEBIDL_FILES@', os.path.join(self.environment.topobjdir, "dom", "bindings"))
         fh.write(project)
 
     def _write_cproject(self, fh):
         cproject_header = CPROJECT_TEMPLATE_HEADER
-        cproject_header = cproject_header.replace(
-            '@PROJECT_TOPSRCDIR@', self.environment.topobjdir)
-        cproject_header = cproject_header.replace(
-            '@MACH_COMMAND@', os.path.join(self.environment.topsrcdir, 'mach'))
+        cproject_header = cproject_header.replace('@PROJECT_TOPSRCDIR@', self.environment.topobjdir)
+        cproject_header = cproject_header.replace('@MACH_COMMAND@', os.path.join(self.environment.topsrcdir, 'mach'))
         fh.write(cproject_header)
         fh.write(CPROJECT_TEMPLATE_FOOTER)
 
 
 PROJECT_TEMPLATE = """<?xml version="1.0" encoding="UTF-8"?>
 <projectDescription>
         <name>@PROJECT_NAME@</name>
         <comment></comment>
@@ -373,18 +364,18 @@ PROJECT_TEMPLATE = """<?xml version="1.0
                         <name>org.eclipse.cdt.managedbuilder.core.genmakebuilder</name>
                         <triggers>clean,full,incremental,</triggers>
                         <arguments>
                         </arguments>
                 </buildCommand>
                 <buildCommand>
                         <name>org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder</name>
                         <triggers></triggers>
-            <arguments>
-            </arguments>
+			<arguments>
+			</arguments>
                 </buildCommand>
         </buildSpec>
         <natures>
                 <nature>org.eclipse.cdt.core.cnature</nature>
                 <nature>org.eclipse.cdt.core.ccnature</nature>
                 <nature>org.eclipse.cdt.managedbuilder.core.managedBuildNature</nature>
                 <nature>org.eclipse.cdt.managedbuilder.core.ScannerConfigNature</nature>
         </natures>
@@ -472,33 +463,33 @@ CPROJECT_TEMPLATE_HEADER = """<?xml vers
                                         <extension id="org.eclipse.cdt.core.GLDErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
                                 </extensions>
                         </storageModule>
                         <storageModule moduleId="cdtBuildSystem" version="4.0.0">
                                 <configuration artifactName="${ProjName}" buildProperties="" description="" id="0.1674256904" name="Default" parent="org.eclipse.cdt.build.core.prefbase.cfg">
                                         <folderInfo id="0.1674256904." name="/" resourcePath="">
                                                 <toolChain id="cdt.managedbuild.toolchain.gnu.cross.exe.debug.1276586933" name="Cross GCC" superClass="cdt.managedbuild.toolchain.gnu.cross.exe.debug">
                                                         <targetPlatform archList="all" binaryParser="" id="cdt.managedbuild.targetPlatform.gnu.cross.710759961" isAbstract="false" osList="all" superClass="cdt.managedbuild.targetPlatform.gnu.cross"/>
-                            <builder arguments="--log-no-times build" buildPath="@PROJECT_TOPSRCDIR@" command="@MACH_COMMAND@" enableCleanBuild="false" incrementalBuildTarget="binaries" id="org.eclipse.cdt.build.core.settings.default.builder.1437267827" keepEnvironmentInBuildfile="false" name="Gnu Make Builder" superClass="org.eclipse.cdt.build.core.settings.default.builder"/>
+							<builder arguments="--log-no-times build" buildPath="@PROJECT_TOPSRCDIR@" command="@MACH_COMMAND@" enableCleanBuild="false" incrementalBuildTarget="binaries" id="org.eclipse.cdt.build.core.settings.default.builder.1437267827" keepEnvironmentInBuildfile="false" name="Gnu Make Builder" superClass="org.eclipse.cdt.build.core.settings.default.builder"/>
                                                 </toolChain>
                                         </folderInfo>
 """
 CPROJECT_TEMPLATE_FILEINFO = """                                        <fileInfo id="0.1674256904.474736658" name="Layers.cpp" rcbsApplicability="disable" resourcePath="tree/gfx/layers/Layers.cpp" toolsToInvoke="org.eclipse.cdt.build.core.settings.holder.582514939.463639939">
                                                 <tool id="org.eclipse.cdt.build.core.settings.holder.582514939.463639939" name="GNU C++" superClass="org.eclipse.cdt.build.core.settings.holder.582514939">
                                                         <option id="org.eclipse.cdt.build.core.settings.holder.symbols.232300236" superClass="org.eclipse.cdt.build.core.settings.holder.symbols" valueType="definedSymbols">
                                                                 <listOptionValue builtIn="false" value="BENWA=BENWAVAL"/>
                                                         </option>
                                                         <inputType id="org.eclipse.cdt.build.core.settings.holder.inType.1942876228" languageId="org.eclipse.cdt.core.g++" languageName="GNU C++" sourceContentType="org.eclipse.cdt.core.cxxSource,org.eclipse.cdt.core.cxxHeader" superClass="org.eclipse.cdt.build.core.settings.holder.inType"/>
                                                 </tool>
                                         </fileInfo>
 """
 CPROJECT_TEMPLATE_FOOTER = """
-                    <sourceEntries>
-                        <entry excluding="**/lib*|**/third_party/|tree/*.xcodeproj/|tree/.cargo/|tree/.vscode/|tree/build/|tree/extensions/|tree/gfx/angle/|tree/gfx/cairo/|tree/gfx/skia/skia/|tree/intl/icu/|tree/js/|tree/media/|tree/modules/freetype2|tree/modules/pdfium/|tree/netwerk/|tree/netwerk/sctp|tree/netwerk/srtp|tree/nsprpub/lib|tree/nsprpub/pr/src|tree/other-licenses/|tree/parser/|tree/python/|tree/security/nss/|tree/tools/" flags="VALUE_WORKSPACE_PATH" kind="sourcePath" name=""/>
-                    </sourceEntries>
+					<sourceEntries>
+						<entry excluding="**/lib*|**/third_party/|tree/*.xcodeproj/|tree/.cargo/|tree/.vscode/|tree/build/|tree/extensions/|tree/gfx/angle/|tree/gfx/cairo/|tree/gfx/skia/skia/|tree/intl/icu/|tree/js/|tree/media/|tree/modules/freetype2|tree/modules/pdfium/|tree/netwerk/|tree/netwerk/sctp|tree/netwerk/srtp|tree/nsprpub/lib|tree/nsprpub/pr/src|tree/other-licenses/|tree/parser/|tree/python/|tree/security/nss/|tree/tools/" flags="VALUE_WORKSPACE_PATH" kind="sourcePath" name=""/>
+					</sourceEntries>
                                 </configuration>
                         </storageModule>
                         <storageModule moduleId="org.eclipse.cdt.core.externalSettings"/>
                 </cconfiguration>
         </storageModule>
         <storageModule moduleId="cdtBuildSystem" version="4.0.0">
                 <project id="Empty.null.1281234804" name="Empty"/>
         </storageModule>
@@ -530,48 +521,48 @@ WORKSPACE_LANGUAGE_SETTINGS_TEMPLATE = "
 # The settings set via this template can be found in the UI by opening
 # the Properties for a directory in the Project Explorer tab, then going to
 # C/C++ General > Preprocessor Include Paths, Macros, etc., selecting the
 # C++ item from the Languages column, and then expanding the
 # CDT User Settings Entries item to the right.
 
 LANGUAGE_SETTINGS_TEMPLATE_HEADER = """<?xml version="1.0" encoding="UTF-8" standalone="no"?>
 <project>
-    <configuration id="0.1674256904" name="Default">
-        <extension point="org.eclipse.cdt.core.LanguageSettingsProvider">
-            <provider class="org.eclipse.cdt.core.language.settings.providers.LanguageSettingsGenericProvider" id="org.eclipse.cdt.ui.UserLanguageSettingsProvider" name="CDT User Setting Entries" prefer-non-shared="true" store-entries-with-project="true">
-                <language id="org.eclipse.cdt.core.g++">
+	<configuration id="0.1674256904" name="Default">
+		<extension point="org.eclipse.cdt.core.LanguageSettingsProvider">
+			<provider class="org.eclipse.cdt.core.language.settings.providers.LanguageSettingsGenericProvider" id="org.eclipse.cdt.ui.UserLanguageSettingsProvider" name="CDT User Setting Entries" prefer-non-shared="true" store-entries-with-project="true">
+				<language id="org.eclipse.cdt.core.g++">
 """
 
-LANGUAGE_SETTINGS_TEMPLATE_DIR_HEADER = """                 <resource project-relative-path="@RELATIVE_PATH@">
-                        <entry kind="includeFile" name="@PREINCLUDE_FILE_PATH@">
-                            <flag value="LOCAL"/>
-                        </entry>
+LANGUAGE_SETTINGS_TEMPLATE_DIR_HEADER = """					<resource project-relative-path="@RELATIVE_PATH@">
+						<entry kind="includeFile" name="@PREINCLUDE_FILE_PATH@">
+							<flag value="LOCAL"/>
+						</entry>
 """
 
-LANGUAGE_SETTINGS_TEMPLATE_DIR_INCLUDE = """                        <entry kind="includePath" name="@INCLUDE_PATH@">
-                            <flag value="LOCAL"/>
-                        </entry>
+LANGUAGE_SETTINGS_TEMPLATE_DIR_INCLUDE = """						<entry kind="includePath" name="@INCLUDE_PATH@">
+							<flag value="LOCAL"/>
+						</entry>
 """
 
-LANGUAGE_SETTINGS_TEMPLATE_DIR_DEFINE = """                        <entry kind="macro" name="@NAME@" value=@VALUE@/>
+LANGUAGE_SETTINGS_TEMPLATE_DIR_DEFINE = """						<entry kind="macro" name="@NAME@" value=@VALUE@/>
 """
 
-LANGUAGE_SETTINGS_TEMPLATE_DIR_FOOTER = """                    </resource>
+LANGUAGE_SETTINGS_TEMPLATE_DIR_FOOTER = """					</resource>
 """
 
-LANGUAGE_SETTINGS_TEMPLATE_FOOTER = """                </language>
-                </provider>
-            <provider class="org.eclipse.cdt.internal.build.crossgcc.CrossGCCBuiltinSpecsDetector" console="false" env-hash="-859273372804152468" id="org.eclipse.cdt.build.crossgcc.CrossGCCBuiltinSpecsDetector" keep-relative-paths="false" name="CDT Cross GCC Built-in Compiler Settings" parameter="@COMPILER_FLAGS@ -E -P -v -dD &quot;${INPUTS}&quot; -std=c++11" prefer-non-shared="true" store-entries-with-project="true">
-                <language-scope id="org.eclipse.cdt.core.gcc"/>
-                <language-scope id="org.eclipse.cdt.core.g++"/>
-            </provider>
-            <provider-reference id="org.eclipse.cdt.managedbuilder.core.MBSLanguageSettingsProvider" ref="shared-provider"/>
-        </extension>
-    </configuration>
+LANGUAGE_SETTINGS_TEMPLATE_FOOTER = """				</language>
+			</provider>
+			<provider class="org.eclipse.cdt.internal.build.crossgcc.CrossGCCBuiltinSpecsDetector" console="false" env-hash="-859273372804152468" id="org.eclipse.cdt.build.crossgcc.CrossGCCBuiltinSpecsDetector" keep-relative-paths="false" name="CDT Cross GCC Built-in Compiler Settings" parameter="@COMPILER_FLAGS@ -E -P -v -dD &quot;${INPUTS}&quot; -std=c++11" prefer-non-shared="true" store-entries-with-project="true">
+				<language-scope id="org.eclipse.cdt.core.gcc"/>
+				<language-scope id="org.eclipse.cdt.core.g++"/>
+			</provider>
+			<provider-reference id="org.eclipse.cdt.managedbuilder.core.MBSLanguageSettingsProvider" ref="shared-provider"/>
+		</extension>
+	</configuration>
 </project>
 """
 
 
 GECKO_LAUNCH_CONFIG_TEMPLATE = """<?xml version="1.0" encoding="UTF-8" standalone="no"?>
 <launchConfiguration type="org.eclipse.cdt.launch.applicationLaunchType">
 <booleanAttribute key="org.eclipse.cdt.dsf.gdb.AUTO_SOLIB" value="true"/>
 <listAttribute key="org.eclipse.cdt.dsf.gdb.AUTO_SOLIB_LIST"/>
@@ -619,31 +610,31 @@ showLeadingSpaces=false
 showLineFeed=false
 showWhitespaceCharacters=true
 spacesForTabs=true
 tabWidth=2
 undoHistorySize=200
 """
 
 
-STATIC_CORE_RESOURCES_PREFS = """eclipse.preferences.version=1
+STATIC_CORE_RESOURCES_PREFS="""eclipse.preferences.version=1
 refresh.enabled=true
 """
 
-STATIC_CORE_RUNTIME_PREFS = """eclipse.preferences.version=1
+STATIC_CORE_RUNTIME_PREFS="""eclipse.preferences.version=1
 content-types/org.eclipse.cdt.core.cxxSource/file-extensions=mm
 content-types/org.eclipse.core.runtime.xml/file-extensions=xul
 content-types/org.eclipse.wst.jsdt.core.jsSource/file-extensions=jsm
 """
 
-STATIC_UI_PREFS = """eclipse.preferences.version=1
+STATIC_UI_PREFS="""eclipse.preferences.version=1
 showIntro=false
 """
 
-STATIC_CDT_CORE_PREFS = """eclipse.preferences.version=1
+STATIC_CDT_CORE_PREFS="""eclipse.preferences.version=1
 indexer.updatePolicy=0
 """
 
 FORMATTER_SETTINGS = """org.eclipse.cdt.core.formatter.alignment_for_arguments_in_method_invocation=16
 org.eclipse.cdt.core.formatter.alignment_for_assignment=16
 org.eclipse.cdt.core.formatter.alignment_for_base_clause_in_type_declaration=80
 org.eclipse.cdt.core.formatter.alignment_for_binary_expression=16
 org.eclipse.cdt.core.formatter.alignment_for_compact_if=16
@@ -801,17 +792,17 @@ org.eclipse.cdt.core.formatter.keep_then
 org.eclipse.cdt.core.formatter.lineSplit=80
 org.eclipse.cdt.core.formatter.number_of_empty_lines_to_preserve=1
 org.eclipse.cdt.core.formatter.put_empty_statement_on_new_line=true
 org.eclipse.cdt.core.formatter.tabulation.char=space
 org.eclipse.cdt.core.formatter.tabulation.size=2
 org.eclipse.cdt.core.formatter.use_tabs_only_for_leading_indentations=false
 """
 
-STATIC_CDT_UI_PREFS = """eclipse.preferences.version=1
+STATIC_CDT_UI_PREFS="""eclipse.preferences.version=1
 buildConsoleLines=10000
 Console.limitConsoleOutput=false
 ensureNewlineAtEOF=false
 formatter_profile=_Mozilla
 formatter_settings_version=1
 org.eclipse.cdt.ui.formatterprofiles.version=1
 removeTrailingWhitespace=true
 removeTrailingWhitespaceEditedLines=true
--- a/python/mozbuild/mozbuild/backend/fastermake.py
+++ b/python/mozbuild/mozbuild/backend/fastermake.py
@@ -129,22 +129,20 @@ class FasterMakeBackend(CommonBackend, P
             if obj.path != top_level:
                 entry = 'manifest %s' % mozpath.relpath(obj.path,
                                                         obj.install_target)
                 self._manifest_entries[top_level].add(entry)
             self._manifest_entries[obj.path].add(str(obj.entry))
 
         elif isinstance(obj, GeneratedFile):
             if obj.outputs:
-                first_output = mozpath.relpath(mozpath.join(
-                    obj.objdir, obj.outputs[0]), self.environment.topobjdir)
+                first_output = mozpath.relpath(mozpath.join(obj.objdir, obj.outputs[0]), self.environment.topobjdir)
                 for o in obj.outputs[1:]:
                     fullpath = mozpath.join(obj.objdir, o)
-                    self._generated_files_map[mozpath.relpath(
-                        fullpath, self.environment.topobjdir)] = first_output
+                    self._generated_files_map[mozpath.relpath(fullpath, self.environment.topobjdir)] = first_output
             # We don't actually handle GeneratedFiles, we just need to know if
             # we can build multiple of them from a single make invocation in the
             # faster backend.
             return False
 
         elif isinstance(obj, XPIDLModule):
             self._has_xpidl = True
             # We're not actually handling XPIDL files.
@@ -191,50 +189,43 @@ class FasterMakeBackend(CommonBackend, P
         mk.add_statement('INSTALL_MANIFESTS = %s'
                          % ' '.join(self._install_manifests.keys()))
 
         # Add dependencies we inferred:
         for target, deps in self._dependencies.iteritems():
             mk.create_rule([target]).add_dependencies(
                 '$(TOPOBJDIR)/%s' % d for d in deps)
 
+
         # This is not great, but it's better to have some dependencies on these Python files.
         python_deps = [
             '$(TOPSRCDIR)/python/mozbuild/mozbuild/action/l10n_merge.py',
             '$(TOPSRCDIR)/third_party/python/compare-locales/compare_locales/compare.py',
             '$(TOPSRCDIR)/third_party/python/compare-locales/compare_locales/paths.py',
         ]
         # Add l10n dependencies we inferred:
         for target, deps in self._l10n_dependencies.iteritems():
             mk.create_rule([target]).add_dependencies(
                 '%s' % d[0] for d in deps)
             for (merge, ref_file, l10n_file) in deps:
                 rule = mk.create_rule([merge]).add_dependencies(
                     [ref_file, l10n_file] + python_deps)
-                rule.add_commands(
-                    [
-                        '$(PYTHON) -m mozbuild.action.l10n_merge '
-                        '--output {} --ref-file {} --l10n-file {}'.format(
-                            merge, ref_file, l10n_file
-                        )
-                    ]
-                )
+                rule.add_commands(['$(PYTHON) -m mozbuild.action.l10n_merge --output {} --ref-file {} --l10n-file {}'.format(merge, ref_file, l10n_file)])
                 # Add a dummy rule for the l10n file since it might not exist.
                 mk.create_rule([l10n_file])
 
         mk.add_statement('include $(TOPSRCDIR)/config/faster/rules.mk')
 
         for base, install_manifest in self._install_manifests.iteritems():
             with self._write_file(
                     mozpath.join(self.environment.topobjdir, 'faster',
                                  'install_%s' % base.replace('/', '_'))) as fh:
                 install_manifest.write(fileobj=fh)
 
-        # For artifact builds only, write a single unified manifest
-        # for consumption by |mach watch|.
+        # For artifact builds only, write a single unified manifest for consumption by |mach watch|.
         if self.environment.is_artifact_build:
             unified_manifest = InstallManifest()
             for base, install_manifest in self._install_manifests.iteritems():
                 # Expect 'dist/bin/**', which includes 'dist/bin' with no trailing slash.
                 assert base.startswith('dist/bin')
                 base = base[len('dist/bin'):]
                 if base and base[0] == '/':
                     base = base[1:]
--- a/python/mozbuild/mozbuild/backend/mach_commands.py
+++ b/python/mozbuild/mozbuild/backend/mach_commands.py
@@ -1,34 +1,34 @@
 # 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 absolute_import, print_function, unicode_literals
 
 import argparse
 import os
+import sys
 import subprocess
 import which
 
 from mozbuild.base import (
     MachCommandBase,
 )
 
 from mach.decorators import (
     CommandArgument,
     CommandProvider,
     Command,
 )
 
-
 @CommandProvider
 class MachCommands(MachCommandBase):
     @Command('ide', category='devenv',
-             description='Generate a project and launch an IDE.')
+        description='Generate a project and launch an IDE.')
     @CommandArgument('ide', choices=['eclipse', 'visualstudio'])
     @CommandArgument('args', nargs=argparse.REMAINDER)
     def eclipse(self, ide, args):
         if ide == 'eclipse':
             backend = 'CppEclipse'
         elif ide == 'visualstudio':
             backend = 'VisualStudio'
 
@@ -52,21 +52,19 @@ class MachCommands(MachCommandBase):
         config_status = os.path.join(self.topobjdir, 'config.status')
         args = [python, config_status, '--backend=%s' % backend]
         res = self._run_command_in_objdir(args=args, pass_thru=True, ensure_exit_code=False)
         if res != 0:
             return 1
 
         if ide == 'eclipse':
             eclipse_workspace_dir = self.get_eclipse_workspace_path()
-            subprocess.check_call(['eclipse', '-data', eclipse_workspace_dir])
+            process = subprocess.check_call(['eclipse', '-data', eclipse_workspace_dir])
         elif ide == 'visualstudio':
             visual_studio_workspace_dir = self.get_visualstudio_workspace_path()
-            subprocess.check_call(
-                ['explorer.exe', visual_studio_workspace_dir]
-            )
+            process = subprocess.check_call(['explorer.exe', visual_studio_workspace_dir])
 
     def get_eclipse_workspace_path(self):
         from mozbuild.backend.cpp_eclipse import CppEclipseBackend
         return CppEclipseBackend.get_workspace_path(self.topsrcdir, self.topobjdir)
 
     def get_visualstudio_workspace_path(self):
         return os.path.join(self.topobjdir, 'msvc', 'mozilla.sln')
--- a/python/mozbuild/mozbuild/backend/recursivemake.py
+++ b/python/mozbuild/mozbuild/backend/recursivemake.py
@@ -1,13 +1,13 @@
 # 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 absolute_import, print_function, unicode_literals
+from __future__ import absolute_import, unicode_literals
 
 import logging
 import os
 import re
 
 from collections import (
     defaultdict,
     namedtuple,
@@ -46,16 +46,17 @@ from ..frontend.data import (
     HostGeneratedSources,
     HostLibrary,
     HostProgram,
     HostRustProgram,
     HostSimpleProgram,
     HostSources,
     InstallationTarget,
     JARManifest,
+    Library,
     Linkable,
     LocalInclude,
     LocalizedFiles,
     LocalizedPreprocessedFiles,
     ObjdirFiles,
     ObjdirPreprocessedFiles,
     PerSourceFlag,
     PgoGenerateOnlySources,
@@ -120,17 +121,17 @@ MOZBUILD_VARIABLES = [
     b'SHARED_LIBRARY_LIBS',
     b'SHARED_LIBRARY_NAME',
     b'SIMPLE_PROGRAMS',
     b'SONAME',
     b'STATIC_LIBRARY_NAME',
     b'TEST_DIRS',
     b'TOOL_DIRS',
     # XXX config/Makefile.in specifies this in a make invocation
-    # 'USE_EXTENSION_MANIFEST',
+    #'USE_EXTENSION_MANIFEST',
     b'XPCSHELL_TESTS',
     b'XPIDL_MODULE',
 ]
 
 DEPRECATED_VARIABLES = [
     b'ALLOW_COMPILER_WARNINGS',
     b'EXPORT_LIBRARY',
     b'EXTRA_LIBS',
@@ -219,19 +220,19 @@ class BackendMakeFile(object):
 
     def close(self):
         if self.xpt_name:
             # We just recompile all xpidls because it's easier and less error
             # prone.
             self.fh.write('NONRECURSIVE_TARGETS += export\n')
             self.fh.write('NONRECURSIVE_TARGETS_export += xpidl\n')
             self.fh.write('NONRECURSIVE_TARGETS_export_xpidl_DIRECTORY = '
-                          '$(DEPTH)/xpcom/xpidl\n')
+                '$(DEPTH)/xpcom/xpidl\n')
             self.fh.write('NONRECURSIVE_TARGETS_export_xpidl_TARGETS += '
-                          'export\n')
+                'export\n')
 
         return self.fh.close()
 
     @property
     def diff(self):
         return self.fh.diff
 
 
@@ -242,17 +243,16 @@ class RecursiveMakeTraversal(object):
     from Makefiles.
 
     Each directory may have one or more types of subdirectories:
         - (normal) dirs
         - tests
     """
     SubDirectoryCategories = ['dirs', 'tests']
     SubDirectoriesTuple = namedtuple('SubDirectories', SubDirectoryCategories)
-
     class SubDirectories(SubDirectoriesTuple):
         def __new__(self):
             return RecursiveMakeTraversal.SubDirectoriesTuple.__new__(self, [], [])
 
     def __init__(self):
         self._traversal = {}
         self._attached = set()
 
@@ -307,17 +307,17 @@ class RecursiveMakeTraversal(object):
         deps = {}
 
         def recurse(start_node, prev_nodes=None):
             current, parallel, sequential = self.call_filter(start_node, filter)
             if current is not None:
                 if start_node != '':
                     deps[start_node] = prev_nodes
                 prev_nodes = (start_node,)
-            if start_node not in self._traversal:
+            if not start_node in self._traversal:
                 return prev_nodes
             parallel_nodes = []
             for node in parallel:
                 nodes = recurse(node, prev_nodes)
                 if nodes and nodes != ('',):
                     parallel_nodes.extend(nodes)
             if parallel_nodes:
                 prev_nodes = tuple(parallel_nodes)
@@ -333,17 +333,17 @@ class RecursiveMakeTraversal(object):
         make traversal order.
         """
         if filter is None:
             filter = self.default_filter
 
         current, parallel, sequential = self.call_filter(start, filter)
         if current is not None:
             yield start
-        if start not in self._traversal:
+        if not start in self._traversal:
             return
         for node in parallel:
             for n in self.traverse(node, filter):
                 yield n
         for dir in sequential:
             for d in self.traverse(dir, filter):
                 yield d
 
@@ -385,17 +385,17 @@ class RecursiveMakeBackend(CommonBackend
         self._idl_dirs = set()
 
         self._makefile_in_count = 0
         self._makefile_out_count = 0
 
         self._test_manifests = {}
 
         self.backend_input_files.add(mozpath.join(self.environment.topobjdir,
-                                                  'config', 'autoconf.mk'))
+            'config', 'autoconf.mk'))
 
         self._install_manifests = defaultdict(InstallManifest)
         # The build system relies on some install manifests always existing
         # even if they are empty, because the directories are still filled
         # by the build system itself, and the install manifests are only
         # used for a "magic" rm -rf.
         self._install_manifests['dist_public']
         self._install_manifests['dist_private']
@@ -419,17 +419,17 @@ class RecursiveMakeBackend(CommonBackend
                        makefile_in=self._makefile_in_count,
                        makefile_out=self._makefile_out_count)
         return summary
 
     def _get_backend_file_for(self, obj):
         if obj.objdir not in self._backend_files:
             self._backend_files[obj.objdir] = \
                 BackendMakeFile(obj.srcdir, obj.objdir, obj.config,
-                                obj.topsrcdir, self.environment.topobjdir, self.dry_run)
+                    obj.topsrcdir, self.environment.topobjdir, self.dry_run)
         return self._backend_files[obj.objdir]
 
     def consume_object(self, obj):
         """Write out build files necessary to build with recursive make."""
 
         if not isinstance(obj, ContextDerived):
             return False
 
@@ -598,40 +598,35 @@ class RecursiveMakeBackend(CommonBackend
                         # handling.
                         backend_file.write('%s:: %s\n' % (tier, stub_file))
                 for output in outputs:
                     backend_file.write('%s: %s ;\n' % (output, stub_file))
                     backend_file.write('GARBAGE += %s\n' % output)
                 backend_file.write('GARBAGE += %s\n' % stub_file)
                 backend_file.write('EXTRA_MDDEPEND_FILES += %s\n' % dep_file)
 
-                backend_file.write((
-                    """{stub}: {script}{inputs}{backend}{force}
+                backend_file.write("""{stub}: {script}{inputs}{backend}{force}
 \t$(REPORT_BUILD)
-\t$(call py_action,file_generate,{locale}{script} """  # wrap for E501
-                    """{method} {output} $(MDDEPDIR)/{dep_file} {stub}{inputs}{flags})
+\t$(call py_action,file_generate,{locale}{script} {method} {output} $(MDDEPDIR)/{dep_file} {stub}{inputs}{flags})
 \t@$(TOUCH) $@
 
-""").format(
-                    stub=stub_file,
-                    output=first_output,
-                    dep_file=dep_file,
-                    inputs=' ' + ' '.join(inputs) if inputs else '',
-                    flags=' ' + ' '.join(shell_quote(f) for f in obj.flags) if obj.flags else '',
-                    backend=' backend.mk' if obj.flags else '',
-                    # Locale repacks repack multiple locales from a single configured objdir,
-                    # so standard mtime dependencies won't work properly when the build is re-run
-                    # with a different locale as input. IS_LANGUAGE_REPACK will reliably be set
-                    # in this situation, so simply force the generation to run in that case.
-                    force=force,
-                    locale='--locale=$(AB_CD) ' if obj.localized else '',
-                    script=obj.script,
-                    method=obj.method
-                    )
-                )
+""".format(stub=stub_file,
+           output=first_output,
+           dep_file=dep_file,
+           inputs=' ' + ' '.join(inputs) if inputs else '',
+           flags=' ' + ' '.join(shell_quote(f) for f in obj.flags) if obj.flags else '',
+           backend=' backend.mk' if obj.flags else '',
+           # Locale repacks repack multiple locales from a single configured objdir,
+           # so standard mtime dependencies won't work properly when the build is re-run
+           # with a different locale as input. IS_LANGUAGE_REPACK will reliably be set
+           # in this situation, so simply force the generation to run in that case.
+           force=force,
+           locale='--locale=$(AB_CD) ' if obj.localized else '',
+           script=obj.script,
+           method=obj.method))
 
         elif isinstance(obj, JARManifest):
             self._no_skip['libs'].add(backend_file.relobjdir)
             backend_file.write('JAR_MANIFEST := %s\n' % obj.path.full_path)
 
         elif isinstance(obj, RustProgram):
             self._process_rust_program(obj, backend_file)
             self._rust_dirs.add(obj.relobjdir)
@@ -784,29 +779,29 @@ class RecursiveMakeBackend(CommonBackend
 
         root_deps_mk = Makefile()
 
         # Fill the dependencies for traversal of each tier.
         for tier, filter in filters:
             main, all_deps = \
                 self._traversal.compute_dependencies(filter)
             for dir, deps in all_deps.items():
-                if deps is not None or (dir in self._idl_dirs
+                if deps is not None or (dir in self._idl_dirs \
                                         and tier == 'export'):
                     rule = root_deps_mk.create_rule(['%s/%s' % (dir, tier)])
                 if deps:
                     rule.add_dependencies('%s/%s' % (d, tier) for d in deps if d)
                 if dir in self._idl_dirs and tier == 'export':
                     rule.add_dependencies(['xpcom/xpidl/%s' % tier])
             rule = root_deps_mk.create_rule(['recurse_%s' % tier])
             if main:
                 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()
+        all_compile_deps = reduce(lambda x,y: x|y,
+            self._compile_graph.values()) if self._compile_graph else set()
         # Include the following as dependencies of the top recursion target for
         # compilation:
         # - nodes that are not dependended upon by anything. Typically, this
         #   would include programs, that need to be recursed, but that nothing
         #   depends on.
         # - nodes that have no dependencies of their own. Technically, this is
         #   not necessary, because other things have dependencies on them, and
         #   they all end up rooting to nodes from the above category. But the
@@ -817,20 +812,18 @@ class RecursiveMakeBackend(CommonBackend
         compile_roots = [t for t, deps in self._compile_graph.iteritems()
                          if not deps or t not in all_compile_deps]
 
         def add_category_rules(category, roots, graph):
             rule = root_deps_mk.create_rule(['recurse_%s' % category])
             # Directories containing rust compilations don't generally depend
             # on other directories in the tree, so putting them first here will
             # start them earlier in the build.
-            rule.add_dependencies(
-                chain((r for r in roots if mozpath.dirname(r) in self._rust_dirs),
-                      (r for r in roots if mozpath.dirname(r) not in self._rust_dirs))
-                )
+            rule.add_dependencies(chain((r for r in roots if mozpath.dirname(r) in self._rust_dirs),
+                                        (r for r in roots if mozpath.dirname(r) not in self._rust_dirs)))
             for target, deps in sorted(graph.items()):
                 if deps:
                     rule = root_deps_mk.create_rule([target])
                     rule.add_dependencies(deps)
 
         non_default_roots = defaultdict(list)
         non_default_graphs = defaultdict(lambda: OrderedDefaultDict(set))
 
@@ -903,18 +896,17 @@ class RecursiveMakeBackend(CommonBackend
             "# compilation times and debug information size."
         makefile.add_statement(explanation)
 
         all_sources = ' '.join(source for source, _ in unified_source_mapping)
         makefile.add_statement('%s := %s' % (unified_files_makefile_variable,
                                              all_sources))
 
         if include_curdir_build_rules:
-            makefile.add_statement(
-                '\n'
+            makefile.add_statement('\n'
                 '# Make sometimes gets confused between "foo" and "$(CURDIR)/foo".\n'
                 '# Help it out by explicitly specifiying dependencies.')
             makefile.add_statement('all_absolute_unified_files := \\\n'
                                    '  $(addprefix $(CURDIR)/,$(%s))'
                                    % unified_files_makefile_variable)
             rule = makefile.create_rule(['$(all_absolute_unified_files)'])
             rule.add_dependencies(['$(CURDIR)/%: %'])
 
@@ -952,58 +944,58 @@ class RecursiveMakeBackend(CommonBackend
                 makefile_in = mozpath.join(srcdir, 'Makefile.in')
                 makefile = mozpath.join(objdir, 'Makefile')
 
                 # If Makefile.in exists, use it as a template. Otherwise,
                 # create a stub.
                 stub = not os.path.exists(makefile_in)
                 if not stub:
                     self.log(logging.DEBUG, 'substitute_makefile',
-                             {'path': makefile}, 'Substituting makefile: {path}')
+                        {'path': makefile}, 'Substituting makefile: {path}')
                     self._makefile_in_count += 1
 
                     # In the export and libs tiers, we don't skip directories
                     # containing a Makefile.in.
                     # topobjdir is handled separatedly, don't do anything for
                     # it.
                     if bf.relobjdir:
                         for tier in ('export', 'libs',):
                             self._no_skip[tier].add(bf.relobjdir)
                 else:
                     self.log(logging.DEBUG, 'stub_makefile',
-                             {'path': makefile}, 'Creating stub Makefile: {path}')
+                        {'path': makefile}, 'Creating stub Makefile: {path}')
 
                 obj = self.Substitution()
                 obj.output_path = makefile
                 obj.input_path = makefile_in
                 obj.topsrcdir = backend_file.topsrcdir
                 obj.topobjdir = bf.environment.topobjdir
                 obj.config = bf.environment
                 self._create_makefile(obj, stub=stub)
                 with open(obj.output_path) as fh:
                     content = fh.read()
                     # Directories with a Makefile containing a tools target, or
                     # XPI_PKGNAME or INSTALL_EXTENSION_ID can't be skipped and
                     # must run during the 'tools' tier.
                     for t in (b'XPI_PKGNAME', b'INSTALL_EXTENSION_ID',
-                              b'tools'):
+                            b'tools'):
                         if t not in content:
                             continue
                         if t == b'tools' and not re.search('(?:^|\s)tools.*::', content, re.M):
                             continue
                         if objdir == self.environment.topobjdir:
                             continue
                         self._no_skip['tools'].add(mozpath.relpath(objdir,
-                                                                   self.environment.topobjdir))
+                            self.environment.topobjdir))
 
                     # Directories with a Makefile containing a check target
                     # can't be skipped and must run during the 'check' tier.
                     if re.search('(?:^|\s)check.*::', content, re.M):
                         self._no_skip['check'].add(mozpath.relpath(objdir,
-                                                                   self.environment.topobjdir))
+                            self.environment.topobjdir))
 
                     # Detect any Makefile.ins that contain variables on the
                     # moz.build-only list
                     self._check_blacklisted_variables(makefile_in, content)
 
         self._fill_root_mk()
 
         # Make the master test manifest files.
@@ -1070,20 +1062,20 @@ class RecursiveMakeBackend(CommonBackend
     def _process_directory_traversal(self, obj, backend_file):
         """Process a data.DirectoryTraversal instance."""
         fh = backend_file.fh
 
         def relativize(base, dirs):
             return (mozpath.relpath(d.translated, base) for d in dirs)
 
         if obj.dirs:
-            fh.write('DIRS := %s\n' % ' '.join(relativize(backend_file.objdir, obj.dirs)))
-            self._traversal.add(
-                backend_file.relobjdir, dirs=relativize(self.environment.topobjdir, obj.dirs)
-            )
+            fh.write('DIRS := %s\n' % ' '.join(
+                relativize(backend_file.objdir, obj.dirs)))
+            self._traversal.add(backend_file.relobjdir,
+                dirs=relativize(self.environment.topobjdir, obj.dirs))
 
         # The directory needs to be registered whether subdirectories have been
         # registered or not.
         self._traversal.add(backend_file.relobjdir)
 
     def _process_defines(self, obj, backend_file, which='DEFINES'):
         """Output the DEFINES rules to the given backend file."""
         defines = list(obj.get_defines())
@@ -1097,35 +1089,33 @@ class RecursiveMakeBackend(CommonBackend
         # much as possible here to avoid breaking things.
         if obj.xpiname:
             backend_file.write('XPI_NAME = %s\n' % (obj.xpiname))
         if obj.subdir:
             backend_file.write('DIST_SUBDIR = %s\n' % (obj.subdir))
         if obj.target and not obj.is_custom():
             backend_file.write('FINAL_TARGET = $(DEPTH)/%s\n' % (obj.target))
         else:
-            backend_file.write(
-                'FINAL_TARGET = $(if $(XPI_NAME),$(DIST)/xpi-stage/$(XPI_NAME),'
-                '$(DIST)/bin)$(DIST_SUBDIR:%=/%)\n'
-                )
+            backend_file.write('FINAL_TARGET = $(if $(XPI_NAME),$(DIST)/xpi-stage/$(XPI_NAME),$(DIST)/bin)$(DIST_SUBDIR:%=/%)\n')
 
         if not obj.enabled:
             backend_file.write('NO_DIST_INSTALL := 1\n')
 
     def _handle_idl_manager(self, manager):
         build_files = self._install_manifests['xpidl']
 
         for p in ('Makefile', 'backend.mk', '.deps/.mkdir.done'):
             build_files.add_optional_exists(p)
 
         for stem in manager.idl_stems():
             self._install_manifests['dist_include'].add_optional_exists('%s.h' % stem)
 
         for module in manager.modules:
-            build_files.add_optional_exists(mozpath.join('.deps', '%s.pp' % module))
+            build_files.add_optional_exists(mozpath.join('.deps',
+                '%s.pp' % module))
 
         modules = manager.modules
         xpt_modules = sorted(modules.keys())
 
         mk = Makefile()
         all_directories = set()
 
         for module_name in xpt_modules:
@@ -1155,19 +1145,19 @@ class RecursiveMakeBackend(CommonBackend
 
         # Create dependency for output header so we force regeneration if the
         # header was deleted. This ideally should not be necessary. However,
         # some processes (such as PGO at the time this was implemented) wipe
         # out dist/include without regard to our install manifests.
 
         obj = self.Substitution()
         obj.output_path = mozpath.join(self.environment.topobjdir, 'config',
-                                       'makefiles', 'xpidl', 'Makefile')
+            'makefiles', 'xpidl', 'Makefile')
         obj.input_path = mozpath.join(self.environment.topsrcdir, 'config',
-                                      'makefiles', 'xpidl', 'Makefile.in')
+            'makefiles', 'xpidl', 'Makefile.in')
         obj.topsrcdir = self.environment.topsrcdir
         obj.topobjdir = self.environment.topobjdir
         obj.config = self.environment
         self._create_makefile(obj, extra=dict(
             xpidl_rules=rules.getvalue(),
             xpidl_modules=' '.join(xpt_modules),
         ))
 
@@ -1241,45 +1231,45 @@ class RecursiveMakeBackend(CommonBackend
         self._install_manifests['_tests'].add_optional_exists(
             mozpath.join(obj.install_target[len('_tests') + 1:],
                          dest_basename))
 
     def _process_test_manifest(self, obj, backend_file):
         # Much of the logic in this function could be moved to CommonBackend.
         for source in obj.source_relpaths:
             self.backend_input_files.add(mozpath.join(obj.topsrcdir,
-                                                      source))
+                source))
 
         # 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():
             try:
                 self._install_manifests['_test_files'].add_link(source, dest)
             except ValueError:
                 if not obj.dupe_manifest and is_test:
                     raise
 
         for base, pattern, dest in obj.pattern_installs:
             try:
                 self._install_manifests['_test_files'].add_pattern_link(base,
-                                                                        pattern, dest)
+                    pattern, dest)
             except ValueError:
                 if not obj.dupe_manifest:
                     raise
 
         for dest in obj.external_installs:
             try:
                 self._install_manifests['_test_files'].add_optional_exists(dest)
             except ValueError:
                 if not obj.dupe_manifest:
                     raise
 
         m = self._test_manifests.setdefault(obj.flavor,
-                                            (obj.install_prefix, set()))
+            (obj.install_prefix, set()))
         m[1].add(obj.manifest_obj_relpath)
 
         try:
             from reftest import ReftestManifest
 
             if isinstance(obj.manifest, ReftestManifest):
                 # Mark included files as part of the build backend so changes
                 # result in re-config.
@@ -1300,24 +1290,22 @@ class RecursiveMakeBackend(CommonBackend
         if quoted_path != path:
             path = quoted_path[0] + d + quoted_path[1:]
         else:
             path = d + path
         backend_file.write('LOCAL_INCLUDES += -I%s\n' % path)
 
     def _process_per_source_flag(self, per_source_flag, backend_file):
         for flag in per_source_flag.flags:
-            backend_file.write('%s_FLAGS += %s\n' %
-                               (mozpath.basename(per_source_flag.file_name), flag))
+            backend_file.write('%s_FLAGS += %s\n' % (mozpath.basename(per_source_flag.file_name), flag))
 
     def _process_computed_flags(self, computed_flags, backend_file):
         for var, flags in computed_flags.get_flags():
-            backend_file.write(
-                'COMPUTED_%s += %s\n' % (var,
-                                         ' '.join(make_quote(shell_quote(f)) for f in flags)))
+            backend_file.write('COMPUTED_%s += %s\n' % (var,
+                                                        ' '.join(make_quote(shell_quote(f)) for f in flags)))
 
     def _process_non_default_target(self, libdef, target_name, backend_file):
         backend_file.write("%s:: %s\n" % (libdef.output_category, target_name))
         backend_file.write('MOZBUILD_NON_DEFAULT_TARGETS += %s\n' % target_name)
 
     def _process_shared_library(self, libdef, backend_file):
         backend_file.write_once('LIBRARY_NAME := %s\n' % libdef.basename)
         backend_file.write('FORCE_SHARED_LIB := 1\n')
@@ -1364,23 +1352,24 @@ class RecursiveMakeBackend(CommonBackend
         backend_file.write('HOST_SHARED_LIBRARY = %s\n' % libdef.lib_name)
 
     def _build_target_for_obj(self, obj):
         if hasattr(obj, 'output_category') and obj.output_category:
             target_name = obj.output_category
         else:
             target_name = obj.KIND
         return '%s/%s' % (mozpath.relpath(obj.objdir,
-                                          self.environment.topobjdir), target_name)
+            self.environment.topobjdir), target_name)
 
     def _process_linked_libraries(self, obj, backend_file):
         def pretty_relpath(lib, name):
             return os.path.normpath(mozpath.join(mozpath.relpath(lib.objdir, obj.objdir),
                                                  name))
 
+        topobjdir = mozpath.normsep(obj.topobjdir)
         # This will create the node even if there aren't any linked libraries.
         build_target = self._build_target_for_obj(obj)
         self._compile_graph[build_target]
 
         objs, pgo_gen_objs, no_pgo_objs, shared_libs, os_libs, static_libs = self._expand_libs(obj)
 
         obj_target = obj.name
         if isinstance(obj, Program):
@@ -1420,17 +1409,17 @@ class RecursiveMakeBackend(CommonBackend
         pgo_objs_ref = ' \\\n    '.join(os.path.relpath(o, obj.objdir)
                                         for o in profile_gen_objs)
         # Don't bother with a list file if we're only linking objects built
         # in this directory or building a real static library. This
         # accommodates clang-plugin, where we would otherwise pass an
         # incorrect list file format to the host compiler as well as when
         # creating an archive with AR, which doesn't understand list files.
         if (objs == obj.objs and not isinstance(obj, (HostLibrary, StaticLibrary)) or
-            isinstance(obj, StaticLibrary) and obj.no_expand_lib):
+          isinstance(obj, StaticLibrary) and obj.no_expand_lib):
             backend_file.write_once('%s_OBJS := %s\n' % (obj.name,
                                                          objs_ref))
             if profile_gen_objs:
                 backend_file.write_once('%s_PGO_OBJS := %s\n' % (obj.name,
                                                                  pgo_objs_ref))
             write_obj_deps(obj_target, objs_ref, pgo_objs_ref)
         elif not isinstance(obj, (HostLibrary, StaticLibrary)):
             list_file_path = '%s.list' % obj.name.replace('.', '_')
@@ -1525,18 +1514,18 @@ class RecursiveMakeBackend(CommonBackend
             for f in files:
                 assert not isinstance(f, RenamedSourcePath)
                 dest = mozpath.join(reltarget, path, f.target_basename)
                 if not isinstance(f, ObjDirPath):
                     if '*' in f:
                         if f.startswith('/') or isinstance(f, AbsolutePath):
                             basepath, wild = os.path.split(f.full_path)
                             if '*' in basepath:
-                                raise Exception("Wildcards are only supported in the filename part"
-                                                " of srcdir-relative or absolute paths.")
+                                raise Exception("Wildcards are only supported in the filename part of "
+                                                "srcdir-relative or absolute paths.")
 
                             install_manifest.add_pattern_link(basepath, wild, path)
                         else:
                             install_manifest.add_pattern_link(f.srcdir, f, path)
                     else:
                         install_manifest.add_link(f.full_path, dest)
                 else:
                     install_manifest.add_optional_exists(dest)
@@ -1657,17 +1646,17 @@ class RecursiveMakeBackend(CommonBackend
         ]
         rule.add_commands(['$(call py_action,buildlist,%s)' % ' '.join(args)])
         fragment.dump(backend_file.fh, removal_guard=False)
 
         self._no_skip['misc'].add(obj.relsrcdir)
 
     def _write_manifests(self, dest, manifests):
         man_dir = mozpath.join(self.environment.topobjdir, '_build_manifests',
-                               dest)
+            dest)
 
         for k, manifest in manifests.items():
             with self._write_file(mozpath.join(man_dir, k)) as fh:
                 manifest.write(fileobj=fh)
 
     def _write_master_test_manifest(self, path, manifests):
         with self._write_file(path) as master:
             master.write(
@@ -1694,17 +1683,17 @@ class RecursiveMakeBackend(CommonBackend
         When the stub argument is True, no source file is used, and a stub
         makefile with the default header and footer only is created.
         '''
         with self._get_preprocessor(obj) as pp:
             if extra:
                 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'# 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'srcdir_rel := @srcdir_rel@\n')
             pp.handleLine(b'VPATH := @srcdir@\n')
             pp.handleLine(b'relativesrcdir := @relativesrcdir@\n')
             pp.handleLine(b'include $(DEPTH)/config/@autoconfmk@\n')
@@ -1738,38 +1727,37 @@ class RecursiveMakeBackend(CommonBackend
         for source in sorted_nonstatic_ipdl_sources:
             basename = os.path.basename(source)
             sorted_nonstatic_ipdl_basenames.append(basename)
             rule = mk.create_rule([basename])
             rule.add_dependencies([source])
             rule.add_commands([
                 '$(RM) $@',
                 '$(call py_action,preprocessor,$(DEFINES) $(ACDEFINES) '
-                '$< -o $@)'
+                    '$< -o $@)'
             ])
 
         mk.add_statement('ALL_IPDLSRCS := %s %s' % (' '.join(sorted_nonstatic_ipdl_basenames),
-                                                    ' '.join(sorted_static_ipdl_sources)))
+                         ' '.join(sorted_static_ipdl_sources)))
 
         self._add_unified_build_rules(mk, unified_ipdl_cppsrcs_mapping,
                                       unified_files_makefile_variable='CPPSRCS')
 
         # Preprocessed ipdl files are generated in ipdl_dir.
-        mk.add_statement(
-            'IPDLDIRS := %s %s' % (ipdl_dir, ' '.join(sorted(set(mozpath.dirname(p)
-                                                      for p in sorted_static_ipdl_sources)))))
+        mk.add_statement('IPDLDIRS := %s %s' % (ipdl_dir, ' '.join(sorted(set(mozpath.dirname(p)
+            for p in sorted_static_ipdl_sources)))))
 
         with self._write_file(mozpath.join(ipdl_dir, 'ipdlsrcs.mk')) as ipdls:
             mk.dump(ipdls, removal_guard=False)
 
     def _handle_webidl_build(self, bindings_dir, unified_source_mapping,
                              webidls, expected_build_output_files,
                              global_define_files):
         include_dir = mozpath.join(self.environment.topobjdir, 'dist',
-                                   'include')
+            'include')
         for f in expected_build_output_files:
             if f.startswith(include_dir):
                 self._install_manifests['dist_include'].add_optional_exists(
                     mozpath.relpath(f, include_dir))
 
         # We pass WebIDL info to make via a completely generated make file.
         mk = Makefile()
         mk.add_statement('nonstatic_webidl_files := %s' % ' '.join(
@@ -1790,18 +1778,18 @@ class RecursiveMakeBackend(CommonBackend
             rule = mk.create_rule([basename])
             rule.add_dependencies([source, '$(GLOBAL_DEPS)'])
             rule.add_commands([
                 # Remove the file before writing so bindings that go from
                 # static to preprocessed don't end up writing to a symlink,
                 # which would modify content in the source directory.
                 '$(RM) $@',
                 '$(call py_action,preprocessor,$(DEFINES) $(ACDEFINES) '
-                '$< -o $@)'
+                    '$< -o $@)'
             ])
 
         self._add_unified_build_rules(mk,
-                                      unified_source_mapping,
-                                      unified_files_makefile_variable='unified_binding_cpp_files')
+            unified_source_mapping,
+            unified_files_makefile_variable='unified_binding_cpp_files')
 
         webidls_mk = mozpath.join(bindings_dir, 'webidlsrcs.mk')
         with self._write_file(webidls_mk) as fh:
             mk.dump(fh, removal_guard=False)
--- a/python/mozbuild/mozbuild/backend/test_manifest.py
+++ b/python/mozbuild/mozbuild/backend/test_manifest.py
@@ -1,13 +1,13 @@
 # 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 absolute_import, print_function, unicode_literals
+from __future__ import absolute_import, unicode_literals
 
 import cPickle as pickle
 from collections import defaultdict
 
 import mozpack.path as mozpath
 
 from mozbuild.backend.base import PartialBackend
 from mozbuild.frontend.data import TestManifest
--- a/python/mozbuild/mozbuild/backend/tup.py
+++ b/python/mozbuild/mozbuild/backend/tup.py
@@ -1,25 +1,28 @@
 # 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 absolute_import, print_function, unicode_literals
+from __future__ import absolute_import, unicode_literals
 
 import os
 import gzip
 import itertools
 import json
 import sys
 import shutil
 
 import mozpack.path as mozpath
+from mozbuild import shellutil
 from mozbuild.analyze.graph import Graph
 from mozbuild.analyze.hg import Report
 from mozbuild.base import MozbuildObject
+from mozbuild.backend.base import PartialBackend, HybridBackend
+from mozbuild.backend.recursivemake import RecursiveMakeBackend
 from mozbuild.mozconfig import MozconfigLoader
 from mozbuild.shellutil import quote as shell_quote
 from mozbuild.util import OrderedDefaultDict
 from collections import defaultdict
 import multiprocessing
 
 from mozpack.files import (
     FileFinder,
@@ -51,16 +54,17 @@ from ..frontend.data import (
     RustProgram,
     SharedLibrary,
     Sources,
     StaticLibrary,
     VariablePassthru,
 )
 from ..util import (
     FileAvoidWrite,
+    expand_variables,
 )
 from ..frontend.context import (
     AbsolutePath,
     ObjDirPath,
     RenamedSourcePath,
 )
 from .cargo_build_defs import (
     cargo_extra_outputs,
@@ -138,18 +142,17 @@ class BackendTupfile(object):
             # same.
             flags += "o"
 
         if display:
             caret_text = flags + ' ' + display
         else:
             caret_text = flags
 
-        self.write((': %(inputs)s%(extra_inputs)s |> %(display)s%(cmd)s |> '
-                    '%(outputs)s%(output_group)s\n') % {
+        self.write(': %(inputs)s%(extra_inputs)s |> %(display)s%(cmd)s |> %(outputs)s%(output_group)s\n' % {
             'inputs': ' '.join(inputs),
             'extra_inputs': ' | ' + ' '.join(extra_inputs) if extra_inputs else '',
             'display': '^%s^ ' % caret_text if caret_text else '',
             'cmd': ' '.join(cmd),
             'outputs': ' '.join(outputs),
             'output_group': ' ' + output_group if output_group else '',
         })
 
@@ -264,18 +267,17 @@ class TupBackend(CommonBackend):
         self._early_generated_files = self._output_group('early-generated-files')
 
         self._shlibs = self._output_group('shlibs')
         self._default_group = self._output_group('default')
 
         self._rust_cmds = set()
 
         self._built_in_addons = set()
-        self._built_in_addons_file = \
-            'dist/bin/browser/chrome/browser/content/browser/built_in_addons.json'
+        self._built_in_addons_file = 'dist/bin/browser/chrome/browser/content/browser/built_in_addons.json'
 
     def _output_group(self, label):
         if label:
             return '$(MOZ_OBJ_ROOT)/<%s>' % label
 
     def _rust_output_group(self, label):
         if label:
             return self._output_group('rust-' + label)
@@ -325,19 +327,19 @@ class TupBackend(CommonBackend):
             args += ['-j%d' % jobs]
         else:
             args += ['-j%d' % multiprocessing.cpu_count()]
 
         tiers = output.monitor.tiers
         tiers.set_tiers(('tup',))
         tiers.begin_tier('tup')
         status = config.run_process(args=args,
-                                    line_handler=output.on_line,
-                                    ensure_exit_code=False,
-                                    append_env=self._get_mozconfig_env(config))
+                                  line_handler=output.on_line,
+                                  ensure_exit_code=False,
+                                  append_env=self._get_mozconfig_env(config))
         tiers.finish_tier('tup')
         if not status and self.environment.substs.get('MOZ_AUTOMATION'):
             config.log_manager.enable_unstructured()
             config._activate_virtualenv()
             config.virtualenv_manager.install_pip_package('tablib==0.12.1')
             src = mozpath.join(self.environment.topsrcdir, '.tup')
             dst = os.environ['UPLOAD_PATH']
             if self.environment.substs.get('UPLOAD_TUP_DB'):
@@ -468,16 +470,17 @@ class TupBackend(CommonBackend):
         static_libs = self._lib_paths(backend_file.objdir, static_libs)
         shared_libs = self._lib_paths(backend_file.objdir, shared_libs)
 
         # Linking some programs will access libraries installed to dist/bin,
         # so depend on the installed libraries here. This can be made more
         # accurate once we start building libraries in their final locations.
         inputs = objs + static_libs + shared_libs + [self._shlibs]
 
+
         rust_linked = [l for l in prog.linked_libraries
                        if isinstance(l, RustLibrary)]
 
         extra_inputs = []
         if rust_linked:
             extra_inputs = [self._rust_output_group(rust_linked[0].output_category) or
                             self._rust_libs]
             static_libs += self._lib_paths(backend_file.objdir, rust_linked)
@@ -505,20 +508,22 @@ class TupBackend(CommonBackend):
         backend_file.rule(
             cmd=cmd,
             inputs=inputs,
             extra_inputs=extra_inputs,
             outputs=outputs,
             display='LINK %o'
         )
 
+
     def _gen_host_programs(self, backend_file):
         for p in backend_file.host_programs:
             self._gen_host_program(backend_file, p)
 
+
     def _gen_host_program(self, backend_file, prog):
         _, _, _, _, extra_libs, _ = self._expand_libs(prog)
         objs = prog.objs
 
         if isinstance(prog, HostSimpleProgram):
             outputs = [prog.name]
         else:
             outputs = [mozpath.relpath(prog.output_path.full_path,
@@ -549,16 +554,17 @@ class TupBackend(CommonBackend):
         backend_file.rule(
             cmd=cmd,
             inputs=inputs,
             extra_inputs=extra_inputs,
             outputs=outputs,
             display='LINK %o'
         )
 
+
     def _gen_static_library(self, backend_file):
         ar = [
             backend_file.environment.substs['AR'],
             backend_file.environment.substs['AR_FLAGS'].replace('$@', '%o')
         ]
 
         objs, _, _, shared_libs, _, static_libs = self._expand_libs(backend_file.static_lib)
         static_libs = self._lib_paths(backend_file.objdir, static_libs)
@@ -573,16 +579,17 @@ class TupBackend(CommonBackend):
 
         backend_file.rule(
             cmd=cmd,
             inputs=inputs,
             outputs=[backend_file.static_lib.name],
             display='AR %o'
         )
 
+
     def consume_object(self, obj):
         """Write out build files necessary to build with tup."""
 
         if not isinstance(obj, ContextDerived):
             return False
 
         consumed = CommonBackend.consume_object(self, obj)
         if consumed:
@@ -665,38 +672,35 @@ class TupBackend(CommonBackend):
 
         if self._built_in_addons:
             with self._write_file(mozpath.join(self.environment.topobjdir,
                                                self._built_in_addons_file)) as fh:
                 json.dump({'system': sorted(list(self._built_in_addons))}, fh)
 
         for objdir, backend_file in sorted(self._backend_files.items()):
             backend_file.gen_sources_rules([self._installed_files])
-            for var, gen_method in (
-                (backend_file.shared_lib, self._gen_shared_library),
-                (backend_file.static_lib and backend_file.static_lib.no_expand_lib,
-                 self._gen_static_library),
-                (backend_file.programs, self._gen_programs),
-                (backend_file.host_programs, self._gen_host_programs)
-            ):
+            for var, gen_method in ((backend_file.shared_lib, self._gen_shared_library),
+                                    (backend_file.static_lib and backend_file.static_lib.no_expand_lib,
+                                     self._gen_static_library),
+                                    (backend_file.programs, self._gen_programs),
+                                    (backend_file.host_programs, self._gen_host_programs)):
                 if var:
                     backend_file.export_shell()
                     backend_file.export_icecc()
                     gen_method(backend_file)
             for obj in backend_file.delayed_generated_files:
                 self._process_generated_file(backend_file, obj)
             for path, output, output_group in backend_file.delayed_installed_files:
                 backend_file.symlink_rule(path, output=output, output_group=output_group)
             with self._write_file(fh=backend_file):
                 pass
 
         with self._write_file(mozpath.join(self.environment.topobjdir, 'Tuprules.tup')) as fh:
-            acdefines_flags = ' '.join(
-                ['-D%s=%s' % (name, shell_quote(value))
-                 for (name, value) in sorted(self.environment.acdefines.iteritems())])
+            acdefines_flags = ' '.join(['-D%s=%s' % (name, shell_quote(value))
+                for (name, value) in sorted(self.environment.acdefines.iteritems())])
             # TODO: AB_CD only exists in Makefiles at the moment.
             acdefines_flags += ' -DAB_CD=en-US'
 
             # Use BUILD_FASTER to avoid CXXFLAGS/CPPFLAGS in
             # toolkit/content/buildconfig.html
             acdefines_flags += ' -DBUILD_FASTER=1'
 
             fh.write('MOZ_OBJ_ROOT = $(TUP_CWD)\n')
@@ -720,23 +724,22 @@ class TupBackend(CommonBackend):
                 print("Found old tup root at '%s', removing..." %
                       mozpath.join(self.environment.topsrcdir, '.tup'))
                 shutil.rmtree(mozpath.join(self.environment.topsrcdir, '.tup'))
         if not os.path.isdir(mozpath.join(tup_base_dir, '.tup')):
             if tup_base_dir != self.environment.topsrcdir:
                 # Ask the user to figure out where to run 'tup init' before
                 # continuing.
                 raise Exception("Please run `tup init --no-sync` in a common "
-                                "ancestor directory of your objdir and srcdir, possibly "
-                                "%s. To reduce file scanning overhead, this directory "
-                                "should contain the fewest files possible that are not "
-                                "necessary for this build." % tup_base_dir)
+                    "ancestor directory of your objdir and srcdir, possibly "
+                    "%s. To reduce file scanning overhead, this directory "
+                    "should contain the fewest files possible that are not "
+                    "necessary for this build." % tup_base_dir)
             tup = self.environment.substs.get('TUP', 'tup')
-            self._cmd.run_process(cwd=tup_base_dir, log_name='tup',
-                                  args=[tup, 'init', '--no-sync'])
+            self._cmd.run_process(cwd=tup_base_dir, log_name='tup', args=[tup, 'init', '--no-sync'])
 
     def _get_cargo_flags(self, obj):
 
         def output_flags(obj):
             if isinstance(obj, RustLibrary):
                 return ['--lib']
             if isinstance(obj, RustProgram):
                 return ['--bin', obj.name]
@@ -805,21 +808,23 @@ class TupBackend(CommonBackend):
         return env
 
     def _gen_cargo_rules(self, obj,  build_plan, cargo_env, output_group):
         invocations = build_plan['invocations']
         processed = set()
 
         # Enable link-time optimization for release builds.
         cargo_library_flags = []
-        if not obj.config.substs.get('DEVELOPER_OPTIONS') and not obj.config.substs.get(
-            'MOZ_DEBUG_RUST'
-        ):
+        if (not obj.config.substs.get('DEVELOPER_OPTIONS') and
+            not obj.config.substs.get('MOZ_DEBUG_RUST')):
             cargo_library_flags += ['-C', 'lto']
 
+        rust_build_home = mozpath.join(self.environment.topobjdir,
+                                       'toolkit/library/rust')
+
         def display_name(invocation):
             output_str = ''
             if invocation['outputs']:
                 outputs = [os.path.basename(f) for f in invocation['outputs']]
                 output_str = ' -> [%s]' % self._trim_outputs(outputs)
             return '{name} v{version} {kind}{output}'.format(
                 name=invocation['package_name'],
                 version=invocation['package_version'],
@@ -863,19 +868,17 @@ class TupBackend(CommonBackend):
             if (invocation['target_kind'][0] == 'staticlib' and
                 obj.basename == shortname):
                 command += cargo_library_flags
 
             outputs = invocation['outputs']
 
             invocation['full-deps'] = set()
 
-            if os.path.basename(invocation['program']) in [
-                'build-script-build', 'build-script-main'
-            ]:
+            if os.path.basename(invocation['program']) in ['build-script-build', 'build-script-main']:
                 out_dir = invocation['env']['OUT_DIR']
                 for output in cargo_extra_outputs.get(shortname, []):
                     outputs.append(os.path.join(out_dir, output))
 
                 script_stdout = mozpath.join(out_dir,
                                              '%s_%s_build_out.txt' % (shortname,
                                                                       invocation['kind']))
                 command.extend(['>', script_stdout])
@@ -976,25 +979,26 @@ class TupBackend(CommonBackend):
                     if invocation['target_kind'][0] == 'bin' and link in outputs:
                         # Additionally link the program to its final target.
                         rust_backend_file.symlink_rule(link,
                                                        mozpath.join(self.environment.topobjdir,
                                                                     obj.install_target,
                                                                     obj.name),
                                                        output_group)
 
+
         for val in enumerate(invocations):
             _process(*val)
 
+
     def _gen_rust_rules(self, obj, backend_file):
         cargo_flags = self._get_cargo_flags(obj)
         cargo_env = self._get_cargo_env(obj, backend_file)
 
         output_lines = []
-
         def accumulate_output(line):
             output_lines.append(line)
 
         cargo_status = self._cmd.run_process(
             [self.environment.substs['CARGO'], 'build'] + cargo_flags,
             line_handler=accumulate_output,
             ensure_exit_code=False,
             explicit_env=cargo_env)
@@ -1005,28 +1009,29 @@ class TupBackend(CommonBackend):
         cargo_plan = json.loads(''.join(output_lines))
 
         output_group = self._rust_libs
         if isinstance(obj, RustLibrary) and obj.output_category:
             output_group = self._rust_output_group(obj.output_category)
         self._gen_cargo_rules(obj, cargo_plan, cargo_env, output_group)
         self.backend_input_files |= set(cargo_plan['inputs'])
 
+
     def _process_generated_file(self, backend_file, obj):
         if obj.script and obj.method:
             backend_file.export_shell()
             cmd = self._py_action('file_generate')
             if obj.localized:
                 cmd.append('--locale=en-US')
             cmd.extend([
                 obj.script,
                 obj.method,
                 obj.outputs[0],
-                '%s.pp' % obj.outputs[0],  # deps file required
-                'unused',  # deps target is required
+                '%s.pp' % obj.outputs[0], # deps file required
+                'unused', # deps target is required
             ])
             full_inputs = [f.full_path for f in obj.inputs]
             cmd.extend(full_inputs)
             cmd.extend(shell_quote(f) for f in obj.flags)
 
             outputs = []
             outputs.extend(obj.outputs)
             outputs.append('%s.pp' % obj.outputs[0])
@@ -1115,19 +1120,18 @@ class TupBackend(CommonBackend):
                     output_group = self._installed_files
 
                 if not isinstance(f, ObjDirPath):
                     backend_file = self._get_backend_file(mozpath.join(target, path))
                     if '*' in f:
                         if f.startswith('/') or isinstance(f, AbsolutePath):
                             basepath, wild = os.path.split(f.full_path)
                             if '*' in basepath:
-                                raise Exception(
-                                    "Wildcards are only supported in the filename part of "
-                                    "srcdir-relative or absolute paths.")
+                                raise Exception("Wildcards are only supported in the filename part of "
+                                                "srcdir-relative or absolute paths.")
 
                             # TODO: This is only needed for Windows, so we can
                             # skip this for now.
                             pass
                         else:
                             def _prefix(s):
                                 for p in mozpath.split(s):
                                     if '*' not in p:
@@ -1146,50 +1150,48 @@ class TupBackend(CommonBackend):
                             # can rely on 'path' to be our destination path relative
                             # to any wildcard match. Otherwise, the output file may
                             # contribute to our destination directory.
                             if not isinstance(f, RenamedSourcePath):
                                 output_dir = ''.join(_prefix(mozpath.dirname(f)))
 
                             finder = FileFinder(prefix)
                             for p, _ in finder.find(f.full_path[len(prefix):]):
+                                install_dir = prefix[len(obj.srcdir) + 1:]
                                 output = p
                                 if f.target_basename and '*' not in f.target_basename:
                                     output = mozpath.join(f.target_basename, output)
                                 backend_file.symlink_rule(mozpath.join(prefix, p),
                                                           output=mozpath.join(output_dir, output),
                                                           output_group=output_group)
                     else:
-                        backend_file.symlink_rule(
-                            f.full_path, output=f.target_basename, output_group=output_group)
+                        backend_file.symlink_rule(f.full_path, output=f.target_basename, output_group=output_group)
                 else:
                     if (self.environment.is_artifact_build and
-                        any(mozpath.match(f.target_basename, p)
-                            for p in self._compile_env_gen_files)):
+                        any(mozpath.match(f.target_basename, p) for p in self._compile_env_gen_files)):
                         # If we have an artifact build we never would have generated this file,
                         # so do not attempt to install it.
                         continue
 
                     output = mozpath.join('$(MOZ_OBJ_ROOT)', target, path,
                                           f.target_basename)
                     gen_backend_file = self._get_backend_file(f.context.relobjdir)
                     if gen_backend_file.requires_delay([f]):
-                        gen_backend_file.delayed_installed_files.append(
-                            (f.full_path, output, output_group))
+                        gen_backend_file.delayed_installed_files.append((f.full_path, output, output_group))
                     else:
                         gen_backend_file.symlink_rule(f.full_path, output=output,
                                                       output_group=output_group)
 
+
     def _process_final_target_pp_files(self, obj, backend_file):
         for i, (path, files) in enumerate(obj.files.walk()):
             self._add_features(obj.install_target, path)
             for f in files:
                 self._preprocess(backend_file, f.full_path,
-                                 destdir=mozpath.join(self.environment.topobjdir,
-                                                      obj.install_target, path),
+                                 destdir=mozpath.join(self.environment.topobjdir, obj.install_target, path),
                                  target=f.target_basename)
 
     def _process_computed_flags(self, obj, backend_file):
         for var, flags in obj.get_flags():
             backend_file.local_flags[var] = flags
 
     def _process_unified_sources(self, obj):
         backend_file = self._get_backend_file_for(obj)
@@ -1308,18 +1310,17 @@ class TupBackend(CommonBackend):
             '--msg-metadata=%s/message-metadata.ini' % srcdir,
             '--outheaders-dir=%s' % outheaderdir,
             '--outcpp-dir=.',
         ]
         ipdldirs = sorted(set(mozpath.dirname(p) for p in sorted_ipdl_sources))
         cmd.extend(['-I%s' % d for d in ipdldirs])
         cmd.extend(sorted_ipdl_sources)
 
-        outputs = ['IPCMessageTypeName.cpp', mozpath.join(
-            outheaderdir, 'IPCMessageStart.h'), 'ipdl_lextab.py', 'ipdl_yacctab.py']
+        outputs = ['IPCMessageTypeName.cpp', mozpath.join(outheaderdir, 'IPCMessageStart.h'), 'ipdl_lextab.py', 'ipdl_yacctab.py']
 
         for filename in sorted_ipdl_sources:
             filepath, ext = os.path.splitext(filename)
             dirname, basename = os.path.split(filepath)
             dirname = mozpath.relpath(dirname, self.environment.topsrcdir)
 
             extensions = ['']
             if ext == '.ipdl':
@@ -1373,10 +1374,9 @@ class TupBackend(CommonBackend):
             outputs=outputs,
             output_group=self._installed_files,
             check_unchanged=True,
         )
         backend_file.sources['.cpp'].extend(u[0] for u in unified_source_mapping)
         backend_file.sources['.cpp'].extend(sorted(global_define_files))
 
         test_backend_file = self._get_backend_file('dom/bindings/test')
-        test_backend_file.sources['.cpp'].extend(
-            sorted('../%sBinding.cpp' % s for s in webidls.all_test_stems()))
+        test_backend_file.sources['.cpp'].extend(sorted('../%sBinding.cpp' % s for s in webidls.all_test_stems()))
--- a/python/mozbuild/mozbuild/backend/visualstudio.py
+++ b/python/mozbuild/mozbuild/backend/visualstudio.py
@@ -1,20 +1,21 @@
 # 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/.
 
 # This file contains a build backend for generating Visual Studio project
 # files.
 
-from __future__ import absolute_import, print_function, unicode_literals
+from __future__ import absolute_import, unicode_literals
 
 import errno
 import os
 import re
+import types
 import uuid
 
 from xml.dom import getDOMImplementation
 
 from mozpack.files import FileFinder
 
 from .common import CommonBackend
 from ..frontend.data import (
@@ -28,35 +29,31 @@ from ..frontend.data import (
     Sources,
     UnifiedSources,
 )
 from mozbuild.base import ExecutionSummary
 
 
 MSBUILD_NAMESPACE = 'http://schemas.microsoft.com/developer/msbuild/2003'
 
-
 def get_id(name):
     return str(uuid.uuid5(uuid.NAMESPACE_URL, name)).upper()
 
-
 def visual_studio_product_to_solution_version(version):
     if version == '2017':
         return '12.00', '15'
     else:
         raise Exception('Unknown version seen: %s' % version)
 
-
 def visual_studio_product_to_platform_toolset_version(version):
     if version == '2017':
         return 'v141'
     else:
         raise Exception('Unknown version seen: %s' % version)
 
-
 class VisualStudioBackend(CommonBackend):
     """Generate Visual Studio project files.
 
     This backend is used to produce Visual Studio projects and a solution
     to foster developing Firefox with Visual Studio.
 
     This backend is currently considered experimental. There are many things
     not optimal about how it works.
@@ -98,17 +95,17 @@ class VisualStudioBackend(CommonBackend)
             self._add_sources(reldir, obj)
 
         elif isinstance(obj, GeneratedSources):
             self._add_sources(reldir, obj)
 
         elif isinstance(obj, UnifiedSources):
             # XXX we should be letting CommonBackend.consume_object call this
             # for us instead.
-            self._process_unified_sources(obj)
+            self._process_unified_sources(obj);
 
         elif isinstance(obj, Library):
             self._libs_to_paths[obj.basename] = reldir
 
         elif isinstance(obj, Program) or isinstance(obj, HostProgram):
             self._progs_to_paths[obj.program] = reldir
 
         elif isinstance(obj, Defines):
@@ -131,37 +128,36 @@ class VisualStudioBackend(CommonBackend)
         s = self._paths_to_sources.setdefault(reldir, set())
         s.update(obj.files)
 
     def consume_finished(self):
         out_dir = self._out_dir
         out_proj_dir = os.path.join(self._out_dir, self._projsubdir)
 
         projects = self._write_projects_for_sources(self._libs_to_paths,
-                                                    "library", out_proj_dir)
+            "library", out_proj_dir)
         projects.update(self._write_projects_for_sources(self._progs_to_paths,
-                                                         "binary", out_proj_dir))
+            "binary", out_proj_dir))
 
         # Generate projects that can be used to build common targets.
         for target in ('export', 'binaries', 'tools', 'full'):
             basename = 'target_%s' % target
             command = '$(SolutionDir)\\mach.bat build'
             if target != 'full':
                 command += ' %s' % target
 
-            project_id = self._write_vs_project(
-                out_proj_dir, basename, target, build_command=command,
+            project_id = self._write_vs_project(out_proj_dir, basename, target,
+                build_command=command,
                 clean_command='$(SolutionDir)\\mach.bat build clean')
 
             projects[basename] = (project_id, basename, target)
 
         # A project that can be used to regenerate the visual studio projects.
         basename = 'target_vs'
-        project_id = self._write_vs_project(
-            out_proj_dir, basename, 'visual-studio',
+        project_id = self._write_vs_project(out_proj_dir, basename, 'visual-studio',
             build_command='$(SolutionDir)\\mach.bat build-backend -b VisualStudio')
         projects[basename] = (project_id, basename, 'visual-studio')
 
         # Write out a shared property file with common variables.
         props_path = os.path.join(out_proj_dir, 'mozilla.props')
         with self._write_file(props_path, mode='rb') as fh:
             self._write_props(fh)
 
@@ -189,28 +185,28 @@ class VisualStudioBackend(CommonBackend)
             sources = self._paths_to_sources.get(path, set())
             sources = set(os.path.join('$(TopSrcDir)', path, s) for s in sources)
             sources = set(os.path.normpath(s) for s in sources)
 
             finder = FileFinder(os.path.join(self.environment.topsrcdir, path))
 
             headers = [t[0] for t in finder.find('*.h')]
             headers = [os.path.normpath(os.path.join('$(TopSrcDir)',
-                                                     path, f)) for f in headers]
+                path, f)) for f in headers]
 
             includes = [
                 os.path.join('$(TopSrcDir)', path),
                 os.path.join('$(TopObjDir)', path),
             ]
             includes.extend(self._paths_to_includes.get(path, []))
             includes.append('$(TopObjDir)\\dist\\include\\nss')
             includes.append('$(TopObjDir)\\dist\\include')
 
             for v in ('NSPR_CFLAGS', 'NSS_CFLAGS', 'MOZ_JPEG_CFLAGS',
-                      'MOZ_PNG_CFLAGS', 'MOZ_ZLIB_CFLAGS', 'MOZ_PIXMAN_CFLAGS'):
+                    'MOZ_PNG_CFLAGS', 'MOZ_ZLIB_CFLAGS', 'MOZ_PIXMAN_CFLAGS'):
                 if not config:
                     break
 
                 args = config.substs.get(v, [])
 
                 for i, arg in enumerate(args):
                     if arg.startswith('-I'):
                         includes.append(os.path.normpath(arg[2:]))
@@ -222,30 +218,29 @@ class VisualStudioBackend(CommonBackend)
 
             defines = []
             for k, v in self._paths_to_defines.get(path, {}).items():
                 if v is True:
                     defines.append(k)
                 else:
                     defines.append('%s=%s' % (k, v))
 
-            debugger = None
+            debugger=None
             if prefix == 'binary':
                 if item.startswith(self.environment.substs['MOZ_APP_NAME']):
                     app_args = '-no-remote -profile $(TopObjDir)\\tmp\\profile-default'
                     if self.environment.substs.get('MOZ_LAUNCHER_PROCESS', False):
                         app_args += ' -wait-for-browser'
                     debugger = ('$(TopObjDir)\\dist\\bin\\%s' % item, app_args)
                 else:
                     debugger = ('$(TopObjDir)\\dist\\bin\\%s' % item, '')
 
             basename = '%s_%s' % (prefix, item)
 
-            project_id = self._write_vs_project(
-                out_dir, basename, item,
+            project_id = self._write_vs_project(out_dir, basename, item,
                 includes=includes,
                 forced_includes=['$(TopObjDir)\\dist\\include\\mozilla-config.h'],
                 defines=defines,
                 headers=headers,
                 sources=sources,
                 debugger=debugger)
 
             projects[basename] = (project_id, basename, item)
@@ -416,28 +411,28 @@ class VisualStudioBackend(CommonBackend)
         yield 'TOPSRCDIR', self.environment.topsrcdir
         yield 'TOPOBJDIR', self.environment.topobjdir
 
     def _write_mach_powershell(self, fh):
         for k, v in self._relevant_environment_variables():
             fh.write(b'$env:%s = "%s"\r\n' % (k, v))
 
         relpath = os.path.relpath(self.environment.topsrcdir,
-                                  self.environment.topobjdir).replace('\\', '/')
+            self.environment.topobjdir).replace('\\', '/')
 
         fh.write(b'$bashargs = "%s/mach", "--log-no-times"\r\n' % relpath)
         fh.write(b'$bashargs = $bashargs + $args\r\n')
 
         fh.write(b"$expanded = $bashargs -join ' '\r\n")
         fh.write(b'$procargs = "-c", $expanded\r\n')
 
         fh.write(b'Start-Process -WorkingDirectory $env:TOPOBJDIR '
-                 b'-FilePath $env:MOZILLABUILD\\msys\\bin\\bash '
-                 b'-ArgumentList $procargs '
-                 b'-Wait -NoNewWindow\r\n')
+            b'-FilePath $env:MOZILLABUILD\\msys\\bin\\bash '
+            b'-ArgumentList $procargs '
+            b'-Wait -NoNewWindow\r\n')
 
     def _write_mach_batch(self, fh):
         """Write out a batch script that builds the tree.
 
         The script "bootstraps" into the MozillaBuild environment by setting
         the environment variables that are active in the current MozillaBuild
         environment. Then, it builds the tree.
         """
@@ -445,44 +440,44 @@ class VisualStudioBackend(CommonBackend)
             fh.write(b'SET "%s=%s"\r\n' % (k, v))
 
         fh.write(b'cd %TOPOBJDIR%\r\n')
 
         # We need to convert Windows-native paths to msys paths. Easiest way is
         # relative paths, since munging c:\ to /c/ is slightly more
         # complicated.
         relpath = os.path.relpath(self.environment.topsrcdir,
-                                  self.environment.topobjdir).replace('\\', '/')
+            self.environment.topobjdir).replace('\\', '/')
 
         # We go through mach because it has the logic for choosing the most
         # appropriate build tool.
         fh.write(b'"%%MOZILLABUILD%%\\msys\\bin\\bash" '
-                 b'-c "%s/mach --log-no-times %%1 %%2 %%3 %%4 %%5 %%6 %%7"' % relpath)
+            b'-c "%s/mach --log-no-times %%1 %%2 %%3 %%4 %%5 %%6 %%7"' % relpath)
 
     def _write_vs_project(self, out_dir, basename, name, **kwargs):
         root = '%s.vcxproj' % basename
         project_id = get_id(basename.encode('utf-8'))
 
         with self._write_file(os.path.join(out_dir, root), mode='rb') as fh:
-            project_id, name = VisualStudioBackend.write_vs_project(
-                fh, self._version, project_id, name, **kwargs)
+            project_id, name = VisualStudioBackend.write_vs_project(fh,
+                self._version, project_id, name, **kwargs)
 
         with self._write_file(os.path.join(out_dir, '%s.user' % root), mode='rb') as fh:
             fh.write('<?xml version="1.0" encoding="utf-8"?>\r\n')
             fh.write('<Project ToolsVersion="4.0" xmlns="%s">\r\n' %
-                     MSBUILD_NAMESPACE)
+                MSBUILD_NAMESPACE)
             fh.write('</Project>\r\n')
 
         return project_id
 
     @staticmethod
     def write_vs_project(fh, version, project_id, name, includes=[],
-                         forced_includes=[], defines=[],
-                         build_command=None, clean_command=None,
-                         debugger=None, headers=[], sources=[]):
+        forced_includes=[], defines=[],
+        build_command=None, clean_command=None,
+        debugger=None, headers=[], sources=[]):
 
         impl = getDOMImplementation()
         doc = impl.createDocument(MSBUILD_NAMESPACE, 'Project', None)
 
         project = doc.documentElement
         project.setAttribute('DefaultTargets', 'Build')
         project.setAttribute('ToolsVersion', '4.0')
         project.setAttribute('xmlns', MSBUILD_NAMESPACE)
@@ -510,18 +505,17 @@ class VisualStudioBackend(CommonBackend)
 
         g = pg.appendChild(doc.createElement('ProjectGuid'))
         g.appendChild(doc.createTextNode('{%s}' % project_id))
 
         rn = pg.appendChild(doc.createElement('RootNamespace'))
         rn.appendChild(doc.createTextNode('mozilla'))
 
         pts = pg.appendChild(doc.createElement('PlatformToolset'))
-        pts.appendChild(doc.createTextNode(
-            visual_studio_product_to_platform_toolset_version(version)))
+        pts.appendChild(doc.createTextNode(visual_studio_product_to_platform_toolset_version(version)))
 
         i = project.appendChild(doc.createElement('Import'))
         i.setAttribute('Project', '$(VCTargetsPath)\\Microsoft.Cpp.Default.props')
 
         ig = project.appendChild(doc.createElement('ImportGroup'))
         ig.setAttribute('Label', 'ExtensionTargets')
 
         ig = project.appendChild(doc.createElement('ImportGroup'))
--- a/python/mozbuild/mozbuild/base.py
+++ b/python/mozbuild/mozbuild/base.py
@@ -32,67 +32,64 @@ from .configure import ConfigureSandbox
 from .controller.clobber import Clobberer
 from .mozconfig import (
     MozconfigFindException,
     MozconfigLoadException,
     MozconfigLoader,
 )
 from .pythonutil import find_python3_executable
 from .util import (
+    ReadOnlyNamespace,
     memoize,
     memoized_property,
 )
 from .virtualenv import VirtualenvManager
 
 
 def ancestors(path):
     """Emit the parent directories of a path."""
     while path:
         yield path
         newpath = os.path.dirname(path)
         if newpath == path:
             break
         path = newpath
 
-
 def samepath(path1, path2):
     if hasattr(os.path, 'samefile'):
         return os.path.samefile(path1, path2)
     return os.path.normcase(os.path.realpath(path1)) == \
         os.path.normcase(os.path.realpath(path2))
 
-
 class BadEnvironmentException(Exception):
     """Base class for errors raised when the build environment is not sane."""
 
 
 class BuildEnvironmentNotFoundException(BadEnvironmentException):
     """Raised when we could not find a build environment."""
 
 
 class ObjdirMismatchException(BadEnvironmentException):
     """Raised when the current dir is an objdir and doesn't match the mozconfig."""
-
     def __init__(self, objdir1, objdir2):
         self.objdir1 = objdir1
         self.objdir2 = objdir2
 
     def __str__(self):
         return "Objdir mismatch: %s != %s" % (self.objdir1, self.objdir2)
 
 
 class MozbuildObject(ProcessExecutionMixin):
     """Base class providing basic functionality useful to many modules.
 
     Modules in this package typically require common functionality such as
     accessing the current config, getting the location of the source directory,
     running processes, etc. This classes provides that functionality. Other
     modules can inherit from this class to obtain this functionality easily.
     """
-
     def __init__(self, topsrcdir, settings, log_manager, topobjdir=None,
                  mozconfig=MozconfigLoader.AUTODETECT):
         """Create a new Mozbuild object instance.
 
         Instances are bound to a source directory, a ConfigSettings instance,
         and a LogManager instance. The topobjdir may be passed in as well. If
         it isn't, it will be calculated from the active mozconfig.
         """
@@ -173,34 +170,33 @@ class MozbuildObject(ProcessExecutionMix
             raise BuildEnvironmentNotFoundException(
                 'Could not find Mozilla source tree or build environment.')
 
         topsrcdir = mozpath.normsep(topsrcdir)
         if topobjdir:
             topobjdir = mozpath.normsep(os.path.normpath(topobjdir))
 
             if topsrcdir == topobjdir:
-                raise BadEnvironmentException(
-                    'The object directory appears '
+                raise BadEnvironmentException('The object directory appears '
                     'to be the same as your source directory (%s). This build '
                     'configuration is not supported.' % topsrcdir)
 
         # If we can't resolve topobjdir, oh well. We'll figure out when we need
         # one.
         return cls(topsrcdir, None, None, topobjdir=topobjdir,
                    mozconfig=mozconfig)
 
     def resolve_mozconfig_topobjdir(self, default=None):
         topobjdir = self.mozconfig['topobjdir'] or default
         if not topobjdir:
             return None
 
         if '@CONFIG_GUESS@' in topobjdir:
             topobjdir = topobjdir.replace('@CONFIG_GUESS@',
-                                          self.resolve_config_guess())
+                self.resolve_config_guess())
 
         if not os.path.isabs(topobjdir):
             topobjdir = os.path.abspath(os.path.join(self.topsrcdir, topobjdir))
 
         return mozpath.normsep(os.path.normpath(topobjdir))
 
     def build_out_of_date(self, output, dep_file):
         if not os.path.isfile(output):
@@ -251,23 +247,20 @@ class MozbuildObject(ProcessExecutionMix
             self._topobjdir = self.resolve_mozconfig_topobjdir(
                 default='obj-@CONFIG_GUESS@')
 
         return self._topobjdir
 
     @property
     def virtualenv_manager(self):
         if self._virtualenv_manager is None:
-            self._virtualenv_manager = VirtualenvManager(
-                self.topsrcdir,
-                self.topobjdir,
-                os.path.join(self.topobjdir, '_virtualenvs', 'init'),
-                sys.stdout,
-                os.path.join(self.topsrcdir, 'build', 'virtualenv_packages.txt')
-                )
+            self._virtualenv_manager = VirtualenvManager(self.topsrcdir,
+                self.topobjdir, os.path.join(self.topobjdir, '_virtualenvs', 'init'),
+                sys.stdout, os.path.join(self.topsrcdir, 'build',
+                'virtualenv_packages.txt'))
 
         return self._virtualenv_manager
 
     @staticmethod
     @memoize
     def get_mozconfig_and_target(topsrcdir, path, env_mozconfig):
         # env_mozconfig is only useful for unittests, which change the value of
         # the environment variable, which has an impact on autodetection (when
@@ -492,16 +485,17 @@ class MozbuildObject(ProcessExecutionMix
                         raise Exception('working directory is not clean; '
                                         'refusing to use a VCS-based finder')
 
             finder = MercurialRevisionFinder(self.topsrcdir, rev=vcs_revision,
                                              recognize_repo_paths=True)
 
         return BuildReader(config, finder=finder)
 
+
     @memoized_property
     def python3(self):
         """Obtain info about a Python 3 executable.
 
         Returns a tuple of an executable path and its version (as a tuple).
         Either both entries will have a value or both will be None.
         """
         # Search configured build info first. Then fall back to system.
@@ -543,20 +537,20 @@ class MozbuildObject(ProcessExecutionMix
         substs = self.substs
 
         stem = self.distdir
         if where == 'staged-package':
             stem = os.path.join(stem, substs['MOZ_APP_NAME'])
 
         if substs['OS_ARCH'] == 'Darwin':
             if substs['MOZ_BUILD_APP'] == 'xulrunner':
-                stem = os.path.join(stem, 'XUL.framework')
+                stem = os.path.join(stem, 'XUL.framework');
             else:
                 stem = os.path.join(stem, substs['MOZ_MACBUNDLE_NAME'], 'Contents',
-                                    'MacOS')
+                    'MacOS')
         elif where == 'default':
             stem = os.path.join(stem, 'bin')
 
         leaf = None
 
         leaf = (substs['MOZ_APP_NAME'] if what == 'app' else what) + substs['BIN_SUFFIX']
         path = os.path.join(stem, leaf)
 
@@ -579,24 +573,23 @@ class MozbuildObject(ProcessExecutionMix
             return
 
         try:
             if sys.platform.startswith('darwin'):
                 try:
                     notifier = which.which('terminal-notifier')
                 except which.WhichError:
                     raise Exception('Install terminal-notifier to get '
-                                    'a notification when the build finishes.')
+                        'a notification when the build finishes.')
                 self.run_process([notifier, '-title',
-                                  'Mozilla Build System', '-group', 'mozbuild',
-                                  '-message', msg], ensure_exit_code=False)
+                    'Mozilla Build System', '-group', 'mozbuild',
+                    '-message', msg], ensure_exit_code=False)
             elif sys.platform.startswith('win'):
                 from ctypes import Structure, windll, POINTER, sizeof
                 from ctypes.wintypes import DWORD, HANDLE, WINFUNCTYPE, BOOL, UINT
-
                 class FLASHWINDOW(Structure):
                     _fields_ = [("cbSize", UINT),
                                 ("hwnd", HANDLE),
                                 ("dwFlags", DWORD),
                                 ("uCount", UINT),
                                 ("dwTimeout", DWORD)]
                 FlashWindowExProto = WINFUNCTYPE(BOOL, POINTER(FLASHWINDOW))
                 FlashWindowEx = FlashWindowExProto(("FlashWindowEx", windll.user32))
@@ -606,31 +599,31 @@ class MozbuildObject(ProcessExecutionMix
 
                 # GetConsoleWindows returns NULL if no console is attached. We
                 # can't flash nothing.
                 console = windll.kernel32.GetConsoleWindow()
                 if not console:
                     return
 
                 params = FLASHWINDOW(sizeof(FLASHWINDOW),
-                                     console,
-                                     FLASHW_CAPTION | FLASHW_TRAY | FLASHW_TIMERNOFG, 3, 0)
+                                    console,
+                                    FLASHW_CAPTION | FLASHW_TRAY | FLASHW_TIMERNOFG, 3, 0)
                 FlashWindowEx(params)
             else:
                 try:
                     notifier = which.which('notify-send')
                 except which.WhichError:
                     raise Exception('Install notify-send (usually part of '
-                                    'the libnotify package) to get a notification when '
-                                    'the build finishes.')
+                        'the libnotify package) to get a notification when '
+                        'the build finishes.')
                 self.run_process([notifier, '--app-name=Mozilla Build System',
-                                  'Mozilla Build System', msg], ensure_exit_code=False)
+                    'Mozilla Build System', msg], ensure_exit_code=False)
         except Exception as e:
-            self.log(logging.WARNING, 'notifier-failed',
-                     {'error': e.message}, 'Notification center failed: {error}')
+            self.log(logging.WARNING, 'notifier-failed', {'error':
+                e.message}, 'Notification center failed: {error}')
 
     def _ensure_objdir_exists(self):
         if os.path.isdir(self.statedir):
             return
 
         os.makedirs(self.statedir)
 
     def _ensure_state_subdir_exists(self, subdir):
@@ -648,20 +641,20 @@ class MozbuildObject(ProcessExecutionMix
             path = os.path.join(path, subdir)
 
         return os.path.join(path, filename)
 
     def _wrap_path_argument(self, arg):
         return PathArgument(arg, self.topsrcdir, self.topobjdir)
 
     def _run_make(self, directory=None, filename=None, target=None, log=True,
-                  srcdir=False, allow_parallel=True, line_handler=None,
-                  append_env=None, explicit_env=None, ignore_errors=False,
-                  ensure_exit_code=0, silent=True, print_directory=True,
-                  pass_thru=False, num_jobs=0, keep_going=False):
+            srcdir=False, allow_parallel=True, line_handler=None,
+            append_env=None, explicit_env=None, ignore_errors=False,
+            ensure_exit_code=0, silent=True, print_directory=True,
+            pass_thru=False, num_jobs=0, keep_going=False):
         """Invoke make.
 
         directory -- Relative directory to look for Makefile in.
         filename -- Explicit makefile to run.
         target -- Makefile target(s) to make. Can be a string or iterable of
             strings.
         srcdir -- If True, invoke make from the source directory tree.
             Otherwise, make will be invoked from the object directory.
@@ -793,21 +786,21 @@ class MozbuildObject(ProcessExecutionMix
             result, xcode_lisense_error_tmp = validate_make(make)
             if result:
                 return [make]
             if xcode_lisense_error_tmp:
                 xcode_lisense_error = True
 
         if xcode_lisense_error:
             raise Exception('Xcode requires accepting to the license agreement.\n'
-                            'Please run Xcode and accept the license agreement.')
+                'Please run Xcode and accept the license agreement.')
 
         if self._is_windows():
             raise Exception('Could not find a suitable make implementation.\n'
-                            'Please use MozillaBuild 1.9 or newer')
+                'Please use MozillaBuild 1.9 or newer')
         else:
             raise Exception('Could not find a suitable make implementation.')
 
     def _run_command_in_srcdir(self, **args):
         return self.run_process(cwd=self.topsrcdir, **args)
 
     def _run_command_in_objdir(self, **args):
         return self.run_process(cwd=self.topobjdir, **args)
@@ -822,32 +815,32 @@ class MozbuildObject(ProcessExecutionMix
         """Create a new MozbuildObject-derived class instance from ourselves.
 
         This is used as a convenience method to create other
         MozbuildObject-derived class instances. It can only be used on
         classes that have the same constructor arguments as us.
         """
 
         return cls(self.topsrcdir, self.settings, self.log_manager,
-                   topobjdir=self.topobjdir)
+            topobjdir=self.topobjdir)
 
     def _activate_virtualenv(self):
         self.virtualenv_manager.ensure()
         self.virtualenv_manager.activate()
 
+
     def _set_log_level(self, verbose):
         self.log_manager.terminal_handler.setLevel(logging.INFO if not verbose else logging.DEBUG)
 
     def ensure_pipenv(self):
         self._activate_virtualenv()
         pipenv = os.path.join(self.virtualenv_manager.bin_path, 'pipenv')
         if not os.path.exists(pipenv):
             for package in ['certifi', 'pipenv', 'six', 'virtualenv', 'virtualenv-clone']:
-                path = os.path.normpath(os.path.join(
-                    self.topsrcdir, 'third_party/python', package))
+                path = os.path.normpath(os.path.join(self.topsrcdir, 'third_party/python', package))
                 self.virtualenv_manager.install_pip_package(path, vendored=True)
         return pipenv
 
     def activate_pipenv(self, pipfile=None, populate=False, python=None):
         if pipfile is not None and not os.path.exists(pipfile):
             raise Exception('Pipfile not found: %s.' % pipfile)
         self.ensure_pipenv()
         self.virtualenv_manager.activate_pipenv(pipfile, populate, python)
@@ -863,20 +856,19 @@ class MachCommandBase(MozbuildObject):
     def __init__(self, context):
         # Attempt to discover topobjdir through environment detection, as it is
         # more reliable than mozconfig when cwd is inside an objdir.
         topsrcdir = context.topdir
         topobjdir = None
         detect_virtualenv_mozinfo = True
         if hasattr(context, 'detect_virtualenv_mozinfo'):
             detect_virtualenv_mozinfo = getattr(context,
-                                                'detect_virtualenv_mozinfo')
+                'detect_virtualenv_mozinfo')
         try:
-            dummy = MozbuildObject.from_environment(
-                cwd=context.cwd,
+            dummy = MozbuildObject.from_environment(cwd=context.cwd,
                 detect_virtualenv_mozinfo=detect_virtualenv_mozinfo)
             topsrcdir = dummy.topsrcdir
             topobjdir = dummy._topobjdir
             if topobjdir:
                 # If we're inside a objdir and the found mozconfig resolves to
                 # another objdir, we abort. The reasoning here is that if you
                 # are inside an objdir you probably want to perform actions on
                 # that objdir, not another one. This prevents accidental usage
@@ -884,39 +876,39 @@ class MachCommandBase(MozbuildObject):
                 config_topobjdir = dummy.resolve_mozconfig_topobjdir()
 
                 if config_topobjdir and not samepath(topobjdir, config_topobjdir):
                     raise ObjdirMismatchException(topobjdir, config_topobjdir)
         except BuildEnvironmentNotFoundException:
             pass
         except ObjdirMismatchException as e:
             print('Ambiguous object directory detected. We detected that '
-                  'both %s and %s could be object directories. This is '
-                  'typically caused by having a mozconfig pointing to a '
-                  'different object directory from the current working '
-                  'directory. To solve this problem, ensure you do not have a '
-                  'default mozconfig in searched paths.' % (e.objdir1,
-                                                            e.objdir2))
+                'both %s and %s could be object directories. This is '
+                'typically caused by having a mozconfig pointing to a '
+                'different object directory from the current working '
+                'directory. To solve this problem, ensure you do not have a '
+                'default mozconfig in searched paths.' % (e.objdir1,
+                    e.objdir2))
             sys.exit(1)
 
         except MozconfigLoadException as e:
             print('Error loading mozconfig: ' + e.path)
             print('')
             print(e.message)
             if e.output:
                 print('')
                 print('mozconfig output:')
                 print('')
                 for line in e.output:
                     print(line)
 
             sys.exit(1)
 
         MozbuildObject.__init__(self, topsrcdir, context.settings,
-                                context.log_manager, topobjdir=topobjdir)
+            context.log_manager, topobjdir=topobjdir)
 
         self._mach_context = context
 
         # Incur mozconfig processing so we have unified error handling for
         # errors. Otherwise, the exceptions could bubble back to mach's error
         # handler.
         try:
             self.mozconfig
--- a/python/mozbuild/mozbuild/chunkify.py
+++ b/python/mozbuild/mozbuild/chunkify.py
@@ -2,18 +2,16 @@
 # 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/.
 
 # This file is a direct clone of
 # https://github.com/bhearsum/chunkify/blob/master/chunkify/__init__.py
 # of version 1.2. Its license (MPL2) is contained in repo root LICENSE file.
 # Please make modifications there where possible.
 
-from __future__ import absolute_import, print_function
-
 from itertools import islice
 
 
 class ChunkingError(Exception):
     pass
 
 
 def split_evenly(n, chunks):
@@ -51,8 +49,9 @@ def chunkify(things, this_chunk, chunks)
     dist = split_evenly(len(things), chunks)
     start = sum(dist[:this_chunk-1])
     end = start + dist[this_chunk-1]
 
     try:
         return things[start:end]
     except TypeError:
         return islice(things, start, end)
+
--- a/python/mozbuild/mozbuild/codecoverage/chrome_map.py
+++ b/python/mozbuild/mozbuild/codecoverage/chrome_map.py
@@ -1,38 +1,36 @@
 # 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 absolute_import, print_function
-
+from collections import defaultdict
 import json
 import os
 import re
+import urlparse
 
 from mach.config import ConfigSettings
 from mach.logging import LoggingManager
 from mozbuild.backend.common import CommonBackend
 from mozbuild.base import MozbuildObject
 from mozbuild.frontend.data import (
     FinalTargetFiles,
     FinalTargetPreprocessedFiles,
 )
 from mozbuild.frontend.data import JARManifest, ChromeManifestEntry
 from mozpack.copier import FileRegistry
 from mozpack.files import PreprocessedFile
 from mozpack.manifests import InstallManifest
 import mozpack.path as mozpath
 
-from .manifest_handler import ChromeManifestHandler
+from manifest_handler import ChromeManifestHandler
 
 
 _line_comment_re = re.compile('^//@line (\d+) "(.+)"$')
-
-
 def generate_pp_info(path, topsrcdir):
     with open(path) as fh:
         # (start, end) -> (included_source, start)
         section_info = dict()
 
         this_section = None
 
         def finish_section(pp_end):
@@ -54,18 +52,16 @@ def generate_pp_info(path, topsrcdir):
 
         if this_section:
             finish_section(count + 2)
 
         return section_info
 
 # This build backend is assuming the build to have happened already, as it is parsing
 # built preprocessed files to generate data to map them to the original sources.
-
-
 class ChromeMapBackend(CommonBackend):
     def _init(self):
         CommonBackend._init(self)
 
         log_manager = LoggingManager()
         self._cmd = MozbuildObject(self.environment.topsrcdir, ConfigSettings(),
                                    log_manager, self.environment.topobjdir)
         self._install_mapping = {}
@@ -115,21 +111,19 @@ class ChromeMapBackend(CommonBackend):
             else:
                 pp_info = None
             self._install_mapping[dest] = src.path, pp_info
 
         # Our result has four parts:
         #  A map from url prefixes to objdir directories:
         #  { "chrome://mozapps/content/": [ "dist/bin/chrome/toolkit/content/mozapps" ], ... }
         #  A map of overrides.
-        #  A map from objdir paths to sourcedir paths, and an object storing mapping
-        #    information for preprocessed files:
+        #  A map from objdir paths to sourcedir paths, and an object storing mapping information for preprocessed files:
         #  { "dist/bin/browser/chrome/browser/content/browser/aboutSessionRestore.js":
-        #    [ "$topsrcdir/browser/components/sessionstore/content/aboutSessionRestore.js", {} ],
-        #    ... }
+        #    [ "$topsrcdir/browser/components/sessionstore/content/aboutSessionRestore.js", {} ], ... }
         #  An object containing build configuration information.
         outputfile = os.path.join(self.environment.topobjdir, 'chrome-map.json')
         with self._write_file(outputfile) as fh:
             chrome_mapping = self.manifest_handler.chrome_mapping
             overrides = self.manifest_handler.overrides
             json.dump([
                 {k: list(v) for k, v in chrome_mapping.iteritems()},
                 overrides,
--- a/python/mozbuild/mozbuild/codecoverage/lcov_rewriter.py
+++ b/python/mozbuild/mozbuild/codecoverage/lcov_rewriter.py
@@ -1,44 +1,40 @@
 # 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 absolute_import, print_function
-
 from argparse import ArgumentParser
 import json
 import os
 
 try:
     import urlparse
 except ImportError:
     import urllib.parse as urlparse
 
 from six import viewitems
 
 from mozpack.chrome.manifest import parse_manifest
 import mozpack.path as mozpath
-from .manifest_handler import ChromeManifestHandler
-
+from manifest_handler import ChromeManifestHandler
 
 class LcovRecord(object):
     __slots__ = ("test_name",
                  "source_file",
                  "functions",
                  "function_exec_counts",
                  "function_count",
                  "covered_function_count",
                  "branches",
                  "branch_count",
                  "covered_branch_count",
                  "lines",
                  "line_count",
                  "covered_line_count")
-
     def __init__(self):
         self.functions = {}
         self.function_exec_counts = {}
         self.branches = {}
         self.lines = {}
 
     def __iadd__(self, other):
 
@@ -63,26 +59,24 @@ class LcovRecord(object):
 
         self.resummarize()
         return self
 
     def resummarize(self):
         # Re-calculate summaries after generating or splitting a record.
         self.function_count = len(self.functions.keys())
         # Function records may have moved between files, so filter here.
-        self.function_exec_counts = {
-            fn_name: count for fn_name, count in viewitems(self.function_exec_counts)
-            if fn_name in self.functions.values()}
+        self.function_exec_counts = {fn_name: count for fn_name, count in viewitems(self.function_exec_counts)
+                                     if fn_name in self.functions.values()}
         self.covered_function_count = len([c for c in self.function_exec_counts.values() if c])
         self.line_count = len(self.lines)
         self.covered_line_count = len([c for c, _ in self.lines.values() if c])
         self.branch_count = len(self.branches)
         self.covered_branch_count = len([c for c in self.branches.values() if c])
 
-
 class RecordRewriter(object):
     # Helper class for rewriting/spliting individual lcov records according
     # to what the preprocessor did.
     def __init__(self):
         self._ranges = None
 
     def _get_range(self, line):
         for start, end in self._ranges:
@@ -165,32 +159,30 @@ class RecordRewriter(object):
                 continue
             rewritten_branches[(new_ln, block_number, branch_number)] = taken
 
         record.branches = rewritten_branches
 
     def rewrite_record(self, record, pp_info):
         # Rewrite the lines in the given record according to preprocessor info
         # and split to additional records when pp_info has included file info.
-        self._current_pp_info = dict(
-            [(tuple([int(l) for l in k.split(',')]), v) for k, v in pp_info.items()])
+        self._current_pp_info = dict([(tuple([int(l) for l in k.split(',')]), v) for k, v in pp_info.items()])
         self._ranges = sorted(self._current_pp_info.keys())
         self._additions = {}
         self._rewrite_lines(record)
         self._rewrite_functions(record)
         self._rewrite_branches(record)
 
         record.resummarize()
 
         generated_records = self._additions.values()
         for r in generated_records:
             r.resummarize()
         return generated_records
 
-
 class LcovFile(object):
     # Simple parser/pretty-printer for lcov format.
     # lcov parsing based on http://ltp.sourceforge.net/coverage/lcov/geninfo.1.php
 
     # TN:<test name>
     # SF:<absolute path to the source file>
     # FN:<line number of function start>,<function name>
     # FNDA:<execution count>,<function name>
@@ -407,17 +399,16 @@ class LcovFile(object):
 
     def parse_LF(self, line_count):
         self.current_record.line_count = line_count
 
 
 class UrlFinderError(Exception):
     pass
 
-
 class UrlFinder(object):
     # Given a "chrome://" or "resource://" url, uses data from the UrlMapBackend
     # and install manifests to find a path to the source file and the corresponding
     # (potentially pre-processed) file in the objdir.
     def __init__(self, chrome_map_path, appdir, gredir, extra_chrome_manifests):
         # Cached entries
         self._final_mapping = {}
 
@@ -573,64 +564,58 @@ class UrlFinder(object):
 
         url_obj = urlparse.urlparse(url)
         if url_obj.scheme == 'jar':
             app_name = self.MOZ_APP_NAME
             omnijar_name = self.OMNIJAR_NAME
 
             if app_name in url:
                 if omnijar_name in url:
-                    # e.g. file:///home/worker/workspace/build/application/firefox/omni.ja!/components/MainProcessSingleton.js  # noqa
+                    # e.g. file:///home/worker/workspace/build/application/firefox/omni.ja!/components/MainProcessSingleton.js
                     parts = url_obj.path.split(omnijar_name + '!', 1)
                 elif '.xpi!' in url:
-                    # e.g. file:///home/worker/workspace/build/application/firefox/browser/features/e10srollout@mozilla.org.xpi!/bootstrap.js  # noqa
+                    # e.g. file:///home/worker/workspace/build/application/firefox/browser/features/e10srollout@mozilla.org.xpi!/bootstrap.js
                     parts = url_obj.path.split('.xpi!', 1)
                 else:
                     # We don't know how to handle this jar: path, so return it to the
                     # caller to make it print a warning.
                     return url_obj.path, None
 
                 dir_parts = parts[0].rsplit(app_name + '/', 1)
-                url = mozpath.normpath(
-                    mozpath.join(self.topobjdir, 'dist',
-                                 'bin', dir_parts[1].lstrip('/'), parts[1].lstrip('/'))
-                    )
+                url = mozpath.normpath(mozpath.join(self.topobjdir, 'dist', 'bin', dir_parts[1].lstrip('/'), parts[1].lstrip('/')))
             elif '.xpi!' in url:
                 # This matching mechanism is quite brittle and based on examples seen in the wild.
                 # There's no rule to match the XPI name to the path in dist/xpi-stage.
                 parts = url_obj.path.split('.xpi!', 1)
                 addon_name = os.path.basename(parts[0])
                 if '-test@mozilla.org' in addon_name:
                     addon_name = addon_name[:-len('-test@mozilla.org')]
                 elif addon_name.endswith('@mozilla.org'):
                     addon_name = addon_name[:-len('@mozilla.org')]
-                url = mozpath.normpath(mozpath.join(self.topobjdir, 'dist',
-                                                    'xpi-stage', addon_name, parts[1].lstrip('/')))
+                url = mozpath.normpath(mozpath.join(self.topobjdir, 'dist', 'xpi-stage', addon_name, parts[1].lstrip('/')))
         elif url_obj.scheme == 'file' and os.path.isabs(url_obj.path):
             path = url_obj.path
             if not os.path.isfile(path):
                 # This may have been in a profile directory that no
                 # longer exists.
                 return None
             if not path.startswith(self.topobjdir):
                 return path, None
             url = url_obj.path
         elif url_obj.scheme in ('http', 'https', 'javascript', 'data', 'about'):
             return None
 
         result = self.find_files(url)
         self._final_mapping[url] = result
         return result
 
-
 class LcovFileRewriter(object):
     # Class for partial parses of LCOV format and rewriting to resolve urls
     # and preprocessed file lines.
-    def __init__(self, chrome_map_path, appdir='dist/bin/browser/',
-                 gredir='dist/bin/', extra_chrome_manifests=[]):
+    def __init__(self, chrome_map_path, appdir='dist/bin/browser/', gredir='dist/bin/', extra_chrome_manifests=[]):
         self.url_finder = UrlFinder(chrome_map_path, appdir, gredir, extra_chrome_manifests)
         self.pp_rewriter = RecordRewriter()
 
     def rewrite_files(self, in_paths, output_file, output_suffix):
         unknowns = set()
         found_valid = [False]
 
         def rewrite_source(url):
@@ -641,21 +626,19 @@ class LcovFileRewriter(object):
             except Exception as e:
                 if url not in unknowns:
                     print("Error: %s.\nCouldn't find source info for %s, removing record" %
                           (e, url))
                 unknowns.add(url)
                 return None
 
             source_file, pp_info = res
-            # We can't assert that the file exists here, because we don't have the source
-            # checkout available on test machines. We can bring back this assertion when
-            # bug 1432287 is fixed.
-            # assert os.path.isfile(source_file), "Couldn't find mapped source file %s at %s!" % (
-            #     url, source_file)
+            # We can't assert that the file exists here, because we don't have the source checkout available
+            # on test machines. We can bring back this assertion when bug 1432287 is fixed.
+            # assert os.path.isfile(source_file), "Couldn't find mapped source file %s at %s!" % (url, source_file)
 
             found_valid[0] = True
 
             return res
 
         in_paths = [os.path.abspath(in_path) for in_path in in_paths]
 
         if output_file:
@@ -669,64 +652,47 @@ class LcovFileRewriter(object):
                     lcov_file.print_file(out_fh, rewrite_source, self.pp_rewriter.rewrite_record)
 
         if not found_valid[0]:
             print("WARNING: No valid records found in %s" % in_paths)
             return
 
 
 def main():
-    parser = ArgumentParser(
-        description="Given a set of gcov .info files produced "
-        "by spidermonkey's code coverage, re-maps file urls "
-        "back to source files and lines in preprocessed files "
-        "back to their original locations."
-    )
-    parser.add_argument(
-        "--chrome-map-path", default="chrome-map.json", help="Path to the chrome-map.json file."
-    )
-    parser.add_argument(
-        "--app-dir",
-        default="dist/bin/browser/",
-        help="Prefix of the appdir in use. This is used to map "
-        "urls starting with resource:///. It may differ by "
-        "app, but defaults to the valid value for firefox.",
-    )
-    parser.add_argument(
-        "--gre-dir",
-        default="dist/bin/",
-        help="Prefix of the gre dir in use. This is used to map "
-        "urls starting with resource://gre. It may differ by "
-        "app, but defaults to the valid value for firefox.",
-    )
-    parser.add_argument(
-        "--output-suffix", default=".out", help="The suffix to append to output files."
-    )
-    parser.add_argument(
-        "--extra-chrome-manifests",
-        nargs='+',
-        help="Paths to files containing extra chrome registration.",
-    )
-    parser.add_argument(
-        "--output-file",
-        default="",
-        help="The output file where the results are merged. Leave empty to make the rewriter not "
-        "merge files.",
-    )
-    parser.add_argument("files", nargs='+', help="The set of files to process.")
+    parser = ArgumentParser(description="Given a set of gcov .info files produced "
+                            "by spidermonkey's code coverage, re-maps file urls "
+                            "back to source files and lines in preprocessed files "
+                            "back to their original locations.")
+    parser.add_argument("--chrome-map-path", default="chrome-map.json",
+                        help="Path to the chrome-map.json file.")
+    parser.add_argument("--app-dir", default="dist/bin/browser/",
+                        help="Prefix of the appdir in use. This is used to map "
+                             "urls starting with resource:///. It may differ by "
+                             "app, but defaults to the valid value for firefox.")
+    parser.add_argument("--gre-dir", default="dist/bin/",
+                        help="Prefix of the gre dir in use. This is used to map "
+                             "urls starting with resource://gre. It may differ by "
+                             "app, but defaults to the valid value for firefox.")
+    parser.add_argument("--output-suffix", default=".out",
+                        help="The suffix to append to output files.")
+    parser.add_argument("--extra-chrome-manifests", nargs='+',
+                        help="Paths to files containing extra chrome registration.")
+    parser.add_argument("--output-file", default="",
+                        help="The output file where the results are merged. Leave empty to make the rewriter not merge files.")
+    parser.add_argument("files", nargs='+',
+                        help="The set of files to process.")
 
     args = parser.parse_args()
 
     rewriter = LcovFileRewriter(args.chrome_map_path, args.app_dir, args.gre_dir,
                                 args.extra_chrome_manifests)
 
     files = []
     for f in args.files:
         if os.path.isdir(f):
             files += [os.path.join(f, e) for e in os.listdir(f)]
         else:
             files.append(f)
 
     rewriter.rewrite_files(files, args.output_file, args.output_suffix)
 
-
 if __name__ == '__main__':
     main()
--- a/python/mozbuild/mozbuild/codecoverage/manifest_handler.py
+++ b/python/mozbuild/mozbuild/codecoverage/manifest_handler.py
@@ -1,14 +1,12 @@
 # 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 absolute_import, print_function
-
 from collections import defaultdict
 
 try:
     import urlparse
 except ImportError:
     import urllib.parse as urlparse
 
 from mozpack.chrome.manifest import (
--- a/python/mozbuild/mozbuild/codecoverage/packager.py
+++ b/python/mozbuild/mozbuild/codecoverage/packager.py
@@ -1,29 +1,27 @@
 # 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 absolute_import, print_function
 
 import argparse
-import errno
 import sys
 import json
 import buildconfig
 
 from mozpack.copier import Jarrer, FileRegistry
 from mozpack.files import FileFinder, GeneratedFile
 from mozpack.manifests import (
     InstallManifest,
     UnreadableInstallManifest,
 )
 import mozpack.path as mozpath
 
-
 def describe_install_manifest(manifest, dest_dir):
     try:
         manifest = InstallManifest(manifest)
     except UnreadableInstallManifest:
         raise IOError(errno.EINVAL, 'Error parsing manifest file', manifest)
 
     reg = FileRegistry()
 
@@ -72,11 +70,10 @@ def cli(args=sys.argv[1:]):
     args = parser.parse_args(args)
 
     if not args.root:
         from buildconfig import topobjdir
         args.root = topobjdir
 
     return package_coverage_data(args.root, args.output_file)
 
-
 if __name__ == '__main__':
     sys.exit(cli())
--- a/python/mozbuild/mozbuild/compilation/codecomplete.py
+++ b/python/mozbuild/mozbuild/compilation/codecomplete.py
@@ -1,15 +1,17 @@
 # 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/.
 
 # This modules provides functionality for dealing with code completion.
 
-from __future__ import absolute_import, print_function
+from __future__ import absolute_import
+
+import os
 
 from mach.decorators import (
     CommandArgument,
     CommandProvider,
     Command,
 )
 
 from mozbuild.base import MachCommandBase
@@ -19,30 +21,30 @@ from mozbuild.shellutil import (
 )
 
 
 @CommandProvider
 class Introspection(MachCommandBase):
     """Instropection commands."""
 
     @Command('compileflags', category='devenv',
-             description='Display the compilation flags for a given source file')
+        description='Display the compilation flags for a given source file')
     @CommandArgument('what', default=None,
-                     help='Source file to display compilation flags for')
+        help='Source file to display compilation flags for')
     def compileflags(self, what):
         from mozbuild.util import resolve_target_to_make
         from mozbuild.compilation import util
 
         if not util.check_top_objdir(self.topobjdir):
             return 1
 
         path_arg = self._wrap_path_argument(what)
 
         make_dir, make_target = resolve_target_to_make(self.topobjdir,
-                                                       path_arg.relpath())
+            path_arg.relpath())
 
         if make_dir is None and make_target is None:
             return 1
 
         build_vars = util.get_build_vars(make_dir, self)
 
         if what.endswith('.c'):
             cc = 'CC'
--- a/python/mozbuild/mozbuild/compilation/database.py
+++ b/python/mozbuild/mozbuild/compilation/database.py
@@ -1,27 +1,28 @@
 # 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/.
 
 # This modules provides functionality for dealing with code completion.
 
-from __future__ import absolute_import, print_function
-
 import os
 import types
 
 from mozbuild.backend.common import CommonBackend
 from mozbuild.frontend.data import (
     ComputedFlags,
     Sources,
     GeneratedSources,
     DirectoryTraversal,
+    Linkable,
+    LocalInclude,
     PerSourceFlag,
     VariablePassthru,
+    SimpleProgram,
 )
 from mozbuild.shellutil import (
     quote as shell_quote,
 )
 from mozbuild.util import expand_variables
 import mozpack.path as mozpath
 from collections import (
     defaultdict,
@@ -170,18 +171,18 @@ class CompileDBBackend(CommonBackend):
         '.mm': 'CXXFLAGS',
     }
 
     def _build_db_line(self, objdir, reldir, cenv, filename,
                        canonical_suffix, unified=None):
         if canonical_suffix not in self.COMPILERS:
             return
         db = self._db.setdefault((objdir, filename, unified),
-                                 cenv.substs[self.COMPILERS[canonical_suffix]].split() +
-                                 ['-o', '/dev/null', '-c'])
+            cenv.substs[self.COMPILERS[canonical_suffix]].split() +
+            ['-o', '/dev/null', '-c'])
         reldir = reldir or mozpath.relpath(objdir, cenv.topobjdir)
 
         def append_var(name):
             value = cenv.substs.get(name)
             if not value:
                 return
             if isinstance(value, types.StringTypes):
                 value = value.split()
--- a/python/mozbuild/mozbuild/compilation/util.py
+++ b/python/mozbuild/mozbuild/compilation/util.py
@@ -1,48 +1,44 @@
 # 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 absolute_import, print_function
-
 import os
-
+from mozbuild import shellutil
 
 def check_top_objdir(topobjdir):
     top_make = os.path.join(topobjdir, 'Makefile')
     if not os.path.exists(top_make):
         print('Your tree has not been built yet. Please run '
-              '|mach build| with no arguments.')
+            '|mach build| with no arguments.')
         return False
     return True
 
-
 def get_build_vars(directory, cmd):
     build_vars = {}
 
     def on_line(line):
         elements = [s.strip() for s in line.split('=', 1)]
 
         if len(elements) != 2:
             return
 
         build_vars[elements[0]] = elements[1]
 
     try:
         old_logger = cmd.log_manager.replace_terminal_handler(None)
         cmd._run_make(directory=directory, target='showbuild', log=False,
-                      print_directory=False, allow_parallel=False, silent=True,
-                      line_handler=on_line)
+                print_directory=False, allow_parallel=False, silent=True,
+                line_handler=on_line)
     finally:
         cmd.log_manager.replace_terminal_handler(old_logger)
 
     return build_vars
 
-
 def sanitize_cflags(flags):
     # We filter out -Xclang arguments as clang based tools typically choke on
     # passing these flags down to the clang driver.  -Xclang tells the clang
     # driver driver to pass whatever comes after it down to clang cc1, which is
     # why we skip -Xclang and the argument immediately after it.  Here is an
     # example: the following two invocations pass |-foo -bar -baz| to cc1:
     # clang -cc1 -foo -bar -baz
     # clang -Xclang -foo -Xclang -bar -Xclang -baz
--- a/python/mozbuild/mozbuild/compilation/warnings.py
+++ b/python/mozbuild/mozbuild/compilation/warnings.py
@@ -1,15 +1,15 @@
 # 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/.
 
 # This modules provides functionality for dealing with compiler warnings.
 
-from __future__ import absolute_import, print_function, unicode_literals
+from __future__ import absolute_import, unicode_literals
 
 import errno
 import json
 import os
 import re
 
 from mozbuild.util import hash_file
 import mozpack.path as mozpath
@@ -82,32 +82,32 @@ class CompilerWarning(dict):
 
     def _compare(self, other, func):
         if not isinstance(other, CompilerWarning):
             return NotImplemented
 
         return func(self._cmpkey(), other._cmpkey())
 
     def __eq__(self, other):
-        return self._compare(other, lambda s, o: s == o)
+        return self._compare(other, lambda s,o: s == o)
 
     def __neq__(self, other):
-        return self._compare(other, lambda s, o: s != o)
+        return self._compare(other, lambda s,o: s != o)
 
     def __lt__(self, other):
-        return self._compare(other, lambda s, o: s < o)
+        return self._compare(other, lambda s,o: s < o)
 
     def __le__(self, other):
-        return self._compare(other, lambda s, o: s <= o)
+        return self._compare(other, lambda s,o: s <= o)
 
     def __gt__(self, other):
-        return self._compare(other, lambda s, o: s > o)
+        return self._compare(other, lambda s,o: s > o)
 
     def __ge__(self, other):
-        return self._compare(other, lambda s, o: s >= o)
+        return self._compare(other, lambda s,o: s >= o)
 
     def __hash__(self):
         """Define so this can exist inside a set, etc."""
         return hash(tuple(sorted(self.items())))
 
 
 class WarningsDatabase(object):
     """Holds a collection of warnings.
@@ -127,17 +127,16 @@ class WarningsDatabase(object):
     The WarningsDatabase handles this by storing the hash of a file a warning
     occurred in. At warning insert time, if the hash of the file does not match
     what is stored in the database, the existing warnings for that file are
     purged from the database.
 
     Callers should periodically prune old, invalid warnings from the database
     by calling prune(). A good time to do this is at the end of a build.
     """
-
     def __init__(self):
         """Create an empty database."""
         self._files = {}
 
     def __len__(self):
         i = 0
         for value in self._files.values():
             i += len(value['warnings'])
@@ -300,17 +299,16 @@ class WarningsCollector(object):
 
     Instances of this class receive data (usually the output of compiler
     invocations) and parse it into warnings.
 
     The collector works by incrementally receiving data, usually line-by-line
     output from the compiler. Therefore, it can maintain state to parse
     multi-line warning messages.
     """
-
     def __init__(self, cb, objdir=None):
         """Initialize a new collector.
 
         ``cb`` is a callable that is called with a ``CompilerWarning``
         instance whenever a new warning is parsed.
 
          ``objdir`` is the object directory. Used for normalizing paths.
          """
--- a/python/mozbuild/mozbuild/config_status.py
+++ b/python/mozbuild/mozbuild/config_status.py
@@ -5,16 +5,17 @@
 # Combined with build/autoconf/config.status.m4, ConfigStatus is an almost
 # 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
+import subprocess
 import sys
 import time
 
 from argparse import ArgumentParser
 
 from mach.logging import LoggingManager
 from mozbuild.backend.configenvironment import ConfigEnvironment
 from mozbuild.base import MachCommandConditions
@@ -74,24 +75,24 @@ def config_status(topobjdir='.', topsrcd
     The options to this function are passed when creating the
     ConfigEnvironment. These lists, as well as the actual wrapper script
     around this function, are meant to be generated by configure.
     See build/autoconf/config.status.m4.
     '''
 
     if 'CONFIG_FILES' in os.environ:
         raise Exception('Using the CONFIG_FILES environment variable is not '
-                        'supported.')
+            'supported.')
     if 'CONFIG_HEADERS' in os.environ:
         raise Exception('Using the CONFIG_HEADERS environment variable is not '
-                        'supported.')
+            'supported.')
 
     if not os.path.isabs(topsrcdir):
         raise Exception('topsrcdir must be defined as an absolute directory: '
-                        '%s' % topsrcdir)
+            '%s' % topsrcdir)
 
     default_backends = ['RecursiveMake']
     default_backends = (substs or {}).get('BUILD_BACKENDS', ['RecursiveMake'])
 
     parser = ArgumentParser()
     parser.add_argument('-v', '--verbose', dest='verbose', action='store_true',
                         help='display verbose output')
     parser.add_argument('-n', dest='not_topobjdir', action='store_true',
@@ -106,18 +107,18 @@ def config_status(topobjdir='.', topsrcd
                         help='do everything except writing files out.')
     options = parser.parse_args(args)
 
     # Without -n, the current directory is meant to be the top object directory
     if not options.not_topobjdir:
         topobjdir = os.path.abspath('.')
 
     env = ConfigEnvironment(topsrcdir, topobjdir, defines=defines,
-                            non_global_defines=non_global_defines, substs=substs,
-                            source=source, mozconfig=mozconfig)
+            non_global_defines=non_global_defines, substs=substs,
+            source=source, mozconfig=mozconfig)
 
     with FileAvoidWrite(os.path.join(topobjdir, 'mozinfo.json')) as f:
         write_mozinfo(f, env, os.environ)
 
     cpu_start = time.clock()
     time_start = time.time()
 
     # Make appropriate backend instances, defaulting to RecursiveMakeBackend,
--- a/python/mozbuild/mozbuild/configure/__init__.py
+++ b/python/mozbuild/mozbuild/configure/__init__.py
@@ -44,17 +44,16 @@ TRACE = 5
 
 
 class ConfigureError(Exception):
     pass
 
 
 class SandboxDependsFunction(object):
     '''Sandbox-visible representation of @depends functions.'''
-
     def __init__(self, unsandboxed):
         self._or = unsandboxed.__or__
         self._and = unsandboxed.__and__
         self._getattr = unsandboxed.__getattr__
 
     def __call__(self, *arg, **kwargs):
         raise ConfigureError('The `%s` function may not be called'
                              % self.__name__)
@@ -229,17 +228,16 @@ class CombinedDependsFunction(DependsFun
     def __eq__(self, other):
         return (isinstance(other, self.__class__) and
                 self._func is other._func and
                 set(self.dependencies) == set(other.dependencies))
 
     def __ne__(self, other):
         return not self == other
 
-
 class SandboxedGlobal(dict):
     '''Identifiable dict type for use as function global'''
 
 
 def forbidden_import(*args, **kwargs):
     raise ImportError('Importing modules is forbidden')
 
 
@@ -354,22 +352,20 @@ class ConfigureSandbox(dict):
                 yield
 
         self._logger = logger
 
         # Some callers will manage to log a bytestring with characters in it
         # that can't be converted to ascii. Make our log methods robust to this
         # by detecting the encoding that a producer is likely to have used.
         encoding = getpreferredencoding()
-
         def wrapped_log_method(logger, key):
             method = getattr(logger, key)
             if not encoding:
                 return method
-
             def wrapped(*args, **kwargs):
                 out_args = [
                     arg.decode(encoding) if isinstance(arg, str) else arg
                     for arg in args
                 ]
                 return method(*out_args, **kwargs)
             return wrapped
 
@@ -660,17 +656,17 @@ class ConfigureSandbox(dict):
         passed). In most cases, the result of this function is not expected to
         be used.
         Command line argument/environment variable parsing for this Option is
         handled here.
         '''
         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()
-                  if k != 'when'}
+                                      if k != 'when'}
         option = Option(*args, **kwargs)
         if when:
             self._conditions[option] = when
         if option.name in self._options:
             raise ConfigureError('Option `%s` already defined' % option.option)
         if option.env in self._options:
             raise ConfigureError('Option `%s` already defined' % option.env)
         if option.name:
--- a/python/mozbuild/mozbuild/configure/check_debug_ranges.py
+++ b/python/mozbuild/mozbuild/configure/check_debug_ranges.py
@@ -1,23 +1,22 @@
 # 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/.
 
 # This script returns the number of items for the DW_AT_ranges corresponding
 # 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, print_function
+from __future__ import absolute_import
 
 import subprocess
 import sys
 import re
 
-
 def get_range_for(compilation_unit, debug_info):
     '''Returns the range offset for a given compilation unit
        in a given debug_info.'''
     name = ranges = ''
     search_cu = False
     for nfo in debug_info.splitlines():
         if 'DW_TAG_compile_unit' in nfo:
             search_cu = True
@@ -28,30 +27,28 @@ def get_range_for(compilation_unit, debu
             search_cu = False
         if search_cu:
             if 'DW_AT_name' in nfo:
                 name = nfo.rsplit(None, 1)[1]
             elif 'DW_AT_ranges' in nfo:
                 ranges = nfo.rsplit(None, 1)[1]
     return None
 
-
 def get_range_length(range, debug_ranges):
     '''Returns the number of items in the range starting at the
        given offset.'''
     length = 0
     for line in debug_ranges.splitlines():
         m = re.match('\s*([0-9a-fA-F]+)\s+([0-9a-fA-F]+)\s+([0-9a-fA-F]+)', line)
         if m and int(m.group(1), 16) == range:
             length += 1
     return length
 
-
 def main(bin, compilation_unit):
-    p = subprocess.Popen(['objdump', '-W', bin], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+    p = subprocess.Popen(['objdump', '-W', bin], stdout = subprocess.PIPE, stderr = subprocess.PIPE)
     (out, err) = p.communicate()
     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')]
     if not debug_ranges or not debug_info:
         return 0
 
     range = get_range_for(compilation_unit, debug_info[0])
--- a/python/mozbuild/mozbuild/configure/libstdcxx.py
+++ b/python/mozbuild/mozbuild/configure/libstdcxx.py
@@ -8,69 +8,63 @@
 # with 8 bits per element. For example, GLIBCXX_3.4.10 becomes
 # 3 << 16 | 4 << 8 | 10 = 197642. This format is easy to use
 # in the C preprocessor.
 
 # We find out both the host and target versions. Since the output
 # will be used from shell, we just print the two assignments and evaluate
 # them from shell.
 
-from __future__ import absolute_import, print_function
+from __future__ import absolute_import
 
 import os
 import subprocess
 import re
 
 re_for_ld = re.compile('.*\((.*)\).*')
 
-
 def parse_readelf_line(x):
     """Return the version from a readelf line that looks like:
     0x00ec: Rev: 1  Flags: none  Index: 8  Cnt: 2  Name: GLIBCXX_3.4.6
     """
     return x.split(':')[-1].split('_')[-1].strip()
 
-
 def parse_ld_line(x):
     """Parse a line from the output of ld -t. The output of gold is just
     the full path, gnu ld prints "-lstdc++ (path)".
     """
     t = re_for_ld.match(x)
     if t:
         return t.groups()[0].strip()
     return x.strip()
 
-
 def split_ver(v):
     """Covert the string '1.2.3' into the list [1,2,3]
     """
     return [int(x) for x in v.split('.')]
 
-
 def cmp_ver(a, b):
     """Compare versions in the form 'a.b.c'
     """
     for (i, j) in zip(split_ver(a), split_ver(b)):
         if i != j:
             return i - j
     return 0
 
-
 def encode_ver(v):
     """Encode the version as a single number.
     """
     t = split_ver(v)
     return t[0] << 16 | t[1] << 8 | t[2]
 
-
 def find_version(args):
     """Given a base command line for a compiler, find the version of the
     libstdc++ it uses.
     """
-    args += ['-shared', '-Wl,-t']
+    args +=  ['-shared', '-Wl,-t']
     p = subprocess.Popen(args, stderr=subprocess.STDOUT, stdout=subprocess.PIPE)
     candidates = [x for x in p.stdout if 'libstdc++.so' in x]
     candidates = [x for x in candidates if 'skipping incompatible' not in x]
     if not candidates:
         raise Exception('''Couldn't find libstdc++ candidates!
 command line: %s''' % args)
     if len(candidates) != 1:
         raise Exception('''Too many libstdc++ candidates!
@@ -78,20 +72,19 @@ command line: %s
 candidates:
 %s''' % (args, '\n'.join(candidates)))
 
     libstdcxx = parse_ld_line(candidates[-1])
 
     p = subprocess.Popen(['readelf', '-V', libstdcxx], stdout=subprocess.PIPE)
     versions = [parse_readelf_line(x)
                 for x in p.stdout.readlines() if 'Name: GLIBCXX' in x]
-    last_version = sorted(versions, cmp=cmp_ver)[-1]
+    last_version = sorted(versions, cmp = cmp_ver)[-1]
     return (last_version, encode_ver(last_version))
 
-
 if __name__ == '__main__':
     """Given the value of environment variable CXX or HOST_CXX, find the
     version of the libstdc++ it uses.
     """
     cxx_env = os.environ['CXX']
     print('MOZ_LIBSTDCXX_TARGET_VERSION=%s' % find_version(cxx_env.split())[1])
     host_cxx_env = os.environ.get('HOST_CXX', cxx_env)
     print('MOZ_LIBSTDCXX_HOST_VERSION=%s' % find_version(host_cxx_env.split())[1])
--- a/python/mozbuild/mozbuild/configure/lint.py
+++ b/python/mozbuild/mozbuild/configure/lint.py
@@ -232,16 +232,17 @@ class LintSandbox(ConfigureSandbox):
                     frame = frame.f_back
                 e = ConfigureError('{} should be used instead of '
                                    '{} with default={}'.format(
                                        name.replace('--{}-'.format(prefix),
                                                     '--{}-'.format(replacement)),
                                        name, default))
                 self._raise_from(e, frame.f_back if frame else None)
 
+
     def _check_help_for_option_with_func_default(self, option, *args, **kwargs):
         default = kwargs['default']
 
         if not isinstance(default, SandboxDependsFunction):
             return
 
         if not option.prefix:
             return
@@ -279,17 +280,16 @@ class LintSandbox(ConfigureSandbox):
     def wraps(self, func):
         def do_wraps(wrapper):
             self._wrapped[wrapper] = func
             return wraps(func)(wrapper)
         return do_wraps
 
     def imports_impl(self, _import, _from=None, _as=None):
         wrapper = super(LintSandbox, self).imports_impl(_import, _from=_from, _as=_as)
-
         def decorator(func):
             self._has_imports.add(func)
             return wrapper(func)
         return decorator
 
     def _prepare_function(self, func, update_globals=None):
         wrapped = super(LintSandbox, self)._prepare_function(func, update_globals)
         _, glob = self.unwrap(wrapped)
--- a/python/mozbuild/mozbuild/configure/lint_util.py
+++ b/python/mozbuild/mozbuild/configure/lint_util.py
@@ -41,17 +41,17 @@ def disassemble_as_iter(co):
     next_byte_line = lnotab.next()
     while i < n:
         while next_byte_line and i >= next_byte_line[0]:
             line = next_byte_line[1]
             next_byte_line = lnotab.next()
         c = code[i]
         op = ord(c)
         opname = dis.opname[op]
-        i += 1
+        i += 1;
         if op >= dis.HAVE_ARGUMENT:
             arg = ord(code[i]) + ord(code[i + 1]) * 256 + extended_arg
             extended_arg = 0
             i += 2
             if op == dis.EXTENDED_ARG:
                 extended_arg = arg * 65536
                 continue
             if op in dis.hasconst:
--- a/python/mozbuild/mozbuild/configure/options.py
+++ b/python/mozbuild/mozbuild/configure/options.py
@@ -101,17 +101,16 @@ class OptionValue(tuple):
                             % type(value).__name__)
 
 
 class PositiveOptionValue(OptionValue):
     '''Represents the value for a positive option (--enable/--with/--foo)
     in the form of a tuple for when values are given to the option (in the form
     --option=value[,value2...].
     '''
-
     def __nonzero__(self):
         return True
 
 
 class NegativeOptionValue(OptionValue):
     '''Represents the value for a negative option (--disable/--without)
 
     This is effectively an empty tuple with a `origin` attribute.
@@ -420,17 +419,16 @@ class CommandLineHelper(object):
     If multiple variants are given, command line is prefered over the
     environment, and if different values are given on the command line, the
     last one wins. (This mimicks the behavior of autoconf, avoiding to break
     existing mozconfigs using valid options in weird ways)
 
     Extra options can be added afterwards through API calls. For those,
     conflicting values will raise an exception.
     '''
-
     def __init__(self, environ=os.environ, argv=sys.argv):
         self._environ = dict(environ)
         self._args = OrderedDict()
         self._extra_args = OrderedDict()
         self._origins = {}
         self._last = 0
 
         assert(argv and not argv[0].startswith('--'))
--- a/python/mozbuild/mozbuild/configure/util.py
+++ b/python/mozbuild/mozbuild/configure/util.py
@@ -9,52 +9,49 @@ import itertools
 import locale
 import logging
 import os
 import sys
 from collections import deque
 from contextlib import contextmanager
 from distutils.version import LooseVersion
 
-
 def getpreferredencoding():
     # locale._parse_localename makes locale.getpreferredencoding
     # return None when LC_ALL is C, instead of e.g. 'US-ASCII' or
     # 'ANSI_X3.4-1968' when it uses nl_langinfo.
     encoding = None
     try:
         encoding = locale.getpreferredencoding()
     except ValueError:
         # On english OSX, LC_ALL is UTF-8 (not en-US.UTF-8), and
         # that throws off locale._parse_localename, which ends up
         # being used on e.g. homebrew python.
         if os.environ.get('LC_ALL', '').upper() == 'UTF-8':
             encoding = 'utf-8'
     return encoding
 
-
 class Version(LooseVersion):
     '''A simple subclass of distutils.version.LooseVersion.
     Adds attributes for `major`, `minor`, `patch` for the first three
     version components so users can easily pull out major/minor
     versions, like:
 
     v = Version('1.2b')
     v.major == 1
     v.minor == 2
     v.patch == 0
     '''
-
     def __init__(self, version):
         # Can't use super, LooseVersion's base class is not a new-style class.
         LooseVersion.__init__(self, version)
         # Take the first three integer components, stopping at the first
         # non-integer and padding the rest with zeroes.
         (self.major, self.minor, self.patch) = list(itertools.chain(
-            itertools.takewhile(lambda x: isinstance(x, int), self.version),
+            itertools.takewhile(lambda x:isinstance(x, int), self.version),
             (0, 0, 0)))[:3]
 
     def __cmp__(self, other):
         # LooseVersion checks isinstance(StringType), so work around it.
         if isinstance(other, unicode):
             other = other.encode('ascii')
         return LooseVersion.__cmp__(self, other)
 
@@ -69,17 +66,16 @@ class ConfigureOutputHandler(logging.Han
 
     Only messages above log level INFO (included) are logged.
 
     Messages below that level can be kept until an ERROR message is received,
     at which point the last `maxlen` accumulated messages below INFO are
     printed out. This feature is only enabled under the `queue_debug` context
     manager.
     '''
-
     def __init__(self, stdout=sys.stdout, stderr=sys.stderr, maxlen=20):
         super(ConfigureOutputHandler, self).__init__()
 
         # Python has this feature where it sets the encoding of pipes to
         # ascii, which blatantly fails when trying to print out non-ascii.
         def fix_encoding(fh):
             try:
                 isatty = fh.isatty()
@@ -150,17 +146,17 @@ class ConfigureOutputHandler(logging.Han
                     self._stdout.write('\n')
                     self._stdout.flush()
                 stream = self._stderr
                 msg = '%s\n' % self.format(record)
             stream.write(msg)
             stream.flush()
         except (KeyboardInterrupt, SystemExit, IOError):
             raise
-        except Exception:
+        except:
             self.handleError(record)
 
     @contextmanager
     def queue_debug(self):
         if self._queue_is_active:
             yield
             return
         self._queue_is_active = True
@@ -192,17 +188,16 @@ class ConfigureOutputHandler(logging.Han
                 break
         self._keep_if_debug = self.KEEP
 
 
 class LineIO(object):
     '''File-like class that sends each line of the written data to a callback
     (without carriage returns).
     '''
-
     def __init__(self, callback, errors='strict'):
         self._callback = callback
         self._buf = ''
         self._encoding = getpreferredencoding()
         self._errors = errors
 
     def write(self, buf):
         if self._encoding and isinstance(buf, str):
--- a/python/mozbuild/mozbuild/controller/building.py
+++ b/python/mozbuild/mozbuild/controller/building.py
@@ -1,16 +1,17 @@
 # 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 absolute_import, print_function, unicode_literals
+from __future__ import absolute_import, unicode_literals
 
 import errno
 import getpass
+import glob
 import io
 import json
 import logging
 import os
 import subprocess
 import sys
 import time
 import which
@@ -73,17 +74,17 @@ slower.
 Consider adding ".noindex" to the end of your object directory name to have
 Finder ignore it. Or, add an indexing exclusion through the Spotlight System
 Preferences.
 ===================
 '''.strip()
 
 
 INSTALL_TESTS_CLOBBER = ''.join([TextWrapper().fill(line) + '\n' for line in
-                                 '''
+'''
 The build system was unable to install tests because the CLOBBER file has \
 been updated. This means if you edited any test files, your changes may not \
 be picked up until a full/clobber build is performed.
 
 The easiest and fastest way to perform a clobber build is to run:
 
  $ mach clobber
  $ mach build
@@ -101,17 +102,17 @@ required to succeed, but we weren't expe
 
 Please consider filing a bug for this failure if you have reason to believe
 this is a clobber bug and not due to local changes.
 ===================
 '''.strip()
 
 
 BuildOutputResult = namedtuple('BuildOutputResult',
-                               ('warning', 'state_changed', 'message'))
+    ('warning', 'state_changed', 'message'))
 
 
 class TierStatus(object):
     """Represents the state and progress of tier traversal.
 
     The build system is organized into linear phases called tiers. Each tier
     executes in the order it was defined, 1 at a time.
     """
@@ -167,19 +168,19 @@ class TierStatus(object):
 
             o.append(t_entry)
 
         return o
 
     def add_resources_to_dict(self, entry, start=None, end=None, phase=None):
         """Helper function to append resource information to a dict."""
         cpu_percent = self.resources.aggregate_cpu_percent(start=start,
-                                                           end=end, phase=phase, per_cpu=False)
+            end=end, phase=phase, per_cpu=False)
         cpu_times = self.resources.aggregate_cpu_times(start=start, end=end,
-                                                       phase=phase, per_cpu=False)
+            phase=phase, per_cpu=False)
         io = self.resources.aggregate_io(start=start, end=end, phase=phase)
 
         if cpu_percent is None:
             return entry
 
         entry['cpu_percent'] = cpu_percent
         entry['cpu_times'] = list(cpu_times)
         entry['io'] = list(io)
@@ -299,17 +300,17 @@ class BuildMonitor(MozbuildObject):
 
             return BuildOutputResult(None, update_needed, message)
 
         warning = None
 
         try:
             warning = self._warnings_collector.process_line(line)
             message = line
-        except Exception:
+        except:
             pass
 
         return BuildOutputResult(warning, False, message)
 
     def stop_resource_recording(self):
         if self._resources_started:
             self.resources.stop()
 
@@ -333,18 +334,18 @@ class BuildMonitor(MozbuildObject):
             if not usage:
                 return
 
             self.log_resource_usage(usage)
             with open(self._get_state_filename('build_resources.json'), 'w') as fh:
                 json.dump(self.resources.as_dict(), fh, indent=2)
         except Exception as e:
             self.log(logging.WARNING, 'build_resources_error',
-                     {'msg': str(e)},
-                     'Exception when writing resource usage file: {msg}')
+                {'msg': str(e)},
+                'Exception when writing resource usage file: {msg}')
 
     def _get_finder_cpu_usage(self):
         """Obtain the CPU usage of the Finder app on OS X.
 
         This is used to detect high CPU usage.
         """
         if not sys.platform.startswith('darwin'):
             return None
@@ -432,19 +433,19 @@ class BuildMonitor(MozbuildObject):
         subsequent analysis.
 
         If no resource usage is available, None is returned.
         """
         if not self.have_resource_usage:
             return None
 
         cpu_percent = self.resources.aggregate_cpu_percent(phase=None,
-                                                           per_cpu=False)
+            per_cpu=False)
         cpu_times = self.resources.aggregate_cpu_times(phase=None,
-                                                       per_cpu=False)
+            per_cpu=False)
         io = self.resources.aggregate_io(phase=None)
 
         o = dict(
             version=3,
             argv=sys.argv,
             start=self.start_time,
             end=self.end_time,
             duration=self.end_time - self.start_time,
@@ -456,32 +457,33 @@ class BuildMonitor(MozbuildObject):
         )
 
         o['tiers'] = self.tiers.tiered_resource_usage()
 
         self.tiers.add_resource_fields_to_dict(o)
 
         for usage in self.resources.range_usage():
             cpu_percent = self.resources.aggregate_cpu_percent(usage.start,
-                                                               usage.end, per_cpu=False)
+                usage.end, per_cpu=False)
             cpu_times = self.resources.aggregate_cpu_times(usage.start,
-                                                           usage.end, per_cpu=False)
+                usage.end, per_cpu=False)
 
             entry = dict(
                 start=usage.start,
                 end=usage.end,
                 virt=list(usage.virt),
                 swap=list(usage.swap),
             )
 
             self.tiers.add_resources_to_dict(entry, start=usage.start,
-                                             end=usage.end)
+                    end=usage.end)
 
             o['resources'].append(entry)
 
+
         # If the imports for this file ran before the in-tree virtualenv
         # was bootstrapped (for instance, for a clobber build in automation),
         # psutil might not be available.
         #
         # Treat psutil as optional to avoid an outright failure to log resources
         # TODO: it would be nice to collect data on the storage device as well
         # in this case.
         o['system'] = {}
@@ -517,18 +519,18 @@ class BuildMonitor(MozbuildObject):
 
         self.log(logging.WARNING, 'resource_usage', params, message)
 
         excessive, sin, sout = self.have_excessive_swapping()
         if excessive is not None and (sin or sout):
             sin /= 1048576
             sout /= 1048576
             self.log(logging.WARNING, 'swap_activity',
-                     {'sin': sin, 'sout': sout},
-                     'Swap in/out (MB): {sin}/{sout}')
+                {'sin': sin, 'sout': sout},
+                'Swap in/out (MB): {sin}/{sout}')
 
     def ccache_stats(self):
         ccache_stats = None
 
         try:
             ccache = which.which('ccache')
             output = subprocess.check_output([ccache, '-s'])
             ccache_stats = CCacheStats(output)
@@ -541,17 +543,16 @@ class BuildMonitor(MozbuildObject):
 
 
 class TerminalLoggingHandler(logging.Handler):
     """Custom logging handler that works with terminal window dressing.
 
     This class should probably live elsewhere, like the mach core. Consider
     this a proving ground for its usefulness.
     """
-
     def __init__(self):
         logging.Handler.__init__(self)
 
         self.fh = sys.stdout
         self.footer = None
 
     def flush(self):
         self.acquire()
@@ -677,16 +678,17 @@ class BuildOutputManager(OutputManager):
     def __exit__(self, exc_type, exc_value, traceback):
         OutputManager.__exit__(self, exc_type, exc_value, traceback)
 
         # Ensure the resource monitor is stopped because leaving it running
         # could result in the process hanging on exit because the resource
         # collection child process hasn't been told to stop.
         self.monitor.stop_resource_recording()
 
+
     def on_line(self, line):
         warning, state_changed, message = self.monitor.on_line(line)
 
         if message:
             self.log(logging.INFO, 'build_output', {'line': message}, '{line}')
         elif state_changed:
             have_handler = hasattr(self, 'handler')
             if have_handler:
@@ -737,17 +739,17 @@ class StaticAnalysisOutputManager(Output
 
     def on_line(self, line):
         warning, relevant = self.monitor.on_line(line)
         if relevant:
             self.raw += line + '\n'
 
         if warning:
             self.log(logging.INFO, 'compiler_warning', warning,
-                     'Warning: {flag} in {filename}: {message}')
+                'Warning: {flag} in {filename}: {message}')
 
         if relevant:
             self.log(logging.INFO, 'build_output', {'line': line}, '{line}')
         else:
             have_handler = hasattr(self, 'handler')
             if have_handler:
                 self.handler.acquire()
             try:
@@ -779,17 +781,17 @@ class CCacheStats(object):
     Instances can be subtracted from each other to obtain differences.
     print() or str() the object to show a ``ccache -s`` like output
     of the captured stats.
 
     """
     STATS_KEYS = [
         # (key, description)
         # Refer to stats.c in ccache project for all the descriptions.
-        ('stats_zeroed', 'stats zero time'),  # Old name prior to ccache 3.4
+        ('stats_zeroed', 'stats zero time'), # Old name prior to ccache 3.4
         ('stats_zeroed', 'stats zeroed'),
         ('stats_updated', 'stats updated'),
         ('cache_hit_direct', 'cache hit (direct)'),
         ('cache_hit_preprocessed', 'cache hit (preprocessed)'),
         ('cache_hit_rate', 'cache hit rate'),
         ('cache_miss', 'cache miss'),
         ('link', 'called for link'),
         ('preprocessing', 'called for preprocessing'),
@@ -896,20 +898,17 @@ class CCacheStats(object):
         elif unit in ('KB', 'Kbytes'):
             unit = CCacheStats.KiB
         else:
             unit = 1
 
         return int(numeric * unit)
 
     def hit_rate_message(self):
-        return ('ccache (direct) hit rate: {:.1%}; (preprocessed) hit rate: {:.1%};'
-                ' miss rate: {:.1%}'.format(
-                    *self.hit_rates()
-                ))
+        return 'ccache (direct) hit rate: {:.1%}; (preprocessed) hit rate: {:.1%}; miss rate: {:.1%}'.format(*self.hit_rates())
 
     def hit_rates(self):
         direct = self._values['cache_hit_direct']
         preprocessed = self._values['cache_hit_preprocessed']
         miss = self._values['cache_miss']
         total = float(direct + preprocessed + miss)
 
         if total > 0:
@@ -1001,21 +1000,21 @@ class BuildDriver(MozbuildObject):
         # down builds.
         mkdir(self.topobjdir, not_indexed=True)
 
         with BuildOutputManager(self.log_manager, monitor, footer) as output:
             monitor.start()
 
             if directory is not None and not what:
                 print('Can only use -C/--directory with an explicit target '
-                      'name.')
+                    'name.')
                 return 1
 
             if directory is not None:
-                disable_extra_make_dependencies = True
+                disable_extra_make_dependencies=True
                 directory = mozpath.normsep(directory)
                 if directory.startswith('/'):
                     directory = directory[1:]
 
             monitor.start_resource_recording()
 
             self.mach_context.command_attrs['clobber'] = False
             config = None
@@ -1100,17 +1099,17 @@ class BuildDriver(MozbuildObject):
                     path_arg = self._wrap_path_argument(target)
 
                     if directory is not None:
                         make_dir = os.path.join(self.topobjdir, directory)
                         make_target = target
                     else:
                         make_dir, make_target = \
                             resolve_target_to_make(self.topobjdir,
-                                                   path_arg.relpath())
+                                path_arg.relpath())
 
                     if make_dir is None and make_target is None:
                         return 1
 
                     # See bug 886162 - we don't want to "accidentally" build
                     # the entire tree (if that's really the intent, it's
                     # unlikely they would have specified a directory.)
                     if not make_dir and not make_target:
@@ -1141,22 +1140,20 @@ class BuildDriver(MozbuildObject):
 
                 # Build target pairs.
                 for make_dir, make_target in target_pairs:
                     # We don't display build status messages during partial
                     # tree builds because they aren't reliable there. This
                     # could potentially be fixed if the build monitor were more
                     # intelligent about encountering undefined state.
                     no_build_status = b'1' if make_dir is not None else b''
-                    status = self._run_make(
-                        directory=make_dir, target=make_target,
+                    status = self._run_make(directory=make_dir, target=make_target,
                         line_handler=output.on_line, log=False, print_directory=False,
                         ensure_exit_code=False, num_jobs=jobs, silent=not verbose,
-                        append_env={
-                            b'NO_BUILDSTATUS_MESSAGES': no_build_status},
+                        append_env={b'NO_BUILDSTATUS_MESSAGES': no_build_status},
                         keep_going=keep_going)
 
                     if status != 0:
                         break
 
             elif status is None:
                 # If the backend doesn't specify a build() method, then just
                 # call client.mk directly.
@@ -1202,18 +1199,18 @@ class BuildDriver(MozbuildObject):
         # whatever code we warned about.
         if not status:
             # Suppress warnings for 3rd party projects in local builds
             # until we suppress them for real.
             # TODO remove entries/feature once we stop generating warnings
             # in these directories.
             pathToThirdparty = os.path.join(self.topsrcdir,
                                             "tools",
-                                            "rewriting",
-                                            "ThirdPartyPaths.txt")
+                                           "rewriting",
+                                           "ThirdPartyPaths.txt")
 
             if os.path.exists(pathToThirdparty):
                 with open(pathToThirdparty) as f:
                     # Normalize the path (no trailing /)
                     LOCAL_SUPPRESS_DIRS = tuple(d.rstrip('/') for d in f.read().splitlines())
             else:
                 # For application based on gecko like thunderbird
                 LOCAL_SUPPRESS_DIRS = ()
@@ -1282,35 +1279,32 @@ class BuildDriver(MozbuildObject):
             #    print(EXCESSIVE_SWAP_MESSAGE)
 
             print('To view resource usage of the build, run |mach '
                   'resource-usage|.')
 
         long_build = monitor.elapsed > 600
 
         if long_build:
-            output.on_line(
-                'We know it took a while, but your build finally finished successfully!')
+            output.on_line('We know it took a while, but your build finally finished successfully!')
         else:
             output.on_line('Your build was successful!')
 
         # Only for full builds because incremental builders likely don't
         # need to be burdened with this.
         if not what:
             try:
                 # Fennec doesn't have useful output from just building. We should
                 # arguably make the build action useful for Fennec. Another day...
                 if self.substs['MOZ_BUILD_APP'] != 'mobile/android':
                     print('To take your build for a test drive, run: |mach run|')
                 app = self.substs['MOZ_BUILD_APP']
                 if app in ('browser', 'mobile/android'):
-                    print(
-                        'For more information on what to do now, see '
-                        'https://developer.mozilla.org/docs/Developer_Guide/So_You_Just_Built_Firefox'  # noqa
-                    )
+                    print('For more information on what to do now, see '
+                        'https://developer.mozilla.org/docs/Developer_Guide/So_You_Just_Built_Firefox')
             except Exception:
                 # Ignore Exceptions in case we can't find config.status (such
                 # as when doing OSX Universal builds)
                 pass
 
         return status
 
     def configure(self, options=None, buildstatus_messages=False,
@@ -1326,24 +1320,24 @@ class BuildDriver(MozbuildObject):
         line_handler = line_handler or on_line
 
         options = ' '.join(shell_quote(o) for o in options or ())
         append_env = {b'CONFIGURE_ARGS': options.encode('utf-8')}
 
         # Only print build status messages when we have an active
         # monitor.
         if not buildstatus_messages:
-            append_env[b'NO_BUILDSTATUS_MESSAGES'] = b'1'
+            append_env[b'NO_BUILDSTATUS_MESSAGES'] =  b'1'
         status = self._run_client_mk(target='configure',
                                      line_handler=line_handler,
                                      append_env=append_env)
 
         if not status:
             print('Configure complete!')
-            print('Be sure to run |mach build| to pick up any changes')
+            print('Be sure to run |mach build| to pick up any changes');
 
         return status
 
     def install_tests(self, test_objs):
         """Install test files."""
 
         if self.is_clobber_needed():
             print(INSTALL_TESTS_CLOBBER.format(
--- a/python/mozbuild/mozbuild/controller/clobber.py
+++ b/python/mozbuild/mozbuild/controller/clobber.py
@@ -11,17 +11,17 @@ import os
 import subprocess
 import sys
 
 from mozfile.mozfile import remove as mozfileremove
 from textwrap import TextWrapper
 
 
 CLOBBER_MESSAGE = ''.join([TextWrapper().fill(line) + '\n' for line in
-                           '''
+'''
 The CLOBBER file has been updated, indicating that an incremental build since \
 your last build will probably not work. A full/clobber build is required.
 
 The reason for the clobber is:
 
 {clobber_reason}
 
 Clobbering can be performed automatically. However, we didn't automatically \
@@ -34,17 +34,16 @@ The easiest and fastest way to clobber i
  $ mach clobber
 
 If you know this clobber doesn't apply to you or you're feeling lucky -- \
 Well, are ya? -- you can ignore this clobber requirement by running:
 
  $ touch {clobber_file}
 '''.splitlines()])
 
-
 class Clobberer(object):
     def __init__(self, topsrcdir, topobjdir):
         """Create a new object to manage clobbering the tree.
 
         It is bound to a top source directory and to a specific object
         directory.
         """
         assert os.path.isabs(topsrcdir)
@@ -65,17 +64,17 @@ class Clobberer(object):
         """Returns a bool indicating whether a tree clobber is required."""
 
         # No object directory clobber file means we're good.
         if not os.path.exists(self.obj_clobber):
             return False
 
         # Object directory clobber older than current is fine.
         if os.path.getmtime(self.src_clobber) <= \
-                os.path.getmtime(self.obj_clobber):
+            os.path.getmtime(self.obj_clobber):
 
             return False
 
         return True
 
     def clobber_cause(self):
         """Obtain the cause why a clobber is required.
 
@@ -90,17 +89,17 @@ class Clobberer(object):
 
     def have_winrm(self):
         # `winrm -h` should print 'winrm version ...' and exit 1
         try:
             p = subprocess.Popen(['winrm.exe', '-h'],
                                  stdout=subprocess.PIPE,
                                  stderr=subprocess.STDOUT)
             return p.wait() == 1 and p.stdout.read().startswith('winrm')
-        except Exception:
+        except:
             return False
 
     def remove_objdir(self, full=True):
         """Remove the object directory.
 
         ``full`` controls whether to fully delete the objdir. If False,
         some directories (e.g. Visual Studio Project Files) will not be
         deleted.
@@ -178,18 +177,18 @@ class Clobberer(object):
         # current directory is not under the object directory. The latter is
         # because operating systems, filesystems, and shell can throw fits
         # if the current working directory is deleted from under you. While it
         # can work in some scenarios, we take the conservative approach and
         # never try.
         if not allow_auto:
             return True, False, \
                self._message('Automatic clobbering is not enabled\n'
-                             '  (add "mk_add_options AUTOCLOBBER=1" to your '
-                             'mozconfig).')
+                              '  (add "mk_add_options AUTOCLOBBER=1" to your '
+                              'mozconfig).')
 
         if cwd.startswith(self.topobjdir) and cwd != self.topobjdir:
             return True, False, self._message(
                 'Cannot clobber while the shell is inside the object directory.')
 
         objdir = self.topobjdir.encode('utf-8', 'replace')
         print('Automatically clobbering %s' % objdir, file=fh)
         try:
@@ -200,9 +199,9 @@ class Clobberer(object):
         except (IOError) as error:
             return True, False, self._message(
                 'Error when automatically clobbering: ' + str(error))
 
     def _message(self, reason):
         lines = [' ' + line for line in self.clobber_cause()]
 
         return CLOBBER_MESSAGE.format(clobber_reason='\n'.join(lines),
-                                      no_reason='  ' + reason, clobber_file=self.obj_clobber)
+            no_reason='  ' + reason, clobber_file=self.obj_clobber)
--- a/python/mozbuild/mozbuild/doctor.py
+++ b/python/mozbuild/mozbuild/doctor.py
@@ -1,13 +1,13 @@
 # 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 absolute_import, print_function
+from __future__ import absolute_import
 
 import os
 import subprocess
 import sys
 
 import psutil
 
 from distutils.util import strtobool
@@ -29,17 +29,16 @@ LATEST_MOZILLABUILD_VERSION = '1.11.0'
 DISABLE_LASTACCESS_WIN = '''
 Disable the last access time feature?
 This improves the speed of file and
 directory access by deferring Last Access Time modification on disk by up to an
 hour. Backup programs that rely on this feature may be affected.
 https://technet.microsoft.com/en-us/library/cc785435.aspx
 '''
 
-
 class Doctor(object):
     def __init__(self, srcdir, objdir, fix):
         self.srcdir = mozpath.normpath(srcdir)
         self.objdir = mozpath.normpath(objdir)
         self.srcdir_mount = self.getmount(self.srcdir)
         self.objdir_mount = self.getmount(self.objdir)
         self.path_mounts = [
             ('srcdir', self.srcdir, self.srcdir_mount),
@@ -65,17 +64,17 @@ class Doctor(object):
             if result.get('status') != 'GOOD':
                 good = False
             if result.get('fixable', False):
                 fixable = True
             if result.get('denied', False):
                 denied = True
         if denied:
             print('run "mach doctor --fix" AS ADMIN to re-attempt fixing your system')
-        elif False and fixable:  # elif fixable:  # 'and fixable' avoids flake8 error
+        elif False: # elif fixable:
             print('run "mach doctor --fix" as admin to attempt fixing your system')
         return int(not good)
 
     def getmount(self, path):
         while path != '/' and not os.path.ismount(path):
             path = mozpath.abspath(mozpath.join(path, os.pardir))
         return path
 
@@ -198,17 +197,17 @@ class Doctor(object):
             except subprocess.CalledProcessError:
                 disablelastaccess = -1
                 status = 'UNSURE'
                 desc = 'unable to check lastaccess behavior'
             if disablelastaccess == 1:
                 status = 'GOOD'
                 desc = 'lastaccess disabled systemwide'
             elif disablelastaccess == 0:
-                if False:  # if self.fix:
+                if False: # if self.fix:
                     choice = self.prompt_bool(DISABLE_LASTACCESS_WIN)
                     if not choice:
                         return {'status': 'BAD, NOT FIXED',
                                 'desc': 'lastaccess enabled systemwide'}
                     try:
                         command = 'fsutil behavior set disablelastaccess 1'.split(' ')
                         fsutil_output = subprocess.check_output(command)
                         status = 'GOOD, FIXED'
--- a/python/mozbuild/mozbuild/dotproperties.py
+++ b/python/mozbuild/mozbuild/dotproperties.py
@@ -1,27 +1,26 @@
 # 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/.
 
 # This file contains utility functions for reading .properties files, like
 # region.properties.
 
-from __future__ import absolute_import, print_function, unicode_literals
+from __future__ import absolute_import, unicode_literals
 
 import codecs
 import re
 import sys
 
 if sys.version_info[0] == 3:
     str_type = str
 else:
     str_type = basestring
 
-
 class DotProperties:
     r'''A thin representation of a key=value .properties file.'''
 
     def __init__(self, file=None):
         self._properties = {}
         if file:
             self.update(file)
 
@@ -73,12 +72,12 @@ class DotProperties:
 
         if not prefix.endswith('.'):
             prefix = prefix + '.'
 
         D = dict((k[len(prefix):], v) for k, v in self._properties.iteritems()
                  if k.startswith(prefix) and '.' not in k[len(prefix):])
 
         for required_key in required_keys:
-            if required_key not in D:
+            if not required_key in D:
                 raise ValueError('Required key %s not present' % required_key)
 
         return D
--- a/python/mozbuild/mozbuild/export_telemetry_schema.py
+++ b/python/mozbuild/mozbuild/export_telemetry_schema.py
@@ -1,11 +1,11 @@
 #!/usr/bin/env python
 
-from __future__ import absolute_import, print_function, unicode_literals
+from __future__ import print_function, unicode_literals
 
 """
 This script converts the build system telemetry schema from voluptuous format to json-schema.
 You should run it with `mach python`.
 """
 
 import argparse
 from mozbuild.base import MozbuildObject
--- a/python/mozbuild/mozbuild/faster_daemon.py
+++ b/python/mozbuild/mozbuild/faster_daemon.py
@@ -103,18 +103,18 @@ class Daemon(object):
                 'allof',
                 ['type', 'f'],
                 ['not',
                  ['anyof',
                   ['dirname', '.hg'],
                   ['name', '.hg', 'wholename'],
                   ['dirname', '.git'],
                   ['name', '.git', 'wholename'],
-                  ],
                  ],
+                ],
             ],
             'fields': ['name'],
         }
         watch = self.client.query('watch-project', dir_to_watch)
         if 'warning' in watch:
             print('WARNING: ', watch['warning'], file=sys.stderr)
 
         root = watch['watch']
@@ -199,17 +199,17 @@ class Daemon(object):
 
             input_to_outputs = self.file_copier.input_to_outputs_tree()
             for input, outputs in input_to_outputs.items():
                 if not outputs:
                     raise Exception("Refusing to watch input ({}) with no outputs".format(input))
 
             while True:
                 try:
-                    self.client.receive()
+                    _watch_result = self.client.receive()
 
                     changed = self.changed_files()
                     if not changed:
                         continue
 
                     result = FasterBuildChange()
 
                     for change in changed:
@@ -223,17 +223,17 @@ class Daemon(object):
                             if output not in result.output_to_inputs:
                                 result.output_to_inputs[output] = set()
                             result.output_to_inputs[output].add(input)
 
                     yield result
 
                 except pywatchman.SocketTimeout:
                     # Let's check to see if we're still functional.
-                    self.client.query('version')
+                    _version = self.client.query('version')
 
         except pywatchman.CommandError as e:
             # Abstract away pywatchman errors.
             raise FasterBuildException(e, 'Command error using pywatchman to watch {}'.format(
                 self.config_environment.topsrcdir))
 
         except pywatchman.SocketTimeout as e:
             # Abstract away pywatchman errors.
--- a/python/mozbuild/mozbuild/frontend/context.py
+++ b/python/mozbuild/mozbuild/frontend/context.py
@@ -9,17 +9,17 @@
 r"""This module contains the data structure (context) holding the configuration
 from a moz.build. The data emitted by the frontend derives from those contexts.
 
 It also defines the set of variables and functions available in moz.build.
 If you are looking for the absolute authority on what moz.build files can
 contain, you've come to the right place.
 """
 
-from __future__ import absolute_import, print_function, unicode_literals
+from __future__ import absolute_import, unicode_literals
 
 import os
 
 from collections import (
     Counter,
     OrderedDict,
 )
 from mozbuild.util import (
@@ -84,17 +84,16 @@ class Context(KeyedDefaultDict):
     this context instance. Keys in this dict are the strings representing keys
     in this context which are valid. Values are tuples of stored type,
     assigned type, default value, a docstring describing the purpose of the
     variable, and a tier indicator (see comment above the VARIABLES declaration
     in this module).
 
     config is the ConfigEnvironment for this context.
     """
-
     def __init__(self, allowed_variables={}, config=None, finder=None):
         self._allowed_variables = allowed_variables
         self.main_path = None
         self.current_path = None
         # There aren't going to be enough paths for the performance of scanning
         # a list to be a problem.
         self._all_paths = []
         self.config = config
@@ -159,17 +158,17 @@ class Context(KeyedDefaultDict):
 
     @memoized_property
     def objdir(self):
         return mozpath.join(self.config.topobjdir, self.relobjdir).rstrip('/')
 
     @memoize
     def _srcdir(self, path):
         return mozpath.join(self.config.topsrcdir,
-                            self._relsrcdir(path)).rstrip('/')
+            self._relsrcdir(path)).rstrip('/')
 
     @property
     def srcdir(self):
         return self._srcdir(self.current_path or self.main_path)
 
     @memoize
     def _relsrcdir(self, path):
         return mozpath.relpath(mozpath.dirname(path), self.config.topsrcdir)
@@ -178,17 +177,17 @@ class Context(KeyedDefaultDict):
     def relsrcdir(self):
         assert self.main_path
         return self._relsrcdir(self.current_path or self.main_path)
 
     @memoized_property
     def relobjdir(self):
         assert self.main_path
         return mozpath.relpath(mozpath.dirname(self.main_path),
-                               self.config.topsrcdir)
+            self.config.topsrcdir)
 
     def _factory(self, key):
         """Function called when requesting a missing key."""
         defaults = self._allowed_variables.get(key)
         if not defaults:
             raise KeyError('global_ns', 'get_unknown', key)
 
         # If the default is specifically a lambda (or, rather, any function
@@ -265,17 +264,16 @@ class TemplateContext(Context):
 class SubContext(Context, ContextDerivedValue):
     """A Context derived from another Context.
 
     Sub-contexts are intended to be used as context managers.
 
     Sub-contexts inherit paths and other relevant state from the parent
     context.
     """
-
     def __init__(self, parent):
         assert isinstance(parent, Context)
 
         Context.__init__(self, allowed_variables=self.VARIABLES,
                          config=parent.config)
 
         # Copy state from parent.
         for p in parent.source_stack:
@@ -567,17 +565,16 @@ class PathMeta(type):
             if value.startswith('!'):
                 cls = ObjDirPath
             elif value.startswith('%'):
                 cls = AbsolutePath
             else:
                 cls = SourcePath
         return super(PathMeta, cls).__call__(context, value)
 
-
 class Path(ContextDerivedValue, unicode):
     """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.
     It expresses paths relative to a context. Supported paths are:
       - '/topsrcdir/relative/paths'
       - 'srcdir/relative/paths'
       - '!/topobjdir/relative/paths'
@@ -634,17 +631,16 @@ class Path(ContextDerivedValue, unicode)
 
     @memoized_property
     def target_basename(self):
         return mozpath.basename(self.full_path)
 
 
 class SourcePath(Path):
     """Like Path, but limited to paths in the source directory."""
-
     def __init__(self, context, value):
         if value.startswith('!'):
             raise ValueError('Object directory paths are not allowed')
         if value.startswith('%'):
             raise ValueError('Filesystem absolute paths are not allowed')
         super(SourcePath, self).__init__(context, value)
 
         if value.startswith('/'):
@@ -675,74 +671,69 @@ class SourcePath(Path):
 class RenamedSourcePath(SourcePath):
     """Like SourcePath, but with a different base name when installed.
 
     The constructor takes a tuple of (source, target_basename).
 
     This class is not meant to be exposed to moz.build sandboxes as of now,
     and is not supported by the RecursiveMake backend.
     """
-
     def __init__(self, context, value):
         assert isinstance(value, tuple)
         source, self._target_basename = value
         super(RenamedSourcePath, self).__init__(context, source)
 
     @property
     def target_basename(self):
         return self._target_basename
 
 
 class ObjDirPath(Path):
     """Like Path, but limited to paths in the object directory."""
-
     def __init__(self, context, value=None):
         if not value.startswith('!'):
             raise ValueError('Object directory paths must start with ! prefix')
         super(ObjDirPath, self).__init__(context, value)
 
         if value.startswith('!/'):
-            path = mozpath.join(context.config.topobjdir, value[2:])
+            path = mozpath.join(context.config.topobjdir,value[2:])
         else:
             path = mozpath.join(context.objdir, value[1:])
         self.full_path = mozpath.normpath(path)
 
 
 class AbsolutePath(Path):
     """Like Path, but allows arbitrary paths outside the source and object directories."""
-
     def __init__(self, context, value=None):
         if not value.startswith('%'):
             raise ValueError('Absolute paths must start with % prefix')
         if not os.path.isabs(value[1:]):
             raise ValueError('Path \'%s\' is not absolute' % value[1:])
         super(AbsolutePath, self).__init__(context, value)
 
         self.full_path = mozpath.normpath(value[1:])
 
 
 @memoize
 def ContextDerivedTypedList(klass, base_class=List):
     """Specialized TypedList for use with ContextDerivedValue types.
     """
     assert issubclass(klass, ContextDerivedValue)
-
     class _TypedList(ContextDerivedValue, TypedList(klass, base_class)):
         def __init__(self, context, iterable=[], **kwargs):
             self.context = context
             super(_TypedList, self).__init__(iterable, **kwargs)
 
         def normalize(self, e):
             if not isinstance(e, klass):
                 e = klass(self.context, e)
             return e
 
     return _TypedList
 
-
 @memoize
 def ContextDerivedTypedListWithItems(type, base_class=List):
     """Specialized TypedList for use with ContextDerivedValue types.
     """
     class _TypedListWithItems(ContextDerivedTypedList(type, base_class)):
         def __getitem__(self, name):
             name = self.normalize(name)
             return super(_TypedListWithItems, self).__getitem__(name)
@@ -866,63 +857,60 @@ def ContextDerivedTypedHierarchicalStrin
             child = self._children.get(name)
             if not child:
                 child = self._children[name] = _TypedListWithItems(
                     self._context)
             return child
 
     return _TypedListWithItems
 
-
 def OrderedPathListWithAction(action):
     """Returns a class which behaves as a StrictOrderingOnAppendList, but
     invokes the given callable with each input and a context as it is
     read, storing a tuple including the result and the original item.
 
     This used to extend moz.build reading to make more data available in
     filesystem-reading mode.
     """
     class _OrderedListWithAction(ContextDerivedTypedList(SourcePath,
-                                                         StrictOrderingOnAppendListWithAction)):
+                                 StrictOrderingOnAppendListWithAction)):
         def __init__(self, context, *args):
             def _action(item):
                 return item, action(context, item)
             super(_OrderedListWithAction, self).__init__(context, action=_action, *args)
 
     return _OrderedListWithAction
 
-
 def TypedListWithAction(typ, action):
     """Returns a class which behaves as a TypedList with the provided type, but
     invokes the given given callable with each input and a context as it is
     read, storing a tuple including the result and the original item.
 
     This used to extend moz.build reading to make more data available in
     filesystem-reading mode.
     """
     class _TypedListWithAction(ContextDerivedValue, TypedList(typ), ListWithAction):
         def __init__(self, context, *args):
             def _action(item):
                 return item, action(context, item)
             super(_TypedListWithAction, self).__init__(action=_action, *args)
     return _TypedListWithAction
 
-
 ManifestparserManifestList = OrderedPathListWithAction(read_manifestparser_manifest)
 ReftestManifestList = OrderedPathListWithAction(read_reftest_manifest)
 
 OrderedSourceList = ContextDerivedTypedList(SourcePath, StrictOrderingOnAppendList)
 OrderedTestFlavorList = TypedList(Enum(*all_test_flavors()),
                                   StrictOrderingOnAppendList)
 OrderedStringList = TypedList(unicode, StrictOrderingOnAppendList)
 DependentTestsEntry = ContextDerivedTypedRecord(('files', OrderedSourceList),
                                                 ('tags', OrderedStringList),
                                                 ('flavors', OrderedTestFlavorList))
 BugzillaComponent = TypedNamedTuple('BugzillaComponent',
-                                    [('product', unicode), ('component', unicode)])
+                        [('product', unicode), ('component', unicode)])
 SchedulingComponents = ContextDerivedTypedRecord(
         ('inclusive', TypedList(unicode, StrictOrderingOnAppendList)),
         ('exclusive', TypedList(unicode, StrictOrderingOnAppendList)))
 
 GeneratedFilesList = StrictOrderingOnAppendListWithFlagsFactory({
     'script': unicode,
     'inputs': list,
     'force': bool,
@@ -972,38 +960,38 @@ class Files(SubContext):
     The difference in behavior between ``*`` and ``**`` is only evident if
     a pattern follows the ``*`` or ``**``. A pattern ending with ``*`` is
     greedy. ``**`` is needed when you need an additional pattern after the
     wildcard. e.g. ``**/foo``.
     """
 
     VARIABLES = {
         'BUG_COMPONENT': (BugzillaComponent, tuple,
-                          """The bug component that tracks changes to these files.
+            """The bug component that tracks changes to these files.
 
             Values are a 2-tuple of unicode describing the Bugzilla product and
             component. e.g. ``('Firefox Build System', 'General')``.
             """),
 
         'FINAL': (bool, bool,
-                  """Mark variable assignments as finalized.
+            """Mark variable assignments as finalized.
 
             During normal processing, values from newer Files contexts
             overwrite previously set values. Last write wins. This behavior is
             not always desired. ``FINAL`` provides a mechanism to prevent
             further updates to a variable.
 
             When ``FINAL`` is set, the value of all variables defined in this
             context are marked as frozen and all subsequent writes to them
             are ignored during metadata reading.
 
             See :ref:`mozbuild_files_metadata_finalizing` for more info.
             """),
         'IMPACTED_TESTS': (DependentTestsEntry, list,
-                           """File patterns, tags, and flavors for tests relevant to these files.
+            """File patterns, tags, and flavors for tests relevant to these files.
 
             Maps source files to the tests potentially impacted by those files.
             Tests can be specified by file pattern, tag, or flavor.
 
             For example:
 
             with Files('runtests.py'):
                IMPACTED_TESTS.files += [
@@ -1041,17 +1029,17 @@ class Files(SubContext):
                 IMPACTED_TESTS.flavors += [
                     'mochitest',
                 ]
 
             Would suggest that nsGlobalWindow.cpp is potentially relevant to
             any plain mochitest.
             """),
         'SCHEDULES': (Schedules, list,
-                      """Maps source files to the CI tasks that should be scheduled when
+            """Maps source files to the CI tasks that should be scheduled when
             they change.  The tasks are grouped by named components, and those
             names appear again in the taskgraph configuration
             `($topsrcdir/taskgraph/).
 
             Some components are "inclusive", meaning that changes to most files
             do not schedule them, aside from those described in a Files
             subcontext.  For example, py-lint tasks need not be scheduled for
             most changes, but should be scheduled when any Python file changes.
@@ -1196,115 +1184,76 @@ SUBCONTEXTS = {cls.__name__: cls for cls
 
 # This defines the set of mutable global variables.
 #
 # Each variable is a tuple of:
 #
 #   (storage_type, input_types, docs)
 
 VARIABLES = {
-    'SOURCES': (
-        ContextDerivedTypedListWithItems(
-            Path,
-            StrictOrderingOnAppendListWithFlagsFactory(
-                {'no_pgo': bool,
-                 'flags': List,
-                 'pgo_generate_only': bool
-                 }
-                )
-            ),
-        list,
+    'SOURCES': (ContextDerivedTypedListWithItems(Path, StrictOrderingOnAppendListWithFlagsFactory({'no_pgo': bool, 'flags': List, 'pgo_generate_only': bool})), list,
         """Source code files.
 
         This variable contains a list of source code files to compile.
         Accepts assembler, C, C++, Objective C/C++.
-        """
-        ),
-
-    'FILES_PER_UNIFIED_FILE': (
-        int,
-        int,
+        """),
+
+    'FILES_PER_UNIFIED_FILE': (int, int,
         """The number of source files to compile into each unified source file.
 
-        """
-        ),
-
-    'IS_RUST_LIBRARY': (
-        bool,
-        bool,
+        """),
+
+    'IS_RUST_LIBRARY': (bool, bool,
         """Whether the current library defined by this moz.build is built by Rust.
 
         The library defined by this moz.build should have a build definition in
         a Cargo.toml file that exists in this moz.build's directory.
-        """
-        ),
-
-    'RUST_LIBRARY_FEATURES': (
-        List,
-        list,
+        """),
+
+    'RUST_LIBRARY_FEATURES': (List, list,
         """Cargo features to activate for this library.
 
         This variable should not be used directly; you should be using the
         RustLibrary template instead.
-        """
-        ),
-
-    'RUST_LIBRARY_TARGET_DIR': (
-        unicode,
-        unicode,
+        """),
+
+    'RUST_LIBRARY_TARGET_DIR': (unicode, unicode,
         """Where CARGO_TARGET_DIR should point when compiling this library.  If
         not set, it defaults to the current objdir.  It should be a relative path
         to the current objdir; absolute paths should not be used.
 
         This variable should not be used directly; you should be using the
         RustLibrary template instead.
-        """
-        ),
-
-    'HOST_RUST_LIBRARY_FEATURES': (
-        List,
-        list,
+        """),
+
+    'HOST_RUST_LIBRARY_FEATURES': (List, list,
         """Cargo features to activate for this host library.
 
         This variable should not be used directly; you should be using the
         HostRustLibrary template instead.
-        """
-        ),
-
-    'RUST_TESTS': (
-        TypedList(unicode),
-        list,
+        """),
+
+    'RUST_TESTS': (TypedList(unicode), list,
         """Names of Rust tests to build and run via `cargo test`.
         """),
 
-    'RUST_TEST_FEATURES': (
-        TypedList(unicode),
-        list,
+    'RUST_TEST_FEATURES': (TypedList(unicode), list,
         """Cargo features to activate for RUST_TESTS.
-        """
-        ),
-
-    'UNIFIED_SOURCES': (
-        ContextDerivedTypedList(
-            SourcePath,
-            StrictOrderingOnAppendList
-            ),
-        list,
+        """),
+
+    'UNIFIED_SOURCES': (ContextDerivedTypedList(SourcePath, StrictOrderingOnAppendList), list,
         """Source code files that can be compiled together.
 
         This variable contains a list of source code files to compile,
         that can be concatenated all together and built as a single source
         file. This can help make the build faster and reduce the debug info
         size.
-        """
-        ),
-
-    'GENERATED_FILES': (
-        GeneratedFilesList,
-        list,
+        """),
+
+    'GENERATED_FILES': (GeneratedFilesList, list,
         """Generic generated files.
 
         This variable contains a list of files for the build system to
         generate at export time. The generation method may be declared
         with optional ``script``, ``inputs``, ``flags``, and ``force``
         attributes on individual entries.
         If the optional ``script`` attribute is not present on an entry, it
         is assumed that rules for generating the file are present in
@@ -1343,22 +1292,19 @@ VARIABLES = {
 
         When the ``flags`` attribute is present, the given list of flags is
         passed as extra arguments following the inputs.
 
         When the ``force`` attribute is present, the file is generated every
         build, regardless of whether it is stale.  This is special to the
         RecursiveMake backend and intended for special situations only (e.g.,
         localization).  Please consult a build peer before using ``force``.
-        """
-        ),
-
-    'DEFINES': (
-        InitializedDefines,
-        dict,
+        """),
+
+    'DEFINES': (InitializedDefines, dict,
         """Dictionary of compiler defines to declare.
 
         These are passed in to the compiler as ``-Dkey='value'`` for string
         values, ``-Dkey=value`` for numeric values, or ``-Dkey`` if the
         value is True. Note that for string values, the outer-level of
         single-quotes will be consumed by the shell. If you want to have
         a string-literal in the program, the value needs to have
         double-quotes.
@@ -1374,86 +1320,76 @@ VARIABLES = {
         respectively. These could also be combined into a single
         update::
 
            DEFINES.update({
                'NS_NO_XPCOM': True,
                'MOZ_EXTENSIONS_DB_SCHEMA': 15,
                'DLL_SUFFIX': '".so"',
            })
-        """
-        ),
-
-    'DELAYLOAD_DLLS': (
-        List,
-        list,
+        """),
+
+    'DELAYLOAD_DLLS': (List, list,
         """Delay-loaded DLLs.
 
         This variable contains a list of DLL files which the module being linked
         should load lazily.  This only has an effect when building with MSVC.
-        """
-        ),
-
-    'DIRS': (
-        ContextDerivedTypedList(SourcePath),
-        list,
+        """),
+
+    'DIRS': (ContextDerivedTypedList(SourcePath), list,
         """Child directories to descend into looking for build frontend files.
 
         This works similarly to the ``DIRS`` variable in make files. Each str
         value in the list is the name of a child directory. When this file is
         done parsing, the build reader will descend into each listed directory
         and read the frontend file there. If there is no frontend file, an error
         is raised.
 
         Values are relative paths. They can be multiple directory levels
         above or below. Use ``..`` for parent directories and ``/`` for path
         delimiters.
-        """
-        ),
-
-    'HAS_MISC_RULE': (
-        bool,
-        bool,
+        """),
+
+    'HAS_MISC_RULE': (bool, bool,
         """Whether this directory should be traversed in the ``misc`` tier.
 
         Many ``libs`` rules still exist in Makefile.in files. We highly prefer
         that these rules exist in the ``misc`` tier/target so that they can be
         executed concurrently during tier traversal (the ``misc`` tier is
         fully concurrent).
 
         Presence of this variable indicates that this directory should be
         traversed by the ``misc`` tier.
 
         Please note that converting ``libs`` rules to the ``misc`` tier must
         be done with care, as there are many implicit dependencies that can
         break the build in subtle ways.
-        """
-        ),
+        """),
 
     'FINAL_TARGET_FILES': (ContextDerivedTypedHierarchicalStringList(Path), list,
-                           """List of files to be installed into the application directory.
+        """List of files to be installed into the application directory.
 
         ``FINAL_TARGET_FILES`` will copy (or symlink, if the platform supports it)
         the contents of its files to the directory specified by
         ``FINAL_TARGET`` (typically ``dist/bin``). Files that are destined for a
         subdirectory can be specified by accessing a field, or as a dict access.
         For example, to export ``foo.png`` to the top-level directory and
         ``bar.svg`` to the directory ``images/do-not-use``, append to
         ``FINAL_TARGET_FILES`` like so::
 
            FINAL_TARGET_FILES += ['foo.png']
            FINAL_TARGET_FILES.images['do-not-use'] += ['bar.svg']
         """),
 
     'FINAL_TARGET_PP_FILES': (ContextDerivedTypedHierarchicalStringList(Path), list,
-                              """Like ``FINAL_TARGET_FILES``, with preprocessing.
+        """Like ``FINAL_TARGET_FILES``, with preprocessing.
         """),
 
     'LOCALIZED_FILES': (ContextDerivedTypedHierarchicalStringList(Path), list,
-                        """List of locale-dependent files to be installed into the application
+        """List of locale-dependent files to be installed into the application
         directory.
 
         This functions similarly to ``FINAL_TARGET_FILES``, but the files are
         sourced from the locale directory and will vary per localization.
         For an en-US build, this is functionally equivalent to
         ``FINAL_TARGET_FILES``. For a build with ``--enable-ui-locale``,
         the file will be taken from ``$LOCALE_SRCDIR``, with the leading
         ``en-US`` removed. For a l10n repack of an en-US build, the file
@@ -1485,24 +1421,24 @@ VARIABLES = {
         ``toolkit/locales/en-US/foo.js`` and
         ``toolkit/locales/en-US/things/*.ini`` to ``$(DIST)/bin/foo`` in an
         en-US build, and in a build of a different locale (or a repack),
         it would copy ``$(LOCALE_SRCDIR)/toolkit/foo.js`` and
         ``$(LOCALE_SRCDIR)/toolkit/things/*.ini``.
         """),
 
     'LOCALIZED_PP_FILES': (ContextDerivedTypedHierarchicalStringList(Path), list,
-                           """Like ``LOCALIZED_FILES``, with preprocessing.
+        """Like ``LOCALIZED_FILES``, with preprocessing.
 
         Note that the ``AB_CD`` define is available and expands to the current
         locale being packaged, as with preprocessed entries in jar manifests.
         """),
 
     'LOCALIZED_GENERATED_FILES': (GeneratedFilesList, list,
-                                  """Like ``GENERATED_FILES``, but for files whose content varies based on the locale in use.
+        """Like ``GENERATED_FILES``, but for files whose content varies based on the locale in use.
 
         For simple cases of text substitution, prefer ``LOCALIZED_PP_FILES``.
 
         Refer to the documentation of ``GENERATED_FILES``; for the most part things work the same.
         The two major differences are:
         1. The function in the Python script will be passed an additional keyword argument `locale`
            which provides the locale in use, i.e. ``en-US``.
         2. The ``inputs`` list may contain paths to files that will be taken from the locale
@@ -1516,260 +1452,248 @@ VARIABLES = {
         In addition, ``LOCALIZED_GENERATED_FILES`` can use the special substitutions ``{AB_CD}``
         and ``{AB_rCD}`` in their output paths.  ``{AB_CD}`` expands to the current locale during
         multi-locale builds and single-locale repacks and ``{AB_rCD}`` expands to an
         Android-specific encoding of the current locale.  Both expand to the empty string when the
         current locale is ``en-US``.
         """),
 
     'OBJDIR_FILES': (ContextDerivedTypedHierarchicalStringList(Path), list,
-                     """List of files to be installed anywhere in the objdir. Use sparingly.
+        """List of files to be installed anywhere in the objdir. Use sparingly.
 
         ``OBJDIR_FILES`` is similar to FINAL_TARGET_FILES, but it allows copying
         anywhere in the object directory. This is intended for various one-off
         cases, not for general use. If you wish to add entries to OBJDIR_FILES,
         please consult a build peer.
         """),
 
     'OBJDIR_PP_FILES': (ContextDerivedTypedHierarchicalStringList(Path), list,
-                        """Like ``OBJDIR_FILES``, with preprocessing. Use sparingly.
+        """Like ``OBJDIR_FILES``, with preprocessing. Use sparingly.
         """),
 
     'FINAL_LIBRARY': (unicode, unicode,
-                      """Library in which the objects of the current directory will be linked.
+        """Library in which the objects of the current directory will be linked.
 
         This variable contains the name of a library, defined elsewhere with
         ``LIBRARY_NAME``, in which the objects of the current directory will be
         linked.
         """),
 
     'CPP_UNIT_TESTS': (StrictOrderingOnAppendList, list,
-                       """Compile a list of C++ unit test names.
+        """Compile a list of C++ unit test names.
 
         Each name in this variable corresponds to an executable built from the
         corresponding source file with the same base name.
 
         If the configuration token ``BIN_SUFFIX`` is set, its value will be
         automatically appended to each name. If a name already ends with
         ``BIN_SUFFIX``, the name will remain unchanged.
         """),
 
     'FORCE_SHARED_LIB': (bool, bool,
-                         """Whether the library in this directory is a shared library.
+        """Whether the library in this directory is a shared library.
         """),
 
     'FORCE_STATIC_LIB': (bool, bool,
-                         """Whether the library in this directory is a static library.
+        """Whether the library in this directory is a static library.
         """),
 
     'USE_STATIC_LIBS': (bool, bool,
-                        """Whether the code in this directory is a built against the static
+        """Whether the code in this directory is a built against the static
         runtime library.
 
         This variable only has an effect when building with MSVC.
         """),
 
     'HOST_SOURCES': (ContextDerivedTypedList(Path, StrictOrderingOnAppendList), list,
-                     """Source code files to compile with the host compiler.
+        """Source code files to compile with the host compiler.
 
         This variable contains a list of source code files to compile.
         with the host compiler.
         """),
 
     'HOST_LIBRARY_NAME': (unicode, unicode,
-                          """Name of target library generated when cross compiling.
+        """Name of target library generated when cross compiling.
         """),
 
     'LIBRARY_DEFINES': (OrderedDict, dict,
-                        """Dictionary of compiler defines to declare for the entire library.
+        """Dictionary of compiler defines to declare for the entire library.
 
         This variable works like DEFINES, except that declarations apply to all
         libraries that link into this library via FINAL_LIBRARY.
         """),
 
     'LIBRARY_NAME': (unicode, unicode,
-                     """The code name of the library generated for a directory.
+        """The code name of the library generated for a directory.
 
         By default STATIC_LIBRARY_NAME and SHARED_LIBRARY_NAME take this name.
         In ``example/components/moz.build``,::
 
            LIBRARY_NAME = 'xpcomsample'
 
         would generate ``example/components/libxpcomsample.so`` on Linux, or
         ``example/components/xpcomsample.lib`` on Windows.
         """),
 
     'SHARED_LIBRARY_NAME': (unicode, unicode,
-                            """The name of the static library generated for a directory, if it needs to
+        """The name of the static library generated for a directory, if it needs to
         differ from the library code name.
 
         Implies FORCE_SHARED_LIB.
         """),
 
     'SHARED_LIBRARY_OUTPUT_CATEGORY': (unicode, unicode,
-                                       """The output category for this context's shared library. If set this will
+        """The output category for this context's shared library. If set this will
         correspond to the build command that will build this shared library, and
         the library will not be built as part of the default build.
         """),
 
     'RUST_LIBRARY_OUTPUT_CATEGORY': (unicode, unicode,
-                                     """The output category for this context's rust library. If set this will
+        """The output category for this context's rust library. If set this will
         correspond to the build command that will build this rust library, and
         the library will not be built as part of the default build.
         """),
 
     'IS_FRAMEWORK': (bool, bool,
-                     """Whether the library to build should be built as a framework on OSX.
+        """Whether the library to build should be built as a framework on OSX.
 
         This implies the name of the library won't be prefixed nor suffixed.
         Implies FORCE_SHARED_LIB.
         """),
 
     'STATIC_LIBRARY_NAME': (unicode, unicode,
-                            """The name of the static library generated for a directory, if it needs to
+        """The name of the static library generated for a directory, if it needs to
         differ from the library code name.
 
         Implies FORCE_STATIC_LIB.
         """),
 
     'USE_LIBS': (StrictOrderingOnAppendList, list,
-                 """List of libraries to link to programs and libraries.
+        """List of libraries to link to programs and libraries.
         """),
 
     'HOST_USE_LIBS': (StrictOrderingOnAppendList, list,
-                      """List of libraries to link to host programs and libraries.
+        """List of libraries to link to host programs and libraries.
         """),
 
     'HOST_OS_LIBS': (List, list,
-                     """List of system libraries for host programs and libraries.
+        """List of system libraries for host programs and libraries.
         """),
 
     'LOCAL_INCLUDES': (ContextDerivedTypedList(Path, StrictOrderingOnAppendList), list,
-                       """Additional directories to be searched for include files by the compiler.
+        """Additional directories to be searched for include files by the compiler.
         """),
 
     'NO_PGO': (bool, bool,
-               """Whether profile-guided optimization is disable in this directory.
+        """Whether profile-guided optimization is disable in this directory.
         """),
 
     'OS_LIBS': (List, list,
-                """System link libraries.
+        """System link libraries.
 
         This variable contains a list of system libaries to link against.
         """),
     'RCFILE': (unicode, unicode,
-               """The program .rc file.
+        """The program .rc file.
 
         This variable can only be used on Windows.
         """),
 
     'RESFILE': (unicode, unicode,
-                """The program .res file.
+        """The program .res file.
 
         This variable can only be used on Windows.
         """),
 
     'RCINCLUDE': (unicode, unicode,
-                  """The resource script file to be included in the default .res file.
+        """The resource script file to be included in the default .res file.
 
         This variable can only be used on Windows.
         """),
 
     'DEFFILE': (Path, unicode,
-                """The program .def (module definition) file.
+        """The program .def (module definition) file.
 
         This variable can only be used on Windows.
         """),
 
     'SYMBOLS_FILE': (Path, unicode,
-                     """A file containing a list of symbols to export from a shared library.
+        """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
         preprocessed.
         A special marker "@DATA@" must be added after a symbol name if it
         points to data instead of code, so that the Windows linker can treat
         them correctly.
         """),
 
     'SIMPLE_PROGRAMS': (StrictOrderingOnAppendList, list,
-                        """Compile a list of executable names.
+        """Compile a list of executable names.
 
         Each name in this variable corresponds to an executable built from the
         corresponding source file with the same base name.
 
         If the configuration token ``BIN_SUFFIX`` is set, its value will be
         automatically appended to each name. If a name already ends with
         ``BIN_SUFFIX``, the name will remain unchanged.
         """),
 
     'SONAME': (unicode, unicode,
-               """The soname of the shared object currently being linked
+        """The soname of the shared object currently being linked
 
         soname is the "logical name" of a shared object, often used to provide
         version backwards compatibility. This variable makes sense only for
         shared objects, and is supported only on some unix platforms.
         """),
 
     'HOST_SIMPLE_PROGRAMS': (StrictOrderingOnAppendList, list,
-                             """Compile a list of host executable names.
+        """Compile a list of host executable names.
 
         Each name in this variable corresponds to a hosst executable built
         from the corresponding source file with the same base name.
 
         If the configuration token ``HOST_BIN_SUFFIX`` is set, its value will
         be automatically appended to each name. If a name already ends with
         ``HOST_BIN_SUFFIX``, the name will remain unchanged.
         """),
 
     'RUST_PROGRAMS': (StrictOrderingOnAppendList, list,
-                      """Compile a list of Rust host executable names.
+        """Compile a list of Rust host executable names.
 
         Each name in this variable corresponds to an executable built from
         the Cargo.toml in the same directory.
         """),
 
     'HOST_RUST_PROGRAMS': (StrictOrderingOnAppendList, list,
-                           """Compile a list of Rust executable names.
+        """Compile a list of Rust executable names.
 
         Each name in this variable corresponds to an executable built from
         the Cargo.toml in the same directory.
         """),
 
-    'CONFIGURE_SUBST_FILES': (
-        ContextDerivedTypedList(
-            SourcePath,
-            StrictOrderingOnAppendList
-            ),
-        list,
+    'CONFIGURE_SUBST_FILES': (ContextDerivedTypedList(SourcePath, StrictOrderingOnAppendList), list,
         """Output files that will be generated using configure-like substitution.
 
         This is a substitute for ``AC_OUTPUT`` in autoconf. For each path in this
         list, we will search for a file in the srcdir having the name
         ``{path}.in``. The contents of this file will be read and variable
         patterns like ``@foo@`` will be substituted with the values of the
         ``AC_SUBST`` variables declared during configure.
-        """
-        ),
-
-    'CONFIGURE_DEFINE_FILES': (
-        ContextDerivedTypedList(
-            SourcePath,
-            StrictOrderingOnAppendList
-            ),
-        list,
+        """),
+
+    'CONFIGURE_DEFINE_FILES': (ContextDerivedTypedList(SourcePath, StrictOrderingOnAppendList), list,
         """Output files generated from configure/config.status.
 
         This is a substitute for ``AC_CONFIG_HEADER`` in autoconf. This is very
         similar to ``CONFIGURE_SUBST_FILES`` except the generation logic takes
         into account the values of ``AC_DEFINE`` instead of ``AC_SUBST``.
-        """
-        ),
+        """),
 
     'EXPORTS': (ContextDerivedTypedHierarchicalStringList(Path), list,
-                """List of files to be exported, and in which subdirectories.
+        """List of files to be exported, and in which subdirectories.
 
         ``EXPORTS`` is generally used to list the include files to be exported to
         ``dist/include``, but it can be used for other files as well. This variable
         behaves as a list when appending filenames for export in the top-level
         directory. Files can also be appended to a field to indicate which
         subdirectory they should be exported to. For example, to export
         ``foo.h`` to the top-level directory, and ``bar.h`` to ``mozilla/dom/``,
         append to ``EXPORTS`` like so::
@@ -1777,251 +1701,247 @@ VARIABLES = {
            EXPORTS += ['foo.h']
            EXPORTS.mozilla.dom += ['bar.h']
 
         Entries in ``EXPORTS`` are paths, so objdir paths may be used, but
         any files listed from the objdir must also be listed in
         ``GENERATED_FILES``.
         """),
 
-    'PROGRAM': (unicode, unicode,
-                """Compiled executable name.
+    'PROGRAM' : (unicode, unicode,
+        """Compiled executable name.
 
         If the configuration token ``BIN_SUFFIX`` is set, its value will be
         automatically appended to ``PROGRAM``. If ``PROGRAM`` already ends with
         ``BIN_SUFFIX``, ``PROGRAM`` will remain unchanged.
         """),
 
-    'HOST_PROGRAM': (unicode, unicode,
-                     """Compiled host executable name.
+    'HOST_PROGRAM' : (unicode, unicode,
+        """Compiled host executable name.
 
         If the configuration token ``HOST_BIN_SUFFIX`` is set, its value will be
         automatically appended to ``HOST_PROGRAM``. If ``HOST_PROGRAM`` already
         ends with ``HOST_BIN_SUFFIX``, ``HOST_PROGRAM`` will remain unchanged.
         """),
 
     'DIST_INSTALL': (Enum(None, False, True), bool,
-                     """Whether to install certain files into the dist directory.
+        """Whether to install certain files into the dist directory.
 
         By default, some files types are installed in the dist directory, and
         some aren't. Set this variable to True to force the installation of
         some files that wouldn't be installed by default. Set this variable to
         False to force to not install some files that would be installed by
         default.
 
         This is confusing for historical reasons, but eventually, the behavior
         will be made explicit.
         """),
 
     'JAR_MANIFESTS': (ContextDerivedTypedList(SourcePath, StrictOrderingOnAppendList), list,
-                      """JAR manifest files that should be processed as part of the build.
+        """JAR manifest files that should be processed as part of the build.
 
         JAR manifests are files in the tree that define how to package files
         into JARs and how chrome registration is performed. For more info,
         see :ref:`jar_manifests`.
         """),
 
     # IDL Generation.
     'XPIDL_SOURCES': (ContextDerivedTypedList(SourcePath, StrictOrderingOnAppendList), list,
-                      """XPCOM Interface Definition Files (xpidl).
+        """XPCOM Interface Definition Files (xpidl).
 
         This is a list of files that define XPCOM interface definitions.
         Entries must be files that exist. Entries are almost certainly ``.idl``
         files.
         """),
 
     'XPIDL_MODULE': (unicode, unicode,
-                     """XPCOM Interface Definition Module Name.
+        """XPCOM Interface Definition Module Name.
 
         This is the name of the ``.xpt`` file that is created by linking
         ``XPIDL_SOURCES`` together. If unspecified, it defaults to be the same
         as ``MODULE``.
         """),
 
     'XPCOM_MANIFESTS': (ContextDerivedTypedList(SourcePath, StrictOrderingOnAppendList), list,
-                        """XPCOM Component Manifest Files.
+        """XPCOM Component Manifest Files.
 
         This is a list of files that define XPCOM components to be added
         to the component registry.
         """),
 
     'PREPROCESSED_IPDL_SOURCES': (StrictOrderingOnAppendList, list,
-                                  """Preprocessed IPDL source files.
+        """Preprocessed IPDL source files.
 
         These files will be preprocessed, then parsed and converted to
         ``.cpp`` files.
         """),
 
     'IPDL_SOURCES': (StrictOrderingOnAppendList, list,
-                     """IPDL source files.
+        """IPDL source files.
 
         These are ``.ipdl`` files that will be parsed and converted to
         ``.cpp`` files.
         """),
 
     'WEBIDL_FILES': (StrictOrderingOnAppendList, list,
-                     """WebIDL source files.
+        """WebIDL source files.
 
         These will be parsed and converted to ``.cpp`` and ``.h`` files.
         """),
 
     'GENERATED_EVENTS_WEBIDL_FILES': (StrictOrderingOnAppendList, list,
-                                      """WebIDL source files for generated events.
+        """WebIDL source files for generated events.
 
         These will be parsed and converted to ``.cpp`` and ``.h`` files.
         """),
 
     'TEST_WEBIDL_FILES': (StrictOrderingOnAppendList, list,
-                          """Test WebIDL source files.
+         """Test WebIDL source files.
 
          These will be parsed and converted to ``.cpp`` and ``.h`` files
          if tests are enabled.
          """),
 
     'GENERATED_WEBIDL_FILES': (StrictOrderingOnAppendList, list,
-                               """Generated WebIDL source files.
+         """Generated WebIDL source files.
 
          These will be generated from some other files.
          """),
 
     'PREPROCESSED_TEST_WEBIDL_FILES': (StrictOrderingOnAppendList, list,
-                                       """Preprocessed test WebIDL source files.
+         """Preprocessed test WebIDL source files.
 
          These will be preprocessed, then parsed and converted to .cpp
          and ``.h`` files if tests are enabled.
          """),
 
     'PREPROCESSED_WEBIDL_FILES': (StrictOrderingOnAppendList, list,
-                                  """Preprocessed WebIDL source files.
+         """Preprocessed WebIDL source files.
 
          These will be preprocessed before being parsed and converted.
          """),
 
     'WEBIDL_EXAMPLE_INTERFACES': (StrictOrderingOnAppendList, list,
-                                  """Names of example WebIDL interfaces to build as part of the build.
+        """Names of example WebIDL interfaces to build as part of the build.
 
         Names in this list correspond to WebIDL interface names defined in
         WebIDL files included in the build from one of the \*WEBIDL_FILES
         variables.
         """),
 
     # Test declaration.
     'A11Y_MANIFESTS': (ManifestparserManifestList, list,
-                       """List of manifest files defining a11y tests.
+        """List of manifest files defining a11y tests.
         """),
 
     'BROWSER_CHROME_MANIFESTS': (ManifestparserManifestList, list,
-                                 """List of manifest files defining browser chrome tests.
+        """List of manifest files defining browser chrome tests.
         """),
 
     'ANDROID_INSTRUMENTATION_MANIFESTS': (ManifestparserManifestList, list,
-                                          """List of manifest files defining Android instrumentation tests.
+        """List of manifest files defining Android instrumentation tests.
         """),
 
     'FIREFOX_UI_FUNCTIONAL_MANIFESTS': (ManifestparserManifestList, list,
-                                        """List of manifest files defining firefox-ui-functional tests.
+        """List of manifest files defining firefox-ui-functional tests.
         """),
 
     'FIREFOX_UI_UPDATE_MANIFESTS': (ManifestparserManifestList, list,
-                                    """List of manifest files defining firefox-ui-update tests.
+        """List of manifest files defining firefox-ui-update tests.
         """),
 
     'PUPPETEER_FIREFOX_MANIFESTS': (ManifestparserManifestList, list,
-                                    """List of manifest files defining puppeteer unit tests for Firefox.
+        """List of manifest files defining puppeteer unit tests for Firefox.
         """),
 
     'MARIONETTE_LAYOUT_MANIFESTS': (ManifestparserManifestList, list,
-                                    """List of manifest files defining marionette-layout tests.
+        """List of manifest files defining marionette-layout tests.
         """),
 
     'MARIONETTE_GPU_MANIFESTS': (ManifestparserManifestList, list,
-                                 """List of manifest files defining marionette-gpu tests.
+        """List of manifest files defining marionette-gpu tests.
         """),
 
     'MARIONETTE_UNIT_MANIFESTS': (ManifestparserManifestList, list,
-                                  """List of manifest files defining marionette-unit tests.
+        """List of manifest files defining marionette-unit tests.
         """),
 
     'METRO_CHROME_MANIFESTS': (ManifestparserManifestList, list,
-                               """List of manifest files defining metro browser chrome tests.
+        """List of manifest files defining metro browser chrome tests.
         """),
 
     'MOCHITEST_CHROME_MANIFESTS': (ManifestparserManifestList, list,
-                                   """List of manifest files defining mochitest chrome tests.
+        """List of manifest files defining mochitest chrome tests.
         """),
 
     'MARIONETTE_DOM_MEDIA_MANIFESTS': (ManifestparserManifestList, list,
-                                       """List of manifest files defining marionette-media tests.
+        """List of manifest files defining marionette-media tests.
         """),
 
     'MOCHITEST_MANIFESTS': (ManifestparserManifestList, list,
-                            """List of manifest files defining mochitest tests.
+        """List of manifest files defining mochitest tests.
         """),
 
     'REFTEST_MANIFESTS': (ReftestManifestList, list,
-                          """List of manifest files defining reftests.
+        """List of manifest files defining reftests.
 
         These are commonly named reftest.list.
         """),
 
     'CRASHTEST_MANIFESTS': (ReftestManifestList, list,
-                            """List of manifest files defining crashtests.
+        """List of manifest files defining crashtests.
 
         These are commonly named crashtests.list.
         """),
 
     'WEBRTC_SIGNALLING_TEST_MANIFESTS': (ManifestparserManifestList, list,
-                                         """List of manifest files defining WebRTC signalling tests.
+        """List of manifest files defining WebRTC signalling tests.
         """),
 
     'XPCSHELL_TESTS_MANIFESTS': (ManifestparserManifestList, list,
-                                 """List of manifest files defining xpcshell tests.
+        """List of manifest files defining xpcshell tests.
         """),
 
     'PYTHON_UNITTEST_MANIFESTS': (ManifestparserManifestList, list,
-                                  """List of manifest files defining python unit tests.
+        """List of manifest files defining python unit tests.
         """),
 
     'CRAMTEST_MANIFESTS': (ManifestparserManifestList, list,
-                           """List of manifest files defining cram unit tests.
-        """),
-
-    'TELEMETRY_TESTS_CLIENT_MANIFESTS': (ManifestparserManifestList, list,
-                                         """List of manifest files defining telemetry client tests.
+        """List of manifest files defining cram unit tests.
         """),
 
 
     # The following variables are used to control the target of installed files.
     'XPI_NAME': (unicode, unicode,
-                 """The name of an extension XPI to generate.
+        """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,
-                    """The name of an alternate directory to install files to.
+        """The name of an alternate directory to install files to.
 
         When this variable is present, the results of this directory will end up
         being placed in the $(DIST_SUBDIR) subdirectory of where it would
         otherwise be placed.
         """),
 
     'FINAL_TARGET': (FinalTargetValue, unicode,
-                     """The name of the directory to install targets to.
+        """The name of the directory to install targets to.
 
         The directory is relative to the top of the object directory. The
         default value is dependent on the values of XPI_NAME and DIST_SUBDIR. If
         neither are present, the result is dist/bin. If XPI_NAME is present, the
         result is dist/xpi-stage/$(XPI_NAME). If DIST_SUBDIR is present, then
         the $(DIST_SUBDIR) directory of the otherwise default value is used.
         """),
 
     'USE_EXTENSION_MANIFEST': (bool, bool,
-                               """Controls the name of the manifest for JAR files.
+        """Controls the name of the manifest for JAR files.
 
         By default, the name of the manifest is ${JAR_MANIFEST}.manifest.
         Setting this variable to ``True`` changes the name of the manifest to
         chrome.manifest.
         """),
 
     'GYP_DIRS': (StrictOrderingOnAppendListWithFlagsFactory({
             'variables': dict,
@@ -2081,204 +2001,204 @@ VARIABLES = {
               the current moz.build, that should be excluded from source file
               unification.
             - mozilla_flags, a set of flags that if present in the gn config
               will be mirrored to the resulting mozbuild configuration.
             - gn_target, the name of the target to build.
         """),
 
     'SPHINX_TREES': (dict, dict,
-                     """Describes what the Sphinx documentation tree will look like.
+        """Describes what the Sphinx documentation tree will look like.
 
         Keys are relative directories inside the final Sphinx documentation
         tree to install files into. Values are directories (relative to this
         file) whose content to copy into the Sphinx documentation tree.
         """),
 
     'SPHINX_PYTHON_PACKAGE_DIRS': (StrictOrderingOnAppendList, list,
-                                   """Directories containing Python packages that Sphinx documents.
+        """Directories containing Python packages that Sphinx documents.
         """),
 
     'COMPILE_FLAGS': (CompileFlags, dict,
-                      """Recipe for compile flags for this context. Not to be manipulated
+        """Recipe for compile flags for this context. Not to be manipulated
         directly.
         """),
 
     'LINK_FLAGS': (LinkFlags, dict,
-                   """Recipe for linker flags for this context. Not to be manipulated
+        """Recipe for linker flags for this context. Not to be manipulated
         directly.
         """),
 
     'ASM_FLAGS': (AsmFlags, dict,
-                  """Recipe for linker flags for this context. Not to be manipulated
+        """Recipe for linker flags for this context. Not to be manipulated
         directly.
         """),
 
     'CFLAGS': (List, list,
-               """Flags passed to the C compiler for all of the C source files
+        """Flags passed to the C compiler for all of the C source files
            declared in this directory.
 
            Note that the ordering of flags matters here, these flags will be
            added to the compiler's command line in the same order as they
            appear in the moz.build file.
         """),
 
     'CXXFLAGS': (List, list,
-                 """Flags passed to the C++ compiler for all of the C++ source files
+        """Flags passed to the C++ compiler for all of the C++ source files
            declared in this directory.
 
            Note that the ordering of flags matters here; these flags will be
            added to the compiler's command line in the same order as they
            appear in the moz.build file.
         """),
 
     'HOST_COMPILE_FLAGS': (HostCompileFlags, dict,
-                           """Recipe for host compile flags for this context. Not to be manipulated
+        """Recipe for host compile flags for this context. Not to be manipulated
         directly.
         """),
 
     'HOST_DEFINES': (InitializedDefines, dict,
-                     """Dictionary of compiler defines to declare for host compilation.
+        """Dictionary of compiler defines to declare for host compilation.
         See ``DEFINES`` for specifics.
         """),
 
     'CMFLAGS': (List, list,
-                """Flags passed to the Objective-C compiler for all of the Objective-C
+        """Flags passed to the Objective-C compiler for all of the Objective-C
            source files declared in this directory.
 
            Note that the ordering of flags matters here; these flags will be
            added to the compiler's command line in the same order as they
            appear in the moz.build file.
         """),
 
     'CMMFLAGS': (List, list,
-                 """Flags passed to the Objective-C++ compiler for all of the
+        """Flags passed to the Objective-C++ compiler for all of the
            Objective-C++ source files declared in this directory.
 
            Note that the ordering of flags matters here; these flags will be
            added to the compiler's command line in the same order as they
            appear in the moz.build file.
         """),
 
     'ASFLAGS': (List, list,
-                """Flags passed to the assembler for all of the assembly source files
+        """Flags passed to the assembler for all of the assembly source files
            declared in this directory.
 
            Note that the ordering of flags matters here; these flags will be
            added to the assembler's command line in the same order as they
            appear in the moz.build file.
         """),
 
     'HOST_CFLAGS': (List, list,
-                    """Flags passed to the host C compiler for all of the C source files
+        """Flags passed to the host C compiler for all of the C source files
            declared in this directory.
 
            Note that the ordering of flags matters here, these flags will be
            added to the compiler's command line in the same order as they
            appear in the moz.build file.
         """),
 
     'HOST_CXXFLAGS': (List, list,
-                      """Flags passed to the host C++ compiler for all of the C++ source files
+        """Flags passed to the host C++ compiler for all of the C++ source files
            declared in this directory.
 
            Note that the ordering of flags matters here; these flags will be
            added to the compiler's command line in the same order as they
            appear in the moz.build file.
         """),
 
     'LDFLAGS': (List, list,
-                """Flags passed to the linker when linking all of the libraries and
+        """Flags passed to the linker when linking all of the libraries and
            executables declared in this directory.
 
            Note that the ordering of flags matters here; these flags will be
            added to the linker's command line in the same order as they
            appear in the moz.build file.
         """),
 
     'EXTRA_DSO_LDOPTS': (List, list,
-                         """Flags passed to the linker when linking a shared library.
+        """Flags passed to the linker when linking a shared library.
 
            Note that the ordering of flags matter here, these flags will be
            added to the linker's command line in the same order as they
            appear in the moz.build file.
         """),
 
     'WIN32_EXE_LDFLAGS': (List, list,
-                          """Flags passed to the linker when linking a Windows .exe executable
+        """Flags passed to the linker when linking a Windows .exe executable
            declared in this directory.
 
            Note that the ordering of flags matter here, these flags will be
            added to the linker's command line in the same order as they
            appear in the moz.build file.
 
            This variable only has an effect on Windows.
         """),
 
     'TEST_HARNESS_FILES': (ContextDerivedTypedHierarchicalStringList(Path), list,
-                           """List of files to be installed for test harnesses.
+        """List of files to be installed for test harnesses.
 
         ``TEST_HARNESS_FILES`` can be used to install files to any directory
         under $objdir/_tests. Files can be appended to a field to indicate
         which subdirectory they should be exported to. For example,
         to export ``foo.py`` to ``_tests/foo``, append to
         ``TEST_HARNESS_FILES`` like so::
            TEST_HARNESS_FILES.foo += ['foo.py']
 
         Files from topsrcdir and the objdir can also be installed by prefixing
         the path(s) with a '/' character and a '!' character, respectively::
            TEST_HARNESS_FILES.path += ['/build/bar.py', '!quux.py']
         """),
 
     'NO_EXPAND_LIBS': (bool, bool,
-                       """Forces to build a real static library, and no corresponding fake
+        """Forces to build a real static library, and no corresponding fake
            library.
         """),
 
     'NO_COMPONENTS_MANIFEST': (bool, bool,
-                               """Do not create a binary-component manifest entry for the
+        """Do not create a binary-component manifest entry for the
         corresponding XPCOMBinaryComponent.
         """),
 
     'USE_NASM': (bool, bool,
-                 """Use the nasm assembler to assemble assembly files from SOURCES.
+        """Use the nasm assembler to assemble assembly files from SOURCES.
 
         By default, the build will use the toolchain assembler, $(AS), to
         assemble source files in assembly language (.s or .asm files). Setting
         this value to ``True`` will cause it to use nasm instead.
 
         If nasm is not available on this system, or does not support the
         current target architecture, an error will be raised.
         """),
 
     'USE_YASM': (bool, bool,
-                 """Use the yasm assembler to assemble assembly files from SOURCES.
+        """Use the yasm assembler to assemble assembly files from SOURCES.
 
         By default, the build will use the toolchain assembler, $(AS), to
         assemble source files in assembly language (.s or .asm files). Setting
         this value to ``True`` will cause it to use yasm instead.
 
         If yasm is not available on this system, or does not support the
         current target architecture, an error will be raised.
         """),
 
     'USE_INTEGRATED_CLANGCL_AS': (bool, bool,
-                                  """Use the integrated clang-cl assembler to assemble assembly files from SOURCES.
+        """Use the integrated clang-cl assembler to assemble assembly files from SOURCES.
 
         This allows using clang-cl to assemble assembly files which is useful
         on platforms like aarch64 where the alternative is to have to run a
         pre-processor to generate files with suitable syntax.
         """),
 }
 
 # 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():
     if storage_type == list:
         raise RuntimeError('%s has a "list" storage type. Use "List" instead.'
-                           % name)
+            % name)
 
 # Set of variables that are only allowed in templates:
 TEMPLATE_VARIABLES = {
     'CPP_UNIT_TESTS',
     'FORCE_SHARED_LIB',
     'HOST_PROGRAM',
     'HOST_LIBRARY_NAME',
     'HOST_SIMPLE_PROGRAMS',
@@ -2287,34 +2207,34 @@ TEMPLATE_VARIABLES = {
     'PROGRAM',
     'SIMPLE_PROGRAMS',
 }
 
 # Add a note to template variable documentation.
 for name in TEMPLATE_VARIABLES:
     if name not in VARIABLES:
         raise RuntimeError('%s is in TEMPLATE_VARIABLES but not in VARIABLES.'
-                           % name)
+            % name)
     storage_type, input_types, docs = VARIABLES[name]
     docs += 'This variable is only available in templates.\n'
     VARIABLES[name] = (storage_type, input_types, docs)
 
 
 # The set of functions exposed to the sandbox.
 #
 # Each entry is a tuple of:
 #
 #  (function returning the corresponding function from a given sandbox,
 #   (argument types), docs)
 #
 # The first element is an attribute on Sandbox that should be a function type.
 #
 FUNCTIONS = {
     'include': (lambda self: self._include, (SourcePath,),
-                """Include another mozbuild file in the context of this one.
+        """Include another mozbuild file in the context of this one.
 
         This is similar to a ``#include`` in C languages. The filename passed to
         the function will be read and its contents will be evaluated within the
         context of the calling file.
 
         If a relative path is given, it is evaluated as relative to the file
         currently being processed. If there is a chain of multiple include(),
         the relative path computation is from the most recent/active file.
@@ -2331,17 +2251,17 @@ FUNCTIONS = {
            include('sibling.build')
 
         Include ``foo.build`` from a path within the top source directory::
 
            include('/elsewhere/foo.build')
         """),
 
     'export': (lambda self: self._export, (str,),
-               """Make the specified variable available to all child directories.
+        """Make the specified variable available to all child directories.
 
         The variable specified by the argument string is added to the
         environment of all directories specified in the DIRS and TEST_DIRS
         variables. If those directories themselves have child directories,
         the variable will be exported to all of them.
 
         The value used for the variable is the final value at the end of the
         moz.build file, so it is possible (but not recommended style) to place
@@ -2358,31 +2278,31 @@ FUNCTIONS = {
 
         To make all children directories install as the given extension::
 
           XPI_NAME = 'cool-extension'
           export('XPI_NAME')
         """),
 
     'warning': (lambda self: self._warning, (str,),
-                """Issue a warning.
+        """Issue a warning.
 
         Warnings are string messages that are printed during execution.
 
         Warnings are ignored during execution.
         """),
 
     'error': (lambda self: self._error, (str,),
-              """Issue a fatal error.
+        """Issue a fatal error.
 
         If this function is called, processing is aborted immediately.
         """),
 
     'template': (lambda self: self._template_decorator, (FunctionType,),
-                 """Decorator for template declarations.
+        """Decorator for template declarations.
 
         Templates are a special kind of functions that can be declared in
         mozbuild files. Uppercase variables assigned in the function scope
         are considered to be the result of the template.
 
         Contrary to traditional python functions:
            - return values from template functions are ignored,
            - template functions don't have access to the global scope.
@@ -2431,48 +2351,48 @@ TestDirsPlaceHolder = List()
 # Special variables. These complement VARIABLES.
 #
 # Each entry is a tuple of:
 #
 #  (function returning the corresponding value from a given context, type, docs)
 #
 SPECIAL_VARIABLES = {
     'TOPSRCDIR': (lambda context: context.config.topsrcdir, str,
-                  """Constant defining the top source directory.
+        """Constant defining the top source directory.
 
         The top source directory is the parent directory containing the source
         code and all build files. It is typically the root directory of a
         cloned repository.
         """),
 
     'TOPOBJDIR': (lambda context: context.config.topobjdir, str,
-                  """Constant defining the top object directory.
+        """Constant defining the top object directory.
 
         The top object directory is the parent directory which will contain
         the output of the build. This is commonly referred to as "the object
         directory."
         """),
 
     'RELATIVEDIR': (lambda context: context.relsrcdir, str,
-                    """Constant defining the relative path of this file.
+        """Constant defining the relative path of this file.
 
         The relative path is from ``TOPSRCDIR``. This is defined as relative
         to the main file being executed, regardless of whether additional
         files have been included using ``include()``.
         """),
 
     'SRCDIR': (lambda context: context.srcdir, str,
-               """Constant defining the source directory of this file.
+        """Constant defining the source directory of this file.
 
         This is the path inside ``TOPSRCDIR`` where this file is located. It
         is the same as ``TOPSRCDIR + RELATIVEDIR``.
         """),
 
     'OBJDIR': (lambda context: context.objdir, str,
-               """The path to the object directory for this file.
+        """The path to the object directory for this file.
 
         Is is the same as ``TOPOBJDIR + RELATIVEDIR``.
         """),
 
     'CONFIG': (lambda context: ReadOnlyKeyedDefaultDict(
             lambda key: context.config.substs_unicode.get(key)), dict,
         """Dictionary containing the current configuration variables.
 
@@ -2481,103 +2401,92 @@ SPECIAL_VARIABLES = {
 
         Values in this container are read-only. Attempts at changing values
         will result in a run-time error.
 
         Access to an unknown variable will return None.
         """),
 
     'EXTRA_COMPONENTS': (lambda context: context['FINAL_TARGET_FILES'].components._strings, list,
-                         """Additional component files to distribute.
+        """Additional component files to distribute.
 
        This variable contains a list of files to copy into
        ``$(FINAL_TARGET)/components/``.
         """),
 
-    'EXTRA_PP_COMPONENTS': (
-        lambda context: context['FINAL_TARGET_PP_FILES'].components._strings,
-        list,
+    'EXTRA_PP_COMPONENTS': (lambda context: context['FINAL_TARGET_PP_FILES'].components._strings, list,
         """Javascript XPCOM files.
 
        This variable contains a list of files to preprocess.  Generated
        files will be installed in the ``/components`` directory of the distribution.
-        """
-        ),
-
-    'JS_PREFERENCE_FILES': (
-        lambda context: context['FINAL_TARGET_FILES'].defaults.pref._strings,
-        list,
+        """),
+
+    'JS_PREFERENCE_FILES': (lambda context: context['FINAL_TARGET_FILES'].defaults.pref._strings, list,
         """Exported JavaScript files.
 
         A list of files copied into the dist directory for packaging and installation.
         Path will be defined for gre or application prefs dir based on what is building.
         """),
 
-    'JS_PREFERENCE_PP_FILES': (
-        lambda context: context['FINAL_TARGET_PP_FILES'].defaults.pref._strings,
-        list,
+    'JS_PREFERENCE_PP_FILES': (lambda context: context['FINAL_TARGET_PP_FILES'].defaults.pref._strings, list,
         """Like JS_PREFERENCE_FILES, preprocessed..
-        """
-        ),
+        """),
 
     'RESOURCE_FILES': (lambda context: context['FINAL_TARGET_FILES'].res, list,
-                       """List of resources to be exported, and in which subdirectories.
+        """List of resources to be exported, and in which subdirectories.
 
         ``RESOURCE_FILES`` is used to list the resource files to be exported to
         ``dist/bin/res``, but it can be used for other files as well. This variable
         behaves as a list when appending filenames for resources in the top-level
         directory. Files can also be appended to a field to indicate which
         subdirectory they should be exported to. For example, to export
         ``foo.res`` to the top-level directory, and ``bar.res`` to ``fonts/``,
         append to ``RESOURCE_FILES`` like so::
 
            RESOURCE_FILES += ['foo.res']
            RESOURCE_FILES.fonts += ['bar.res']
         """),
 
-    'CONTENT_ACCESSIBLE_FILES': (
-        lambda context: context['FINAL_TARGET_FILES'].contentaccessible,
-        list,
+    'CONTENT_ACCESSIBLE_FILES': (lambda context: context['FINAL_TARGET_FILES'].contentaccessible, list,
         """List of files which can be accessed by web content through resource:// URIs.
 
         ``CONTENT_ACCESSIBLE_FILES`` is used to list the files to be exported
         to ``dist/bin/contentaccessible``. Files can also be appended to a
         field to indicate which subdirectory they should be exported to.
-        """
-        ),
+        """),
 
     'EXTRA_JS_MODULES': (lambda context: context['FINAL_TARGET_FILES'].modules, list,
-                         """Additional JavaScript files to distribute.
+        """Additional JavaScript files to distribute.
 
         This variable contains a list of files to copy into
         ``$(FINAL_TARGET)/modules.
         """),
 
     'EXTRA_PP_JS_MODULES': (lambda context: context['FINAL_TARGET_PP_FILES'].modules, list,
-                            """Additional JavaScript files to distribute.
+        """Additional JavaScript files to distribute.
 
         This variable contains a list of files to copy into
         ``$(FINAL_TARGET)/modules``, after preprocessing.
         """),
 
     'TESTING_JS_MODULES': (lambda context: context['TEST_HARNESS_FILES'].modules, list,
-                           """JavaScript modules to install in the test-only destination.
+        """JavaScript modules to install in the test-only destination.
 
         Some JavaScript modules (JSMs) are test-only and not distributed
         with Firefox. This variable defines them.
 
         To install modules in a subdirectory, use properties of this
         variable to control the final destination. e.g.
 
         ``TESTING_JS_MODULES.foo += ['module.jsm']``.
         """),
 
     'TEST_DIRS': (lambda context: context['DIRS'] if context.config.substs.get('ENABLE_TESTS')
-                  else TestDirsPlaceHolder, list,
-                  """Like DIRS but only for directories that contain test-only code.
+                                  else TestDirsPlaceHolder, list,
+        """Like DIRS but only for directories that contain test-only code.
 
         If tests are not enabled, this variable will be ignored.
 
         This variable may go away once the transition away from Makefiles is
         complete.
         """),
 
 }
--- a/python/mozbuild/mozbuild/frontend/data.py
+++ b/python/mozbuild/mozbuild/frontend/data.py
@@ -10,28 +10,29 @@ structures are defined in this module.
 All data structures of interest are children of the TreeMetadata class.
 
 Logic for populating these data structures is not defined in this class.
 Instead, what we have here are dumb container classes. The emitter module
 contains the code for converting executed mozbuild files into these data
 structures.
 """
 
-from __future__ import absolute_import, print_function, unicode_literals
+from __future__ import absolute_import, unicode_literals
 
 from mozbuild.frontend.context import (
     ObjDirPath,
     SourcePath,
 )
+from mozbuild.util import StrictOrderingOnAppendList
 from mozpack.chrome.manifest import ManifestEntry
 
 import mozpack.path as mozpath
 from .context import FinalTargetValue
 
-from collections import defaultdict
+from collections import defaultdict, OrderedDict
 import itertools
 
 from ..util import (
     group_unified_files,
 )
 
 from ..testing import (
     all_test_flavors,
@@ -186,33 +187,31 @@ class ComputedFlags(ContextDerived):
         flags = defaultdict(list)
         for key, _, dest_vars in self.flags.flag_variables:
             value = self.flags.get(key)
             if value:
                 for dest_var in dest_vars:
                     flags[dest_var].extend(value)
         return flags.items()
 
-
 class XPIDLModule(ContextDerived):
     """Describes an XPIDL module to be compiled."""
 
     __slots__ = (
         'name',
         'idl_files',
     )
 
     def __init__(self, context, name, idl_files):
         ContextDerived.__init__(self, context)
 
         assert all(isinstance(idl, SourcePath) for idl in idl_files)
         self.name = name
         self.idl_files = idl_files
 
-
 class BaseDefines(ContextDerived):
     """Context derived container object for DEFINES/HOST_DEFINES,
     which are OrderedDicts.
     """
     __slots__ = ('defines')
 
     def __init__(self, context, defines):
         ContextDerived.__init__(self, context)
@@ -228,25 +227,22 @@ class BaseDefines(ContextDerived):
                 yield('-D%s=%s' % (define, value))
 
     def update(self, more_defines):
         if isinstance(more_defines, Defines):
             self.defines.update(more_defines.defines)
         else:
             self.defines.update(more_defines)
 
-
 class Defines(BaseDefines):
     pass
 
-
 class HostDefines(BaseDefines):
     pass
 
-
 class WebIDLCollection(ContextDerived):
     """Collects WebIDL info referenced during the build."""
 
     def __init__(self, context):
         ContextDerived.__init__(self, context)
         self.sources = set()
         self.generated_sources = set()
         self.generated_events_sources = set()
@@ -512,18 +508,17 @@ class BaseProgram(Linkable):
         if not program.endswith(bin_suffix):
             program += bin_suffix
         self.program = program
         self.is_unit_test = is_unit_test
 
     @property
     def output_path(self):
         if self.installed:
-            return ObjDirPath(self._context, '!/' + mozpath.join(
-                self.install_target, self.program))
+            return ObjDirPath(self._context, '!/' + mozpath.join(self.install_target, self.program))
         else:
             return ObjDirPath(self._context, '!' + self.program)
 
     def __repr__(self):
         return '<%s: %s/%s>' % (type(self).__name__, self.relobjdir, self.program)
 
     @property
     def name(self):
@@ -676,17 +671,17 @@ class Library(BaseLibrary):
 class StaticLibrary(Library):
     """Context derived container object for a static library"""
     __slots__ = (
         'link_into',
         'no_expand_lib',
     )
 
     def __init__(self, context, basename, real_name=None,
-                 link_into=None, no_expand_lib=False):
+        link_into=None, no_expand_lib=False):
         Library.__init__(self, context, basename, real_name)
         self.link_into = link_into
         self.no_expand_lib = no_expand_lib
 
 
 class RustLibrary(StaticLibrary):
     """Context derived container object for a static library"""
     __slots__ = (
@@ -708,18 +703,18 @@ class RustLibrary(StaticLibrary):
         self.cargo_file = cargo_file
         self.crate_type = crate_type
         # We need to adjust our naming here because cargo replaces '-' in
         # package names defined in Cargo.toml with underscores in actual
         # filenames. But we need to keep the basename consistent because
         # many other things in the build system depend on that.
         assert self.crate_type == 'staticlib'
         self.lib_name = '%s%s%s' % (context.config.rust_lib_prefix,
-                                    basename.replace('-', '_'),
-                                    context.config.rust_lib_suffix)
+                                     basename.replace('-', '_'),
+                                     context.config.rust_lib_suffix)
         self.dependencies = dependencies
         self.features = features
         self.target_dir = target_dir
         self.output_category = context.get('RUST_LIBRARY_OUTPUT_CATEGORY')
         # Skip setting properties below which depend on cargo
         # when we don't have a compile environment. The required
         # config keys won't be available, but the instance variables
         # that we don't set should never be accessed by the actual
@@ -892,18 +887,18 @@ class TestManifest(ContextDerived):
         'source_relpaths',
 
         # If this manifest is a duplicate of another one, this is the