mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1138322 - TelemetryEnvironment.jsm should not use |ProfileTimesAccessor|. r=vladan
This commit is contained in:
parent
399347d25c
commit
4a7c8befaa
@ -27,8 +27,8 @@ XPCOMUtils.defineLazyModuleGetter(this, "OS",
|
||||
"resource://gre/modules/osfile.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "FileUtils",
|
||||
"resource://gre/modules/FileUtils.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "ProfileTimesAccessor",
|
||||
"resource://gre/modules/services/healthreport/profile.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "ProfileAge",
|
||||
"resource://gre/modules/ProfileAge.jsm");
|
||||
|
||||
|
||||
function FirefoxProfileMigrator() {
|
||||
@ -171,7 +171,7 @@ FirefoxProfileMigrator.prototype._getResourcesInternal = function(sourceProfileD
|
||||
file.copyTo(currentProfileDir, "");
|
||||
}
|
||||
// And record the fact a migration (ie, a reset) happened.
|
||||
let timesAccessor = new ProfileTimesAccessor(currentProfileDir.path);
|
||||
let timesAccessor = new ProfileAge(currentProfileDir.path);
|
||||
timesAccessor.recordProfileReset().then(
|
||||
() => aCallback(true),
|
||||
() => aCallback(false)
|
||||
|
@ -6,10 +6,7 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
this.EXPORTED_SYMBOLS = [
|
||||
"ProfileTimesAccessor",
|
||||
"ProfileMetadataProvider",
|
||||
];
|
||||
this.EXPORTED_SYMBOLS = ["ProfileMetadataProvider"];
|
||||
|
||||
const {utils: Cu, classes: Cc, interfaces: Ci} = Components;
|
||||
|
||||
@ -27,195 +24,7 @@ Cu.import("resource://gre/modules/Promise.jsm");
|
||||
Cu.import("resource://gre/modules/osfile.jsm")
|
||||
Cu.import("resource://gre/modules/Task.jsm");
|
||||
Cu.import("resource://gre/modules/Log.jsm");
|
||||
Cu.import("resource://services-common/utils.js");
|
||||
|
||||
// Profile access to times.json (eg, creation/reset time).
|
||||
// This is separate from the provider to simplify testing and enable extraction
|
||||
// to a shared location in the future.
|
||||
this.ProfileTimesAccessor = function(profile, log) {
|
||||
this.profilePath = profile || OS.Constants.Path.profileDir;
|
||||
if (!this.profilePath) {
|
||||
throw new Error("No profile directory.");
|
||||
}
|
||||
this._log = log || {"debug": function (s) { dump(s + "\n"); }};
|
||||
}
|
||||
this.ProfileTimesAccessor.prototype = {
|
||||
/**
|
||||
* There are three ways we can get our creation time:
|
||||
*
|
||||
* 1. From our own saved value (to avoid redundant work).
|
||||
* 2. From the on-disk JSON file.
|
||||
* 3. By calculating it from the filesystem.
|
||||
*
|
||||
* If we have to calculate, we write out the file; if we have
|
||||
* to touch the file, we persist in-memory.
|
||||
*
|
||||
* @return a promise that resolves to the profile's creation time.
|
||||
*/
|
||||
get created() {
|
||||
function onSuccess(times) {
|
||||
if (times.created) {
|
||||
return times.created;
|
||||
}
|
||||
return onFailure.call(this, null, times);
|
||||
}
|
||||
|
||||
function onFailure(err, times) {
|
||||
return this.computeAndPersistCreated(times)
|
||||
.then(function onSuccess(created) {
|
||||
return created;
|
||||
}.bind(this));
|
||||
}
|
||||
|
||||
return this.getTimes()
|
||||
.then(onSuccess.bind(this),
|
||||
onFailure.bind(this));
|
||||
},
|
||||
|
||||
/**
|
||||
* Explicitly make `file`, a filename, a full path
|
||||
* relative to our profile path.
|
||||
*/
|
||||
getPath: function (file) {
|
||||
return OS.Path.join(this.profilePath, file);
|
||||
},
|
||||
|
||||
/**
|
||||
* Return a promise which resolves to the JSON contents
|
||||
* of the time file, using the already read value if possible.
|
||||
*/
|
||||
getTimes: function (file="times.json") {
|
||||
if (this._times) {
|
||||
return Promise.resolve(this._times);
|
||||
}
|
||||
return this.readTimes(file).then(
|
||||
times => {
|
||||
return this.times = times || {};
|
||||
}
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* Return a promise which resolves to the JSON contents
|
||||
* of the time file in this accessor's profile.
|
||||
*/
|
||||
readTimes: function (file="times.json") {
|
||||
return CommonUtils.readJSON(this.getPath(file));
|
||||
},
|
||||
|
||||
/**
|
||||
* Return a promise representing the writing of `contents`
|
||||
* to `file` in the specified profile.
|
||||
*/
|
||||
writeTimes: function (contents, file="times.json") {
|
||||
return CommonUtils.writeJSON(contents, this.getPath(file));
|
||||
},
|
||||
|
||||
/**
|
||||
* Merge existing contents with a 'created' field, writing them
|
||||
* to the specified file. Promise, naturally.
|
||||
*/
|
||||
computeAndPersistCreated: function (existingContents, file="times.json") {
|
||||
let path = this.getPath(file);
|
||||
function onOldest(oldest) {
|
||||
let contents = existingContents || {};
|
||||
contents.created = oldest;
|
||||
this._times = contents;
|
||||
return this.writeTimes(contents, path)
|
||||
.then(function onSuccess() {
|
||||
return oldest;
|
||||
});
|
||||
}
|
||||
|
||||
return this.getOldestProfileTimestamp()
|
||||
.then(onOldest.bind(this));
|
||||
},
|
||||
|
||||
/**
|
||||
* Traverse the contents of the profile directory, finding the oldest file
|
||||
* and returning its creation timestamp.
|
||||
*/
|
||||
getOldestProfileTimestamp: function () {
|
||||
let self = this;
|
||||
let oldest = Date.now() + 1000;
|
||||
let iterator = new OS.File.DirectoryIterator(this.profilePath);
|
||||
self._log.debug("Iterating over profile " + this.profilePath);
|
||||
if (!iterator) {
|
||||
throw new Error("Unable to fetch oldest profile entry: no profile iterator.");
|
||||
}
|
||||
|
||||
function onEntry(entry) {
|
||||
function onStatSuccess(info) {
|
||||
// OS.File doesn't seem to be behaving. See Bug 827148.
|
||||
// Let's do the best we can. This whole function is defensive.
|
||||
let date = info.winBirthDate || info.macBirthDate;
|
||||
if (!date || !date.getTime()) {
|
||||
// OS.File will only return file creation times of any kind on Mac
|
||||
// and Windows, where birthTime is defined.
|
||||
// That means we're unable to function on Linux, so we use mtime
|
||||
// instead.
|
||||
self._log.debug("No birth date. Using mtime.");
|
||||
date = info.lastModificationDate;
|
||||
}
|
||||
|
||||
if (date) {
|
||||
let timestamp = date.getTime();
|
||||
self._log.debug("Using date: " + entry.path + " = " + date);
|
||||
if (timestamp < oldest) {
|
||||
oldest = timestamp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function onStatFailure(e) {
|
||||
// Never mind.
|
||||
self._log.debug("Stat failure: " + CommonUtils.exceptionStr(e));
|
||||
}
|
||||
|
||||
return OS.File.stat(entry.path)
|
||||
.then(onStatSuccess, onStatFailure);
|
||||
}
|
||||
|
||||
let promise = iterator.forEach(onEntry);
|
||||
|
||||
function onSuccess() {
|
||||
iterator.close();
|
||||
return oldest;
|
||||
}
|
||||
|
||||
function onFailure(reason) {
|
||||
iterator.close();
|
||||
throw new Error("Unable to fetch oldest profile entry: " + reason);
|
||||
}
|
||||
|
||||
return promise.then(onSuccess, onFailure);
|
||||
},
|
||||
|
||||
/**
|
||||
* Record (and persist) when a profile reset happened. We just store a
|
||||
* single value - the timestamp of the most recent reset - but there is scope
|
||||
* to keep a list of reset times should our health-reporter successor
|
||||
* be able to make use of that.
|
||||
* Returns a promise that is resolved once the file has been written.
|
||||
*/
|
||||
recordProfileReset: function (time=Date.now(), file="times.json") {
|
||||
return this.getTimes(file).then(
|
||||
times => {
|
||||
times.reset = time;
|
||||
return this.writeTimes(times, file);
|
||||
}
|
||||
);
|
||||
},
|
||||
|
||||
/* Returns a promise that resolves to the time the profile was reset,
|
||||
* or undefined if not recorded.
|
||||
*/
|
||||
get reset() {
|
||||
return this.getTimes().then(
|
||||
times => times.reset
|
||||
);
|
||||
},
|
||||
}
|
||||
Cu.import("resource://gre/modules/ProfileAge.jsm");
|
||||
|
||||
/**
|
||||
* Measurements pertaining to the user's profile.
|
||||
@ -283,7 +92,7 @@ this.ProfileMetadataProvider.prototype = {
|
||||
|
||||
getProfileDays: Task.async(function* () {
|
||||
let result = {};
|
||||
let accessor = new ProfileTimesAccessor(null, this._log);
|
||||
let accessor = new ProfileAge(null, this._log);
|
||||
|
||||
let created = yield accessor.created;
|
||||
result["profileCreation"] = truncate(created);
|
||||
|
@ -15,6 +15,7 @@ do_get_profile();
|
||||
Cu.import("resource://gre/modules/Promise.jsm");
|
||||
Cu.import("resource://gre/modules/Metrics.jsm");
|
||||
Cu.import("resource://gre/modules/services/healthreport/profile.jsm");
|
||||
Cu.import("resource://gre/modules/ProfileAge.jsm");
|
||||
Cu.import("resource://gre/modules/Task.jsm");
|
||||
|
||||
|
||||
@ -64,7 +65,7 @@ add_test(function use_os_file() {
|
||||
});
|
||||
|
||||
function getAccessor() {
|
||||
let acc = new ProfileTimesAccessor();
|
||||
let acc = new ProfileAge();
|
||||
print("Profile is " + acc.profilePath);
|
||||
return acc;
|
||||
}
|
||||
|
@ -24,8 +24,8 @@ XPCOMUtils.defineLazyModuleGetter(this, "ctypes",
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "LightweightThemeManager",
|
||||
"resource://gre/modules/LightweightThemeManager.jsm");
|
||||
#endif
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "ProfileTimesAccessor",
|
||||
"resource://gre/modules/services/healthreport/profile.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "ProfileAge",
|
||||
"resource://gre/modules/ProfileAge.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "UpdateChannel",
|
||||
"resource://gre/modules/UpdateChannel.jsm");
|
||||
|
||||
@ -501,7 +501,7 @@ this.TelemetryEnvironment = {
|
||||
* @return Object containing the profile data.
|
||||
*/
|
||||
_getProfile: Task.async(function* () {
|
||||
let profileAccessor = new ProfileTimesAccessor(null, this._log);
|
||||
let profileAccessor = new ProfileAge(null, this._log);
|
||||
|
||||
let creationDate = yield profileAccessor.created;
|
||||
let resetDate = yield profileAccessor.reset;
|
||||
|
@ -15,9 +15,9 @@ Cu.import("resource://testing-common/httpd.js");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "LightweightThemeManager",
|
||||
"resource://gre/modules/LightweightThemeManager.jsm");
|
||||
|
||||
// Lazy load |ProfileTimesAccessor| as it is not available on Android.
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "ProfileTimesAccessor",
|
||||
"resource://gre/modules/services/healthreport/profile.jsm");
|
||||
// Lazy load |ProfileAge| as it is not available on Android.
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "ProfileAge",
|
||||
"resource://gre/modules/ProfileAge.jsm");
|
||||
|
||||
// The webserver hosting the addons.
|
||||
let gHttpServer = null;
|
||||
@ -160,11 +160,11 @@ function spoofGfxAdapter() {
|
||||
|
||||
function spoofProfileReset() {
|
||||
if (gIsAndroid) {
|
||||
// ProfileTimesAccessor is not available on Android.
|
||||
// ProfileAge is not available on Android.
|
||||
return true;
|
||||
}
|
||||
|
||||
let profileAccessor = new ProfileTimesAccessor();
|
||||
let profileAccessor = new ProfileAge();
|
||||
|
||||
return profileAccessor.writeTimes({
|
||||
created: PROFILE_CREATION_DATE_MS,
|
||||
|
205
toolkit/modules/ProfileAge.jsm
Normal file
205
toolkit/modules/ProfileAge.jsm
Normal file
@ -0,0 +1,205 @@
|
||||
/* 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/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
this.EXPORTED_SYMBOLS = ["ProfileAge"];
|
||||
|
||||
const {classes: Cc, interfaces: Ci, results: Cr, utils: Cu} = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/Promise.jsm");
|
||||
Cu.import("resource://gre/modules/osfile.jsm")
|
||||
Cu.import("resource://gre/modules/Task.jsm");
|
||||
Cu.import("resource://gre/modules/Log.jsm");
|
||||
Cu.import("resource://services-common/utils.js");
|
||||
|
||||
/**
|
||||
* Profile access to times.json (eg, creation/reset time).
|
||||
* This is separate from the provider to simplify testing and enable extraction
|
||||
* to a shared location in the future.
|
||||
*/
|
||||
this.ProfileAge = function(profile, log) {
|
||||
this.profilePath = profile || OS.Constants.Path.profileDir;
|
||||
if (!this.profilePath) {
|
||||
throw new Error("No profile directory.");
|
||||
}
|
||||
this._log = log || {"debug": function (s) { dump(s + "\n"); }};
|
||||
}
|
||||
this.ProfileAge.prototype = {
|
||||
/**
|
||||
* There are three ways we can get our creation time:
|
||||
*
|
||||
* 1. From our own saved value (to avoid redundant work).
|
||||
* 2. From the on-disk JSON file.
|
||||
* 3. By calculating it from the filesystem.
|
||||
*
|
||||
* If we have to calculate, we write out the file; if we have
|
||||
* to touch the file, we persist in-memory.
|
||||
*
|
||||
* @return a promise that resolves to the profile's creation time.
|
||||
*/
|
||||
get created() {
|
||||
function onSuccess(times) {
|
||||
if (times.created) {
|
||||
return times.created;
|
||||
}
|
||||
return onFailure.call(this, null, times);
|
||||
}
|
||||
|
||||
function onFailure(err, times) {
|
||||
return this.computeAndPersistCreated(times)
|
||||
.then(function onSuccess(created) {
|
||||
return created;
|
||||
}.bind(this));
|
||||
}
|
||||
|
||||
return this.getTimes()
|
||||
.then(onSuccess.bind(this),
|
||||
onFailure.bind(this));
|
||||
},
|
||||
|
||||
/**
|
||||
* Explicitly make `file`, a filename, a full path
|
||||
* relative to our profile path.
|
||||
*/
|
||||
getPath: function (file) {
|
||||
return OS.Path.join(this.profilePath, file);
|
||||
},
|
||||
|
||||
/**
|
||||
* Return a promise which resolves to the JSON contents
|
||||
* of the time file, using the already read value if possible.
|
||||
*/
|
||||
getTimes: function (file="times.json") {
|
||||
if (this._times) {
|
||||
return Promise.resolve(this._times);
|
||||
}
|
||||
return this.readTimes(file).then(
|
||||
times => {
|
||||
return this.times = times || {};
|
||||
}
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* Return a promise which resolves to the JSON contents
|
||||
* of the time file in this accessor's profile.
|
||||
*/
|
||||
readTimes: function (file="times.json") {
|
||||
return CommonUtils.readJSON(this.getPath(file));
|
||||
},
|
||||
|
||||
/**
|
||||
* Return a promise representing the writing of `contents`
|
||||
* to `file` in the specified profile.
|
||||
*/
|
||||
writeTimes: function (contents, file="times.json") {
|
||||
return CommonUtils.writeJSON(contents, this.getPath(file));
|
||||
},
|
||||
|
||||
/**
|
||||
* Merge existing contents with a 'created' field, writing them
|
||||
* to the specified file. Promise, naturally.
|
||||
*/
|
||||
computeAndPersistCreated: function (existingContents, file="times.json") {
|
||||
let path = this.getPath(file);
|
||||
function onOldest(oldest) {
|
||||
let contents = existingContents || {};
|
||||
contents.created = oldest;
|
||||
this._times = contents;
|
||||
return this.writeTimes(contents, path)
|
||||
.then(function onSuccess() {
|
||||
return oldest;
|
||||
});
|
||||
}
|
||||
|
||||
return this.getOldestProfileTimestamp()
|
||||
.then(onOldest.bind(this));
|
||||
},
|
||||
|
||||
/**
|
||||
* Traverse the contents of the profile directory, finding the oldest file
|
||||
* and returning its creation timestamp.
|
||||
*/
|
||||
getOldestProfileTimestamp: function () {
|
||||
let self = this;
|
||||
let oldest = Date.now() + 1000;
|
||||
let iterator = new OS.File.DirectoryIterator(this.profilePath);
|
||||
self._log.debug("Iterating over profile " + this.profilePath);
|
||||
if (!iterator) {
|
||||
throw new Error("Unable to fetch oldest profile entry: no profile iterator.");
|
||||
}
|
||||
|
||||
function onEntry(entry) {
|
||||
function onStatSuccess(info) {
|
||||
// OS.File doesn't seem to be behaving. See Bug 827148.
|
||||
// Let's do the best we can. This whole function is defensive.
|
||||
let date = info.winBirthDate || info.macBirthDate;
|
||||
if (!date || !date.getTime()) {
|
||||
// OS.File will only return file creation times of any kind on Mac
|
||||
// and Windows, where birthTime is defined.
|
||||
// That means we're unable to function on Linux, so we use mtime
|
||||
// instead.
|
||||
self._log.debug("No birth date. Using mtime.");
|
||||
date = info.lastModificationDate;
|
||||
}
|
||||
|
||||
if (date) {
|
||||
let timestamp = date.getTime();
|
||||
self._log.debug("Using date: " + entry.path + " = " + date);
|
||||
if (timestamp < oldest) {
|
||||
oldest = timestamp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function onStatFailure(e) {
|
||||
// Never mind.
|
||||
self._log.debug("Stat failure: " + CommonUtils.exceptionStr(e));
|
||||
}
|
||||
|
||||
return OS.File.stat(entry.path)
|
||||
.then(onStatSuccess, onStatFailure);
|
||||
}
|
||||
|
||||
let promise = iterator.forEach(onEntry);
|
||||
|
||||
function onSuccess() {
|
||||
iterator.close();
|
||||
return oldest;
|
||||
}
|
||||
|
||||
function onFailure(reason) {
|
||||
iterator.close();
|
||||
throw new Error("Unable to fetch oldest profile entry: " + reason);
|
||||
}
|
||||
|
||||
return promise.then(onSuccess, onFailure);
|
||||
},
|
||||
|
||||
/**
|
||||
* Record (and persist) when a profile reset happened. We just store a
|
||||
* single value - the timestamp of the most recent reset - but there is scope
|
||||
* to keep a list of reset times should our health-reporter successor
|
||||
* be able to make use of that.
|
||||
* Returns a promise that is resolved once the file has been written.
|
||||
*/
|
||||
recordProfileReset: function (time=Date.now(), file="times.json") {
|
||||
return this.getTimes(file).then(
|
||||
times => {
|
||||
times.reset = time;
|
||||
return this.writeTimes(times, file);
|
||||
}
|
||||
);
|
||||
},
|
||||
|
||||
/* Returns a promise that resolves to the time the profile was reset,
|
||||
* or undefined if not recorded.
|
||||
*/
|
||||
get reset() {
|
||||
return this.getTimes().then(
|
||||
times => times.reset
|
||||
);
|
||||
},
|
||||
}
|
@ -36,6 +36,7 @@ EXTRA_JS_MODULES += [
|
||||
'PopupNotifications.jsm',
|
||||
'Preferences.jsm',
|
||||
'PrivateBrowsingUtils.jsm',
|
||||
'ProfileAge.jsm',
|
||||
'Promise-backend.js',
|
||||
'Promise.jsm',
|
||||
'PromiseUtils.jsm',
|
||||
|
Loading…
Reference in New Issue
Block a user