9
9
"""
10
10
import argparse
11
11
import ipaddress
12
+ import json
12
13
import logging
13
14
import os
15
+ import shutil
14
16
import sys
15
17
import tempfile
16
18
@@ -63,8 +65,12 @@ def parse_args(args: Optional[Sequence[str]] = None) -> argparse.Namespace:
63
65
64
66
"""
65
67
parser = argparse .ArgumentParser (formatter_class = argparse .ArgumentDefaultsHelpFormatter )
66
- parser .add_argument ('-c' , '--config' , help = 'The config file to load.' , default = '/etc/dns-snippets.cfg ' )
68
+ parser .add_argument ('-c' , '--config' , help = 'The config file to load.' , default = '/etc/dns-snippets.ini ' )
67
69
parser .add_argument ('-v' , '--verbose' , help = 'Verbose mode.' , action = 'store_true' )
70
+ parser .add_argument ('-b' , '--batch' , action = 'store_true' ,
71
+ help = ('Enable the non-interactive mode, the commit will not be pushed to its remote and the '
72
+ 'temporary directory will not be deleted. A JSON with the path of the temporary '
73
+ 'directory and the SHA1 of the commit will be printed to the last line of stdout.' ))
68
74
parser .add_argument ('message' , help = 'The commit message to use.' )
69
75
70
76
return parser .parse_args (args )
@@ -208,18 +214,19 @@ def get_file_stats(tmpdir: str) -> Tuple[int, int]:
208
214
return files , lines
209
215
210
216
211
- def commit_changes (args : argparse .Namespace , working_repo : git .Repo ) -> Optional [Dict [ str , int ] ]:
217
+ def commit_changes (args : argparse .Namespace , working_repo : git .Repo ) -> Optional [git . objects . commit . Commit ]:
212
218
"""Add local changes and commit them, if any."""
213
219
working_repo .index .add ('*' )
214
- if not working_repo .index .diff (working_repo .head .commit ):
220
+ if working_repo . head . is_valid () and not working_repo .index .diff (working_repo .head .commit ):
215
221
logger .info ('Nothing to commit!' )
216
222
return None
217
223
218
224
author = git .Actor (GIT_USER_NAME , GIT_USER_EMAIL )
219
225
message = '{user}: {message}' .format (user = get_user_id (), message = args .message )
220
226
commit = working_repo .index .commit (message , author = author , committer = author )
227
+ logger .info ('Committed changes: %s' , commit .hexsha )
221
228
222
- return commit . stats . total
229
+ return commit
223
230
224
231
225
232
def validate_delta (changed : int , existing : int , warning : int , error : int , what : str ) -> None :
@@ -249,19 +256,27 @@ def run(args: argparse.Namespace, config: ConfigParser, tmpdir: str) -> int:
249
256
records = generate_records (devices , config .getint ('dns_snippets' , 'min_records' ))
250
257
working_repo = setup_repo (config , tmpdir )
251
258
files , lines = get_file_stats (tmpdir )
252
- working_repo .git .rm ('.' , r = True ) # Delete all existing files to ensure removal of stale files
259
+ working_repo .git .rm ('.' , r = True , ignore_unmatch = True ) # Delete all existing files to ensure removal of stale files
253
260
generate_snippets (records , tmpdir )
254
- delta = commit_changes (args , working_repo )
255
- if delta is None :
261
+ commit = commit_changes (args , working_repo )
262
+
263
+ if commit is None :
264
+ if args .batch :
265
+ print (json .dumps ({'no_changes' : True }))
256
266
return NO_CHANGES_RETURN_CODE
257
267
258
268
print (working_repo .git .show (['--color=always' , 'HEAD' ]))
259
- validate (files , lines , delta )
269
+ validate (files , lines , commit .stats .total )
270
+
271
+ if args .batch :
272
+ print (json .dumps ({'path' : tmpdir , 'sha1' : commit .hexsha }))
273
+ return 0
274
+
260
275
answer = input ('OK to push the changes to the {origin} repository? (y/n) ' .format (
261
276
origin = config .get ('dns_snippets' , 'repo_path' )))
262
277
if answer == 'y' :
263
278
push_info = working_repo .remote ().push ()[0 ]
264
- logger .info ('Pushed with %d flags : %s %s' , push_info .flags , push_info .summary .strip (), delta )
279
+ logger .info ('Pushed with bitflags %d : %s %s' , push_info .flags , push_info .summary .strip (), commit . stats . total )
265
280
exit_code = 0
266
281
else :
267
282
logger .error ('Manually aborted.' )
@@ -277,17 +292,22 @@ def main() -> int:
277
292
config = ConfigParser ()
278
293
config .read (args .config )
279
294
280
- with tempfile .TemporaryDirectory (prefix = 'dns-snippets-' ) as tmpdir :
281
- try :
282
- exit_code = run (args , config , tmpdir )
283
- except Exception :
284
- logger .exception ('Failed to run' )
285
- exit_code = 1
295
+ tmpdir = tempfile .mkdtemp (prefix = 'dns-snippets-' )
296
+ try :
297
+ exit_code = run (args , config , tmpdir )
286
298
299
+ except Exception :
300
+ logger .exception ('Failed to run' )
301
+ exit_code = 1
302
+
303
+ finally :
287
304
if exit_code not in (0 , NO_CHANGES_RETURN_CODE ):
288
305
print ('An error occurred, the generated files can be inspected in {tmpdir}' .format (tmpdir = tmpdir ))
289
306
input ('Press any key to cleanup the generated files and exit ' )
290
307
308
+ if not args .batch or exit_code == NO_CHANGES_RETURN_CODE :
309
+ shutil .rmtree (tmpdir , ignore_errors = True )
310
+
291
311
return exit_code
292
312
293
313
0 commit comments