Repositorio del curso CCOM4030 el semestre B91 del proyecto Artesanías con el Instituto de Cultura

create.js 16KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362
  1. #!/usr/bin/env node
  2. /*
  3. Licensed to the Apache Software Foundation (ASF) under one
  4. or more contributor license agreements. See the NOTICE file
  5. distributed with this work for additional information
  6. regarding copyright ownership. The ASF licenses this file
  7. to you under the Apache License, Version 2.0 (the
  8. "License"); you may not use this file except in compliance
  9. with the License. You may obtain a copy of the License at
  10. http://www.apache.org/licenses/LICENSE-2.0
  11. Unless required by applicable law or agreed to in writing,
  12. software distributed under the License is distributed on an
  13. "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  14. KIND, either express or implied. See the License for the
  15. specific language governing permissions and limitations
  16. under the License.
  17. */
  18. var shell = require('shelljs');
  19. var Q = require('q');
  20. var path = require('path');
  21. var fs = require('fs');
  22. var check_reqs = require('./../templates/cordova/lib/check_reqs');
  23. var ROOT = path.join(__dirname, '..', '..');
  24. var CordovaError = require('cordova-common').CordovaError;
  25. var AndroidManifest = require('../templates/cordova/lib/AndroidManifest');
  26. // Export all helper functions, and make sure internally within this module, we
  27. // reference these methods via the `exports` object - this helps with testing
  28. // (since we can then mock and control behaviour of all of these functions)
  29. exports.validatePackageName = validatePackageName;
  30. exports.validateProjectName = validateProjectName;
  31. exports.setShellFatal = setShellFatal;
  32. exports.copyJsAndLibrary = copyJsAndLibrary;
  33. exports.copyScripts = copyScripts;
  34. exports.copyBuildRules = copyBuildRules;
  35. exports.writeProjectProperties = writeProjectProperties;
  36. exports.prepBuildFiles = prepBuildFiles;
  37. function setShellFatal (value, func) {
  38. var oldVal = shell.config.fatal;
  39. shell.config.fatal = value;
  40. func();
  41. shell.config.fatal = oldVal;
  42. }
  43. function getFrameworkDir (projectPath, shared) {
  44. return shared ? path.join(ROOT, 'framework') : path.join(projectPath, 'CordovaLib');
  45. }
  46. function copyJsAndLibrary (projectPath, shared, projectName, isLegacy) {
  47. var nestedCordovaLibPath = getFrameworkDir(projectPath, false);
  48. var srcCordovaJsPath = path.join(ROOT, 'bin', 'templates', 'project', 'assets', 'www', 'cordova.js');
  49. var app_path = path.join(projectPath, 'app', 'src', 'main');
  50. if (isLegacy) {
  51. app_path = projectPath;
  52. }
  53. shell.cp('-f', srcCordovaJsPath, path.join(app_path, 'assets', 'www', 'cordova.js'));
  54. // Copy the cordova.js file to platforms/<platform>/platform_www/
  55. // The www dir is nuked on each prepare so we keep cordova.js in platform_www
  56. shell.mkdir('-p', path.join(projectPath, 'platform_www'));
  57. shell.cp('-f', srcCordovaJsPath, path.join(projectPath, 'platform_www'));
  58. // Copy cordova-js-src directory into platform_www directory.
  59. // We need these files to build cordova.js if using browserify method.
  60. shell.cp('-rf', path.join(ROOT, 'cordova-js-src'), path.join(projectPath, 'platform_www'));
  61. // Don't fail if there are no old jars.
  62. exports.setShellFatal(false, function () {
  63. shell.ls(path.join(app_path, 'libs', 'cordova-*.jar')).forEach(function (oldJar) {
  64. console.log('Deleting ' + oldJar);
  65. shell.rm('-f', oldJar);
  66. });
  67. var wasSymlink = true;
  68. try {
  69. // Delete the symlink if it was one.
  70. fs.unlinkSync(nestedCordovaLibPath);
  71. } catch (e) {
  72. wasSymlink = false;
  73. }
  74. // Delete old library project if it existed.
  75. if (shared) {
  76. shell.rm('-rf', nestedCordovaLibPath);
  77. } else if (!wasSymlink) {
  78. // Delete only the src, since Eclipse / Android Studio can't handle their project files being deleted.
  79. shell.rm('-rf', path.join(nestedCordovaLibPath, 'src'));
  80. }
  81. });
  82. if (shared) {
  83. var relativeFrameworkPath = path.relative(projectPath, getFrameworkDir(projectPath, true));
  84. fs.symlinkSync(relativeFrameworkPath, nestedCordovaLibPath, 'dir');
  85. } else {
  86. shell.mkdir('-p', nestedCordovaLibPath);
  87. shell.cp('-f', path.join(ROOT, 'framework', 'AndroidManifest.xml'), nestedCordovaLibPath);
  88. shell.cp('-f', path.join(ROOT, 'framework', 'project.properties'), nestedCordovaLibPath);
  89. shell.cp('-f', path.join(ROOT, 'framework', 'build.gradle'), nestedCordovaLibPath);
  90. shell.cp('-f', path.join(ROOT, 'framework', 'cordova.gradle'), nestedCordovaLibPath);
  91. shell.cp('-r', path.join(ROOT, 'framework', 'src'), nestedCordovaLibPath);
  92. }
  93. }
  94. function extractSubProjectPaths (data) {
  95. var ret = {};
  96. var r = /^\s*android\.library\.reference\.\d+=(.*)(?:\s|$)/mg;
  97. var m;
  98. while ((m = r.exec(data))) {
  99. ret[m[1]] = 1;
  100. }
  101. return Object.keys(ret);
  102. }
  103. function writeProjectProperties (projectPath, target_api) {
  104. var dstPath = path.join(projectPath, 'project.properties');
  105. var templatePath = path.join(ROOT, 'bin', 'templates', 'project', 'project.properties');
  106. var srcPath = fs.existsSync(dstPath) ? dstPath : templatePath;
  107. var data = fs.readFileSync(srcPath, 'utf8');
  108. data = data.replace(/^target=.*/m, 'target=' + target_api);
  109. var subProjects = extractSubProjectPaths(data);
  110. subProjects = subProjects.filter(function (p) {
  111. return !(/^CordovaLib$/m.exec(p) ||
  112. /[\\/]cordova-android[\\/]framework$/m.exec(p) ||
  113. /^(\.\.[\\/])+framework$/m.exec(p));
  114. });
  115. subProjects.unshift('CordovaLib');
  116. data = data.replace(/^\s*android\.library\.reference\.\d+=.*\n/mg, '');
  117. if (!/\n$/.exec(data)) {
  118. data += '\n';
  119. }
  120. for (var i = 0; i < subProjects.length; ++i) {
  121. data += 'android.library.reference.' + (i + 1) + '=' + subProjects[i] + '\n';
  122. }
  123. fs.writeFileSync(dstPath, data);
  124. }
  125. // This makes no sense, what if you're building with a different build system?
  126. function prepBuildFiles (projectPath) {
  127. var buildModule = require('../templates/cordova/lib/builders/builders');
  128. buildModule.getBuilder(projectPath).prepBuildFiles();
  129. }
  130. function copyBuildRules (projectPath, isLegacy) {
  131. var srcDir = path.join(ROOT, 'bin', 'templates', 'project');
  132. if (isLegacy) {
  133. // The project's build.gradle is identical to the earlier build.gradle, so it should still work
  134. shell.cp('-f', path.join(srcDir, 'legacy', 'build.gradle'), projectPath);
  135. shell.cp('-f', path.join(srcDir, 'wrapper.gradle'), projectPath);
  136. } else {
  137. shell.cp('-f', path.join(srcDir, 'build.gradle'), projectPath);
  138. shell.cp('-f', path.join(srcDir, 'app', 'build.gradle'), path.join(projectPath, 'app'));
  139. shell.cp('-f', path.join(srcDir, 'wrapper.gradle'), projectPath);
  140. }
  141. }
  142. function copyScripts (projectPath) {
  143. var bin = path.join(ROOT, 'bin');
  144. var srcScriptsDir = path.join(bin, 'templates', 'cordova');
  145. var destScriptsDir = path.join(projectPath, 'cordova');
  146. // Delete old scripts directory if this is an update.
  147. shell.rm('-rf', destScriptsDir);
  148. // Copy in the new ones.
  149. shell.cp('-r', srcScriptsDir, projectPath);
  150. let nodeModulesDir = path.join(ROOT, 'node_modules');
  151. if (fs.existsSync(nodeModulesDir)) shell.cp('-r', nodeModulesDir, destScriptsDir);
  152. shell.cp(path.join(bin, 'check_reqs*'), destScriptsDir);
  153. shell.cp(path.join(bin, 'android_sdk_version*'), destScriptsDir);
  154. var check_reqs = path.join(destScriptsDir, 'check_reqs');
  155. var android_sdk_version = path.join(destScriptsDir, 'android_sdk_version');
  156. // TODO: the two files being edited on-the-fly here are shared between
  157. // platform and project-level commands. the below `sed` is updating the
  158. // `require` path for the two libraries. if there's a better way to share
  159. // modules across both the repo and generated projects, we should make sure
  160. // to remove/update this.
  161. shell.sed('-i', /templates\/cordova\//, '', android_sdk_version);
  162. shell.sed('-i', /templates\/cordova\//, '', check_reqs);
  163. }
  164. /**
  165. * Test whether a package name is acceptable for use as an android project.
  166. * Returns a promise, fulfilled if the package name is acceptable; rejected
  167. * otherwise.
  168. */
  169. function validatePackageName (package_name) {
  170. // Make the package conform to Java package types
  171. // http://developer.android.com/guide/topics/manifest/manifest-element.html#package
  172. // Enforce underscore limitation
  173. var msg = 'Error validating package name. ';
  174. if (!/^[a-zA-Z][a-zA-Z0-9_]+(\.[a-zA-Z][a-zA-Z0-9_]*)+$/.test(package_name)) {
  175. return Q.reject(new CordovaError(msg + 'Must look like: `com.company.Name`. Currently is: `' + package_name + '`'));
  176. }
  177. // Class is a reserved word
  178. if (/\b[Cc]lass\b/.test(package_name)) {
  179. return Q.reject(new CordovaError(msg + '"class" is a reserved word'));
  180. }
  181. return Q.resolve();
  182. }
  183. /**
  184. * Test whether a project name is acceptable for use as an android class.
  185. * Returns a promise, fulfilled if the project name is acceptable; rejected
  186. * otherwise.
  187. */
  188. function validateProjectName (project_name) {
  189. var msg = 'Error validating project name. ';
  190. // Make sure there's something there
  191. if (project_name === '') {
  192. return Q.reject(new CordovaError(msg + 'Project name cannot be empty'));
  193. }
  194. // Enforce stupid name error
  195. if (project_name === 'CordovaActivity') {
  196. return Q.reject(new CordovaError(msg + 'Project name cannot be CordovaActivity'));
  197. }
  198. // Classes in Java don't begin with numbers
  199. if (/^[0-9]/.test(project_name)) {
  200. return Q.reject(new CordovaError(msg + 'Project name must not begin with a number'));
  201. }
  202. return Q.resolve();
  203. }
  204. /**
  205. * Creates an android application with the given options.
  206. *
  207. * @param {String} project_path Path to the new Cordova android project.
  208. * @param {ConfigParser} config Instance of ConfigParser to retrieve basic
  209. * project properties.
  210. * @param {Object} [options={}] Various options
  211. * @param {String} [options.activityName='MainActivity'] Name for the
  212. * activity
  213. * @param {Boolean} [options.link=false] Specifies whether javascript files
  214. * and CordovaLib framework will be symlinked to created application.
  215. * @param {String} [options.customTemplate] Path to project template
  216. * (override)
  217. * @param {EventEmitter} [events] An EventEmitter instance for logging
  218. * events
  219. *
  220. * @return {Promise<String>} Directory where application has been created
  221. */
  222. exports.create = function (project_path, config, options, events) {
  223. options = options || {};
  224. // Set default values for path, package and name
  225. project_path = path.relative(process.cwd(), (project_path || 'CordovaExample'));
  226. // Check if project already exists
  227. if (fs.existsSync(project_path)) {
  228. return Q.reject(new CordovaError('Project already exists! Delete and recreate'));
  229. }
  230. var package_name = config.android_packageName() || config.packageName() || 'my.cordova.project';
  231. var project_name = config.name() ?
  232. config.name().replace(/[^\w.]/g, '_') : 'CordovaExample';
  233. var safe_activity_name = config.android_activityName() || options.activityName || 'MainActivity';
  234. var target_api = check_reqs.get_target();
  235. // Make the package conform to Java package types
  236. return exports.validatePackageName(package_name)
  237. .then(function () {
  238. return exports.validateProjectName(project_name);
  239. }).then(function () {
  240. // Log the given values for the project
  241. events.emit('log', 'Creating Cordova project for the Android platform:');
  242. events.emit('log', '\tPath: ' + project_path);
  243. events.emit('log', '\tPackage: ' + package_name);
  244. events.emit('log', '\tName: ' + project_name);
  245. events.emit('log', '\tActivity: ' + safe_activity_name);
  246. events.emit('log', '\tAndroid target: ' + target_api);
  247. events.emit('verbose', 'Copying android template project to ' + project_path);
  248. exports.setShellFatal(true, function () {
  249. var project_template_dir = options.customTemplate || path.join(ROOT, 'bin', 'templates', 'project');
  250. var app_path = path.join(project_path, 'app', 'src', 'main');
  251. // copy project template
  252. shell.mkdir('-p', app_path);
  253. shell.cp('-r', path.join(project_template_dir, 'assets'), app_path);
  254. shell.cp('-r', path.join(project_template_dir, 'res'), app_path);
  255. shell.cp(path.join(project_template_dir, 'gitignore'), path.join(project_path, '.gitignore'));
  256. // Manually create directories that would be empty within the template (since git doesn't track directories).
  257. shell.mkdir(path.join(app_path, 'libs'));
  258. // copy cordova.js, cordova.jar
  259. exports.copyJsAndLibrary(project_path, options.link, safe_activity_name);
  260. // Set up ther Android Studio paths
  261. var java_path = path.join(app_path, 'java');
  262. var assets_path = path.join(app_path, 'assets');
  263. var resource_path = path.join(app_path, 'res');
  264. shell.mkdir('-p', java_path);
  265. shell.mkdir('-p', assets_path);
  266. shell.mkdir('-p', resource_path);
  267. // interpolate the activity name and package
  268. var packagePath = package_name.replace(/\./g, path.sep);
  269. var activity_dir = path.join(java_path, packagePath);
  270. var activity_path = path.join(activity_dir, safe_activity_name + '.java');
  271. shell.mkdir('-p', activity_dir);
  272. shell.cp('-f', path.join(project_template_dir, 'Activity.java'), activity_path);
  273. shell.sed('-i', /__ACTIVITY__/, safe_activity_name, activity_path);
  274. shell.sed('-i', /__NAME__/, project_name, path.join(app_path, 'res', 'values', 'strings.xml'));
  275. shell.sed('-i', /__ID__/, package_name, activity_path);
  276. var manifest = new AndroidManifest(path.join(project_template_dir, 'AndroidManifest.xml'));
  277. manifest.setPackageId(package_name)
  278. .getActivity().setName(safe_activity_name);
  279. var manifest_path = path.join(app_path, 'AndroidManifest.xml');
  280. manifest.write(manifest_path);
  281. exports.copyScripts(project_path);
  282. exports.copyBuildRules(project_path);
  283. });
  284. // Link it to local android install.
  285. exports.writeProjectProperties(project_path, target_api);
  286. exports.prepBuildFiles(project_path);
  287. events.emit('log', generateDoneMessage('create', options.link));
  288. }).thenResolve(project_path);
  289. };
  290. function generateDoneMessage (type, link) {
  291. var pkg = require('../../package');
  292. var msg = 'Android project ' + (type === 'update' ? 'updated ' : 'created ') + 'with ' + pkg.name + '@' + pkg.version;
  293. if (link) {
  294. msg += ' and has a linked CordovaLib';
  295. }
  296. return msg;
  297. }
  298. // Returns a promise.
  299. exports.update = function (projectPath, options, events) {
  300. var errorString =
  301. 'An in-place platform update is not supported. \n' +
  302. 'The `platforms` folder is always treated as a build artifact in the CLI workflow.\n' +
  303. 'To update your platform, you have to remove, then add your android platform again.\n' +
  304. 'Make sure you save your plugins beforehand using `cordova plugin save`, and save \n' + 'a copy of the platform first if you had manual changes in it.\n' +
  305. '\tcordova plugin save\n' +
  306. '\tcordova platform rm android\n' +
  307. '\tcordova platform add android\n'
  308. ;
  309. return Q.reject(errorString);
  310. };