├── .gitignore ├── LICENSE ├── README.md ├── RELEASENOTES.md ├── bin └── cocoon.js ├── cli.js ├── package.json ├── src ├── assets │ └── logo.png ├── help │ ├── cloud.txt │ └── help.txt ├── index.js ├── lib │ ├── cli-manager.js │ ├── cloud │ │ ├── apps.js │ │ ├── build.js │ │ ├── clone.js │ │ ├── create.js │ │ ├── delete.js │ │ ├── login.js │ │ └── logout.js │ ├── cmd.js │ ├── cocoon-lib.js │ ├── cocoon │ │ ├── cloud.js │ │ ├── home.html │ │ ├── livereload │ │ │ ├── README │ │ │ ├── connect-index.js │ │ │ ├── connect-livereload.js │ │ │ └── map-index.js │ │ ├── serve.js │ │ └── serve_home.js │ ├── config-xml.js │ ├── cordova-lib.js │ └── cordova │ │ ├── build.js │ │ ├── build │ │ └── samsung-smarttv.js │ │ ├── create.js │ │ ├── generic.js │ │ ├── platform.js │ │ ├── platforms.js │ │ ├── platforms │ │ ├── samsung-smarttv.js │ │ └── samsung-smarttv │ │ │ ├── config.xml │ │ │ └── widget.info │ │ ├── plugin.js │ │ └── serve.js ├── ludei_platforms.json ├── ludei_plugins.json └── utils.js └── test.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .idea 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2014 Ludei, Inc. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # IMPORTANT: This project has been discontinued. Please go to the new Cocoon Cloud at http://cocoon.io. 2 | The new Cocoon cloud is completely Cordova based and has enhanced features that include: the most up to date Webview+, new Cocoon plugins, a better Developer App, support for any Cordova plugin and a revamped UI. 3 | 4 | # CocoonJS Command Line tools # 5 | 6 | The CocoonJS command line tools let you build Cordova-based applications that benefit of Ludei's services (like cloud project management) right in you terminal. 7 | 8 | The CocoonJS CLI also provide access to the Webview+ execution environment. The CocoonJS CLI handles the installation and usage of the webview+ plugin directly in your computer. 9 | 10 | > Ludei's WebView+ is a Chromium based solution for Android 4.0+ and the WKWebView for iOS 8.0+. 11 | 12 | - [Webview+ for iOs](https://github.com/ludei/webview-plus-ios) 13 | - [Webview+ for Android](https://github.com/ludei/webview-plus) 14 | 15 | ## Requirements ## 16 | Install cordova-cli 3.2 or higher (Cordova 3.5 is recommended). Please refer to [Cordova prerequisites](https://github.com/apache/cordova-cli#requirements) to set up your environment. 17 | 18 | After installing Cordova in your computer, execute the following command to install the CocoonJS CLI tools: 19 | 20 | ``` 21 | $ npm install -g cocoonjs 22 | ``` 23 | 24 | ## How to use ## 25 | 26 | Use any valid cordova command with the CocoonJS-CLI to manage your project, eg: 27 | 28 | ``` 29 | $ cocoonjs create MyProject com.ludei.test LudeiTest 30 | $ cd MyProject 31 | $ cocoonjs platform add android 32 | $ cocoonjs plugin add com.ludei.webview.plus 33 | $ cocoonjs run 34 | ``` 35 | 36 | #### Regarding cordova versions #### 37 | 38 | The CocoonJS command line tool automatically detects the Cordova version installed in your computer. However, if you have multiple versions installed locally, you can explicitly point to a specific path using the --cordova-path argument to force that cordova binary to execute, eg: 39 | 40 | 41 | ``` 42 | $ cocoonjs platform add android --cordova-path=/Users/Cocoon/cordova/cordova-3.5.0-0.2.4/ 43 | ``` 44 | Using the *--cordova-path*, the CocoonJS-CLI will find the cordova binary inside *cordova-3.5.0-0.2.4/bin/cordova* and will use it to spawn all the cordova-based commands. You can use any cordova 3.x version. 45 | 46 | 47 | #### Troubleshooting #### 48 | 49 | CocoonJS command line has a verbose mode. If you get any error, launch the command with -d flag. And you'll get more info. For instance: 50 | 51 | ``` 52 | cocoonjs plugin add com.ludei.webview.plus -d 53 | ``` 54 | 55 | And post the info in the console attached to your issue. 56 | 57 | Documentation 58 | ---- 59 | http://support.ludei.com/hc/en-us/sections/200476168-CocoonJS-Command-Line-Interface 60 | 61 | License 62 | ---- 63 | Copyright 2014 Ludei, Inc. 64 | 65 | Licensed under the Apache License, Version 2.0 (the "License"); 66 | you may not use this file except in compliance with the License. 67 | You may obtain a copy of the License at 68 | 69 | http://www.apache.org/licenses/LICENSE-2.0 70 | 71 | Unless required by applicable law or agreed to in writing, software 72 | distributed under the License is distributed on an "AS IS" BASIS, 73 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 74 | See the License for the specific language governing permissions and 75 | limitations under the License. 76 | 77 | ### About the author ### 78 | 79 | [Ludei](http://www.ludei.com) is a San Francisco based company, creators of [CocoonJS](https://www.ludei.com/cocoonjs/). Ludei aims to empower HTML5 industry with a set of tools that eases the adoption of HTML5 as the target platform for every mobile development. 80 | -------------------------------------------------------------------------------- /RELEASENOTES.md: -------------------------------------------------------------------------------- 1 | # CocoonJS-cli Release Notes 2 | 3 | ###1.0.0-0.5.0 () 4 | * cocoonjs serve now has livereload enabled by default 5 | 6 | * Known issues: 7 | * cocoonjs serve may crash on canvas+ environments 8 | * livereload feature may not work in system webview for certain android versions 9 | 10 | ### 1.0.0-0.4.0 () 11 | * Improved Webview+ installation method 12 | 13 | ### 1.0.0-0.3.0 () 14 | * checkRequirements() now uses the correct cordova-cli provided by getCordovaCMD() 15 | * Minor changes made to the readme.md 16 | 17 | ### 1.0.0-0.2.0 () 18 | * Fixed a bug that makes the Android platform detection fail. 19 | 20 | ### 1.0.0-0.1.0 () 21 | * Public release -------------------------------------------------------------------------------- /bin/cocoon.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | var CocoonJSCLI = require("../cli.js"); -------------------------------------------------------------------------------- /cli.js: -------------------------------------------------------------------------------- 1 | new (require('./src/index'))(process.argv.slice(2)); -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cocoonjs", 3 | "version": "1.0.0-0.9.0", 4 | "preferGlobal": "true", 5 | "description": "CocoonJS command line tool", 6 | "main": "cli", 7 | "engines": { 8 | "node": ">=0.10.0" 9 | }, 10 | "engineStrict": true, 11 | "bin": { 12 | "cocoonjs": "./bin/cocoon.js" 13 | }, 14 | "bugs": { 15 | "url": "https://support.ludei.com" 16 | }, 17 | "repository": { 18 | "type": "git", 19 | "url": "git@github.com:ludei/cocoonjs-cli.git" 20 | }, 21 | "keywords": [ 22 | "ludei", 23 | "cocoonjs", 24 | "chromium", 25 | "Webview+", 26 | "browser", 27 | "cordova", 28 | "app", 29 | "html5" 30 | ], 31 | "dependencies": { 32 | "shelljs": "0.3.0", 33 | "minimist": "0.1.0", 34 | "colors": "0.6.2", 35 | "xml2js": "0.4.4", 36 | "gulp" : "3.8.6", 37 | "gulp-connect" : "2.0.6", 38 | "tiny-lr": "0.0.7", 39 | "qrcode-terminal" : "0.9.5", 40 | "ip" : "0.3.1", 41 | "prompt" : "0.2.14", 42 | "mime" : "1.2.11", 43 | "cocoonjs-cloud-api" : "0.1.0", 44 | "cli-table" : "0.3.0", 45 | "async" : "0.9.0", 46 | "archiver" : "0.12.0", 47 | "char-spinner" : "1.0.1" 48 | }, 49 | "author": "Carlos Hernández Gómez - @k4rliky", 50 | "contributors": [ 51 | { 52 | "name": "Txus Ordorika", 53 | "email": "txus@ludei.com" 54 | }, 55 | { 56 | "name": "Abdul Martinez", 57 | "email": "amartinez@ludei.com" 58 | } 59 | ], 60 | "license": "Apache version 2.0" 61 | } 62 | -------------------------------------------------------------------------------- /src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ludei/cocoonjs-cli/9fc4595843babd729506188f20a9a07be0a169cd/src/assets/logo.png -------------------------------------------------------------------------------- /src/help/cloud.txt: -------------------------------------------------------------------------------- 1 | Synopsis 2 | 3 | cocoonjs cloud [options] 4 | 5 | Project-Level Commands 6 | 7 | login ................ login to CocoonJS' Cloud compiler 8 | logout ................ logout of CocoonJS' Cloud compiler 9 | create [ID] [NAME] ................ Creates a CocoonJS project in the cloud compiler in the specified PATH, with 10 | optional [NAME] and [ID] (reverse-domain-style package name) 11 | build ................ Compresses your www/ and plugins/ folders and uploads them to be compiled 12 | in the cloud compiler. 13 | clone [ID] ................ Clone a remote project into a local folder. The [ID] of your project 14 | delete ................ Deletes the remote project (not the local files), this operation cannot be undone. 15 | You'll be asked for confirmation unless you pass the --force argument. 16 | apps ................ Shows the information of all your apps, use --raw-mode to show the information 17 | as an array. 18 | 19 | Command-line Flags/Options 20 | 21 | -d, --verbose ............................. debug mode produces verbose log output for all activity, 22 | including output of sub-commands cordova/cocoonjs invokes. 23 | 24 | Example usage 25 | 26 | Example 1: 27 | $ cocoonjs cloud create 28 | Example 2 (Clone a remote project into your computer): 29 | $ cocoonjs cloud clone com.your.project.id 30 | Example 3: 31 | $ cocoonjs apps 32 | 33 | Documentation 34 | http://support.ludei.com 35 | 36 | Cloud Compilation 37 | http://cloud.ludei.com 38 | -------------------------------------------------------------------------------- /src/help/help.txt: -------------------------------------------------------------------------------- 1 | Synopsis 2 | 3 | cocoonjs command [options] 4 | 5 | Global Commands 6 | 7 | create [ID] [NAME] ................ creates a cordova project in the specified PATH, with 8 | optional NAME and ID (reverse-domain-style package name) 9 | help ..................................... shows this syntax summary 10 | 11 | info ..................................... print out useful information helpful for submitting bug 12 | reports and getting help. Creates a info.txt file at the 13 | base of your project 14 | 15 | Project-Level Commands 16 | 17 | platform(s) [{add|remove|rm} ] .. add or remove a specified PLATFORM, OR 18 | [{list|ls}] ................... list all installed, available and unavailable platforms 19 | plugin(s) [{add|remove|rm} ] .... add or remove a plugin from the specified PATH or URI, OR 20 | [{ls|list}] ..................... list all currently installed plugins 21 | prepare [PLATFORM..] ...................... copies files for specified platforms, or all platforms, 22 | so that the project is ready to build in each SDK. 23 | compile [PLATFORM..] ...................... builds the app for specified platforms, or all platforms 24 | build [PLATFORM...] ....................... shortcut for prepare, then compile 25 | emulate [PLATFORM...] ..................... deploys app in specified (or all) platform emulator(s), 26 | opening emulator if necessary 27 | run [PLATFORM...] ......................... deploys app on specified (or all) platform devices, which 28 | must be properly connected and configured in each SDK 29 | serve [PORT] .............................. runs a local web server for www/ assets. Port defaults to 8000. 30 | Access projects at: http://HOST_IP:PORT/PLATFORM/www 31 | 32 | Command-line Flags/Options 33 | 34 | -v, --version ............................. prints out this utility's version 35 | -d, --verbose ............................. debug mode produces verbose log output for all activity, 36 | including output of sub-commands cordova/cocoonjs invokes 37 | 38 | Example usage 39 | 40 | $ cocoonjs create cocoonjs_test 41 | $ cd cocoonjs_test 42 | $ cocoonjs platform add android 43 | $ cocoonjs plugin add com.ludei.webview.plus 44 | $ cocoonjs run 45 | 46 | Documentation 47 | http://support.ludei.com 48 | 49 | Cloud Compilation 50 | http://cloud.ludei.com 51 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | var parse_arguments = null, 2 | fs = require('fs'), 3 | path = require('path'), 4 | util = require('./utils.js'); 5 | var argv; 6 | 7 | module.exports = function CLI(args) { 8 | 9 | try{ 10 | parse_arguments = require('minimist'); 11 | }catch(e){ 12 | console.error("Oooops, Did you forgot to run 'npm install'? Execute the following commands: \n", 13 | "$ cd " + path.dirname(__dirname) + "\n", 14 | "$ npm install -g \n"); 15 | process.exit(1); 16 | } 17 | 18 | argv = parse_arguments(args); 19 | 20 | if(argv["_"]){ 21 | for(var prop in argv["_"]){ 22 | argv[prop] = argv["_"][prop]; 23 | } 24 | delete argv["_"]; 25 | } 26 | 27 | var options = { 28 | verboseEnabled : false, 29 | command : args 30 | }; 31 | 32 | if(args.length === 0){ 33 | return util.log('No valid command found. Try --help for a list of all the available commands.'); 34 | } 35 | 36 | if (argv.help || argv[1] && argv[1] === "help") { 37 | return util.printHelpInfo(); 38 | } 39 | 40 | if (argv.v || argv.version) { 41 | return console.log(require('../package').version); 42 | } 43 | 44 | if (argv.d || argv.verbose) { 45 | options.verboseEnabled = true; 46 | } 47 | 48 | var CORDOVA_CMD = [ "create", 49 | "platform", "platforms", 50 | "plugin", "plugins", 51 | "prepare", 52 | "compile", 53 | "build", 54 | "emulate", 55 | "run" ]; 56 | var COCOON_CMD = [ "cloud", "serve" ]; 57 | 58 | if(options.command.length === 0) { 59 | return util.printHelpInfo(); 60 | } 61 | 62 | if( (CORDOVA_CMD.indexOf(args[0]) !== -1)) { 63 | return new (require('./lib/cordova-lib'))(argv, options); 64 | } 65 | 66 | if( (COCOON_CMD.indexOf(args[0]) !== -1)){ 67 | return new (require('./lib/cocoon-lib'))(argv, options); 68 | } 69 | 70 | return util.log('No valid command found. Try --help for a list of all the available commands.'); 71 | 72 | }; -------------------------------------------------------------------------------- /src/lib/cli-manager.js: -------------------------------------------------------------------------------- 1 | var shell = require('shelljs'), 2 | fs = require('fs'), 3 | path = require('path'), 4 | util = require('../utils.js'); 5 | /** 6 | * 7 | * @constructor 8 | */ 9 | function CliManager(argv, options){ 10 | 11 | this._argv = (function(argv){ // Optional arguments like --cordova-path or --plugins-path 12 | var arr = []; 13 | for(var prop in argv){ 14 | var key = prop; 15 | var value = argv[key]; 16 | if( isNaN( parseInt(key) ) ){ 17 | arr[key] = value; 18 | }else{ 19 | arr.push(value); 20 | } 21 | } 22 | return arr; 23 | })(argv); 24 | 25 | this._args = util.cleanUpArguments(options.command); // Cordova command and flags 26 | this._argsStr = this._args.join(" "); // Cordova command and flags as string 27 | this._customArgvEnabled = false; 28 | 29 | this._custom_argv = this._argv; 30 | this._custom_args = this._args; 31 | this._custom_argsStr = this._argsStr; 32 | 33 | this._cmdPath = util.getCordovaCMD(this._argv); // Path to the Cordova CLI executable 34 | this._cmd = new (require('./cmd.js'))(this._cmdPath, options); 35 | 36 | } 37 | /** 38 | * 39 | * @type {{AS_STRING: number, RAW: number}} 40 | */ 41 | CliManager.prototype.ARGV = { 42 | AS_STRING : "AS_STRING", 43 | RAW : "RAW" 44 | } 45 | /** 46 | * 47 | * @param mode 48 | * @returns {*} 49 | */ 50 | CliManager.prototype.getArgv = function(mode){ 51 | // If custom argv is enabled, return the custom one. 52 | if(this._customArgvEnabled){ 53 | return this.getCustomArgv(mode); 54 | } 55 | mode = mode || this.ARGV.RAW; 56 | 57 | if( mode === this.ARGV.AS_STRING ){ 58 | return this._argsStr; 59 | }else if( mode === this.ARGV.RAW ){ 60 | return (this._argv) ? this._argv : []; 61 | } 62 | 63 | return (this._argv) ? this._argv : []; 64 | } 65 | /** 66 | * 67 | * @param argv 68 | */ 69 | CliManager.prototype.setCustomArgv = function(argv){ 70 | this._custom_argv = argv; 71 | this._custom_args = util.cleanUpArguments(argv); 72 | this._custom_argsStr = this._custom_args.join(" "); 73 | } 74 | /** 75 | * 76 | * @param bool 77 | */ 78 | CliManager.prototype.toogleCustomArgv = function(bool){ 79 | this._customArgvEnabled = bool; 80 | } 81 | CliManager.prototype.isCustomArgvActive = function(){ 82 | return this._customArgvEnabled; 83 | } 84 | /** 85 | * 86 | * @param mode 87 | */ 88 | CliManager.prototype.getCustomArgv = function(mode){ 89 | mode = mode || this.ARGV.RAW; 90 | 91 | if( mode === this.ARGV.AS_STRING ){ 92 | return this._custom_argsStr; 93 | }else if( mode === this.ARGV.RAW ){ 94 | return (this._custom_argv) ? this._custom_argv : []; 95 | } 96 | 97 | return (this._custom_argv) ? this._custom_argv : []; 98 | } 99 | /** 100 | * 101 | * @returns {*} 102 | */ 103 | CliManager.prototype.getCMD = function(){ 104 | return this._cmd; 105 | } 106 | /** 107 | * 108 | */ 109 | CliManager.prototype.getCocoonLib = function(command){ 110 | var lib_path = path.join(__dirname , "cocoon" , command + ".js"); 111 | 112 | if(fs.existsSync(lib_path)){ 113 | return require(lib_path); 114 | }else{ 115 | return false; 116 | } 117 | } 118 | /** 119 | * 120 | */ 121 | CliManager.prototype.getCordovaLib = function(command){ 122 | var lib_path = path.join(__dirname , "cordova" , command + ".js"); 123 | var generic_path = path.join(__dirname , "cordova" , "generic.js"); 124 | 125 | if(fs.existsSync(lib_path)){ 126 | return require(lib_path); 127 | }else{ 128 | return require(generic_path); 129 | } 130 | } 131 | /** 132 | * 133 | */ 134 | CliManager.prototype.getCloudLib = function(command){ 135 | var lib_path = path.join(__dirname , "cloud" , command + ".js"); 136 | 137 | if(fs.existsSync(lib_path)){ 138 | return require(lib_path); 139 | }else{ 140 | return false; 141 | } 142 | } 143 | 144 | CliManager.prototype.getLudeiPlatforms = function(){ 145 | var platforms_path = path.join( __dirname, "..", "..", "src", "ludei_platforms.json"); 146 | return require(platforms_path); 147 | }; 148 | 149 | CliManager.prototype.getLudeiPlugins = function(){ 150 | return [{ 151 | isView : true, 152 | name : "webview+", 153 | package : "com.ludei.webview.plus" 154 | },{ 155 | isView : true, 156 | name : "webview+", 157 | package : "com.ludei.ios.webview.plus" 158 | },{ 159 | isView : true, 160 | name : "canvas+", 161 | package : "com.ludei.cocoonjs.canvasplus" 162 | }]; 163 | }; 164 | /** 165 | * 166 | */ 167 | CliManager.prototype.getAvailablePlatforms = function(){ 168 | var platforms_path = path.join( process.cwd() , "platforms"); 169 | var directories = []; 170 | var directory_content = fs.readdirSync(platforms_path); 171 | var length = directory_content.length; 172 | 173 | for(var x = 0; x < length; x++){ 174 | var file = directory_content[x]; 175 | if(file === "cocoonjs"){ 176 | continue; 177 | } 178 | var stats = fs.statSync( path.join(platforms_path, file) ); 179 | if(stats.isDirectory()){ 180 | directories.push(file); 181 | } 182 | } 183 | 184 | return directories; 185 | } 186 | 187 | /** 188 | * 189 | */ 190 | CliManager.prototype.getAvailablePlugins = function(){ 191 | var plugins_path = path.join( process.cwd() , "plugins"); 192 | var directories = []; 193 | var directory_content = fs.readdirSync(plugins_path); 194 | var length = directory_content.length; 195 | 196 | for(var x = 0; x < length; x++){ 197 | var file = directory_content[x]; 198 | var stats = fs.statSync( path.join(plugins_path, file) ); 199 | if(stats.isDirectory()){ 200 | directories.push(file); 201 | } 202 | } 203 | 204 | return directories; 205 | } 206 | module.exports = CliManager; -------------------------------------------------------------------------------- /src/lib/cloud/apps.js: -------------------------------------------------------------------------------- 1 | var shell = require('shelljs'); 2 | var path = require('path'); 3 | var fs = require('fs'); 4 | var util = require('../../utils.js'); 5 | var Table = require('cli-table'); 6 | var CocoonJSCloud = require('cocoonjs-cloud-api'); 7 | var CliManager; 8 | 9 | /** 10 | * 11 | * @param Cloud 12 | * @param manager 13 | * @param callback optional 14 | * @constructor 15 | */ 16 | function Apps(Cloud, manager, callback) { 17 | 18 | CliManager = manager; 19 | 20 | this._cmd = CliManager.getCMD(); 21 | this._rawMode = CliManager.getArgv( CliManager.ARGV.RAW )['raw-mode'] ? true : false; 22 | 23 | var me = this; 24 | var credentials = Cloud.loadCredentials(); 25 | 26 | if(!credentials){ 27 | throw new Error("You have to log in first, see 'cocoonjs cloud login'."); 28 | } 29 | 30 | this.api = new CocoonJSCloud.API(credentials); 31 | 32 | var appId = ""; 33 | if(CliManager.isCustomArgvActive()){ 34 | appId = "/" + CliManager.getCustomArgv( CliManager.ARGV.RAW )[1]; 35 | } 36 | 37 | this.api.get('/project' + appId, function (err, data) { 38 | if(err){ 39 | util.errorLog(err.message); 40 | return; 41 | } 42 | 43 | if(data.length === 0){ 44 | util.log("No projects found, you will need to create one, see 'cocoonjs cloud create'."); 45 | } 46 | 47 | /** 48 | * Notify through this callback 49 | * the completion of this request. 50 | */ 51 | if(callback){ 52 | callback(data); 53 | return; 54 | } 55 | 56 | /** 57 | * Print the object in raw 58 | */ 59 | if(me._rawMode){ 60 | console.log(data); 61 | return; 62 | } 63 | 64 | /** 65 | * 'Pretty prints' a table :) 66 | * @type {Table} 67 | */ 68 | var table = new Table({ 69 | head: ['Title', 'Package' ,'Build count'], 70 | colWidths: [20, 30, 15] 71 | }); 72 | 73 | data.forEach(function(project){ 74 | table.push( 75 | [project.title, project.package, project.build_count] 76 | ); 77 | }); 78 | 79 | console.log(table.toString()); 80 | }); 81 | } 82 | 83 | module.exports = Apps; -------------------------------------------------------------------------------- /src/lib/cloud/build.js: -------------------------------------------------------------------------------- 1 | var shell = require('shelljs'); 2 | var path = require('path'); 3 | var fs = require('fs'); 4 | var util = require('../../utils.js'); 5 | var archiver = require('archiver'); 6 | var ConfigManager = require('../config-xml.js'); 7 | var CocoonJSCloud = require('cocoonjs-cloud-api'); 8 | var spinner = require("char-spinner"); 9 | var CliManager; 10 | 11 | function Build(Cloud, manager) { 12 | 13 | this.CliManager = manager; 14 | 15 | this.Cloud = Cloud; 16 | this.interval = spinner(); 17 | 18 | this.credentials = Cloud.loadCredentials(); 19 | 20 | if(!this.credentials){ 21 | util.errorLog("You have to log in first, see 'cocoonjs cloud'. "); 22 | return; 23 | } 24 | 25 | this.api = new CocoonJSCloud.API(this.credentials); 26 | 27 | this.compressProject(); 28 | } 29 | 30 | Build.prototype.compressProject = function(){ 31 | 32 | this.projectPath = process.cwd(); 33 | var outputPath = path.join(process.cwd(), "platforms", "cocoonjs"); 34 | var outputFile = "cloud.zip"; 35 | var pluginsPath = path.join(process.cwd(), "plugins"); 36 | var srcPath = path.join(process.cwd(), "www"); 37 | var zipArchive = archiver('zip'); 38 | var me = this; 39 | 40 | if( !fs.existsSync(outputPath) ) { 41 | shell.mkdir("-p", outputPath); 42 | } 43 | 44 | var output = fs.createWriteStream(path.join( outputPath , outputFile)); 45 | 46 | output.on('close', function() { 47 | me.build( path.join(outputPath, outputFile) ); 48 | }); 49 | 50 | output.on('error', function() { 51 | console.log('error', arguments); 52 | }); 53 | 54 | zipArchive.pipe(output); 55 | 56 | var bulkDirectories = [ 57 | { src: [ '**/*' ], cwd: srcPath, dest: 'www', expand: true }, 58 | { src: [ '**/*' ], cwd: pluginsPath, dest: 'plugins', expand: true } 59 | ]; 60 | 61 | if( !fs.existsSync( path.join(srcPath, "config.xml") ) ){ 62 | bulkDirectories.push({ src: [ '**/config.xml' ], cwd: this.projectPath, expand: true }); 63 | } 64 | 65 | zipArchive.bulk(bulkDirectories); 66 | 67 | zipArchive.finalize(); 68 | 69 | } 70 | 71 | Build.prototype.build = function(filePath){ 72 | var configManager = new ConfigManager(); 73 | var me = this; 74 | configManager.readConfigXML( process.cwd() , function(err) { 75 | 76 | if (err) { 77 | throw new Error(err); 78 | } 79 | 80 | var bundle = configManager.getValue("package"); 81 | var platforms = me.CliManager.getAvailablePlatforms(); 82 | var plugins = me.CliManager.getAvailablePlugins(); 83 | 84 | util.log("Uploading project '" + bundle + "' to CocoonJS' Cloud Compiler."); 85 | var view = me.getView(); 86 | var options = { 87 | form: { 88 | file: filePath, 89 | data: { 90 | "view": view, 91 | "version": "default", 92 | "platforms" : platforms 93 | } 94 | } 95 | }; 96 | 97 | var viewHelp = "The project '" + package + "' "; 98 | viewHelp += "will be compiled with the '" + view + "' execution environment,"; 99 | viewHelp += "see 'cocoonjs environments' for more info."; 100 | 101 | var pluginHelp = ""; 102 | if(plugins.length === 0){ 103 | pluginHelp += "Your project does not have installed plugins."; 104 | }else{ 105 | pluginHelp += "Plugins that will be compiled with your project:\n"; 106 | for(var x = 0; x < plugins.length; x++){ 107 | pluginHelp += plugins[x] + "\n"; 108 | } 109 | } 110 | 111 | util.log(viewHelp); 112 | util.log(pluginHelp); 113 | 114 | me.api.post('/project/' + package + '/compile', options, function(err) { 115 | if(err){ 116 | throw new Error(err); 117 | } 118 | 119 | util.log("Compilation started..."); 120 | clearInterval(me.interval); 121 | }); 122 | }); 123 | } 124 | /** 125 | * CocoonJS uses three diferent views to render apps 126 | * Canvas+, Webview+ and System Webview. This function 127 | * determines whatever should be used. 128 | * @returns {*} 129 | */ 130 | Build.prototype.getView = function(){ 131 | var pluginsPath = path.join(this.projectPath, "plugins"); 132 | var pluginsInstalled = fs.readdirSync(pluginsPath); 133 | var defaultView = "webview"; 134 | 135 | if(pluginsInstalled.length === 0){ 136 | return defaultView; 137 | } 138 | 139 | var LudeiPlugins = this.CliManager.getLudeiPlugins(); 140 | 141 | for(var i = 0; i < LudeiPlugins.length; i++){ 142 | if(pluginsInstalled.indexOf(LudeiPlugins[i].package) !== -1){ 143 | return LudeiPlugins[i].name; 144 | } 145 | } 146 | 147 | return defaultView; 148 | } 149 | 150 | module.exports = Build; -------------------------------------------------------------------------------- /src/lib/cloud/clone.js: -------------------------------------------------------------------------------- 1 | var shell = require('shelljs'); 2 | var path = require('path'); 3 | var fs = require('fs'); 4 | var util = require('../../utils.js'); 5 | var Table = require('cli-table'); 6 | var ConfigManager = require('../config-xml.js'); 7 | var CliManager; 8 | 9 | function Clone(Cloud, manager) { 10 | 11 | CliManager = manager; 12 | 13 | this._cmd = CliManager.getCMD(); 14 | 15 | var me = this; 16 | var credentials = Cloud.loadCredentials(); 17 | 18 | if(!credentials){ 19 | throw new Error("You have to log in first, see 'cocoonjs cloud login'."); 20 | } 21 | 22 | util.log("Cloning project"); 23 | 24 | var AppLib = CliManager.getCloudLib("apps"); 25 | if(!AppLib){ 26 | throw new Error("Cannot find 'cocoonjs apps' library."); // This should never happen lol wut 27 | } 28 | 29 | var CreateLib = CliManager.getCordovaLib("create"); 30 | if(!CreateLib){ 31 | throw new Error("Cannot find 'cocoonjs create' library."); // This should never happen lol wut 32 | } 33 | 34 | var bundle = CliManager.getArgv( CliManager.ARGV.RAW )[2]; 35 | if (!bundle){ 36 | throw new Error("Missing argument package."); 37 | } 38 | 39 | var path = CliManager.getArgv( CliManager.ARGV.RAW )[3]; 40 | if (!path){ 41 | throw new Error("Missing argument path."); 42 | } 43 | 44 | /** 45 | * Activate the custom ARGV mode 46 | * so AppLib can use the correct project info. 47 | */ 48 | CliManager.toogleCustomArgv(true); 49 | CliManager.setCustomArgv(["apps", bundle]); 50 | new AppLib(Cloud, CliManager, function(projectInfo){ 51 | 52 | CliManager.toogleCustomArgv(false); 53 | 54 | me.setUpLocalProject(CreateLib, projectInfo, path); 55 | }); 56 | } 57 | 58 | Clone.prototype.setUpLocalProject = function(CreateLib, projectInfo, path){ 59 | 60 | if(!projectInfo){ 61 | throw new Error(projectInfo); 62 | } 63 | 64 | this.createLocalProject(CreateLib, projectInfo, path); 65 | }; 66 | 67 | Clone.prototype.createLocalProject = function(CreateLib, projectInfo, path){ 68 | 69 | var customArgv = ["create", path, projectInfo.package, '"' + projectInfo.title + '"']; 70 | var me = this; 71 | var copyFrom = CliManager.getArgv(CliManager.ARGV.RAW)['copy-from']; 72 | if(copyFrom){ 73 | customArgv.push("--copy-from=" + copyFrom); 74 | } 75 | 76 | CliManager.setCustomArgv(customArgv); 77 | CliManager.toogleCustomArgv(true); 78 | 79 | new CreateLib(CliManager, function(stdout, stderr){ 80 | 81 | CliManager.toogleCustomArgv(false); 82 | 83 | if(stderr){ 84 | throw new Error(stderr); 85 | } 86 | 87 | me.updateProjectSettings(projectInfo, path); 88 | }); 89 | }; 90 | 91 | Clone.prototype.updateProjectSettings = function (projectInfo, path) { 92 | 93 | var configManager = new ConfigManager(); 94 | 95 | configManager.readConfigXML(path , function(err){ 96 | if(err){ 97 | throw new Error(err); 98 | } 99 | 100 | configManager.setValue("app_version", projectInfo.version); 101 | configManager.saveConfig(); 102 | 103 | util.log("Your config.xml '" + configManager.config_xml_path + "' has been updated with its project information."); 104 | util.log("Project configuration '" + projectInfo.title + "' cloned correctly into " + path); 105 | 106 | }); 107 | }; 108 | 109 | module.exports = Clone; -------------------------------------------------------------------------------- /src/lib/cloud/create.js: -------------------------------------------------------------------------------- 1 | var shell = require('shelljs'); 2 | var path = require('path'); 3 | var fs = require('fs'); 4 | var prompt = require('prompt'); 5 | var util = require('../../utils.js'); 6 | var async = require('async'); 7 | var CocoonJSCloud = require('cocoonjs-cloud-api'); 8 | var CliManager; 9 | /** 10 | * Created a local project and a remote one. 11 | * @param Cloud 12 | * @param manager 13 | * @constructor 14 | */ 15 | function Create(Cloud, manager) { 16 | CliManager = manager; 17 | 18 | var me = this; 19 | 20 | this._cmd = CliManager.getCMD(); 21 | this._command = CliManager.getArgv( CliManager.ARGV.RAW ); 22 | this.credentials = Cloud.loadCredentials(); 23 | 24 | if(!this.credentials){ 25 | util.errorLog("You have to log in first, see 'cocoonjs cloud'. "); 26 | return; 27 | } 28 | 29 | this.api = new CocoonJSCloud.API(this.credentials); 30 | 31 | if(!this._command[1]){ 32 | util.errorLog("At least the dir must be provided to create new project. See `cocoonjs help`."); 33 | process.exit(1); 34 | } 35 | 36 | util.log("creating a new project at", this._command[2]); 37 | 38 | var CreateLib = CliManager.getCordovaLib(this._command[1]); 39 | if(!CreateLib){ 40 | util.errorLog("Cannot find 'cocoonjs create' library."); // This should never happen lol wut 41 | } 42 | 43 | /** 44 | * Arguments passed to "$ cocoonjs create ..." 45 | * @type {{path: *, package: *, name: *}} 46 | */ 47 | var commandList = { 48 | path : this._command[2], 49 | package : this._command[3], 50 | name : this._command[4] 51 | }; 52 | 53 | async.waterfall([ 54 | function(callback){ 55 | if(!commandList.path){ 56 | me.getPrompt(commandList, 'path', 'Local path to your new CocoonJS project (absolute path)', callback); 57 | }else{ 58 | callback(null); 59 | } 60 | }, 61 | function(callback){ 62 | if(!commandList.package){ 63 | me.getPrompt(commandList, 'package', 'Package (reverse domain style, e.g. com.ludei.test)', callback); 64 | }else{ 65 | callback(null); 66 | } 67 | }, 68 | function(callback){ 69 | if(!commandList.name){ 70 | me.getPrompt(commandList, 'name', 'The name of your app', callback); 71 | }else{ 72 | callback(null); 73 | } 74 | } 75 | ], function (err) { 76 | if(err){ 77 | throw new Error(err); 78 | } 79 | 80 | var customArgv = ["create", commandList.path, commandList.package, commandList.name]; 81 | var copyFrom = CliManager.getArgv(CliManager.ARGV.RAW)['copy-from']; 82 | if(copyFrom){ 83 | customArgv.push("--copy-from=" + copyFrom); 84 | } 85 | 86 | CliManager.setCustomArgv(customArgv); 87 | CliManager.toogleCustomArgv(true); 88 | 89 | // Executes '$ cocoonjs create {/path/} {package} {name}' 90 | new CreateLib(CliManager, function(stdout, stderr, statusCode){ 91 | if(statusCode !== 0){ 92 | util.errorLog(stderr); 93 | return; 94 | } 95 | util.log(stdout); 96 | // Disable custom 'argv' so future operations 97 | // will use the original argv. 98 | CliManager.toogleCustomArgv(false); 99 | // Create the project in the cloud service 100 | me.createCloudProject(CliManager, customArgv); 101 | }); 102 | }); 103 | 104 | } 105 | /** 106 | * 107 | * @param CliManager 108 | * @param argv 109 | */ 110 | Create.prototype.createCloudProject = function(CliManager, argv){ 111 | 112 | var options = { 113 | form: { 114 | "title": argv[3].replace(/['"]+/g, ''), 115 | "package": argv[2], 116 | "version": "0.0.1" 117 | } 118 | }; 119 | 120 | this.api.post('/project', options, function(err) { 121 | if(err){ 122 | throw new Error(err) 123 | } 124 | util.log("Your project has been created correctly in www.cocoonjs.com."); 125 | }); 126 | 127 | }; 128 | /** 129 | * 130 | * @param objReference 131 | * @param name 132 | * @param description 133 | * @param callback 134 | */ 135 | Create.prototype.getPrompt = function(objReference, name, description, callback){ 136 | prompt.get([ 137 | { name: name, description: description, required: true } 138 | ], function (err, result) { 139 | if (err) { 140 | callback(err.message); 141 | return; 142 | } 143 | 144 | if (result && result[name]) { 145 | objReference[name] = result[name]; 146 | callback(null); 147 | } 148 | }); 149 | }; 150 | 151 | module.exports = Create; -------------------------------------------------------------------------------- /src/lib/cloud/delete.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by karliky on 21/10/14. 3 | */ 4 | var shell = require('shelljs'); 5 | var path = require('path'); 6 | var fs = require('fs'); 7 | var util = require('../../utils.js'); 8 | var prompt = require('prompt'); 9 | var CocoonJSCloud = require('cocoonjs-cloud-api'); 10 | var CliManager; 11 | 12 | /** 13 | * Deletes a project in the cloud compiler 14 | * @param Cloud 15 | * @param CliManager 16 | */ 17 | function Delete(Cloud, CliManager) { 18 | 19 | var me = this; 20 | this.package = CliManager.getArgv( CliManager.ARGV.RAW )[2]; 21 | 22 | if(!this.package){ 23 | throw new Error("Missing argument 'package', see 'cocoonjs cloud'."); 24 | } 25 | 26 | this.credentials = Cloud.loadCredentials(); 27 | 28 | if(!this.credentials){ 29 | throw new Error("You have to log in first, see 'cocoonjs cloud'."); 30 | } 31 | 32 | if( !CliManager.getArgv(CliManager.ARGV.RAW)["force"] ){ 33 | prompt.get([ 34 | { 35 | name: 'confirm', 36 | description: 'Delete project?[y/n]', 37 | required: true 38 | } 39 | ], function (err, result) { 40 | if (err) { 41 | console.log("\n" + err); 42 | return; 43 | } 44 | if(result.confirm === "yes" || result.confirm === "y"){ 45 | me.deleteProject(); 46 | }else{ 47 | util.log("User canceled the process."); 48 | } 49 | }); 50 | }else{ 51 | me.deleteProject(); 52 | } 53 | 54 | } 55 | 56 | Delete.prototype.deleteProject = function(){ 57 | this.api = new CocoonJSCloud.API(this.credentials); 58 | 59 | this.api.del('/project/' + this.package, function(err) { 60 | if(err){ 61 | throw new Error(err.message); 62 | } 63 | util.log("Project deleted successfully from www.cocoonjs.com."); 64 | }); 65 | } 66 | 67 | module.exports = Delete; -------------------------------------------------------------------------------- /src/lib/cloud/login.js: -------------------------------------------------------------------------------- 1 | var shell = require('shelljs'); 2 | var path = require('path'); 3 | var fs = require('fs'); 4 | var prompt = require('prompt'); 5 | var util = require('../../utils.js'); 6 | var CocoonJSCloud = require('cocoonjs-cloud-api'); 7 | var CliManager; 8 | /** 9 | * Requests a valid token and saves it 10 | * in ~/.cordova/cocoon.js 11 | * @param Cloud 12 | * @param CliManager 13 | */ 14 | function Login(Cloud, CliManager) { 15 | 16 | var me = this; 17 | this._cmd = CliManager.getCMD(); 18 | this.Cloud = Cloud; 19 | this.credentials = Cloud.loadCredentials(); 20 | 21 | if(this.credentials){ 22 | process.exit(0); // already logged in 23 | } 24 | 25 | prompt.message = ""; 26 | prompt.delimiter = ""; 27 | prompt.start(); 28 | 29 | util.log("CocoonJS Cloud Login"); 30 | util.log("Sign up at www.cocoonjs.com/register"); 31 | 32 | prompt.get([ 33 | { 34 | name: 'username', 35 | description: 'Enter email:', 36 | required: true 37 | }, 38 | { 39 | name: 'password', 40 | description: 'Enter password:', 41 | required: true, 42 | hidden: true 43 | } 44 | ], function (err, result) { 45 | if (err) { 46 | console.log("\n" + err); 47 | return; 48 | } 49 | 50 | if (result && result.username && result.password) { 51 | me.signIn(result.username, result.password); 52 | } else { 53 | console.log("Bad credentials?, Try again."); 54 | } 55 | }); 56 | } 57 | 58 | /** 59 | * signIn in the CocoonJS' cloud 60 | * @param username 61 | * @param password 62 | */ 63 | Login.prototype.signIn = function(username, password){ 64 | 65 | var me = this; 66 | 67 | CocoonJSCloud.auth({ username: username, password: password }, function(error, api) { 68 | if(error){ 69 | if(error.description){ 70 | util.errorLog(error.description); 71 | }else{ 72 | util.errorLog(error); 73 | } 74 | return; 75 | } 76 | 77 | var cloud_credentials = { 78 | token : api.token, 79 | protocol : api.protocol, 80 | host : api.host, 81 | port : api.port, 82 | path : api.path 83 | }; 84 | 85 | me.saveCredentials(cloud_credentials); 86 | }); 87 | }; 88 | 89 | Login.prototype.saveCredentials = function(credentials){ 90 | 91 | var credentialsPath = this.Cloud.getCredentialsPath(); 92 | var credentialsFile = "cocoonjs.json"; 93 | 94 | if( !fs.existsSync(credentialsPath) ){ 95 | shell.mkdir('-p', credentialsPath); 96 | } 97 | 98 | fs.writeFile( path.join(credentialsPath, credentialsFile) , JSON.stringify(credentials), function (err) { 99 | if (err){ 100 | util.errorLog(err); 101 | return; 102 | } 103 | util.log("You are now logged in!"); 104 | process.exit(0); 105 | }); 106 | }; 107 | 108 | module.exports = Login; -------------------------------------------------------------------------------- /src/lib/cloud/logout.js: -------------------------------------------------------------------------------- 1 | var shell = require('shelljs'); 2 | var path = require('path'); 3 | var fs = require('fs'); 4 | var util = require('../../utils.js'); 5 | 6 | function Logout(Cloud) { 7 | 8 | this.Cloud = Cloud; 9 | this.credentials = Cloud.loadCredentials(); 10 | 11 | if(this.credentials){ 12 | var credentialsPath = Cloud.getCredentialsPath(); 13 | shell.rm("-rf", path.join(credentialsPath, "cocoonjs.json")); 14 | util.log("logged out of www.cocoonjs.com"); 15 | } 16 | } 17 | 18 | 19 | module.exports = Logout; -------------------------------------------------------------------------------- /src/lib/cmd.js: -------------------------------------------------------------------------------- 1 | var shell = require('shelljs'), 2 | util = require('../utils.js'), 3 | spawn = require('child_process').spawn; 4 | 5 | function Cmd(cmd_path, options) { 6 | this.cmd = cmd_path; 7 | this.verboseEnabled = (options) ? !options.verboseEnabled : false; 8 | } 9 | 10 | Cmd.prototype.getCmdBinaryPath = function() { 11 | return this.cmd; 12 | }; 13 | 14 | Cmd.prototype.exec = function(command, options) { 15 | 16 | var ops = { 17 | silent: this.verboseEnabled, 18 | callback: undefined, 19 | avoidCordovaCMD: false, 20 | env: "" 21 | }; 22 | 23 | options = options || {}; 24 | util.extend(ops, options); 25 | 26 | var complete_command; 27 | 28 | if (ops.avoidCordovaCMD) { 29 | complete_command = ops.env + command; 30 | } else { 31 | complete_command = ops.env + this.cmd + " " + command; 32 | } 33 | 34 | if (ops.callback) { 35 | shell.exec(complete_command, ops, ops.callback); 36 | } else { 37 | return shell.exec(complete_command, ops); 38 | } 39 | }; 40 | 41 | Cmd.prototype.execAsync = function(command, options) { 42 | 43 | var ops = { 44 | silent: this.verboseEnabled, 45 | callback: undefined, 46 | avoidCordovaCMD: false, 47 | events : { 48 | stdout : function(data){}, 49 | stderr : function(data){}, 50 | exit : function(status){} 51 | }, 52 | env: "" 53 | }; 54 | 55 | options = options || {}; 56 | util.extend(ops, options); 57 | 58 | var complete_command; 59 | 60 | if (ops.avoidCordovaCMD) { 61 | complete_command = ops.env + command; 62 | } else { 63 | complete_command = ops.env + this.cmd + " " + command; 64 | } 65 | 66 | //Spawn command needs command and args passed as array 67 | var tempArr = complete_command.match(/"[^"]*"|'[^']*'|\S+/g); 68 | var command = tempArr[0]; 69 | tempArr.shift(); 70 | 71 | // Create child process using spawn of node 72 | var child = spawn(command, tempArr, ops, ops.callback); 73 | 74 | // Callback registering 75 | child.stdout.on('data', ops.events.stdout); 76 | 77 | child.stderr.on('data', ops.events.stderr); 78 | 79 | child.on('exit', ops.events.exit); 80 | 81 | } 82 | 83 | Cmd.prototype.setVerboseMode = function(verbose_mode) { 84 | this.verboseEnabled = verbose_mode; 85 | } 86 | 87 | module.exports = Cmd; -------------------------------------------------------------------------------- /src/lib/cocoon-lib.js: -------------------------------------------------------------------------------- 1 | var shell = require('shelljs'), 2 | path = require('path'), 3 | fs = require('fs'), 4 | util = require('../utils.js'); 5 | var CliManager = null; 6 | 7 | function CocoonLib(argv, options) { 8 | CliManager = new (require("./cli-manager.js"))(argv, options); 9 | this.init(); 10 | } 11 | 12 | CocoonLib.prototype.init = function(){ 13 | 14 | shell.exec("cd " + process.cwd()); 15 | 16 | var Lib = CliManager.getCocoonLib(CliManager.getArgv(CliManager.ARGV.RAW)[0]); 17 | 18 | if(!Lib){ 19 | return util.printHelpInfo(); 20 | } 21 | 22 | new Lib(CliManager); 23 | }; 24 | 25 | module.exports = CocoonLib; -------------------------------------------------------------------------------- /src/lib/cocoon/cloud.js: -------------------------------------------------------------------------------- 1 | var shell = require('shelljs'), 2 | path = require('path'), 3 | fs = require('fs'), 4 | util = require('../../utils.js'); 5 | var CliManager = null; 6 | 7 | /** 8 | * This module manages all the requests made to the cloud compiler. 9 | * @constructor 10 | * @param CliManager 11 | */ 12 | function Cloud(CliManager) { 13 | 14 | var actions = CliManager.getArgv( CliManager.ARGV.RAW ); 15 | var command = CliManager.getArgv( CliManager.ARGV.AS_STRING ); 16 | 17 | if(actions[0] === "cloud" && actions.length === 1 ){ 18 | util.printHelpInfo("cloud.txt"); 19 | return; 20 | } 21 | 22 | var lib = this.loadCommand(actions[1]); 23 | 24 | if(lib){ 25 | new lib(this, CliManager); 26 | }else{ 27 | util.errorLog("Unknown command " + actions[1]); 28 | } 29 | } 30 | 31 | /** 32 | * 33 | * @returns {*} 34 | */ 35 | Cloud.prototype.loadCredentials = function(){ 36 | var home_path = process.env[(process.platform == 'win32') ? 'USERPROFILE' : 'HOME']; 37 | var config_file = "cocoonjs.json"; 38 | var credentialsPath = path.join(home_path, '.cordova', config_file); 39 | if(!fs.existsSync(credentialsPath)){ 40 | return false; 41 | } 42 | var content = fs.readFileSync(credentialsPath, "utf-8"); 43 | return JSON.parse(content); 44 | }; 45 | 46 | /** 47 | * 48 | * @returns {*} 49 | */ 50 | Cloud.prototype.getCredentialsPath = function(){ 51 | var home_path = process.env[(process.platform == 'win32') ? 'USERPROFILE' : 'HOME']; 52 | return path.join(home_path, '.cordova'); 53 | }; 54 | 55 | /** 56 | * Loads the specified command library and executes it. 57 | */ 58 | Cloud.prototype.loadCommand = function(action){ 59 | var lib_path = path.join(__dirname , "..", "cloud" , action + ".js"); 60 | 61 | if(fs.existsSync(lib_path)){ 62 | return require(lib_path); 63 | }else{ 64 | return false; 65 | } 66 | }; 67 | 68 | module.exports = Cloud; -------------------------------------------------------------------------------- /src/lib/cocoon/home.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {{title}} 6 | 7 | 67 | 68 | 69 |
70 | 73 | 74 |
75 | 76 |
77 |
78 |

{{heading_title}}

79 |

Project information:

80 | {{project_info}} 81 |

Available platforms:

82 |
    {{platforms}}
83 |
Missing platforms? run $ cocoonjs platform add <platform>
84 |
85 |

86 |
87 | 88 |
89 | 90 |
91 |

Visit Ludei for a showcase of amazing apps and games published with CocoonJS.

92 |
93 |
94 | 95 | -------------------------------------------------------------------------------- /src/lib/cocoon/livereload/README: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013 intesso 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is furnished 8 | to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. -------------------------------------------------------------------------------- /src/lib/cocoon/livereload/connect-index.js: -------------------------------------------------------------------------------- 1 | // Generated by CoffeeScript 1.7.1 2 | var ConnectApp, connect, es, fs, http, https, liveReload, lr, opt, path, server, tiny_lr, util; 3 | 4 | path = require("path"); 5 | 6 | es = require("./map-index.js"); 7 | 8 | http = require("http"); 9 | 10 | https = require("https"); 11 | 12 | fs = require("fs"); 13 | 14 | connect = require(path.resolve(__dirname,"../../../../","node_modules","gulp-connect","node_modules","connect","index.js")); 15 | 16 | liveReload = require("./connect-livereload.js"); 17 | 18 | tiny_lr = require("tiny-lr"); 19 | 20 | opt = {}; 21 | 22 | server = void 0; 23 | 24 | lr = void 0; 25 | 26 | ConnectApp = (function() { 27 | function ConnectApp(options) { 28 | opt = options; 29 | opt.port = opt.port || "8080"; 30 | opt.root = opt.root || path.dirname(module.parent.id); 31 | opt.host = opt.host || "localhost"; 32 | if (opt.open) { 33 | this.oldMethod("open"); 34 | } 35 | this.server(); 36 | } 37 | 38 | ConnectApp.prototype.server = function() { 39 | var app; 40 | app = connect(); 41 | this.middleware().forEach(function(middleware) { 42 | return app.use(middleware); 43 | }); 44 | if (opt.https != null) { 45 | server = https.createServer({ 46 | key: opt.https.key || fs.readFileSync(__dirname + '/certs/server.key'), 47 | cert: opt.https.cert || fs.readFileSync(__dirname + '/certs/server.crt'), 48 | ca: opt.https.ca || fs.readFileSync(__dirname + '/certs/ca.crt'), 49 | passphrase: opt.https.passphrase || 'gulp' 50 | }, app); 51 | } else { 52 | server = http.createServer(app); 53 | } 54 | app.use(connect.directory(typeof opt.root === "object" ? opt.root[0] : opt.root)); 55 | server.listen(opt.port); 56 | this.log("Server started http://" + opt.host + ":" + opt.port); 57 | if (opt.livereload) { 58 | tiny_lr.Server.prototype.error = function() {}; 59 | if (opt.https != null) { 60 | lr = tiny_lr({ 61 | key: opt.https.key || fs.readFileSync(__dirname + '/certs/server.key'), 62 | cert: opt.https.cert || fs.readFileSync(__dirname + '/certs/server.crt') 63 | }); 64 | } else { 65 | lr = tiny_lr(); 66 | } 67 | lr.listen(opt.livereload.port); 68 | return this.log("LiveReload started on port " + opt.livereload.port); 69 | } 70 | }; 71 | 72 | ConnectApp.prototype.middleware = function() { 73 | var middleware; 74 | middleware = opt.middleware ? opt.middleware.call(this, connect, opt) : []; 75 | if (opt.livereload) { 76 | if (typeof opt.livereload === "boolean") { 77 | opt.livereload = {}; 78 | } 79 | if (!opt.livereload.port) { 80 | opt.livereload.port = 35729; 81 | } 82 | middleware.push(liveReload({ 83 | port: opt.livereload.port 84 | })); 85 | } 86 | if (typeof opt.root === "object") { 87 | opt.root.forEach(function(path) { 88 | return middleware.push(connect["static"](path)); 89 | }); 90 | } else { 91 | middleware.push(connect["static"](opt.root)); 92 | } 93 | if (opt.fallback) { 94 | middleware.push(function(req, res) { 95 | return require('fs').createReadStream(opt.fallback).pipe(res); 96 | }); 97 | } 98 | return middleware; 99 | }; 100 | 101 | ConnectApp.prototype.log = function(text) { 102 | this.text = text; 103 | if (!opt.silent) { 104 | return this.text; 105 | } 106 | }; 107 | 108 | ConnectApp.prototype.logWarning = function(text) { 109 | this.text = text; 110 | if (!opt.silent) { 111 | return this.text; 112 | } 113 | }; 114 | 115 | ConnectApp.prototype.oldMethod = function(type) { 116 | var text; 117 | text = 'does not work in gulp-connect v 2.*. Please read "readme" https://github.com/AveVlad/gulp-connect'; 118 | switch (type) { 119 | case "open": 120 | return this.logWarning("Option open " + text); 121 | } 122 | }; 123 | 124 | return ConnectApp; 125 | 126 | })(); 127 | 128 | module.exports = { 129 | server: function(options) { 130 | if (options == null) { 131 | options = {}; 132 | } 133 | return new ConnectApp(options); 134 | }, 135 | reload: function() { 136 | return es(function(file, callback) { 137 | if (opt.livereload && typeof lr === "object") { 138 | lr.changed({ 139 | body: { 140 | files: file.path 141 | } 142 | }); 143 | } 144 | return callback(null, file); 145 | }); 146 | }, 147 | serverClose: function() { 148 | return server.close(); 149 | } 150 | }; 151 | -------------------------------------------------------------------------------- /src/lib/cocoon/livereload/connect-livereload.js: -------------------------------------------------------------------------------- 1 | module.exports = function livereload(opt) { 2 | // options 3 | var opt = opt || {}; 4 | var ignore = opt.ignore || opt.excludeList || ['.js', '.css', '.svg', '.ico', '.woff', '.png', '.jpg', '.jpeg']; 5 | var html = opt.html || _html; 6 | var rules = opt.rules || [{ 7 | match: /<\/body>/, 8 | fn: prepend 9 | }, { 10 | match: /<\/html>/, 11 | fn: prepend 12 | }, { 13 | match: /<\!DOCTYPE.+>/, 14 | fn: append 15 | }]; 16 | var port = opt.port || 35729; 17 | // CocoonJS Snippet, modified to make it work in Canvas+ 18 | var src = opt.src || "(location.protocol || \"http:\") + \"//\" + (location.hostname || \"localhost\") + \":\"+" + port + "+\"/livereload.js?snipver=1\""; 19 | var snippet = "\n\n"; 31 | 32 | // helper functions 33 | var regex = (function() { 34 | var matches = rules.map(function(item) { 35 | return item.match.source; 36 | }).join('|'); 37 | 38 | return new RegExp(matches); 39 | })(); 40 | 41 | function prepend(w, s) { 42 | return s + w; 43 | } 44 | 45 | function append(w, s) { 46 | return w + s; 47 | } 48 | 49 | function _html(str) { 50 | if (!str) return false; 51 | return /<[:_-\w\s\!\/\=\"\']+>/i.test(str); 52 | } 53 | 54 | function exists(body) { 55 | if (!body) return false; 56 | return regex.test(body); 57 | } 58 | 59 | function snip(body) { 60 | if (!body) return false; 61 | return (~body.lastIndexOf("/livereload.js")); 62 | } 63 | 64 | function snap(body) { 65 | var _body = body; 66 | rules.some(function(rule) { 67 | if (rule.match.test(body)) { 68 | _body = body.replace(rule.match, function(w) { 69 | return rule.fn(w, snippet); 70 | }); 71 | return true; 72 | } 73 | return false; 74 | }); 75 | return _body; 76 | } 77 | 78 | function accept(req) { 79 | var ha = req.headers["accept"]; 80 | if (!ha) return false; 81 | return (~ha.indexOf("html")); 82 | } 83 | 84 | function leave(req) { 85 | var url = req.url; 86 | var ignored = false; 87 | if (!url) return true; 88 | ignore.forEach(function(item) { 89 | if (~url.indexOf(item)) { 90 | ignored = true; 91 | } 92 | }); 93 | return ignored; 94 | } 95 | 96 | // middleware 97 | return function livereload(req, res, next) { 98 | if (res._livereload) return next(); 99 | res._livereload = true; 100 | 101 | var writeHead = res.writeHead; 102 | var write = res.write; 103 | var end = res.end; 104 | 105 | // if (!accept(req) || leave(req)) { 106 | // return next(); 107 | // } 108 | 109 | function restore() { 110 | res.writeHead = writeHead; 111 | res.write = write; 112 | res.end = end; 113 | } 114 | 115 | res.push = function(chunk) { 116 | res.data = (res.data || '') + chunk; 117 | }; 118 | 119 | res.inject = res.write = function(string, encoding) { 120 | if (string !== undefined) { 121 | var body = string instanceof Buffer ? string.toString(encoding) : string; 122 | if (exists(body) && !snip(res.data)) { 123 | res.push(snap(body)); 124 | return true; 125 | } else if (html(body) || html(res.data)) { 126 | res.push(body); 127 | return true; 128 | } else { 129 | restore(); 130 | return write.call(res, string, encoding); 131 | } 132 | } 133 | return true; 134 | }; 135 | 136 | res.writeHead = function() { 137 | var headers = arguments[arguments.length - 1]; 138 | if (headers && typeof headers === 'object') { 139 | for (var name in headers) { 140 | if (/content-length/i.test(name)) { 141 | delete headers[name]; 142 | } 143 | } 144 | } 145 | 146 | var header = res.getHeader( 'content-length' ); 147 | if ( header ) res.removeHeader( 'content-length' ); 148 | 149 | writeHead.apply(res, arguments); 150 | }; 151 | 152 | res.end = function(string, encoding) { 153 | restore(); 154 | var result = res.inject(string, encoding); 155 | if (!result) return end.call(res, string, encoding); 156 | if (res.data !== undefined && !res._header) res.setHeader('content-length', Buffer.byteLength(res.data, encoding)); 157 | res.end(res.data, encoding); 158 | }; 159 | next(); 160 | }; 161 | 162 | } 163 | -------------------------------------------------------------------------------- /src/lib/cocoon/livereload/map-index.js: -------------------------------------------------------------------------------- 1 | //filter will reemit the data if cb(err,pass) pass is truthy 2 | 3 | // reduce is more tricky 4 | // maybe we want to group the reductions or emit progress updates occasionally 5 | // the most basic reduce just emits one 'data' event after it has recieved 'end' 6 | 7 | 8 | var Stream = require('stream').Stream 9 | 10 | 11 | //create an event stream and apply function to each .write 12 | //emitting each response as data 13 | //unless it's an empty callback 14 | 15 | module.exports = function (mapper, opts) { 16 | 17 | var stream = new Stream() 18 | , self = this 19 | , inputs = 0 20 | , outputs = 0 21 | , ended = false 22 | , paused = false 23 | , destroyed = false 24 | , lastWritten = 0 25 | , inNext = false 26 | 27 | this.opts = opts || {}; 28 | var errorEventName = this.opts.failures ? 'failure' : 'error'; 29 | 30 | // Items that are not ready to be written yet (because they would come out of 31 | // order) get stuck in a queue for later. 32 | var writeQueue = {} 33 | 34 | stream.writable = true 35 | stream.readable = true 36 | 37 | function queueData (data, number) { 38 | var nextToWrite = lastWritten + 1 39 | 40 | if (number === nextToWrite) { 41 | // If it's next, and its not undefined write it 42 | if (data !== undefined) { 43 | stream.emit.apply(stream, ['data', data]) 44 | } 45 | lastWritten ++ 46 | nextToWrite ++ 47 | } else { 48 | // Otherwise queue it for later. 49 | writeQueue[number] = data 50 | } 51 | 52 | // If the next value is in the queue, write it 53 | if (writeQueue.hasOwnProperty(nextToWrite)) { 54 | var dataToWrite = writeQueue[nextToWrite] 55 | delete writeQueue[nextToWrite] 56 | return queueData(dataToWrite, nextToWrite) 57 | } 58 | 59 | outputs ++ 60 | if(inputs === outputs) { 61 | if(paused) paused = false, stream.emit('drain') //written all the incoming events 62 | if(ended) end() 63 | } 64 | } 65 | 66 | function next (err, data, number) { 67 | if(destroyed) return 68 | inNext = true 69 | 70 | if (!err || self.opts.failures) { 71 | queueData(data, number) 72 | } 73 | 74 | if (err) { 75 | stream.emit.apply(stream, [ errorEventName, err ]); 76 | } 77 | 78 | inNext = false; 79 | } 80 | 81 | // Wrap the mapper function by calling its callback with the order number of 82 | // the item in the stream. 83 | function wrappedMapper (input, number, callback) { 84 | return mapper.call(null, input, function(err, data){ 85 | callback(err, data, number) 86 | }) 87 | } 88 | 89 | stream.write = function (data) { 90 | if(ended) throw new Error('map stream is not writable') 91 | inNext = false 92 | inputs ++ 93 | 94 | try { 95 | //catch sync errors and handle them like async errors 96 | var written = wrappedMapper(data, inputs, next) 97 | paused = (written === false) 98 | return !paused 99 | } catch (err) { 100 | //if the callback has been called syncronously, and the error 101 | //has occured in an listener, throw it again. 102 | if(inNext) 103 | throw err 104 | next(err) 105 | return !paused 106 | } 107 | } 108 | 109 | function end (data) { 110 | //if end was called with args, write it, 111 | ended = true //write will emit 'end' if ended is true 112 | stream.writable = false 113 | if(data !== undefined) { 114 | return queueData(data, inputs) 115 | } else if (inputs == outputs) { //wait for processing 116 | stream.readable = false, stream.emit('end'), stream.destroy() 117 | } 118 | } 119 | 120 | stream.end = function (data) { 121 | if(ended) return 122 | end() 123 | } 124 | 125 | stream.destroy = function () { 126 | ended = destroyed = true 127 | stream.writable = stream.readable = paused = false 128 | process.nextTick(function () { 129 | stream.emit('close') 130 | }) 131 | } 132 | stream.pause = function () { 133 | paused = true 134 | } 135 | 136 | stream.resume = function () { 137 | paused = false 138 | } 139 | 140 | return stream 141 | } 142 | 143 | 144 | 145 | 146 | -------------------------------------------------------------------------------- /src/lib/cocoon/serve.js: -------------------------------------------------------------------------------- 1 | var shell = require('shelljs'), 2 | util = require('../../utils.js'), 3 | path = require('path'), 4 | fs = require('fs'), 5 | gulp = require('gulp'), 6 | gulp_connect = require(path.resolve(__dirname,"livereload","connect-index.js")), 7 | ip = require('ip'), 8 | qrcode = require('qrcode-terminal'), 9 | me = this, 10 | root = path.join(process.cwd() , "www"), 11 | platformId = null, 12 | mime = require('mime'), 13 | config_xml; 14 | 15 | var CliManager; 16 | function LiveReload(manager) { 17 | CliManager = manager; 18 | 19 | var command = CliManager.getArgv( CliManager.ARGV.AS_STRING ); 20 | 21 | util.log("Executing command '" + command + "'"); 22 | 23 | this.cmd = CliManager.getCMD(); 24 | 25 | util.log("A 'cordova prepare' is needed before executing 'cordova serve'."); 26 | // Prepare the project before serving it. 27 | var prepare = this.cmd.exec("prepare", { silent : false }); 28 | if(prepare.code !== 0){ 29 | util.errorLog("Error executing 'cordova prepare'. " + prepare.output); 30 | process.exit(0); 31 | } 32 | 33 | util.log("Command 'cordova prepare' executed correctly."); 34 | console.log(""); // Blank line for spacing unrelated logs of the livereload 35 | 36 | me = this; 37 | util.getConfigXML(function(err, xml){ 38 | if(err){ 39 | process.exit(0); 40 | } 41 | config_xml = xml; 42 | me.init(); 43 | }); 44 | } 45 | 46 | // Function helpers for serving specific files of cordova 47 | LiveReload.prototype.serveCordovaLibrary = function(res, platform){ 48 | var cordova_lib_path = path.join(process.cwd() , "platforms", platform, "platform_www", "cordova.js"); 49 | var cordova_lib_content = fs.readFileSync( cordova_lib_path , 'utf-8'); 50 | res.end( cordova_lib_content ); 51 | }; 52 | 53 | LiveReload.prototype.serveCordovaPlugins = function(res, platform){ 54 | var cordova_plugin_path = path.join(process.cwd() , "platforms", platform, this.getCordovaPluginsPath(platform), "cordova_plugins.js"); 55 | var cordova_plugin_content = fs.readFileSync( cordova_plugin_path , 'utf-8'); 56 | res.end( cordova_plugin_content ); 57 | }; 58 | 59 | LiveReload.prototype.getCordovaPluginsPath = function(platform){ 60 | var plugins_path; 61 | if(platform === "android"){ 62 | plugins_path = "assets/www"; 63 | }else if(platform === "ios" || platform === "browser"){ 64 | plugins_path = "www"; 65 | } 66 | return plugins_path; 67 | }; 68 | 69 | // Middleware for gulp, serves static files and injects livereload snippet in case of inde.html file 70 | LiveReload.prototype.middlewareCordovaLib = function(req, res, next){ 71 | 72 | util.log("Serving file " + req.url); 73 | 74 | var queryString = req.url.split("/"); 75 | var platforms = util.getPlatforms(); 76 | 77 | if(queryString.length >= 1 && queryString[0] === "" ) queryString.shift(); 78 | 79 | if(platforms.length === 0){ 80 | util.log("Platform add"); 81 | process.exit(0); 82 | } 83 | 84 | if (queryString.length === 1 && queryString[0] === "") { 85 | res.end( me.getMainHTML(platforms) ); 86 | return; 87 | } 88 | 89 | if( platforms[queryString[0]] ) { 90 | if( platformId != queryString[0]){ 91 | platformId = queryString[0]; 92 | } 93 | } 94 | 95 | //Special files, served from specific directories. 96 | if(queryString[0] && queryString[0] === "cordova.js"){ 97 | me.serveCordovaLibrary(res, platformId); 98 | next(); 99 | } 100 | 101 | if(queryString[0] && queryString[0] === "cordova_plugins.js"){ 102 | me.serveCordovaPlugins(res, platformId); 103 | next(); 104 | } 105 | 106 | if(platformId === queryString[0]) queryString.shift(); 107 | 108 | var path_file = queryString.join("/"); 109 | if( path_file === "" || path_file ){ 110 | var file; 111 | 112 | if( path_file === "" || path_file === "/" + platformId){ 113 | file = me.getStaticFile("index.html", res); 114 | // next middleware only loaded if we're using index.html 115 | // TODO: read from config file the main HTML file to inject there. 116 | next(); 117 | }else{ 118 | file = me.getStaticFile(path_file, res); 119 | } 120 | 121 | if(file){ 122 | res.end( file ); 123 | } 124 | } 125 | }; 126 | 127 | LiveReload.prototype.getMainHTML = function (platforms){ 128 | var ServeTemplateManager = require("./serve_home.js"); 129 | return new ServeTemplateManager(platforms, config_xml).getTemplate(); 130 | }; 131 | 132 | LiveReload.prototype.getStaticFile = function(path_file, res){ 133 | var static_file = path.join(process.cwd() , "www", path_file); 134 | 135 | var textExtensions = [".htm",".html",".js",".css"]; 136 | var isPlainTextFile = this.isPlainTextFile(path_file,textExtensions); 137 | 138 | var mimeType = mime.lookup(static_file); 139 | 140 | 141 | // Detection of file type and return with proper myme type and encondig 142 | if(fs.existsSync(static_file)){ 143 | res.writeHead(200, {'Content-Type': mimeType }); 144 | return fs.readFileSync( static_file , (isPlainTextFile) ? 'utf-8' : undefined); 145 | }else{ 146 | return false; 147 | } 148 | }; 149 | 150 | LiveReload.prototype.isPlainTextFile = function (str, strArray) { 151 | for (var j=0; j= 0 ) return true; 153 | } 154 | return false; 155 | } 156 | 157 | LiveReload.prototype.init = function(){ 158 | var port = 8070; 159 | var server_url = "http://" + ip.address() + ":" + port; 160 | 161 | if( !fs.existsSync(root) ){ 162 | util.log("Current working directory is not a CocoonJS/Cordova-based project."); 163 | process.exit(); 164 | } 165 | 166 | gulp.task('connect', function() { 167 | gulp_connect.server({ 168 | root: root, 169 | silent : true, 170 | port : 8070, 171 | livereload: true, 172 | middleware: function() { 173 | return [me.middlewareCordovaLib] 174 | } 175 | }); 176 | }); 177 | 178 | gulp.task('reload_html', function () { 179 | gulp.src( path.join(root,'/**/*.html') ).pipe(gulp_connect.reload()); 180 | }); 181 | 182 | gulp.task('reload_styles', function () { 183 | gulp.src( path.join(root,'/**/*.css') ).pipe(gulp_connect.reload()); 184 | }); 185 | 186 | gulp.task('reload_code', function () { 187 | gulp.src( path.join(root,'/**/*.js') ).pipe(gulp_connect.reload()); 188 | }); 189 | 190 | gulp.task('watch', function () { 191 | gulp.watch([ path.join(root,'/**/*.html') ], ['reload_html']); 192 | gulp.watch([ path.join(root,'/**/*.css') ], ['reload_styles']); 193 | gulp.watch([ path.join(root,'/**/*.js') ], ['reload_code']); 194 | }); 195 | 196 | gulp.task('default', ['connect', 'watch']); 197 | gulp.start('default'); 198 | 199 | util.log("Static file server running on port " + port + " (i.e. " + server_url + ")"); 200 | util.log("Path: " + root); 201 | util.log("CTRL + C to shut down"); 202 | 203 | if( CliManager.getArgv( CliManager.ARGV.RAW )['qrcode'] ) qrcode.generate(server_url); 204 | }; 205 | 206 | module.exports = LiveReload; 207 | -------------------------------------------------------------------------------- /src/lib/cocoon/serve_home.js: -------------------------------------------------------------------------------- 1 | var util = require('../../utils.js'), 2 | path = require('path'), 3 | fs = require('fs'); 4 | 5 | (function(){ 6 | function ServeHome(platforms, config_xml) { 7 | if(!config_xml) return; 8 | 9 | var home_template = fs.readFileSync( path.join(__dirname,"home.html") , "utf-8"); 10 | 11 | var platforms_template = ""; 12 | for (var i = 0; i < platforms.length; i++) { 13 | platforms_template += "
  • "+ platforms[i] +"
  • \n"; 14 | } 15 | 16 | home_template = home_template.replace("{{platforms}}", platforms_template); 17 | 18 | var project_info_template = ""; 19 | 20 | var bundle_id = this.getConfigParam("bundle_id"); 21 | if(bundle_id){ 22 | project_info_template += "

    Bundle id: " + bundle_id + "

    \n"; 23 | } 24 | 25 | var version = this.getConfigParam("version"); 26 | if(version){ 27 | project_info_template += "

    Version: " + version + "

    \n"; 28 | } 29 | 30 | var name = this.getConfigParam("title"); 31 | if(name){ 32 | project_info_template += "

    Name: " + name + "

    \n"; 33 | } 34 | 35 | var description = this.getConfigParam("description"); 36 | if(description){ 37 | project_info_template += "

    Description: " + description + "

    \n"; 38 | } 39 | 40 | var author = this.getConfigParam("author"); 41 | if(author){ 42 | project_info_template += "

    Author: " + author + "

    \n"; 43 | } 44 | 45 | home_template = home_template.replace("{{project_info}}", project_info_template); 46 | 47 | home_template = home_template.replace("{{title}}", this.getConfigParam("title")); 48 | home_template = home_template.replace("{{heading_title}}", this.getConfigParam("title").toUpperCase()); 49 | 50 | this.home_template = home_template; 51 | } 52 | 53 | ServeHome.prototype.getConfigParam = function(param){ 54 | var namespace = ""; 55 | var ret = []; 56 | switch (param) { 57 | case "title": 58 | namespace = "config_xml.widget.name"; 59 | ret = this.getValueFromObj(this,namespace); 60 | return (ret[0]) ? ret[0] : ""; 61 | break; 62 | case "bundle_id": 63 | namespace = "config_xml.widget.$.id"; 64 | ret = this.getValueFromObj(this,namespace); 65 | return (ret[0]) ? ret[0] : ""; 66 | break; 67 | case "version": 68 | namespace = "config_xml.widget.$.version"; 69 | ret = this.getValueFromObj(this,namespace); 70 | return ret; 71 | break; 72 | case "description": 73 | namespace = "config_xml.widget.description"; 74 | ret = this.getValueFromObj(this,namespace); 75 | return (ret[0]) ? ret[0] : ""; 76 | break; 77 | case "author": 78 | namespace = "config_xml.widget.author"; 79 | ret = this.getValueFromObj(this,namespace); 80 | return (ret[0] && ret[0]["_"]) ? [0]["_"] : ""; 81 | break; 82 | default: 83 | return ""; 84 | break; 85 | } 86 | }; 87 | 88 | ServeHome.prototype.getValueFromObj = function(objReference, namespace){ 89 | var parts = namespace.split("."); 90 | var len = parts.length; 91 | for (var i = 0; i < len; ++i) { 92 | if(!objReference[parts[i]]) return ""; 93 | objReference = objReference[parts[i]]; 94 | } 95 | return objReference; 96 | }; 97 | 98 | ServeHome.prototype.getTemplate = function(){ 99 | return this.home_template; 100 | }; 101 | 102 | module.exports = ServeHome; 103 | })(); -------------------------------------------------------------------------------- /src/lib/config-xml.js: -------------------------------------------------------------------------------- 1 | var shell = require('shelljs'); 2 | var path = require('path'); 3 | var fs = require('fs'); 4 | var xml2js = require('xml2js'); 5 | 6 | function ConfigManager() { 7 | 8 | } 9 | 10 | ConfigManager.prototype.getConfigXMLPath = function(project_path){ 11 | var config_path = path.join(project_path, "config.xml"); 12 | 13 | this.xml = ""; 14 | this.config_xml_path = ""; 15 | 16 | if( fs.existsSync(config_path) ){ 17 | return config_path; 18 | } 19 | 20 | config_path = path.join(project_path, "www","config.xml"); 21 | if( fs.existsSync(config_path) ){ 22 | return config_path; 23 | } 24 | 25 | return false; 26 | }; 27 | 28 | /** 29 | * 30 | * @param workingPath 31 | * @param callback 32 | * @returns {*} 33 | */ 34 | ConfigManager.prototype.readConfigXML = function(workingPath, callback){ 35 | var parser = new xml2js.Parser(); 36 | this.config_xml_path = this.getConfigXMLPath(workingPath); 37 | 38 | if(!this.config_xml_path){ 39 | callback("Can't find your config.xml at the given path " + workingPath, null); 40 | } 41 | 42 | var configAsXml = fs.readFileSync( this.config_xml_path ).toString('UTF-8'); 43 | this.xml = configAsXml; 44 | parser.parseString(configAsXml, function(err, configAsObj){ 45 | callback(err, configAsObj, configAsXml); 46 | }); 47 | }; 48 | 49 | ConfigManager.prototype.setValue = function(section, value){ 50 | 51 | if (!this.xml){ 52 | throw new Error("You have to call .readConfigXML(); before setting a value."); 53 | } 54 | 55 | switch ( section ) { 56 | case "app_version": 57 | this.xml = this.xml.replace(/" version="([^"]*)"/, '" version=\"' + value + '\"'); 58 | break; 59 | } 60 | 61 | }; 62 | 63 | ConfigManager.prototype.getValue = function(section){ 64 | if (!this.xml){ 65 | throw new Error("You have to call .readConfigXML(); before getting a value."); 66 | } 67 | 68 | switch ( section ) { 69 | case "package": 70 | return this.xml.match(/id="([^"]*)"/)[1]; 71 | break; 72 | } 73 | }; 74 | 75 | ConfigManager.prototype.saveConfig = function(){ 76 | fs.writeFileSync(this.config_xml_path, this.xml, { encoding : 'utf8' }); 77 | } 78 | 79 | module.exports = ConfigManager; 80 | -------------------------------------------------------------------------------- /src/lib/cordova-lib.js: -------------------------------------------------------------------------------- 1 | var shell = require('shelljs'), 2 | fs = require('fs'), 3 | path = require('path'), 4 | util = require('../utils.js'); 5 | var CliManager = null; 6 | 7 | function CordovaLib(argv, options) { 8 | CliManager = new (require("./cli-manager.js"))(argv, options); 9 | this.init(); 10 | } 11 | 12 | CordovaLib.prototype.init = function(){ 13 | shell.exec("cd " + process.cwd()); 14 | 15 | var CommandLib = CliManager.getCordovaLib(CliManager.getArgv(CliManager.ARGV.RAW)[0]); 16 | this._cmd = CliManager.getCMD(); 17 | 18 | var req_results = this.checkRequirements(); 19 | if(req_results.code !== 0){ 20 | util.log("Could not find a valid Cordova version installed in your system."); 21 | util.log("Please install it with '$ npm install -g cordova'."); 22 | util.log("Or use --cordova-path to provide a local copy of the Cordova-CLI."); 23 | return; 24 | } 25 | 26 | if(!CommandLib){ 27 | util.errorLog("Could not execute the command '" + CliManager.getArgv(CliManager.ARGV.RAW)[0] + "'."); 28 | util.errorLog("The command because it's not available as a cordova library."); 29 | return; 30 | } 31 | 32 | new CommandLib(CliManager); 33 | }; 34 | 35 | CordovaLib.prototype.checkRequirements = function(){ 36 | var options = { 37 | silent : true 38 | }; 39 | 40 | return this._cmd.exec(" --version", options); 41 | }; 42 | 43 | module.exports = CordovaLib; -------------------------------------------------------------------------------- /src/lib/cordova/build.js: -------------------------------------------------------------------------------- 1 | var shell = require('shelljs'), 2 | path = require('path'), 3 | util = require('../../utils.js'); 4 | 5 | function BuildCommand(CliManager) { 6 | 7 | this.CliManager = CliManager; 8 | this.argv = CliManager.getArgv(CliManager.ARGV.RAW); 9 | this.command = CliManager.getArgv(CliManager.ARGV.AS_STRING); 10 | this.cmd = CliManager.getCMD(); 11 | 12 | util.log("Executing command '" + this.command + "'"); 13 | 14 | var platform_name = this.argv[1]; 15 | if( this.argv[1] && this.isLudeiPlatform(platform_name) ){ 16 | this.buildCustomPlatform(platform_name); 17 | return; 18 | } 19 | 20 | this.executeGenericCommand(); 21 | } 22 | 23 | BuildCommand.prototype.buildCustomPlatform = function(platform_name){ 24 | var platform_path = path.join(__dirname, "build", platform_name); 25 | var PlatformLib = require(platform_path); 26 | new PlatformLib(this.CliManager); 27 | }; 28 | 29 | BuildCommand.prototype.isLudeiPlatform = function(platform_name){ 30 | var platforms = this.CliManager.getLudeiPlatforms(); 31 | 32 | for(var x = 0; x < platforms.length; x++){ 33 | if(platform_name === platforms[x].name){ 34 | return true; 35 | } 36 | } 37 | 38 | return false; 39 | }; 40 | 41 | BuildCommand.prototype.executeGenericCommand = function(){ 42 | this.cmd.execAsync( this.command, { 43 | events : { 44 | stdout : function(data){ 45 | util.log(data.toString()); 46 | }, 47 | stderr : function(data){ 48 | console.error(data.toString()); 49 | }, 50 | exit : function(status){ 51 | process.exit(status); 52 | } 53 | } 54 | }); 55 | }; 56 | 57 | module.exports = BuildCommand; -------------------------------------------------------------------------------- /src/lib/cordova/build/samsung-smarttv.js: -------------------------------------------------------------------------------- 1 | var shell = require('shelljs'), 2 | path = require('path'), 3 | fs = require('fs'), 4 | util = require('../../../utils.js'); 5 | var archiver = require('archiver'); 6 | 7 | function SamsungSmartTv(CliManager) { 8 | 9 | this.CliManager = CliManager; 10 | util.log("Building SamsungSmartTv"); 11 | 12 | this.project_path = path.join( process.cwd() ); 13 | this.platforms_path = path.join(this.project_path, "platforms", "samsung-smarttv"); 14 | this.platforms_path_www = path.join(this.platforms_path, "www"); 15 | this.platforms_path_build = path.join(this.platforms_path, "build"); 16 | this.project_www = path.join(this.project_path, "www", "/"); 17 | 18 | shell.cp('-Rf', this.project_www, this.platforms_path_www); 19 | 20 | this.build(); 21 | } 22 | 23 | SamsungSmartTv.prototype.build = function(){ 24 | util.log("Compressing project..."); 25 | 26 | this.projectPath = process.cwd(); 27 | var outputPath = this.platforms_path_build; 28 | var outputFile = "samsung-smarttv.zip"; 29 | var srcPath = this.platforms_path_www; 30 | var zipArchive = archiver('zip'); 31 | var me = this; 32 | 33 | if( !fs.existsSync(outputPath) ) { 34 | shell.mkdir("-p", outputPath); 35 | } 36 | 37 | var output = fs.createWriteStream( path.join( outputPath , outputFile) ); 38 | 39 | output.on('close', function() { 40 | util.log("Build succeeded! " + path.join(me.platforms_path_build, outputFile) ); 41 | }); 42 | 43 | output.on('error', function() { 44 | console.error('error', arguments); 45 | }); 46 | 47 | zipArchive.pipe(output); 48 | 49 | var bulkDirectories = [ 50 | { src: [ '**/*' ], cwd: srcPath, dest: '/', expand: true } 51 | ]; 52 | 53 | zipArchive.bulk(bulkDirectories); 54 | 55 | zipArchive.finalize(); 56 | 57 | } 58 | 59 | module.exports = SamsungSmartTv; -------------------------------------------------------------------------------- /src/lib/cordova/create.js: -------------------------------------------------------------------------------- 1 | var shell = require('shelljs'), 2 | fs = require('fs'), 3 | path = require('path'), 4 | util = require('../../utils.js'); 5 | 6 | function Create(CliManager, callback) { 7 | 8 | var command_list = CliManager.getArgv(CliManager.ARGV.RAW); 9 | var cmd = CliManager.getCMD(); 10 | var command = CliManager.getArgv(CliManager.ARGV.AS_STRING); 11 | 12 | if(command_list.length === 1){ 13 | throw new Error("At least the dir must be provided to create new project. See `cocoonjs --help`."); 14 | }else{ 15 | util.log("Executing command '" + command + "'"); 16 | } 17 | 18 | this.commands = command_list; 19 | 20 | this.stdout = ""; 21 | this.stderr = ""; 22 | var me = this; 23 | cmd.execAsync(command, { 24 | events : { 25 | stdout : function(data){ 26 | me.stdout += data; 27 | if(!callback) util.log(data); 28 | }, 29 | stderr : function(data){ 30 | me.stderr += data; 31 | if(!callback) util.log(data); 32 | }, 33 | exit : function(status){ 34 | 35 | if(status === 0){ 36 | me.updateAssets(); 37 | me.terminateCommand(callback, status); 38 | }else{ 39 | me.terminateCommand(callback, status); 40 | } 41 | 42 | } 43 | } 44 | }); 45 | } 46 | 47 | Create.prototype.terminateCommand = function(callback, status){ 48 | if(callback){ 49 | callback(this.stdout, this.stderr, status); 50 | }else{ 51 | process.exit(status); 52 | } 53 | }; 54 | 55 | Create.prototype.updateAssets = function(){ 56 | var project_path = path.join( this.commands[1] , "www"); 57 | var brand = path.join(project_path, "img", "logo.png"); 58 | var cli_brand = path.join(__dirname, "..", "..", "assets", "logo.png"); 59 | var index_file = path.join(project_path, "index.html"); 60 | 61 | if( fs.existsSync(brand) ){ 62 | shell.cp("-f", cli_brand,brand); 63 | } 64 | 65 | if( fs.existsSync(index_file) ){ 66 | var index_content = fs.readFileSync(index_file,'utf8'); 67 | index_content = index_content.replace("

    Apache Cordova

    ", "

    CocoonJS

    "); 68 | fs.writeFileSync(index_file, index_content, 'utf8') 69 | } 70 | }; 71 | 72 | module.exports = Create; -------------------------------------------------------------------------------- /src/lib/cordova/generic.js: -------------------------------------------------------------------------------- 1 | var shell = require('shelljs'), 2 | util = require('../../utils.js'); 3 | 4 | function GenericCommand(CliManager) { 5 | 6 | var command = CliManager.getArgv(CliManager.ARGV.AS_STRING); 7 | var cmd = CliManager.getCMD(); 8 | 9 | util.log("Executing command '" + command + "'"); 10 | 11 | cmd.execAsync(command, { 12 | events : { 13 | stdout : function(data){ 14 | util.log(data.toString()); 15 | }, 16 | stderr : function(data){ 17 | console.error(data.toString()); 18 | }, 19 | exit : function(status){ 20 | process.exit(status); 21 | } 22 | } 23 | }); 24 | } 25 | 26 | module.exports = GenericCommand; -------------------------------------------------------------------------------- /src/lib/cordova/platform.js: -------------------------------------------------------------------------------- 1 | var shell = require('shelljs'), 2 | path = require('path'), 3 | util = require('../../utils.js'); 4 | 5 | function Platform(CliManager) { 6 | 7 | this.CliManager = CliManager; 8 | this.argv = CliManager.getArgv(CliManager.ARGV.RAW); 9 | this.command = CliManager.getArgv(CliManager.ARGV.AS_STRING); 10 | this.cmd = CliManager.getCMD(); 11 | 12 | util.log("Executing command '" + this.command + "'"); 13 | 14 | var platform_name = this.argv[2]; 15 | if( this.argv[1] === "add" && this.isLudeiPlatform(platform_name) ){ 16 | this.installLudeiPlatform(platform_name); 17 | return; 18 | } 19 | 20 | this.executeGenericCommand(); 21 | } 22 | 23 | Platform.prototype.installLudeiPlatform = function(platform_name){ 24 | var platform_path = path.join(__dirname, "platforms", platform_name); 25 | var PlatformLib = require(platform_path); 26 | new PlatformLib(this.CliManager); 27 | }; 28 | 29 | Platform.prototype.isLudeiPlatform = function(platform_name){ 30 | var platforms = this.CliManager.getLudeiPlatforms(); 31 | 32 | for(var x = 0; x < platforms.length; x++){ 33 | if(platform_name === platforms[x].name){ 34 | return true; 35 | } 36 | } 37 | 38 | return false; 39 | }; 40 | 41 | Platform.prototype.executeGenericCommand = function(){ 42 | this.cmd.execAsync( this.command, { 43 | events : { 44 | stdout : function(data){ 45 | util.log(data.toString()); 46 | }, 47 | stderr : function(data){ 48 | console.error(data.toString()); 49 | }, 50 | exit : function(status){ 51 | process.exit(status); 52 | } 53 | } 54 | }); 55 | } 56 | 57 | module.exports = Platform; -------------------------------------------------------------------------------- /src/lib/cordova/platforms.js: -------------------------------------------------------------------------------- 1 | var shell = require('shelljs'), 2 | util = require('../../utils.js'); 3 | 4 | function Platform(CliManager) { 5 | 6 | var Lib = CliManager.getCordovaLib("platform"); 7 | new Lib(CliManager); 8 | 9 | } 10 | 11 | module.exports = Platform; -------------------------------------------------------------------------------- /src/lib/cordova/platforms/samsung-smarttv.js: -------------------------------------------------------------------------------- 1 | var shell = require('shelljs'), 2 | path = require('path'), 3 | fs = require('fs'), 4 | util = require('../../../utils.js'); 5 | 6 | function SamsungSmartTv(CliManager) { 7 | 8 | this.CliManager = CliManager; 9 | util.log("Installing SamsungSmartTv"); 10 | 11 | var project_path = path.join( process.cwd() ); 12 | var platforms_path = path.join(project_path, "platforms", "samsung-smarttv"); 13 | var platforms_path_www = path.join(platforms_path, "www"); 14 | var platforms_path_build = path.join(platforms_path, "build"); 15 | var assets_path = path.join(__dirname, "samsung-smarttv", "/"); 16 | 17 | if( !fs.existsSync(platforms_path_www) ){ 18 | shell.mkdir('-p', platforms_path_www); 19 | } 20 | 21 | if( !fs.existsSync(platforms_path_build) ){ 22 | shell.mkdir('-p', platforms_path_build); 23 | } 24 | 25 | shell.cp('-Rf', assets_path, platforms_path_www); 26 | util.log("Platform 'samsung-smarttv' added correctly.") 27 | } 28 | 29 | module.exports = SamsungSmartTv; -------------------------------------------------------------------------------- /src/lib/cordova/platforms/samsung-smarttv/config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | icon/sampleIcon_106_87.png 7 | icon/sampleIcon_115_95.png 8 | icon/sampleIcon_85_70.png 9 | icon/sampleIcon_95_78.png 10 | 11 | n 12 | 0.100 13 | 14 | y 15 | user 16 | y 17 | n 18 | n 19 | n 20 | y 21 | LudeiHTML5App 22 | 23 | 960 24 | 540 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /src/lib/cordova/platforms/samsung-smarttv/widget.info: -------------------------------------------------------------------------------- 1 | Use Alpha Blending? = Yes 2 | Screen Resolution = 960x540 3 | -------------------------------------------------------------------------------- /src/lib/cordova/plugin.js: -------------------------------------------------------------------------------- 1 | var shell = require('shelljs'), 2 | path = require('path'), 3 | fs = require('fs'), 4 | util = require('../../utils.js'); 5 | var fileExists = fs.existsSync; 6 | 7 | function CordovaPlugin(CliManager) { 8 | 9 | var cmd = CliManager.getCMD(); 10 | var command = CliManager.getArgv( CliManager.ARGV.AS_STRING ); 11 | this._argv = CliManager.getArgv( CliManager.ARGV.RAW ); 12 | 13 | util.log("Executing command '" + command + "'"); 14 | 15 | var ctx = this; 16 | this._commands = command; 17 | this._commands_list = command.split(" "); 18 | this._cmd = cmd; 19 | 20 | this._config_xml = {}; 21 | this.ludei_plugins = []; 22 | util.getConfigXML(function(err, data){ 23 | if(err){ 24 | util.log("Cannot locate your config.xml"); 25 | ctx.init(); 26 | } 27 | ctx._config_xml = data; 28 | ctx.init(); 29 | }); 30 | } 31 | 32 | CordovaPlugin.prototype.init = function(){ 33 | 34 | if(this._commands_list.length < 2) { 35 | this.executePluginCommand(); 36 | return; 37 | } 38 | 39 | var plugin_id = this._commands_list[2]; 40 | 41 | // Is this a folder?, get the plugin id if so. 42 | if( fs.existsSync(plugin_id) && fs.existsSync( path.join(plugin_id, "plugin.xml") ) ){ 43 | var plugin_info = fs.readFileSync( path.join(plugin_id, "plugin.xml"), "utf8"); 44 | plugin_id = plugin_info.match(/ id="(.*?)"/)[1]; 45 | delete plugin_info; 46 | } 47 | 48 | /** 49 | * TODO: The following code should be compatible with any Ludei plugin. 50 | */ 51 | var ludei_plugin = this.isLudeiPlugin(plugin_id); 52 | if(this._commands_list[1] === "add" && ludei_plugin){ 53 | if( ludei_plugin.plugin_id === plugin_id ){ 54 | if( ludei_plugin.plugin_id === "com.ludei.ios.webview.plus" ){ 55 | this.installiOSWebViewPlus(ludei_plugin); 56 | }else if (ludei_plugin.plugin_id === "com.ludei.webview.plus"){ 57 | this.installAndroidWebViewPlus(ludei_plugin); 58 | } 59 | } 60 | }else if(this._commands_list[1] === "rm" || this._commands_list[1] === "remove" && ludei_plugin){ 61 | if( ludei_plugin.plugin_id === plugin_id ) { 62 | if( ludei_plugin.plugin_id === "com.ludei.ios.webview.plus" ){ 63 | this.uninstalliOSWebViewPlus(ludei_plugin); 64 | }else if (ludei_plugin.plugin_id === "com.ludei.webview.plus"){ 65 | this.removeAndroidWebViewPlus(ludei_plugin); 66 | } 67 | } 68 | }else{ 69 | this.executePluginCommand(); 70 | } 71 | }; 72 | 73 | CordovaPlugin.prototype.isLudeiPlugin = function(plugin_id){ 74 | var bundle_id = plugin_id; 75 | var ludei_plugins = this.getLudeiPlugins(); 76 | 77 | if(!ludei_plugins) return false; 78 | 79 | for (var i = 0; i < ludei_plugins.length; i++) { 80 | if(bundle_id === ludei_plugins[i].plugin_id) return ludei_plugins[i]; 81 | } 82 | 83 | return false; 84 | }; 85 | 86 | CordovaPlugin.prototype.getLudeiPlugins = function(){ 87 | var plugins_info_path = path.join(__dirname, "../", "../", "ludei_plugins.json"); 88 | if(fs.existsSync(plugins_info_path)) return require(plugins_info_path).plugins; 89 | return false; 90 | }; 91 | 92 | CordovaPlugin.prototype.executePluginCommand = function(){ 93 | var result = this._cmd.exec(this._commands); 94 | if(result.code !== 0){ 95 | util.log("Something went wrong"); 96 | util.log(result.output); 97 | process.exit(result.code); 98 | }else{ 99 | util.log(result.output); 100 | process.exit(result.code); 101 | } 102 | }; 103 | 104 | CordovaPlugin.prototype.WebViewPlusReq = function(){ 105 | var result = ""; 106 | var options = { avoidCordovaCMD : true, silent : true }; 107 | var command = ""; 108 | 109 | command = (util.inWindows) ? "android --help" : "which android"; 110 | result = this._cmd.exec(command, options); 111 | if(result.code !== 0){ 112 | util.log("The command `android` failed. Add the platform-tools/ as well as the tools/ directory to your PATH environment variable."); 113 | return false; 114 | } 115 | 116 | command = (util.inWindows) ? "set" : "echo $ANDROID_HOME"; 117 | result = this._cmd.exec(command, options); 118 | if(util.inWindows){ 119 | if(result.output.indexOf("ANDROID_HOME") === -1){ 120 | util.log("Missing environment variable ANDROID_HOME. The ANDROID_HOME variable must exist and should point to your android SDK directory."); 121 | return false; 122 | } 123 | }else{ 124 | if( (result.output.length < 2) ) { 125 | util.log("Missing environment variable ANDROID_HOME. The ANDROID_HOME variable must exist and should point to your android SDK directory."); 126 | return false; 127 | } 128 | } 129 | 130 | command = (util.inWindows) ? "javac -help" : "which javac"; 131 | result = this._cmd.exec(command, options); 132 | if(result.code !== 0){ 133 | util.log("The command `javac` failed. Download the latest JDK at http://www.oracle.com/technetwork/java/javase/downloads/index.html"); 134 | return false; 135 | } 136 | 137 | return true; 138 | }; 139 | 140 | CordovaPlugin.prototype.installiOSWebViewPlus = function(plugin){ 141 | util.log("Installing '" + plugin.bundle_id + "' in your project."); 142 | var plugin_result = this._cmd.exec("plugin add " + plugin.bundle_id); 143 | if(plugin_result.code !== 0) { 144 | util.errorLog("Cannot install " + plugin.bundle_id + ", failed to execute the command `cocoonjs plugin add " + plugin.bundle_id + "`. "); 145 | console.error(plugin_result.output); 146 | process.exit(plugin_result.code); 147 | } 148 | 149 | var project_path = process.cwd(); 150 | var project_plugins_path = path.join( project_path, "plugins"); 151 | var plugin_path = path.join( project_plugins_path, plugin.plugin_id); 152 | var hook_path = path.join( plugin_path, "ios", "hooks", "install.js"); 153 | 154 | if( fs.existsSync(hook_path) ){ 155 | var CustomHook = require(hook_path); 156 | new CustomHook(project_path, this._cmd); 157 | } 158 | }; 159 | 160 | CordovaPlugin.prototype.uninstalliOSWebViewPlus = function(plugin){ 161 | util.log("Uninstalling '" + plugin.bundle_id + "'"); 162 | 163 | var project_path = process.cwd(); 164 | var project_plugins_path = path.join( project_path, "plugins"); 165 | var plugin_path = path.join( project_plugins_path, plugin.plugin_id); 166 | var hook_path = path.join( plugin_path, "ios", "hooks", "uninstall.js"); 167 | 168 | if( fs.existsSync(hook_path) ){ 169 | var CustomHook = require(hook_path); 170 | new CustomHook(project_path); 171 | } 172 | 173 | var plugin_result = this._cmd.exec("plugin rm " + plugin.plugin_id); 174 | if(plugin_result.code !== 0) { 175 | util.errorLog("Cannot uninstall " + plugin.bundle_id + ", failed to execute the command `cocoonjs plugin rm " + plugin.bundle_id + "`. "); 176 | console.error(plugin_result.output); 177 | process.exit(plugin_result.code); 178 | } 179 | 180 | }; 181 | 182 | CordovaPlugin.prototype.removeAndroidWebViewPlus = function(plugin){ 183 | 184 | var plugin_id = plugin.plugin_id; 185 | var plugin_path = path.join(process.cwd(), "plugins", plugin_id, "android"); 186 | var project_hooks_path = this.getHooksPath(); 187 | var hook_path = path.join(project_hooks_path, "after_plugin_rm", plugin_id + ".js"); 188 | var hook_installation_path = path.join(project_hooks_path, "after_plugin_add", plugin_id + ".js"); 189 | var platforms = this.getPlatforms(); 190 | var isAndroidAvailable = platforms.filter(function(platform_name){ return platform_name === "android" }); 191 | 192 | if( (isAndroidAvailable.length === 0) ){ 193 | util.errorLog("The platform Android is not available in your project."); 194 | process.exit(1); 195 | } 196 | 197 | if( !this.WebViewPlusReq(plugin_path) ){ 198 | process.exit(1); 199 | } 200 | 201 | if(!fs.existsSync(hook_path)){ 202 | util.errorLog("Can't find uninstall hook."); 203 | process.exit(1); 204 | } 205 | 206 | var exec_result = this.executeHook(plugin_path, hook_path); 207 | if( exec_result.code !== 0){ 208 | util.errorLog("Error executing Webview+ hook", hook_path); 209 | console.error(exec_result.output); 210 | return false; 211 | } 212 | 213 | var plugin_result = this._cmd.exec("plugin rm " + plugin_id); 214 | if(plugin_result.code !== 0){ 215 | util.errorLog("Cannot uninstall the Webview+, failed to execute the command `cocoonjs plugin rm " + plugin_id + "`."); 216 | util.errorLog(plugin_result.output); 217 | process.exit(plugin_result.code); 218 | } 219 | 220 | try{ 221 | fs.unlinkSync(hook_path); 222 | fs.unlinkSync(hook_installation_path); 223 | }catch(e){ 224 | util.errorLog("Cannot delete Webview+ hooks, please remove them manually:"); 225 | util.errorLog(hook_path, hook_installation_path); 226 | console.error(e); 227 | } 228 | 229 | util.log("Webview+ uninstalled correctly"); 230 | process.exit(exec_result.code); 231 | }; 232 | 233 | CordovaPlugin.prototype.installAndroidWebViewPlus = function(plugin){ 234 | 235 | util.log("Installing Webview+ in your Cordova Project."); 236 | 237 | var plugin_id = plugin.plugin_id; 238 | var platforms = this.getPlatforms(); 239 | var plugin_path = path.join(process.cwd(), "plugins", plugin_id, "android"); 240 | var isAndroidAvailable = platforms.filter(function(platform_name){ return platform_name === "android" }); 241 | 242 | if( (isAndroidAvailable.length === 0) ){ 243 | util.errorLog("The platform Android is not available in your project. Please execute 'cocoonjs platform add android' before installing the Webview+"); 244 | process.exit(1); 245 | } 246 | 247 | if( !this.WebViewPlusReq(plugin_path) ){ 248 | process.exit(1); 249 | } 250 | 251 | if(this._argv['plugins-path']){ 252 | plugin.bundle_id = path.join(this._argv['plugins-path'] , plugin.plugin_id); 253 | } 254 | util.log("Downloading Webview+..."); 255 | var plugin_result = this._cmd.exec("plugin add " + plugin.bundle_id); 256 | if(plugin_result.code !== 0) { 257 | util.errorLog("Cannot install the WebView+ in your project, failed to execute the command `cocoonjs plugin add " + plugin.bundle_id + "`. "); 258 | console.error(plugin_result.output); 259 | process.exit(plugin_result.code); 260 | } 261 | 262 | var hooks_path = path.join(plugin_path, 'hooks'); 263 | var build_xml_path = path.join(plugin_path, "build.xml"); 264 | 265 | if(!fileExists(build_xml_path)) { 266 | util.errorLog("Can't find a build.xml needed to build the WebView+ project"); 267 | process.exit(1); 268 | } 269 | 270 | var installed_hooks = this.installHooks(hooks_path); 271 | if( !installed_hooks ){ 272 | util.errorLog("Cannot install needed hook in your project"); 273 | process.exit(1); 274 | } 275 | 276 | util.log("Executing 'ant release -buildfile " + build_xml_path + "'"); 277 | var release_result = this._cmd.exec("ant release -buildfile " + build_xml_path, { avoidCordovaCMD : true }); 278 | 279 | if(release_result.code !== 0) { 280 | util.errorLog("Cannot build Webview+ project"); 281 | process.exit(release_result.code); 282 | } 283 | 284 | var hook_path = ""; 285 | for (var i = 0; i < installed_hooks.length; i++) { 286 | var hook_info = installed_hooks[i]; 287 | if(hook_info.folder === "after_plugin_add"){ 288 | hook_path = hook_info.full_path; 289 | } 290 | } 291 | 292 | if(!hook_path){ 293 | util.errorLog("Cannot find a valid Webview+ hook to be executed."); 294 | process.exit(1); 295 | } 296 | 297 | var installation_result = this.executeHook(plugin_path, hook_path); 298 | if( installation_result.code !== 0){ 299 | util.errorLog("Error executing Webview+ hook", hook_path); 300 | util.errorLog("here's the error info we have"); 301 | this._cmd.exec("plugin rm " + plugin_id); 302 | console.error(installation_result.output); 303 | return false; 304 | } 305 | 306 | util.log("The Webview+ has been installed correctly in your Cordova project :)"); 307 | process.exit(0); 308 | }; 309 | 310 | CordovaPlugin.prototype.installHooks = function(hooks_path){ 311 | if(!fileExists(hooks_path)) return false; 312 | 313 | var files = fs.readdirSync(hooks_path); 314 | var project_hooks_path = this.getHooksPath(); 315 | var installed_hooks = []; 316 | 317 | if(!project_hooks_path) return false; 318 | 319 | for (var i = 0; i < files.length; i++) { 320 | var file = files[i]; 321 | var full_path = path.join(hooks_path , file); 322 | var stats = fs.statSync(full_path); 323 | if( stats.isDirectory() ){ 324 | var hook_name = file; 325 | var hook_list = fs.readdirSync(full_path); 326 | for (var x = 0; x < hook_list.length; x++) { 327 | var js_file = hook_list[x]; 328 | if(path.extname(js_file) === ".js"){ 329 | var installation_path = path.join(project_hooks_path, hook_name); 330 | if( !fileExists(installation_path) ){ 331 | shell.mkdir('-p', installation_path); 332 | } 333 | var hook_dest = path.join(installation_path, js_file); 334 | installed_hooks.push({ folder : hook_name, file_name : js_file, full_path : hook_dest }); 335 | fs.renameSync( path.join(full_path, js_file) , hook_dest); 336 | shell.chmod("+x", hook_dest); 337 | } 338 | } 339 | } 340 | } 341 | 342 | return installed_hooks; 343 | }; 344 | 345 | CordovaPlugin.prototype.getPlatforms = function(){ 346 | var platforms_path = path.join(process.cwd(), "platforms"); 347 | return fs.readdirSync(platforms_path); 348 | }; 349 | 350 | CordovaPlugin.prototype.getHooksPath = function(){ 351 | var project_path = process.cwd(); 352 | 353 | var possible_path = path.join(project_path,".cordova"); 354 | if( fileExists( possible_path ) ) return possible_path; 355 | 356 | possible_path = path.join(project_path,"hooks"); 357 | if( fileExists( possible_path ) ) return possible_path; 358 | 359 | }; 360 | 361 | CordovaPlugin.prototype.executeHook = function(plugin_path, hook_path){ 362 | 363 | var CORDOVA_CMD_PATH = this._cmd.getCmdBinaryPath(); 364 | var CORDOVA_VERSION = util.getCordovaVersion(this._cmd); 365 | var CORDOVA_PROJECT_NAME = this._config_xml.widget.name.toString(); 366 | var CORDOVA_PLUGIN_PATH = plugin_path; 367 | 368 | var env_vars = ""; 369 | if(util.inWindows){ 370 | env_vars += ("set CORDOVA_PATH_BINARY='" + new Buffer(CORDOVA_CMD_PATH).toString('base64') +"' & "); 371 | env_vars += ("set CORDOVA_CUSTOM_VERSION='" + new Buffer(CORDOVA_VERSION).toString('base64') +"' & "); 372 | env_vars += ("set CORDOVA_PROJECT_NAME='" + new Buffer(CORDOVA_PROJECT_NAME).toString('base64') +"' & "); 373 | env_vars += ("set CORDOVA_PLUGIN_PATH='" + new Buffer(CORDOVA_PLUGIN_PATH).toString('base64') +"' & "); 374 | }else{ 375 | env_vars += ("export CORDOVA_PATH_BINARY='" + new Buffer(CORDOVA_CMD_PATH).toString('base64') +"' && "); 376 | env_vars += ("export CORDOVA_CUSTOM_VERSION='" + new Buffer(CORDOVA_VERSION).toString('base64') +"' && "); 377 | env_vars += ("export CORDOVA_PROJECT_NAME='" + new Buffer(CORDOVA_PROJECT_NAME).toString('base64') +"' && "); 378 | env_vars += ("export CORDOVA_PLUGIN_PATH='" + new Buffer(CORDOVA_PLUGIN_PATH).toString('base64') +"' && "); 379 | } 380 | 381 | var results = this._cmd.exec("node " + hook_path, { env: env_vars, avoidCordovaCMD : true }); 382 | if(results.code !== 0){ 383 | return results; 384 | } 385 | 386 | return results; 387 | }; 388 | 389 | module.exports = CordovaPlugin; -------------------------------------------------------------------------------- /src/lib/cordova/serve.js: -------------------------------------------------------------------------------- 1 | var shell = require('shelljs'), 2 | util = require('../../utils.js'); 3 | 4 | function ServeCommand(cmd, command) { 5 | util.log("Executing command '" + command + "'"); 6 | cmd.execAsync(command, { 7 | events : { 8 | stdout : function(data){ 9 | util.log(data); 10 | }, 11 | stderr : function(data){ 12 | util.log(data); 13 | }, 14 | exit : function(status){ 15 | process.exit(status); 16 | } 17 | } 18 | }); 19 | } 20 | 21 | module.exports = ServeCommand; -------------------------------------------------------------------------------- /src/ludei_platforms.json: -------------------------------------------------------------------------------- 1 | [ { "name" : "samsung-smarttv" } ] -------------------------------------------------------------------------------- /src/ludei_plugins.json: -------------------------------------------------------------------------------- 1 | { 2 | "plugins" : [ 3 | { "plugin_id" : "com.ludei.webview.plus", "bundle_id" : "com.ludei.webview.plus"}, 4 | { "plugin_id" : "com.ludei.ios.webview.plus", "bundle_id" : "com.ludei.ios.webview.plus"} 5 | ] 6 | } -------------------------------------------------------------------------------- /src/utils.js: -------------------------------------------------------------------------------- 1 | var colors = require('colors'), 2 | path = require('path'), 3 | fs = require('fs'), 4 | os = require('os'), 5 | xml2js = require('xml2js'); 6 | 7 | var fileExists = fs.existsSync; 8 | // wtf javascript you are drunked 9 | String.prototype.replaceAll = function (find, replace) { 10 | var str = this; 11 | return str.replace(new RegExp(find.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'), 'g'), replace); 12 | }; 13 | (function(){ 14 | 15 | /** 16 | * The "exported" object, this object holds all the "utils" functionalities 17 | */ 18 | var utils = {}; 19 | 20 | /** 21 | * Property with the running operating system. 22 | */ 23 | utils.OPERATING_SYSTEM = os.type(); 24 | utils.inWindows = (os.platform() === 'win32'); 25 | utils.TAG = ("[" + ("Cocoon") + "] ").cyan; 26 | utils.TAG_ERROR = ("[" + ("Cocoon") + "] ").yellow; 27 | 28 | /** 29 | * Creates a valid path depending on the platform 30 | */ 31 | utils.getPath = function(filepath){ 32 | if(utils.inWindows){ 33 | return filepath.replaceAll('/', path.sep); 34 | }else{ 35 | return filepath; 36 | } 37 | }; 38 | 39 | /** 40 | * Check if this platform is ready to handle Cordova compilations 41 | */ 42 | utils.isCordovaAvailable = function (cmd) { 43 | var exec = cmd.exec(" --version"); 44 | if(exec.code === 0){ 45 | return exec; 46 | }else{ 47 | return false; 48 | } 49 | }; 50 | 51 | utils.getConfigXML = function(callback){ 52 | var project_path = process.cwd(); 53 | var config_path = path.join(project_path, "config.xml"); 54 | var parser = new xml2js.Parser(); 55 | var data; 56 | 57 | if( fileExists(config_path) ){ 58 | data = fs.readFileSync(config_path).toString('UTF-8'); 59 | parser.parseString(data, callback); 60 | return; 61 | } 62 | 63 | config_path = path.join(project_path, "www","config.xml"); 64 | if( fileExists(config_path) ){ 65 | data = fs.readFileSync(config_path).toString('UTF-8'); 66 | parser.parseString(data, callback); 67 | return; 68 | } 69 | 70 | return callback(false); 71 | }; 72 | 73 | /** 74 | * Checks if this platform ready to manage cordova compilations, also returns 75 | * the cordova version. 76 | */ 77 | utils.getCordovaVersion = function(cmd){ 78 | var isAvailable = utils.isCordovaAvailable(cmd); 79 | if(isAvailable){ 80 | return isAvailable.output.replace(/(\r\n|\n|\r)/gm,""); 81 | }else{ 82 | return false; 83 | } 84 | }; 85 | /** 86 | * Prints a help file. 87 | * @param filename 88 | * @returns {*} 89 | */ 90 | utils.printHelpInfo = function(filename){ 91 | var help = path.join(__dirname, "/help", (filename) ? filename : "help.txt" ); 92 | return console.log( fs.readFileSync( help ).toString() ); 93 | }; 94 | 95 | /** 96 | * Basic extends functionality for JS 97 | * @returns {*} 98 | */ 99 | utils.extend = function(){ 100 | for(var i=1; i 0 && new RegExp(/\\n/).test(JSON.stringify(args[args.length - 1]))){ 114 | args = args.substring(0, args.length - 1); 115 | } 116 | args = args.replace('`cordova','`cocoonjs'); 117 | console.log(utils.TAG + args); 118 | }; 119 | 120 | utils.getPlatforms = function(){ 121 | var platforms_path = path.join( process.cwd(), "platforms" ); 122 | var platforms = []; 123 | 124 | if( fs.existsSync(platforms_path) ){ 125 | var dir_content = fs.readdirSync(platforms_path); 126 | for (var i = 0; i < dir_content.length; i++) { 127 | var stat = fs.statSync( path.join( platforms_path, dir_content[i]) ); 128 | if(stat.isDirectory()){ 129 | platforms.push(dir_content[i]); 130 | platforms[dir_content[i]] = true; 131 | } 132 | } 133 | } 134 | 135 | return platforms; 136 | }; 137 | 138 | utils.getCordovaCMD = function(argv){ 139 | var path = (utils.inWindows) ? "cordova.cmd" : "cordova"; 140 | 141 | if(!argv['cordova-path']) return path; 142 | 143 | var path_info = fs.lstatSync(argv['cordova-path']); 144 | var bin_path = argv['cordova-path'] + "/bin/cordova"; 145 | if( path_info.isDirectory() && fs.existsSync(bin_path) ){ 146 | path = "node " + bin_path; 147 | }else{ 148 | path = "node " + argv['cordova-path']; 149 | } 150 | 151 | return path; 152 | }; 153 | 154 | utils.errorLog = function(){ 155 | var args = Array.prototype.slice.call(arguments).join(" "); 156 | if(args.length > 0 && new RegExp(/\\n/).test(JSON.stringify(args[args.length - 1]))){ 157 | args = args.substring(0, args.length - 1); 158 | } 159 | args = args.replace('`cordova','`cocoonjs'); 160 | console.error(utils.TAG_ERROR + (args.red)); 161 | }; 162 | 163 | utils.cleanUpArguments = function(CMD_ARGS){ 164 | for (var i = 0; i < CMD_ARGS.length; i++){ 165 | if(CMD_ARGS[i].indexOf("--cordova-path") !== -1) { 166 | CMD_ARGS.splice(i, 1); 167 | continue; 168 | } 169 | if(CMD_ARGS[i].indexOf("--plugins-path") !== -1) { 170 | CMD_ARGS.splice(i, 1); 171 | continue; 172 | } 173 | if(CMD_ARGS[i] === "cloud") { 174 | CMD_ARGS.splice(i, 1); 175 | // continue; is unnecessary as the last statement in a loop 176 | } 177 | } 178 | return CMD_ARGS; 179 | }; 180 | 181 | module.exports = utils; 182 | })(); -------------------------------------------------------------------------------- /test.js: -------------------------------------------------------------------------------- 1 | var gulp = require('gulp'); 2 | var webserver = require('gulp-webserver'); 3 | 4 | gulp.task('webserver', function() { 5 | gulp.src('/Users/karliky/Documents/ludei/engines/cordova/projects/livereload/') 6 | .pipe(webserver({ 7 | livereload: true, 8 | directoryListing: true 9 | })); 10 | }); --------------------------------------------------------------------------------