You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cordova.apache.org by ca...@apache.org on 2016/08/04 22:43:34 UTC
cordova-create git commit: CB-11623 added symlinking option
Repository: cordova-create
Updated Branches:
refs/heads/master da2e8567a -> fa36b9415
CB-11623 added symlinking option
Project: http://git-wip-us.apache.org/repos/asf/cordova-create/repo
Commit: http://git-wip-us.apache.org/repos/asf/cordova-create/commit/fa36b941
Tree: http://git-wip-us.apache.org/repos/asf/cordova-create/tree/fa36b941
Diff: http://git-wip-us.apache.org/repos/asf/cordova-create/diff/fa36b941
Branch: refs/heads/master
Commit: fa36b94155956d95f6a9cdbf6b342385eae4aeda
Parents: da2e856
Author: carynbear <ca...@berkeley.edu>
Authored: Thu Aug 4 11:28:36 2016 -0700
Committer: carynbear <ca...@berkeley.edu>
Committed: Thu Aug 4 15:06:17 2016 -0700
----------------------------------------------------------------------
index.js | 98 ++++++++++---
spec/create.spec.js | 183 ++++++++++++++++++++++++
spec/templates/noconfig/hooks/hooks.file | 0
spec/templates/noconfig/merges/merges.file | 0
spec/templates/noconfig/www/index.html | 49 +++++++
5 files changed, 312 insertions(+), 18 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cordova-create/blob/fa36b941/index.js
----------------------------------------------------------------------
diff --git a/index.js b/index.js
index b0b3950..ee73b51 100644
--- a/index.js
+++ b/index.js
@@ -189,6 +189,12 @@ module.exports = function(dir, optionalId, optionalName, cfg, extEvents) {
var isGit;
var isNPM;
+ //If symlink, don't fetch
+ if (!!cfg.lib.www.link) {
+ events.emit('verbose', 'Symlinking assets.');
+ return Q(cfg.lib.www.url);
+ }
+
events.emit('verbose', 'Copying assets."');
isGit = cfg.lib.www.template && isUrl(cfg.lib.www.url);
isNPM = cfg.lib.www.template && (cfg.lib.www.url.indexOf('@') > -1 || !fs.existsSync(path.resolve(cfg.lib.www.url)));
@@ -247,14 +253,19 @@ module.exports = function(dir, optionalId, optionalName, cfg, extEvents) {
}
try {
+
// Copy files from template to project
if (cfg.lib.www.template)
copyTemplateFiles(import_from_path, dir, isSubDir);
- // If following were not copied from template, copy from stock app hello world
- ifNotCopied(paths.www, path.join(dir, 'www'));
- ifNotCopied(paths.hooks, path.join(dir, 'hooks'));
- var configXmlExists = projectConfig(dir);
+ // If --link, link merges, hooks, www, and config.xml (and/or copy to root)
+ if (!!cfg.lib.www.link)
+ linkFromTemplate(import_from_path, dir);
+
+ // If following were not copied/linked from template, copy from stock app hello world
+ copyIfNotExists(paths.www, path.join(dir, 'www'));
+ copyIfNotExists(paths.hooks, path.join(dir, 'hooks'));
+ var configXmlExists = projectConfig(dir); //moves config to root if in www
if (paths.configXml && !configXmlExists) {
shell.cp(paths.configXml, path.join(dir, 'config.xml'));
}
@@ -262,17 +273,21 @@ module.exports = function(dir, optionalId, optionalName, cfg, extEvents) {
if (!dirAlreadyExisted) {
shell.rm('-rf', dir);
}
+ if (process.platform.slice(0, 3) == 'win' && e.code == 'EPERM') {
+ throw new CordovaError('Symlinks on Windows require Administrator privileges');
+ }
throw e;
}
- // Update package.json name and version fields.
- if (fs.existsSync(path.join(dir, 'package.json'))) {
- var pkgjson = require(path.resolve(dir, 'package.json'));
+ var pkgjsonPath = path.join(dir, 'package.json');
+ // Update package.json name and version fields
+ if (fs.existsSync(pkgjsonPath)) {
+ var pkgjson = require(pkgjsonPath);
if (cfg.name) {
pkgjson.name = cfg.name.toLowerCase();
}
pkgjson.version = '1.0.0';
- fs.writeFileSync(path.join(dir, 'package.json'), JSON.stringify(pkgjson, null, 4), 'utf8');
+ fs.writeFileSync(pkgjsonPath, JSON.stringify(pkgjson, null, 4), 'utf8');
}
// Create basic project structure.
@@ -282,26 +297,29 @@ module.exports = function(dir, optionalId, optionalName, cfg, extEvents) {
if (!fs.existsSync(path.join(dir, 'plugins')))
shell.mkdir(path.join(dir, 'plugins'));
- // Write out id and name to config.xml; set version to 1.0.0 (to match package.json default version)
- var configPath = projectConfig(dir);
- var conf = new ConfigParser(configPath);
- if (cfg.id) conf.setPackageName(cfg.id);
- if (cfg.name) conf.setName(cfg.name);
- conf.setVersion('1.0.0');
- conf.write();
+ var configPath = path.join(dir, 'config.xml');
+ // only update config.xml if not a symlink
+ if(!fs.lstatSync(configPath).isSymbolicLink()) {
+ // Write out id and name to config.xml; set version to 1.0.0 (to match package.json default version)
+ var conf = new ConfigParser(configPath);
+ if (cfg.id) conf.setPackageName(cfg.id);
+ if (cfg.name) conf.setName(cfg.name);
+ conf.setVersion('1.0.0');
+ conf.write();
+ }
}).then(function(){
cleanupEvents();
});
};
/**
- * Recursively copies folder to destination if folder is not found in destination.
+ * Recursively copies folder to destination if folder is not found in destination (including symlinks).
* @param {string} src for copying
* @param {string} dst for copying
* @return No return value
*/
-function ifNotCopied(src, dst) {
- if (!fs.existsSync(dst) && src) {
+function copyIfNotExists(src, dst) {
+ if (!fs.existsSync(dst) && !fs.lstatSync(dst).isSymbolicLink() && src) {
shell.mkdir(dst);
shell.cp('-R', path.join(src, '*'), dst);
}
@@ -410,3 +428,47 @@ function writeToConfigJson(project_root, opts, autoPersist) {
return json;
}
}
+
+/**
+ * Removes existing files and symlinks them if they exist.
+ * Symlinks folders: www, merges, hooks
+ * Symlinks file: config.xml (but only if it exists outside of the www folder)
+ * If config.xml exists inside of template/www, COPY (not link) it to project/
+ * */
+ function linkFromTemplate(templateDir, projectDir) {
+ var linkSrc, linkDst, linkFolders, copySrc, copyDst;
+ function rmlinkSync(src, dst, type) {
+ if (src && dst) {
+ if (fs.existsSync(dst)) {
+ shell.rm('-rf', dst);
+ }
+ if (fs.existsSync(src)) {
+ fs.symlinkSync(src, dst, type);
+ }
+ }
+ }
+ // if template is a www dir
+ if (path.basename(templateDir) === 'www') {
+ linkSrc = path.resolve(templateDir);
+ linkDst = path.join(projectDir, 'www');
+ rmlinkSync(linkSrc, linkDst, 'dir');
+ copySrc = path.join(templateDir, 'config.xml');
+ } else {
+ linkFolders = ['www', 'merges', 'hooks'];
+ // Link each folder
+ for (var i = 0; i < linkFolders.length; i++) {
+ linkSrc = path.join(templateDir, linkFolders[i]);
+ linkDst = path.join(projectDir, linkFolders[i]);
+ rmlinkSync(linkSrc, linkDst, 'dir');
+ }
+ linkSrc = path.join(templateDir, 'config.xml');
+ linkDst = path.join(projectDir, 'config.xml');
+ rmlinkSync(linkSrc, linkDst, 'file');
+ copySrc = path.join(templateDir, 'www', 'config.xml');
+ }
+ // if template/www/config.xml then copy to project/config.xml
+ copyDst = path.join(projectDir, 'config.xml');
+ if (!fs.existsSync(copyDst) && fs.existsSync(copySrc)) {
+ shell.cp(copySrc, projectDir);
+ }
+ }
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cordova-create/blob/fa36b941/spec/create.spec.js
----------------------------------------------------------------------
diff --git a/spec/create.spec.js b/spec/create.spec.js
index 8ad0693..d564c61 100644
--- a/spec/create.spec.js
+++ b/spec/create.spec.js
@@ -23,6 +23,7 @@ var helpers = require('./helpers'),
events = require('cordova-common').events,
ConfigParser = require('cordova-common').ConfigParser,
create = require('../index'),
+ fs = require('fs'),
CordovaLogger = require('cordova-common').CordovaLogger.get().setLevel('error');
var tmpDir = helpers.tmpDir('create_test');
@@ -328,4 +329,186 @@ describe('create end-to-end', function() {
.fin(done);
}, 60000);
+ describe('when --link-to is provided', function() {
+ it('when passed www folder should not move www/config.xml, only copy and update', function(done) {
+ function checkSymWWW() {
+ // Check if top level dirs exist.
+ var dirs = ['hooks', 'platforms', 'plugins', 'www'];
+ dirs.forEach(function(d) {
+ expect(path.join(project, d)).toExist();
+ });
+ expect(path.join(project, 'hooks', 'README.md')).toExist();
+
+ // Check if www files exist.
+ expect(path.join(project, 'www', 'index.html')).toExist();
+
+ // Check www/config exists
+ expect(path.join(project, 'www', 'config.xml')).toExist();
+ // Check www/config.xml was not updated.
+ var configXml = new ConfigParser(path.join(project, 'www', 'config.xml'));
+ expect(configXml.packageName()).toEqual('io.cordova.hellocordova');
+ expect(configXml.version()).toEqual('0.0.1');
+ expect(configXml.description()).toEqual('this is the correct config.xml');
+
+ // Check that config.xml was copied to project/config.xml
+ expect(path.join(project, 'config.xml')).toExist();
+ configXml = new ConfigParser(path.join(project, 'config.xml'));
+ expect(configXml.description()).toEqual('this is the correct config.xml');
+ // Check project/config.xml was updated.
+ expect(configXml.packageName()).toEqual(appId);
+ expect(configXml.version()).toEqual('1.0.0');
+
+ // Check that we got no package.json
+ expect(path.join(project, 'package.json')).not.toExist();
+
+ // Check that www is really a symlink,
+ // and project/config.xml , hooks and merges are not
+ expect(fs.lstatSync(path.join(project, 'www')).isSymbolicLink()).toBe(true);
+ expect(fs.lstatSync(path.join(project, 'hooks')).isSymbolicLink()).not.toBe(true);
+ expect(fs.lstatSync(path.join(project, 'config.xml')).isSymbolicLink()).not.toBe(true);
+ }
+ var config = {
+ lib: {
+ www: {
+ template: true,
+ url: path.join(__dirname, 'templates', 'config_in_www', 'www'),
+ version: '',
+ link: true
+ }
+ }
+ };
+ project = project + '4';
+ return create(project, appId, appName, config)
+ .then(checkSymWWW)
+ .fail(function(err) {
+ if(process.platform.slice(0, 3) == 'win') {
+ // Allow symlink error if not in admin mode
+ expect(err.message).toBe('Symlinks on Windows require Administrator privileges');
+ } else {
+ if (err) {
+ console.log(err.stack);
+ }
+ expect(err).toBeUndefined();
+ }
+ })
+ .fin(done);
+ }, 60000);
+
+ it('with subdirectory should not update symlinked project/config.xml', function(done) {
+ function checkSymSubDir() {
+ // Check if top level dirs exist.
+ var dirs = ['hooks', 'platforms', 'plugins', 'www'];
+ dirs.forEach(function(d) {
+ expect(path.join(project, d)).toExist();
+ });
+ expect(path.join(project, 'hooks', 'README.md')).toExist();
+
+ //index.js and template subdir folder should not exist (inner files should be copied to the project folder)
+ expect(path.join(project, 'index.js')).not.toExist();
+ expect(path.join(project, 'template')).not.toExist();
+
+ // Check if www files exist.
+ expect(path.join(project, 'www', 'index.html')).toExist();
+
+ // Check that www, and config.xml is really a symlink
+ expect(fs.lstatSync(path.join(project, 'www')).isSymbolicLink()).toBe(true);
+ expect(fs.lstatSync(path.join(project, 'config.xml')).isSymbolicLink()).toBe(true);
+
+ // Check that config.xml was not updated. (symlinked config does not get updated!)
+ var configXml = new ConfigParser(path.join(project, 'config.xml'));
+ expect(configXml.packageName()).toEqual('io.cordova.hellocordova');
+ expect(configXml.version()).toEqual('0.0.1');
+
+ // Check that we got the right config.xml
+ expect(configXml.description()).toEqual('this is the correct config.xml');
+
+ // Check that we got package.json (the correct one) and it was changed
+ var pkjson = require(path.join(project, 'package.json'));
+ expect(pkjson.name).toEqual(appName.toLowerCase());
+ expect(pkjson.valid).toEqual('true');
+ }
+ var config = {
+ lib: {
+ www: {
+ template: true,
+ url: path.join(__dirname, 'templates', 'withsubdirectory_package_json'),
+ version: '',
+ link: true
+ }
+ }
+ };
+ project = project + '5';
+ return create(project, appId, appName, config)
+ .then(checkSymSubDir)
+ .fail(function(err) {
+ if(process.platform.slice(0, 3) == 'win') {
+ // Allow symlink error if not in admin mode
+ expect(err.message).toBe('Symlinks on Windows require Administrator privileges');
+ } else {
+ if (err) {
+ console.log(err.stack);
+ }
+ expect(err).toBeUndefined();
+ }
+ })
+ .fin(done);
+ }, 60000);
+
+ it('with no config should create one and update it', function(done) {
+ function checkSymNoConfig() {
+ // Check if top level dirs exist.
+ var dirs = ['hooks', 'platforms', 'plugins', 'www'];
+ dirs.forEach(function(d) {
+ expect(path.join(project, d)).toExist();
+ });
+ expect(path.join(project, 'hooks', 'hooks.file')).toExist();
+ expect(path.join(project, 'merges', 'merges.file')).toExist();
+
+ // Check if www files exist.
+ expect(path.join(project, 'www', 'index.html')).toExist();
+
+ // Check that config.xml was updated.
+ var configXml = new ConfigParser(path.join(project, 'config.xml'));
+ expect(configXml.packageName()).toEqual(appId);
+
+ // Check that www, hooks, merges are really a symlink; config is not
+ expect(fs.lstatSync(path.join(project, 'www')).isSymbolicLink()).toBe(true);
+ expect(fs.lstatSync(path.join(project, 'hooks')).isSymbolicLink()).toBe(true);
+ expect(fs.lstatSync(path.join(project, 'merges')).isSymbolicLink()).toBe(true);
+ expect(fs.lstatSync(path.join(project, 'config.xml')).isSymbolicLink()).not.toBe(true);
+ }
+
+ var config = {
+ lib: {
+ www: {
+ template: true,
+ url: path.join(__dirname, 'templates', 'noconfig'),
+ version: '',
+ link: true
+ }
+ }
+ };
+ project = project + '6';
+ return create(project, appId, appName, config)
+ .then(checkSymNoConfig)
+ .fail(function(err) {
+ if(process.platform.slice(0, 3) == 'win') {
+ // Allow symlink error if not in admin mode
+ expect(err.message).toBe('Symlinks on Windows require Administrator privileges');
+ } else {
+ if (err) {
+ console.log(err.stack);
+ }
+ expect(err).toBeUndefined();
+ }
+ })
+ .fin(done);
+ }, 60000);
+
+ });
+
+
+
+
+
});
http://git-wip-us.apache.org/repos/asf/cordova-create/blob/fa36b941/spec/templates/noconfig/hooks/hooks.file
----------------------------------------------------------------------
diff --git a/spec/templates/noconfig/hooks/hooks.file b/spec/templates/noconfig/hooks/hooks.file
new file mode 100644
index 0000000..e69de29
http://git-wip-us.apache.org/repos/asf/cordova-create/blob/fa36b941/spec/templates/noconfig/merges/merges.file
----------------------------------------------------------------------
diff --git a/spec/templates/noconfig/merges/merges.file b/spec/templates/noconfig/merges/merges.file
new file mode 100644
index 0000000..e69de29
http://git-wip-us.apache.org/repos/asf/cordova-create/blob/fa36b941/spec/templates/noconfig/www/index.html
----------------------------------------------------------------------
diff --git a/spec/templates/noconfig/www/index.html b/spec/templates/noconfig/www/index.html
new file mode 100644
index 0000000..646f9cb
--- /dev/null
+++ b/spec/templates/noconfig/www/index.html
@@ -0,0 +1,49 @@
+<!DOCTYPE html>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+-->
+<html>
+ <head>
+ <!--
+ Customize this policy to fit your own app's needs. For more guidance, see:
+ https://github.com/apache/cordova-plugin-whitelist/blob/master/README.md#content-security-policy
+ Some notes:
+ * gap: is required only on iOS (when using UIWebView) and is needed for JS->native communication
+ * https://ssl.gstatic.com is required only on Android and is needed for TalkBack to function properly
+ * Disables use of inline scripts in order to mitigate risk of XSS vulnerabilities. To change this:
+ * Enable inline JS: add 'unsafe-inline' to default-src
+ -->
+ <meta http-equiv="Content-Security-Policy" content="default-src 'self' data: gap: https://ssl.gstatic.com 'unsafe-eval'; style-src 'self' 'unsafe-inline'; media-src *">
+ <meta name="format-detection" content="telephone=no">
+ <meta name="msapplication-tap-highlight" content="no">
+ <meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width">
+ <link rel="stylesheet" type="text/css" href="css/index.css">
+ <title>Hello World</title>
+ </head>
+ <body>
+ <div class="app">
+ <h1>Apache Cordova</h1>
+ <div id="deviceready" class="blink">
+ <p class="event listening">Connecting to Device</p>
+ <p class="event received">Device is Ready</p>
+ </div>
+ </div>
+ <script type="text/javascript" src="cordova.js"></script>
+ <script type="text/javascript" src="js/index.js"></script>
+ </body>
+</html>
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@cordova.apache.org
For additional commands, e-mail: commits-help@cordova.apache.org