text: /*
   * Copyright (c) 2003-2008 The University of Wroclaw.
   * All rights reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *    1. Redistributions of source code must retain the above copyright
   *       notice, this list of conditions and the following disclaimer.
   *    2. Redistributions in binary form must reproduce the above copyright
   *       notice, this list of conditions and the following disclaimer in the
   *       documentation and/or other materials provided with the distribution.
   *    3. The name of the University may not be used to endorse or promote
   *       products derived from this software without specific prior
   *       written permission.
   *
   * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY ``AS IS'' AND ANY EXPRESS OR
   * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
   * NO EVENT SHALL THE UNIVERSITY BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
   * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
   * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
   * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
   * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
   * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   */
  
  using Nemerle;
  using Nemerle.Assertions;
  using Nemerle.Collections;
  using Nemerle.Compiler.Parsetree;
  using Nemerle.Compiler;
  using Nemerle.Imperative;
  using Nemerle.Macros;
  using Nemerle.Text;
  
  using System;
  using System.Globalization;
  using System.IO;
  using System.Text.RegularExpressions;
  using System.Text;
  
  namespace Nemerle.Utility
  {
    [Nemerle.MacroUsage (Nemerle.MacroPhase.BeforeInheritance,
                         Nemerle.MacroTargets.Assembly)]
    macro GeneratedAssemblyVersion(str, defaults = null)
    {
      def version = ExpandEnvHelper.Expand(str, defaults);
  
      Manager().Hierarchy.AddAssemblyAttribute(Manager().CoreEnv,
        <[ System.Reflection.AssemblyVersion($(version : string)) ]>);
    }
  
    module GitRevisionHelper
    {
      [Memoize]
      public GetRevisionGeneric(path : string) : option[string * string * string]
      {
        def execGit(startInfoConfigurator)
        {
          // Execute "git describe"
          def process = System.Diagnostics.Process();
          process.StartInfo.UseShellExecute = false;
          process.StartInfo.RedirectStandardOutput = true;
          process.StartInfo.RedirectStandardError = true;
          process.StartInfo.WorkingDirectory = path;
          process.StartInfo.CreateNoWindow = true;
          startInfoConfigurator(process.StartInfo);
  
          // Read git output line by line until regex is matched
          def loop(reader)
          {
            match (reader.ReadLine())
            {
              | null => None()
              | line =>
                regexp match (line)
                {
                  | @"(?<tag>.+)\-(?<rev>.+)\-(?<commit>.+)" =>
                    def tag = Regex.Replace(tag, @"[^\d\.]", "");
                    if (tag == ".")
                      Some(null, rev, commit)
                    else
                      Some(tag, rev, commit);
                      
                  | _ => loop(reader);
                }
            }
          }
  
          try
          {
            if (process.Start())
            {
              def revision = loop (process.StandardOutput);
  
              // Wait for git client process to terminate
              unless (process.WaitForExit (2000))
                process.Kill ();
  
              revision;
            }
            else
            {
              None()
            }
          }
          catch
          {
            | _ => None();
          }
        }
  
        def configCommon(si) // mono git or msysgit with git.exe in PATH
        {
          si.FileName  = Environment.GetEnvironmentVariable("GIT_PATH") ?? "git";
          si.Arguments = "describe --tags --long";
        }
  
        def configCmd(si) // PATH conatains git.cmd only workaround
        {
          si.FileName  = "cmd";
          si.Arguments = "/C git describe --tags --long";
        }
  
        match (execGit(configCommon))
        {
          | Some(_) as x => x
          | None()       => execGit(configCmd);
        }
      }
    }
  }
  