aboutsummaryrefslogtreecommitdiffstats
path: root/Software/Visual_Studio/Tango.Protobuf/ProtoCompiler.cs
blob: 2e51de6df680f919e8b96e89ae71cb78690553f8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
pre { line-height: 125%; }
td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
.highlight .hll { background-color: #ffffcc }
.highlight .c { color: #888888 } /* Comment */
.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */
.highlight .k { color: #008800; font-weight: bold } /* Keyword */
.highlight .ch { color: #888888 } /* Comment.Hashbang */
.highlight .cm { color: #888888 } /* Comment.Multiline */
.highlight .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */
.highlight .cpf { color: #888888 } /* Comment.PreprocFile */
.highlight .c1 { color: #888888 } /* Comment.Single */
.highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */
.highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .ges { font-weight: bold; font-style: italic } /* Generic.EmphStrong */
.highlight .gr { color: #aa0000 } /* Generic.Error */
.highlight .gh { color: #333333 } /* Generic.Heading */
.highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
.highlight .go { color: #888888 } /* Generic.Output */
.highlight .gp { color: #555555 } /* Generic.Prompt */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #666666 } /* Generic.Subheading */
.highlight .gt { color: #aa0000 } /* Generic.Traceback */
.highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */
.highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */
.highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */
.highlight .kp { color: #008800 } /* Keyword.Pseudo */
.highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */
.highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */
.highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */
.highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */
.highlight .na { color: #336699 } /* Name.Attribute */
.highlight .nb { color: #003388 } /* Name.Builtin */
.highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */
.highlight .no { color: #003366; font-weight: bold } /* Name.Constant */
.highlight .nd { color: #555555 } /* Name.Decorator */
.highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */
.highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */
.highlight .nl { color: #336699; font-style: italic } /* Name.Label */
.highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */
.highlight .py { color: #336699; font-weight: bold } /* Name.Property */
.highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */
.highlight .nv { color: #336699 } /* Name.Variable */
.highlight .ow { color: #008800 } /* Operator.Word */
.highlight .w { color: #bbbbbb } /* Text.Whitespace */
.highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */
.highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */
.highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */
.highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */
.highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */
.highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */
.highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */
.highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */
.highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */
.highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */
.highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */
.highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */
.highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */
.highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */
.highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */
.highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */
.highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */
.highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */
.highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */
.highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */
.highlight .vc { color: #336699 } /* Name.Variable.Class */
.highlight .vg { color: #dd7700 } /* Name.Variable.Global */
.highlight .vi { color: #3333bb } /* Name.Variable.Instance */
.highlight .vm { color: #336699 } /* Name.Variable.Magic */
.highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using Tango.PPC.Browser.Attributes;
using Tango.PPC.Browser.Views;
using Tango.PPC.Common.Helpers;
using Tango.Touch.Keyboard;

namespace Tango.PPC.Browser.BoundsObjects
{
    [BoundObject("keyboard", "keyboard.js")]
    public class KeyboardHandler
    {
        private DateTime _lastTime;

        public KeyboardHandler()
        {
            _lastTime = DateTime.Now;
        }

        public void openKeyboard(String inputType)
        {
            if pre { line-height: 125%; }
td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
.highlight .hll { background-color: #ffffcc }
.highlight .c { color: #888888 } /* Comment */
.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */
.highlight .k { color: #008800; font-weight: bold } /* Keyword */
.highlight .ch { color: #888888 } /* Comment.Hashbang */
.highlight .cm { color: #888888 } /* Comment.Multiline */
.highlight .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */
.highlight .cpf { color: #888888 } /* Comment.PreprocFile */
.highlight .c1 { color: #888888 } /* Comment.Single */
.highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */
.highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .ges { font-weight: bold; font-style: italic } /* Generic.EmphStrong */
.highlight .gr { color: #aa0000 } /* Generic.Error */
.highlight .gh { color: #333333 } /* Generic.Heading */
.highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
.highlight .go { color: #888888 } /* Generic.Output */
.highlight .gp { color: #555555 } /* Generic.Prompt */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #666666 } /* Generic.Subheading */
.highlight .gt { color: #aa0000 } /* Generic.Traceback */
.highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */
.highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */
.highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */
.highlight .kp { color: #008800 } /* Keyword.Pseudo */
.highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */
.highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */
.highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */
.highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */
.highlight .na { color: #336699 } /* Name.Attribute */
.highlight .nb { color: #003388 } /* Name.Builtin */
.highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */
.highlight .no { color: #003366; font-weight: bold } /* Name.Constant */
.highlight .nd { color: #555555 } /* Name.Decorator */
.highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */
.highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */
.highlight .nl { color: #336699; font-style: italic } /* Name.Label */
.highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */
.highlight .py { color: #336699; font-weight: bold } /* Name.Property */
.highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */
.highlight .nv { color: #336699 } /* Name.Variable */
.highlight .ow { color: #008800 } /* Operator.Word */
.highlight .w { color: #bbbbbb } /* Text.Whitespace */
.highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */
.highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */
.highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */
.highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */
.highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */
.highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */
.highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */
.highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */
.highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */
.highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */
.highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */
.highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */
.highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */
.highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */
.highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */
.highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */
.highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */
.highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */
.highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */
.highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */
.highlight .vc { color: #336699 } /* Name.Variable.Class */
.highlight .vg { color: #dd7700 } /* Name.Variable.Global */
.highlight .vi { color: #3333bb } /* Name.Variable.Instance */
.highlight .vm { color: #336699 } /* Name.Variable.Magic */
.highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using Tango.Core.Helpers;
using Tango.Core.IO;
using Tango.Logging;

namespace Tango.Protobuf
{
    /// <summary>
    /// Represents a protobuf compiler base class.
    /// </summary>
    /// <seealso cref="Tango.Protobuf.IProtoCompiler" />
    public abstract class ProtoCompiler : IProtoCompiler
    {
        private const String COMPILERS_FOLDER_NAME = "ProtoCompilers"; //Compilers folder name.
        protected String _compilersPath; //Compilers folder path.
        private LogManager logManager = LogManager.Default;
        private int _currentProgress;
        private int _totalProgress;

        /// <summary>
        /// Occurs when the compiler has made some progress.
        /// </summary>
        public event EventHandler<CompilerProgressEventArgs> CompilationProgress;

        /// <summary>
        /// Gets the compiler language.
        /// </summary>
        public abstract CompilerLanguage Language { get; }

        /// <summary>
        /// Gets the proto imports folders.
        /// </summary>
        public List<String> ImportsFolders { get; private set; }

        /// <summary>
        /// Gets a value indicating whether this compiler uses the default folder structure when generating code.
        /// </summary>
        public virtual bool UsesDefaultStructure { get; }

        /// <summary>
        /// Initializes a new instance of the <see cref="ProtoCompiler"/> class.
        /// </summary>
        public ProtoCompiler()
        {
            ImportsFolders = new List<string>();
            _compilersPath = Path.Combine(AssemblyHelper.GetCurrentAssemblyFolder(), COMPILERS_FOLDER_NAME);
        }

        /// <summary>
        /// Compiles the specified .proto message file.
        /// </summary>
        /// <param name="inputFile">.proto file to compile</param>
        /// <returns>
        /// A list of compiled results.
        /// </returns>
        public virtual IEnumerable<CompilerFileResult> CompileFile(string inputFile)
        {
            logManager.Log("Compiling file " + inputFile);

            CompilationProgress?.Invoke(this, new CompilerProgressEventArgs()
            {
                Current = _currentProgress++,
                Total = _totalProgress,
                File = inputFile,
            });

            var tmpPath = TemporaryManager.Default.CreateFolder();

            logManager.Log("Temp path: " + tmpPath);

            String importsString = "--proto_path \"" + Path.GetDirectoryName(inputFile) + "\" ";

            logManager.Log("Added import string: " + importsString);

            foreach (var path in ImportsFolders)
            {
                String importStr = "--proto_path \"" + path + "\" ";
                importsString += importStr;
                logManager.Log("Added import string: " + importStr);
            }

            Process p = new Process();

            logManager.Log("Compilers folder path: " + _compilersPath);

            p.StartInfo.WorkingDirectory = _compilersPath;
            String oldCurrentDirectory = Environment.CurrentDirectory;
            Environment.CurrentDirectory = _compilersPath;
            p.StartInfo.FileName = GetProtoCompilerName();

            logManager.Log("Protobuf executable path: " + p.StartInfo.FileName);

            p.StartInfo.Arguments = String.Format(
                "{0} {1}=\"{2}\" \"{3}\"",
                importsString,
                GetProtoArguments(),
                tmpPath,
                inputFile);

            logManager.Log("Final arguments:\n" + p.StartInfo.Arguments);

            p.StartInfo.CreateNoWindow = true;
            p.StartInfo.UseShellExecute = false;
            p.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;

            p.StartInfo.RedirectStandardError = true;
            p.StartInfo.RedirectStandardOutput = true;


            logManager.Log("Executing compilation...");

            p.Start();
            p.WaitForExit(5000);

            Environment.CurrentDirectory = oldCurrentDirectory;

            String error = p.StandardError.ReadToEnd();

            if (!String.IsNullOrWhiteSpace(error))
            {
                var lines = error.Split(new[] { '\r', '\n' });
                throw logManager.Log(new CompilerException() { Issues = lines.Where(x => x.Length > 0).ToList() });
            }

            List<CompilerFileResult> results = new List<CompilerFileResult>();

            foreach (var file in Directory.GetFiles(tmpPath, "*.*", SearchOption.AllDirectories))
            {
                CompilerFileResult result = new CompilerFileResult(Language, inputFile, Path.GetFileName(file), Path.GetDirectoryName(file).Replace(tmpPath, "").TrimStart('\\', '\\'), File.ReadAllText(file));
                results.Add(result);
            }


            if (tmpPath.Delete())
            {
                logManager.Log("Removed temp path: " + tmpPath);
            }
            else
            {
                logManager.Log("Could not remove temp path: " + tmpPath);
            }

            logManager.Log(Path.GetFileName(inputFile) + "compiled!");

            return results;
        }

        /// <summary>
        /// Compiles the specified .proto message file asynchronously.
        /// </summary>
        /// <param name="inputFile">.proto file to compile</param>
        /// <returns>
        /// A list of compiled results.
        /// </returns>
        public async Task<IEnumerable<CompilerFileResult>> CompileFileAsync(string inputFile)
        {
            return await new Task<IEnumerable<CompilerFileResult>>(() => { return CompileFile(inputFile); });
        }

        /// <summary>
        /// Compiles all files in the specified folder recursively.
        /// </summary>
        /// <param name="sourceFolder">The source folder</param>
        /// <returns>
        /// Compilation result.
        /// </returns>
        public virtual CompilerFolderResult CompileFolder(string sourceFolder, params String[] includeFolders)
        {
            _currentProgress = 0;
            _totalProgress = Directory.GetFiles(sourceFolder, "*.proto", SearchOption.AllDirectories).Length;

            if (!UsesDefaultStructure)
            {
                logManager.Log("Compiling folder: " + sourceFolder);

                ImportsFolders.Clear();
                ImportsFolders.AddRange(Directory.GetDirectories(sourceFolder, "*.*", SearchOption.AllDirectories));
                var result = CompileFolder(sourceFolder, sourceFolder);

                logManager.Log(Path.GetFileName(sourceFolder) + "compiled!");

                return OnPostProcessFolderCompilation(result);
            }
            else
            {
                return CompileFolderDefault(sourceFolder);
            }
        }

        /// <summary>
        /// Compiles all files in the specified folder recursively.
        /// </summary>
        /// <param name="sourceFolder">The source folder</param>
        /// <returns>
        /// Compilation result.
        /// </returns>
        protected virtual CompilerFolderResult CompileFolder(string rootFolder, string sourceFolder)
        {
            List<ICompilerResult> currentFolderResults = new List<ICompilerResult>();
            CompilerFolderResult currentFolder = new CompilerFolderResult(currentFolderResults, Language, sourceFolder, sourceFolder.Replace(rootFolder, ""));

            foreach (String file in Directory.GetFiles(sourceFolder, "*.proto"))
            {
                currentFolderResults.AddRange(CompileFile(file));
            }
            foreach (string folder in Directory.GetDirectories(sourceFolder))
            {
                if (Directory.GetFiles(folder, "*.proto").Length > 0)
                {
                    currentFolderResults.Add(CompileFolder(rootFolder, folder));
                }
            }

            return currentFolder;
        }

        /// <summary>
        /// Compiles all files in the specified folder recursively and asynchronously.
        /// </summary>
        /// <param name="sourceFolder">The source folder</param>
        /// <returns>
        /// Compilation result.
        /// </returns>
        public async Task<CompilerFolderResult> CompileFolderAsync(string sourceFolder)
        {
            return await new Task<CompilerFolderResult>(() => { return CompileFolder(sourceFolder); });
        }

        /// <summary>
        /// Compiles all files in the specified folder recursively using the default structure.
        /// </summary>
        /// <param name="sourceFolder">The source folder</param>
        /// <returns>
        /// Compilation result.
        /// </returns>
        private CompilerFolderResult CompileFolderDefault(string sourceFolder)
        {
            logManager.Log("Compiling folder: " + sourceFolder);

            Dictionary<string, CompilerFileResult> fileResults = new Dictionary<string, CompilerFileResult>();
            ImportsFolders.Clear();
            ImportsFolders.AddRange(Directory.GetDirectories(sourceFolder, "*.*", SearchOption.AllDirectories));

            var tempPath = TemporaryManager.Default.CreateFolder();

            foreach (var file in Directory.GetFiles(sourceFolder, "*.proto", SearchOption.AllDirectories))
            {
                foreach (var fileResult in CompileFile(file))
                {
                    String targetFolder = Path.Combine(tempPath, fileResult.RelativePath);
                    String targetFile = Path.Combine(targetFolder, fileResult.Name);
                    Directory.CreateDirectory(targetFolder);
                    File.WriteAllText(targetFile, fileResult.Content);

                    fileResults.Add(targetFile, fileResult);
                }
            }

            var result = CompileFolderDefault(tempPath, tempPath, fileResults);

            tempPath.Delete();

            logManager.Log(Path.GetFileName(sourceFolder) + "compiled!");

            return OnPostProcessFolderCompilation(result);
        }

        /// <summary>
        /// Compiles all files in the specified folder recursively using the default structure.
        /// </summary>
        /// <param name="rootFolder"></param>
        /// <param name="sourceFolder">The source folder</param>
        /// <returns>
        /// Compilation result.
        /// </returns>
        private CompilerFolderResult CompileFolderDefault(string rootFolder, string sourceFolder, Dictionary<string, CompilerFileResult> fileResults)
        {
            List<ICompilerResult> currentFolderResults = new List<ICompilerResult>();
            CompilerFolderResult currentFolder = new CompilerFolderResult(currentFolderResults, Language, sourceFolder, Path.GetFileName(sourceFolder));

            foreach (String file in Directory.GetFiles(sourceFolder, "*.*"))
            {
                currentFolderResults.Add(fileResults[file]);
            }
            foreach (string folder in Directory.GetDirectories(sourceFolder))
            {
                currentFolderResults.Add(CompileFolderDefault(rootFolder, folder, fileResults));
            }

            return currentFolder;
        }

        /// <summary>
        /// Override in order to manipulate the folder compilation result.
        /// </summary>
        /// <param name="result">The result.</param>
        /// <returns></returns>
        protected virtual CompilerFolderResult OnPostProcessFolderCompilation(CompilerFolderResult result)
        {
            return result;
        }

        /// <summary>
        /// Gets the protobuf compiler CLI arguments (without input/output files!).
        /// </summary>
        /// <returns></returns>
        protected abstract String GetProtoArguments();

        /// <summary>
        /// Gets the protobuf compiler CLI file name (override when using a compiler other than the default 'protoc.exe').
        /// </summary>
        /// <remarks>
        /// The compiler program must be located in the compilers folder.
        /// </remarks>
        /// <returns></returns>
        protected virtual String GetProtoCompilerName()
        {
            return "protoc.exe";
        }

        /// <summary>
        /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
        /// </summary>
        public void Dispose()
        {
            //TODO: Dispose...
        }
    }
}