Advertisement
agmike

gsmake -- do you really want this $h!t?

Jan 4th, 2014
90
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 21.92 KB | None | 0 0
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Diagnostics;
  4. using System.IO;
  5. using System.Linq;
  6. using System.Text;
  7. using System.Text.RegularExpressions;
  8. using System.Xml.Serialization;
  9.  
  10.  
  11. namespace gsmake
  12. {
  13.     [Serializable]
  14.     [XmlType(TypeName = "project")]
  15.     public sealed class Project
  16.     {
  17.         public class CPath
  18.         {
  19.             [XmlAttribute(AttributeName = "path")]
  20.             public string Path;
  21.         }
  22.  
  23.         [XmlElement(ElementName = "input")]
  24.         public CPath Input;
  25.  
  26.         [XmlElement(ElementName = "output")]
  27.         public CPath Output;
  28.  
  29.         public class CTrainz
  30.         {
  31.             [XmlAttribute(AttributeName = "path")]
  32.             public string Path;
  33.         }
  34.  
  35.         [XmlElement(ElementName = "trainz")]
  36.         public CTrainz Trainz;
  37.  
  38.         public class CDefine
  39.         {
  40.             [XmlElement(ElementName = "what")]
  41.             public string Pattern;
  42.  
  43.             [XmlElement(ElementName = "with-file")]
  44.             public string FilePath;
  45.  
  46.             [XmlElement(ElementName = "with")]
  47.             public string Content;
  48.         }
  49.  
  50.         public class CParam
  51.         {
  52.             [XmlAttribute(AttributeName = "name")]
  53.             public string Name;
  54.  
  55.             [XmlText]
  56.             public string Value;
  57.         }
  58.  
  59.         public class CTarget
  60.         {
  61.             [XmlAttribute(AttributeName = "prefix")]
  62.             public string Prefix;
  63.  
  64.             [XmlAttribute(AttributeName = "asset-kuid")]
  65.             public string AssetKuid;
  66.  
  67.             public class Include
  68.             {
  69.                 [XmlAttribute(AttributeName = "path")]
  70.                 public string Path;
  71.             }
  72.  
  73.             [XmlElement(ElementName = "include")]
  74.             public Include[] Includes;
  75.  
  76.             [XmlElement(ElementName = "define")]
  77.             public CDefine[] Defines;
  78.  
  79.             [XmlElement(ElementName = "param")]
  80.             public CParam[] Params;
  81.         }
  82.  
  83.         [XmlElement(ElementName = "target")]
  84.         public CTarget[] Targets;
  85.  
  86.         [XmlElement(ElementName = "replace")]
  87.         public CDefine[] Defines;
  88.  
  89.         [XmlElement(ElementName = "param")]
  90.         public CParam[] Params;
  91.  
  92.         public static Project Load()
  93.         {
  94.             var serializer = new XmlSerializer(typeof(Project));
  95.             return (Project)serializer.Deserialize(new StreamReader("gsmake.config.xml"));
  96.         }
  97.  
  98.         public void Save()
  99.         {
  100.             var serializer = new XmlSerializer(typeof(Project));
  101.             serializer.Serialize(new StreamWriter("gsmake.config2.xml"), this);
  102.         }
  103.  
  104.         //public void SaveYaml()
  105.         //{
  106.         //    var serializer = new YamlSerializer();
  107.         //    serializer.Serialize(new StreamWriter("gsmake.config2.xml"), this);
  108.         //}
  109.     }
  110.  
  111.     class Program
  112.     {
  113.         static Project project;
  114.  
  115.         class TargetData
  116.         {
  117.             public Project.CTarget Target;
  118.             public List<string> Files;
  119.         }
  120.  
  121.         static Project.CTarget GetFileTarget(string file)
  122.         {
  123.             var fileName = Path.GetFileName(file);
  124.             var result =  project.Targets
  125.                 .Where(t => fileName.StartsWith(t.Prefix))
  126.                 .Select(t => new { t, l = t != null ? t.Prefix.Length : -1 })
  127.                 .OrderByDescending(tl => tl.l)
  128.                 .FirstOrDefault();
  129.             return result != null ? result.t : null;
  130.         }
  131.  
  132.         static TargetData GetTargetData(string targetName)
  133.         {
  134.             if (targetName.EndsWith(".gs"))
  135.             {
  136.                 return new TargetData
  137.                        {
  138.                            Target = GetFileTarget(targetName),
  139.                            Files = new List<string> { Path.Combine(Environment.CurrentDirectory, Path.Combine(project.Output.Path, targetName)) }
  140.                        };
  141.             }
  142.  
  143.             var target = GetFileTarget(targetName);
  144.             if (target.Prefix != targetName)
  145.                 return null;
  146.  
  147.             var ret = new TargetData
  148.                       {
  149.                           Target = GetFileTarget(targetName)
  150.                       };
  151.             ret.Files = GetAllOutputFiles().Where(file => GetFileTarget(file) == ret.Target).ToList();
  152.             return ret;
  153.         }
  154.  
  155.         static IEnumerable<string> GetAllOutputFiles()
  156.         {
  157.             var inputPath = Path.Combine(Environment.CurrentDirectory, project.Input.Path);
  158.             var outputPath = Path.Combine(Environment.CurrentDirectory, project.Output.Path);
  159.             return new DirectoryInfo(inputPath).GetFiles("*.gs").Select(f => Path.Combine(outputPath, f.Name));
  160.         }
  161.  
  162.         static List<TargetData> GetAllTargetData()
  163.         {
  164.             var ret = new List<TargetData>();
  165.             foreach (var file in GetAllOutputFiles())
  166.             {
  167.                 var target = GetFileTarget(file);
  168.                 var targetData = ret.Where(td => td.Target == target).FirstOrDefault();
  169.                 if (targetData == null)
  170.                     ret.Add(new TargetData { Target = target, Files = new List<string> { file } });
  171.                 else
  172.                     targetData.Files.Add(file);
  173.             }
  174.             return ret;
  175.         }
  176.  
  177.         static string CallTrainzUtil(string args)
  178.         {
  179.             var trainzutil = new Process
  180.                                  {
  181.                                      StartInfo = new ProcessStartInfo
  182.                                                  {
  183.                                                      FileName = Path.Combine(project.Trainz.Path, "bin/trainzutil.exe"),
  184.                                                      Arguments = args,
  185.                                                      CreateNoWindow = true,
  186.                                                      RedirectStandardOutput = true,
  187.                                                      UseShellExecute = false
  188.                                                  }
  189.                                  };
  190.  
  191.             trainzutil.Start();
  192.             trainzutil.WaitForExit();
  193.             return trainzutil.StandardOutput.ReadToEnd();
  194.         }
  195.  
  196.         static void Compile(TargetData target)
  197.         {
  198.             if (target.Files.Count() == 0)
  199.                 return;
  200.  
  201.             var includes = new StringBuilder();
  202.  
  203.             includes.AppendFormat("-i\"{0}\"", Path.Combine(project.Trainz.Path, "scripts"));
  204.  
  205.             if (target.Target.Includes != null)
  206.                 foreach (var include in target.Target.Includes)
  207.                     if (!String.IsNullOrEmpty(include.Path))
  208.                         includes.AppendFormat(" -i\"{0}\"", include.Path);
  209.  
  210.             //var output = String.Format("-p\"{0}\"", Path.Combine(Environment.CurrentDirectory, Path.Combine(project.Output.Path, "a")));
  211.             var output = "";
  212.  
  213.             foreach (var file in target.Files)
  214.             {
  215.                 var fileDir = Path.Combine(Environment.CurrentDirectory, project.Input.Path);
  216.                 var filePath = Path.Combine(fileDir, file);
  217.  
  218.                 Console.WriteLine("Compiling {0}:", file);
  219.                 Console.Write(CallTrainzUtil(String.Format("compile \"{0}\" {1} {2}", filePath, includes, output)));
  220.             }
  221.         }
  222.  
  223.         static void Encrypt(TargetData target)
  224.         {
  225.             for (int i = 0; i < target.Files.Count; ++i)
  226.             {
  227.                 var file = target.Files[i];
  228.                 var encryptedFile = Regex.Replace(file, @"\.gs$", ".gse");
  229.                 File.Delete(encryptedFile);
  230.                 var output = CallTrainzUtil(String.Format("encrypt \"{0}\"", file));
  231.                 if (!File.Exists(encryptedFile))
  232.                     Console.Write(output);
  233.                 else
  234.                     target.Files[i] = encryptedFile;
  235.             }
  236.         }
  237.  
  238.         static void Install(TargetData target)
  239.         {
  240.             if (target.Files.Count() == 0)
  241.                 return;
  242.  
  243.             var resultRegex = new Regex(@"OK \((\d+) \w+, (\d+) \w+\)");
  244.             var openResult = CallTrainzUtil(String.Format("edit {0}", target.Target.AssetKuid));
  245.             var resultLines = openResult.Split('\n').Where(l => !String.IsNullOrEmpty(l));
  246.             var match = resultRegex.Match(resultLines.Last());
  247.             if (!match.Success || match.Groups[1].Captures[0].Value != "0")
  248.             {
  249.                 Console.WriteLine(openResult);
  250.                 return;
  251.             }
  252.  
  253.             var pathLine = resultLines.First();
  254.             var pathKuidStrLength = pathLine.IndexOf('>') + 3;
  255.             var openedPath = pathLine.Substring(pathKuidStrLength).Trim();
  256.  
  257.             //foreach (var file in new DirectoryInfo(openedPath).GetFiles("*.gs"))
  258.             //    File.Delete(file.FullName);
  259.             //foreach (var file in new DirectoryInfo(openedPath).GetFiles("*.gse"))
  260.             //    File.Delete(file.FullName);
  261.  
  262.             foreach (var file in target.Files)
  263.             {
  264.                 var fileName = Path.GetFileName(file);
  265.                 File.Copy(file, Path.Combine(openedPath, fileName), overwrite: true);
  266.             }
  267.  
  268.             var commitResult = CallTrainzUtil(String.Format("commit {0}", target.Target.AssetKuid));
  269.             resultLines = commitResult.Split('\n').Where(l => !String.IsNullOrEmpty(l));
  270.             match = resultRegex.Match(resultLines.Last());
  271.  
  272.             if (!match.Success || match.Groups[1].Captures[0].Value != "0")
  273.                 Console.WriteLine(commitResult);
  274.             else
  275.                 Console.WriteLine("Installing to <{0}> - OK", target.Target.AssetKuid);
  276.         }
  277.  
  278.         static void PreprocessDefines(ref string contents, IEnumerable<Project.CDefine> defines)
  279.         {
  280.             if (defines != null)
  281.                 contents = defines.Aggregate(contents, (current, define) =>
  282.                     current.Replace(define.Pattern,  String.IsNullOrEmpty(define.FilePath)
  283.                                                      ? define.Content
  284.                                                      : File.ReadAllText(define.FilePath))
  285.                     );
  286.         }
  287.  
  288.         static void PreprocessParams(ref string contents, Dictionary<string, string> allParams)
  289.         {
  290.             bool anyReplace = false;
  291.             var i = allParams.GetEnumerator();
  292.             while (true)
  293.             {
  294.                 if (!i.MoveNext())
  295.                 {
  296.                     if (anyReplace)
  297.                     {
  298.                         anyReplace = false;
  299.                         i = allParams.GetEnumerator();
  300.                         continue;
  301.                     }
  302.                     break;
  303.                 }
  304.  
  305.                 var name = i.Current.Key;
  306.                 var value = i.Current.Value;
  307.                 var quotedName = GetParamQuotedName(name);
  308.  
  309.                 if (contents.Contains(quotedName))
  310.                 {
  311.                     anyReplace = true;
  312.  
  313.                     switch (name)
  314.                     {
  315.                         case "line":
  316.                             var paramIndex = contents.IndexOf(quotedName);
  317.                             var lineCount = contents.Substring(0, paramIndex).Count(c => c == '\n') + 1;
  318.                             contents = contents.Replace(quotedName, lineCount.ToString());
  319.                             break;
  320.                         default:
  321.                             contents = contents.Replace(quotedName, value);
  322.                             break;
  323.                     }
  324.                 }
  325.             }
  326.         }
  327.  
  328.         static string GetParamQuotedName(string param)
  329.         {
  330.             return String.Format("{{%{0}%}}", param);
  331.         }
  332.  
  333.         static void PreparePreprocess()
  334.         {
  335.             var allParams = new Dictionary<string, string>(paramsDict);
  336.             var targets = GetAllTargetData();
  337.             if (project.Params != null)
  338.                 Array.ForEach(project.Params, p => allParams[p.Name] = p.Value);
  339.             targets.ForEach(td =>
  340.                             {
  341.                                 if (td.Target.Params != null)
  342.                                     Array.ForEach(td.Target.Params, p => allParams[p.Name] = p.Value);
  343.                             });
  344.  
  345.             foreach (var td in targets)
  346.             {
  347.                 foreach (var file in td.Files)
  348.                 {
  349.                     allParams["file"] = Path.GetFileName(file);
  350.  
  351.                     var contents = File.ReadAllText(file);
  352.  
  353.                     PreprocessDefines(ref contents, defines);
  354.                     PreprocessDefines(ref contents, project.Defines);
  355.                     PreprocessDefines(ref contents, td.Target.Defines);
  356.                     PreprocessParams(ref contents, allParams);
  357.  
  358.                     File.WriteAllText(file, contents);
  359.                 }
  360.             }
  361.         }
  362.  
  363.         static void PrepareFiles()
  364.         {
  365.             var inputPath = Path.Combine(Environment.CurrentDirectory, project.Input.Path);
  366.             var inputFiles = new DirectoryInfo(inputPath).GetFiles("*.gs").Select(f => f.FullName);
  367.  
  368.             var copyPath = Path.Combine(Environment.CurrentDirectory, project.Output.Path);
  369.             foreach (var file in inputFiles)
  370.                 File.Copy(file, Path.Combine(copyPath, Path.GetFileName(file)), overwrite: true);
  371.         }
  372.  
  373.         static bool preparingDone = false;
  374.  
  375.         static void Prepare()
  376.         {
  377.             if (!preparingDone)
  378.             {
  379.                 PrepareFiles();
  380.                 PreparePreprocess();
  381.                 preparingDone = true;
  382.             }
  383.         }
  384.  
  385.         static void Clean()
  386.         {
  387.             var outPath = Path.Combine(Environment.CurrentDirectory, project.Output.Path);
  388.             var dirInfo = new DirectoryInfo(outPath);
  389.             foreach (var fileInfo in dirInfo.GetFiles("*.gs"))
  390.                 fileInfo.Delete();
  391.             foreach (var fileInfo in dirInfo.GetFiles("*.gsl"))
  392.                 fileInfo.Delete();
  393.             foreach (var fileInfo in dirInfo.GetFiles("*.gse"))
  394.                 fileInfo.Delete();
  395.             preparingDone = false;
  396.         }
  397.  
  398.         static List<Project.CDefine> defines = new List<Project.CDefine>();
  399.         static Dictionary<string, string> paramsDict = new Dictionary<string, string>
  400.                                                        {
  401.                                                            { "date", DateTime.Now.ToString("dd.MM.yyyy") },
  402.                                                            { "time", DateTime.Now.ToString("HH:mm") },
  403.                                                            { "line", "" }
  404.                                                        };
  405.         static bool displayHelp = false;
  406.  
  407.         static void Main(string[] args)
  408.         {
  409.             try
  410.             {
  411.                 var jobs = new List<string>();
  412.                 var argsEnum = args.ToList().GetEnumerator();
  413.                 while (argsEnum.MoveNext())
  414.                 {
  415.                     if (!argsEnum.Current.StartsWith("-"))
  416.                     {
  417.                         jobs.Add(argsEnum.Current);
  418.                     }
  419.                     else
  420.                     {
  421.                         do
  422.                         {
  423.                             var option = argsEnum.Current;
  424.                             if (option == "-replace-str")
  425.                             {
  426.                                 if (argsEnum.MoveNext())
  427.                                 {
  428.                                     var pattern = argsEnum.Current;
  429.                                     if (argsEnum.MoveNext())
  430.                                     {
  431.                                         var replace = argsEnum.Current;
  432.                                         defines.Add(new Project.CDefine { Pattern = pattern, Content = replace });
  433.                                     }
  434.                                 }
  435.                             }
  436.                             else if (option == "-replace-file")
  437.                             {
  438.                                 if (argsEnum.MoveNext())
  439.                                 {
  440.                                     var pattern = argsEnum.Current;
  441.                                     if (argsEnum.MoveNext())
  442.                                     {
  443.                                         var replaceFile = argsEnum.Current;
  444.                                         defines.Add(new Project.CDefine { Pattern = pattern, FilePath = replaceFile });
  445.                                     }
  446.                                 }
  447.                             }
  448.                             else if (option == "-param")
  449.                             {
  450.                                 if (argsEnum.MoveNext())
  451.                                 {
  452.                                     var name = argsEnum.Current;
  453.                                     if (argsEnum.MoveNext())
  454.                                     {
  455.                                         var value = argsEnum.Current;
  456.                                         paramsDict[name] = value;
  457.                                     }
  458.                                 }
  459.                             }
  460.                             else if (option == "-help")
  461.                             {
  462.                                 displayHelp = true;
  463.                             }
  464.                             else
  465.                                 throw new FormatException(String.Format(@"Bad option '{0}'", option));
  466.                         }
  467.                         while (argsEnum.MoveNext());
  468.                     }
  469.                 }
  470.  
  471.                 if (displayHelp)
  472.                     return;
  473.  
  474.                 project = Project.Load();
  475.  
  476.                 if (jobs.Count == 0)
  477.                 {
  478.                     jobs.Add(":c");
  479.                 }
  480.  
  481.                 foreach (var job in jobs)
  482.                 {
  483.  
  484.                     var jobTokens = job.Split(':');
  485.                     string aTarget = jobTokens[0];
  486.                     string actions = jobTokens.Length == 2 ? jobTokens[1] : "c";
  487.  
  488.                     var targets = String.IsNullOrEmpty(aTarget)
  489.                                       ? GetAllTargetData()
  490.                                       : new List<TargetData> { GetTargetData(aTarget) };
  491.  
  492.                     if (!targets.Any(t => t != null && t.Target != null))
  493.                     {
  494.                         Console.WriteLine(@"Bad arg '{0}'", job);
  495.                         return;
  496.                     }
  497.  
  498.                     foreach (var action in actions)
  499.                     {
  500.                         switch (action)
  501.                         {
  502.                             case 'c':
  503.                                 Prepare();
  504.                                 targets.ForEach(Compile);
  505.                                 break;
  506.                             case 'e':
  507.                                 Prepare();
  508.                                 targets.ForEach(Encrypt);
  509.                                 break;
  510.                             case 'i':
  511.                                 Prepare();
  512.                                 targets.ForEach(Install);
  513.                                 break;
  514.                             case 'C':
  515.                                 Clean();
  516.                                 break;
  517.                             default:
  518.                                 Console.WriteLine(@"Bad action '{0}'", action);
  519.                                 return;
  520.                         }
  521.                     }
  522.                 }
  523.             }
  524.             catch (FormatException e)
  525.             {
  526.                 Console.WriteLine(e.Message);
  527.                 displayHelp = true;
  528.             }
  529.             finally
  530.             {
  531.                 if (displayHelp)
  532.                 {
  533.                     Console.WriteLine("gsmake version 0.9.10");
  534.                     Console.WriteLine("Usage:");
  535.                     Console.WriteLine("  gsmake [OPTIONS] -- compile all targets");
  536.                     Console.WriteLine("  gsmake TARGET:ACTION [OPTIONS]");
  537.                     Console.WriteLine("Description:");
  538.                     Console.WriteLine("  gsmake performs actions to set of GameScript files.");
  539.                     Console.WriteLine("  Actions are:");
  540.                     Console.WriteLine("    1. Cleaning output directory");
  541.                     Console.WriteLine("    2. Compiling");
  542.                     Console.WriteLine("    3. Ecnrypting");
  543.                     Console.WriteLine("    4. Installing");
  544.                     Console.WriteLine("  Actions are done to sets of files.");
  545.                     Console.WriteLine("  They are defined in config.xml file as targets.");
  546.                     Console.WriteLine("  It is written as:");
  547.                     Console.WriteLine("    targetName:c -- this will compile all files in target targetName");
  548.                     Console.WriteLine("    :i -- this will install all targets to assets");
  549.                     Console.WriteLine("    target1:i target2:ei -- this will install");
  550.                     Console.WriteLine("      target1 as plain files and target2 as ecnrypted files");
  551.                     Console.WriteLine("    :i :C -- this will install all targets and then clean output directory");
  552.                     Console.WriteLine("  Default action is compile (c).");
  553.                     Console.WriteLine("  Cleaning could be done only as global action (means not linked with any target.");
  554.                     Console.WriteLine("Options:");
  555.                     Console.WriteLine("  -replace-str WHAT WITH: replace in all files with string");
  556.                     Console.WriteLine("  -replace-file WHAT FILE: replace in all files with FILE contents");
  557.                     Console.WriteLine("  -param PARAM_NAME VALUE: set parameter name to value");
  558.                     Console.WriteLine("  -help: show this help text");
  559.                     Console.WriteLine("");
  560.                 }
  561.             }
  562.  
  563.             return;
  564.         }
  565.     }
  566. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement