mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-10 03:45:46 +00:00
Merge mozilla central to inbound. r=merge a=merge on a CLOSED TREE
This commit is contained in:
commit
251971ad8e
@ -180,11 +180,6 @@ var gPage = {
|
||||
*/
|
||||
_handleUnloadEvent: function Page_handleUnloadEvent() {
|
||||
gAllPages.unregister(this);
|
||||
// compute page life-span and send telemetry probe: using milli-seconds will leave
|
||||
// many low buckets empty. Instead we use half-second precision to make low end
|
||||
// of histogram linear and not lose the change in user attention
|
||||
let delta = Math.round((Date.now() - this._firstVisibleTime) / 500);
|
||||
Services.telemetry.getHistogramById("NEWTAB_PAGE_LIFE_SPAN").add(delta);
|
||||
},
|
||||
|
||||
/**
|
||||
@ -233,18 +228,12 @@ var gPage = {
|
||||
},
|
||||
|
||||
onPageFirstVisible: function () {
|
||||
// Record another page impression.
|
||||
Services.telemetry.getHistogramById("NEWTAB_PAGE_SHOWN").add(true);
|
||||
|
||||
for (let site of gGrid.sites) {
|
||||
if (site) {
|
||||
site.captureIfMissing();
|
||||
}
|
||||
}
|
||||
|
||||
// save timestamp to compute page life-span delta
|
||||
this._firstVisibleTime = Date.now();
|
||||
|
||||
if (document.readyState == "complete") {
|
||||
this.onPageVisibleAndLoaded();
|
||||
} else {
|
||||
|
@ -242,21 +242,6 @@ Site.prototype = {
|
||||
} catch (e) {}
|
||||
},
|
||||
|
||||
/**
|
||||
* Record interaction with site using telemetry.
|
||||
*/
|
||||
_recordSiteClicked: function Site_recordSiteClicked(aIndex) {
|
||||
if (Services.prefs.prefHasUserValue("browser.newtabpage.rows") ||
|
||||
Services.prefs.prefHasUserValue("browser.newtabpage.columns") ||
|
||||
aIndex > 8) {
|
||||
// We only want to get indices for the default configuration, everything
|
||||
// else goes in the same bucket.
|
||||
aIndex = 9;
|
||||
}
|
||||
Services.telemetry.getHistogramById("NEWTAB_PAGE_SITE_CLICKED")
|
||||
.add(aIndex);
|
||||
},
|
||||
|
||||
/**
|
||||
* Handles site click events.
|
||||
*/
|
||||
@ -265,16 +250,8 @@ Site.prototype = {
|
||||
let tileIndex = this.cell.index;
|
||||
let {button, target} = aEvent;
|
||||
|
||||
// Handle tile/thumbnail link click
|
||||
if (target.classList.contains("newtab-link") ||
|
||||
target.parentElement.classList.contains("newtab-link")) {
|
||||
// Record for primary and middle clicks
|
||||
if (button == 0 || button == 1) {
|
||||
this._recordSiteClicked(tileIndex);
|
||||
}
|
||||
}
|
||||
// Only handle primary clicks for the remaining targets
|
||||
else if (button == 0) {
|
||||
if (button == 0) {
|
||||
aEvent.preventDefault();
|
||||
if (target.classList.contains("newtab-control-block")) {
|
||||
this.block();
|
||||
|
@ -534,17 +534,56 @@ this.FormAutofillHeuristics = {
|
||||
*/
|
||||
_parseAddressFields(fieldScanner) {
|
||||
let parsedFields = false;
|
||||
let addressLines = ["address-line1", "address-line2", "address-line3"];
|
||||
for (let i = 0; !fieldScanner.parsingFinished && i < addressLines.length; i++) {
|
||||
const addressLines = ["address-line1", "address-line2", "address-line3"];
|
||||
|
||||
// TODO: These address-line* regexps are for the lines with numbers, and
|
||||
// they are the subset of the regexps in `heuristicsRegexp.js`. We have to
|
||||
// find a better way to make them consistent.
|
||||
const addressLineRegexps = {
|
||||
"address-line1": new RegExp(
|
||||
"address[_-]?line(1|one)|address1|addr1" +
|
||||
"|addrline1|address_1" + // Extra rules by Firefox
|
||||
"|indirizzo1" + // it-IT
|
||||
"|住所1" + // ja-JP
|
||||
"|地址1" + // zh-CN
|
||||
"|주소.?1", // ko-KR
|
||||
"iu"
|
||||
),
|
||||
"address-line2": new RegExp(
|
||||
"address[_-]?line(2|two)|address2|addr2" +
|
||||
"|addrline2|address_2" + // Extra rules by Firefox
|
||||
"|indirizzo2" + // it-IT
|
||||
"|住所2" + // ja-JP
|
||||
"|地址2" + // zh-CN
|
||||
"|주소.?2", // ko-KR
|
||||
"iu"
|
||||
),
|
||||
"address-line3": new RegExp(
|
||||
"address[_-]?line(3|three)|address3|addr3" +
|
||||
"|addrline3|address_3" + // Extra rules by Firefox
|
||||
"|indirizzo3" + // it-IT
|
||||
"|住所3" + // ja-JP
|
||||
"|地址3" + // zh-CN
|
||||
"|주소.?3", // ko-KR
|
||||
"iu"
|
||||
),
|
||||
};
|
||||
while (!fieldScanner.parsingFinished) {
|
||||
let detail = fieldScanner.getFieldDetailByIndex(fieldScanner.parsingIndex);
|
||||
if (!detail || !addressLines.includes(detail.fieldName)) {
|
||||
// When the field is not related to any address-line[1-3] fields, it
|
||||
// means the parsing process can be terminated.
|
||||
if (!detail || !addressLines.includes(detail.fieldName) || detail._reason == "autocomplete") {
|
||||
// When the field is not related to any address-line[1-3] fields or
|
||||
// determined by autocomplete attr, it means the parsing process can be
|
||||
// terminated.
|
||||
break;
|
||||
}
|
||||
fieldScanner.updateFieldName(fieldScanner.parsingIndex, addressLines[i]);
|
||||
const elem = detail.elementWeakRef.get();
|
||||
for (let regexp of Object.keys(addressLineRegexps)) {
|
||||
if (this._matchRegexp(elem, addressLineRegexps[regexp])) {
|
||||
fieldScanner.updateFieldName(fieldScanner.parsingIndex, regexp);
|
||||
parsedFields = true;
|
||||
}
|
||||
}
|
||||
fieldScanner.parsingIndex++;
|
||||
parsedFields = true;
|
||||
}
|
||||
|
||||
return parsedFields;
|
||||
|
@ -66,6 +66,7 @@ var HeuristicsRegExp = {
|
||||
),
|
||||
"address-line1": new RegExp(
|
||||
"^address$|address[_-]?line(one)?|address1|addr1|street" +
|
||||
"|addrline1|address_1" + // Extra rules by Firefox
|
||||
"|(?:shipping|billing)address$" +
|
||||
"|strasse|straße|hausnummer|housenumber" + // de-DE
|
||||
"|house.?name" + // en-GB
|
||||
@ -81,6 +82,7 @@ var HeuristicsRegExp = {
|
||||
),
|
||||
"address-line2": new RegExp(
|
||||
"address[_-]?line(2|two)|address2|addr2|street|suite|unit" +
|
||||
"|addrline2|address_2" + // Extra rules by Firefox
|
||||
"|adresszusatz|ergänzende.?angaben" + // de-DE
|
||||
"|direccion2|colonia|adicional" + // es
|
||||
"|addresssuppl|complementnom|appartement" + // fr-FR
|
||||
@ -94,6 +96,7 @@ var HeuristicsRegExp = {
|
||||
),
|
||||
"address-line3": new RegExp(
|
||||
"address[_-]?line(3|three)|address3|addr3|street|suite|unit" +
|
||||
"|addrline3|address_3" + // Extra rules by Firefox
|
||||
"|adresszusatz|ergänzende.?angaben" + // de-DE
|
||||
"|direccion3|colonia|adicional" + // es
|
||||
"|addresssuppl|complementnom|appartement" + // fr-FR
|
||||
|
@ -40,6 +40,14 @@
|
||||
<p><button type="reset">Reset</button></p>
|
||||
</form>
|
||||
|
||||
<form id="formC">
|
||||
<p><label><input type="text" name="someprefixAddrLine1" /></label></p>
|
||||
<p><label>City: <input type="text" name="address-level2" /></label></p>
|
||||
<p><label><input type="text" name="someprefixAddrLine2" /></label></p>
|
||||
<p><label>Organization: <input type="text" name="organization" /></label></p>
|
||||
<p><label><input type="text" name="someprefixAddrLine3" /></label></p>
|
||||
</form>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
@ -32,6 +32,13 @@ runHeuristicsTest([
|
||||
{"section": "", "addressType": "", "contactType": "", "fieldName": "cc-exp-month"},
|
||||
{"section": "", "addressType": "", "contactType": "", "fieldName": "cc-exp-year"},
|
||||
]],
|
||||
[[
|
||||
{"section": "", "addressType": "", "contactType": "", "fieldName": "address-line1"},
|
||||
{"section": "", "addressType": "", "contactType": "", "fieldName": "address-level2"},
|
||||
{"section": "", "addressType": "", "contactType": "", "fieldName": "address-line2"},
|
||||
{"section": "", "addressType": "", "contactType": "", "fieldName": "organization"},
|
||||
{"section": "", "addressType": "", "contactType": "", "fieldName": "address-line3"},
|
||||
]],
|
||||
],
|
||||
},
|
||||
], "../../fixtures/");
|
||||
|
@ -120,7 +120,8 @@ const TESTCASES = [
|
||||
}],
|
||||
},
|
||||
{
|
||||
description: "Address form with street-address, address-line[1, 3]",
|
||||
description: "Address form with street-address, address-line[1, 3]" +
|
||||
", determined by autocomplete attr",
|
||||
document: `<form>
|
||||
<input id="street-addr" autocomplete="street-address">
|
||||
<input id="line1" autocomplete="address-line1">
|
||||
@ -131,8 +132,34 @@ const TESTCASES = [
|
||||
"guid": "123",
|
||||
"street-address": "2 Harrison St line2 line3",
|
||||
"-moz-street-address-one-line": "2 Harrison St line2 line3",
|
||||
"address-line1": "2 Harrison St",
|
||||
"address-line2": "line2 line3",
|
||||
// Since the form is missing address-line2 field, the value of
|
||||
// address-line1 should contain line2 value as well.
|
||||
"address-line1": "2 Harrison St line2",
|
||||
"address-line2": "line2",
|
||||
"address-line3": "line3",
|
||||
"address-level1": "CA",
|
||||
"country": "US",
|
||||
"tel": "+19876543210",
|
||||
"tel-national": "9876543210",
|
||||
}],
|
||||
},
|
||||
{
|
||||
description: "Address form with street-address, address-line[1, 3]" +
|
||||
", determined by heuristics",
|
||||
document: `<form>
|
||||
<input id="street-address">
|
||||
<input id="address-line1">
|
||||
<input id="address-line3">
|
||||
</form>`,
|
||||
profileData: [Object.assign({}, DEFAULT_ADDRESS_RECORD)],
|
||||
expectedResult: [{
|
||||
"guid": "123",
|
||||
"street-address": "2 Harrison St line2 line3",
|
||||
"-moz-street-address-one-line": "2 Harrison St line2 line3",
|
||||
// Since the form is missing address-line2 field, the value of
|
||||
// address-line1 should contain line2 value as well.
|
||||
"address-line1": "2 Harrison St line2",
|
||||
"address-line2": "line2",
|
||||
"address-line3": "line3",
|
||||
"address-level1": "CA",
|
||||
"country": "US",
|
||||
|
@ -149,7 +149,7 @@ public:
|
||||
// Adjust code sections offsets according to their size
|
||||
std::vector<ElfSection *>::iterator c = code.begin();
|
||||
(*c)->getShdr().sh_addr = 0;
|
||||
for(ElfSection *last = *(c++); c != code.end(); c++) {
|
||||
for(ElfSection *last = *(c++); c != code.end(); ++c) {
|
||||
unsigned int addr = last->getShdr().sh_addr + last->getSize();
|
||||
if (addr & ((*c)->getAddrAlign() - 1))
|
||||
addr = (addr | ((*c)->getAddrAlign() - 1)) + 1;
|
||||
@ -162,7 +162,7 @@ public:
|
||||
shdr.sh_size = code.back()->getAddr() + code.back()->getSize();
|
||||
data = new char[shdr.sh_size];
|
||||
char *buf = data;
|
||||
for (c = code.begin(); c != code.end(); c++) {
|
||||
for (c = code.begin(); c != code.end(); ++c) {
|
||||
memcpy(buf, (*c)->getData(), (*c)->getSize());
|
||||
buf += (*c)->getSize();
|
||||
}
|
||||
@ -176,11 +176,11 @@ public:
|
||||
void serialize(std::ofstream &file, char ei_class, char ei_data)
|
||||
{
|
||||
// Readjust code offsets
|
||||
for (std::vector<ElfSection *>::iterator c = code.begin(); c != code.end(); c++)
|
||||
for (std::vector<ElfSection *>::iterator c = code.begin(); c != code.end(); ++c)
|
||||
(*c)->getShdr().sh_addr += getAddr();
|
||||
|
||||
// Apply relocations
|
||||
for (std::vector<ElfSection *>::iterator c = code.begin(); c != code.end(); c++) {
|
||||
for (std::vector<ElfSection *>::iterator c = code.begin(); c != code.end(); ++c) {
|
||||
for (ElfSection *rel = elf->getSection(1); rel != nullptr; rel = rel->getNext())
|
||||
if (((rel->getType() == SHT_REL) ||
|
||||
(rel->getType() == SHT_RELA)) &&
|
||||
@ -237,7 +237,7 @@ private:
|
||||
void scan_relocs_for_code(ElfRel_Section<Rel_Type> *rel)
|
||||
{
|
||||
ElfSymtab_Section *symtab = (ElfSymtab_Section *)rel->getLink();
|
||||
for (auto r = rel->rels.begin(); r != rel->rels.end(); r++) {
|
||||
for (auto r = rel->rels.begin(); r != rel->rels.end(); ++r) {
|
||||
ElfSection *section = symtab->syms[ELF32_R_SYM(r->r_info)].value.getSection();
|
||||
add_code_section(section);
|
||||
}
|
||||
@ -350,7 +350,7 @@ private:
|
||||
char *buf = data + (the_code->getAddr() - code.front()->getAddr());
|
||||
// TODO: various checks on the sections
|
||||
ElfSymtab_Section *symtab = (ElfSymtab_Section *)rel->getLink();
|
||||
for (typename std::vector<Rel_Type>::iterator r = rel->rels.begin(); r != rel->rels.end(); r++) {
|
||||
for (typename std::vector<Rel_Type>::iterator r = rel->rels.begin(); r != rel->rels.end(); ++r) {
|
||||
// TODO: various checks on the symbol
|
||||
const char *name = symtab->syms[ELF32_R_SYM(r->r_info)].name;
|
||||
unsigned int addr;
|
||||
@ -476,7 +476,7 @@ void maybe_split_segment(Elf *elf, ElfSegment *segment, bool fill)
|
||||
for (; it != segment->end(); ++it) {
|
||||
newSegment->addSection(*it);
|
||||
}
|
||||
for (it = newSegment->begin(); it != newSegment->end(); it++) {
|
||||
for (it = newSegment->begin(); it != newSegment->end(); ++it) {
|
||||
segment->removeSection(*it);
|
||||
}
|
||||
// Fill the virtual address space gap left between the two PT_LOADs
|
||||
@ -576,7 +576,7 @@ int do_relocation_section(Elf *elf, unsigned int rel_type, unsigned int rel_type
|
||||
relhack_entry.r_offset = relhack_entry.r_info = 0;
|
||||
size_t init_array_reloc = 0;
|
||||
for (typename std::vector<Rel_Type>::iterator i = section->rels.begin();
|
||||
i != section->rels.end(); i++) {
|
||||
i != section->rels.end(); ++i) {
|
||||
// We don't need to keep R_*_NONE relocations
|
||||
if (!ELF32_R_TYPE(i->r_info))
|
||||
continue;
|
||||
|
@ -9,7 +9,7 @@
|
||||
* Functions handling details about a single recorded animation frame snapshot
|
||||
* (the calls list, rendering preview, thumbnails filmstrip etc.).
|
||||
*/
|
||||
var CallsListView = Heritage.extend(WidgetMethods, {
|
||||
var CallsListView = extend(WidgetMethods, {
|
||||
/**
|
||||
* Initialization function, called when the tool is started.
|
||||
*/
|
||||
|
@ -14,10 +14,11 @@ const EventEmitter = require("devtools/shared/old-event-emitter");
|
||||
const { CallWatcherFront } = require("devtools/shared/fronts/call-watcher");
|
||||
const { CanvasFront } = require("devtools/shared/fronts/canvas");
|
||||
const DevToolsUtils = require("devtools/shared/DevToolsUtils");
|
||||
const { extend } = require("devtools/shared/extend");
|
||||
const flags = require("devtools/shared/flags");
|
||||
const { LocalizationHelper } = require("devtools/shared/l10n");
|
||||
const { PluralForm } = require("devtools/shared/plural-form");
|
||||
const { Heritage, WidgetMethods, setNamedTimeout, clearNamedTimeout,
|
||||
const { WidgetMethods, setNamedTimeout, clearNamedTimeout,
|
||||
setConditionalTimeout } = require("devtools/client/shared/widgets/view-helpers");
|
||||
|
||||
// Use privileged promise in panel documents to prevent having them to freeze
|
||||
|
@ -8,7 +8,7 @@
|
||||
/**
|
||||
* Functions handling the recorded animation frame snapshots UI.
|
||||
*/
|
||||
var SnapshotsListView = Heritage.extend(WidgetMethods, {
|
||||
var SnapshotsListView = extend(WidgetMethods, {
|
||||
/**
|
||||
* Initialization function, called when the tool is started.
|
||||
*/
|
||||
|
@ -8,7 +8,8 @@
|
||||
|
||||
const actions = require("../actions/event-listeners");
|
||||
const { bindActionCreators } = require("devtools/client/shared/vendor/redux");
|
||||
const { Heritage, WidgetMethods } = require("devtools/client/shared/widgets/view-helpers");
|
||||
const { extend } = require("devtools/shared/extend");
|
||||
const { WidgetMethods } = require("devtools/client/shared/widgets/view-helpers");
|
||||
const { SideMenuWidget } = require("resource://devtools/client/shared/widgets/SideMenuWidget.jsm");
|
||||
|
||||
/**
|
||||
@ -26,7 +27,7 @@ function EventListenersView(controller) {
|
||||
controller.onChange("event-listeners", this.renderListeners.bind(this));
|
||||
}
|
||||
|
||||
EventListenersView.prototype = Heritage.extend(WidgetMethods, {
|
||||
EventListenersView.prototype = extend(WidgetMethods, {
|
||||
/**
|
||||
* Initialization function, called when the debugger is started.
|
||||
*/
|
||||
|
@ -20,8 +20,8 @@ const actions = Object.assign(
|
||||
require("../actions/breakpoints")
|
||||
);
|
||||
const { bindActionCreators } = require("devtools/client/shared/vendor/redux");
|
||||
const { extend } = require("devtools/shared/extend");
|
||||
const {
|
||||
Heritage,
|
||||
WidgetMethods,
|
||||
setNamedTimeout
|
||||
} = require("devtools/client/shared/widgets/view-helpers");
|
||||
@ -80,7 +80,7 @@ function SourcesView(controller, DebuggerView) {
|
||||
this._onConditionalPopupHidden = this._onConditionalPopupHidden.bind(this);
|
||||
}
|
||||
|
||||
SourcesView.prototype = Heritage.extend(WidgetMethods, {
|
||||
SourcesView.prototype = extend(WidgetMethods, {
|
||||
/**
|
||||
* Initialization function, called when the debugger is started.
|
||||
*/
|
||||
@ -350,13 +350,13 @@ SourcesView.prototype = Heritage.extend(WidgetMethods, {
|
||||
}
|
||||
|
||||
// Create the element node and menu popup for the breakpoint item.
|
||||
let breakpointArgs = Heritage.extend(breakpoint.asMutable(), options);
|
||||
let breakpointArgs = extend(breakpoint.asMutable(), options);
|
||||
let breakpointView = this._createBreakpointView.call(this, breakpointArgs);
|
||||
let contextMenu = this._createContextMenu.call(this, breakpointArgs);
|
||||
|
||||
// Append a breakpoint child item to the corresponding source item.
|
||||
sourceItem.append(breakpointView.container, {
|
||||
attachment: Heritage.extend(breakpointArgs, {
|
||||
attachment: extend(breakpointArgs, {
|
||||
actor: location.actor,
|
||||
line: location.line,
|
||||
view: breakpointView,
|
||||
|
@ -109,8 +109,9 @@ const { SideMenuWidget } = require("resource://devtools/client/shared/widgets/Si
|
||||
const { VariablesView } = require("resource://devtools/client/shared/widgets/VariablesView.jsm");
|
||||
const { VariablesViewController, StackFrameUtils } = require("resource://devtools/client/shared/widgets/VariablesViewController.jsm");
|
||||
const EventEmitter = require("devtools/shared/old-event-emitter");
|
||||
const { extend } = require("devtools/shared/extend");
|
||||
const { gDevTools } = require("devtools/client/framework/devtools");
|
||||
const { ViewHelpers, Heritage, WidgetMethods, setNamedTimeout,
|
||||
const { ViewHelpers, WidgetMethods, setNamedTimeout,
|
||||
clearNamedTimeout } = require("devtools/client/shared/widgets/view-helpers");
|
||||
|
||||
// Use privileged promise in panel documents to prevent having them to freeze
|
||||
|
@ -846,7 +846,7 @@ var DebuggerView = {
|
||||
function ResultsPanelContainer() {
|
||||
}
|
||||
|
||||
ResultsPanelContainer.prototype = Heritage.extend(WidgetMethods, {
|
||||
ResultsPanelContainer.prototype = extend(WidgetMethods, {
|
||||
/**
|
||||
* Sets the anchor node for this container panel.
|
||||
* @param nsIDOMNode aNode
|
||||
|
@ -551,7 +551,7 @@ function FilteredSourcesView(DebuggerView) {
|
||||
this._onSelect = this._onSelect.bind(this);
|
||||
}
|
||||
|
||||
FilteredSourcesView.prototype = Heritage.extend(ResultsPanelContainer.prototype, {
|
||||
FilteredSourcesView.prototype = extend(ResultsPanelContainer.prototype, {
|
||||
/**
|
||||
* Initialization function, called when the debugger is started.
|
||||
*/
|
||||
@ -714,7 +714,7 @@ function FilteredFunctionsView(SourceScripts, Parser, DebuggerView) {
|
||||
this._onSelect = this._onSelect.bind(this);
|
||||
}
|
||||
|
||||
FilteredFunctionsView.prototype = Heritage.extend(ResultsPanelContainer.prototype, {
|
||||
FilteredFunctionsView.prototype = extend(ResultsPanelContainer.prototype, {
|
||||
/**
|
||||
* Initialization function, called when the debugger is started.
|
||||
*/
|
||||
|
@ -23,7 +23,7 @@ function GlobalSearchView(DebuggerController, DebuggerView) {
|
||||
this._onMatchClick = this._onMatchClick.bind(this);
|
||||
}
|
||||
|
||||
GlobalSearchView.prototype = Heritage.extend(WidgetMethods, {
|
||||
GlobalSearchView.prototype = extend(WidgetMethods, {
|
||||
/**
|
||||
* Initialization function, called when the debugger is started.
|
||||
*/
|
||||
|
@ -20,7 +20,7 @@ function StackFramesClassicListView(DebuggerController, DebuggerView) {
|
||||
this._onSelect = this._onSelect.bind(this);
|
||||
}
|
||||
|
||||
StackFramesClassicListView.prototype = Heritage.extend(WidgetMethods, {
|
||||
StackFramesClassicListView.prototype = extend(WidgetMethods, {
|
||||
/**
|
||||
* Initialization function, called when the debugger is started.
|
||||
*/
|
||||
|
@ -25,7 +25,7 @@ function StackFramesView(DebuggerController, DebuggerView) {
|
||||
this._getStackAsString = this._getStackAsString.bind(this);
|
||||
}
|
||||
|
||||
StackFramesView.prototype = Heritage.extend(WidgetMethods, {
|
||||
StackFramesView.prototype = extend(WidgetMethods, {
|
||||
/**
|
||||
* Initialization function, called when the debugger is started.
|
||||
*/
|
||||
|
@ -29,7 +29,7 @@ function WatchExpressionsView(DebuggerController, DebuggerView) {
|
||||
this._onKeyPress = this._onKeyPress.bind(this);
|
||||
}
|
||||
|
||||
WatchExpressionsView.prototype = Heritage.extend(WidgetMethods, {
|
||||
WatchExpressionsView.prototype = extend(WidgetMethods, {
|
||||
/**
|
||||
* Initialization function, called when the debugger is started.
|
||||
*/
|
||||
|
@ -13,7 +13,7 @@ function WorkersView() {
|
||||
this._onWorkerSelect = this._onWorkerSelect.bind(this);
|
||||
}
|
||||
|
||||
WorkersView.prototype = Heritage.extend(WidgetMethods, {
|
||||
WorkersView.prototype = extend(WidgetMethods, {
|
||||
initialize: function () {
|
||||
if (!Prefs.workersEnabled) {
|
||||
return;
|
||||
|
@ -159,6 +159,7 @@
|
||||
display: block;
|
||||
height: 100%;
|
||||
flex: 1;
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.network-monitor .source-editor-mount {
|
||||
|
@ -11,7 +11,7 @@ add_task(function* () {
|
||||
let { L10N } = require("devtools/client/netmonitor/src/utils/l10n");
|
||||
|
||||
// Set a higher panel height in order to get full CodeMirror content
|
||||
Services.prefs.setIntPref("devtools.toolbox.footer.height", 400);
|
||||
Services.prefs.setIntPref("devtools.toolbox.footer.height", 600);
|
||||
|
||||
let { tab, monitor } = yield initNetMonitor(POST_DATA_URL);
|
||||
info("Starting test... ");
|
||||
@ -139,7 +139,13 @@ add_task(function* () {
|
||||
|
||||
is(labels.length, 3, "There should be 3 param values displayed in this tabpanel.");
|
||||
|
||||
let text = document.querySelector(".CodeMirror-code").textContent;
|
||||
// Collect code lines and combine into one text for checking
|
||||
let text = "";
|
||||
let lines = [...document.querySelectorAll(".CodeMirror-line")];
|
||||
|
||||
lines.forEach((line) => {
|
||||
text += line.textContent + "\n";
|
||||
});
|
||||
|
||||
ok(text.includes("Content-Disposition: form-data; name=\"text\""),
|
||||
"The text shown in the source editor is incorrect (1.1).");
|
||||
|
@ -8,7 +8,7 @@
|
||||
*/
|
||||
|
||||
const { Task } = require("devtools/shared/task");
|
||||
const { Heritage } = require("devtools/client/shared/widgets/view-helpers");
|
||||
const { extend } = require("devtools/shared/extend");
|
||||
const LineGraphWidget = require("devtools/client/shared/widgets/LineGraphWidget");
|
||||
const MountainGraphWidget = require("devtools/client/shared/widgets/MountainGraphWidget");
|
||||
const { CanvasGraphUtils } = require("devtools/client/shared/widgets/Graphs");
|
||||
@ -59,7 +59,7 @@ function PerformanceGraph(parent, metric) {
|
||||
this.setTheme();
|
||||
}
|
||||
|
||||
PerformanceGraph.prototype = Heritage.extend(LineGraphWidget.prototype, {
|
||||
PerformanceGraph.prototype = extend(LineGraphWidget.prototype, {
|
||||
strokeWidth: STROKE_WIDTH,
|
||||
dampenValuesFactor: DAMPEN_VALUES,
|
||||
fixedHeight: HEIGHT,
|
||||
@ -108,7 +108,7 @@ function FramerateGraph(parent) {
|
||||
PerformanceGraph.call(this, parent, ProfilerGlobal.L10N.getStr("graphs.fps"));
|
||||
}
|
||||
|
||||
FramerateGraph.prototype = Heritage.extend(PerformanceGraph.prototype, {
|
||||
FramerateGraph.prototype = extend(PerformanceGraph.prototype, {
|
||||
mainColor: FRAMERATE_GRAPH_COLOR_NAME,
|
||||
setPerformanceData: function ({ duration, ticks }, resolution) {
|
||||
this.dataDuration = duration;
|
||||
@ -126,7 +126,7 @@ function MemoryGraph(parent) {
|
||||
PerformanceGraph.call(this, parent, ProfilerGlobal.L10N.getStr("graphs.memory"));
|
||||
}
|
||||
|
||||
MemoryGraph.prototype = Heritage.extend(PerformanceGraph.prototype, {
|
||||
MemoryGraph.prototype = extend(PerformanceGraph.prototype, {
|
||||
mainColor: MEMORY_GRAPH_COLOR_NAME,
|
||||
setPerformanceData: function ({ duration, memory }) {
|
||||
this.dataDuration = duration;
|
||||
@ -138,7 +138,7 @@ function TimelineGraph(parent, filter) {
|
||||
MarkersOverview.call(this, parent, filter);
|
||||
}
|
||||
|
||||
TimelineGraph.prototype = Heritage.extend(MarkersOverview.prototype, {
|
||||
TimelineGraph.prototype = extend(MarkersOverview.prototype, {
|
||||
headerHeight: MARKERS_GRAPH_HEADER_HEIGHT,
|
||||
rowHeight: MARKERS_GRAPH_ROW_HEIGHT,
|
||||
groupPadding: MARKERS_GROUP_VERTICAL_PADDING,
|
||||
@ -439,7 +439,7 @@ function OptimizationsGraph(parent) {
|
||||
this.setTheme();
|
||||
}
|
||||
|
||||
OptimizationsGraph.prototype = Heritage.extend(MountainGraphWidget.prototype, {
|
||||
OptimizationsGraph.prototype = extend(MountainGraphWidget.prototype, {
|
||||
|
||||
render: Task.async(function* (threadNode, frameNode) {
|
||||
// Regardless if we draw or clear the graph, wait
|
||||
|
@ -9,7 +9,7 @@
|
||||
* markers are visible in the "waterfall".
|
||||
*/
|
||||
|
||||
const { Heritage } = require("devtools/client/shared/widgets/view-helpers");
|
||||
const { extend } = require("devtools/shared/extend");
|
||||
const { AbstractCanvasGraph } = require("devtools/client/shared/widgets/Graphs");
|
||||
|
||||
const { colorUtils } = require("devtools/shared/css/color");
|
||||
@ -48,7 +48,7 @@ function MarkersOverview(parent, filter = [], ...args) {
|
||||
this.setFilter(filter);
|
||||
}
|
||||
|
||||
MarkersOverview.prototype = Heritage.extend(AbstractCanvasGraph.prototype, {
|
||||
MarkersOverview.prototype = extend(AbstractCanvasGraph.prototype, {
|
||||
clipheadLineColor: OVERVIEW_CLIPHEAD_LINE_COLOR,
|
||||
selectionLineColor: OVERVIEW_SELECTION_LINE_COLOR,
|
||||
headerHeight: OVERVIEW_HEADER_HEIGHT,
|
||||
|
@ -9,7 +9,7 @@
|
||||
*/
|
||||
|
||||
const { L10N } = require("devtools/client/performance/modules/global");
|
||||
const { Heritage } = require("devtools/client/shared/widgets/view-helpers");
|
||||
const { extend } = require("devtools/shared/extend");
|
||||
const { AbstractTreeItem } = require("resource://devtools/client/shared/widgets/AbstractTreeItem.jsm");
|
||||
|
||||
const URL_LABEL_TOOLTIP = L10N.getStr("table.url.tooltiptext");
|
||||
@ -174,7 +174,7 @@ function CallView({
|
||||
this._onUrlClick = this._onUrlClick.bind(this);
|
||||
}
|
||||
|
||||
CallView.prototype = Heritage.extend(AbstractTreeItem.prototype, {
|
||||
CallView.prototype = extend(AbstractTreeItem.prototype, {
|
||||
/**
|
||||
* Creates the view for this tree node.
|
||||
* @param nsIDOMNode document
|
||||
|
@ -14,10 +14,11 @@ var { loader, require } = BrowserLoaderModule.BrowserLoader({
|
||||
window
|
||||
});
|
||||
var { Task } = require("devtools/shared/task");
|
||||
/* exported Heritage, ViewHelpers, WidgetMethods, setNamedTimeout, clearNamedTimeout */
|
||||
var { Heritage, ViewHelpers, WidgetMethods, setNamedTimeout, clearNamedTimeout } = require("devtools/client/shared/widgets/view-helpers");
|
||||
/* exported ViewHelpers, WidgetMethods, setNamedTimeout, clearNamedTimeout */
|
||||
var { ViewHelpers, WidgetMethods, setNamedTimeout, clearNamedTimeout } = require("devtools/client/shared/widgets/view-helpers");
|
||||
var { PrefObserver } = require("devtools/client/shared/prefs");
|
||||
|
||||
/* exported extend */
|
||||
const { extend } = require("devtools/shared/extend");
|
||||
// Use privileged promise in panel documents to prevent having them to freeze
|
||||
// during toolbox destruction. See bug 1402779.
|
||||
var Promise = require("Promise");
|
||||
|
@ -55,14 +55,14 @@ exports.synthesizeProfile = () => {
|
||||
exports.synthesizeCustomTreeClass = () => {
|
||||
const { Cu } = require("chrome");
|
||||
const { AbstractTreeItem } = Cu.import("resource://devtools/client/shared/widgets/AbstractTreeItem.jsm", {});
|
||||
const { Heritage } = require("devtools/client/shared/widgets/view-helpers");
|
||||
const { extend } = require("devtools/shared/extend");
|
||||
|
||||
function MyCustomTreeItem(dataSrc, properties) {
|
||||
AbstractTreeItem.call(this, properties);
|
||||
this.itemDataSrc = dataSrc;
|
||||
}
|
||||
|
||||
MyCustomTreeItem.prototype = Heritage.extend(AbstractTreeItem.prototype, {
|
||||
MyCustomTreeItem.prototype = extend(AbstractTreeItem.prototype, {
|
||||
_displaySelf: function (document, arrowNode) {
|
||||
let node = document.createElement("hbox");
|
||||
node.style.marginInlineStart = (this.level * 10) + "px";
|
||||
|
@ -9,7 +9,7 @@
|
||||
/**
|
||||
* CallTree view containing profiler call tree, controlled by DetailsView.
|
||||
*/
|
||||
var JsCallTreeView = Heritage.extend(DetailsSubview, {
|
||||
var JsCallTreeView = extend(DetailsSubview, {
|
||||
|
||||
rerenderPrefs: [
|
||||
"invert-call-tree",
|
||||
|
@ -10,7 +10,7 @@
|
||||
* FlameGraph view containing a pyramid-like visualization of a profile,
|
||||
* controlled by DetailsView.
|
||||
*/
|
||||
var JsFlameGraphView = Heritage.extend(DetailsSubview, {
|
||||
var JsFlameGraphView = extend(DetailsSubview, {
|
||||
|
||||
shouldUpdateWhileMouseIsActive: true,
|
||||
|
||||
|
@ -9,7 +9,7 @@
|
||||
/**
|
||||
* CallTree view containing memory allocation sites, controlled by DetailsView.
|
||||
*/
|
||||
var MemoryCallTreeView = Heritage.extend(DetailsSubview, {
|
||||
var MemoryCallTreeView = extend(DetailsSubview, {
|
||||
|
||||
rerenderPrefs: [
|
||||
"invert-call-tree"
|
||||
|
@ -10,7 +10,7 @@
|
||||
* FlameGraph view containing a pyramid-like visualization of memory allocation
|
||||
* sites, controlled by DetailsView.
|
||||
*/
|
||||
var MemoryFlameGraphView = Heritage.extend(DetailsSubview, {
|
||||
var MemoryFlameGraphView = extend(DetailsSubview, {
|
||||
|
||||
shouldUpdateWhileMouseIsActive: true,
|
||||
|
||||
|
@ -15,7 +15,7 @@ const { TickUtils } = require("devtools/client/performance/modules/waterfall-tic
|
||||
/**
|
||||
* Waterfall view containing the timeline markers, controlled by DetailsView.
|
||||
*/
|
||||
var WaterfallView = Heritage.extend(DetailsSubview, {
|
||||
var WaterfallView = extend(DetailsSubview, {
|
||||
|
||||
// Smallest unit of time between two markers. Larger by 10x^3 than Number.EPSILON.
|
||||
MARKER_EPSILON: 0.000000000001,
|
||||
|
@ -55,7 +55,7 @@ const promise = require("promise");
|
||||
const defer = require("devtools/shared/defer");
|
||||
const Services = require("Services");
|
||||
const {gDevTools} = require("devtools/client/framework/devtools");
|
||||
const {Heritage} = require("devtools/client/shared/widgets/view-helpers");
|
||||
const { extend } = require("devtools/shared/extend");
|
||||
|
||||
const {XPCOMUtils} = require("resource://gre/modules/XPCOMUtils.jsm");
|
||||
const {NetUtil} = require("resource://gre/modules/NetUtil.jsm");
|
||||
@ -2177,7 +2177,7 @@ function ScratchpadWindow() {}
|
||||
|
||||
ScratchpadWindow.consoleFor = ScratchpadTab.consoleFor;
|
||||
|
||||
ScratchpadWindow.prototype = Heritage.extend(ScratchpadTab.prototype, {
|
||||
ScratchpadWindow.prototype = extend(ScratchpadTab.prototype, {
|
||||
/**
|
||||
* Attach to this window.
|
||||
*
|
||||
@ -2207,7 +2207,7 @@ function ScratchpadTarget(aTarget)
|
||||
|
||||
ScratchpadTarget.consoleFor = ScratchpadTab.consoleFor;
|
||||
|
||||
ScratchpadTarget.prototype = Heritage.extend(ScratchpadTab.prototype, {
|
||||
ScratchpadTarget.prototype = extend(ScratchpadTab.prototype, {
|
||||
_attach: function ST__attach()
|
||||
{
|
||||
if (this._target.isRemote) {
|
||||
|
@ -15,7 +15,8 @@ const EventEmitter = require("devtools/shared/old-event-emitter");
|
||||
const Tooltip = require("devtools/client/shared/widgets/tooltip/Tooltip");
|
||||
const Editor = require("devtools/client/sourceeditor/editor");
|
||||
const {LocalizationHelper} = require("devtools/shared/l10n");
|
||||
const {Heritage, WidgetMethods, setNamedTimeout} =
|
||||
const {extend} = require("devtools/shared/extend");
|
||||
const {WidgetMethods, setNamedTimeout} =
|
||||
require("devtools/client/shared/widgets/view-helpers");
|
||||
const {Task} = require("devtools/shared/task");
|
||||
|
||||
@ -198,7 +199,7 @@ var EventsHandler = {
|
||||
/**
|
||||
* Functions handling the sources UI.
|
||||
*/
|
||||
var ShadersListView = Heritage.extend(WidgetMethods, {
|
||||
var ShadersListView = extend(WidgetMethods, {
|
||||
/**
|
||||
* Initialization function, called when the tool is started.
|
||||
*/
|
||||
|
@ -41,7 +41,7 @@ this.EXPORTED_SYMBOLS = ["AbstractTreeItem"];
|
||||
* this.itemDataSrc = dataSrc;
|
||||
* }
|
||||
*
|
||||
* MyCustomTreeItem.prototype = Heritage.extend(AbstractTreeItem.prototype, {
|
||||
* MyCustomTreeItem.prototype = extend(AbstractTreeItem.prototype, {
|
||||
* _displaySelf: function(document, arrowNode) {
|
||||
* let node = document.createElement("hbox");
|
||||
* ...
|
||||
|
@ -1,6 +1,7 @@
|
||||
"use strict";
|
||||
|
||||
const { Heritage, setNamedTimeout, clearNamedTimeout } = require("devtools/client/shared/widgets/view-helpers");
|
||||
const { extend } = require("devtools/shared/extend");
|
||||
const { setNamedTimeout, clearNamedTimeout } = require("devtools/client/shared/widgets/view-helpers");
|
||||
const { AbstractCanvasGraph, CanvasGraphUtils } = require("devtools/client/shared/widgets/Graphs");
|
||||
|
||||
const HTML_NS = "http://www.w3.org/1999/xhtml";
|
||||
@ -77,7 +78,7 @@ this.BarGraphWidget = function (parent, ...args) {
|
||||
});
|
||||
};
|
||||
|
||||
BarGraphWidget.prototype = Heritage.extend(AbstractCanvasGraph.prototype, {
|
||||
BarGraphWidget.prototype = extend(AbstractCanvasGraph.prototype, {
|
||||
clipheadLineColor: GRAPH_CLIPHEAD_LINE_COLOR,
|
||||
selectionLineColor: GRAPH_SELECTION_LINE_COLOR,
|
||||
selectionBackgroundColor: GRAPH_SELECTION_BACKGROUND_COLOR,
|
||||
|
@ -1,7 +1,7 @@
|
||||
"use strict";
|
||||
|
||||
const { Task } = require("devtools/shared/task");
|
||||
const { Heritage } = require("devtools/client/shared/widgets/view-helpers");
|
||||
const { extend } = require("devtools/shared/extend");
|
||||
const { AbstractCanvasGraph, CanvasGraphUtils } = require("devtools/client/shared/widgets/Graphs");
|
||||
const { LocalizationHelper } = require("devtools/shared/l10n");
|
||||
|
||||
@ -89,7 +89,7 @@ this.LineGraphWidget = function (parent, options = {}, ...args) {
|
||||
});
|
||||
};
|
||||
|
||||
LineGraphWidget.prototype = Heritage.extend(AbstractCanvasGraph.prototype, {
|
||||
LineGraphWidget.prototype = extend(AbstractCanvasGraph.prototype, {
|
||||
backgroundColor: GRAPH_BACKGROUND_COLOR,
|
||||
backgroundGradientStart: GRAPH_BACKGROUND_GRADIENT_START,
|
||||
backgroundGradientEnd: GRAPH_BACKGROUND_GRADIENT_END,
|
||||
|
@ -1,6 +1,6 @@
|
||||
"use strict";
|
||||
|
||||
const { Heritage } = require("devtools/client/shared/widgets/view-helpers");
|
||||
const { extend } = require("devtools/shared/extend");
|
||||
const { AbstractCanvasGraph } = require("devtools/client/shared/widgets/Graphs");
|
||||
|
||||
// Bar graph constants.
|
||||
@ -57,7 +57,7 @@ this.MountainGraphWidget = function (parent, ...args) {
|
||||
AbstractCanvasGraph.apply(this, [parent, "mountain-graph", ...args]);
|
||||
};
|
||||
|
||||
MountainGraphWidget.prototype = Heritage.extend(AbstractCanvasGraph.prototype, {
|
||||
MountainGraphWidget.prototype = extend(AbstractCanvasGraph.prototype, {
|
||||
backgroundColor: GRAPH_BACKGROUND_COLOR,
|
||||
strokeColor: GRAPH_STROKE_COLOR,
|
||||
strokeWidth: GRAPH_STROKE_WIDTH,
|
||||
|
@ -24,7 +24,8 @@ const Services = require("Services");
|
||||
const { getSourceNames } = require("devtools/client/shared/source-utils");
|
||||
const promise = require("promise");
|
||||
const defer = require("devtools/shared/defer");
|
||||
const { Heritage, ViewHelpers, setNamedTimeout } =
|
||||
const { extend } = require("devtools/shared/extend");
|
||||
const { ViewHelpers, setNamedTimeout } =
|
||||
require("devtools/client/shared/widgets/view-helpers");
|
||||
const { Task } = require("devtools/shared/task");
|
||||
const nodeConstants = require("devtools/shared/dom-node-constants");
|
||||
@ -2179,7 +2180,7 @@ function Variable(aScope, aName, aDescriptor, aOptions) {
|
||||
this.setGrip(aDescriptor.value);
|
||||
}
|
||||
|
||||
Variable.prototype = Heritage.extend(Scope.prototype, {
|
||||
Variable.prototype = extend(Scope.prototype, {
|
||||
/**
|
||||
* Whether this Variable should be prefetched when it is remoted.
|
||||
*/
|
||||
@ -3072,7 +3073,7 @@ function Property(aVar, aName, aDescriptor, aOptions) {
|
||||
Variable.call(this, aVar, aName, aDescriptor, aOptions);
|
||||
}
|
||||
|
||||
Property.prototype = Heritage.extend(Variable.prototype, {
|
||||
Property.prototype = extend(Variable.prototype, {
|
||||
/**
|
||||
* The class name applied to this property's target element.
|
||||
*/
|
||||
@ -3160,7 +3161,7 @@ VariablesView.prototype.commitHierarchy = function () {
|
||||
|
||||
// Some variables are likely to contain a very large number of properties.
|
||||
// It would be a bad idea to re-expand them or perform expensive operations.
|
||||
VariablesView.prototype.commitHierarchyIgnoredItems = Heritage.extend(null, {
|
||||
VariablesView.prototype.commitHierarchyIgnoredItems = extend(null, {
|
||||
"window": true,
|
||||
"this": true
|
||||
});
|
||||
@ -4116,7 +4117,7 @@ function EditableName(aVariable, aOptions) {
|
||||
|
||||
EditableName.create = Editable.create;
|
||||
|
||||
EditableName.prototype = Heritage.extend(Editable.prototype, {
|
||||
EditableName.prototype = extend(Editable.prototype, {
|
||||
className: "element-name-input",
|
||||
|
||||
get label() {
|
||||
@ -4138,7 +4139,7 @@ function EditableValue(aVariable, aOptions) {
|
||||
|
||||
EditableValue.create = Editable.create;
|
||||
|
||||
EditableValue.prototype = Heritage.extend(Editable.prototype, {
|
||||
EditableValue.prototype = extend(Editable.prototype, {
|
||||
className: "element-value-input",
|
||||
|
||||
get label() {
|
||||
@ -4160,7 +4161,7 @@ function EditableNameAndValue(aVariable, aOptions) {
|
||||
|
||||
EditableNameAndValue.create = Editable.create;
|
||||
|
||||
EditableNameAndValue.prototype = Heritage.extend(EditableName.prototype, {
|
||||
EditableNameAndValue.prototype = extend(EditableName.prototype, {
|
||||
_reset: function (e) {
|
||||
// Hide the Variable or Property if the user presses escape.
|
||||
this._variable.remove();
|
||||
|
@ -13,29 +13,6 @@ const WIDGET_FOCUSABLE_NODES = new Set(["vbox", "hbox"]);
|
||||
|
||||
var namedTimeoutsStore = new Map();
|
||||
|
||||
/**
|
||||
* Inheritance helpers from the addon SDK's core/heritage.
|
||||
* Remove these when all devtools are loadered.
|
||||
*/
|
||||
exports.Heritage = {
|
||||
/**
|
||||
* @see extend in sdk/core/heritage.
|
||||
*/
|
||||
extend: function (prototype, properties = {}) {
|
||||
return Object.create(prototype, this.getOwnPropertyDescriptors(properties));
|
||||
},
|
||||
|
||||
/**
|
||||
* @see getOwnPropertyDescriptors in sdk/core/heritage.
|
||||
*/
|
||||
getOwnPropertyDescriptors: function (object) {
|
||||
return Object.getOwnPropertyNames(object).reduce((descriptor, name) => {
|
||||
descriptor[name] = Object.getOwnPropertyDescriptor(object, name);
|
||||
return descriptor;
|
||||
}, {});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Helper for draining a rapid succession of events and invoking a callback
|
||||
* once everything settles down.
|
||||
@ -490,7 +467,7 @@ Item.prototype = {
|
||||
* this.widget = new MyWidget(document.querySelector(".my-node"));
|
||||
* }
|
||||
*
|
||||
* MyView.prototype = Heritage.extend(WidgetMethods, {
|
||||
* MyView.prototype = extend(WidgetMethods, {
|
||||
* myMethod: function() {},
|
||||
* ...
|
||||
* });
|
||||
|
@ -1,6 +1,6 @@
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
// A test to ensure Style Editor doesn't bybass cache when loading style sheet
|
||||
@ -42,8 +42,6 @@ add_task(function* () {
|
||||
}
|
||||
}
|
||||
|
||||
is(items.length, 2,
|
||||
"Got two requests for doc_uncached.css after Style Editor was loaded.");
|
||||
ok(items[1].fromCache,
|
||||
"Second request was loaded from browser cache");
|
||||
is(items.length, 1,
|
||||
"Got one request for doc_uncached.css after Style Editor was loaded.");
|
||||
});
|
||||
|
@ -125,10 +125,38 @@ describe("ConsoleAPICall component:", () => {
|
||||
|
||||
describe("console.count", () => {
|
||||
it("renders", () => {
|
||||
const message = stubPreparedMessages.get("console.count('bar')");
|
||||
const wrapper = render(ConsoleApiCall({ message, serviceContainer }));
|
||||
const messages = [{
|
||||
key: "console.count('bar')",
|
||||
expectedBodyText: "bar: 1",
|
||||
}, {
|
||||
key: "console.count | default: 1",
|
||||
expectedBodyText: "default: 1",
|
||||
}, {
|
||||
key: "console.count | default: 2",
|
||||
expectedBodyText: "default: 2",
|
||||
}, {
|
||||
key: "console.count | test counter: 1",
|
||||
expectedBodyText: "test counter: 1",
|
||||
}, {
|
||||
key: "console.count | test counter: 2",
|
||||
expectedBodyText: "test counter: 2",
|
||||
}, {
|
||||
key: "console.count | default: 3",
|
||||
expectedBodyText: "default: 3",
|
||||
}, {
|
||||
key: "console.count | default: 4",
|
||||
expectedBodyText: "default: 4",
|
||||
}, {
|
||||
key: "console.count | test counter: 3",
|
||||
expectedBodyText: "test counter: 3",
|
||||
}];
|
||||
|
||||
expect(wrapper.find(".message-body").text()).toBe("bar: 1");
|
||||
for (const {key, expectedBodyText} of messages) {
|
||||
const message = stubPreparedMessages.get(key);
|
||||
const wrapper = render(ConsoleApiCall({ message, serviceContainer }));
|
||||
|
||||
expect(wrapper.find(".message-body").text()).toBe(expectedBodyText);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -135,6 +135,28 @@ consoleApi.set("console.dir({C, M, Y, K})", {
|
||||
code: "console.dir({cyan: 'C', magenta: 'M', yellow: 'Y', black: 'K'});"
|
||||
});
|
||||
|
||||
consoleApi.set("console.count", {
|
||||
keys: [
|
||||
"console.count | default: 1",
|
||||
"console.count | default: 2",
|
||||
"console.count | test counter: 1",
|
||||
"console.count | test counter: 2",
|
||||
"console.count | default: 3",
|
||||
"console.count | clear",
|
||||
"console.count | default: 4",
|
||||
"console.count | test counter: 3",
|
||||
],
|
||||
code: `
|
||||
console.count();
|
||||
console.count();
|
||||
console.count("test counter");
|
||||
console.count("test counter");
|
||||
console.count();
|
||||
console.clear();
|
||||
console.count();
|
||||
console.count("test counter");
|
||||
`});
|
||||
|
||||
// CSS messages
|
||||
const cssMessage = new Map();
|
||||
|
||||
|
@ -1297,6 +1297,200 @@ stubPreparedMessages.set("console.dir({C, M, Y, K})", new ConsoleMessage({
|
||||
"indent": 0
|
||||
}));
|
||||
|
||||
stubPreparedMessages.set("console.count | default: 1", new ConsoleMessage({
|
||||
"id": "1",
|
||||
"allowRepeating": true,
|
||||
"source": "console-api",
|
||||
"timeStamp": 1511365913333,
|
||||
"type": "log",
|
||||
"helperType": null,
|
||||
"level": "log",
|
||||
"messageText": "default: 1",
|
||||
"parameters": null,
|
||||
"repeatId": "{\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"line\":2,\"column\":5},\"groupId\":null,\"indent\":0,\"level\":\"log\",\"messageText\":\"default: 1\",\"parameters\":null,\"source\":\"console-api\",\"type\":\"log\",\"userProvidedStyles\":[]}",
|
||||
"stacktrace": null,
|
||||
"frame": {
|
||||
"source": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html",
|
||||
"line": 2,
|
||||
"column": 5
|
||||
},
|
||||
"groupId": null,
|
||||
"exceptionDocURL": null,
|
||||
"userProvidedStyles": [],
|
||||
"notes": null,
|
||||
"indent": 0
|
||||
}));
|
||||
|
||||
stubPreparedMessages.set("console.count | default: 2", new ConsoleMessage({
|
||||
"id": "1",
|
||||
"allowRepeating": true,
|
||||
"source": "console-api",
|
||||
"timeStamp": 1511365913334,
|
||||
"type": "log",
|
||||
"helperType": null,
|
||||
"level": "log",
|
||||
"messageText": "default: 2",
|
||||
"parameters": null,
|
||||
"repeatId": "{\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"line\":3,\"column\":5},\"groupId\":null,\"indent\":0,\"level\":\"log\",\"messageText\":\"default: 2\",\"parameters\":null,\"source\":\"console-api\",\"type\":\"log\",\"userProvidedStyles\":[]}",
|
||||
"stacktrace": null,
|
||||
"frame": {
|
||||
"source": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html",
|
||||
"line": 3,
|
||||
"column": 5
|
||||
},
|
||||
"groupId": null,
|
||||
"exceptionDocURL": null,
|
||||
"userProvidedStyles": [],
|
||||
"notes": null,
|
||||
"indent": 0
|
||||
}));
|
||||
|
||||
stubPreparedMessages.set("console.count | test counter: 1", new ConsoleMessage({
|
||||
"id": "1",
|
||||
"allowRepeating": true,
|
||||
"source": "console-api",
|
||||
"timeStamp": 1511365913334,
|
||||
"type": "log",
|
||||
"helperType": null,
|
||||
"level": "log",
|
||||
"messageText": "test counter: 1",
|
||||
"parameters": null,
|
||||
"repeatId": "{\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"line\":4,\"column\":5},\"groupId\":null,\"indent\":0,\"level\":\"log\",\"messageText\":\"test counter: 1\",\"parameters\":null,\"source\":\"console-api\",\"type\":\"log\",\"userProvidedStyles\":[]}",
|
||||
"stacktrace": null,
|
||||
"frame": {
|
||||
"source": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html",
|
||||
"line": 4,
|
||||
"column": 5
|
||||
},
|
||||
"groupId": null,
|
||||
"exceptionDocURL": null,
|
||||
"userProvidedStyles": [],
|
||||
"notes": null,
|
||||
"indent": 0
|
||||
}));
|
||||
|
||||
stubPreparedMessages.set("console.count | test counter: 2", new ConsoleMessage({
|
||||
"id": "1",
|
||||
"allowRepeating": true,
|
||||
"source": "console-api",
|
||||
"timeStamp": 1511365913334,
|
||||
"type": "log",
|
||||
"helperType": null,
|
||||
"level": "log",
|
||||
"messageText": "test counter: 2",
|
||||
"parameters": null,
|
||||
"repeatId": "{\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"line\":5,\"column\":5},\"groupId\":null,\"indent\":0,\"level\":\"log\",\"messageText\":\"test counter: 2\",\"parameters\":null,\"source\":\"console-api\",\"type\":\"log\",\"userProvidedStyles\":[]}",
|
||||
"stacktrace": null,
|
||||
"frame": {
|
||||
"source": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html",
|
||||
"line": 5,
|
||||
"column": 5
|
||||
},
|
||||
"groupId": null,
|
||||
"exceptionDocURL": null,
|
||||
"userProvidedStyles": [],
|
||||
"notes": null,
|
||||
"indent": 0
|
||||
}));
|
||||
|
||||
stubPreparedMessages.set("console.count | default: 3", new ConsoleMessage({
|
||||
"id": "1",
|
||||
"allowRepeating": true,
|
||||
"source": "console-api",
|
||||
"timeStamp": 1511365913334,
|
||||
"type": "log",
|
||||
"helperType": null,
|
||||
"level": "log",
|
||||
"messageText": "default: 3",
|
||||
"parameters": null,
|
||||
"repeatId": "{\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"line\":6,\"column\":5},\"groupId\":null,\"indent\":0,\"level\":\"log\",\"messageText\":\"default: 3\",\"parameters\":null,\"source\":\"console-api\",\"type\":\"log\",\"userProvidedStyles\":[]}",
|
||||
"stacktrace": null,
|
||||
"frame": {
|
||||
"source": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html",
|
||||
"line": 6,
|
||||
"column": 5
|
||||
},
|
||||
"groupId": null,
|
||||
"exceptionDocURL": null,
|
||||
"userProvidedStyles": [],
|
||||
"notes": null,
|
||||
"indent": 0
|
||||
}));
|
||||
|
||||
stubPreparedMessages.set("console.count | clear", new ConsoleMessage({
|
||||
"id": "1",
|
||||
"allowRepeating": true,
|
||||
"source": "console-api",
|
||||
"timeStamp": 1511365913334,
|
||||
"type": "clear",
|
||||
"helperType": null,
|
||||
"level": "log",
|
||||
"messageText": null,
|
||||
"parameters": [
|
||||
"Console was cleared."
|
||||
],
|
||||
"repeatId": "{\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"line\":7,\"column\":5},\"groupId\":null,\"indent\":0,\"level\":\"log\",\"messageText\":null,\"parameters\":[\"Console was cleared.\"],\"source\":\"console-api\",\"type\":\"clear\",\"userProvidedStyles\":[]}",
|
||||
"stacktrace": null,
|
||||
"frame": {
|
||||
"source": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html",
|
||||
"line": 7,
|
||||
"column": 5
|
||||
},
|
||||
"groupId": null,
|
||||
"exceptionDocURL": null,
|
||||
"userProvidedStyles": [],
|
||||
"notes": null,
|
||||
"indent": 0
|
||||
}));
|
||||
|
||||
stubPreparedMessages.set("console.count | default: 4", new ConsoleMessage({
|
||||
"id": "1",
|
||||
"allowRepeating": true,
|
||||
"source": "console-api",
|
||||
"timeStamp": 1511365913335,
|
||||
"type": "log",
|
||||
"helperType": null,
|
||||
"level": "log",
|
||||
"messageText": "default: 4",
|
||||
"parameters": null,
|
||||
"repeatId": "{\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"line\":8,\"column\":5},\"groupId\":null,\"indent\":0,\"level\":\"log\",\"messageText\":\"default: 4\",\"parameters\":null,\"source\":\"console-api\",\"type\":\"log\",\"userProvidedStyles\":[]}",
|
||||
"stacktrace": null,
|
||||
"frame": {
|
||||
"source": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html",
|
||||
"line": 8,
|
||||
"column": 5
|
||||
},
|
||||
"groupId": null,
|
||||
"exceptionDocURL": null,
|
||||
"userProvidedStyles": [],
|
||||
"notes": null,
|
||||
"indent": 0
|
||||
}));
|
||||
|
||||
stubPreparedMessages.set("console.count | test counter: 3", new ConsoleMessage({
|
||||
"id": "1",
|
||||
"allowRepeating": true,
|
||||
"source": "console-api",
|
||||
"timeStamp": 1511365913335,
|
||||
"type": "log",
|
||||
"helperType": null,
|
||||
"level": "log",
|
||||
"messageText": "test counter: 3",
|
||||
"parameters": null,
|
||||
"repeatId": "{\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"line\":9,\"column\":5},\"groupId\":null,\"indent\":0,\"level\":\"log\",\"messageText\":\"test counter: 3\",\"parameters\":null,\"source\":\"console-api\",\"type\":\"log\",\"userProvidedStyles\":[]}",
|
||||
"stacktrace": null,
|
||||
"frame": {
|
||||
"source": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html",
|
||||
"line": 9,
|
||||
"column": 5
|
||||
},
|
||||
"groupId": null,
|
||||
"exceptionDocURL": null,
|
||||
"userProvidedStyles": [],
|
||||
"notes": null,
|
||||
"indent": 0
|
||||
}));
|
||||
|
||||
stubPackets.set("console.log('foobar', 'test')", {
|
||||
"from": "server1.conn0.child1/consoleActor2",
|
||||
"type": "consoleAPICall",
|
||||
@ -2524,6 +2718,217 @@ stubPackets.set("console.dir({C, M, Y, K})", {
|
||||
}
|
||||
});
|
||||
|
||||
stubPackets.set("console.count | default: 1", {
|
||||
"from": "server1.conn0.child1/consoleActor2",
|
||||
"type": "consoleAPICall",
|
||||
"message": {
|
||||
"addonId": "",
|
||||
"arguments": [
|
||||
"default"
|
||||
],
|
||||
"columnNumber": 5,
|
||||
"counter": {
|
||||
"count": 1,
|
||||
"label": "default"
|
||||
},
|
||||
"filename": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html",
|
||||
"functionName": "triggerPacket",
|
||||
"groupName": "",
|
||||
"level": "count",
|
||||
"lineNumber": 2,
|
||||
"private": false,
|
||||
"timeStamp": 1511365913333,
|
||||
"timer": null,
|
||||
"workerType": "none",
|
||||
"styles": [],
|
||||
"category": "webdev"
|
||||
}
|
||||
});
|
||||
|
||||
stubPackets.set("console.count | default: 2", {
|
||||
"from": "server1.conn0.child1/consoleActor2",
|
||||
"type": "consoleAPICall",
|
||||
"message": {
|
||||
"addonId": "",
|
||||
"arguments": [
|
||||
"default"
|
||||
],
|
||||
"columnNumber": 5,
|
||||
"counter": {
|
||||
"count": 2,
|
||||
"label": "default"
|
||||
},
|
||||
"filename": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html",
|
||||
"functionName": "triggerPacket",
|
||||
"groupName": "",
|
||||
"level": "count",
|
||||
"lineNumber": 3,
|
||||
"private": false,
|
||||
"timeStamp": 1511365913334,
|
||||
"timer": null,
|
||||
"workerType": "none",
|
||||
"styles": [],
|
||||
"category": "webdev"
|
||||
}
|
||||
});
|
||||
|
||||
stubPackets.set("console.count | test counter: 1", {
|
||||
"from": "server1.conn0.child1/consoleActor2",
|
||||
"type": "consoleAPICall",
|
||||
"message": {
|
||||
"addonId": "",
|
||||
"arguments": [
|
||||
"test counter"
|
||||
],
|
||||
"columnNumber": 5,
|
||||
"counter": {
|
||||
"count": 1,
|
||||
"label": "test counter"
|
||||
},
|
||||
"filename": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html",
|
||||
"functionName": "triggerPacket",
|
||||
"groupName": "",
|
||||
"level": "count",
|
||||
"lineNumber": 4,
|
||||
"private": false,
|
||||
"timeStamp": 1511365913334,
|
||||
"timer": null,
|
||||
"workerType": "none",
|
||||
"styles": [],
|
||||
"category": "webdev"
|
||||
}
|
||||
});
|
||||
|
||||
stubPackets.set("console.count | test counter: 2", {
|
||||
"from": "server1.conn0.child1/consoleActor2",
|
||||
"type": "consoleAPICall",
|
||||
"message": {
|
||||
"addonId": "",
|
||||
"arguments": [
|
||||
"test counter"
|
||||
],
|
||||
"columnNumber": 5,
|
||||
"counter": {
|
||||
"count": 2,
|
||||
"label": "test counter"
|
||||
},
|
||||
"filename": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html",
|
||||
"functionName": "triggerPacket",
|
||||
"groupName": "",
|
||||
"level": "count",
|
||||
"lineNumber": 5,
|
||||
"private": false,
|
||||
"timeStamp": 1511365913334,
|
||||
"timer": null,
|
||||
"workerType": "none",
|
||||
"styles": [],
|
||||
"category": "webdev"
|
||||
}
|
||||
});
|
||||
|
||||
stubPackets.set("console.count | default: 3", {
|
||||
"from": "server1.conn0.child1/consoleActor2",
|
||||
"type": "consoleAPICall",
|
||||
"message": {
|
||||
"addonId": "",
|
||||
"arguments": [
|
||||
"default"
|
||||
],
|
||||
"columnNumber": 5,
|
||||
"counter": {
|
||||
"count": 3,
|
||||
"label": "default"
|
||||
},
|
||||
"filename": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html",
|
||||
"functionName": "triggerPacket",
|
||||
"groupName": "",
|
||||
"level": "count",
|
||||
"lineNumber": 6,
|
||||
"private": false,
|
||||
"timeStamp": 1511365913334,
|
||||
"timer": null,
|
||||
"workerType": "none",
|
||||
"styles": [],
|
||||
"category": "webdev"
|
||||
}
|
||||
});
|
||||
|
||||
stubPackets.set("console.count | clear", {
|
||||
"from": "server1.conn0.child1/consoleActor2",
|
||||
"type": "consoleAPICall",
|
||||
"message": {
|
||||
"addonId": "",
|
||||
"arguments": [],
|
||||
"columnNumber": 5,
|
||||
"counter": null,
|
||||
"filename": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html",
|
||||
"functionName": "triggerPacket",
|
||||
"groupName": "",
|
||||
"level": "clear",
|
||||
"lineNumber": 7,
|
||||
"private": false,
|
||||
"timeStamp": 1511365913334,
|
||||
"timer": null,
|
||||
"workerType": "none",
|
||||
"styles": [],
|
||||
"category": "webdev"
|
||||
}
|
||||
});
|
||||
|
||||
stubPackets.set("console.count | default: 4", {
|
||||
"from": "server1.conn0.child1/consoleActor2",
|
||||
"type": "consoleAPICall",
|
||||
"message": {
|
||||
"addonId": "",
|
||||
"arguments": [
|
||||
"default"
|
||||
],
|
||||
"columnNumber": 5,
|
||||
"counter": {
|
||||
"count": 4,
|
||||
"label": "default"
|
||||
},
|
||||
"filename": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html",
|
||||
"functionName": "triggerPacket",
|
||||
"groupName": "",
|
||||
"level": "count",
|
||||
"lineNumber": 8,
|
||||
"private": false,
|
||||
"timeStamp": 1511365913335,
|
||||
"timer": null,
|
||||
"workerType": "none",
|
||||
"styles": [],
|
||||
"category": "webdev"
|
||||
}
|
||||
});
|
||||
|
||||
stubPackets.set("console.count | test counter: 3", {
|
||||
"from": "server1.conn0.child1/consoleActor2",
|
||||
"type": "consoleAPICall",
|
||||
"message": {
|
||||
"addonId": "",
|
||||
"arguments": [
|
||||
"test counter"
|
||||
],
|
||||
"columnNumber": 5,
|
||||
"counter": {
|
||||
"count": 3,
|
||||
"label": "test counter"
|
||||
},
|
||||
"filename": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html",
|
||||
"functionName": "triggerPacket",
|
||||
"groupName": "",
|
||||
"level": "count",
|
||||
"lineNumber": 9,
|
||||
"private": false,
|
||||
"timeStamp": 1511365913335,
|
||||
"timer": null,
|
||||
"workerType": "none",
|
||||
"styles": [],
|
||||
"category": "webdev"
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = {
|
||||
stubPreparedMessages,
|
||||
stubPackets,
|
||||
|
@ -272,9 +272,7 @@ skip-if = true # Bug 1403907
|
||||
[browser_webconsole_errors_after_page_reload.js]
|
||||
[browser_webconsole_eval_in_debugger_stackframe.js]
|
||||
[browser_webconsole_eval_in_debugger_stackframe2.js]
|
||||
skip-if = true # Bug 1408893
|
||||
[browser_webconsole_execution_scope.js]
|
||||
skip-if = true # Bug 1405333
|
||||
[browser_webconsole_external_script_errors.js]
|
||||
[browser_webconsole_file_uri.js]
|
||||
skip-if = true # Bug 1404382
|
||||
|
@ -10,62 +10,56 @@
|
||||
"use strict";
|
||||
|
||||
const TEST_URI = "http://example.com/browser/devtools/client/webconsole/" +
|
||||
"test/test-eval-in-stackframe.html";
|
||||
"new-console-output/test/mochitest/test-eval-in-stackframe.html";
|
||||
|
||||
// Force the old debugger UI since it's directly used (see Bug 1301705)
|
||||
Services.prefs.setBoolPref("devtools.debugger.new-debugger-frontend", false);
|
||||
registerCleanupFunction(function* () {
|
||||
Services.prefs.clearUserPref("devtools.debugger.new-debugger-frontend");
|
||||
});
|
||||
add_task(async function () {
|
||||
// Force the old debugger UI since it's directly used (see Bug 1301705).
|
||||
await pushPref("devtools.debugger.new-debugger-frontend", false);
|
||||
|
||||
add_task(function* () {
|
||||
yield loadTab(TEST_URI);
|
||||
|
||||
info("open the web console");
|
||||
let hud = yield openConsole();
|
||||
let {jsterm} = hud;
|
||||
info("open the console");
|
||||
const hud = await openNewTabAndConsole(TEST_URI);
|
||||
const {jsterm} = hud;
|
||||
|
||||
info("open the debugger");
|
||||
let {panelWin} = yield openDebugger();
|
||||
let {DebuggerController} = panelWin;
|
||||
let {activeThread} = DebuggerController;
|
||||
let {panel} = await openDebugger();
|
||||
let {activeThread} = panel.panelWin.DebuggerController;
|
||||
|
||||
let firstCall = defer();
|
||||
let frameAdded = defer();
|
||||
executeSoon(() => {
|
||||
info("Executing firstCall");
|
||||
activeThread.addOneTimeListener("framesadded", () => {
|
||||
executeSoon(frameAdded.resolve);
|
||||
});
|
||||
jsterm.execute("firstCall()").then(firstCall.resolve);
|
||||
const onFirstCallFramesAdded = activeThread.addOneTimeListener("framesadded");
|
||||
// firstCall calls secondCall, which has a debugger statement, so we'll be paused.
|
||||
const onFirstCallMessageReceived = waitForMessage(hud, "undefined");
|
||||
|
||||
const unresolvedSymbol = Symbol();
|
||||
let firstCallEvaluationResult = unresolvedSymbol;
|
||||
onFirstCallMessageReceived.then(message => {
|
||||
firstCallEvaluationResult = message;
|
||||
});
|
||||
jsterm.execute("firstCall()");
|
||||
|
||||
info("Waiting for a frame to be added");
|
||||
yield frameAdded.promise;
|
||||
await onFirstCallFramesAdded;
|
||||
|
||||
info("frames added, select the console again");
|
||||
await openConsole();
|
||||
|
||||
info("Executing basic command while paused");
|
||||
yield executeAndConfirm(jsterm, "1 + 2", "3");
|
||||
let onMessageReceived = waitForMessage(hud, "3");
|
||||
jsterm.execute("1 + 2");
|
||||
let message = await onMessageReceived;
|
||||
ok(message, "`1 + 2` was evaluated whith debugger paused");
|
||||
|
||||
info("Executing command using scoped variables while paused");
|
||||
yield executeAndConfirm(jsterm, "foo + foo2",
|
||||
'"globalFooBug783499foo2SecondCall"');
|
||||
onMessageReceived = waitForMessage(hud, `"globalFooBug783499foo2SecondCall"`);
|
||||
jsterm.execute("foo + foo2");
|
||||
message = await onMessageReceived;
|
||||
ok(message, "`foo + foo2` was evaluated as expected with debugger paused");
|
||||
|
||||
info("Checking the first command, which is the last to resolve since it paused");
|
||||
ok(firstCallEvaluationResult === unresolvedSymbol, "firstCall was not evaluated yet");
|
||||
|
||||
info("Resuming the thread");
|
||||
activeThread.resume();
|
||||
|
||||
info("Checking the first command, which is the last to resolve since it " +
|
||||
"paused");
|
||||
let node = yield firstCall.promise;
|
||||
is(node.querySelector(".message-body").textContent,
|
||||
"undefined",
|
||||
"firstCall() returned correct value");
|
||||
message = await onFirstCallMessageReceived;
|
||||
ok(firstCallEvaluationResult !== unresolvedSymbol,
|
||||
"firstCall() returned correct value");
|
||||
});
|
||||
|
||||
function* executeAndConfirm(jsterm, input, output) {
|
||||
info("Executing command `" + input + "`");
|
||||
|
||||
let node = yield jsterm.execute(input);
|
||||
|
||||
is(node.querySelector(".message-body").textContent, output,
|
||||
"Expected result from call to " + input);
|
||||
}
|
||||
|
@ -8,30 +8,20 @@
|
||||
"use strict";
|
||||
|
||||
const TEST_URI = "http://example.com/browser/devtools/client/webconsole/" +
|
||||
"test/test-console.html";
|
||||
"new-console-output/test/mochitest/test-console.html";
|
||||
|
||||
add_task(function* () {
|
||||
yield loadTab(TEST_URI);
|
||||
let hud = yield openConsole();
|
||||
hud.jsterm.clearOutput();
|
||||
hud.jsterm.execute("window.location.href;");
|
||||
add_task(async function () {
|
||||
const hud = await openNewTabAndConsole(TEST_URI);
|
||||
const {jsterm} = hud;
|
||||
jsterm.clearOutput();
|
||||
|
||||
let [input, output] = yield waitForMessages({
|
||||
webconsole: hud,
|
||||
messages: [{
|
||||
text: "window.location.href;",
|
||||
category: CATEGORY_INPUT,
|
||||
},
|
||||
{
|
||||
text: TEST_URI,
|
||||
category: CATEGORY_OUTPUT,
|
||||
}],
|
||||
});
|
||||
const onInputMessage = waitForMessage(hud, "window.location.href;", ".message.command");
|
||||
const onEvaluationResultMessage = waitForMessage(hud, TEST_URI, ".message.result");
|
||||
jsterm.execute("window.location.href;");
|
||||
|
||||
let inputNode = [...input.matched][0];
|
||||
let outputNode = [...output.matched][0];
|
||||
is(inputNode.getAttribute("category"), "input",
|
||||
"input node category is correct");
|
||||
is(outputNode.getAttribute("category"), "output",
|
||||
"output node category is correct");
|
||||
let message = await onInputMessage;
|
||||
ok(message, "Input message is displayed with the expected class");
|
||||
|
||||
message = await onEvaluationResultMessage;
|
||||
ok(message, "EvaluationResult message is displayed with the expected class");
|
||||
});
|
||||
|
@ -698,7 +698,7 @@ describe("Message reducer:", () => {
|
||||
dispatch(actions.networkMessageUpdate(updatePacket.networkInfo));
|
||||
|
||||
let networkUpdates = getAllNetworkMessagesUpdateById(getState());
|
||||
expect(Object.keys(networkUpdates).length).toBe(1);
|
||||
expect(Object.keys(networkUpdates).length > 0).toBe(true);
|
||||
|
||||
dispatch(actions.messagesClear());
|
||||
|
||||
|
@ -18,7 +18,14 @@ describe("Testing UI", () => {
|
||||
|
||||
describe("Toggle sidebar", () => {
|
||||
it("sidebar is toggled on and off", () => {
|
||||
store.dispatch(actions.sidebarClose());
|
||||
const packet = stubPackets.get("inspect({a: 1})");
|
||||
const message = stubPreparedMessages.get("inspect({a: 1})");
|
||||
store.dispatch(actions.messageAdd(packet));
|
||||
|
||||
const actorId = message.parameters[0].actor;
|
||||
const messageId = getFirstMessage(store.getState()).id;
|
||||
store.dispatch(actions.showObjectInSidebar(actorId, messageId));
|
||||
|
||||
expect(store.getState().ui.sidebarVisible).toEqual(true);
|
||||
store.dispatch(actions.sidebarClose());
|
||||
expect(store.getState().ui.sidebarVisible).toEqual(false);
|
||||
@ -27,7 +34,14 @@ describe("Testing UI", () => {
|
||||
|
||||
describe("Hide sidebar on clear", () => {
|
||||
it("sidebar is hidden on clear", () => {
|
||||
store.dispatch(actions.sidebarClose());
|
||||
const packet = stubPackets.get("inspect({a: 1})");
|
||||
const message = stubPreparedMessages.get("inspect({a: 1})");
|
||||
store.dispatch(actions.messageAdd(packet));
|
||||
|
||||
const actorId = message.parameters[0].actor;
|
||||
const messageId = getFirstMessage(store.getState()).id;
|
||||
store.dispatch(actions.showObjectInSidebar(actorId, messageId));
|
||||
|
||||
expect(store.getState().ui.sidebarVisible).toEqual(true);
|
||||
store.dispatch(actions.messagesClear());
|
||||
expect(store.getState().ui.sidebarVisible).toEqual(false);
|
||||
|
@ -14,6 +14,7 @@
|
||||
* [Creating and sending patches](./contributing/making-prs.md)
|
||||
* [Code reviews](./contributing/code-reviews.md)
|
||||
* [Filing good bugs](./contributing/filing-good-bugs.md)
|
||||
* [Investigating performance issues](./contributing/performance.md)
|
||||
* [Bugs and issue trackers](bugs-issues.md)
|
||||
* [Files and directories](files/README.md)
|
||||
* [Adding New Files](files/adding-files.md)
|
||||
|
152
devtools/docs/contributing/performance.md
Normal file
152
devtools/docs/contributing/performance.md
Normal file
@ -0,0 +1,152 @@
|
||||
# Writing efficient code
|
||||
|
||||
When debugging a page, tools get to slow down the website because of the added instrumentation.
|
||||
While working on Developer Tools we should strive to be the less impactful.
|
||||
First, because it is painful to work with laggy UI, but also because some tools record timings.
|
||||
For example, the network monitor records HTTP request timings.
|
||||
If the tools are slowing down Firefox significantly, it will make these measurements be wrong.
|
||||
|
||||
To be efficient while working on performance, you should always focus on one precise user scenario.
|
||||
It could be:
|
||||
* a bug report where someone reports a precise interaction being slow,
|
||||
* or you could be trying to improve overall tools performance by looking at the most common usages.
|
||||
The important point here is to have some steps to reproduce, that you can redo manually in order to record a profile.
|
||||
And also, it is even better if you can replay via a test script. Test script that you can save as a new performance test.
|
||||
|
||||
## Don't guess — profile.
|
||||
|
||||
The very first thing to do is to record a profile while reproducing the scenario.
|
||||
|
||||
Here's the Firefox documentation for [how to install the profiler and record a profile](https://developer.mozilla.org/docs/Mozilla/Performance/Reporting_a_Performance_Problem) and also [how to interpret the profiles](https://developer.mozilla.org/docs/Mozilla/Performance/Profiling_with_the_Built-in_Profiler#Understanding_Profiles)
|
||||
|
||||
There are some peculiarities about DevTools architecture that are worth knowing about when looking at a profile:
|
||||
|
||||
### Tweak profiler default settings
|
||||
|
||||
The default buffer size (9MB) is too small. If you don't increase it, you may easily miss data and only see last couple of seconds of your recording.
|
||||
To increase the buffer size, click on the profiler add-on icon, in the Firefox toolbar, and set it to 360MB, like this:
|
||||
|
||||
<img src="performance/profiler-buffer-size.png" alt="Profiler buffer size" style="width: 300px" />
|
||||
|
||||
The other setting worth mentioning for DevTools debugging is the `Interval`
|
||||
The profiler records only samples, based on this `Interval`.
|
||||
If you want to see more fine-grained stack traces, you may reduce this interval to 0.1ms,
|
||||
but do that only if you really need it, as it will make Firefox much even slower when recording,
|
||||
and the measured times will be even slower.
|
||||
|
||||
### The DevTools UI runs on the parent process
|
||||
|
||||
When you are debugging tool front-ends (e.g. panels), always ensure you select the `Main Thread` line.
|
||||
It should have a light blue background like this:
|
||||
|
||||
<img src="performance/profiler-main-thread.png" alt="Select main process" style="width: 300px" />
|
||||
|
||||
Otherwise, the vast majority of DevTools backend (DebuggerServer, actors, ...) lives in content processes.
|
||||
So if you are debugging them, you should select one of the `Content` lines.
|
||||
|
||||
### Most of the DevTools codebase is in Javascript
|
||||
|
||||
In the call tree, it is easier to filter by `JS`, via this menu list:
|
||||
<img src="performance/profiler-filter-js.png" alt="JS Filtering" style="width: 200px" />
|
||||
|
||||
But note that you may have to switch back to `Combined` in order to understand why some particular Javascript method is slow.
|
||||
|
||||
### Handy filter strings for DevTools:
|
||||
|
||||
* `require`
|
||||
Helps highlighting the cost of module loading
|
||||
![modules](performance/profiler-filter-require.png)
|
||||
* DevTools uses two kind of URLs:
|
||||
* `chrome://devtools/` for all panel documents. Filter with this to see the cost of all panel documents:
|
||||
![panels documents](performance/profiler-chrome-url.png)
|
||||
* `resource://devtools/` for all javascript modules. Filter with this to see the cost of all modules:
|
||||
![modules](performance/profiler-resource-url.png)
|
||||
|
||||
### Record durations manually
|
||||
|
||||
Sometimes it is handy to focus on a very precise piece of code and record its time manually.
|
||||
For example when you identified one slow running method and think you can speed it up.
|
||||
It saves your from having to: record the profile, wait for the profiler to display and search for the precise method durations.
|
||||
|
||||
#### Print durations in your Terminal and in the Browser Console
|
||||
|
||||
You can use the [`Performance`](https://developer.mozilla.org/docs/Web/API/Performance) API, like this:
|
||||
```
|
||||
let start = window.performance.now();
|
||||
|
||||
// Run the code you want to measure
|
||||
|
||||
// Once it is done, do:
|
||||
console.log("my function took", window.performance.now() - start, "ms");
|
||||
```
|
||||
|
||||
#### Use markers
|
||||
|
||||
The Performance API also allows recording markers, like this:
|
||||
```
|
||||
window.performance.mark("my-function-start");
|
||||
|
||||
// Run the code you want to measure
|
||||
|
||||
// Once it is done, do:
|
||||
window.performance.measure("my-function", "my-function-start");
|
||||
```
|
||||
|
||||
This marker will appear in the `Marker Chart` section in perf-html, in the `UserTiming` lines:
|
||||
![custom markers](performance/profiler-custom-markers.png)
|
||||
|
||||
You can double click on it to make perf-html display the record during this precise moment in time,
|
||||
and the call tree will only display what was executed during this measurement.
|
||||
|
||||
### Prototype quickly
|
||||
|
||||
Sometimes the best way to find what is slow is to comment blocks of code out
|
||||
and uncomment them one by one until you identify the culprit. And then focus on it.
|
||||
|
||||
There are few things worse than spending a long time refactoring the piece of code that was not slow to begin with!
|
||||
|
||||
## Assess your improvement.
|
||||
|
||||
Once you have a patch that you think improves the performance, you have to assess whether it actually improves it.
|
||||
|
||||
### Record another profile
|
||||
|
||||
Compare the two profiles, without and with your patch.
|
||||
Then see if the call tree reports a significant difference:
|
||||
* A function call completely disappears in the new profile, with your fix.
|
||||
For example you were loading a big module, and you got a frame for `require("my/big/module")` call, and no longer see it.
|
||||
* The same function call takes xxx ms less with your patch.
|
||||
|
||||
This [lazy loading of modules in netmonitor](https://bugzilla.mozilla.org/show_bug.cgi?id=1420289) is a good example.
|
||||
Without this patch, App.js was loading in 91ms and was loading MonitorPanel.js and StatisticsPanel.js as dependencies:
|
||||
![netmonitor without patch](performance/profiler-netmonitor-open.png)
|
||||
|
||||
With the patch, App.js loads in 47ms and only loads MonitorPanel.js:
|
||||
![netmonitor with patch](performance/profiler-netmon-open-fixed.png)
|
||||
|
||||
It highlights that:
|
||||
* we no longer load StatisticsPanel,
|
||||
* App is faster to load.
|
||||
|
||||
### Run performance tests
|
||||
|
||||
See if any subtest reports a improvement. Ensure that the improvement makes any sense.
|
||||
For example, if the test is 50% faster, maybe you broke the performance test.
|
||||
This might happen if the test no longer waits for all the operations to finish executing before completing.
|
||||
|
||||
To push your current patch to try, execute:
|
||||
```
|
||||
./mach try -b o -p linux64 -u none -t g2-e10s --rebuild-talos 5 --artifact
|
||||
```
|
||||
It will print in your Terminal a link to perfherder like this one:
|
||||
[https://treeherder.mozilla.org/perf.html#/comparechooser?newProject=try&newRevision=9bef6cb13c43bbce21d40ffaea595e082a4c28db](https://treeherder.mozilla.org/perf.html#/comparechooser?newProject=try&newRevision=9bef6cb13c43bbce21d40ffaea595e082a4c28db)
|
||||
Running performance tests takes time, so you should open it 30 minutes up to 2 hours later to see your results.
|
||||
See [Performance tests (DAMP)](../tests/performance-tests.md) for more information about PerfHerder/try.
|
||||
|
||||
Let's look at how to interpret an actual real-life [set of perfherder results](https://treeherder.mozilla.org/perf.html#/comparesubtest?originalProject=mozilla-central&newProject=try&newRevision=9bef6cb13c43bbce21d40ffaea595e082a4c28db&originalSignature=edaec66500db21d37602c99daa61ac983f21a6ac&newSignature=edaec66500db21d37602c99daa61ac983f21a6ac&showOnlyImportant=1&framework=1&selectedTimeRange=172800):
|
||||
|
||||
![perfherder results](performance/perfherder-results.png)
|
||||
|
||||
These results are related to [lazy loading of modules in netmonitor](https://bugzilla.mozilla.org/show_bug.cgi?id=1420289).
|
||||
It is interesting to see that this patch is a trade-off. It makes netmonitor opening significantly faster, by preventing loading many modules during its opening.
|
||||
But it makes the page reload a bit slower as some modules that used to be loaded during netmonitor open, now have to be loaded during page reload.
|
@ -423,6 +423,12 @@ var StyleSheetActor = protocol.ActorClassWithSpec(styleSheetSpec, {
|
||||
* If an error occurs, the promise is rejected with that error.
|
||||
*/
|
||||
fetchStylesheet: Task.async(function* (href) {
|
||||
// Check if network monitor observed this load, and if so, use that.
|
||||
let result = this.fetchStylesheetFromNetworkMonitor(href);
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
|
||||
let options = {
|
||||
loadFromCache: true,
|
||||
policy: Ci.nsIContentPolicy.TYPE_INTERNAL_STYLESHEET,
|
||||
@ -442,7 +448,6 @@ var StyleSheetActor = protocol.ActorClassWithSpec(styleSheetSpec, {
|
||||
options.principal = this.ownerDocument.nodePrincipal;
|
||||
}
|
||||
|
||||
let result;
|
||||
try {
|
||||
result = yield fetch(this.href, options);
|
||||
} catch (e) {
|
||||
@ -458,6 +463,43 @@ var StyleSheetActor = protocol.ActorClassWithSpec(styleSheetSpec, {
|
||||
return result;
|
||||
}),
|
||||
|
||||
/**
|
||||
* Try to locate the console actor if it exists via our parent actor (the tab).
|
||||
*/
|
||||
get _consoleActor() {
|
||||
if (this.parentActor.exited) {
|
||||
return null;
|
||||
}
|
||||
let form = this.parentActor.form();
|
||||
return this.conn._getOrCreateActor(form.consoleActor);
|
||||
},
|
||||
|
||||
/**
|
||||
* Try to fetch the stylesheet text from the network monitor. If it was enabled during
|
||||
* the load, it should have a copy of the text saved.
|
||||
*
|
||||
* @param string href
|
||||
* The URL of the sheet to fetch.
|
||||
*/
|
||||
fetchStylesheetFromNetworkMonitor(href) {
|
||||
let consoleActor = this._consoleActor;
|
||||
if (!consoleActor) {
|
||||
return null;
|
||||
}
|
||||
let request = consoleActor.getNetworkEventActorForURL(href);
|
||||
if (!request) {
|
||||
return null;
|
||||
}
|
||||
let content = request._response.content;
|
||||
if (request._discardResponseBody || !content) {
|
||||
return null;
|
||||
}
|
||||
return {
|
||||
content: content.text,
|
||||
contentType: content.mimeType,
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* Protocol method to get the media rules for the stylesheet.
|
||||
*/
|
||||
|
@ -68,6 +68,7 @@ function WebConsoleActor(connection, parentActor) {
|
||||
this.dbg = this.parentActor.makeDebugger();
|
||||
|
||||
this._netEvents = new Map();
|
||||
this._networkEventActorsByURL = new Map();
|
||||
this._gripDepth = 0;
|
||||
this._listeners = new Set();
|
||||
this._lastConsoleInputEvaluation = undefined;
|
||||
@ -124,13 +125,23 @@ WebConsoleActor.prototype =
|
||||
|
||||
/**
|
||||
* Holds a map between nsIChannel objects and NetworkEventActors for requests
|
||||
* created with sendHTTPRequest.
|
||||
* created with sendHTTPRequest or found via the network listener.
|
||||
*
|
||||
* @private
|
||||
* @type Map
|
||||
*/
|
||||
_netEvents: null,
|
||||
|
||||
/**
|
||||
* Holds a map from URL to NetworkEventActors for requests noticed by the network
|
||||
* listener. Requests are added when they start, so the actor might not yet have all
|
||||
* data for the request until it has completed.
|
||||
*
|
||||
* @private
|
||||
* @type Map
|
||||
*/
|
||||
_networkEventActorsByURL: null,
|
||||
|
||||
/**
|
||||
* Holds a set of all currently registered listeners.
|
||||
*
|
||||
@ -1632,6 +1643,8 @@ WebConsoleActor.prototype =
|
||||
let actor = this.getNetworkEventActor(event.channelId);
|
||||
actor.init(event);
|
||||
|
||||
this._networkEventActorsByURL.set(actor._request.url, actor);
|
||||
|
||||
let packet = {
|
||||
from: this.actorID,
|
||||
type: "networkEvent",
|
||||
@ -1665,6 +1678,18 @@ WebConsoleActor.prototype =
|
||||
return actor;
|
||||
},
|
||||
|
||||
/**
|
||||
* Get the NetworkEventActor for a given URL that may have been noticed by the network
|
||||
* listener. Requests are added when they start, so the actor might not yet have all
|
||||
* data for the request until it has completed.
|
||||
*
|
||||
* @param string url
|
||||
* The URL of the request to search for.
|
||||
*/
|
||||
getNetworkEventActorForURL(url) {
|
||||
return this._networkEventActorsByURL.get(url);
|
||||
},
|
||||
|
||||
/**
|
||||
* Send a new HTTP request from the target's window.
|
||||
*
|
||||
@ -1992,6 +2017,9 @@ NetworkEventActor.prototype =
|
||||
}
|
||||
this._longStringActors = new Set();
|
||||
|
||||
if (this._request.url) {
|
||||
this.parent._networkEventActorsByURL.delete(this._request.url);
|
||||
}
|
||||
if (this.channel) {
|
||||
this.parent._netEvents.delete(this.channel);
|
||||
}
|
||||
|
@ -2685,7 +2685,7 @@ Element::SetAttrAndNotify(int32_t aNamespaceID,
|
||||
// Copy aParsedValue for later use since it will be lost when we call
|
||||
// SetAndSwapMappedAttr below
|
||||
nsAttrValue valueForAfterSetAttr;
|
||||
if (aCallAfterSetAttr) {
|
||||
if (aCallAfterSetAttr || GetCustomElementData()) {
|
||||
valueForAfterSetAttr.SetTo(aParsedValue);
|
||||
}
|
||||
|
||||
|
@ -86,7 +86,7 @@ nsStyledElement::SetInlineStyleDeclaration(DeclarationBlock* aDeclaration,
|
||||
// getting a new stylerule here. And we can't compare the stringvalues of
|
||||
// the old and the new rules since both will point to the same declaration
|
||||
// and thus will be the same.
|
||||
if (hasListeners) {
|
||||
if (hasListeners || GetCustomElementData()) {
|
||||
// save the old attribute so we can set up the mutation event properly
|
||||
nsAutoString oldValueStr;
|
||||
modification = GetAttr(kNameSpaceID_None, nsGkAtoms::style,
|
||||
|
@ -28,7 +28,7 @@ def generate(output, idlFilename, preprocessorHeader):
|
||||
continue
|
||||
# Unfortunately, even some of the getters here are fallible
|
||||
# (e.g. on nsComputedDOMStyle).
|
||||
extendedAttrs = ["Throws", "TreatNullAs=EmptyString",
|
||||
extendedAttrs = ["CEReactions", "Throws", "TreatNullAs=EmptyString",
|
||||
"SetterNeedsSubjectPrincipal=NonSystem"]
|
||||
if pref is not "":
|
||||
extendedAttrs.append('Pref="%s"' % pref)
|
||||
|
@ -1364,6 +1364,7 @@ OggTrackDemuxer::NextSample()
|
||||
// This will also update mSharedAudioTrackInfo.
|
||||
mParent->ReadOggChain(data->GetEndTime());
|
||||
}
|
||||
data->mOffset = mParent->Resource(mType)->Tell();
|
||||
// We adjust the start time of the sample to account for the potential ogg chaining.
|
||||
data->mTime += totalDuration;
|
||||
return data;
|
||||
|
@ -292,6 +292,48 @@ function testAttributeChangedExtended() {
|
||||
elem.setAttribute("foo", "bar");
|
||||
}
|
||||
|
||||
function testStyleAttributeChange() {
|
||||
var expectedCallbackArguments = [
|
||||
// [name, oldValue, newValue]
|
||||
// This is an additional attributeChangedCallback from *first* style
|
||||
// attribute change, see https://bugzilla.mozilla.org/show_bug.cgi?id=1428246.
|
||||
["style", null, ""],
|
||||
["style", "", "font-size: 10px;"],
|
||||
["style", "font-size: 10px;", "font-size: 20px;"],
|
||||
["style", "font-size: 20px;", "font-size: 30px;"],
|
||||
];
|
||||
|
||||
customElements.define("x-style-attribute-change", class extends HTMLElement {
|
||||
attributeChangedCallback(name, oldValue, newValue) {
|
||||
if (expectedCallbackArguments.length === 0) {
|
||||
ok(false, "Got unexpected attributeChangedCallback?");
|
||||
return;
|
||||
}
|
||||
|
||||
let expectedArgument = expectedCallbackArguments.shift();
|
||||
is(name, expectedArgument[0],
|
||||
"The name argument should match the expected value.");
|
||||
is(oldValue, expectedArgument[1],
|
||||
"The old value argument should match the expected value.");
|
||||
is(newValue, expectedArgument[2],
|
||||
"The new value argument should match the expected value.");
|
||||
}
|
||||
|
||||
static get observedAttributes() {
|
||||
return ["style"];
|
||||
}
|
||||
});
|
||||
|
||||
var elem = document.createElement("x-style-attribute-change");
|
||||
elem.style.fontSize = "10px";
|
||||
elem.style.fontSize = "20px";
|
||||
elem.style.fontSize = "30px";
|
||||
|
||||
ok(expectedCallbackArguments.length === 0,
|
||||
"The attributeChangedCallback should be fired synchronously.");
|
||||
runNextTest();
|
||||
}
|
||||
|
||||
// Creates a custom element that is an upgrade candidate (no registration)
|
||||
// and mutate the element in ways that would call callbacks for registered
|
||||
// elements.
|
||||
@ -368,6 +410,7 @@ var testFunctions = [
|
||||
testRegisterResolved,
|
||||
testAttributeChanged,
|
||||
testAttributeChangedExtended,
|
||||
testStyleAttributeChange,
|
||||
testUpgradeCandidate,
|
||||
testChangingCallback,
|
||||
testNotInDocEnterLeave,
|
||||
|
@ -107,7 +107,9 @@ ExpectedOwnerForChild(const nsIFrame& aFrame)
|
||||
// Handle :-moz-table and :-moz-inline-table.
|
||||
parent = IsAnonBox(*tableFrame) ? parent->GetParent() : tableFrame;
|
||||
} else {
|
||||
parent = parent->GetParent();
|
||||
// We get the in-flow parent here so that we can handle the OOF anonymous
|
||||
// boxed to get the correct parent.
|
||||
parent = parent->GetInFlowParent();
|
||||
}
|
||||
parent = FirstContinuationOrPartOfIBSplit(parent);
|
||||
}
|
||||
|
@ -1099,7 +1099,10 @@ GetDisplayPortFromMarginsData(nsIContent* aContent,
|
||||
int32_t budget = maxHeightScreenPx - screenRect.height;
|
||||
// Scale the margins down to fit into the budget if necessary, maintaining
|
||||
// their relative ratio.
|
||||
float scale = std::min(1.0f, float(budget) / margins.TopBottom());
|
||||
float scale = 1.0f;
|
||||
if (float(budget) < margins.TopBottom()) {
|
||||
scale = float(budget) / margins.TopBottom();
|
||||
}
|
||||
float top = margins.top * scale;
|
||||
float bottom = margins.bottom * scale;
|
||||
screenRect.y -= top;
|
||||
@ -1107,7 +1110,10 @@ GetDisplayPortFromMarginsData(nsIContent* aContent,
|
||||
}
|
||||
if (screenRect.width < maxWidthScreenPx) {
|
||||
int32_t budget = maxWidthScreenPx - screenRect.width;
|
||||
float scale = std::min(1.0f, float(budget) / margins.LeftRight());
|
||||
float scale = 1.0f;
|
||||
if (float(budget) < margins.LeftRight()) {
|
||||
scale = float(budget) / margins.LeftRight();
|
||||
}
|
||||
float left = margins.left * scale;
|
||||
float right = margins.right * scale;
|
||||
screenRect.x -= left;
|
||||
|
@ -888,7 +888,7 @@ public:
|
||||
* Gets the parent of a frame, using the parent of the placeholder for
|
||||
* out-of-flow frames.
|
||||
*/
|
||||
inline nsContainerFrame* GetInFlowParent();
|
||||
inline nsContainerFrame* GetInFlowParent() const;
|
||||
|
||||
/**
|
||||
* Gets the primary frame of the Content's flattened tree
|
||||
|
@ -170,7 +170,7 @@ nsIFrame::PropagateRootElementWritingMode(mozilla::WritingMode aRootElemWM)
|
||||
}
|
||||
|
||||
nsContainerFrame*
|
||||
nsIFrame::GetInFlowParent()
|
||||
nsIFrame::GetInFlowParent() const
|
||||
{
|
||||
if (GetStateBits() & NS_FRAME_OUT_OF_FLOW) {
|
||||
nsIFrame* ph = FirstContinuation()->GetProperty(nsIFrame::PlaceholderFrameProperty());
|
||||
|
@ -1786,6 +1786,7 @@ public abstract class GeckoApp extends GeckoActivity
|
||||
});
|
||||
} else if (Intent.ACTION_ASSIST.equals(action)) {
|
||||
Tabs.getInstance().addTab(Tabs.LOADURL_START_EDITING | Tabs.LOADURL_EXTERNAL);
|
||||
autoHideTabs();
|
||||
} else if (ACTION_HOMESCREEN_SHORTCUT.equals(action)) {
|
||||
final GeckoBundle data = new GeckoBundle(2);
|
||||
data.putString("uri", uri);
|
||||
|
@ -260,7 +260,6 @@ pub unsafe fn new_rt_and_cx() -> Runtime {
|
||||
if let Some(val) = PREFS.get("js.mem.gc.dynamic_mark_slice.enabled").as_boolean() {
|
||||
JS_SetGCParameter(runtime.rt(), JSGCParamKey::JSGC_DYNAMIC_MARK_SLICE, val as u32);
|
||||
}
|
||||
// TODO: handle js.mem.gc.refresh_frame_slices.enabled
|
||||
if let Some(val) = PREFS.get("js.mem.gc.dynamic_heap_growth.enabled").as_boolean() {
|
||||
JS_SetGCParameter(runtime.rt(), JSGCParamKey::JSGC_DYNAMIC_HEAP_GROWTH, val as u32);
|
||||
}
|
||||
|
@ -45,7 +45,6 @@
|
||||
"js.mem.gc.incremental.slice_ms": 10,
|
||||
"js.mem.gc.low_frequency_heap_growth": 150,
|
||||
"js.mem.gc.per_compartment.enabled": true,
|
||||
"js.mem.gc.refresh_frame_slices.enabled": true,
|
||||
"js.mem.gc.zeal.frequency": 100,
|
||||
"js.mem.gc.zeal.level": 0,
|
||||
"js.mem.high_water_mark": 128,
|
||||
|
@ -35,6 +35,8 @@ jobs:
|
||||
symbol: I(idx)
|
||||
funsize-update-generator:
|
||||
symbol: I(pg)
|
||||
google-play-strings:
|
||||
symbol: I(gps)
|
||||
funsize-balrog-submitter:
|
||||
symbol: I(fbs)
|
||||
beet-mover:
|
||||
|
54
taskcluster/ci/google-play-strings/kind.yml
Normal file
54
taskcluster/ci/google-play-strings/kind.yml
Normal file
@ -0,0 +1,54 @@
|
||||
# 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/.
|
||||
|
||||
loader: taskgraph.loader.transform:loader
|
||||
|
||||
transforms:
|
||||
- taskgraph.transforms.google_play_strings:transforms
|
||||
- taskgraph.transforms.task:transforms
|
||||
|
||||
jobs:
|
||||
google-play-strings:
|
||||
description: Download strings to display on Google Play from https://l10n.mozilla-community.org/stores_l10n/
|
||||
attributes:
|
||||
build_type: google_play_strings
|
||||
build_platform: android-nightly
|
||||
nightly: true
|
||||
shipping-phase: promote
|
||||
shipping-product: fennec
|
||||
worker-type: aws-provisioner-v1/gecko-{level}-b-android
|
||||
worker:
|
||||
implementation: docker-worker
|
||||
os: linux
|
||||
docker-image: {in-tree: google-play-strings}
|
||||
chain-of-trust: true
|
||||
max-run-time: 600
|
||||
artifacts:
|
||||
- name: 'public/google_play_strings.json'
|
||||
# XXX The folder depends on the one defined in the Dockerfile
|
||||
path: /builds/worker/google_play_strings.json
|
||||
type: 'file'
|
||||
env:
|
||||
# TODO Use the branch name instead of the android package name
|
||||
PACKAGE_NAME:
|
||||
by-project:
|
||||
mozilla-central: org.mozilla.fennec_aurora
|
||||
mozilla-beta: org.mozilla.firefox_beta
|
||||
mozilla-release: org.mozilla.firefox_beta
|
||||
default: org.mozilla.fennec_aurora # Fetches strings for mozilla-central
|
||||
# XXX The folder depends on the one defined in the Dockerfile
|
||||
GOOGLE_PLAY_STRING_FILE: /builds/worker/google_play_strings.json
|
||||
command:
|
||||
- bash
|
||||
- -cx
|
||||
- >
|
||||
python3 ./mozapkpublisher/get_l10n_strings.py
|
||||
--package-name "${PACKAGE_NAME}"
|
||||
--output-file "${GOOGLE_PLAY_STRING_FILE}"
|
||||
treeherder:
|
||||
symbol: pub(gps)
|
||||
platform: Android/opt
|
||||
tier: 2
|
||||
kind: other
|
||||
run-on-projects: ['maple', 'mozilla-central', 'mozilla-beta', 'mozilla-release']
|
@ -5,39 +5,39 @@
|
||||
loader: taskgraph.loader.push_apk:loader
|
||||
|
||||
transforms:
|
||||
- taskgraph.transforms.push_apk:transforms
|
||||
- taskgraph.transforms.task:transforms
|
||||
- taskgraph.transforms.push_apk:transforms
|
||||
- taskgraph.transforms.task:transforms
|
||||
|
||||
kind-dependencies:
|
||||
- build-signing
|
||||
- push-apk-breakpoint
|
||||
- build-signing
|
||||
- google-play-strings
|
||||
- push-apk-breakpoint
|
||||
|
||||
jobs:
|
||||
push-apk/opt:
|
||||
description: Publishes APK onto Google Play Store
|
||||
attributes:
|
||||
build_platform: android-nightly
|
||||
nightly: true
|
||||
shipping-phase: ship
|
||||
shipping-product: fennec
|
||||
worker-type:
|
||||
by-project:
|
||||
mozilla-central: scriptworker-prov-v1/pushapk-v1
|
||||
mozilla-beta: scriptworker-prov-v1/pushapk-v1
|
||||
mozilla-release: scriptworker-prov-v1/pushapk-v1
|
||||
default: scriptworker-prov-v1/dep-pushapk
|
||||
worker:
|
||||
upstream-artifacts: # see transforms
|
||||
google-play-track: # see transforms
|
||||
implementation: push-apk
|
||||
commit: # see transforms
|
||||
scopes: # see transforms
|
||||
treeherder:
|
||||
symbol: pub(gp)
|
||||
platform: Android/opt
|
||||
tier: 2
|
||||
kind: other
|
||||
run-on-projects: ['mozilla-central', 'mozilla-beta', 'mozilla-release']
|
||||
deadline-after: 5 days
|
||||
extra:
|
||||
product: fennec
|
||||
push-apk/opt:
|
||||
description: Publishes APK onto Google Play Store
|
||||
attributes:
|
||||
build_platform: android-nightly
|
||||
nightly: true
|
||||
shipping-phase: ship
|
||||
shipping-product: fennec
|
||||
worker-type:
|
||||
by-project:
|
||||
mozilla-central: scriptworker-prov-v1/pushapk-v1
|
||||
mozilla-beta: scriptworker-prov-v1/pushapk-v1
|
||||
mozilla-release: scriptworker-prov-v1/pushapk-v1
|
||||
default: scriptworker-prov-v1/dep-pushapk
|
||||
worker:
|
||||
upstream-artifacts: # see transforms
|
||||
google-play-track: # see transforms
|
||||
implementation: push-apk
|
||||
commit: # see transforms
|
||||
requires: all-resolved
|
||||
scopes: # see transforms
|
||||
treeherder:
|
||||
symbol: pub(gp)
|
||||
platform: Android/opt
|
||||
tier: 2
|
||||
kind: other
|
||||
run-on-projects: ['mozilla-central', 'mozilla-beta', 'mozilla-release', 'maple']
|
||||
deadline-after: 5 days
|
||||
|
@ -3,6 +3,7 @@ version: @VERSION@-@BUILD_NUMBER@
|
||||
summary: Mozilla Firefox web browser
|
||||
description: Firefox is a powerful, extensible web browser with support for modern web application technologies.
|
||||
confinement: strict
|
||||
grade: stable
|
||||
|
||||
apps:
|
||||
firefox:
|
||||
@ -11,8 +12,10 @@ apps:
|
||||
environment:
|
||||
DISABLE_WAYLAND: 1
|
||||
plugs:
|
||||
- avahi-observe
|
||||
- browser-sandbox
|
||||
- camera
|
||||
- cups-control
|
||||
- desktop
|
||||
- desktop-legacy
|
||||
- gsettings
|
||||
@ -41,4 +44,7 @@ parts:
|
||||
- libgl1-mesa-dri
|
||||
- libgl1-mesa-glx
|
||||
- libmirclient9
|
||||
- desktop-file-utils
|
||||
- xdg-utils
|
||||
- ffmpeg
|
||||
after: [desktop-gtk3]
|
||||
|
@ -2,4 +2,6 @@ mar==2.1.2
|
||||
backports.lzma==0.0.8
|
||||
datadog==0.17.0
|
||||
redo==1.6
|
||||
aiohttp==2.3.6
|
||||
awscli==1.14.10
|
||||
scriptworker==6.0.0
|
||||
|
@ -18,7 +18,8 @@ curl --location --retry 10 --retry-delay 10 -o /home/worker/task.json \
|
||||
S3_BUCKET_AND_PATH=$(jq -r '.scopes[] | select(contains ("auth:aws-s3"))' /home/worker/task.json | awk -F: '{print $4}')
|
||||
|
||||
# Will be empty if there's no scope for AWS S3.
|
||||
if [ -n "${S3_BUCKET_AND_PATH}" ]; then
|
||||
if [ -n "${S3_BUCKET_AND_PATH}" ] && getent hosts taskcluster
|
||||
then
|
||||
# Does this parse as we expect?
|
||||
S3_PATH=${S3_BUCKET_AND_PATH#*/}
|
||||
AWS_BUCKET_NAME=${S3_BUCKET_AND_PATH%/${S3_PATH}*}
|
||||
|
@ -5,6 +5,8 @@
|
||||
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
import asyncio
|
||||
import aiohttp
|
||||
import configparser
|
||||
import argparse
|
||||
import hashlib
|
||||
@ -18,6 +20,7 @@ import requests
|
||||
import sh
|
||||
|
||||
import redo
|
||||
from scriptworker.utils import retry_async
|
||||
from mardor.reader import MarReader
|
||||
from mardor.signing import get_keysize
|
||||
|
||||
@ -25,6 +28,12 @@ from datadog import initialize, ThreadStats
|
||||
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
# Create this even when not sending metrics, so the context manager
|
||||
# statements work.
|
||||
ddstats = ThreadStats(namespace='releng.releases.partials')
|
||||
|
||||
|
||||
ALLOWED_URL_PREFIXES = [
|
||||
"http://download.cdn.mozilla.net/pub/mozilla.org/firefox/nightly/",
|
||||
"http://download.cdn.mozilla.net/pub/firefox/nightly/",
|
||||
@ -71,48 +80,87 @@ def get_secret(secret_name):
|
||||
return r.json().get('secret', {})
|
||||
|
||||
|
||||
@redo.retriable()
|
||||
def download(url, dest, mode=None):
|
||||
log.debug("Downloading %s to %s", url, dest)
|
||||
r = requests.get(url)
|
||||
r.raise_for_status()
|
||||
async def retry_download(*args, **kwargs): # noqa: E999
|
||||
"""Retry download() calls."""
|
||||
await retry_async(
|
||||
download,
|
||||
retry_exceptions=(
|
||||
aiohttp.ClientError
|
||||
),
|
||||
args=args,
|
||||
kwargs=kwargs
|
||||
)
|
||||
|
||||
|
||||
async def download(url, dest, mode=None): # noqa: E999
|
||||
log.info("Downloading %s to %s", url, dest)
|
||||
|
||||
bytes_downloaded = 0
|
||||
with open(dest, 'wb') as fd:
|
||||
for chunk in r.iter_content(4096):
|
||||
fd.write(chunk)
|
||||
bytes_downloaded += len(chunk)
|
||||
|
||||
log.debug('Downloaded %s bytes', bytes_downloaded)
|
||||
if 'content-length' in r.headers:
|
||||
log.debug('Content-Length: %s bytes', r.headers['content-length'])
|
||||
if bytes_downloaded != int(r.headers['content-length']):
|
||||
raise IOError('Unexpected number of bytes downloaded')
|
||||
async with aiohttp.ClientSession(raise_for_status=True) as session:
|
||||
async with session.get(url) as resp:
|
||||
with open(dest, 'wb') as fd:
|
||||
while True:
|
||||
chunk = await resp.content.read(4096)
|
||||
if not chunk:
|
||||
break
|
||||
fd.write(chunk)
|
||||
bytes_downloaded += len(chunk)
|
||||
|
||||
if mode:
|
||||
log.debug("chmod %o %s", mode, dest)
|
||||
os.chmod(dest, mode)
|
||||
log.debug('Downloaded %s bytes', bytes_downloaded)
|
||||
if 'content-length' in resp.headers:
|
||||
log.debug('Content-Length: %s bytes', resp.headers['content-length'])
|
||||
if bytes_downloaded != int(resp.headers['content-length']):
|
||||
raise IOError('Unexpected number of bytes downloaded')
|
||||
|
||||
if mode:
|
||||
log.debug("chmod %o %s", mode, dest)
|
||||
os.chmod(dest, mode)
|
||||
|
||||
|
||||
def unpack(work_env, mar, dest_dir):
|
||||
async def run_command(cmd, cwd='/', env=None, label=None, silent=False):
|
||||
if not env:
|
||||
env = dict()
|
||||
process = await asyncio.create_subprocess_shell(cmd,
|
||||
stdout=asyncio.subprocess.PIPE,
|
||||
stderr=asyncio.subprocess.STDOUT,
|
||||
cwd=cwd, env=env)
|
||||
stdout, stderr = await process.communicate()
|
||||
|
||||
await process.wait()
|
||||
|
||||
if silent:
|
||||
return
|
||||
|
||||
if not stderr:
|
||||
stderr = ""
|
||||
if not stdout:
|
||||
stdout = ""
|
||||
|
||||
label = "{}: ".format(label)
|
||||
|
||||
for line in stdout.splitlines():
|
||||
log.debug("%s%s", label, line.decode('utf-8'))
|
||||
for line in stderr.splitlines():
|
||||
log.warn("%s%s", label, line.decode('utf-8'))
|
||||
|
||||
|
||||
async def unpack(work_env, mar, dest_dir):
|
||||
os.mkdir(dest_dir)
|
||||
unwrap_cmd = sh.Command(os.path.join(work_env.workdir,
|
||||
"unwrap_full_update.pl"))
|
||||
log.debug("Unwrapping %s", mar)
|
||||
env = work_env.env
|
||||
if not is_lzma_compressed_mar(mar):
|
||||
env['MAR_OLD_FORMAT'] = '1'
|
||||
elif 'MAR_OLD_FORMAT' in env:
|
||||
del env['MAR_OLD_FORMAT']
|
||||
out = unwrap_cmd(mar, _cwd=dest_dir, _env=env, _timeout=240,
|
||||
_err_to_out=True)
|
||||
if out:
|
||||
log.debug(out)
|
||||
|
||||
cmd = "{} {}".format(work_env.paths['unwrap_full_update.pl'], mar)
|
||||
await run_command(cmd, cwd=dest_dir, env=env, label=dest_dir)
|
||||
|
||||
|
||||
def find_file(directory, filename):
|
||||
log.debug("Searching for %s in %s", filename, directory)
|
||||
for root, dirs, files in os.walk(directory):
|
||||
for root, _, files in os.walk(directory):
|
||||
if filename in files:
|
||||
f = os.path.join(root, filename)
|
||||
log.debug("Found %s", f)
|
||||
@ -120,7 +168,7 @@ def find_file(directory, filename):
|
||||
|
||||
|
||||
def get_option(directory, filename, section, option):
|
||||
log.debug("Exctracting [%s]: %s from %s/**/%s", section, option, directory,
|
||||
log.debug("Extracting [%s]: %s from %s/**/%s", section, option, directory,
|
||||
filename)
|
||||
f = find_file(directory, filename)
|
||||
config = configparser.ConfigParser()
|
||||
@ -130,9 +178,9 @@ def get_option(directory, filename, section, option):
|
||||
return rv
|
||||
|
||||
|
||||
def generate_partial(work_env, from_dir, to_dir, dest_mar, channel_ids,
|
||||
version, use_old_format):
|
||||
log.debug("Generating partial %s", dest_mar)
|
||||
async def generate_partial(work_env, from_dir, to_dir, dest_mar, channel_ids,
|
||||
version, use_old_format):
|
||||
log.info("Generating partial %s", dest_mar)
|
||||
env = work_env.env
|
||||
env["MOZ_PRODUCT_VERSION"] = version
|
||||
env["MOZ_CHANNEL_ID"] = channel_ids
|
||||
@ -142,11 +190,9 @@ def generate_partial(work_env, from_dir, to_dir, dest_mar, channel_ids,
|
||||
del env['MAR_OLD_FORMAT']
|
||||
make_incremental_update = os.path.join(work_env.workdir,
|
||||
"make_incremental_update.sh")
|
||||
out = sh.bash(make_incremental_update, dest_mar, from_dir, to_dir,
|
||||
_cwd=work_env.workdir, _env=env, _timeout=900,
|
||||
_err_to_out=True)
|
||||
if out:
|
||||
log.debug(out)
|
||||
cmd = " ".join([make_incremental_update, dest_mar, from_dir, to_dir])
|
||||
|
||||
await run_command(cmd, cwd=work_env.workdir, env=env, label=dest_mar.split('/')[-1])
|
||||
|
||||
|
||||
def get_hash(path, hash_type="sha512"):
|
||||
@ -160,32 +206,42 @@ class WorkEnv(object):
|
||||
|
||||
def __init__(self):
|
||||
self.workdir = tempfile.mkdtemp()
|
||||
self.paths = {
|
||||
'unwrap_full_update.pl': os.path.join(self.workdir, 'unwrap_full_update.pl'),
|
||||
'mar': os.path.join(self.workdir, 'mar'),
|
||||
'mbsdiff': os.path.join(self.workdir, 'mbsdiff')
|
||||
}
|
||||
|
||||
def setup(self):
|
||||
self.download_unwrap()
|
||||
self.download_martools()
|
||||
async def setup(self):
|
||||
await self.download_unwrap()
|
||||
await self.download_martools()
|
||||
|
||||
def download_unwrap(self):
|
||||
async def clone(self, workenv):
|
||||
for path in workenv.paths:
|
||||
if os.path.exists(self.paths[path]):
|
||||
os.unlink(self.paths[path])
|
||||
os.link(workenv.paths[path], self.paths[path])
|
||||
|
||||
async def download_unwrap(self):
|
||||
# unwrap_full_update.pl is not too sensitive to the revision
|
||||
url = "https://hg.mozilla.org/mozilla-central/raw-file/default/" \
|
||||
"tools/update-packaging/unwrap_full_update.pl"
|
||||
download(url, dest=os.path.join(self.workdir, "unwrap_full_update.pl"),
|
||||
mode=0o755)
|
||||
await retry_download(url, dest=self.paths['unwrap_full_update.pl'], mode=0o755)
|
||||
|
||||
def download_buildsystem_bits(self, repo, revision):
|
||||
async def download_buildsystem_bits(self, repo, revision):
|
||||
prefix = "{repo}/raw-file/{revision}/tools/update-packaging"
|
||||
prefix = prefix.format(repo=repo, revision=revision)
|
||||
for f in ("make_incremental_update.sh", "common.sh"):
|
||||
for f in ('make_incremental_update.sh', 'common.sh'):
|
||||
url = "{prefix}/{f}".format(prefix=prefix, f=f)
|
||||
download(url, dest=os.path.join(self.workdir, f), mode=0o755)
|
||||
await retry_download(url, dest=os.path.join(self.workdir, f), mode=0o755)
|
||||
|
||||
def download_martools(self):
|
||||
async def download_martools(self):
|
||||
# TODO: check if the tools have to be branch specific
|
||||
prefix = "https://ftp.mozilla.org/pub/mozilla.org/firefox/nightly/" \
|
||||
"latest-mozilla-central/mar-tools/linux64"
|
||||
for f in ("mar", "mbsdiff"):
|
||||
for f in ('mar', 'mbsdiff'):
|
||||
url = "{prefix}/{f}".format(prefix=prefix, f=f)
|
||||
download(url, dest=os.path.join(self.workdir, f), mode=0o755)
|
||||
await retry_download(url, dest=self.paths[f], mode=0o755)
|
||||
|
||||
def cleanup(self):
|
||||
shutil.rmtree(self.workdir)
|
||||
@ -206,6 +262,151 @@ def verify_allowed_url(mar):
|
||||
))
|
||||
|
||||
|
||||
async def manage_partial(partial_def, work_env, filename_template, artifacts_dir, signing_certs):
|
||||
"""Manage the creation of partial mars based on payload."""
|
||||
for mar in (partial_def["from_mar"], partial_def["to_mar"]):
|
||||
verify_allowed_url(mar)
|
||||
|
||||
complete_mars = {}
|
||||
use_old_format = False
|
||||
|
||||
for mar_type, f in (("from", partial_def["from_mar"]), ("to", partial_def["to_mar"])):
|
||||
dest = os.path.join(work_env.workdir, "{}.mar".format(mar_type))
|
||||
unpack_dir = os.path.join(work_env.workdir, mar_type)
|
||||
|
||||
with ddstats.timer('mar.download.time'):
|
||||
await retry_download(f, dest)
|
||||
|
||||
if not os.getenv("MOZ_DISABLE_MAR_CERT_VERIFICATION"):
|
||||
verify_signature(dest, signing_certs)
|
||||
|
||||
complete_mars["%s_size" % mar_type] = os.path.getsize(dest)
|
||||
complete_mars["%s_hash" % mar_type] = get_hash(dest)
|
||||
|
||||
with ddstats.timer('mar.unpack.time'):
|
||||
await unpack(work_env, dest, unpack_dir)
|
||||
|
||||
if mar_type == 'from':
|
||||
version = get_option(unpack_dir, filename="application.ini",
|
||||
section="App", option="Version")
|
||||
major = int(version.split(".")[0])
|
||||
# The updater for versions less than 56.0 requires BZ2
|
||||
# compressed MAR files
|
||||
if major < 56:
|
||||
use_old_format = True
|
||||
log.info("Forcing BZ2 compression for %s", f)
|
||||
|
||||
log.info("AV-scanning %s ...", unpack_dir)
|
||||
metric_tags = [
|
||||
"platform:{}".format(partial_def['platform']),
|
||||
]
|
||||
with ddstats.timer('mar.clamscan.time', tags=metric_tags):
|
||||
await run_command("clamscan -r {}".format(unpack_dir), label='clamscan')
|
||||
log.info("Done.")
|
||||
|
||||
to_path = os.path.join(work_env.workdir, "to")
|
||||
from_path = os.path.join(work_env.workdir, "from")
|
||||
|
||||
mar_data = {
|
||||
"ACCEPTED_MAR_CHANNEL_IDS": get_option(
|
||||
to_path, filename="update-settings.ini", section="Settings",
|
||||
option="ACCEPTED_MAR_CHANNEL_IDS"),
|
||||
"version": get_option(to_path, filename="application.ini",
|
||||
section="App", option="Version"),
|
||||
"to_buildid": get_option(to_path, filename="application.ini",
|
||||
section="App", option="BuildID"),
|
||||
"from_buildid": get_option(from_path, filename="application.ini",
|
||||
section="App", option="BuildID"),
|
||||
"appName": get_option(from_path, filename="application.ini",
|
||||
section="App", option="Name"),
|
||||
# Use Gecko repo and rev from platform.ini, not application.ini
|
||||
"repo": get_option(to_path, filename="platform.ini", section="Build",
|
||||
option="SourceRepository"),
|
||||
"revision": get_option(to_path, filename="platform.ini",
|
||||
section="Build", option="SourceStamp"),
|
||||
"from_mar": partial_def["from_mar"],
|
||||
"to_mar": partial_def["to_mar"],
|
||||
"platform": partial_def["platform"],
|
||||
"locale": partial_def["locale"],
|
||||
}
|
||||
# Override ACCEPTED_MAR_CHANNEL_IDS if needed
|
||||
if "ACCEPTED_MAR_CHANNEL_IDS" in os.environ:
|
||||
mar_data["ACCEPTED_MAR_CHANNEL_IDS"] = os.environ["ACCEPTED_MAR_CHANNEL_IDS"]
|
||||
for field in ("update_number", "previousVersion", "previousBuildNumber",
|
||||
"toVersion", "toBuildNumber"):
|
||||
if field in partial_def:
|
||||
mar_data[field] = partial_def[field]
|
||||
mar_data.update(complete_mars)
|
||||
|
||||
# if branch not set explicitly use repo-name
|
||||
mar_data['branch'] = partial_def.get('branch', mar_data['repo'].rstrip('/').split('/')[-1])
|
||||
|
||||
if 'dest_mar' in partial_def:
|
||||
mar_name = partial_def['dest_mar']
|
||||
else:
|
||||
# default to formatted name if not specified
|
||||
mar_name = filename_template.format(**mar_data)
|
||||
|
||||
mar_data['mar'] = mar_name
|
||||
dest_mar = os.path.join(work_env.workdir, mar_name)
|
||||
|
||||
# TODO: download these once
|
||||
await work_env.download_buildsystem_bits(repo=mar_data["repo"],
|
||||
revision=mar_data["revision"])
|
||||
|
||||
metric_tags = [
|
||||
"branch:{}".format(mar_data['branch']),
|
||||
"platform:{}".format(mar_data['platform']),
|
||||
# If required. Shouldn't add much useful info, but increases
|
||||
# cardinality of metrics substantially, so avoided.
|
||||
# "locale:{}".format(mar_data['locale']),
|
||||
]
|
||||
with ddstats.timer('generate_partial.time', tags=metric_tags):
|
||||
await generate_partial(work_env, from_path, to_path, dest_mar,
|
||||
mar_data["ACCEPTED_MAR_CHANNEL_IDS"],
|
||||
mar_data["version"],
|
||||
use_old_format)
|
||||
|
||||
mar_data["size"] = os.path.getsize(dest_mar)
|
||||
|
||||
metric_tags.append("unit:bytes")
|
||||
# Allows us to find out how many releases there were between the two,
|
||||
# making buckets of the file sizes easier.
|
||||
metric_tags.append("update_number:{}".format(mar_data.get('update_number', 0)))
|
||||
ddstats.gauge('partial_mar_size', mar_data['size'], tags=metric_tags)
|
||||
|
||||
mar_data["hash"] = get_hash(dest_mar)
|
||||
|
||||
shutil.copy(dest_mar, artifacts_dir)
|
||||
work_env.cleanup()
|
||||
|
||||
return mar_data
|
||||
|
||||
|
||||
async def async_main(args, signing_certs):
|
||||
tasks = []
|
||||
|
||||
master_env = WorkEnv()
|
||||
await master_env.setup()
|
||||
|
||||
task = json.load(args.task_definition)
|
||||
# TODO: verify task["extra"]["funsize"]["partials"] with jsonschema
|
||||
for definition in task["extra"]["funsize"]["partials"]:
|
||||
workenv = WorkEnv()
|
||||
await workenv.clone(master_env)
|
||||
tasks.append(asyncio.ensure_future(manage_partial(
|
||||
partial_def=definition,
|
||||
filename_template=args.filename_template,
|
||||
artifacts_dir=args.artifacts_dir,
|
||||
work_env=workenv,
|
||||
signing_certs=signing_certs)
|
||||
))
|
||||
|
||||
manifest = await asyncio.gather(*tasks)
|
||||
master_env.cleanup()
|
||||
return manifest
|
||||
|
||||
|
||||
def main():
|
||||
|
||||
start = time.time()
|
||||
@ -227,8 +428,6 @@ def main():
|
||||
|
||||
logging.basicConfig(format="%(asctime)s - %(levelname)s - %(message)s")
|
||||
log.setLevel(args.log_level)
|
||||
task = json.load(args.task_definition)
|
||||
# TODO: verify task["extra"]["funsize"]["partials"] with jsonschema
|
||||
|
||||
signing_certs = {
|
||||
'sha1': open(args.sha1_signing_cert, 'rb').read(),
|
||||
@ -244,10 +443,6 @@ def main():
|
||||
if not dd_api_key and os.environ.get('DATADOG_API_SECRET'):
|
||||
dd_api_key = get_secret(os.environ.get('DATADOG_API_SECRET')).get('key')
|
||||
|
||||
# Create this even when not sending metrics, so the context manager
|
||||
# statements work.
|
||||
ddstats = ThreadStats(namespace='releng.releases.partials')
|
||||
|
||||
if dd_api_key:
|
||||
dd_options = {
|
||||
'api_key': dd_api_key,
|
||||
@ -269,133 +464,29 @@ def main():
|
||||
except sh.ErrorReturnCode:
|
||||
log.warning("Freshclam failed, skipping DB update")
|
||||
|
||||
manifest = []
|
||||
for e in task["extra"]["funsize"]["partials"]:
|
||||
for mar in (e["from_mar"], e["to_mar"]):
|
||||
verify_allowed_url(mar)
|
||||
|
||||
work_env = WorkEnv()
|
||||
# TODO: run setup once
|
||||
work_env.setup()
|
||||
complete_mars = {}
|
||||
use_old_format = False
|
||||
for mar_type, f in (("from", e["from_mar"]), ("to", e["to_mar"])):
|
||||
dest = os.path.join(work_env.workdir, "{}.mar".format(mar_type))
|
||||
unpack_dir = os.path.join(work_env.workdir, mar_type)
|
||||
with ddstats.timer('mar.download.time'):
|
||||
download(f, dest)
|
||||
if not os.getenv("MOZ_DISABLE_MAR_CERT_VERIFICATION"):
|
||||
verify_signature(dest, signing_certs)
|
||||
complete_mars["%s_size" % mar_type] = os.path.getsize(dest)
|
||||
complete_mars["%s_hash" % mar_type] = get_hash(dest)
|
||||
with ddstats.timer('mar.unpack.time'):
|
||||
unpack(work_env, dest, unpack_dir)
|
||||
if mar_type == 'from':
|
||||
version = get_option(unpack_dir, filename="application.ini",
|
||||
section="App", option="Version")
|
||||
major = int(version.split(".")[0])
|
||||
# The updater for versions less than 56.0 requires BZ2
|
||||
# compressed MAR files
|
||||
if major < 56:
|
||||
use_old_format = True
|
||||
log.info("Forcing BZ2 compression for %s", f)
|
||||
log.info("AV-scanning %s ...", unpack_dir)
|
||||
metric_tags = [
|
||||
"platform:{}".format(e['platform']),
|
||||
]
|
||||
with ddstats.timer('mar.clamscan.time', tags=metric_tags):
|
||||
sh.clamscan("-r", unpack_dir, _timeout=600, _err_to_out=True)
|
||||
log.info("Done.")
|
||||
|
||||
path = os.path.join(work_env.workdir, "to")
|
||||
from_path = os.path.join(work_env.workdir, "from")
|
||||
mar_data = {
|
||||
"ACCEPTED_MAR_CHANNEL_IDS": get_option(
|
||||
path, filename="update-settings.ini", section="Settings",
|
||||
option="ACCEPTED_MAR_CHANNEL_IDS"),
|
||||
"version": get_option(path, filename="application.ini",
|
||||
section="App", option="Version"),
|
||||
"to_buildid": get_option(path, filename="application.ini",
|
||||
section="App", option="BuildID"),
|
||||
"from_buildid": get_option(from_path, filename="application.ini",
|
||||
section="App", option="BuildID"),
|
||||
"appName": get_option(from_path, filename="application.ini",
|
||||
section="App", option="Name"),
|
||||
# Use Gecko repo and rev from platform.ini, not application.ini
|
||||
"repo": get_option(path, filename="platform.ini", section="Build",
|
||||
option="SourceRepository"),
|
||||
"revision": get_option(path, filename="platform.ini",
|
||||
section="Build", option="SourceStamp"),
|
||||
"from_mar": e["from_mar"],
|
||||
"to_mar": e["to_mar"],
|
||||
"platform": e["platform"],
|
||||
"locale": e["locale"],
|
||||
}
|
||||
# Override ACCEPTED_MAR_CHANNEL_IDS if needed
|
||||
if "ACCEPTED_MAR_CHANNEL_IDS" in os.environ:
|
||||
mar_data["ACCEPTED_MAR_CHANNEL_IDS"] = os.environ["ACCEPTED_MAR_CHANNEL_IDS"]
|
||||
for field in ("update_number", "previousVersion",
|
||||
"previousBuildNumber", "toVersion",
|
||||
"toBuildNumber"):
|
||||
if field in e:
|
||||
mar_data[field] = e[field]
|
||||
mar_data.update(complete_mars)
|
||||
# if branch not set explicitly use repo-name
|
||||
mar_data["branch"] = e.get("branch",
|
||||
mar_data["repo"].rstrip("/").split("/")[-1])
|
||||
if 'dest_mar' in e:
|
||||
mar_name = e['dest_mar']
|
||||
else:
|
||||
# default to formatted name if not specified
|
||||
mar_name = args.filename_template.format(**mar_data)
|
||||
mar_data["mar"] = mar_name
|
||||
dest_mar = os.path.join(work_env.workdir, mar_name)
|
||||
# TODO: download these once
|
||||
work_env.download_buildsystem_bits(repo=mar_data["repo"],
|
||||
revision=mar_data["revision"])
|
||||
|
||||
metric_tags = [
|
||||
"branch:{}".format(mar_data['branch']),
|
||||
"platform:{}".format(mar_data['platform']),
|
||||
# If required. Shouldn't add much useful info, but increases
|
||||
# cardinality of metrics substantially, so avoided.
|
||||
# "locale:{}".format(mar_data['locale']),
|
||||
]
|
||||
|
||||
with ddstats.timer('generate_partial.time', tags=metric_tags):
|
||||
generate_partial(work_env, from_path, path, dest_mar,
|
||||
mar_data["ACCEPTED_MAR_CHANNEL_IDS"],
|
||||
mar_data["version"],
|
||||
use_old_format)
|
||||
|
||||
mar_data["size"] = os.path.getsize(dest_mar)
|
||||
metric_tags.append("unit:bytes")
|
||||
# Allows us to find out how many releases there were between the two,
|
||||
# making buckets of the file sizes easier.
|
||||
metric_tags.append("update_number:{}".format(mar_data.get('update_number', 0)))
|
||||
ddstats.gauge('partial_mar_size', mar_data['size'], tags=metric_tags)
|
||||
|
||||
mar_data["hash"] = get_hash(dest_mar)
|
||||
|
||||
shutil.copy(dest_mar, args.artifacts_dir)
|
||||
work_env.cleanup()
|
||||
manifest.append(mar_data)
|
||||
loop = asyncio.get_event_loop()
|
||||
manifest = loop.run_until_complete(async_main(args, signing_certs))
|
||||
loop.close()
|
||||
|
||||
manifest_file = os.path.join(args.artifacts_dir, "manifest.json")
|
||||
with open(manifest_file, "w") as fp:
|
||||
json.dump(manifest, fp, indent=2, sort_keys=True)
|
||||
|
||||
log.debug("{}".format(json.dumps(manifest, indent=2, sort_keys=True)))
|
||||
|
||||
# Warning: Assumption that one partials task will always be for one branch.
|
||||
metric_tags = [
|
||||
"branch:{}".format(mar_data['branch']),
|
||||
"branch:{}".format(manifest[0]['branch']),
|
||||
]
|
||||
|
||||
ddstats.timing('task_duration', time.time() - start,
|
||||
start, tags=metric_tags)
|
||||
|
||||
# Wait for all the metrics to flush. If the program ends before
|
||||
# they've been sent, they'll be dropped.
|
||||
# Should be more than the flush_interval for the ThreadStats object
|
||||
time.sleep(10)
|
||||
if dd_api_key:
|
||||
time.sleep(10)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
19
taskcluster/docker/google-play-strings/Dockerfile
Normal file
19
taskcluster/docker/google-play-strings/Dockerfile
Normal file
@ -0,0 +1,19 @@
|
||||
FROM ubuntu:16.04
|
||||
MAINTAINER Johan Lorenzo <jlorenzo+tc@mozilla.com>
|
||||
|
||||
RUN mkdir /builds
|
||||
RUN groupadd -g 500 worker
|
||||
RUN useradd -u 500 -g 500 -d /builds/worker -s /bin/bash -m worker
|
||||
|
||||
RUN apt-get update
|
||||
RUN apt-get install --yes git python3-setuptools build-essential libssl-dev libffi-dev python3-dev
|
||||
|
||||
WORKDIR /builds/worker/
|
||||
RUN git clone https://github.com/mozilla-releng/mozapkpublisher
|
||||
WORKDIR /builds/worker/mozapkpublisher
|
||||
RUN python3 setup.py develop
|
||||
|
||||
RUN chown -R worker:worker /builds/worker
|
||||
|
||||
# Set a default command useful for debugging
|
||||
CMD ["/bin/bash", "--login"]
|
@ -217,6 +217,11 @@ Beetmover, takes specific artifact checksums and pushes it to a location outside
|
||||
of Taskcluster's task artifacts (archive.mozilla.org as one place) and in the
|
||||
process determines the final location and "pretty" names it (version product name)
|
||||
|
||||
google-play-strings
|
||||
-------------------
|
||||
Download strings to display on Google Play from https://l10n.mozilla-community.org/stores_l10n/.
|
||||
Artifact is then used by push-apk.
|
||||
|
||||
push-apk-breakpoint
|
||||
-------------------
|
||||
Decides whether or not APKs should be published onto Google Play Store. Jobs of this
|
||||
|
64
taskcluster/taskgraph/transforms/google_play_strings.py
Normal file
64
taskcluster/taskgraph/transforms/google_play_strings.py
Normal file
@ -0,0 +1,64 @@
|
||||
# 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/.
|
||||
"""
|
||||
Transform the push-apk kind into an actual task description.
|
||||
"""
|
||||
|
||||
from __future__ import absolute_import, print_function, unicode_literals
|
||||
|
||||
import functools
|
||||
|
||||
from taskgraph.transforms.base import TransformSequence
|
||||
from taskgraph.transforms.task import task_description_schema
|
||||
from taskgraph.util.schema import resolve_keyed_by, Schema
|
||||
from taskgraph.util.push_apk import fill_labels_tranform, validate_jobs_schema_transform_partial
|
||||
|
||||
from voluptuous import Required
|
||||
|
||||
|
||||
transforms = TransformSequence()
|
||||
|
||||
# Voluptuous uses marker objects as dictionary *keys*, but they are not
|
||||
# comparable, so we cast all of the keys back to regular strings
|
||||
task_description_schema = {str(k): v for k, v in task_description_schema.schema.iteritems()}
|
||||
|
||||
google_play_description_schema = Schema({
|
||||
Required('name'): basestring,
|
||||
Required('label'): task_description_schema['label'],
|
||||
Required('description'): task_description_schema['description'],
|
||||
Required('job-from'): task_description_schema['job-from'],
|
||||
Required('attributes'): task_description_schema['attributes'],
|
||||
Required('treeherder'): task_description_schema['treeherder'],
|
||||
Required('run-on-projects'): task_description_schema['run-on-projects'],
|
||||
Required('shipping-phase'): task_description_schema['shipping-phase'],
|
||||
Required('shipping-product'): task_description_schema['shipping-product'],
|
||||
Required('worker-type'): task_description_schema['worker-type'],
|
||||
Required('worker'): object,
|
||||
})
|
||||
|
||||
validate_jobs_schema_transform = functools.partial(
|
||||
validate_jobs_schema_transform_partial,
|
||||
google_play_description_schema,
|
||||
'GooglePlayStrings'
|
||||
)
|
||||
|
||||
transforms.add(fill_labels_tranform)
|
||||
transforms.add(validate_jobs_schema_transform)
|
||||
|
||||
|
||||
@transforms.add
|
||||
def set_worker_data(config, jobs):
|
||||
for job in jobs:
|
||||
worker = job['worker']
|
||||
|
||||
env = worker.setdefault('env', {})
|
||||
resolve_keyed_by(
|
||||
env, 'PACKAGE_NAME', item_name=job['name'],
|
||||
project=config.params['project']
|
||||
)
|
||||
|
||||
cot = job.setdefault('extra', {}).setdefault('chainOfTrust', {})
|
||||
cot.setdefault('inputs', {})['docker-image'] = {'task-reference': '<docker-image>'}
|
||||
|
||||
yield job
|
@ -28,22 +28,22 @@ task_description_schema = {str(k): v for k, v in task_description_schema.schema.
|
||||
|
||||
|
||||
push_apk_description_schema = Schema({
|
||||
# the dependent task (object) for this beetmover job, used to inform beetmover.
|
||||
Required('dependent-tasks'): object,
|
||||
Required('name'): basestring,
|
||||
Required('label'): basestring,
|
||||
Required('description'): basestring,
|
||||
Required('job-from'): basestring,
|
||||
Required('attributes'): object,
|
||||
Required('treeherder'): object,
|
||||
Required('run-on-projects'): list,
|
||||
Required('label'): task_description_schema['label'],
|
||||
Required('description'): task_description_schema['description'],
|
||||
Required('job-from'): task_description_schema['job-from'],
|
||||
Required('attributes'): task_description_schema['attributes'],
|
||||
Required('treeherder'): task_description_schema['treeherder'],
|
||||
Required('run-on-projects'): task_description_schema['run-on-projects'],
|
||||
Required('worker-type'): optionally_keyed_by('project', basestring),
|
||||
Required('worker'): object,
|
||||
Required('scopes'): None,
|
||||
Required('requires'): task_description_schema['requires'],
|
||||
Required('deadline-after'): basestring,
|
||||
Required('shipping-phase'): task_description_schema['shipping-phase'],
|
||||
Required('shipping-product'): task_description_schema['shipping-product'],
|
||||
Optional('extra'): object,
|
||||
Optional('extra'): task_description_schema['extra'],
|
||||
})
|
||||
|
||||
validate_jobs_schema_transform = functools.partial(
|
||||
@ -83,8 +83,21 @@ transforms.add(delete_non_required_fields_transform)
|
||||
|
||||
|
||||
def generate_upstream_artifacts(dependencies):
|
||||
return [{
|
||||
apks = [{
|
||||
'taskId': {'task-reference': '<{}>'.format(task_kind)},
|
||||
'taskType': 'signing',
|
||||
'paths': ['public/build/target.apk'],
|
||||
} for task_kind in dependencies.keys() if 'breakpoint' not in task_kind]
|
||||
} for task_kind in dependencies.keys()
|
||||
if task_kind not in ('push-apk-breakpoint', 'google-play-strings')
|
||||
]
|
||||
|
||||
google_play_strings = [{
|
||||
'taskId': {'task-reference': '<{}>'.format(task_kind)},
|
||||
'taskType': 'build',
|
||||
'paths': ['public/google_play_strings.json'],
|
||||
'optional': True,
|
||||
} for task_kind in dependencies.keys()
|
||||
if 'google-play-strings' in task_kind
|
||||
]
|
||||
|
||||
return apks + google_play_strings
|
||||
|
@ -93,6 +93,8 @@ task_description_schema = Schema({
|
||||
# method.
|
||||
Optional('dependencies'): {basestring: object},
|
||||
|
||||
Optional('requires'): Any('all-completed', 'all-resolved'),
|
||||
|
||||
# expiration and deadline times, relative to task creation, with units
|
||||
# (e.g., "14 days"). Defaults are set based on the project.
|
||||
Optional('expires-after'): basestring,
|
||||
@ -571,6 +573,9 @@ task_description_schema = Schema({
|
||||
|
||||
# Paths to the artifacts to sign
|
||||
Required('paths'): [basestring],
|
||||
|
||||
# Artifact is optional to run the task
|
||||
Optional('optional', default=False): bool,
|
||||
}],
|
||||
|
||||
# "Invalid" is a noop for try and other non-supported branches
|
||||
@ -1471,6 +1476,9 @@ def build_task(config, tasks):
|
||||
'priority': task['priority'],
|
||||
}
|
||||
|
||||
if task.get('requires', None):
|
||||
task_def['requires'] = task['requires']
|
||||
|
||||
if task_th:
|
||||
# link back to treeherder in description
|
||||
th_push_link = 'https://treeherder.mozilla.org/#/jobs?repo={}&revision={}'.format(
|
||||
|
@ -278,18 +278,20 @@ GeckoDriver.prototype.QueryInterface = XPCOMUtils.generateQI([
|
||||
]);
|
||||
|
||||
GeckoDriver.prototype.init = function() {
|
||||
this.mm.addMessageListener("Marionette:WebDriver:GetCapabilities", this);
|
||||
this.mm.addMessageListener("Marionette:GetLogLevel", this);
|
||||
this.mm.addMessageListener("Marionette:getVisibleCookies", this);
|
||||
this.mm.addMessageListener("Marionette:listenersAttached", this);
|
||||
this.mm.addMessageListener("Marionette:register", this);
|
||||
this.mm.addMessageListener("Marionette:ListenersAttached", this);
|
||||
this.mm.addMessageListener("Marionette:Register", this);
|
||||
this.mm.addMessageListener("Marionette:switchedToFrame", this);
|
||||
};
|
||||
|
||||
GeckoDriver.prototype.uninit = function() {
|
||||
this.mm.removeMessageListener("Marionette:WebDriver:GetCapabilities", this);
|
||||
this.mm.removeMessageListener("Marionette:GetLogLevel", this);
|
||||
this.mm.removeMessageListener("Marionette:getVisibleCookies", this);
|
||||
this.mm.removeMessageListener("Marionette:listenersAttached", this);
|
||||
this.mm.removeMessageListener("Marionette:register", this);
|
||||
this.mm.removeMessageListener("Marionette:ListenersAttached", this);
|
||||
this.mm.removeMessageListener("Marionette:Register", this);
|
||||
this.mm.removeMessageListener("Marionette:switchedToFrame", this);
|
||||
};
|
||||
|
||||
@ -443,7 +445,6 @@ GeckoDriver.prototype.startBrowser = function(window, isNewSession = false) {
|
||||
this.mainFrame = window;
|
||||
this.curFrame = null;
|
||||
this.addBrowser(window);
|
||||
this.curBrowser.isNewSession = isNewSession;
|
||||
this.whenBrowserStarted(window, isNewSession);
|
||||
};
|
||||
|
||||
@ -536,26 +537,20 @@ GeckoDriver.prototype.registerBrowser = function(id, be) {
|
||||
|
||||
this.wins.set(id, listenerWindow);
|
||||
if (nullPrevious && (this.curBrowser.curFrameId !== null)) {
|
||||
this.sendAsync(
|
||||
"newSession",
|
||||
this.capabilities,
|
||||
this.newSessionCommandId);
|
||||
if (this.curBrowser.isNewSession) {
|
||||
this.newSessionCommandId = null;
|
||||
}
|
||||
this.sendAsync("newSession");
|
||||
}
|
||||
|
||||
return [id, this.capabilities.toJSON()];
|
||||
return id;
|
||||
};
|
||||
|
||||
GeckoDriver.prototype.registerPromise = function() {
|
||||
const li = "Marionette:register";
|
||||
const li = "Marionette:Register";
|
||||
|
||||
return new Promise(resolve => {
|
||||
let cb = msg => {
|
||||
let wid = msg.json.value;
|
||||
let be = msg.target;
|
||||
let rv = this.registerBrowser(wid, be);
|
||||
let outerWindowID = this.registerBrowser(wid, be);
|
||||
|
||||
if (this.curBrowser.frameRegsPending > 0) {
|
||||
this.curBrowser.frameRegsPending--;
|
||||
@ -567,18 +562,18 @@ GeckoDriver.prototype.registerPromise = function() {
|
||||
}
|
||||
|
||||
// this is a sync message and listeners expect the ID back
|
||||
return rv;
|
||||
return outerWindowID;
|
||||
};
|
||||
this.mm.addMessageListener(li, cb);
|
||||
});
|
||||
};
|
||||
|
||||
GeckoDriver.prototype.listeningPromise = function() {
|
||||
const li = "Marionette:listenersAttached";
|
||||
const li = "Marionette:ListenersAttached";
|
||||
|
||||
return new Promise(resolve => {
|
||||
let cb = msg => {
|
||||
if (msg.json.listenerId === this.curBrowser.curFrameId) {
|
||||
if (msg.json.outerWindowID === this.curBrowser.curFrameId) {
|
||||
this.mm.removeMessageListener(li, cb);
|
||||
resolve();
|
||||
}
|
||||
@ -699,7 +694,6 @@ GeckoDriver.prototype.newSession = async function(cmd) {
|
||||
throw new SessionNotCreatedError("Maximum number of active sessions");
|
||||
}
|
||||
this.sessionID = WebElement.generateUUID();
|
||||
this.newSessionCommandId = cmd.id;
|
||||
|
||||
try {
|
||||
this.capabilities = session.Capabilities.fromJSON(cmd.parameters);
|
||||
@ -3343,22 +3337,25 @@ GeckoDriver.prototype.receiveMessage = function(message) {
|
||||
}
|
||||
break;
|
||||
|
||||
case "Marionette:register":
|
||||
case "Marionette:Register":
|
||||
let wid = message.json.value;
|
||||
let be = message.target;
|
||||
let rv = this.registerBrowser(wid, be);
|
||||
return rv;
|
||||
let outerWindowID = this.registerBrowser(wid, be);
|
||||
return {outerWindowID};
|
||||
|
||||
case "Marionette:listenersAttached":
|
||||
if (message.json.listenerId === this.curBrowser.curFrameId) {
|
||||
case "Marionette:ListenersAttached":
|
||||
if (message.json.outerWindowID === this.curBrowser.curFrameId) {
|
||||
// If the frame script gets reloaded we need to call newSession.
|
||||
// In the case of desktop this just sets up a small amount of state
|
||||
// that doesn't change over the course of a session.
|
||||
this.sendAsync("newSession", this.capabilities);
|
||||
this.sendAsync("newSession");
|
||||
this.curBrowser.flushPendingCommands();
|
||||
}
|
||||
break;
|
||||
|
||||
case "Marionette:WebDriver:GetCapabilities":
|
||||
return this.capabilities.toJSON();
|
||||
|
||||
case "Marionette:GetLogLevel":
|
||||
return logger.level;
|
||||
}
|
||||
|
@ -47,7 +47,7 @@ Cu.import("chrome://marionette/content/session.js");
|
||||
|
||||
Cu.importGlobalProperties(["URL"]);
|
||||
|
||||
let listenerId = null; // unique ID of this listener
|
||||
let outerWindowID = null;
|
||||
let curContainer = {frame: content, shadowRoot: null};
|
||||
|
||||
// Listen for click event to indicate one click has happened, so actions
|
||||
@ -69,7 +69,13 @@ const SUPPORTED_STRATEGIES = new Set([
|
||||
element.Strategy.XPath,
|
||||
]);
|
||||
|
||||
let capabilities;
|
||||
Object.defineProperty(this, "capabilities", {
|
||||
get() {
|
||||
let payload = sendSyncMessage("Marionette:WebDriver:GetCapabilities");
|
||||
return session.Capabilities.fromJSON(payload[0]);
|
||||
},
|
||||
configurable: true,
|
||||
});
|
||||
|
||||
let legacyactions = new legacyaction.Chain();
|
||||
|
||||
@ -447,15 +453,11 @@ function registerSelf() {
|
||||
|
||||
// register will have the ID and a boolean describing if this is the
|
||||
// main process or not
|
||||
let register = sendSyncMessage("Marionette:register", msg);
|
||||
let register = sendSyncMessage("Marionette:Register", msg);
|
||||
if (register[0]) {
|
||||
listenerId = register[0][0];
|
||||
capabilities = session.Capabilities.fromJSON(register[0][1]);
|
||||
if (typeof listenerId != "undefined") {
|
||||
startListeners();
|
||||
sendAsyncMessage("Marionette:listenersAttached",
|
||||
{"listenerId": listenerId});
|
||||
}
|
||||
outerWindowID = register[0].outerWindowID;
|
||||
startListeners();
|
||||
sendAsyncMessage("Marionette:ListenersAttached", {outerWindowID});
|
||||
}
|
||||
}
|
||||
|
||||
@ -490,18 +492,12 @@ function dispatch(fn) {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a message listener that's tied to our listenerId.
|
||||
*/
|
||||
function addMessageListenerId(messageName, handler) {
|
||||
addMessageListener(messageName + listenerId, handler);
|
||||
addMessageListener(messageName + outerWindowID, handler);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a message listener that's tied to our listenerId.
|
||||
*/
|
||||
function removeMessageListenerId(messageName, handler) {
|
||||
removeMessageListener(messageName + listenerId, handler);
|
||||
removeMessageListener(messageName + outerWindowID, handler);
|
||||
}
|
||||
|
||||
let getPageSourceFn = dispatch(getPageSource);
|
||||
@ -582,9 +578,12 @@ function startListeners() {
|
||||
* Called when we start a new session. It registers the
|
||||
* current environment, and resets all values
|
||||
*/
|
||||
function newSession(msg) {
|
||||
capabilities = session.Capabilities.fromJSON(msg.json);
|
||||
resetValues();
|
||||
function newSession() {
|
||||
sandboxes.clear();
|
||||
curContainer = {frame: content, shadowRoot: null};
|
||||
legacyactions.mouseEventsOnly = false;
|
||||
action.inputStateMap = new Map();
|
||||
action.inputsToCancel = [];
|
||||
}
|
||||
|
||||
/**
|
||||
@ -706,17 +705,6 @@ function sendError(err, uuid) {
|
||||
sendToServer(uuid, err);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear test values after completion of test
|
||||
*/
|
||||
function resetValues() {
|
||||
sandboxes.clear();
|
||||
curContainer = {frame: content, shadowRoot: null};
|
||||
legacyactions.mouseEventsOnly = false;
|
||||
action.inputStateMap = new Map();
|
||||
action.inputsToCancel = [];
|
||||
}
|
||||
|
||||
async function execute(script, args, timeout, opts) {
|
||||
opts.timeout = timeout;
|
||||
let sb = sandbox.createMutable(curContainer.frame);
|
||||
|
@ -12,9 +12,6 @@
|
||||
[setProperty on CSSStyleDeclaration must enqueue an attributeChanged reaction when it mutates the observed style attribute]
|
||||
expected: FAIL
|
||||
|
||||
[setProperty on CSSStyleDeclaration must enqueue an attributeChanged reaction when it makes a property important and the style attribute is observed]
|
||||
expected: FAIL
|
||||
|
||||
[setPropertyValue on CSSStyleDeclaration must enqueue an attributeChanged reaction when it adds the observed style attribute]
|
||||
expected: FAIL
|
||||
|
||||
@ -33,9 +30,6 @@
|
||||
[setPropertyPriority on CSSStyleDeclaration must enqueue an attributeChanged reaction when it makes a property important but the style attribute is not observed]
|
||||
expected: FAIL
|
||||
|
||||
[removeProperty on CSSStyleDeclaration must enqueue an attributeChanged reaction when it removes a property from the observed style attribute]
|
||||
expected: FAIL
|
||||
|
||||
[cssFloat on CSSStyleDeclaration must enqueue an attributeChanged reaction when it adds the observed style attribute]
|
||||
expected: FAIL
|
||||
|
||||
|
@ -5244,6 +5244,8 @@
|
||||
"expires_in_version" : "never",
|
||||
"kind": "enumerated",
|
||||
"n_values": 4,
|
||||
"alert_emails": ["fx-search@mozilla.com"],
|
||||
"bug_numbers": [1053467],
|
||||
"description": "The possible types of the 'sizes' attribute for <link rel=icon>. 0: Attribute not specified, 1: 'any', 2: Integer dimensions, 3: Invalid value."
|
||||
},
|
||||
"LINK_ICON_SIZES_ATTR_DIMENSION": {
|
||||
@ -5252,6 +5254,8 @@
|
||||
"kind": "linear",
|
||||
"high": 513,
|
||||
"n_buckets" : 64,
|
||||
"alert_emails": ["fx-search@mozilla.com"],
|
||||
"bug_numbers": [1053467],
|
||||
"description": "The width dimension of the 'sizes' attribute for <link rel=icon>."
|
||||
},
|
||||
"PAGE_METADATA_SIZE": {
|
||||
@ -7812,14 +7816,6 @@
|
||||
"kind": "boolean",
|
||||
"description": "New tab page is enhanced (showing suggestions)."
|
||||
},
|
||||
"NEWTAB_PAGE_LIFE_SPAN": {
|
||||
"record_in_processes": ["main", "content"],
|
||||
"expires_in_version": "default",
|
||||
"kind": "exponential",
|
||||
"high": 1200,
|
||||
"n_buckets": 100,
|
||||
"description": "Life-span of a new tab without suggested tile: time delta between first-visible and unload events (half-seconds)."
|
||||
},
|
||||
"NEWTAB_PAGE_PINNED_SITES_COUNT": {
|
||||
"record_in_processes": ["main", "content"],
|
||||
"expires_in_version": "default",
|
||||
@ -7835,19 +7831,6 @@
|
||||
"n_buckets": 10,
|
||||
"description": "Number of sites blocked from the new tab page."
|
||||
},
|
||||
"NEWTAB_PAGE_SHOWN": {
|
||||
"record_in_processes": ["main", "content"],
|
||||
"expires_in_version": "35",
|
||||
"kind": "boolean",
|
||||
"description": "Number of times about:newtab was shown from opening a new tab or window. *** No longer needed (bug 1156565). Delete histogram and accumulation code! ***"
|
||||
},
|
||||
"NEWTAB_PAGE_SITE_CLICKED": {
|
||||
"record_in_processes": ["main", "content"],
|
||||
"expires_in_version": "35",
|
||||
"kind": "enumerated",
|
||||
"n_values": 10,
|
||||
"description": "Track click count on about:newtab tiles per index (0-8). For non-default row or column configurations all clicks into the '9' bucket. *** No longer needed (bug 1156565). Delete histogram and accumulation code! ***"
|
||||
},
|
||||
"BROWSERPROVIDER_XUL_IMPORT_BOOKMARKS": {
|
||||
"record_in_processes": ["main", "content"],
|
||||
"expires_in_version": "default",
|
||||
|
@ -288,8 +288,6 @@
|
||||
"IPC_SAME_PROCESS_MESSAGE_COPY_OOM_KB",
|
||||
"IPV4_AND_IPV6_ADDRESS_CONNECTIVITY",
|
||||
"JS_TELEMETRY_ADDON_EXCEPTIONS",
|
||||
"LINK_ICON_SIZES_ATTR_DIMENSION",
|
||||
"LINK_ICON_SIZES_ATTR_USAGE",
|
||||
"LOCALDOMSTORAGE_CLEAR_BLOCKING_MS",
|
||||
"LOCALDOMSTORAGE_GETALLKEYS_BLOCKING_MS",
|
||||
"LOCALDOMSTORAGE_GETKEY_BLOCKING_MS",
|
||||
@ -371,10 +369,7 @@
|
||||
"NEWTAB_PAGE_BLOCKED_SITES_COUNT",
|
||||
"NEWTAB_PAGE_ENABLED",
|
||||
"NEWTAB_PAGE_ENHANCED",
|
||||
"NEWTAB_PAGE_LIFE_SPAN",
|
||||
"NEWTAB_PAGE_PINNED_SITES_COUNT",
|
||||
"NEWTAB_PAGE_SHOWN",
|
||||
"NEWTAB_PAGE_SITE_CLICKED",
|
||||
"NTLM_MODULE_USED_2",
|
||||
"ONBEFOREUNLOAD_PROMPT_ACTION",
|
||||
"ONBEFOREUNLOAD_PROMPT_COUNT",
|
||||
@ -959,8 +954,6 @@
|
||||
"IPV4_AND_IPV6_ADDRESS_CONNECTIVITY",
|
||||
"JS_DEPRECATED_LANGUAGE_EXTENSIONS_IN_CONTENT",
|
||||
"JS_TELEMETRY_ADDON_EXCEPTIONS",
|
||||
"LINK_ICON_SIZES_ATTR_DIMENSION",
|
||||
"LINK_ICON_SIZES_ATTR_USAGE",
|
||||
"LOCALDOMSTORAGE_CLEAR_BLOCKING_MS",
|
||||
"LOCALDOMSTORAGE_GETALLKEYS_BLOCKING_MS",
|
||||
"LOCALDOMSTORAGE_GETKEY_BLOCKING_MS",
|
||||
@ -1059,10 +1052,7 @@
|
||||
"NEWTAB_PAGE_BLOCKED_SITES_COUNT",
|
||||
"NEWTAB_PAGE_ENABLED",
|
||||
"NEWTAB_PAGE_ENHANCED",
|
||||
"NEWTAB_PAGE_LIFE_SPAN",
|
||||
"NEWTAB_PAGE_PINNED_SITES_COUNT",
|
||||
"NEWTAB_PAGE_SHOWN",
|
||||
"NEWTAB_PAGE_SITE_CLICKED",
|
||||
"NTLM_MODULE_USED_2",
|
||||
"ONBEFOREUNLOAD_PROMPT_ACTION",
|
||||
"ONBEFOREUNLOAD_PROMPT_COUNT",
|
||||
@ -1591,7 +1581,6 @@
|
||||
"NEWTAB_PAGE_ENABLED",
|
||||
"MOZ_SQLITE_OPEN_MS",
|
||||
"SHOULD_TRANSLATION_UI_APPEAR",
|
||||
"NEWTAB_PAGE_LIFE_SPAN",
|
||||
"FX_TOTAL_TOP_VISITS",
|
||||
"FX_SESSION_RESTORE_NUMBER_OF_EAGER_TABS_RESTORED",
|
||||
"CACHE_DISK_SEARCH_2",
|
||||
|
@ -531,7 +531,8 @@ XRE_InitChildProcess(int aArgc,
|
||||
printf_stderr("Could not allow ptrace from any process.\n");
|
||||
}
|
||||
#endif
|
||||
printf_stderr("\n\nCHILDCHILDCHILDCHILD\n debug me @ %d\n\n",
|
||||
printf_stderr("\n\nCHILDCHILDCHILDCHILD (process type %s)\n debug me @ %d\n\n",
|
||||
XRE_ChildProcessTypeToString(XRE_GetProcessType()),
|
||||
base::GetCurrentProcId());
|
||||
sleep(GetDebugChildPauseTime());
|
||||
}
|
||||
@ -541,7 +542,8 @@ XRE_InitChildProcess(int aArgc,
|
||||
"Invoking NS_DebugBreak() to debug child process",
|
||||
nullptr, __FILE__, __LINE__);
|
||||
} else if (PR_GetEnv("MOZ_DEBUG_CHILD_PAUSE")) {
|
||||
printf_stderr("\n\nCHILDCHILDCHILDCHILD\n debug me @ %d\n\n",
|
||||
printf_stderr("\n\nCHILDCHILDCHILDCHILD (process type %s)\n debug me @ %d\n\n",
|
||||
XRE_ChildProcessTypeToString(XRE_GetProcessType()),
|
||||
base::GetCurrentProcId());
|
||||
::Sleep(GetDebugChildPauseTime());
|
||||
}
|
||||
|
@ -34,6 +34,7 @@ py2:
|
||||
- security
|
||||
- services/common/tests/mach_commands.py
|
||||
- servo
|
||||
- taskcluster/docker/funsize-update-generator
|
||||
- testing/awsy
|
||||
- testing/firefox-ui
|
||||
- testing/geckodriver
|
||||
|
Loading…
Reference in New Issue
Block a user