You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cordova.apache.org by cs...@apache.org on 2015/12/03 23:59:34 UTC

cordova-lib git commit: CB-9964 Added --template to Cordova Create

Repository: cordova-lib
Updated Branches:
  refs/heads/master 7af5c5367 -> ac57bebf3


CB-9964 Added --template to Cordova Create


Project: http://git-wip-us.apache.org/repos/asf/cordova-lib/repo
Commit: http://git-wip-us.apache.org/repos/asf/cordova-lib/commit/ac57bebf
Tree: http://git-wip-us.apache.org/repos/asf/cordova-lib/tree/ac57bebf
Diff: http://git-wip-us.apache.org/repos/asf/cordova-lib/diff/ac57bebf

Branch: refs/heads/master
Commit: ac57bebf3b567f825fe6e586b34ddaa748a27185
Parents: 7af5c53
Author: dubeejw <jw...@us.ibm.com>
Authored: Thu Nov 5 16:05:06 2015 -0500
Committer: Carlos Santana <cs...@gmail.com>
Committed: Thu Dec 3 17:57:22 2015 -0500

----------------------------------------------------------------------
 cordova-lib/spec-cordova/create.spec.js | 113 +++++++++++++++-----
 cordova-lib/src/cordova/create.js       | 127 +++++++++++++++++++----
 cordova-lib/src/cordova/remote_load.js  | 147 +++++++++++++++++++++++++++
 3 files changed, 341 insertions(+), 46 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/ac57bebf/cordova-lib/spec-cordova/create.spec.js
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-cordova/create.spec.js b/cordova-lib/spec-cordova/create.spec.js
index 0cbddc8..1f4be51 100644
--- a/cordova-lib/spec-cordova/create.spec.js
+++ b/cordova-lib/spec-cordova/create.spec.js
@@ -30,6 +30,7 @@ var tmpDir = helpers.tmpDir('create_test');
 var appName = 'TestBase';
 var appId = 'org.testing';
 var project = path.join(tmpDir, appName);
+
 var configNormal = {
       lib: {
         www: {
@@ -48,6 +49,28 @@ var configSymlink = {
       }
     };
 
+var configGit = {
+    lib: {
+        www: {
+            url: 'https://github.com/apache/cordova-app-hello-world',
+            template: true,
+            version: 'not_versioned',
+            id: appName
+        }
+    }
+};
+
+var configNPM = {
+    lib: {
+        www: {
+            template: true,
+            url: 'cordova-app-hello-world',
+            version: '',
+            id: appName
+        }
+    }
+};
+
 describe('cordova create checks for valid-identifier', function(done) {
 
     it('should reject reserved words from start of id', function(done) {
@@ -69,11 +92,14 @@ describe('cordova create checks for valid-identifier', function(done) {
 
 
 describe('create end-to-end', function() {
+    //this.timeout(240000);
 
     beforeEach(function() {
         shell.rm('-rf', project);
         shell.mkdir('-p', tmpDir);
     });
+
+
     afterEach(function() {
         process.chdir(path.join(__dirname, '..'));  // Needed to rm the dir on Windows.
         shell.rm('-rf', tmpDir);
@@ -92,7 +118,7 @@ describe('create end-to-end', function() {
         expect(path.join(project, 'www', 'index.html')).toExist();
 
         // Check that www/config.xml was updated.
-        var configXml = new ConfigParser(path.join(project, 'www', 'config.xml'));
+        var configXml = new ConfigParser(path.join(project, 'config.xml'));
         expect(configXml.packageName()).toEqual(appId);
 
         // TODO (kamrik): check somehow that we got the right config.xml from the fixture and not some place else.
@@ -105,37 +131,70 @@ describe('create end-to-end', function() {
     it('should successfully run with regular config', function(done) {
         // Call cordova create with no args, should return help.
         Q()
-        .then(function() {
-            // Create a real project
-            return cordova.raw.create(project, appId, appName, configNormal);
-        })
-        .then(checkProject)
-        .fail(function(err) {
-            console.log(err && err.stack);
-            expect(err).toBeUndefined();
-        })
-        .fin(done);
+            .then(function() {
+                // Create a real project
+                return cordova.raw.create(project, appId, appName, configNormal);
+            })
+            .then(checkProject)
+            .fail(function(err) {
+                console.log(err && err.stack);
+                expect(err).toBeUndefined();
+            })
+            .fin(done);
     });
 
     it('should successfully run with symlinked www', function(done) {
         // Call cordova create with no args, should return help.
         cordova.raw.create(project, appId, appName, configSymlink)
-        .then(checkProject)
-        .then(function() {
-            // Check that www is really a symlink
-            expect(fs.lstatSync(path.join(project, 'www')).isSymbolicLink()).toBe(true);
-        })
-        .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);
+            .then(checkProject)
+            .then(function() {
+                // Check that www is really a symlink
+                expect(fs.lstatSync(path.join(project, 'www')).isSymbolicLink()).toBe(true);
+            })
+            .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);
+    });
+
+   it('should successfully run with Git URL', function(done) {
+        // Call cordova create with no args, should return help.
+        Q()
+            .then(function() {
+                // Create a real project
+                return cordova.raw.create(project, appId, appName, configGit);
+            })
+            .then(checkProject)
+            .fail(function(err) {
+                console.log(err && err.stack);
                 expect(err).toBeUndefined();
-            }
-        })
-        .fin(done);
+            })
+            .fin(done);
+    }, 60000);
+
+    it('should successfully run with NPM package', function(done) {
+        // Call cordova create with no args, should return help.
+        Q()
+            .then(function() {
+                // Create a real project
+                return cordova.raw.create(project, appId, appName, configNPM);
+            })
+            .then(checkProject)
+            .fail(function(err) {
+                console.log(err && err.stack);
+                expect(err).toBeUndefined();
+            })
+            .fin(done);
     });
-});
+
+
+
+});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/ac57bebf/cordova-lib/src/cordova/create.js
----------------------------------------------------------------------
diff --git a/cordova-lib/src/cordova/create.js b/cordova-lib/src/cordova/create.js
index 1f5e010..b848a16 100644
--- a/cordova-lib/src/cordova/create.js
+++ b/cordova-lib/src/cordova/create.js
@@ -22,7 +22,7 @@ var path          = require('path'),
     shell         = require('shelljs'),
     events        = require('cordova-common').events,
     config        = require('./config'),
-    lazy_load     = require('./lazy_load'),
+    remoteLoad = require('./remote_load'),
     Q             = require('q'),
     CordovaError  = require('cordova-common').CordovaError,
     ConfigParser  = require('cordova-common').ConfigParser,
@@ -40,7 +40,7 @@ var path          = require('path'),
 module.exports = create;
 function create(dir, optionalId, optionalName, cfg) {
     var argumentCount = arguments.length;
-    
+
     return Q.fcall(function() {
         // Lets check prerequisites first
 
@@ -165,24 +165,67 @@ function create(dir, optionalId, optionalName, cfg) {
         config.setAutoPersist(origAutoPersist);
     })
     .then(function() {
+        var gitURL;
+        var branch;
+        var parseArr;
+        var packageName;
+        var packageVersion;
+        var isGit;
+        var isNPM;
+
         if (!!cfg.lib.www.link) {
             events.emit('verbose', 'Symlinking assets."');
             return cfg.lib.www.url;
         } else {
             events.emit('verbose', 'Copying assets."');
-            return lazy_load.custom({ 'www': cfg.lib.www }, 'www')
-            .fail(function (error) {
-                var message = 'Failed to fetch custom www assets from ' + cfg.lib.www +
-                    '\nProbably this is either a connection problem, or assets URL is incorrect.' +
-                    '\nCheck your connection and assets URL.' +
-                    '\n' + error;
-                return Q.reject(message);
-            });
+
+            isGit = cfg.lib.www.template && cordova_util.isUrl(cfg.lib.www.url);
+            isNPM = cfg.lib.www.template && (cfg.lib.www.url.indexOf('@') > -1 || !fs.existsSync(path.resolve(cfg.lib.www.url)));
+
+            if (isGit) {
+                parseArr = cfg.lib.www.url.split('#');
+                gitURL = parseArr[0];
+                branch = parseArr[1];
+
+                events.emit('log', 'Retrieving ' + cfg.lib.www.url + ' from GitHub...');
+
+                return remoteLoad.gitClone(gitURL, branch).fail(
+                    function(err) {
+                        events.emit('verbose', err);
+                        return Q.reject('Failed to retrieve '+ cfg.lib.www.url + ' from Git.');
+                    }
+                );
+            } else if (isNPM) {
+                events.emit('log', 'Retrieving ' + cfg.lib.www.url + ' from NPM...');
+
+                // Determine package name, and version
+                if (cfg.lib.www.url.indexOf('@') !== -1) {
+                    parseArr = cfg.lib.www.url.split('@');
+                    packageName = parseArr[0];
+                    packageVersion = parseArr[1];
+                } else {
+                    packageName = cfg.lib.www.url;
+                    packageVersion = '';
+                }
+
+                return remoteLoad.npmFetch(packageName, packageVersion).fail(
+                    function(err) {
+                        events.emit('verbose', err);
+                        return Q.reject('Failed to retrieve '+ cfg.lib.www.url + ' from NPM.');
+                    }
+                );
+            } else {
+                cfg.lib.www.url = path.resolve(cfg.lib.www.url);
+
+                return Q(cfg.lib.www.url);
+            }
         }
     })
     .then(function(import_from_path) {
+
         if (!fs.existsSync(import_from_path)) {
-            throw new CordovaError('Could not find directory: ' + import_from_path);
+            throw new CordovaError('Could not find directory: ' +
+                import_from_path);
         }
 
         var paths = {
@@ -191,21 +234,27 @@ function create(dir, optionalId, optionalName, cfg) {
         };
 
         // Keep going into child "www" folder if exists in stock app package.
+        // why?
         while (fs.existsSync(path.join(paths.www, 'www'))) {
             paths.root = paths.www;
             paths.www = path.join(paths.root, 'www');
         }
 
+        // find config.xml
         if (fs.existsSync(path.join(paths.root, 'config.xml'))) {
             paths.configXml = path.join(paths.root, 'config.xml');
             paths.configXmlLinkable = true;
         } else {
             try {
-                paths.configXml = path.join(require('cordova-app-hello-world').dirname, 'config.xml');
+                paths.configXml =
+                    path.join(require('cordova-app-hello-world').dirname,
+                        'config.xml');
             } catch (e) {
                 // Falling back on npm@2 path hierarchy
                 // TODO: Remove fallback after cordova-app-hello-world release
-                paths.configXml = path.join(__dirname, '..', '..', 'node_modules', 'cordova-app-hello-world', 'config.xml');
+                paths.configXml =
+                    path.join(__dirname, '..', '..', 'node_modules',
+                        'cordova-app-hello-world', 'config.xml');
             }
         }
         if (fs.existsSync(path.join(paths.root, 'merges'))) {
@@ -218,11 +267,15 @@ function create(dir, optionalId, optionalName, cfg) {
             paths.hooksLinkable = true;
         } else {
             try {
-                paths.hooks = path.join(require('cordova-app-hello-world').dirname, 'hooks');
+                paths.hooks =
+                    path.join(require('cordova-app-hello-world').dirname,
+                        'hooks');
             } catch (e) {
                 // Falling back on npm@2 path hierarchy
                 // TODO: Remove fallback after cordova-app-hello-world release
-                paths.hooks = path.join(__dirname, '..', '..', 'node_modules', 'cordova-app-hello-world', 'hooks');
+                paths.hooks =
+                    path.join(__dirname, '..', '..', 'node_modules',
+                        'cordova-app-hello-world', 'hooks');
             }
         }
 
@@ -231,6 +284,7 @@ function create(dir, optionalId, optionalName, cfg) {
             fs.mkdirSync(dir);
         }
 
+
         var tryToLink = !!cfg.lib.www.link;
         function copyOrLink(src, dst, linkable) {
             if (src) {
@@ -242,10 +296,43 @@ function create(dir, optionalId, optionalName, cfg) {
                 }
             }
         }
+
+        /*
+        Copies template files, and directories into a Cordova project directory.
+        Files, and directories not copied include: www, mergers,platforms,
+        plugins, hooks, and config.xml. A template directory, and platform
+        directory must be passed.
+
+        templateDir - Template directory
+        projectDir - Project directory
+         */
+        function copyTemplateFiles(templateDir, projectDir) {
+            var templateFiles;		// Current file
+
+            templateFiles = fs.readdirSync(templateDir);
+
+            // Remove directories, and files that are automatically copied
+            templateFiles = templateFiles.filter(
+                function (value) {
+                    return !(value === 'www' || value === 'mergers' ||
+                    value === 'config.xml' || value === 'hooks');
+                }
+            );
+
+            // Copy each template file
+            for (var i = 0; i < templateFiles.length; i++)
+                shell.cp('-R', path.resolve(templateDir, templateFiles[i]), projectDir);
+        }
+
         try {
             copyOrLink(paths.www, path.join(dir, 'www'), true);
             copyOrLink(paths.merges, path.join(dir, 'merges'), true);
-            copyOrLink(paths.hooks, path.join(dir, 'hooks'), paths.hooksLinkable);
+            copyOrLink(paths.hooks, path.join(dir, 'hooks'),
+                paths.hooksLinkable);
+
+            if (cfg.lib.www.template)
+                copyTemplateFiles(import_from_path, dir);
+
             if (paths.configXml) {
                 if (tryToLink && paths.configXmlLinkable) {
                     fs.symlinkSync(paths.configXml, path.join(dir, 'config.xml'));
@@ -262,10 +349,12 @@ function create(dir, optionalId, optionalName, cfg) {
             }
             throw e;
         }
-
         // Create basic project structure.
-        shell.mkdir(path.join(dir, 'platforms'));
-        shell.mkdir(path.join(dir, 'plugins'));
+        if (!fs.existsSync(path.join(dir, 'platforms')))
+            shell.mkdir(path.join(dir, 'platforms'));
+
+        if (!fs.existsSync(path.join(dir, 'plugins')))
+            shell.mkdir(path.join(dir, 'plugins'));
 
         // Write out id and name to config.xml
         var configPath = cordova_util.projectConfig(dir);

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/ac57bebf/cordova-lib/src/cordova/remote_load.js
----------------------------------------------------------------------
diff --git a/cordova-lib/src/cordova/remote_load.js b/cordova-lib/src/cordova/remote_load.js
new file mode 100644
index 0000000..ac56786
--- /dev/null
+++ b/cordova-lib/src/cordova/remote_load.js
@@ -0,0 +1,147 @@
+/**
+    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.
+*/
+
+var path = require('path');
+var shell = require('shelljs');
+var Q = require('q');
+var npm = require('npm');
+var npmHelper = require('../util/npm-helper');
+var unpack = require('../util/unpack');
+var util = require('./util');
+var git = require('../gitclone');
+
+/*
+Fetches the latests version of a package from NPM. A promise is returned that
+resolves to the directory the NPM package is located in. Package options must be
+passed containing a packageName, name, and version.
+
+options - Package options
+ */
+function npmFetch(packageName, packageVersion) {
+    var versionCallback;        // Resultant callback
+    var downloadDir;            // Download directory
+    var npmPackage;             // NPM package information
+
+    // Get the latest matching version from NPM if a version range is specified
+    versionCallback = util.getLatestMatchingNpmVersion(packageName, packageVersion).then(
+        function (latestVersion) {
+            downloadDir = path.join(util.libDirectory, packageName, 'cordova', latestVersion);
+            npmPackage = packageName + '@' + latestVersion;
+
+            return exports.npmCacheAdd(npmPackage);
+        },
+        function (err) {
+            return Q.reject(err);
+        }
+    );
+
+    return versionCallback;
+}
+
+/*
+Invokes "npm cache add," and then returns a promise that resolves to a
+directory containing the downloaded, or cached package. NPM package information
+must be passed in the form of package@version.
+
+npmPackage - NPM package details
+ */
+function npmCacheAdd(npmPackage) {
+    var loadCallback;           // Resultant callback
+    var cacheAddCallback;       // Callback for cache
+    var cacheDir;               // Cache directory
+    var npmConfig;              // NPM Configuration
+    var packageDir;             // Downloaded package directory
+    var packageTGZ;             // Downloaded TGZ directory
+
+    cacheDir = path.join(util.libDirectory, 'npm_cache');
+
+    npmConfig = {
+        'cache-min': 3600 * 24,
+        'cache': cacheDir
+    };
+
+    // Load with NPM configuration
+    loadCallback = npmHelper.loadWithSettingsThenRestore(npmConfig,
+        function () {
+
+            // Invoke NPM Cache Add
+            cacheAddCallback = Q.ninvoke(npm.commands, 'cache', ['add', npmPackage]).then(
+                function (info) {
+                    packageDir = path.resolve(npm.cache, info.name, info.version, 'package');
+                    packageTGZ = path.resolve(npm.cache, info.name, info.version, 'package.tgz');
+
+                    return unpack.unpackTgz(packageTGZ, packageDir);
+                },
+                function (err) {
+                    return Q.reject(err);
+                }
+            );
+
+            return cacheAddCallback;
+        },
+        function (err) {
+            return Q.reject(err);
+        }
+    );
+
+    return loadCallback;
+}
+
+/*
+Performs a Git clone an a Git URL, and branch. If the clone was successful,
+the path to the cloned directory will be returned. Otherwise, a error is
+returned. A gitURL, must be passed, and a branch to checkout at is optionally
+passed.
+
+gitURL - URL to Git repository
+branch - Branch to checkout at
+ */
+function gitClone(gitURL, branch) {
+    var cloneCallback;          // Resultant callback
+    var tmpSubDir;              // Temporary sub-directory
+    var tmpDir;                 // Temporary directory
+    var checkoutBranch;         // Branch to checkout
+
+    checkoutBranch = branch || 'master';
+    tmpSubDir = 'tmp_cordova_git_' + process.pid + '_' + (new Date()).valueOf();
+    tmpDir = path.join(util.libDirectory, 'tmp', tmpSubDir);
+
+    shell.rm('-rf', tmpDir);
+    shell.mkdir('-p', tmpDir);
+
+    cloneCallback = git.clone(gitURL, checkoutBranch, tmpDir);
+
+    // Callback for Git clone
+    cloneCallback.then(
+        function() {
+            return tmpDir;
+        },
+        function (err) {
+            shell.rm('-rf', tmpDir);
+
+            return Q.reject(err);
+        }
+    );
+
+    return cloneCallback;
+}
+
+exports.gitClone = gitClone;
+exports.npmFetch = npmFetch;
+exports.npmCacheAdd = npmCacheAdd;
\ No newline at end of file


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