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
|