blob: f9457cf260ea5096770f8a3622d43a09d2b0e101 [file] [log] [blame]
#!/usr/bin/env node
////////////////////////////////////////////////////////////////////////////////
//
// Licensed to the Apache Software Foundation (ASF) under one or more
// contributor license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright ownership.
// The ASF licenses this file to You under the Apache License, Version 2.0
// (the "License"); you may not use this file except in compliance with
// the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
////////////////////////////////////////////////////////////////////////////////
var fs = require('fs-extra');
var path = require('path');
var execSync = require('child_process').execSync;
var spawn = require('child_process').spawn;
var fork = require('child_process').fork;
var releaseServer=require('node-http-server');
var chokidar = require('chokidar');
var open = require("open");
var livereload = require('livereload');
var args = require('yargs')
.usage('Usage: royale <command>')
.example('royale new my-royale-project', 'Creates a new Apache Royale project in the my-royale-project directory')
.example('royale serve:debug', 'Builds debug version and starts server on http://localhost:3000; also watches the ' +
'my-royale-project/src directory for changes')
.example('royale serve:release', 'Builds release version and starts server on http://localhost:3001')
.help('h')
.alias('h', 'help')
.epilog('Email: users@royale.apache.org | Github: https://github.com/apache/royale-asjs')
.argv;
const CREATE_NEW_PROJECT = 'new';
const DEFAULT_PROJECT_NAME = 'my-royale-project';
const SERVE_DEBUG = 'serve:debug';
const DEBUG_PORT = 3000;
const SERVE_RELEASE = 'serve:release';
const RELEASE_PORT = 3001;
const SOURCE_DIR_NAME = 'src';
const APP_START_FILE_NAME = 'Main.mxml';
var command = args._[0];
if(!args.help && !args.h) {
switch (command) {
case CREATE_NEW_PROJECT: {
createNewProject();
break;
}
case SERVE_DEBUG: {
serveDebug();
break;
}
case SERVE_RELEASE: {
serveRelease();
break;
}
default: {
console.log('Unknown command. Use -h option for help')
}
}
}
function createNewProject() {
//Get project name. If project name is missing, use a default one
var projectName = args._[1] || DEFAULT_PROJECT_NAME;
//Copy template project; create directories automatically
var projectPath = path.join(process.cwd(), projectName);
try {
fs.copySync(path.join(__dirname, 'template'), projectPath);
console.log('Successfully created new Apache Royale project: %s', projectName);
} catch (err) {
console.error(err)
}
}
function serveDebug() {
compileDebug();
startDebugServer();
startWatchingSourceFiles();
}
//Compile project in debug mode
function compileDebug() {
var command = 'mxmlc ' + path.join(process.cwd(), SOURCE_DIR_NAME , APP_START_FILE_NAME) + ' -debug=true';
console.log('Compiling...');
try {
execSync(command);
console.log('Finished compiling');
}
catch(e) {
console.error(e.message);
}
finally {
reloadBrowser();
updateIndex();
}
}
var debugServerRunning = false;
var connectServer;
// Start debug server if it is not already running
function startDebugServer() {
if(!debugServerRunning) {
var command = 'node ' + path.join(__dirname, 'connect.js');
console.log('Starting server on http://localhost:%s...', DEBUG_PORT);
connectServer = fork(path.join(__dirname, 'connect.js'));
openBrowser('http://localhost:' + DEBUG_PORT);
}
}
//Inject reload script into index.html
function updateIndex() {
var debugDirPath = path.join(process.cwd(), 'bin', 'js-debug');
var indexHTML = fs.readFileSync(path.join(debugDirPath, 'index.html'), 'utf8');
indexHTML = indexHTML.replace('</html>', '<script src="http://localhost:35729/livereload.js?snipver=1"></script></html>')
fs.writeFile(path.join(debugDirPath, 'index.html'), indexHTML);
}
var watchingFiles = false;
var watcher;
//Watch source files, trigger debug compilation when anything changes
//Note: we are not checking for file adds, since that causes multiple compilations
function startWatchingSourceFiles() {
if(!watchingFiles) {
watchingFiles = true;
//Watch the SOURCE_DIR_NAME directory, recompile if anything changes
var pathToWatch = path.join(process.cwd(), SOURCE_DIR_NAME);
console.log('Watching the directory %s for changes...', pathToWatch);
watcher = chokidar.watch(pathToWatch)
.on('change',
function(path){
console.log('Change detected... %s', path);
compileDebug();
}
);
}
}
//Send message to Connect server to make it send a refresh command to browser
function reloadBrowser() {
if(connectServer) {
connectServer.send({ message: 'reload' });
}
}
var browserOpened = false;
function openBrowser(url) {
if(!browserOpened) {
browserOpened = true;
console.log('Launching browser: ', url);
open(url);
}
}
function serveRelease() {
compileRelease();
startReleaseServer();
}
//Compile project in release mode
function compileRelease() {
//Compile project in release mode
var command = 'mxmlc ' + path.join(process.cwd(), SOURCE_DIR_NAME , APP_START_FILE_NAME) + ' -debug=false';
console.log('Compiling release build...');
execSync(command);
console.log('Finished compiling');
}
var releaseServerRunning = false;
// Start release server
// after server is ready, launch browser
function startReleaseServer() {
if(!releaseServerRunning) {
releaseServer.deploy(
{
port: RELEASE_PORT,
root: path.join(process.cwd(), 'bin', 'js-release')
},
handleReleaseServerReady
);
}
}
function handleReleaseServerReady() {
releaseServerRunning = true;
console.log('Your app (release version) is running on localhost:%s', RELEASE_PORT);
open('http://localhost:' + RELEASE_PORT);
}