2020import sys
2121import re
2222import subprocess
23+ import threading
2324import tarfile
2425
2526import speakreader
@@ -51,7 +52,7 @@ def __init__(self):
5152 if os .path .isdir (os .path .join (speakreader .PROG_DIR , '.git' )):
5253 self .INSTALL_TYPE = 'git'
5354
54- output , err = runGit ('rev-parse HEAD' )
55+ output , err = self . runGit ('rev-parse HEAD' )
5556 if output :
5657 if re .match ('^[a-z0-9]+$' , output ):
5758 self .INSTALLED_VERSION_HASH = output
@@ -66,7 +67,7 @@ def __init__(self):
6667 if speakreader .CONFIG .DO_NOT_OVERRIDE_GIT_BRANCH and speakreader .CONFIG .GIT_BRANCH :
6768 self .BRANCH_NAME = speakreader .CONFIG .GIT_BRANCH
6869 else :
69- remote_branch , err = runGit ('rev-parse --abbrev-ref --symbolic-full-name @{u}' )
70+ remote_branch , err = self . runGit ('rev-parse --abbrev-ref --symbolic-full-name @{u}' )
7071 remote_branch = remote_branch .rsplit ('/' , 1 ) if remote_branch else []
7172 if len (remote_branch ) == 2 :
7273 self .REMOTE_NAME , self .BRANCH_NAME = remote_branch
@@ -87,6 +88,9 @@ def __init__(self):
8788 logger .error ('Could not retrieve branch name from git. Defaulting to master.' )
8889 self .BRANCH_NAME = 'master'
8990
91+ speakreader .CONFIG .GIT_REMOTE = self .REMOTE_NAME
92+ speakreader .CONFIG .GIT_BRANCH = self .BRANCH_NAME
93+
9094 else :
9195 self .INSTALL_TYPE = 'source'
9296 self .REMOTE_NAME = 'origin'
@@ -273,20 +277,20 @@ def update(self):
273277
274278 if self .INSTALL_TYPE == 'git' :
275279
276- output , err = runGit ('diff --name-only %s' % speakreader .CONFIG .GIT_REMOTE )
280+ output , err = self . runGit ('diff --name-only %s/%s ' % ( speakreader .CONFIG .GIT_REMOTE , speakreader . CONFIG . GIT_BRANCH ) )
277281
278282 if output == '' :
279283 logger .debug ("No differences found from the origin" )
280284
281285 elif output == 'requirements.txt' :
282286 logger .warn ('Requirements file is out of sync. Restoring to original.' )
283- output , err = runGit ('checkout %s/%s requirements.txt' % (speakreader .CONFIG .GIT_REMOTE , speakreader .CONFIG .GIT_BRANCH ))
287+ output , err = self . runGit ('checkout %s/%s requirements.txt' % (speakreader .CONFIG .GIT_REMOTE , speakreader .CONFIG .GIT_BRANCH ))
284288 else :
285289 logger .error ("Differences Found. Unable to update." )
286290 logger .info ('Output: ' + str (output ))
287291 return False
288292
289- output , err = runGit ('pull ' + speakreader .CONFIG .GIT_REMOTE + ' ' + speakreader .CONFIG .GIT_BRANCH )
293+ output , err = self . runGit ('pull ' + speakreader .CONFIG .GIT_REMOTE + ' ' + speakreader .CONFIG .GIT_BRANCH )
290294
291295 if not output :
292296 logger .error ('Unable to download latest version' )
@@ -362,14 +366,14 @@ def update(self):
362366 logger .error ("Unable to write current version to version.txt, update not complete: %s" % e )
363367 return False
364368
365- output , err = pip_sync ()
369+ self . pip_sync ()
366370 logger .info ("Update Complete" )
367371 return True
368372
369373 def checkout_git_branch (self ):
370374 if self .INSTALL_TYPE == 'git' :
371- output , err = runGit ('fetch %s' % speakreader .CONFIG .GIT_REMOTE )
372- output , err = runGit ('checkout %s' % speakreader .CONFIG .GIT_BRANCH )
375+ output , err = self . runGit ('fetch %s' % speakreader .CONFIG .GIT_REMOTE )
376+ output , err = self . runGit ('checkout %s' % speakreader .CONFIG .GIT_BRANCH )
373377
374378 if not output :
375379 logger .error ('Unable to change git branch.' )
@@ -380,8 +384,8 @@ def checkout_git_branch(self):
380384 logger .error ('Unable to checkout from git: ' + line )
381385 logger .info ('Output: ' + str (output ))
382386
383- output , err = runGit ('pull %s %s' % (speakreader .CONFIG .GIT_REMOTE , speakreader .CONFIG .GIT_BRANCH ))
384- output , err = pip_sync ()
387+ output , err = self . runGit ('pull %s %s' % (speakreader .CONFIG .GIT_REMOTE , speakreader .CONFIG .GIT_BRANCH ))
388+ self . pip_sync ()
385389
386390
387391 def read_changelog (self , latest_only = False , since_prev_release = False ):
@@ -449,76 +453,82 @@ def read_changelog(self, latest_only=False, since_prev_release=False):
449453 return '<h4>Unable to open changelog file</h4>'
450454
451455
452- def runGit (args ):
453- if speakreader .CONFIG .GIT_PATH :
454- git_locations = ['"' + speakreader .CONFIG .GIT_PATH + '"' ]
455- else :
456- git_locations = ['git' ]
456+ def runGit (self , args ):
457+ if speakreader .CONFIG .GIT_PATH :
458+ git_locations = ['"' + speakreader .CONFIG .GIT_PATH + '"' ]
459+ else :
460+ git_locations = ['git' ]
457461
458- output = err = None
462+ output = err = None
459463
460- for cur_git in git_locations :
461- cmd = cur_git + ' ' + args
464+ for cur_git in git_locations :
465+ cmd = cur_git + ' ' + args
462466
467+ try :
468+ logger .debug ('Trying to execute: "' + cmd + '" with shell in ' + speakreader .PROG_DIR )
469+ p = subprocess .Popen (cmd , stdout = subprocess .PIPE , stderr = subprocess .STDOUT , shell = True ,
470+ cwd = speakreader .PROG_DIR )
471+ output , err = p .communicate ()
472+ output = output .decode ('utf-8' ).strip ()
473+
474+ for line in output .split ('\n ' ):
475+ if line :
476+ logger .debug ('Git output: ' + line )
477+
478+ except OSError :
479+ logger .debug ('Command failed: %s' , cmd )
480+ continue
481+
482+ if 'not found' in output or "not recognized as an internal or external command" in output :
483+ logger .debug ('Unable to find git with command ' + cmd )
484+ output = None
485+ elif 'fatal:' in output or err :
486+ logger .error ('Git returned bad info. Are you sure this is a git installation?' )
487+ output = None
488+ elif output :
489+ break
490+
491+ return (output , err )
492+
493+
494+ def pip_sync (self ):
495+ """
496+ Run pip install requirements first because running pip-sync will fail if pip-tools gets updated.
497+ """
463498 try :
464- logger .debug ('Trying to execute: "' + cmd + '" with shell in ' + speakreader .PROG_DIR )
465- p = subprocess .Popen (cmd , stdout = subprocess .PIPE , stderr = subprocess .STDOUT , shell = True ,
466- cwd = speakreader .PROG_DIR )
467- output , err = p .communicate ()
468- output = output .decode ('utf-8' ).strip ()
499+ logger .info ("Running pip install requirements to update the environment." )
500+ cmd = sys .executable + ' -m pip install -r requirements.txt'
501+ output = self ._exec_command (cmd )
502+ for line in output :
503+ logger .info ('pip output: %s' % line )
504+
505+ logger .info ("Running pip-sync to synchronize the environment." )
506+ cmd = sys .executable + ' -m piptools sync requirements.txt'
507+ output = self ._exec_command (cmd )
508+ for line in output :
509+ logger .info ('pip-sync output: %s' % line )
469510
470- for line in output .split ('\n ' ):
471- if line :
472- logger .debug ('Git output: ' + line )
473-
474- except OSError :
475- logger .debug ('Command failed: %s' , cmd )
476- continue
477-
478- if 'not found' in output or "not recognized as an internal or external command" in output :
479- logger .debug ('Unable to find git with command ' + cmd )
480- output = None
481- elif 'fatal:' in output or err :
482- logger .error ('Git returned bad info. Are you sure this is a git installation?' )
483- output = None
484- elif output :
485- break
486-
487- return (output , err )
488-
489-
490- def pip_sync ():
491- """
492- Run pip install requirements first because running pip-sync will fail if pip-tools gets updated.
493- """
494- logger .info ("Running pip install for requirements update to synchronize the environment." )
495- cmd = sys .executable + ' -m pip install -r requirements.txt'
496- try :
497- logger .debug ('Trying to execute: "' + cmd + '" with shell in ' + speakreader .PROG_DIR )
498- p = subprocess .Popen (cmd , stdout = subprocess .PIPE , stderr = subprocess .STDOUT , shell = True ,
499- cwd = speakreader .PROG_DIR )
500- output , err = p .communicate ()
501- for line in output .decode ('utf-8' ).split ('\n ' ):
502- if line :
503- logger .info ('pip output: ' + str (line ))
504-
505- except Exception as e :
506- logger .error ('Command failed: %s' % e )
507- return None , None
508-
509- logger .info ("Running pip-sync to synchronize the environment." )
510- cmd = sys .executable + ' -m piptools sync requirements.txt'
511- try :
512- logger .debug ('Trying to execute: "' + cmd + '" with shell in ' + speakreader .PROG_DIR )
513- p = subprocess .Popen (cmd , stdout = subprocess .PIPE , stderr = subprocess .STDOUT , shell = True ,
514- cwd = speakreader .PROG_DIR )
515- output , err = p .communicate ()
516- for line in output .decode ('utf-8' ).split ('\n ' ):
517- if line :
518- logger .info ('pip-sync output: ' + str (line ))
519-
520- except Exception as e :
521- logger .error ('Command failed: %s' % e )
522- return None , None
523-
524- return (output , err )
511+ except Exception as e :
512+ logger .error ('Command failed: %s' % e )
513+ return None , None
514+
515+
516+ def _exec_command (self , cmd , cwd = None ):
517+ if cwd is None :
518+ cwd = speakreader .PROG_DIR
519+ logger .debug ('Trying to execute: "' + cmd + '" with shell in ' + cwd )
520+ p = subprocess .Popen (
521+ cmd , stdout = subprocess .PIPE , stderr = subprocess .STDOUT , cwd = cwd , shell = True
522+ )
523+
524+ while True :
525+ out = p .stdout .readline ().decode ('utf-8' ).replace ('\r ' , '' ).replace ('\n ' , '' )
526+ return_code = p .poll ()
527+ if out == '' and return_code is not None :
528+ break
529+
530+ if out != '' :
531+ yield out
532+
533+ if return_code :
534+ raise subprocess .CalledProcessError (return_code , cmd )
0 commit comments