510 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			Haxe
		
	
	
	
	
	
			
		
		
	
	
			510 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			Haxe
		
	
	
	
	
	
import haxe.io.BytesOutput;
 | 
						|
import haxe.io.Eof;
 | 
						|
import haxe.io.Path;
 | 
						|
import sys.io.Process;
 | 
						|
import sys.FileSystem;
 | 
						|
#if haxe4
 | 
						|
import sys.thread.Thread;
 | 
						|
#elseif neko
 | 
						|
import neko.vm.Thread;
 | 
						|
#else
 | 
						|
import cpp.vm.Thread;
 | 
						|
#end
 | 
						|
 | 
						|
class ProcessManager
 | 
						|
{
 | 
						|
   static function dup(inArgs:Array<String>)
 | 
						|
   {
 | 
						|
      if (inArgs==null)
 | 
						|
         return [];
 | 
						|
      return inArgs.copy();
 | 
						|
   }
 | 
						|
 | 
						|
   // Command may be a pseudo command, like "xcrun --sdk abc", or 'python "some script"'
 | 
						|
   // Here we split the first word into command and move the rest into args, being careful
 | 
						|
   //  to preserve quoted words
 | 
						|
   static function combineCommand(command:String, args:Array<String>)
 | 
						|
   {
 | 
						|
      var parts = new Array<String>();
 | 
						|
      var c = command;
 | 
						|
      var quoted = ~/^\s*"([^"]+)"(.*)/;
 | 
						|
      var word = ~/^\s*(\S+)(.*)/;
 | 
						|
      while(c.length>0)
 | 
						|
      {
 | 
						|
         if (quoted.match(c))
 | 
						|
         {
 | 
						|
            parts.push( quoted.matched(1) );
 | 
						|
            c = quoted.matched(2);
 | 
						|
         }
 | 
						|
         else if (word.match(c))
 | 
						|
         {
 | 
						|
            parts.push( word.matched(1) );
 | 
						|
            c = word.matched(2);
 | 
						|
         }
 | 
						|
         else
 | 
						|
            break;
 | 
						|
      }
 | 
						|
      if (parts.length>1)
 | 
						|
      {
 | 
						|
         command = parts.shift();
 | 
						|
         while(parts.length>0)
 | 
						|
            args.unshift( parts.pop() );
 | 
						|
      }
 | 
						|
      return PathManager.escape(command);
 | 
						|
   }
 | 
						|
 | 
						|
   private static function formatMessage(command:String, args:Array<String>, colorize:Bool = true):String
 | 
						|
   {
 | 
						|
      var message = "";
 | 
						|
      
 | 
						|
      if (colorize)
 | 
						|
      {
 | 
						|
         message = "\x1b[33;1m" + command + "\x1b[0m";
 | 
						|
      }
 | 
						|
      else
 | 
						|
      {
 | 
						|
         message = command;
 | 
						|
      }
 | 
						|
      
 | 
						|
      for (arg in args)
 | 
						|
      {
 | 
						|
         if (colorize)
 | 
						|
         {
 | 
						|
            var ext = Path.extension(arg);
 | 
						|
            if (ext == "cpp" || ext == "c" || ext == "h" || ext == "hpp" || ext == "m" || ext == "mm")
 | 
						|
            {
 | 
						|
               var split = arg.split ("/");
 | 
						|
               if (split.length > 1)
 | 
						|
               {
 | 
						|
                  arg = "\x1b[33m" + split.slice(0, split.length - 1).join("/") + "/\x1b[33;1m" + split[split.length - 1] + "\x1b[0m";
 | 
						|
               }
 | 
						|
               else
 | 
						|
               {
 | 
						|
                  arg = "\x1b[1m" + arg + "\x1b[0m";
 | 
						|
               }
 | 
						|
            }
 | 
						|
            else if (StringTools.startsWith(arg, "-D"))
 | 
						|
            {
 | 
						|
               arg = "\x1b[1m" + arg + "\x1b[0m";
 | 
						|
            }
 | 
						|
            else
 | 
						|
            {
 | 
						|
               arg = "\x1b[0m" + arg + "\x1b[0m";
 | 
						|
            }
 | 
						|
         }
 | 
						|
         
 | 
						|
         if (arg.indexOf(" ") > -1)
 | 
						|
         {
 | 
						|
            message += " \"" + arg + "\"";
 | 
						|
         }
 | 
						|
         else
 | 
						|
         {
 | 
						|
            message += " " + arg;
 | 
						|
         }
 | 
						|
      }
 | 
						|
      return message;
 | 
						|
   }
 | 
						|
 | 
						|
   public static function runCommand(path:String, command:String, args:Array<String>, print:Bool = true, safeExecute:Bool = true, ignoreErrors:Bool = false,?inText:String):Int
 | 
						|
   {
 | 
						|
      args = dup(args);
 | 
						|
      command = combineCommand(command,args);
 | 
						|
 | 
						|
 | 
						|
      if (print && !Log.verbose && !Log.quiet)
 | 
						|
      {
 | 
						|
         Log.info(inText==null ? "" : inText,formatMessage(command, args));
 | 
						|
      }
 | 
						|
 | 
						|
      if (safeExecute)
 | 
						|
      {
 | 
						|
         try
 | 
						|
         {
 | 
						|
            if (path != null && path != "" && !FileSystem.exists(FileSystem.fullPath(path)) && !FileSystem.exists(FileSystem.fullPath(new Path(path).dir)))
 | 
						|
            {
 | 
						|
               Log.error("The specified target path \"" + path + "\" does not exist");
 | 
						|
               return 1;
 | 
						|
            }
 | 
						|
            return _runCommand(path, command, args, inText);
 | 
						|
         }
 | 
						|
         catch (e:Dynamic)
 | 
						|
         {
 | 
						|
            if (!ignoreErrors)
 | 
						|
            {
 | 
						|
               //var text = formatMessage(command, args);
 | 
						|
               //Log.error("Error while running command\n" + text , e);
 | 
						|
               if (Log.verbose)
 | 
						|
               {
 | 
						|
                  Log.error ("", e);
 | 
						|
               }
 | 
						|
               return 1;
 | 
						|
            }
 | 
						|
            return 0;
 | 
						|
         }
 | 
						|
      }
 | 
						|
      else
 | 
						|
      {
 | 
						|
         return _runCommand(path, command, args, inText);
 | 
						|
      }
 | 
						|
   }
 | 
						|
 | 
						|
   public static function readStderr(inCommand:String,inArgs:Array<String>)
 | 
						|
   {
 | 
						|
      inArgs = dup(inArgs);
 | 
						|
      inCommand = combineCommand(inCommand,inArgs);
 | 
						|
 | 
						|
      var result = new Array<String>();
 | 
						|
      var proc = new Process(inCommand,inArgs);
 | 
						|
      try
 | 
						|
      {
 | 
						|
         while(true)
 | 
						|
         {
 | 
						|
            var out = proc.stderr.readLine();
 | 
						|
            result.push(out);
 | 
						|
         }
 | 
						|
      } catch(e:Dynamic){}
 | 
						|
      proc.close();
 | 
						|
      return result;
 | 
						|
   }
 | 
						|
 | 
						|
   public static function readStdout(command:String,args:Array<String>)
 | 
						|
   {
 | 
						|
      args = dup(args);
 | 
						|
      command = combineCommand(command,args);
 | 
						|
 | 
						|
 | 
						|
      var result = new Array<String>();
 | 
						|
      var proc = new Process(command,args);
 | 
						|
      try
 | 
						|
      {
 | 
						|
         while(true)
 | 
						|
         {
 | 
						|
            var out = proc.stdout.readLine();
 | 
						|
            result.push(out);
 | 
						|
         }
 | 
						|
      } catch(e:Dynamic){}
 | 
						|
      proc.close();
 | 
						|
      return result;
 | 
						|
   }
 | 
						|
 | 
						|
   public static function runProcess(path:String, command:String, args:Array<String>, waitForOutput:Bool = true, print:Bool = true, safeExecute:Bool = true, ignoreErrors:Bool = false, ?text:String):String
 | 
						|
   {
 | 
						|
      args = dup(args);
 | 
						|
      command = combineCommand(command,args);
 | 
						|
 | 
						|
      if (print && !Log.verbose)
 | 
						|
      {
 | 
						|
         Log.info(formatMessage(command, args));
 | 
						|
      }
 | 
						|
 | 
						|
 | 
						|
      if (safeExecute)
 | 
						|
      {
 | 
						|
         try
 | 
						|
         {
 | 
						|
            if (path != null && path != "" && !FileSystem.exists(FileSystem.fullPath(path)) && !FileSystem.exists(FileSystem.fullPath(new Path(path).dir)))
 | 
						|
            {
 | 
						|
               Log.error("The specified target path \"" + path + "\" does not exist");
 | 
						|
            }
 | 
						|
            return _runProcess(path, command, args, waitForOutput, ignoreErrors, text);
 | 
						|
         }
 | 
						|
         catch (e:Dynamic)
 | 
						|
         {
 | 
						|
            if (!ignoreErrors)
 | 
						|
            {
 | 
						|
               //Log.error("Error while running command\n" + formatMessage(command,args), e);
 | 
						|
               if (Log.verbose)
 | 
						|
               {
 | 
						|
                  Log.error ("", e);
 | 
						|
               }
 | 
						|
            }
 | 
						|
            return null;
 | 
						|
         }
 | 
						|
      }
 | 
						|
      else
 | 
						|
      {  
 | 
						|
         return _runProcess(path, command, args, waitForOutput, ignoreErrors, text);
 | 
						|
      }
 | 
						|
   }
 | 
						|
   public static function runProcessLine(path:String, command:String, args:Array<String>, waitForOutput:Bool = true, print:Bool = true, safeExecute:Bool = true, ignoreErrors:Bool = false):String
 | 
						|
   {
 | 
						|
      var result = runProcess(path, command, args, waitForOutput, print, safeExecute, ignoreErrors);
 | 
						|
      if (result!=null)
 | 
						|
         return result.split("\n")[0];
 | 
						|
      return result;
 | 
						|
   }
 | 
						|
   
 | 
						|
  
 | 
						|
   private static function _runCommand(path:String, command:String, args:Array<String>, inText:String):Int
 | 
						|
   {
 | 
						|
      var oldPath:String = "";
 | 
						|
      
 | 
						|
      if (path != null && path != "")
 | 
						|
      {  
 | 
						|
         Log.info("", " - \x1b[1mChanging directory:\x1b[0m " + path + "");
 | 
						|
         
 | 
						|
         oldPath = Sys.getCwd();
 | 
						|
         Sys.setCwd(path);
 | 
						|
      }
 | 
						|
      
 | 
						|
      if (Log.quiet && inText!=null)
 | 
						|
      {
 | 
						|
         Log.info(inText);
 | 
						|
      }
 | 
						|
      else
 | 
						|
      {
 | 
						|
         var text = inText==null ?  "Running command" : inText;
 | 
						|
         Log.info("", " - \x1b[1m" + text + ":\x1b[0m " + formatMessage(command, args));
 | 
						|
      }
 | 
						|
      
 | 
						|
      var result = 0;
 | 
						|
      
 | 
						|
      if (args != null && args.length > 0)
 | 
						|
      {
 | 
						|
         result = Sys.command(command, args);
 | 
						|
      }
 | 
						|
      else
 | 
						|
      {
 | 
						|
         result = Sys.command(command);
 | 
						|
      }
 | 
						|
      
 | 
						|
      if (oldPath != "")
 | 
						|
      {
 | 
						|
         Sys.setCwd(oldPath);
 | 
						|
      }
 | 
						|
      
 | 
						|
      if (result != 0)
 | 
						|
      {  
 | 
						|
         throw ("Error while running command\n" + formatMessage(command, args) + (path != "" ? " [" + path + "]" : "")); 
 | 
						|
      }
 | 
						|
      
 | 
						|
      return result;
 | 
						|
   }
 | 
						|
 | 
						|
   private static function _runProcess(path:String, command:String, args:Array<String>, waitForOutput:Bool, ignoreErrors:Bool, inText:String):String
 | 
						|
   {
 | 
						|
      var oldPath:String = "";
 | 
						|
      
 | 
						|
      if (path != null && path != "")
 | 
						|
      {
 | 
						|
         Log.info("", " - \x1b[1m - Changing directory:\x1b[0m " + path + "");
 | 
						|
         
 | 
						|
         oldPath = Sys.getCwd();
 | 
						|
         Sys.setCwd(path);
 | 
						|
      }
 | 
						|
 | 
						|
      if ( !Log.quiet)
 | 
						|
      {
 | 
						|
         var text = inText==null ? "Running process" : inText;
 | 
						|
         Log.info("", " - \x1b[1m" + text + ":\x1b[0m " + formatMessage(command, args));
 | 
						|
      }
 | 
						|
      else
 | 
						|
      {
 | 
						|
         Log.info("",inText);
 | 
						|
      }
 | 
						|
      
 | 
						|
      var output = "";
 | 
						|
      var result = 0;
 | 
						|
      
 | 
						|
      var process:Process = null;
 | 
						|
      try
 | 
						|
      {
 | 
						|
         process = new Process(command, args);
 | 
						|
      }
 | 
						|
      catch(e:Dynamic)
 | 
						|
      {
 | 
						|
         if (ignoreErrors)
 | 
						|
            return null;
 | 
						|
         Log.error(e+"");
 | 
						|
      }
 | 
						|
 | 
						|
      var buffer = new BytesOutput();
 | 
						|
      
 | 
						|
      if (waitForOutput)
 | 
						|
      {
 | 
						|
         var waiting = true;
 | 
						|
         while (waiting)
 | 
						|
         {
 | 
						|
            try
 | 
						|
            {
 | 
						|
               var current = process.stdout.readAll(1024);
 | 
						|
               buffer.write(current);
 | 
						|
               if (current.length == 0)
 | 
						|
               {  
 | 
						|
                  waiting = false;
 | 
						|
               }
 | 
						|
            }
 | 
						|
            catch (e:Eof)
 | 
						|
            {
 | 
						|
               waiting = false;
 | 
						|
            }
 | 
						|
         }
 | 
						|
         
 | 
						|
         result = process.exitCode();
 | 
						|
         process.close();
 | 
						|
         
 | 
						|
         //if (result == 0)
 | 
						|
         //{   
 | 
						|
            output = buffer.getBytes().toString();
 | 
						|
            if (output == "")
 | 
						|
            {
 | 
						|
               var error = process.stderr.readAll().toString();
 | 
						|
               if (ignoreErrors)
 | 
						|
               {
 | 
						|
                  output = error;
 | 
						|
               }
 | 
						|
               else
 | 
						|
               {
 | 
						|
                  if (error==null || error=="")
 | 
						|
                     error = "Error while running command\n" + formatMessage(command, args);
 | 
						|
                  Log.error(error);
 | 
						|
               }
 | 
						|
 | 
						|
               return null;
 | 
						|
            }
 | 
						|
         //}
 | 
						|
      }
 | 
						|
      
 | 
						|
      if (oldPath != "")
 | 
						|
      {  
 | 
						|
         Sys.setCwd(oldPath); 
 | 
						|
      }
 | 
						|
      
 | 
						|
      return output;
 | 
						|
   }
 | 
						|
 | 
						|
   // This function will return 0 on success, or non-zero error code
 | 
						|
   public static function runProcessThreaded(command:String, args:Array<String>, inText:String = null):Int
 | 
						|
   {
 | 
						|
      args = dup(args);
 | 
						|
      command = combineCommand(command,args);
 | 
						|
 | 
						|
      Log.lock();
 | 
						|
 | 
						|
      // Other thread may have already thrown an error
 | 
						|
      if (BuildTool.threadExitCode!=0)
 | 
						|
      {
 | 
						|
         Log.unlock();
 | 
						|
         return BuildTool.threadExitCode;
 | 
						|
      }
 | 
						|
 | 
						|
      if (inText != null)
 | 
						|
         Log.info(inText,"");
 | 
						|
 | 
						|
      if (!Log.quiet)
 | 
						|
         Log.v(" - \x1b[1mRunning command:\x1b[0m " + formatMessage(command, args));
 | 
						|
      Log.unlock();
 | 
						|
 | 
						|
      var output = new Array<String>();
 | 
						|
      var process:Process = null;
 | 
						|
      try
 | 
						|
      {
 | 
						|
         process = new Process(command, args);
 | 
						|
      }
 | 
						|
      catch(e:Dynamic)
 | 
						|
      {
 | 
						|
         Log.lock();
 | 
						|
         if (BuildTool.threadExitCode == 0)
 | 
						|
         {
 | 
						|
            Log.info('${Log.RED}${Log.BOLD}$e${Log.NORMAL}\n');
 | 
						|
            BuildTool.setThreadError(-1);
 | 
						|
         }
 | 
						|
         Log.unlock();
 | 
						|
         return -1;
 | 
						|
      }
 | 
						|
 | 
						|
 | 
						|
      var err = process.stderr;
 | 
						|
      var out = process.stdout;
 | 
						|
      var reader = BuildTool.helperThread.value;
 | 
						|
      
 | 
						|
      // Read stderr in separate thread to avoid blocking
 | 
						|
      if (reader==null)
 | 
						|
      {
 | 
						|
         var controller = Thread.current();
 | 
						|
         BuildTool.helperThread.value = reader = Thread.create(function()
 | 
						|
         {
 | 
						|
            while(true)
 | 
						|
            {
 | 
						|
               var stream = Thread.readMessage(true);
 | 
						|
               var output:Array<String> = null;
 | 
						|
               try
 | 
						|
               {
 | 
						|
                  while(true)
 | 
						|
                  {
 | 
						|
                     var line = stream.readLine();
 | 
						|
                     if (output==null)
 | 
						|
                        output = [ line ];
 | 
						|
                     else
 | 
						|
                        output.push(line);
 | 
						|
                  }
 | 
						|
               }
 | 
						|
               catch(e:Dynamic){ }
 | 
						|
               controller.sendMessage(output);
 | 
						|
            }
 | 
						|
         });
 | 
						|
      }
 | 
						|
      
 | 
						|
      // Start-up the error reader
 | 
						|
      reader.sendMessage(err);
 | 
						|
 | 
						|
      try
 | 
						|
      {
 | 
						|
         while(true)
 | 
						|
         {
 | 
						|
            var line = out.readLine();
 | 
						|
            output.push(line);
 | 
						|
         }
 | 
						|
      }
 | 
						|
      catch(e:Dynamic){ }
 | 
						|
 | 
						|
      if (output.length==1 && ~/^\S+\.(cpp|c|cc)$/.match(output[0]))
 | 
						|
      {
 | 
						|
         // Microsoft prints the name of the cpp file for some reason
 | 
						|
         output = [];
 | 
						|
      }
 | 
						|
 | 
						|
      var errOut:Array<String> = Thread.readMessage(true);
 | 
						|
      
 | 
						|
      var code = process.exitCode();
 | 
						|
      process.close();
 | 
						|
      
 | 
						|
      if (code != 0)
 | 
						|
      {
 | 
						|
         if (BuildTool.threadExitCode == 0)
 | 
						|
         {
 | 
						|
            Log.lock();
 | 
						|
            var message = "";
 | 
						|
            if (Log.verbose)
 | 
						|
            {
 | 
						|
               Log.println("");
 | 
						|
               message += "Error while running command\n";
 | 
						|
               message += formatMessage(command,args) + "\n\n";
 | 
						|
            }
 | 
						|
            if (output.length > 0)
 | 
						|
            {
 | 
						|
               message += output.join("\n") + "\n";
 | 
						|
            }
 | 
						|
            if (errOut != null)
 | 
						|
            {
 | 
						|
               message += errOut.join("\n") + '${Log.NORMAL}';
 | 
						|
            }
 | 
						|
            Log.error(message,"",null,false);
 | 
						|
            Log.unlock();
 | 
						|
         }
 | 
						|
         
 | 
						|
         return code;
 | 
						|
      }
 | 
						|
      
 | 
						|
      if (errOut!=null && errOut.length>0)
 | 
						|
         output = output.concat(errOut);
 | 
						|
         
 | 
						|
      if (output.length>0)
 | 
						|
      {
 | 
						|
         Log.info(output.join("\n"));
 | 
						|
      }
 | 
						|
      
 | 
						|
      return 0;
 | 
						|
   }
 | 
						|
}
 |