Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

April 2018.  Great Migrations is pleased to announce a major break through in software re-engineering: a .NET API for automating the gmBasic upgrade engine and accessing the semantic models produced by our unique linguistic compilation technology.

...

The API includes special purposes classes to help you integrate API-based EXE upgrade tasks with gmStudio and customize their behavior.  EXE upgrades tasks can be used in gmStudio using procedures very similar to those for gmPL script tasks. The main difference is the EXE tasks are implemented in C# (or VB.NET) using Visual Studio while gmPL script tasks are implemented in XML using your favorite code editor.

We The API is still evolving rapidly so we consider this release a beta, but we have already developed a C# version of the WPF transformation logic using this API and also we have used it with C# to implement several very large multi-feature upgrade solutions.  Additional documentation and samples using the API will be published soon. Please   Contact us  if directly if you are interested in learning being part of the beta-test or discussing how this technology can help you. 

Info

Preview the draft .NET API documentation here.

A sample upgrade program using the API is shown here.  Notice that it use WPF Subsystem logic that is implemented in a C# assembly and available as C# sourceThe example also shows how to load source and edit the source in memory prior to translation.  To use this, API you need to reference gmslAPI.dll from the gmStudio distribution and also make sure you choose Platform Target x86 since the gmBasic engine is presently a 32bit technology.  Contact Great Migrations if you are interested in a 64bit build.

Code Block
languagec#
titleSample gmslAPI Upgrade Program (beta)
linenumberstruecollapsetrue
using gmslLibrary;System.Collections.Generic;
using wpfLibrarySystem.Linq;
using gmslLibrary.Services;
using gmslLibrary.Model;
using gmslLibrary.Enums;
using GM = gmslAPI;

namespace gmUpgrade
{
    public static class Program
    {
        [System.STAThread] // Much faster using STA, ~1.6 vs 8.6 secondsconst string taskArg = "TaskInfo=";
        const string startupArg = static"startup=";
void
Main(string[] args)       [System.STAThread] // {faster using STA
        static  // When started by gmStudio, TaskInfo is passed on the command line.void Main(string[] args)
        {

            //string ThecmlStartup TaskInfo XML file is generated by gmStudio.  It contains= System.Array.Find(args, str => str.StartsWith(startupArg));
            string startupPath = null;
 // details about the upgrade task and the upgrade environment.  if (cmlStartup == null)
       // For debugging or direct operation,{
load upgrade tasks here.             if (args.Length == 0)
// default startup file path
           {     startupPath = gmslAPI.Common.DefaultStartUpFile;
            }
            argselse
= new string[] {         {
           @"TaskInfo=c:\Upgrades\proj\log\Upgrade-task1-exe-csh.xml",     // parse startup path from the command line, and remove it from the list of  @"TaskInfo=c:\Upgrades\proj\log\Upgrade-task2-exe-csh.xmlxml",arguments
                int i = 0;
    @"TaskInfo=c:\Upgrades\proj\log\Upgrade-task3-exe-csh.xml",            foreach (string arg in      @"TaskInfo=c:\Upgrades\proj\log\Upgrade-task4-exe-csh.xmll"args)
                {
                    if (arg.StartsWith(startupArg))
                    {
                        args[i] = "";
                        startupPath = arg.Split('=')[1];
                    }
                    i++;
                }
            }

            // When started by gmStudio, TaskInfo argument is passed on the command line.
            // The TaskInfo XML file is generated by gmStudio.  It contains details about 
            // the upgrade task and the upgrade environment.
            // For debugging or direct operation, load upgrade tasks here.
            // Note: you can redirect the output of this to the log file for 
            // debugging (> log) in project properties, but doing so will block 
            // gmStudio from running the EXE running when VS is open. 
            string cmlTask = System.Array.Find(args, str => str.StartsWith(taskArg));
            List<string> taskList = new List<string>();
            if (cmlTask == null)
            {
                // batch
                taskList.Add(taskArg + @"C:\gmSpec\Util\APITest\proj\log\APITest-APITest-exe-csh.TRAN.Xml");
            }
            else
            {
                // parse taskarg item from the command line
                int i = 0;
                foreach (string arg in args)
                {
                    if (arg.StartsWith(taskArg))
                    {
                        args[i] = "";
                        taskList.Add(arg);
                    }
                    i++;
                }
            }
            if (taskList.Count == 0)
            {
                System.Console.Write("USAGE: " + args[0] + " " + taskArg + " TaskInfoFilePath");
                System.Environment.Exit(1);
            }

            RunAllTranslations(taskList, startupPath, args);
            System.Environment.Exit(0);
        }

        static void RunAllTranslations(List<string> taskList, string startupPath, string[] args)
        {
            GM.Common.LoadLicense(logInfo: true);

            string taskInfoPath = "";
            foreach (string arg in taskList)
            {
                if (arg.StartsWith(taskArg))
                {
                    taskInfoPath = arg.Split('=')[1];
                    if (!System.IO.File.Exists(taskInfoPath))
                    {
                        System.Console.WriteLine("ERROR: TaskInfo File Not Found:" + taskInfoPath);
                        System.Environment.Exit(999);
                    }
                    else
                    {
                        repair(taskInfoPath);
                        GM.gmStudioTask task = GM.Common.Load(taskInfoPath);
                        RunUpgrade(task, startupPath, args);
                    }
                }
            }
        }
        private static void RunUpgrade(gmslAPI.gmStudioTask task, string startupPath, string[] args)
        {
            System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
            sw.Start();

            // Go to Upgrade project working folder so relative file references are correct
            System.IO.Directory.SetCurrentDirectory(task.WorkFolder);

            System.Console.WriteLine("Loaded task:" + task.JobId);

            string projectStartup = @"C:\Program Files (x86)\GreatMigrations\gmStudio\support\tools\gmBasic.xml";
            if (!System.IO.File.Exists(projectStartup)) projectStartup = null;

            gmBasic.StartUp(projectStartup, null, args);

            // Detailed translation rules are stored in a ScriptRules.xml
            // This format can be used by both XML-based and API-based upgrade tasks
            // The ScriptRules class makes these rules available to API calls.
            GM.ScriptRules rules = new GM.ScriptRules(@"..\usr\ScriptRules.xml");

            rules.AddRules(task, "BasicRules");

            rules.logEnable = true;
            log(rules.logEnable, rules.AllRulesReport());

            log(rules.logEnable, "Startup(ms):" + sw.ElapsedMilliseconds);
            Execute.Storage(action: "Create", identifier: task.JobId);

            if (rules.OptionRules != 0)
            {
                Execute.gmPL(commands: rules.OptionRules);
                log(rules.logEnable, "Options(ms):" + sw.ElapsedMilliseconds);
            }

            bool useWPF = Select.SubSystem == Dialects.wpf;

            log(rules.logEnable, "GUI: " + (useWPF ? "WPF" : "WinForms"));

            Execute.Load(project: task.SrcPath, sourcecode: "on");
            AddCommentOnErrorHandlers();

            Execute.Compile(resx: task.ResxFolder, commands: rules.CompileRules);
            //Execute.Compile(project: task.SrcPath, resx: task.ResxFolder, commands: rules.CompileRules);
            log(rules.logEnable, "Compile(ms):" + sw.ElapsedMilliseconds);

            if (rules.PreAnalyseRules != 0)
            {
                Execute.gmPL(commands: rules.PreAnalyseRules);
                log(rules.logEnable, "PreAnalyse(ms):" + sw.ElapsedMilliseconds);
            }

            Execute.Analyse();
            log(rules.logEnable, "Analyze(ms):" + sw.ElapsedMilliseconds);

            if (rules.PostAnalyseRules != 0)
            {
                Execute.gmPL(commands: rules.PostAnalyseRules);
                log(rules.logEnable, "PostAnalyse(ms):" + sw.ElapsedMilliseconds);
            }

            Execute.Output(status: "New", filename: task.BndPath);

            Execute.Author(commands: rules.AuthorRules);
            log(rules.logEnable, "Author(ms):" + sw.ElapsedMilliseconds);
            Execute.Output(status: "Close");

            if (rules.PostAuthorRules != 0)
            {
                Execute.gmPL(commands: rules.PostAuthorRules);
                log(rules.logEnable, "PostAuthor(ms):" + sw.ElapsedMilliseconds);
            }

            Execute.Storage(action: "Close");
            gmBasic.Terminate();
            log(rules.logEnable, "Total(ms):" + sw.ElapsedMilliseconds);
        }
        private static void log(bool doLog, string msg)
        {
            if (doLog) System.Console.WriteLine(msg);
        }
        private static void repair(string taskInfoPath)
        {
            string data = System.IO.File.ReadAllText(taskInfoPath);
            data = data.Replace("UsrCm nt=", "UsrCmnt= ");
            data = data.Replace("UsrDes c=", "UsrDesc= ");
            System.IO.File.WriteAllText(taskInfoPath, data);
        };

        private static void }AddCommentOnErrorHandlers()
        {
   RunAllTranslations(args);         int[] levels =  System.Environment.Exit(0);new int[19];
          }  int iRoot;
      static void RunAllTranslations(string[] args)   tInfoFile formFile;
    {        Text textStream;
   GM.gmslAPI.LoadLicense(logInfo:true); // Must load gmStudio License    int nRecord;
        string taskInfoPath = ""; int curRecord;
          foreach (string argint inlength args)= 0;
           { int rai = 0;
            if (arg.StartsWith("TaskInfo="))string record;

            for (iRoot  {
    = Store.FindFirstChild(levels, 0); iRoot != 0; iRoot = Store.FindNextChild(levels))
            {
  taskInfoPath = arg.Split('=')[1];            if (Store.GetObjectType(iRoot) != ObjectType.FormFile) continue;
    if (!System.IO.File.Exists(taskInfoPath))           string name = Symbol.FullName(iRoot, 0);
     {           FileSystem.LogMessage("name=" + name);

          System.Console.WriteLine("ERROR: TaskInfo File Not Found:" + taskInfoPath);formFile = new  tInfoFile(iRoot);
                if (formFile.textBase ==  System.Environment.Exit(999)0) continue;
                FileSystem.LogMessage("formFile.textBase=" + formFile.textBase);

}                textStream = new Text(formFile.textBase);
 else               FileSystem.LogMessage("textStream=" + textStream);

  {              // sample   code changes lines ending with ":" to Run1Translation(taskInfoPath);lines ending with ": 'TEST"
                }nRecord = textStream.Maximum();
              }  curRecord = 0;
        }        while }(curRecord < nRecord)
       private static void Run1Translation(string taskInfoPath)     {
   {             GM.gmStudioTask task = GM.gmslAPI.Load(taskInfoPath);

    curRecord = curRecord + 1;
        bool useWPF = task.UserDesc == "WPF";       textStream.Position(curRecord);
                  // Go torecord Upgrade project working folder so relative file references are correct= textStream.Access(ref length, ref rai);

                System.IO.Directory.SetCurrentDirectory(task.WorkFolder);    if (length < 2) continue;
     // Detailed translation rules are stored in a ScriptRules.xml file.      string last = Character.Substr(record, length -  // This format can be used by both XML-based and API-based upgrade tasks.1, 1);
                    if (last == ":")
// The ScriptRules class makes them rules available to API calls.          {
  GM.ScriptRules rules = new GM.ScriptRules(@"..\usr\ScriptRules.xml");              rules.AddRules(task, "SetOptions");   // Inserts a record after the current record and  rules.AddRules(task, "PreEdits");
 sets Position to new record
          rules.AddRules(task, "msado15.dll");             rulestextStream.AddRules(task, "scrrun.dllInsert(record + " ' TEST");
            rules.AddRules(task, "excel.exe");            // reset position to  rules.AddRules(task, "AssessmentRules");original record
             rules.AddRules(task, "GenericCollections");          textStream.Position(curRecord);
   rules.logEnable = true;             if (rules.logEnable) FileSystem.LogMessage(rules.AllRulesReport());    // delete original record
      gmBasic.StartUp(@"..\usr\gmBasic.xml", null, null);             Execute.Storage(action: "Create", identifier: tasktextStream.JobIdDelete();
              Execute.gmPL(commands: rules.OptionRules);         continue;
    Execute.Compile(project: task.SrcPath, commands: rules.CompileRules);             }
if (rules.PreAnalyseRules != 0)             {}
                ExecutetextStream.gmPL(commands: rules.PreAnalyseRulesClose();
            }
        }
    Execute.Analyse();

            if (rules.PostAnalyseRules!=0)
            {
       }
}

This sample also uses a ScriptRules file to organize and specify the stock translation options:

Code Block
xml
xml
<ScriptRules>
<!-- Here is a sample of the Basic ScriptRule elements that may be used with an gmAPI based translation -->
<ScriptRule id="BasicRules">
   <Option>
      <!--  Execute.gmPL(commands: rules.PostAnalyseRules);
 directories for configuration files -->

      <select Target="%UserFolder%" />
}      <Select Local="%IdfFromCodeFolder%" />
     int projectRoot<Select System= (useWPF ? wpfSubsystem.WPFCodeScan() : 0); // WPF
    "%IdfFromIdlFolder%" />

      <!-- translation options -->

      Execute.Output(status: "New", filename: task.BndPath);<Select Progress="1" />
      <Select    DevEnv="%DevEnv%" />
      <Select Dialect="%Dialect%" />
      if (useWPF) wpfSubsystem.WPFAuthorProject(projectRoot, rules.AuthorRules); // WPF<Select BuildFile="local" />
      <Registry type="GUID" source="Project" target="{%TaskGuid%}"/>   

 else Execute.Author(commands: rules.AuthorRules);   <!-- directories for deployment and external assemblies -->

  Execute.Storage(action: "Close");   <select VirtualRoot="%VirtualRoot%" />
       gmBasic.Terminate();
<Select DeployLocation="%NetProjFolder%" />
      <Select }
Library="%RuntimeFolder%" />

  } }

</Option>
</ScriptRule>
</ScriptRules>