Зачем? Немного предыстории


Всем привет! Работаю я в группе программистов – мы занимаемся программированием микроконтроллеров и блоков управления на их основе для наземного транспорта. Так уж у нас задалось, что версий одного и того же ПО с разным функционалом/багами довольно много, которое мы зашивали в разное время, то одна из задач: определить версию ПО или его библиотек в зашитом перед нами блоке.

Ранее, при сборке проекта использовались написанные нами шаблоны, из которых получался заголовочный файл с переменными, через которые можно было узнать версии ПО. При переходе на git столкнулись с такой проблемой, что похожих шаблонов не предусмотрено. Следовательно нужно делать самим!

Работаем!


Для начала пришлось определиться, что нам нужно от программы и какой будет формат работы с ней.
Сформировались вот такие вот требования:

  • Программа должна запускаться и работать в 1 клик(для упрощения сборки проекта)
  • В отдельных репозиториях должны быть файлы-шаблоны
  • Рядом с программой будет файл конфигурационный файл, по которому будет собирать
  • Созданные заголовочные файлы будут лежать рядом с шаблонами

И конечно же список заменяемых «переменных» для шаблона и сам шаблон:

  • $git_commit — полный закомментированный текст команды «git status -s»
  • $git_namespace — наименование заголовочного файла
  • $git_countFromHead — число коммитов с создания репозитория
  • $git_hash — хэш данного коммита(5 первых символов)
  • $git_numUnrevisionedFiles — число незакоммиченных файлов
  • $git_timeNow_second — Секунда сборки
  • $git_timeNow_minute — Минута сборки
  • $git_timeNow_hour — Час сборки
  • $git_timeNow_day — День сборки
  • $git_timeNow_month — Месяц сборки
  • $git_timeNow_year — Год сборки

Почему такой странный формат времени? Потому что используем формат std::tm
Шаблон
$git_commit

#ifndef $git_namespace
#define $git_namespace

#include <ctime>

namespace $git_namespace
{
  const unsigned int countFromHead = $git_countFromHead;
  const unsigned int hash = 0x$git_hash;
  const unsigned int numUnrevisionedFiles = $git_numUnrevisionedFiles;
  const std::tm timeNow =
  {
    $git_timeNow_second,
    $git_timeNow_minute,
    $git_timeNow_hour,
    $git_timeNow_day,
    $git_timeNow_month,
    $git_timeNow_year - 1900
  };
}
#endif



Немного кода

Запускаем git и извлекаем данные

 Process git = new Process();
                  git.StartInfo = new ProcessStartInfo(f[0], " --login -i");                 
                  git.StartInfo.RedirectStandardInput = true;// перенаправить вход
                  git.StartInfo.RedirectStandardOutput = true;//перенаправить выход
                  git.StartInfo.UseShellExecute = false;   
                  git.Start();
                  git.StandardInput.WriteLine("git rev-list HEAD --count");
                  string revlist = git.StandardOutput.ReadLine();

Ищем и меняем файлы в шаблоне

           string str = string.Empty;
                        File.Copy(path + filename + ".template",filename + ".h");
                        using (System.IO.StreamReader reader = System.IO.File.OpenText(filename + ".h"))
                        {
                            str = reader.ReadToEnd();
                        }

                        str = str.Replace("$git_namespace", cur_head[0]);  // Хэш данного коммита
                        str = str.Replace("$git_countFromHead", git_revlist(cur_head));
                        str = str.Replace("$git_numUnrevisionedFiles", cur_commit.Length); 
                        str = str.Replace("$git_hash", cur_hash);  // Хэш данного коммита
                        str = str.Replace("$git_timeNow_second", DateTime.Now.Second.ToString());  // Текущая время-дата
                        str = str.Replace("$git_timeNow_minute", DateTime.Now.Minute.ToString());  // Текущая время-дата
                        str = str.Replace("$git_timeNow_hour", DateTime.Now.Hour.ToString());  // Текущая время-дата
                        str = str.Replace("$git_timeNow_day", DateTime.Now.Day.ToString());  // Текущая время-дата
                        str = str.Replace("$git_timeNow_month", DateTime.Now.Month.ToString());  // Текущая время-дата
                        str = str.Replace("$git_timeNow_year", DateTime.Now.Year.ToString());  // Текущая время-дата
                        str = str.Replace("$git_commit", cur_commit);  // состояние коммита

                        using (System.IO.StreamWriter file = new System.IO.StreamWriter(cur_head[0] + ".h"))
                        {
                            file.Write(str);
                        }

Листинг программы. Осторожно! Много быдлокода!
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Diagnostics;


namespace hgitcreate
{
  
    class Program
    {
      static string git_hash(string[] head)
        {
            string git_hash = "0";

            string[] f = Directory.GetFiles(@"C:\Program Files (x86)\Git\bin", "sh.exe"); //ищем git
            if (f.Length == 0)
            {
                f = Directory.GetFiles(@"C:\Program Files\Git\bin", "sh.exe");
            }
            else
            {
                if (f.Length != 0)
                {
                    Process git = new Process();
                    git.StartInfo = new ProcessStartInfo(f[0], " --login -i");//задаем имя исполняемого файла
                    //git.StartInfo.CreateNoWindow = true;//не создавать окно
                    //git.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
                    git.StartInfo.RedirectStandardInput = true;// перенаправить вход
                    git.StartInfo.RedirectStandardOutput = true;//перенаправить выход
                    git.StartInfo.UseShellExecute = false;//обязательный параметр, для работы предыдущих
                   // Process.Start(f[0], " --login -i");
                    git.Start();
                    git.StandardOutput.ReadLine();
                    git.StandardOutput.ReadLine();
                    git.StandardOutput.ReadLine();
                    git.StandardOutput.ReadLine();
                    git.StandardOutput.ReadLine();
                    git.StandardInput.WriteLine("git log");
                    git_hash = git.StandardOutput.ReadLine();
                    git_hash = git_hash.Substring(7, 7);
                    
                    
                   

                   
                
                }
                else
                {
                    Console.Write("git(sh.exe) not found");
                }

            }
            return git_hash;
        }

      static string git_commit(string[] head)
      {
          string git_commit = "0";

          string[] f = Directory.GetFiles(@"C:\Program Files (x86)\Git\bin", "sh.exe"); //ищем git
          if (f.Length == 0)
          {
              f = Directory.GetFiles(@"C:\Program Files\Git\bin", "sh.exe");
          }
          else
          {
              if (f.Length != 0)
              {
                  Process git = new Process();
                  git.StartInfo = new ProcessStartInfo(f[0], " --login -i");//задаем имя исполняемого файла
                  //git.StartInfo.CreateNoWindow = true;//не создавать окно
                  //git.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
                  git.StartInfo.RedirectStandardInput = true;// перенаправить вход
                  git.StartInfo.RedirectStandardOutput = true;//перенаправить выход
                  git.StartInfo.UseShellExecute = false;//обязательный параметр, для работы предыдущих
                  // Process.Start(f[0], " --login -i");
                  git.Start();
                  git.StandardOutput.ReadLine();
                  git.StandardOutput.ReadLine();
                  git.StandardOutput.ReadLine();
                  git.StandardOutput.ReadLine();
                  git.StandardOutput.ReadLine();
                  git.StandardInput.WriteLine("git status -s");
                  git_commit = "/* ";
                  int i = 1;
                  git_commit += git.StandardOutput.ReadLine() + " \n ";
                  while (git.StandardOutput.Peek() != -1)
                  {
                      i++;
                      git_commit += git.StandardOutput.ReadLine() + " \n ";
                      
                  }

                  git_commit += " */ \n //" + i.ToString();






              }
              else
              {
                  Console.Write("git(sh.exe) not found");
              }

          }
          return git_commit;
      }

      static string git_revlist(string[] head)
      {
          string git_revlist = "0";

          string[] f = Directory.GetFiles(@"C:\Program Files (x86)\Git\bin", "sh.exe"); //ищем git
          if (f.Length == 0)
          {
              f = Directory.GetFiles(@"C:\Program Files\Git\bin", "sh.exe");
          }
          else
          {
              if (f.Length != 0)
              {
                  Process git = new Process();
                  git.StartInfo = new ProcessStartInfo(f[0], " --login -i");//задаем имя исполняемого файла
                  //git.StartInfo.CreateNoWindow = true;//не создавать окно
                  //git.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
                  git.StartInfo.RedirectStandardInput = true;// перенаправить вход
                  git.StartInfo.RedirectStandardOutput = true;//перенаправить выход
                  git.StartInfo.UseShellExecute = false;//обязательный параметр, для работы предыдущих
                  // Process.Start(f[0], " --login -i");
                  git.Start();
                  git.StandardOutput.ReadLine();
                  git.StandardOutput.ReadLine();
                  git.StandardOutput.ReadLine();
                  git.StandardOutput.ReadLine();
                  git.StandardOutput.ReadLine();
                  git.StandardInput.WriteLine("git rev-list HEAD --count");
                  git_revlist = git.StandardOutput.ReadLine();
              }
              else
              {
                  Console.Write("git(sh.exe) not found");
              }

          }
          return git_revlist;
      }


        static void Main(string[] args)
        {
            try
            {
                string[] heads = File.ReadAllLines("config.csv");
                if (heads.Length > 0)
                {
                    for (int i = 0; i < heads.Length; i++)
                    {
                        string[] cur_head = heads[i].Split(';');
                        File.Delete(cur_head[1] + cur_head[0] + ".h");
                        File.Copy(cur_head[1] + cur_head[0] + ".template", cur_head[1] + cur_head[0] + ".h");

                        string cur_hash = git_hash(cur_head);
                        string cur_commit = git_commit(cur_head);
                        //Console.ReadKey();


                        string str = string.Empty;
                        using (System.IO.StreamReader reader = System.IO.File.OpenText(cur_head[1] + cur_head[0] + ".h"))
                        {
                            str = reader.ReadToEnd();
                        }

                        str = str.Replace("$git_namespace", cur_head[0]);  // Хэш данного коммита

                        str = str.Replace("$git_countFromHead", git_revlist(cur_head));
                        str = str.Replace("$git_numUnrevisionedFiles", cur_commit.Substring(cur_commit.Length - 1, 1)); 

                        str = str.Replace("$git_hash", cur_hash);  // Хэш данного коммита
                        str = str.Replace("$git_timeNow_second", DateTime.Now.Second.ToString());  // Текущая время-дата
                        str = str.Replace("$git_timeNow_minute", DateTime.Now.Minute.ToString());  // Текущая время-дата
                        str = str.Replace("$git_timeNow_hour", DateTime.Now.Hour.ToString());  // Текущая время-дата
                        str = str.Replace("$git_timeNow_day", DateTime.Now.Day.ToString());  // Текущая время-дата
                        str = str.Replace("$git_timeNow_month", DateTime.Now.Month.ToString());  // Текущая время-дата
                        str = str.Replace("$git_timeNow_year", DateTime.Now.Year.ToString());  // Текущая время-дата
                        str = str.Replace("$git_commit", cur_commit);  // состояние коммита



                        using (System.IO.StreamWriter file = new System.IO.StreamWriter(cur_head[1] + cur_head[0] + ".h"))
                        {
                            file.Write(str);
                        }


                    }
                }
                else
                {
                    Console.WriteLine("Конфигурационный файл пусть");
                }
            }
            catch(ArgumentException ex)
            {
                Console.WriteLine(ex.Message);
             //   Console.ReadKey();
            }
        }


    }
}



Готовый заголовочный файл
/*  D ../../../git_header_maker/git.ps1 
  D ../../../git_header_maker/gitAll.ps1 
  M ../../../git_header_maker/git_test1.h 
  M ../../../git_header_maker/git_test2.h 
  D "../../../git_header_maker/git_version_lpc2000 \342\200\224 \320\272\320\276\320\277\320\270\321\217.h" 
  M ../../../git_header_maker/git_version_lpc2000.h 
  D ../../../git_header_maker/git_version_lpc2000.h 
  M ../../App.config 
  M ../../Program.cs 
  M ../../Properties/AssemblyInfo.cs 
  M ../../hgitcreate.csproj 
 ?? ../../../config.csv 
 ?? ../../../hgitcreate.exe 
 ?? ../../../main exe/ 
  */ 
 //14

#ifndef git_version_lpc2000
#define git_version_lpc2000

#include <ctime>

namespace git_version_lpc2000
{
  const unsigned int countFromHead = 3;
  const unsigned int hash = 0x957d20e;
  const unsigned int numUnrevisionedFiles = 4;
  const std::tm timeNow =
  {
    56,
    33,
    17,
    3,
    7,
    2015 - 1900
  };
}
#endif

Выводы


А вывода нет, просто небольшой костыль для упрощения сборки проекта и кому-нибудь на заметку.

Комментарии ()


  1. Rumlin
    06.07.2015 14:08

    А почему не на хабре опубликовано?


    1. Kubatai
      06.07.2015 14:31

      И правда, приношу свои извинения, немного промахнулся с целевой аудиторией. Перепроверил несколько раз на предмет опечаток/ошибок, но в конце концов промахнулся с сайтом.