Return-Path: X-Original-To: archive-asf-public-internal@cust-asf2.ponee.io Delivered-To: archive-asf-public-internal@cust-asf2.ponee.io Received: from cust-asf.ponee.io (cust-asf.ponee.io [163.172.22.183]) by cust-asf2.ponee.io (Postfix) with ESMTP id BB414200B7F for ; Fri, 5 Aug 2016 00:43:36 +0200 (CEST) Received: by cust-asf.ponee.io (Postfix) id B9E6C160AAE; Thu, 4 Aug 2016 22:43:36 +0000 (UTC) Delivered-To: archive-asf-public@cust-asf.ponee.io Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by cust-asf.ponee.io (Postfix) with SMTP id B304A160AAB for ; Fri, 5 Aug 2016 00:43:35 +0200 (CEST) Received: (qmail 59512 invoked by uid 500); 4 Aug 2016 22:43:34 -0000 Mailing-List: contact commits-help@cordova.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Delivered-To: mailing list commits@cordova.apache.org Received: (qmail 59503 invoked by uid 99); 4 Aug 2016 22:43:34 -0000 Received: from git1-us-west.apache.org (HELO git1-us-west.apache.org) (140.211.11.23) by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 04 Aug 2016 22:43:34 +0000 Received: by git1-us-west.apache.org (ASF Mail Server at git1-us-west.apache.org, from userid 33) id C8CF1E0A7D; Thu, 4 Aug 2016 22:43:34 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: carynbear@apache.org To: commits@cordova.apache.org Message-Id: <1ac93162a08f4e6f87224ef586de553a@git.apache.org> X-Mailer: ASF-Git Admin Mailer Subject: cordova-create git commit: CB-11623 added symlinking option Date: Thu, 4 Aug 2016 22:43:34 +0000 (UTC) archived-at: Thu, 04 Aug 2016 22:43:36 -0000 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 Authored: Thu Aug 4 11:28:36 2016 -0700 Committer: carynbear 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 @@ + + + + + + + + + + + Hello World + + +
+

Apache Cordova

+ +
+ + + + --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscribe@cordova.apache.org For additional commands, e-mail: commits-help@cordova.apache.org