LCOV - code coverage report
Current view: top level - source/sys - gitRepo.cpp (source / functions) Coverage Total Hit
Test: mxlib Lines: 0.0 % 143 0
Test Date: 2026-08-30 22:23:37 Functions: 0.0 % 14 0

            Line data    Source code
       1              : /** \file gitRepo.cpp
       2              :  * \author Jared R. Males
       3              :  * \brief Interrogate the current state of a git repository (definitions)
       4              :  * \ingroup utils_files
       5              :  */
       6              : 
       7              : //***********************************************************************//
       8              : // Copyright 2021 Jared R. Males (jaredmales@gmail.com)
       9              : //
      10              : // This file is part of mxlib.
      11              : //
      12              : // mxlib is free software: you can redistribute it and/or modify
      13              : // it under the terms of the GNU General Public License as published by
      14              : // the Free Software Foundation, either version 3 of the License, or
      15              : // (at your option) any later version.
      16              : //
      17              : // mxlib is distributed in the hope that it will be useful,
      18              : // but WITHOUT ANY WARRANTY; without even the implied warranty of
      19              : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      20              : // GNU General Public License for more details.
      21              : //
      22              : // You should have received a copy of the GNU General Public License
      23              : // along with mxlib.  If not, see <http://www.gnu.org/licenses/>.
      24              : //***********************************************************************//
      25              : 
      26              : #include "sys/gitRepo.hpp"
      27              : 
      28              : #include "ipc/processInterface.hpp"
      29              : #include "ioutils/stringUtils.hpp"
      30              : #include "ioutils/fileUtils.hpp"
      31              : 
      32              : namespace mx
      33              : {
      34              : namespace sys
      35              : {
      36              : 
      37            0 : gitRepo::gitRepo()
      38              : {
      39            0 : }
      40              : 
      41            0 : gitRepo::gitRepo( const std::string &d )
      42              : {
      43            0 :     dir( d );
      44            0 : }
      45              : 
      46            0 : void gitRepo::dir( const std::string &d )
      47              : {
      48            0 :     m_dir = d;
      49              : 
      50            0 :     getGitName();
      51            0 :     getGitHash();
      52            0 :     getGitModified();
      53            0 :     getGitFileState();
      54            0 : }
      55              : 
      56            0 : std::string gitRepo::dir()
      57              : {
      58            0 :     return m_dir;
      59              : }
      60              : 
      61            0 : std::string gitRepo::gitDir()
      62              : {
      63            0 :     return m_dir + "/.git";
      64              : }
      65              : 
      66            0 : int gitRepo::getGitName()
      67              : {
      68              :     int retVal;
      69            0 :     std::vector<std::string> stdOut, stdErr;
      70              : 
      71            0 :     if( ipc::runCommand( retVal, stdOut, stdErr, { "git", "--git-dir=" + gitDir(), "rev-parse", "--show-toplevel" } ) <
      72              :         0 )
      73              :     {
      74            0 :         internal::mxlib_error_report(error_t::procerr, "error running git command" );
      75            0 :         return -1;
      76              :     }
      77              : 
      78            0 :     if( stdErr.size() > 0 )
      79              :     {
      80            0 :         internal::mxlib_error_report(error_t::procerr, "error returned by git" );
      81              : 
      82            0 :         for( size_t n = 0; n < stdErr.size(); ++n )
      83              :         {
      84            0 :             std::cerr << "err: " << stdErr[n] << "\n";
      85              :         }
      86              : 
      87            0 :         return -1;
      88              :     }
      89              : 
      90            0 :     if( stdOut.size() < 1 )
      91              :     {
      92            0 :         internal::mxlib_error_report(error_t::procerr, "nothing returned by git" );
      93            0 :         return -1;
      94              :     }
      95              : 
      96            0 :     if( stdOut.size() > 1 )
      97              :     {
      98            0 :         internal::mxlib_error_report(error_t::procerr, "too much returned by git" );
      99            0 :         return -1;
     100              :     }
     101              : 
     102            0 :     m_name = ioutils::pathFilename( stdOut[0] );
     103              : 
     104            0 :     return 0;
     105            0 : }
     106              : 
     107            0 : int gitRepo::getGitHash()
     108              : {
     109              :     int retVal;
     110            0 :     std::vector<std::string> stdOut, stdErr;
     111              : 
     112            0 :     if( ipc::runCommand( retVal,
     113              :                          stdOut,
     114              :                          stdErr,
     115            0 :                          { "git", "--git-dir=" + gitDir(), "--work-tree=" + dir(), "log", "-1", "--format=%H" } ) < 0 )
     116              :     {
     117            0 :         internal::mxlib_error_report(error_t::procerr, "error running git command" );
     118            0 :         return -1;
     119              :     }
     120              : 
     121            0 :     if( stdErr.size() > 0 )
     122              :     {
     123            0 :         internal::mxlib_error_report(error_t::procerr, "error returned by git" );
     124              : 
     125            0 :         for( size_t n = 0; n < stdErr.size(); ++n )
     126              :         {
     127            0 :             std::cerr << "err: " << stdErr[n] << "\n";
     128              :         }
     129              : 
     130            0 :         return -1;
     131              :     }
     132              : 
     133            0 :     if( stdOut.size() < 1 )
     134              :     {
     135            0 :        internal::mxlib_error_report(error_t::procerr, "nothing returned by git" );
     136            0 :         return -1;
     137              :     }
     138              : 
     139            0 :     if( stdOut.size() > 1 )
     140              :     {
     141            0 :         internal::mxlib_error_report(error_t::procerr, "too much returned by git" );
     142            0 :         return -1;
     143              :     }
     144              : 
     145            0 :     m_hash = stdOut[0];
     146              : 
     147            0 :     return 0;
     148            0 : }
     149              : 
     150            0 : int gitRepo::getGitModified()
     151              : {
     152              :     int retVal;
     153            0 :     std::vector<std::string> stdOut, stdErr;
     154              : 
     155            0 :     if( ipc::runCommand( retVal,
     156              :                          stdOut,
     157              :                          stdErr,
     158            0 :                          { "git", "--git-dir=" + gitDir(), "--work-tree=" + dir(), "diff-index", "HEAD", "--" } ) < 0 )
     159              :     {
     160            0 :         internal::mxlib_error_report(error_t::procerr, "error running git command" );
     161            0 :         return -1;
     162              :     }
     163              : 
     164            0 :     if( stdErr.size() > 0 )
     165              :     {
     166            0 :         internal::mxlib_error_report(error_t::procerr, "error returned by git" );
     167            0 :         for( size_t n = 0; n < stdErr.size(); ++n )
     168              :         {
     169            0 :             std::cerr << "err: " << stdErr[n] << "\n";
     170              :         }
     171              : 
     172            0 :         return -1;
     173              :     }
     174              : 
     175            0 :     m_modified = ( stdOut.size() > 0 ); // rv;
     176              : 
     177            0 :     return 0;
     178            0 : }
     179              : 
     180            0 : int gitRepo::getGitFileState()
     181              : {
     182              :     int retVal;
     183            0 :     std::vector<std::string> stdOut, stdErr;
     184              : 
     185            0 :     if( ipc::runCommand(
     186            0 :             retVal, stdOut, stdErr, { "git", "--git-dir=" + gitDir(), "--work-tree=" + dir(), "status" } ) < 0 )
     187              :     {
     188            0 :         internal::mxlib_error_report(error_t::procerr, "error running git command" );
     189            0 :         return -1;
     190              :     }
     191              : 
     192            0 :     if( stdErr.size() > 0 )
     193              :     {
     194            0 :         internal::mxlib_error_report(error_t::procerr, "error returned by git" );
     195              : 
     196            0 :         for( size_t n = 0; n < stdErr.size(); ++n )
     197              :         {
     198            0 :             std::cerr << "err: " << stdErr[n] << "\n";
     199              :         }
     200              : 
     201            0 :         return -1;
     202              :     }
     203              : 
     204            0 :     if( stdOut.size() < 1 )
     205              :     {
     206            0 :         internal::mxlib_error_report(error_t::procerr, "nothing returned by git" );
     207            0 :         return -1;
     208              :     }
     209              : 
     210            0 :     m_modifiedFiles.clear();
     211            0 :     m_deletedFiles.clear();
     212            0 :     m_renamedFiles.clear();
     213            0 :     m_renamedFiles2.clear();
     214            0 :     m_untrackedFiles.clear();
     215              : 
     216            0 :     for( size_t n = 0; n < stdOut.size(); ++n )
     217              :     {
     218            0 :         if( stdOut[n].find( "On b" ) != std::string::npos )
     219              :         {
     220            0 :             m_branch = stdOut[n].substr( sizeof( "On branch" ) );
     221              :         }
     222            0 :         else if( stdOut[n].find( "Changes not" ) != std::string::npos )
     223              :         {
     224              :             // Changes not staged for commit
     225              : 
     226            0 :             ++n;
     227            0 :             while( stdOut[n].size() > 0 )
     228              :             {
     229            0 :                 if( n >= stdOut.size() )
     230            0 :                     break;
     231              : 
     232            0 :                 if( stdOut[n].find( "mod" ) != std::string::npos )
     233              :                 {
     234            0 :                     m_modifiedFiles.insert( ioutils::removeWhiteSpace( stdOut[n].substr( sizeof( "modified:" ) ) ) );
     235              :                 }
     236            0 :                 else if( stdOut[n].find( "del" ) != std::string::npos )
     237              :                 {
     238            0 :                     m_deletedFiles.insert( ioutils::removeWhiteSpace( stdOut[n].substr( sizeof( "deleted:" ) ) ) );
     239              :                 }
     240            0 :                 else if( stdOut[n].find( "ren" ) != std::string::npos )
     241              :                 {
     242            0 :                     size_t a = stdOut[n].find( " -> " );
     243              : 
     244            0 :                     m_renamedFiles.insert( ioutils::removeWhiteSpace(
     245            0 :                         stdOut[n].substr( sizeof( "renamed:" ), a - sizeof( "renamed:" ) ) ) );
     246            0 :                     m_renamedFiles2.insert( ioutils::removeWhiteSpace( stdOut[n].substr( a + sizeof( " ->" ) ) ) );
     247              :                 }
     248            0 :                 ++n;
     249              :             }
     250              :         }
     251            0 :         else if( stdOut[n].find( "Changes to" ) != std::string::npos )
     252              :         {
     253              :             // Changes to be committed
     254              : 
     255            0 :             ++n;
     256            0 :             while( stdOut[n].size() > 0 )
     257              :             {
     258            0 :                 if( n >= stdOut.size() )
     259            0 :                     break;
     260              : 
     261            0 :                 if( stdOut[n].find( "mod" ) != std::string::npos )
     262              :                 {
     263            0 :                     m_modifiedFiles.insert( ioutils::removeWhiteSpace( stdOut[n].substr( sizeof( "modified:" ) ) ) );
     264              :                 }
     265            0 :                 else if( stdOut[n].find( "del" ) != std::string::npos )
     266              :                 {
     267            0 :                     m_deletedFiles.insert( ioutils::removeWhiteSpace( stdOut[n].substr( sizeof( "deleted:" ) ) ) );
     268              :                 }
     269            0 :                 else if( stdOut[n].find( "ren" ) != std::string::npos )
     270              :                 {
     271            0 :                     size_t a = stdOut[n].find( " -> " );
     272              : 
     273            0 :                     m_renamedFiles.insert( ioutils::removeWhiteSpace(
     274            0 :                         stdOut[n].substr( sizeof( "renamed:    " ), a - sizeof( "renamed:" ) ) ) );
     275            0 :                     m_renamedFiles2.insert( ioutils::removeWhiteSpace( stdOut[n].substr( a + sizeof( " ->" ) ) ) );
     276              :                 }
     277            0 :                 ++n;
     278              :             }
     279              :         }
     280            0 :         else if( stdOut[n].find( "Untracked" ) != std::string::npos )
     281              :         {
     282              :             // Untracked files:
     283              : 
     284            0 :             ++n;
     285            0 :             ++n;
     286            0 :             while( stdOut[n].size() > 0 )
     287              :             {
     288            0 :                 if( n >= stdOut.size() )
     289            0 :                     break;
     290            0 :                 m_untrackedFiles.insert( ioutils::removeWhiteSpace( stdOut[n] ) );
     291            0 :                 ++n;
     292              :             }
     293              :         }
     294              :     }
     295              : 
     296            0 :     return 0;
     297            0 : }
     298              : 
     299            0 : std::string gitRepo::name()
     300              : {
     301            0 :     return m_name;
     302              : }
     303              : 
     304            0 : std::string gitRepo::branch()
     305              : {
     306            0 :     return m_branch;
     307              : }
     308              : 
     309            0 : std::string gitRepo::hash()
     310              : {
     311            0 :     return m_hash;
     312              : }
     313              : 
     314            0 : bool gitRepo::modified()
     315              : {
     316            0 :     return m_modified;
     317              : }
     318              : 
     319            0 : bool gitRepo::isNotCommitted( const std::string &file )
     320              : {
     321            0 :     return ( m_modifiedFiles.count( file ) + m_deletedFiles.count( file ) + m_renamedFiles.count( file ) +
     322            0 :                  m_renamedFiles2.count( file ) + m_untrackedFiles.count( file ) >
     323            0 :              0 );
     324              : }
     325              : 
     326              : } // namespace sys
     327              : } // namespace mx
        

Generated by: LCOV version 2.0-1