from __future__ import absolute_import
from binascii import hexlify, unhexlify
-import errno, os, re, struct, time, zlib
+import os, re, struct, time, zlib
import socket
from bup import git, ssh, vfs
-from bup.compat import environ, range, reraise
+from bup.compat import environ, pending_raise, range, reraise
from bup.helpers import (Conn, atomically_replaced_file, chunkyreader, debug1,
debug2, linereader, lines_until_sentinel,
- mkdirp, progress, qprogress, DemuxConn)
+ mkdirp, nullcontext_if_not, progress, qprogress, DemuxConn)
from bup.io import path_msg
from bup.vint import write_bvec
class Client:
def __init__(self, remote, create=False):
+ self.closed = False
self._busy = self.conn = None
self.sock = self.p = self.pout = self.pin = None
is_reverse = environ.get(b'BUP_SERVER_REVERSE')
self.check_ok()
self.sync_indexes()
- def __del__(self):
- try:
- self.close()
- except IOError as e:
- if e.errno == errno.EPIPE:
- pass
- else:
- raise
-
def close(self):
+ self.closed = True
if self.conn and not self._busy:
self.conn.write(b'quit\n')
if self.pin:
self.conn = None
self.sock = self.p = self.pin = self.pout = None
+ def __del__(self):
+ assert self.closed
+
+ def __enter__(self):
+ return self
+
+ def __exit__(self, type, value, traceback):
+ with pending_raise(value, rethrow=False):
+ self.close()
+
def check_ok(self):
if self.p:
rv = self.p.poll()
return self.conn.check_ok()
except Exception as e:
reraise(ClientError(e))
+ # reraise doesn't return
+ return None
def check_busy(self):
if self._busy:
raise ClientError('already busy with command %r' % self._busy)
-
+
def ensure_busy(self):
if not self._busy:
raise ClientError('expected to be busy, but not busy?!')
-
+
def _not_busy(self):
self._busy = None
return result
+# FIXME: disentangle this (stop inheriting) from PackWriter
class PackWriter_Remote(git.PackWriter):
+
def __init__(self, conn, objcache_maker, suggest_packs,
onopen, onclose,
ensure_busy,
compression_level=compression_level,
max_pack_size=max_pack_size,
max_pack_objects=max_pack_objects)
+ self.remote_closed = False
self.file = conn
self.filename = b'remote socket'
self.suggest_packs = suggest_packs
self._bwcount = 0
self._bwtime = time.time()
+ # __enter__ and __exit__ are inherited
+
def _open(self):
if not self._packopen:
self.onopen()
self._packopen = True
def _end(self, run_midx=True):
+ # Called by other PackWriter methods like breakpoint().
+ # Must not close the connection (self.file)
assert(run_midx) # We don't support this via remote yet
- if self._packopen and self.file:
+ self.objcache, objcache = None, self.objcache
+ with nullcontext_if_not(objcache):
+ if not (self._packopen and self.file):
+ return None
self.file.write(b'\0\0\0\0')
self._packopen = False
self.onclose() # Unbusy
- self.objcache = None
+ if objcache is not None:
+ objcache.close()
return self.suggest_packs() # Returns last idx received
def close(self):
+ # Called by inherited __exit__
+ self.remote_closed = True
id = self._end()
self.file = None
return id
+ def __del__(self):
+ assert self.remote_closed
+ super(PackWriter_Remote, self).__del__()
+
def abort(self):
raise ClientError("don't know how to abort remote pack writing")