original_docstring: 
      Encapsulates Pyforce, does book keeping to ensure that all files
      that should be operated on are in fact dealt with by p4. Handles
      retry and strips out asks for files that are caseful mismatches on
      the current file system (macOS).
      
docstring: Encapsulates Pyforce, does book keeping to ensure that all files
  that should be operated on are in fact dealt with by p4. Handles
  retry and strips out asks for files that are caseful mismatches on
  the current file system (macOS).
docstring_tokens: Encapsulates Pyforce does book keeping to ensure that all files that should be operated on are in fact dealt with by p4 . Handles retry and strips out asks for files that are caseful mismatches on the current file system ( macOS ) .
code: def o4_pyforce(debug, no_revision, args: list, quiet=False):
      """
      Encapsulates Pyforce, does book keeping to ensure that all files
      that should be operated on are in fact dealt with by p4. Handles
      retry and strips out asks for files that are caseful mismatches on
      the current file system (macOS).
      """
  
      from collections import defaultdict
  
      class LogAndAbort(Exception):
          'Dumps debug information on errors.'
  
      o4_log('pyforce', no_revision=no_revision, quiet=quiet, *args)
  
      tmpf = NamedTemporaryFile(dir='.o4')
      fstats = []
      for line in sys.stdin.read().splitlines():
          if line.startswith('#o4pass'):
              print(line)
              continue
          f = fstat_split(line)
          if f and caseful_accurate(f[F_PATH]):
              fstats.append(f)
          elif f:
              print(f"*** WARNING: Pyforce is skipping {f[F_PATH]} because it is casefully",
                    "mismatching a local file.",
                    file=sys.stderr)
      retries = 3
      head = _depot_path().replace('/...', '')
      client_head = _client_path().replace('/...', '')
      while fstats:
          if no_revision:
              p4paths = [Pyforce.escape(f[F_PATH]) for f in fstats]
          else:
              p4paths = []
              for f in fstats:
                  rev = f[F_REVISION]
                  if rev == 'USECL':
                      p4paths.append(f"{Pyforce.escape(f[F_PATH])}@{f[F_CHANGELIST]}")
                  else:
                      p4paths.append(f"{Pyforce.escape(f[F_PATH])}#{f[F_REVISION]}")
          tmpf.seek(0)
          tmpf.truncate()
          pargs = []
          xargs = []
          queued_prints = []  # Print the fstats after the p4 process has ended, because p4 marshals
          # its objects before operation, as in "And for my next act... !"
          # This premature printing leads to false checksum errors during sync.
          # This is a really bad idea, p4 prints filenames before the actual
          # sync happens, causing checksum tests to start too early:
          #        if len(p4paths) > 30 and 'sync' in args:
          #            xargs.append('--parallel=threads=5')
          if sum(len(s) for s in p4paths) > 30000:
              pargs.append('-x')
              pargs.append(tmpf.name)
              for f in p4paths:
                  tmpf.write(f.encode('utf8'))
                  tmpf.write(b'\n')
              tmpf.flush()
          else:
              xargs.extend(p4paths)
          try:
              # TODO: Verbose
              #print('# PYFORCE({}, {}{})'.format(','.join(repr(a) for a in args), ','.join(
              #    repr(a) for a in paths[:3]), ', ...' if len(paths) > 3 else ''))
              errs = []
              repeats = defaultdict(list)
              infos = []
              for res in Pyforce(*pargs, *args, *xargs):
                  if debug:
                      err_print("*** DEBUG: Received", repr(res))
                  # FIXME: Delete this if-statement:
                  if res.get('code', '') == 'info':
                      infos.append(res)
                      if res.get('data', '').startswith('Diff chunks: '):
                          continue
                  if res.get('code', '') == 'error':
                      errs.append(res)
                      continue
                  if 'resolveFlag' in res:
                      # TODO: resolveFlag can be ...?
                      #         m: merge
                      #         c: copy from  (not conflict!)
                      # We skip this entry as it is the second returned from p4
                      # for one input file
                      continue
                  res_str = res.get('depotFile') or res.get('fromFile')
                  if not res_str and res.get('data'):
                      res_str = client_path_to_depot_path(res['data']) or f'{head}/{res["data"]}'
  
                  if not res_str:
                      errs.append(res)
                      continue
                  res_str = Pyforce.unescape(res_str)
                  for i, f in enumerate(fstats):
                      path = f'{head}/{f[F_PATH]}'
                      if path in res_str:
                          repeats[path].append(res)
                          fstats.pop(i)
                          if res['code'] != 'mute':
                              queued_prints.append(f)
                          if '- resolve skipped' in res.get('data', ''):
                              if p4_operation(path, f[F_REVISION]).startswith('move/'):
                                  print(f'#o4pass-err#But {path} was renamed')
                          break
                  else:
                      for f in repeats.keys():
                          if f in res_str:
                              if debug:
                                  err_print(f"*** DEBUG: REPEAT: {res_str}\n {res}\n {repeats[f]}")
                              break
                      else:
                          if debug:
                              err_print("*** DEBUG: ERRS APPEND", res)
                          errs.append(res)
              if errs:
                  raise LogAndAbort('Unexpected reply from p4')
  
              if len(p4paths) == len(fstats):
                  raise LogAndAbort('Nothing recognized from p4')
          except P4Error as e:
              non_recoverable = False
              for a in e.args:
                  if 'clobber writable file' in a['data']:
                      fname = a['data'].split('clobber writable file')[1].strip()
                      if os.path.exists(fname + '.bak'):
                          now = time.time()
                          print(f"#o4pass-info#Moved previous .bak to {fname}.bak.{now}")
                          os.rename(fname + '.bak', f'{fname}.bak.{now}')
                      print(f"#o4pass-info#Writable file {fname} copied to .bak")
                      shutil.copy(fname, fname + '.bak')
                      os.chmod(fname, 0o400)
                  else:
                      print(f"#o4pass-err#{a['data']}")
                      non_recoverable = True
              if non_recoverable:
                  raise
          except P4TimeoutError as e:
              e = str(e).replace('\n', ' ')
              print(f"# P4 TIMEOUT, RETRIES {retries}: {e}", file=sys.stderr)
              retries -= 1
              if not retries:
                  sys.exit(f"{CLR}*** ERROR: Perforce timed out too many times:\n{e}")
          except LogAndAbort as e:
              import json
              fname = f'debug-pyforce.{os.getpid()}.{int(time.time())}'
              d = {
                  'args': args,
                  'fstats': fstats,
                  'errs': errs,
                  'repeats': repeats,
                  'infos': infos,
              }
              json.dump(d, open(f'.o4/{fname}', 'wt'))
              sys.exit(f'{CLR}*** ERROR: {e}; detail in {fname}')
          finally:
              if not quiet:
                  for fstat in queued_prints:
                      print(fstat_join(fstat))
code_tokens: def o4_pyforce ( debug , no_revision , args : list , quiet = False ) : from collections import defaultdict class LogAndAbort ( Exception ) : 'Dumps debug information on errors.' o4_log ( 'pyforce' , no_revision = no_revision , quiet = quiet , * args ) tmpf = NamedTemporaryFile ( dir = '.o4' ) fstats = [ ] for line in sys . stdin . read ( ) . splitlines ( ) : if line . startswith ( '#o4pass' ) : print ( line ) continue f = fstat_split ( line ) if f and caseful_accurate ( f [ F_PATH ] ) : fstats . append ( f ) elif f : print ( f"*** WARNING: Pyforce is skipping {f[F_PATH]} because it is casefully" , "mismatching a local file." , file = sys . stderr ) retries = 3 head = _depot_path ( ) . replace ( '/...' , '' ) client_head = _client_path ( ) . replace ( '/...' , '' ) while fstats : if no_revision : p4paths = [ Pyforce . escape ( f [ F_PATH ] ) for f in fstats ] else : p4paths = [ ] for f in fstats : rev = f [ F_REVISION ] if rev == 'USECL' : p4paths . append ( f"{Pyforce.escape(f[F_PATH])}@{f[F_CHANGELIST]}" ) else : p4paths . append ( f"{Pyforce.escape(f[F_PATH])}#{f[F_REVISION]}" ) tmpf . seek ( 0 ) tmpf . truncate ( ) pargs = [ ] xargs = [ ] queued_prints = [ ] if sum ( len ( s ) for s in p4paths ) > 30000 : pargs . append ( '-x' ) pargs . append ( tmpf . name ) for f in p4paths : tmpf . write ( f . encode ( 'utf8' ) ) tmpf . write ( b'\n' ) tmpf . flush ( ) else : xargs . extend ( p4paths ) try : errs = [ ] repeats = defaultdict ( list ) infos = [ ] for res in Pyforce ( * pargs , * args , * xargs ) : if debug : err_print ( "*** DEBUG: Received" , repr ( res ) ) if res . get ( 'code' , '' ) == 'info' : infos . append ( res ) if res . get ( 'data' , '' ) . startswith ( 'Diff chunks: ' ) : continue if res . get ( 'code' , '' ) == 'error' : errs . append ( res ) continue if 'resolveFlag' in res : continue res_str = res . get ( 'depotFile' ) or res . get ( 'fromFile' ) if not res_str and res . get ( 'data' ) : res_str = client_path_to_depot_path ( res [ 'data' ] ) or f'{head}/{res["data"]}' if not res_str : errs . append ( res ) continue res_str = Pyforce . unescape ( res_str ) for i , f in enumerate ( fstats ) : path = f'{head}/{f[F_PATH]}' if path in res_str : repeats [ path ] . append ( res ) fstats . pop ( i ) if res [ 'code' ] != 'mute' : queued_prints . append ( f ) if '- resolve skipped' in res . get ( 'data' , '' ) : if p4_operation ( path , f [ F_REVISION ] ) . startswith ( 'move/' ) : print ( f'#o4pass-err#But {path} was renamed' ) break else : for f in repeats . keys ( ) : if f in res_str : if debug : err_print ( f"*** DEBUG: REPEAT: {res_str}\n {res}\n {repeats[f]}" ) break else : if debug : err_print ( "*** DEBUG: ERRS APPEND" , res ) errs . append ( res ) if errs : raise LogAndAbort ( 'Unexpected reply from p4' ) if len ( p4paths ) == len ( fstats ) : raise LogAndAbort ( 'Nothing recognized from p4' ) except P4Error as e : non_recoverable = False for a in e . args : if 'clobber writable file' in a [ 'data' ] : fname = a [ 'data' ] . split ( 'clobber writable file' ) [ 1 ] . strip ( ) if os . path . exists ( fname + '.bak' ) : now = time . time ( ) print ( f"#o4pass-info#Moved previous .bak to {fname}.bak.{now}" ) os . rename ( fname + '.bak' , f'{fname}.bak.{now}' ) print ( f"#o4pass-info#Writable file {fname} copied to .bak" ) shutil . copy ( fname , fname + '.bak' ) os . chmod ( fname , 0o400 ) else : print ( f"#o4pass-err#{a['data']}" ) non_recoverable = True if non_recoverable : raise except P4TimeoutError as e : e = str ( e ) . replace ( '\n' , ' ' ) print ( f"# P4 TIMEOUT, RETRIES {retries}: {e}" , file = sys . stderr ) retries -= 1 if not retries : sys . exit ( f"{CLR}*** ERROR: Perforce timed out too many times:\n{e}" ) except LogAndAbort as e : import json fname = f'debug-pyforce.{os.getpid()}.{int(time.time())}' d = { 'args' : args , 'fstats' : fstats , 'errs' : errs , 'repeats' : repeats , 'infos' : infos , } json . dump ( d , open ( f'.o4/{fname}' , 'wt' ) ) sys . exit ( f'{CLR}*** ERROR: {e}; detail in {fname}' ) finally : if not quiet : for fstat in queued_prints : print ( fstat_join ( fstat ) )
short_docstring: Encapsulates Pyforce, does book keeping to ensure that all files
  that should be operated on are in fact dealt with by p4.
short_docstring_tokens: Encapsulates Pyforce does book keeping to ensure that all files that should be operated on are in fact dealt with by p4 .
comment: """
      Encapsulates Pyforce, does book keeping to ensure that all files
      that should be operated on are in fact dealt with by p4. Handles
      retry and strips out asks for files that are caseful mismatches on
      the current file system (macOS).
      """$SEP$'Dumps debug information on errors.'$SEP$# Print the fstats after the p4 process has ended, because p4 marshals$SEP$# its objects before operation, as in "And for my next act... !"$SEP$# This premature printing leads to false checksum errors during sync.$SEP$# This is a really bad idea, p4 prints filenames before the actual$SEP$# sync happens, causing checksum tests to start too early:$SEP$#        if len(p4paths) > 30 and 'sync' in args:$SEP$#            xargs.append('--parallel=threads=5')$SEP$# TODO: Verbose$SEP$#print('# PYFORCE({}, {}{})'.format(','.join(repr(a) for a in args), ','.join($SEP$#    repr(a) for a in paths[:3]), ', ...' if len(paths) > 3 else ''))$SEP$# FIXME: Delete this if-statement:$SEP$# TODO: resolveFlag can be ...?$SEP$#         m: merge$SEP$#         c: copy from  (not conflict!)$SEP$# We skip this entry as it is the second returned from p4$SEP$# for one input file