/ide/src/com/moonshineproject/plugin/actionscript/mxmlc/MXMLCPlugin.as
ActionScript | 488 lines | 400 code | 78 blank | 10 comment | 68 complexity | 2561f661ed663a35b17ee0668756a503 MD5 | raw file
Possible License(s): LGPL-3.0, MIT, Apache-2.0, GPL-3.0
- package com.moonshineproject.plugin.actionscript.mxmlc
- {
- import com.moonshineproject.IDEModel;
- import com.moonshineproject.plugin.IMenuPlugin;
- import com.moonshineproject.plugin.IPlugin;
- import com.moonshineproject.plugin.PluginBase;
- import com.moonshineproject.plugin.actionscript.as3project.vo.AS3ProjectVO;
- import com.moonshineproject.plugin.actionscript.swflauncher.event.SWFLaunchEvent;
- import com.moonshineproject.plugin.console.MarkupTextLineModel;
- import com.moonshineproject.plugin.core.compiler.CompilerEventBase;
- import com.moonshineproject.plugin.menu.vo.MenuItem;
- import com.moonshineproject.plugin.project.event.RefreshTreeEvent;
- import com.moonshineproject.plugin.project.vo.ProjectVO;
- import com.moonshineproject.plugin.settings.ISettingsProvider;
- import com.moonshineproject.plugin.settings.vo.BooleanSetting;
- import com.moonshineproject.plugin.settings.vo.ISetting;
- import com.moonshineproject.plugin.settings.vo.PathSetting;
- import com.moonshineproject.text.TextLineModel;
- import com.moonshineproject.utils.FileUtil;
- import com.moonshineproject.utils.HtmlFormatter;
- import com.moonshineproject.vo.Settings;
-
- import flash.desktop.NativeProcess;
- import flash.desktop.NativeProcessStartupInfo;
- import flash.events.Event;
- import flash.events.NativeProcessExitEvent;
- import flash.events.ProgressEvent;
- import flash.filesystem.File;
- import flash.ui.Keyboard;
- import flash.utils.Dictionary;
- import flash.utils.IDataInput;
- import flash.utils.IDataOutput;
-
- public class MXMLCPlugin extends PluginBase implements IPlugin, ISettingsProvider, IMenuPlugin
- {
- override public function get name():String { return "MXMLC Compiler Plugin"; }
- override public function get author():String { return "Miha Lunar & Moonshine Project Team"; }
- override public function get description():String { return "Compiles AS3 projects with MXMLC."; }
-
- public var defaultFlexSDK:String
- public var incrementalCompile:Boolean = true;
- protected var runAfterBuild:Boolean;
-
- private var fcshPath:String = "bin/fcsh";
- public function get flexSDK():File
- {
- return currentSDK;
- }
- private var fcsh:NativeProcess;
- private var exiting:Boolean = false;
- private var shellInfo:NativeProcessStartupInfo;
-
- private var lastTarget:File;
- private var targets:Dictionary;
- private var currentSDK:File = flexSDK;
-
- /** Project currently under compilation */
- private var currentProject:ProjectVO;
- private var queue:Vector.<String> = new Vector.<String>();
- private var errors:String = "";
-
- private var cmdLine:CommandLine;
- private var _instance:MXMLCPlugin;
-
- public function MXMLCPlugin()
- {
- if (Settings.os == "win") fcshPath += ".exe";
- }
-
- override public function activate():void
- {
- super.activate();
-
- dispatcher.addEventListener(CompilerEventBase.BUILD_AND_RUN, buildAndRun);
- dispatcher.addEventListener(CompilerEventBase.BUILD_AND_DEBUG, buildAndRun);
- dispatcher.addEventListener(CompilerEventBase.BUILD, build);
- dispatcher.addEventListener(CompilerEventBase.BUILD_RELEASE, buildRelease);
-
- registerCommand('build', buildCommand);
- registerCommand('run', runCommand);
- registerCommand('release', releaseCommand);
-
- // Get shell
- shellInfo = new NativeProcessStartupInfo();
- cmdLine = new CommandLine();
-
- reset();
- }
-
- override public function deactivate():void
- {
- super.deactivate();
-
- reset();
- shellInfo = null;
- cmdLine = null;
- }
-
- public function getSettingsList():Vector.<ISetting>
- {
- return Vector.<ISetting>([
- new PathSetting(this,'defaultFlexSDK', 'Default Flex SDK', true),
- new BooleanSetting(this,'incrementalCompile', 'Incremental Compilation')
- ])
- }
-
- public function getMenu():MenuItem
- {
- // Since plugin will be activated if needed we can return null to block menu
- if( !activated ) return null;
- return new MenuItem(
- "MXMLC",
- [
- new MenuItem("Build", null, CompilerEventBase.BUILD,
- 'b', [Keyboard.COMMAND],
- 'b', [Keyboard.CONTROL]),
- new MenuItem("Build & Run", null, CompilerEventBase.BUILD_AND_RUN,
- "\n", [Keyboard.COMMAND],
- "f8", []),
- new MenuItem("Build & Debug", null, CompilerEventBase.BUILD_AND_DEBUG,
- "\n", [Keyboard.COMMAND, Keyboard.SHIFT],
- "f5", []),
- new MenuItem("Build Release", null, CompilerEventBase.BUILD_RELEASE)
- ]
- );
- }
-
- private function buildCommand(args:Array):void
- {
- build(null, false);
- }
-
- private function runCommand(args:Array):void
- {
- build(null, true);
- }
-
- private function releaseCommand(args:Array):void
- {
- build(null, false, true);
- }
-
- private function reset():void
- {
- fcsh = null;
- targets = new Dictionary();
- }
-
- private function buildAndRun(e:Event):void
- {
- build(e, true);
- }
-
- private function buildRelease(e:Event):void
- {
- build(e, false, true);
- }
-
- private function build(e:Event, runAfterBuild:Boolean=false, release:Boolean=false):void
- {
- this.runAfterBuild = runAfterBuild;
-
- var pvo:ProjectVO = IDEModel.getInstance().activeProject;
-
- // Don't compile if there is no project. Don't warn since other compilers might take the job.
- if (!pvo) return
- if (!(pvo is AS3ProjectVO)) return;
-
-
- if (!fcsh || pvo.folder.nativePath != shellInfo.workingDirectory.nativePath
- || usingInvalidSDK(pvo as AS3ProjectVO))
- {
- currentSDK = getCurrentSDK(pvo as AS3ProjectVO);
- if (!currentSDK)
- {
- error("No Flex SDK set. Check settings.");
- return;
- }
- var fsch:File = currentSDK.resolvePath(fcshPath);
- if (!fsch.exists)
- {
- error("Couldn't find FSCH binary. Check settings.");
- return;
- }
- shellInfo.executable = fsch;
- shellInfo.workingDirectory = pvo.folder;
- initShell();
- }
-
- debug("SDK path: %s", currentSDK.nativePath);
- compile(pvo as AS3ProjectVO, release);
- }
-
- /**
- * @return True if the current SDK matches the project SDK, false otherwise
- */
- private function usingInvalidSDK(pvo:AS3ProjectVO):Boolean
- {
- var customSDK:File = pvo.buildOptions.customSDK;
- if ((customSDK && (currentSDK.nativePath != customSDK.nativePath))
- || (!customSDK && currentSDK.nativePath != flexSDK.nativePath))
- {
- return true;
- }
-
- return false;
- }
-
- private function getCurrentSDK(pvo:AS3ProjectVO):File
- {
- var customSDK:File = pvo.buildOptions.customSDK;
- return customSDK ? customSDK : (defaultFlexSDK ? new File(defaultFlexSDK) : null);
- }
-
- private function compile(pvo:AS3ProjectVO, release:Boolean=false):void
- {
- clearOutput();
- dispatcher.dispatchEvent(new MXMLCPluginEvent(CompilerEventBase.PREBUILD, currentSDK));
- print("Compiling "+pvo.projectName);
-
- currentProject = pvo;
- pvo.updateConfig();
- if (pvo.targets.length == 0)
- {
- error("No targets found for compilation.");
- return;
- }
- var file:File = pvo.targets[0];
- if (targets[file] == undefined)
- {
- lastTarget = file;
-
- // Turn on optimize flag for release builds
- var optFlag:Boolean = pvo.buildOptions.optimize;
- if (release) pvo.buildOptions.optimize = true;
- var buildArgs:String = pvo.buildOptions.getArguments();
- pvo.buildOptions.optimize = optFlag;
-
- var dbg:String;
- if (release) dbg = " -debug=false";
- else dbg = " -debug=true";
- if (buildArgs.indexOf(" -debug=") > -1) dbg = "";
-
- var outputFile:File;
- if (release && pvo.swfOutput.path)
- outputFile = pvo.folder.resolvePath("bin-release/"+pvo.swfOutput.path.name);
- else if (pvo.swfOutput.path)
- outputFile = pvo.swfOutput.path
-
- var output:String
- if (outputFile)
- {
- output = " -o " + pvo.folder.getRelativePath(outputFile);
- if (outputFile.exists == false)
- FileUtil.createFile(outputFile);
- }
-
- var mxmlcStr:String =
- "mxmlc"
- +" -load-config+="+pvo.folder.getRelativePath(pvo.config.file)
- +buildArgs
- +dbg
- +output;
-
- debug("mxmlc command: %s", mxmlcStr);
-
- send(mxmlcStr);
- }
- else
- {
- var target:int = targets[file];
- send("compile "+target);
- }
- }
-
- private function send(msg:String):void
- {
- debug("Sending to mxmlx: %s", msg);
- if (!fcsh) {
- queue.push(msg);
- } else {
- var input:IDataOutput = fcsh.standardInput;
- input.writeUTFBytes(msg+"\n");
- }
- }
-
- private function flush():void
- {
- if (queue.length == 0) return;
- if (fcsh) {
- for (var i:int = 0; i < queue.length; i++) {
- send(queue[i]);
- }
- queue.length = 0;
- }
- }
-
- private function initShell():void
- {
- if (fcsh) {
- fcsh.exit();
- exiting = true;
- reset();
- } else {
- startShell();
- }
- }
-
- private function startShell():void
- {
- fcsh = new NativeProcess();
-
- fcsh.addEventListener(ProgressEvent.STANDARD_OUTPUT_DATA, shellData);
- fcsh.addEventListener(ProgressEvent.STANDARD_ERROR_DATA, shellError);
- fcsh.addEventListener(NativeProcessExitEvent.EXIT, shellExit);
- fcsh.start(shellInfo);
-
- flush();
- }
-
- private function shellData(e:ProgressEvent):void
- {
- var output:IDataInput = fcsh.standardOutput;
- var data:String = output.readUTFBytes(output.bytesAvailable);
-
- var match:Array;
-
- match = data.match(/fcsh: Target \d not found/);
- if (match)
- {
- error("Target not found. Try again.");
- targets = new Dictionary();
- }
-
- match = data.match(/fcsh: Assigned (\d) as the compile target id/);
- if (match && lastTarget) {
- var target:int = int(match[1]);
- targets[lastTarget] = target;
- debug("FSCH target: %s", target);
-
- lastTarget = null;
- }
-
- match = data.match(/(.*) \(\d+? bytes\)/);
- if (match)
- { // Successful compile
- var swfPath:String = match[1];
-
- print("Done");
-
- dispatcher.dispatchEvent(
- new MXMLCPluginEvent(CompilerEventBase.POSTBUILD, currentSDK)
- );
- dispatcher.dispatchEvent(
- new RefreshTreeEvent( currentProject.folder.resolvePath(swfPath) )
- );
-
- if (runAfterBuild)
- {
- testMovie(swfPath);
- }
- }
-
- if (data == "(fcsh) ")
- {
- if (errors != "")
- {
- compilerError(errors);
- errors = "";
- }
- }
-
- if (data.charAt(data.length-1) == "\n") data = data.substr(0, data.length-1);
-
- debug("%s", data);
- }
-
- private function testMovie(swfFilePath:String):void
- {
- var pvo:AS3ProjectVO = currentProject as AS3ProjectVO;
- var swfFile:File = currentProject.folder.resolvePath(swfFilePath);
-
- if (pvo.testMovie == AS3ProjectVO.TEST_MOVIE_CUSTOM)
- {
- var customSplit:Vector.<String> = Vector.<String>(pvo.testMovieCommand.split(";"));
- var customFile:String = customSplit[0];
- var customArgs:String = customSplit.slice(1).join(" ").replace("$(ProjectName)", pvo.projectName).replace("$(CompilerPath)", currentSDK.nativePath);
-
- cmdLine.write(customFile+" "+customArgs, pvo.folder);
- }
- else if (pvo.testMovie == AS3ProjectVO.TEST_MOVIE_AIR)
- {
- // Let SWFLauncher deal with playin' the swf
- dispatcher.dispatchEvent(
- new SWFLaunchEvent(SWFLaunchEvent.EVENT_LAUNCH_SWF, swfFile, pvo, currentSDK)
- );
- }
- else
- {
- // Let SWFLauncher deal with playin' the swf
- dispatcher.dispatchEvent(
- new SWFLaunchEvent(SWFLaunchEvent.EVENT_LAUNCH_SWF, swfFile, pvo)
- );
- }
- currentProject = null;
- }
-
-
- private function shellError(e:ProgressEvent):void
- {
- var output:IDataInput = fcsh.standardError;
- var data:String = output.readUTFBytes(output.bytesAvailable);
-
- var syntaxMatch:Array;
- var generalMatch:Array;
- var initMatch:Array;
-
- syntaxMatch = data.match(/(.*?)\((\d*)\): col: (\d*) Error: (.*).*/);
- if (syntaxMatch) {
- var pathStr:String = syntaxMatch[1];
- var lineNum:int = syntaxMatch[2];
- var colNum:int = syntaxMatch[3];
- var errorStr:String = syntaxMatch[4];
- pathStr = pathStr.substr(pathStr.lastIndexOf("/")+1);
- errors += HtmlFormatter.sprintf("%s<weak>:</weak>%s \t %s\n",
- pathStr, lineNum, errorStr);
- }
-
- generalMatch = data.match(/(.*?): Error: (.*).*/);
- if (!syntaxMatch && generalMatch)
- {
- pathStr = generalMatch[1];
- errorStr = generalMatch[2];
- pathStr = pathStr.substr(pathStr.lastIndexOf("/")+1);
-
- errors += HtmlFormatter.sprintf("%s: %s", pathStr, errorStr);
- }
-
- debug("%s", data);
- }
-
- private function shellExit(e:NativeProcessExitEvent):void
- {
- debug("FSCH exit code: %s", e.exitCode);
-
- reset();
- if (exiting) {
- exiting = false;
- startShell();
- }
- }
-
- protected function compilerWarning(...msg):void
- {
- var text:String = msg.join(" ");
- var textLines:Array = text.split("\n");
- var lines:Vector.<TextLineModel> = Vector.<TextLineModel>([]);
- for (var i:int = 0; i < textLines.length; i++)
- {
- if (textLines[i] == "") continue;
- text = "<warning> ? </warning>" + textLines[i];
- var lineModel:TextLineModel = new MarkupTextLineModel(text);
- lines.push(lineModel);
- }
- outputMsg(lines);
- }
-
- protected function compilerError(...msg):void
- {
- var text:String = msg.join(" ");
- var textLines:Array = text.split("\n");
- var lines:Vector.<TextLineModel> = Vector.<TextLineModel>([]);
- for (var i:int = 0; i < textLines.length; i++)
- {
- if (textLines[i] == "") continue;
- text = "<error> ? </error>" + textLines[i];
- var lineModel:TextLineModel = new MarkupTextLineModel(text);
- lines.push(lineModel);
- }
- outputMsg(lines);
- }
- }
- }