Skip to content
This repository has been archived by the owner on Nov 3, 2021. It is now read-only.

Commit

Permalink
Merge pull request #18317 from cctuan/983573-new
Browse files Browse the repository at this point in the history
bug 983573 - [Gaia] Refactoring webapp-manifest.js
  • Loading branch information
cctuan committed May 8, 2014
2 parents 4bb6458 + 7cd746c commit 42b468d
Show file tree
Hide file tree
Showing 14 changed files with 621 additions and 338 deletions.
31 changes: 21 additions & 10 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -478,7 +478,7 @@ export BUILD_CONFIG
include build/common.mk

# Generate profile/
$(PROFILE_FOLDER): preferences app-makefiles keyboard-layouts copy-build-stage-manifest test-agent-config offline contacts extensions $(XULRUNNER_BASE_DIRECTORY) .git/hooks/pre-commit $(PROFILE_FOLDER)/settings.json create-default-data $(PROFILE_FOLDER)/installed-extensions.json
$(PROFILE_FOLDER): preferences post-manifest app-makefiles keyboard-layouts copy-build-stage-data test-agent-config offline contacts extensions $(XULRUNNER_BASE_DIRECTORY) .git/hooks/pre-commit create-default-data $(PROFILE_FOLDER)/installed-extensions.json
ifeq ($(BUILD_APP_NAME),*)
@echo "Profile Ready: please run [b2g|firefox] -profile $(CURDIR)$(SEP)$(PROFILE_FOLDER)"
endif
Expand All @@ -493,7 +493,7 @@ $(STAGE_DIR):
# FIXME: we use |STAGE_APP_DIR="../../build_stage/$$APP"| here because we got
# some problem on Windows if use absolute path.
.PHONY: app-makefiles
app-makefiles: $(XULRUNNER_BASE_DIRECTORY) keyboard-layouts webapp-manifests svoperapps clear-stage-app webapp-shared | $(STAGE_DIR)
app-makefiles: $(XULRUNNER_BASE_DIRECTORY) keyboard-layouts $(STAGE_DIR)/settings_stage.json webapp-manifests svoperapps clear-stage-app webapp-shared | $(STAGE_DIR)
@for appdir in $(GAIA_APPDIRS); \
do \
APP="`basename $$appdir`"; \
Expand Down Expand Up @@ -540,7 +540,7 @@ LANG=POSIX # Avoiding sort order differences between OSes
# in that case. Right now this is just making sure we don't race app-makefiles
# in case someone does decide to get fancy.
.PHONY: webapp-manifests
webapp-manifests: $(XULRUNNER_BASE_DIRECTORY)
webapp-manifests: $(XULRUNNER_BASE_DIRECTORY) $(STAGE_DIR)
@$(call run-js-command,webapp-manifests)

.PHONY: webapp-zip
Expand Down Expand Up @@ -572,9 +572,14 @@ optimize-clean: webapp-zip $(XULRUNNER_BASE_DIRECTORY)

.PHONY: keyboard-layouts
# A separate step for shared/ folder to generate its content in build time
keyboard-layouts: webapp-manifests $(XULRUNNER_BASE_DIRECTORY)
keyboard-layouts: webapp-manifests $(XULRUNNER_BASE_DIRECTORY)
@$(call run-js-command,keyboard-layouts)

.PHONY: post-manifest
# Updates hostnames for InterApp Communication APIs.
post-manifest: app-makefiles $(XULRUNNER_BASE_DIRECTORY)
@$(call run-js-command,post-manifest)

# Get additional extensions
$(PROFILE_FOLDER)/installed-extensions.json: build/config/additional-extensions.json $(wildcard .build/config/custom-extensions.json)
ifeq ($(SIMULATOR),1)
Expand Down Expand Up @@ -1024,7 +1029,9 @@ purge:
$(ADB) shell rm -r $(MSYS_FIX)/system/b2g/webapps
$(ADB) shell 'if test -d $(MSYS_FIX)/persist/svoperapps; then rm -r $(MSYS_FIX)/persist/svoperapps; fi'

$(PROFILE_FOLDER)/settings.json: profile-dir keyboard-layouts $(XULRUNNER_BASE_DIRECTORY)
$(PROFILE_FOLDER)/settings.json: $(XULRUNNER_BASE_DIRECTORY) profile-dir keyboard-layouts $(STAGE_DIR)/settings_stage.json copy-build-stage-data

$(STAGE_DIR)/settings_stage.json: $(XULRUNNER_BASE_DIRECTORY) keyboard-layouts
ifeq ($(BUILD_APP_NAME),*)
@$(call run-js-command,settings)
endif
Expand Down Expand Up @@ -1066,11 +1073,15 @@ really-clean: clean
.git/hooks/pre-commit: tools/pre-commit
test -d .git && cp tools/pre-commit .git/hooks/pre-commit && chmod +x .git/hooks/pre-commit || true

# Generally we got manifest from webapp-manifest.js unless manifest is generated
# from Makefile of app. so we will copy manifest.webapp if it's avaiable in
# build_stage/
copy-build-stage-manifest: app-makefiles multilocale
@$(call run-js-command,copy-build-stage-manifest)

# This task will do three things.
# 1. Copy manifest to profile: generally we got manifest from webapp-manifest.js
# unless manifest is generated from Makefile of app. so we will copy
# manifest.webapp if it's avaiable in build_stage/ .
# 2. Copy external app to profile dir.
# 3. Generate webapps.json from webapps_stage.json and copy to profile dir.
copy-build-stage-data: app-makefiles post-manifest multilocale
@$(call run-js-command,copy-build-stage-data)

build-test-unit: $(NPM_INSTALLED_PROGRAMS)
@$(call run-build-test, $(shell find build/test/unit/*.test.js))
Expand Down
4 changes: 2 additions & 2 deletions apps/homescreen/build/build.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ HomescreenAppBuilder.prototype.BASE_ICON_SIZE = 60;
HomescreenAppBuilder.prototype.setOptions = function(options) {
this.stageDir = utils.getFile(options.STAGE_APP_DIR);

let mappingFile = utils.getFile(options.STAGE_DIR, 'webapps-mapping.json');
let mappingFile = utils.getFile(options.STAGE_DIR, 'webapps_stage.json');
if (!mappingFile.exists()) {
throw new Error('build_stage/webapps-mapping.json not found.');
throw new Error('build_stage/webapps_stage.json not found.');
}
this.webappsMapping = utils.getJSON(mappingFile);

Expand Down
154 changes: 154 additions & 0 deletions build/copy-build-stage-data.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
// This script is to copy necessary data from build_stage to profile folder,
// include
// 1. copy external app, which may rename the name of stage folder to uuid name.
// 2. generate webapps.json in profile by webapps_stage.json.
// 3. generate settings.json in profile by settings_stage.json.
const utils = require('./utils');

function moveExternalApp(webapp, source, destination) {
// In case of packaged app, just copy `application.zip` and `update.webapp`
if (webapp.pckManifest) {
var updateManifest = source.clone();
updateManifest.append('update.webapp');
if (!updateManifest.exists()) {
throw 'External packaged webapp `' + webapp.domain + ' is ' +
'missing an `update.webapp` file. This JSON file ' +
'contains a `package_path` attribute specifying where ' +
'to download the application zip package from the origin ' +
'specified in `metadata.json` file.';
return;
}
var appPackage = source.clone();
appPackage.append('application.zip');
appPackage.copyTo(destination, 'application.zip');
updateManifest.copyTo(destination, 'update.webapp');
} else {
webapp.manifestFile.copyTo(destination, 'manifest.webapp');

// This is an hosted app. Check if there is an offline cache.
var srcCacheFolder = source.clone();
srcCacheFolder.append('cache');
if (srcCacheFolder.exists()) {
var cacheManifest = srcCacheFolder.clone();
cacheManifest.append('manifest.appcache');
if (!cacheManifest.exists()) {
throw 'External webapp `' + webapp.domain +
'` has a cache directory without `manifest.appcache`' +
' file.';
return;
}

// Copy recursively the whole cache folder to webapp folder
var targetCacheFolder = destination.clone();
targetCacheFolder.append('cache');
utils.copyRec(srcCacheFolder, targetCacheFolder);
}
}
}

function cleanProfile(webappsDir) {
// Profile can contain folders with a generated uuid that need to be deleted
// or apps will be duplicated.
var expreg = /^{[\w]{8}-[\w]{4}-[\w]{4}-[\w]{4}-[\w]{12}}$/;
utils.ls(webappsDir, false).forEach(function(dir) {
if (expreg.test(dir.leafName)) {
dir.remove(true);
}
});
}

/**
* Generate data for webapps.json.
*/
function genWebappJSON(config) {
var configItems = ['origin', 'installOrigin', 'receipt', 'installTime',
'updateTime', 'manifestURL', 'removable', 'localId',
'etag', 'packageEtag', 'appStatus'];
var resultJSON = {};

configItems.forEach(function(key) {
if (key in config) {
resultJSON[key] = config[key];
}
});
return resultJSON;
}

/**
* Copy settings_stage.json under stage to settings.json under profile.
*/
function copySettingsJStoProfile(stageDir, profileDir) {
var settingsFile = stageDir.clone();
settingsFile.append('settings_stage.json');
settingsFile.copyTo(profileDir, 'settings.json');
}

function execute(options) {

const WEBAPP_FILENAME = 'manifest.webapp';
const UPDATE_WEBAPP_FILENAME = 'update.webapp';
var webappsJSON = {};
var gaia = utils.gaia.getInstance(options);
var webappsBaseDir = utils.getFile(options.PROFILE_DIR);
var stageDir = gaia.stageDir;

if (options.BUILD_APP_NAME === '*') {
copySettingsJStoProfile(stageDir, webappsBaseDir);
}

var webappsJSONFile = stageDir.clone();
webappsJSONFile.append('webapps_stage.json');
var webappsStageJSON = utils.getJSON(webappsJSONFile);

webappsBaseDir.append('webapps');

if (webappsBaseDir.exists()) {
// remove all external app with uuid folder name
cleanProfile(webappsBaseDir);
} else {
utils.ensureFolderExists(webappsBaseDir);
}

gaia.webapps.forEach(function(app) {
var webappManifest = app.buildDirectoryFile.clone();
var updateManifest = app.buildDirectoryFile.clone();

webappManifest.append(WEBAPP_FILENAME);
updateManifest.append(UPDATE_WEBAPP_FILENAME);

var stageManifest =
webappManifest.exists() ? webappManifest : updateManifest;

if (!stageManifest.exists()) {
return;
}

// Compute webapp folder name in profile
let webappTargetDir = webappsBaseDir.clone();

// Preparing webapps.json content
var appConfig = webappsStageJSON[app.sourceDirectoryName];
var webappTargetDirName = appConfig.webappTargetDirName;
webappsJSON[webappTargetDirName] = genWebappJSON(appConfig);

webappTargetDir.append(webappTargetDirName);
utils.ensureFolderExists(webappTargetDir);
if (utils.isExternalApp(app)) {
var appSource = stageDir.clone();
appSource.append(app.sourceDirectoryName);
moveExternalApp(app, appSource, webappTargetDir);
return;
}

// We'll remove it once bug 968666 is merged.
var targetManifest = webappTargetDir.clone();
stageManifest.copyTo(targetManifest, WEBAPP_FILENAME);
});

var manifestFile = webappsBaseDir.clone();
manifestFile.append('webapps.json');
utils.writeContent(manifestFile,
JSON.stringify(webappsJSON, null, 2) + '\n');
}

exports.execute = execute;
20 changes: 0 additions & 20 deletions build/copy-build-stage-manifest.js

This file was deleted.

2 changes: 1 addition & 1 deletion build/keyboard-layouts.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ function execute(options) {
// Get web apps mapping file
let stageFolder = utils.getEnv('STAGE_DIR');
let webappsMappingFile = utils.resolve(
utils.joinPath(stageFolder, 'webapps-mapping.json'),
utils.joinPath(stageFolder, 'webapps_stage.json'),
options.GAIA_DIR);

if (!webappsMappingFile.exists()) {
Expand Down
59 changes: 59 additions & 0 deletions build/post-manifest.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// Bug 957418, we need this to fix the origin case when
// running in Firefox Nightly. We change the origin from app:// to
// http:// so the ports will work properly in Nightly, so we still need
// this unless there is a better way of doing it.
const utils = require('./utils');

/**
* Updates hostnames for InterApp Communication APIs
*/
function manifestInterAppHostnames(manifest, config) {
function convertToLocalUrl(url) {
var host = config.GAIA_DOMAIN + config.GAIA_PORT;

return url
.replace(/^(http|app):\/\//, config.GAIA_SCHEME)
.replace(/gaiamobile.org(:[0-9])?/, host);
}
if (manifest.connections) {
for (let i in manifest.connections) {
var connection = manifest.connections[i];
if (!connection.rules || !connection.rules.manifestURLs) {
continue;
}

var manifestURLs = connection.rules.manifestURLs;
manifestURLs = manifestURLs.map(convertToLocalUrl);
}
}
return manifest;
}

function execute(options) {
const WEBAPP_FILENAME = 'manifest.webapp';
const UPDATE_WEBAPP_FILENAME = 'update.webapp';

var gaia = utils.gaia.getInstance(options);
var webappsBaseDir = gaia.stageDir;
gaia.webapps.forEach(function(app) {
if (utils.isExternalApp(app)) {
return;
}

var webappManifest = app.buildDirectoryFile.clone();
var updateManifest = app.buildDirectoryFile.clone();
webappManifest.append(WEBAPP_FILENAME);
updateManifest.append(UPDATE_WEBAPP_FILENAME);
var stageManifest =
webappManifest.exists() ? webappManifest : updateManifest;

if (!stageManifest.exists()) {
return;
}

var manifestContent = utils.getJSON(stageManifest);
manifestContent = manifestInterAppHostnames(manifestContent, options);
utils.writeContent(stageManifest, JSON.stringify(manifestContent));
});
}
exports.execute = execute;
2 changes: 1 addition & 1 deletion build/settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ function overrideSettings(settings, config) {

function writeSettings(settings, config) {
// Finally write the settings file
let settingsFile = utils.getFile(config.PROFILE_DIR, 'settings.json');
let settingsFile = utils.getFile(config.STAGE_DIR, 'settings_stage.json');
let content = JSON.stringify(settings);
utils.writeContent(settingsFile, content + '\n');
}
Expand Down
7 changes: 7 additions & 0 deletions build/test/integration/helper.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,15 @@ function checkPrefs(actual, expected) {
}

function checkWebappsScheme(webapps) {
var configKeys = ['origin', 'installOrigin', 'receipt', 'installTime',
'updateTime', 'manifestURL', 'localId', 'appStatus'];

Object.keys(webapps).forEach(function(key) {
var webapp = webapps[key];
configKeys.forEach(function(configKey) {
assert.equal((configKey in webapp), true,
key + ' of webapps.json has not defined ' + configKey);
});
var scheme =
webapp.origin.indexOf('mochi.test') !== -1 ||
webapp.origin.indexOf('marketplace.allizom.org') !== -1 ||
Expand Down
5 changes: 3 additions & 2 deletions build/test/unit/settings.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ suite('settings.js', function() {
config = {
GAIA_DISTRIBUTION_DIR: 'testDistributionDir',
GAIA_DIR: 'testGaia',
SETTINGS_PATH: 'testSettingsPath'
SETTINGS_PATH: 'testSettingsPath',
STAGE_DIR: 'testStageDir'
};
mockUtils.resolve = function(file, baseLink) {
var fileExist = false;
Expand Down Expand Up @@ -143,7 +144,7 @@ suite('settings.js', function() {
};
};
mockUtils.writeContent = function(target, string) {
if (target.path === config.PROFILE_DIR + '/settings.json') {
if (target.path === config.STAGE_DIR + '/settings_stage.json') {
settingsFile.result = string;
}
};
Expand Down
Loading

0 comments on commit 42b468d

Please sign in to comment.