Esempio n. 1
0
 def serve(self, thread_name_suffix=''):
     self._should_terminate = False
     # for hooks we are letting code know that a server has started (and
     # later stopped).
     # There are three interesting urls:
     # The URL the server can be contacted on. (e.g. bzr://host/)
     # The URL that a commit done on the same machine as the server will
     # have within the servers space. (e.g. file:///home/user/source)
     # The URL that will be given to other hooks in the same process -
     # the URL of the backing transport itself. (e.g. chroot+:///)
     # We need all three because:
     #  * other machines see the first
     #  * local commits on this machine should be able to be mapped to
     #    this server 
     #  * commits the server does itself need to be mapped across to this
     #    server.
     # The latter two urls are different aliases to the servers url,
     # so we group those in a list - as there might be more aliases 
     # in the future.
     backing_urls = [self.backing_transport.base]
     try:
         backing_urls.append(self.backing_transport.external_url())
     except errors.InProcessTransport:
         pass
     for hook in SmartTCPServer.hooks['server_started']:
         hook(backing_urls, self.get_url())
     self._started.set()
     try:
         try:
             while not self._should_terminate:
                 try:
                     conn, client_addr = self._server_socket.accept()
                 except self._socket_timeout:
                     # just check if we're asked to stop
                     pass
                 except self._socket_error, e:
                     # if the socket is closed by stop_background_thread
                     # we might get a EBADF here, any other socket errors
                     # should get logged.
                     if e.args[0] != errno.EBADF:
                         trace.warning("listening socket error: %s", e)
                 else:
                     self.serve_conn(conn, thread_name_suffix)
         except KeyboardInterrupt:
             # dont log when CTRL-C'd.
             raise
         except Exception, e:
             trace.error("Unhandled smart server error.")
             trace.log_exception_quietly()
             raise
     finally:
         self._stopped.set()
         try:
             # ensure the server socket is closed.
             self._server_socket.close()
         except self._socket_error:
             # ignore errors on close
             pass
         for hook in SmartTCPServer.hooks['server_stopped']:
             hook(backing_urls, self.get_url())
Esempio n. 2
0
 def wrapped(*args, **kwargs):
     try:
         return unbound(*args, **kwargs)
     except errors:
         raise
     except:
         trace.mutter('Error suppressed by only_raises:')
         trace.log_exception_quietly()
Esempio n. 3
0
 def wrapped(*args, **kwargs):
     try:
         return unbound(*args, **kwargs)
     except errors:
         raise
     except:
         trace.mutter('Error suppressed by only_raises:')
         trace.log_exception_quietly()
Esempio n. 4
0
def _translate_error(err):
    if isinstance(err, errors.NoSuchFile):
        return ('NoSuchFile', err.path)
    elif isinstance(err, errors.FileExists):
        return ('FileExists', err.path)
    elif isinstance(err, errors.DirectoryNotEmpty):
        return ('DirectoryNotEmpty', err.path)
    elif isinstance(err, errors.IncompatibleRepositories):
        return ('IncompatibleRepositories', str(err.source), str(err.target),
            str(err.details))
    elif isinstance(err, errors.ShortReadvError):
        return ('ShortReadvError', err.path, str(err.offset), str(err.length),
                str(err.actual))
    elif isinstance(err, errors.RevisionNotPresent):
        return ('RevisionNotPresent', err.revision_id, err.file_id)
    elif isinstance(err, errors.UnstackableRepositoryFormat):
        return (('UnstackableRepositoryFormat', str(err.format), err.url))
    elif isinstance(err, errors.UnstackableBranchFormat):
        return ('UnstackableBranchFormat', str(err.format), err.url)
    elif isinstance(err, errors.NotStacked):
        return ('NotStacked',)
    elif isinstance(err, errors.BzrCheckError):
        return ('BzrCheckError', err.msg)
    elif isinstance(err, UnicodeError):
        # If it is a DecodeError, than most likely we are starting
        # with a plain string
        str_or_unicode = err.object
        if isinstance(str_or_unicode, unicode):
            # XXX: UTF-8 might have \x01 (our protocol v1 and v2 seperator
            # byte) in it, so this encoding could cause broken responses.
            # Newer clients use protocol v3, so will be fine.
            val = 'u:' + str_or_unicode.encode('utf-8')
        else:
            val = 's:' + str_or_unicode.encode('base64')
        # This handles UnicodeEncodeError or UnicodeDecodeError
        return (err.__class__.__name__, err.encoding, val, str(err.start),
                str(err.end), err.reason)
    elif isinstance(err, errors.TransportNotPossible):
        if err.msg == "readonly transport":
            return ('ReadOnlyError', )
    elif isinstance(err, errors.ReadError):
        # cannot read the file
        return ('ReadError', err.path)
    elif isinstance(err, errors.PermissionDenied):
        return ('PermissionDenied', err.path, err.extra)
    elif isinstance(err, errors.TokenMismatch):
        return ('TokenMismatch', err.given_token, err.lock_token)
    elif isinstance(err, errors.LockContention):
        return ('LockContention',)
    elif isinstance(err, MemoryError):
        # GZ 2011-02-24: Copy bzrlib.trace -Dmem_dump functionality here?
        return ('MemoryError',)
    # Unserialisable error.  Log it, and return a generic error
    trace.log_exception_quietly()
    return ('error', trace._qualified_exception_name(err.__class__, True),
        str(err))
Esempio n. 5
0
def _translate_error(err):
    if isinstance(err, errors.NoSuchFile):
        return ('NoSuchFile', err.path)
    elif isinstance(err, errors.FileExists):
        return ('FileExists', err.path)
    elif isinstance(err, errors.DirectoryNotEmpty):
        return ('DirectoryNotEmpty', err.path)
    elif isinstance(err, errors.IncompatibleRepositories):
        return ('IncompatibleRepositories', str(err.source), str(err.target),
                str(err.details))
    elif isinstance(err, errors.ShortReadvError):
        return ('ShortReadvError', err.path, str(err.offset), str(err.length),
                str(err.actual))
    elif isinstance(err, errors.RevisionNotPresent):
        return ('RevisionNotPresent', err.revision_id, err.file_id)
    elif isinstance(err, errors.UnstackableRepositoryFormat):
        return (('UnstackableRepositoryFormat', str(err.format), err.url))
    elif isinstance(err, errors.UnstackableBranchFormat):
        return ('UnstackableBranchFormat', str(err.format), err.url)
    elif isinstance(err, errors.NotStacked):
        return ('NotStacked', )
    elif isinstance(err, errors.BzrCheckError):
        return ('BzrCheckError', err.msg)
    elif isinstance(err, UnicodeError):
        # If it is a DecodeError, than most likely we are starting
        # with a plain string
        str_or_unicode = err.object
        if isinstance(str_or_unicode, unicode):
            # XXX: UTF-8 might have \x01 (our protocol v1 and v2 seperator
            # byte) in it, so this encoding could cause broken responses.
            # Newer clients use protocol v3, so will be fine.
            val = 'u:' + str_or_unicode.encode('utf-8')
        else:
            val = 's:' + str_or_unicode.encode('base64')
        # This handles UnicodeEncodeError or UnicodeDecodeError
        return (err.__class__.__name__, err.encoding, val, str(err.start),
                str(err.end), err.reason)
    elif isinstance(err, errors.TransportNotPossible):
        if err.msg == "readonly transport":
            return ('ReadOnlyError', )
    elif isinstance(err, errors.ReadError):
        # cannot read the file
        return ('ReadError', err.path)
    elif isinstance(err, errors.PermissionDenied):
        return ('PermissionDenied', err.path, err.extra)
    elif isinstance(err, errors.TokenMismatch):
        return ('TokenMismatch', err.given_token, err.lock_token)
    elif isinstance(err, errors.LockContention):
        return ('LockContention', )
    elif isinstance(err, MemoryError):
        # GZ 2011-02-24: Copy bzrlib.trace -Dmem_dump functionality here?
        return ('MemoryError', )
    # Unserialisable error.  Log it, and return a generic error
    trace.log_exception_quietly()
    return ('error', trace._qualified_exception_name(err.__class__,
                                                     True), str(err))
Esempio n. 6
0
 def _parse_json_info(self, json_info):
     """Parse the json response from Launchpad into objects."""
     if json is None:
         return None
     try:
         return json.loads(json_info)
     except Exception:
         trace.mutter('Failed to parse json info: %r' % (json_info,))
         trace.log_exception_quietly()
         return None
Esempio n. 7
0
def load_from_dir(d):
    """Load the plugins in directory d."""
    # Get the list of valid python suffixes for __init__.py?
    # this includes .py, .pyc, and .pyo (depending on if we are running -O)
    # but it doesn't include compiled modules (.so, .dll, etc)
    valid_suffixes = [suffix for suffix, mod_type, flags in imp.get_suffixes()
                              if flags in (imp.PY_SOURCE, imp.PY_COMPILED)]
    package_entries = ['__init__'+suffix for suffix in valid_suffixes]
    plugin_names = set()
    for f in os.listdir(d):
        path = osutils.pathjoin(d, f)
        if os.path.isdir(path):
            for entry in package_entries:
                # This directory should be a package, and thus added to
                # the list
                if os.path.isfile(osutils.pathjoin(path, entry)):
                    break
            else: # This directory is not a package
                continue
        else:
            for suffix_info in imp.get_suffixes():
                if f.endswith(suffix_info[0]):
                    f = f[:-len(suffix_info[0])]
                    if suffix_info[2] == imp.C_EXTENSION and f.endswith('module'):
                        f = f[:-len('module')]
                    break
            else:
                continue
        if getattr(_mod_plugins, f, None):
            mutter('Plugin name %s already loaded', f)
        else:
            # mutter('add plugin name %s', f)
            plugin_names.add(f)
    
    for name in plugin_names:
        try:
            exec "import bzrlib.plugins.%s" % name in {}
        except KeyboardInterrupt:
            raise
        except Exception, e:
            ## import pdb; pdb.set_trace()
            if re.search('\.|-| ', name):
                sanitised_name = re.sub('[-. ]', '_', name)
                if sanitised_name.startswith('bzr_'):
                    sanitised_name = sanitised_name[len('bzr_'):]
                warning("Unable to load %r in %r as a plugin because the "
                        "file path isn't a valid module name; try renaming "
                        "it to %r." % (name, d, sanitised_name))
            else:
                warning('Unable to load plugin %r from %r' % (name, d))
            log_exception_quietly()
            if 'error' in debug.debug_flags:
                trace.print_exception(sys.exc_info(), sys.stderr)
Esempio n. 8
0
def unregister_on_hangup(identifier):
    """Remove a callback from being called during sighup."""
    if _on_sighup is None:
        return
    try:
        del _on_sighup[identifier]
    except KeyboardInterrupt:
        raise
    except Exception:
        # This usually runs as a tear-down step. So we don't want to propagate
        # most exceptions.
        trace.mutter('Error occurred during unregister_on_hangup:')
        trace.log_exception_quietly()
Esempio n. 9
0
def unregister_on_hangup(identifier):
    """Remove a callback from being called during sighup."""
    if _on_sighup is None:
        return
    try:
        del _on_sighup[identifier]
    except KeyboardInterrupt:
        raise
    except Exception:
        # This usually runs as a tear-down step. So we don't want to propagate
        # most exceptions.
        trace.mutter('Error occurred during unregister_on_hangup:')
        trace.log_exception_quietly()
Esempio n. 10
0
 def _get_lp_info(self):
     """Place an actual HTTP query against the Launchpad service."""
     if json is None:
         return None
     query_URL = self._query_URL()
     try:
         req = urllib2.Request(query_URL)
         response = urllib2.urlopen(req)
         json_info = response.read()
     # TODO: We haven't tested the HTTPError
     except (urllib2.URLError, urllib2.HTTPError), e:
         trace.mutter('failed to place query to %r' % (query_URL,))
         trace.log_exception_quietly()
         return None
Esempio n. 11
0
 def get_latest_version(self):
     """Get the latest published version for the given package."""
     json_info = self._get_lp_info()
     if json_info is None:
         return None
     info = self._parse_json_info(json_info)
     if info is None:
         return None
     try:
         entries = info['entries']
         if len(entries) == 0:
             return None
         return entries[0]['source_package_version']
     except KeyError:
         trace.log_exception_quietly()
         return None
Esempio n. 12
0
def _sighup_handler(signal_number, interrupted_frame):
    """This is the actual function that is registered for handling SIGHUP.

    It will call out to all the registered functions, letting them know that a
    graceful termination has been requested.
    """
    if _on_sighup is None:
        return
    trace.mutter('Caught SIGHUP, sending graceful shutdown requests.')
    for ref in _on_sighup.valuerefs():
        try:
            cb = ref()
            if cb is not None:
                cb()
        except KeyboardInterrupt:
            raise
        except Exception:
            trace.mutter('Error occurred while running SIGHUP handlers:')
            trace.log_exception_quietly()
Esempio n. 13
0
def _sighup_handler(signal_number, interrupted_frame):
    """This is the actual function that is registered for handling SIGHUP.

    It will call out to all the registered functions, letting them know that a
    graceful termination has been requested.
    """
    if _on_sighup is None:
        return
    trace.mutter('Caught SIGHUP, sending graceful shutdown requests.')
    for ref in _on_sighup.valuerefs():
        try:
            cb = ref()
            if cb is not None:
                cb()
        except KeyboardInterrupt:
            raise
        except Exception:
            trace.mutter('Error occurred while running SIGHUP handlers:')
            trace.log_exception_quietly()
Esempio n. 14
0
 def _do_loop(self):
     while not self._should_terminate.isSet():
         try:
             conn, client_addr = self._server_socket.accept()
         except self._socket_timeout:
             pass  # Run shutdown and children checks.
         except self._socket_error as e:
             if e.args[0] == errno.EINTR:
                 pass  # Run shutdown and children checks.
             elif e.args[0] != errno.EBADF:
                 # We can get EBADF here while we are shutting down
                 # So we just ignore it for now
                 pass
             else:
                 # Log any other failure mode
                 trace.warning("listening socket error: %s", e)
         else:
             self.log(client_addr, 'connected')
             # TODO: We should probably trap exceptions coming out of
             # this and log them, so that we don't kill the service
             # because of an unhandled error.
             # Note: settimeout is used so that a malformed request
             # doesn't cause us to hang forever.  Also note that the
             # particular implementation means that a malicious
             # client could probably send us one byte every once in a
             # while, and we would just keep trying to read it.
             # However, as a local service, we aren't worrying about
             # it.
             conn.settimeout(self.WAIT_FOR_REQUEST_TIMEOUT)
             try:
                 self.serve_one_connection(conn, client_addr)
             except self._socket_timeout as e:
                 trace.log_exception_quietly()
                 self.log(
                     client_addr, 'request timeout failure: %s' % (e,))
                 conn.sendall('FAILURE\nrequest timed out\n')
                 conn.close()
             except Exception as e:
                 trace.log_exception_quietly()
                 self.log(client_addr, 'trapped a failure while handling'
                                       ' connection: %s' % (e,))
         self._poll_children()
Esempio n. 15
0
 def _do_loop(self):
     while not self._should_terminate.isSet():
         try:
             conn, client_addr = self._server_socket.accept()
         except self._socket_timeout:
             pass  # Run shutdown and children checks.
         except self._socket_error as e:
             if e.args[0] == errno.EINTR:
                 pass  # Run shutdown and children checks.
             elif e.args[0] != errno.EBADF:
                 # We can get EBADF here while we are shutting down
                 # So we just ignore it for now
                 pass
             else:
                 # Log any other failure mode
                 trace.warning("listening socket error: %s", e)
         else:
             self.log(client_addr, "connected")
             # TODO: We should probably trap exceptions coming out of
             # this and log them, so that we don't kill the service
             # because of an unhandled error.
             # Note: settimeout is used so that a malformed request
             # doesn't cause us to hang forever.  Also note that the
             # particular implementation means that a malicious
             # client could probably send us one byte every once in a
             # while, and we would just keep trying to read it.
             # However, as a local service, we aren't worrying about
             # it.
             conn.settimeout(self.WAIT_FOR_REQUEST_TIMEOUT)
             try:
                 self.serve_one_connection(conn, client_addr)
             except self._socket_timeout as e:
                 trace.log_exception_quietly()
                 self.log(client_addr, "request timeout failure: %s" % (e,))
                 conn.sendall("FAILURE\nrequest timed out\n")
                 conn.close()
             except Exception as e:
                 trace.log_exception_quietly()
                 self.log(client_addr, "trapped a failure while handling" " connection: %s" % (e,))
         self._poll_children()
Esempio n. 16
0
    def _call(self, protocol_version):
        """We know the protocol version.

        So this just sends the request, and then reads the response. This is
        where the code will be to retry requests if the connection is closed.
        """
        response_handler = self._send(protocol_version)
        try:
            response_tuple = response_handler.read_response_tuple(
                expect_body=self.expect_response_body)
        except errors.ConnectionReset, e:
            self.client._medium.reset()
            if not self._is_safe_to_send_twice():
                raise
            trace.warning('ConnectionReset reading response for %r, retrying'
                          % (self.method,))
            trace.log_exception_quietly()
            encoder, response_handler = self._construct_protocol(
                protocol_version)
            self._send_no_retry(encoder)
            response_tuple = response_handler.read_response_tuple(
                expect_body=self.expect_response_body)
Esempio n. 17
0
    def _send(self, protocol_version):
        """Encode the request, and send it to the server.

        This will retry a request if we get a ConnectionReset while sending the
        request to the server. (Unless we have a body_stream that we have
        already started consuming, since we can't restart body_streams)

        :return: response_handler as defined by _construct_protocol
        """
        encoder, response_handler = self._construct_protocol(protocol_version)
        try:
            self._send_no_retry(encoder)
        except errors.ConnectionReset, e:
            # If we fail during the _send_no_retry phase, then we can
            # be confident that the server did not get our request, because we
            # haven't started waiting for the reply yet. So try the request
            # again. We only issue a single retry, because if the connection
            # really is down, there is no reason to loop endlessly.

            # Connection is dead, so close our end of it.
            self.client._medium.reset()
            if (('noretry' in debug.debug_flags)
                or (self.body_stream is not None
                    and encoder.body_stream_started)):
                # We can't restart a body_stream that has been partially
                # consumed, so we don't retry.
                # Note: We don't have to worry about
                #   SmartClientRequestProtocolOne or Two, because they don't
                #   support client-side body streams.
                raise
            trace.warning('ConnectionReset calling %r, retrying'
                          % (self.method,))
            trace.log_exception_quietly()
            encoder, response_handler = self._construct_protocol(
                protocol_version)
            self._send_no_retry(encoder)
Esempio n. 18
0
 def logException(self, exception):
     """Log exception with Bazaar's exception logger."""
     try:
         raise exception
     except exception.__class__:
         trace.log_exception_quietly()
Esempio n. 19
0
 def logException(self, exception):
     """Log exception with Bazaar's exception logger."""
     try:
         raise exception
     except exception.__class__:
         trace.log_exception_quietly()
Esempio n. 20
0
def report_bug(exc_info, stderr):
    if ('no_apport' in debug.debug_flags) or \
        os.environ.get('APPORT_DISABLE', None):
        return report_bug_legacy(exc_info, stderr)
    try:
        if report_bug_to_apport(exc_info, stderr):
            # wrote a file; if None then report the old way
            return
    except ImportError, e:
        trace.mutter("couldn't find apport bug-reporting library: %s" % e)
    except Exception, e:
        # this should only happen if apport is installed but it didn't
        # work, eg because of an io error writing the crash file
        trace.mutter("bzr: failed to report crash using apport: %r" % e)
        trace.log_exception_quietly()
    return report_bug_legacy(exc_info, stderr)


def report_bug_legacy(exc_info, err_file):
    """Report a bug by just printing a message to the user."""
    trace.print_exception(exc_info, err_file)
    err_file.write('\n')
    import textwrap
    def print_wrapped(l):
        err_file.write(textwrap.fill(l,
            width=78, subsequent_indent='    ') + '\n')
    print_wrapped('bzr %s on python %s (%s)\n' % \
        (bzrlib.__version__,
        bzrlib._format_version_tuple(sys.version_info),
        platform.platform(aliased=1)))
Esempio n. 21
0
def report_bug(exc_info, stderr):
    if ('no_apport' in debug.debug_flags) or \
        os.environ.get('APPORT_DISABLE', None):
        return report_bug_legacy(exc_info, stderr)
    try:
        if report_bug_to_apport(exc_info, stderr):
            # wrote a file; if None then report the old way
            return
    except ImportError, e:
        trace.mutter("couldn't find apport bug-reporting library: %s" % e)
    except Exception, e:
        # this should only happen if apport is installed but it didn't
        # work, eg because of an io error writing the crash file
        trace.mutter("bzr: failed to report crash using apport: %r" % e)
        trace.log_exception_quietly()
    return report_bug_legacy(exc_info, stderr)


def report_bug_legacy(exc_info, err_file):
    """Report a bug by just printing a message to the user."""
    trace.print_exception(exc_info, err_file)
    err_file.write('\n')
    import textwrap

    def print_wrapped(l):
        err_file.write(
            textwrap.fill(l, width=78, subsequent_indent='    ') + '\n')
    print_wrapped('bzr %s on python %s (%s)\n' % \
        (bzrlib.__version__,
        bzrlib._format_version_tuple(sys.version_info),
Esempio n. 22
0
def _log_cleanup_error(exc):
    trace.mutter('Cleanup failed:')
    trace.log_exception_quietly()
    if 'cleanup' in debug.debug_flags:
        trace.warning('bzr: warning: Cleanup failed: %s', exc)
Esempio n. 23
0
def load_from_zip(zip_name):
    """Load all the plugins in a zip."""
    valid_suffixes = ('.py', '.pyc', '.pyo')    # only python modules/packages
                                                # is allowed
    try:
        index = zip_name.rindex('.zip')
    except ValueError:
        return
    archive = zip_name[:index+4]
    prefix = zip_name[index+5:]

    mutter('Looking for plugins in %r', zip_name)

    # use zipfile to get list of files/dirs inside zip
    try:
        z = zipfile.ZipFile(archive)
        namelist = z.namelist()
        z.close()
    except zipfile.error:
        # not a valid zip
        return

    if prefix:
        prefix = prefix.replace('\\','/')
        if prefix[-1] != '/':
            prefix += '/'
        ix = len(prefix)
        namelist = [name[ix:]
                    for name in namelist
                    if name.startswith(prefix)]

    mutter('Names in archive: %r', namelist)
    
    for name in namelist:
        if not name or name.endswith('/'):
            continue
    
        # '/' is used to separate pathname components inside zip archives
        ix = name.rfind('/')
        if ix == -1:
            head, tail = '', name
        else:
            head, tail = name.rsplit('/',1)
        if '/' in head:
            # we don't need looking in subdirectories
            continue
    
        base, suffix = osutils.splitext(tail)
        if suffix not in valid_suffixes:
            continue
    
        if base == '__init__':
            # package
            plugin_name = head
        elif head == '':
            # module
            plugin_name = base
        else:
            continue
    
        if not plugin_name:
            continue
        if getattr(_mod_plugins, plugin_name, None):
            mutter('Plugin name %s already loaded', plugin_name)
            continue
    
        try:
            exec "import bzrlib.plugins.%s" % plugin_name in {}
            mutter('Load plugin %s from zip %r', plugin_name, zip_name)
        except KeyboardInterrupt:
            raise
        except Exception, e:
            ## import pdb; pdb.set_trace()
            warning('Unable to load plugin %r from %r'
                    % (name, zip_name))
            log_exception_quietly()
            if 'error' in debug.debug_flags:
                trace.print_exception(sys.exc_info(), sys.stderr)
Esempio n. 24
0
def _log_cleanup_error(exc):
    trace.mutter("Cleanup failed:")
    trace.log_exception_quietly()
    if "cleanup" in debug.debug_flags:
        trace.warning("bzr: warning: Cleanup failed: %s", exc)
Esempio n. 25
0
    def _commit(self, operation, message, timestamp, timezone, committer,
            specific_files, rev_id, allow_pointless, strict, verbose,
            working_tree, local, reporter, message_callback, recursive,
            exclude, possible_master_transports, lossy):
        mutter('preparing to commit')

        if working_tree is None:
            raise BzrError("working_tree must be passed into commit().")
        else:
            self.work_tree = working_tree
            self.branch = self.work_tree.branch
            if getattr(self.work_tree, 'requires_rich_root', lambda: False)():
                if not self.branch.repository.supports_rich_root():
                    raise errors.RootNotRich()
        if message_callback is None:
            if message is not None:
                if isinstance(message, str):
                    message = message.decode(get_user_encoding())
                message_callback = lambda x: message
            else:
                raise BzrError("The message or message_callback keyword"
                               " parameter is required for commit().")

        self.bound_branch = None
        self.any_entries_deleted = False
        if exclude is not None:
            self.exclude = sorted(
                minimum_path_selection(exclude))
        else:
            self.exclude = []
        self.local = local
        self.master_branch = None
        self.recursive = recursive
        self.rev_id = None
        # self.specific_files is None to indicate no filter, or any iterable to
        # indicate a filter - [] means no files at all, as per iter_changes.
        if specific_files is not None:
            self.specific_files = sorted(
                minimum_path_selection(specific_files))
        else:
            self.specific_files = None

        self.allow_pointless = allow_pointless
        self.message_callback = message_callback
        self.timestamp = timestamp
        self.timezone = timezone
        self.committer = committer
        self.strict = strict
        self.verbose = verbose

        self.work_tree.lock_write()
        operation.add_cleanup(self.work_tree.unlock)
        self.parents = self.work_tree.get_parent_ids()
        # We can use record_iter_changes IFF iter_changes is compatible with
        # the command line parameters, and the repository has fast delta
        # generation. See bug 347649.
        self.use_record_iter_changes = (
            not self.exclude and 
            not self.branch.repository._format.supports_tree_reference and
            (self.branch.repository._format.fast_deltas or
             len(self.parents) < 2))
        self.pb = ui.ui_factory.nested_progress_bar()
        operation.add_cleanup(self.pb.finished)
        self.basis_revid = self.work_tree.last_revision()
        self.basis_tree = self.work_tree.basis_tree()
        self.basis_tree.lock_read()
        operation.add_cleanup(self.basis_tree.unlock)
        # Cannot commit with conflicts present.
        if len(self.work_tree.conflicts()) > 0:
            raise ConflictsInTree

        # Setup the bound branch variables as needed.
        self._check_bound_branch(operation, possible_master_transports)

        # Check that the working tree is up to date
        old_revno, old_revid, new_revno = self._check_out_of_date_tree()

        # Complete configuration setup
        if reporter is not None:
            self.reporter = reporter
        elif self.reporter is None:
            self.reporter = self._select_reporter()
        if self.config_stack is None:
            self.config_stack = self.work_tree.get_config_stack()

        self._set_specific_file_ids()

        # Setup the progress bar. As the number of files that need to be
        # committed in unknown, progress is reported as stages.
        # We keep track of entries separately though and include that
        # information in the progress bar during the relevant stages.
        self.pb_stage_name = ""
        self.pb_stage_count = 0
        self.pb_stage_total = 5
        if self.bound_branch:
            # 2 extra stages: "Uploading data to master branch" and "Merging
            # tags to master branch"
            self.pb_stage_total += 2
        self.pb.show_pct = False
        self.pb.show_spinner = False
        self.pb.show_eta = False
        self.pb.show_count = True
        self.pb.show_bar = True

        self._gather_parents()
        # After a merge, a selected file commit is not supported.
        # See 'bzr help merge' for an explanation as to why.
        if len(self.parents) > 1 and self.specific_files is not None:
            raise errors.CannotCommitSelectedFileMerge(self.specific_files)
        # Excludes are a form of selected file commit.
        if len(self.parents) > 1 and self.exclude:
            raise errors.CannotCommitSelectedFileMerge(self.exclude)

        # Collect the changes
        self._set_progress_stage("Collecting changes", counter=True)
        self._lossy = lossy
        self.builder = self.branch.get_commit_builder(self.parents,
            self.config_stack, timestamp, timezone, committer, self.revprops,
            rev_id, lossy=lossy)
        if not self.builder.supports_record_entry_contents and self.exclude:
            self.builder.abort()
            raise errors.ExcludesUnsupported(self.branch.repository)

        if self.builder.updates_branch and self.bound_branch:
            self.builder.abort()
            raise AssertionError(
                "bound branches not supported for commit builders "
                "that update the branch")

        try:
            self.builder.will_record_deletes()
            # find the location being committed to
            if self.bound_branch:
                master_location = self.master_branch.base
            else:
                master_location = self.branch.base

            # report the start of the commit
            self.reporter.started(new_revno, self.rev_id, master_location)

            self._update_builder_with_changes()
            self._check_pointless()

            # TODO: Now the new inventory is known, check for conflicts.
            # ADHB 2006-08-08: If this is done, populate_new_inv should not add
            # weave lines, because nothing should be recorded until it is known
            # that commit will succeed.
            self._set_progress_stage("Saving data locally")
            self.builder.finish_inventory()

            # Prompt the user for a commit message if none provided
            message = message_callback(self)
            self.message = message

            # Add revision data to the local branch
            self.rev_id = self.builder.commit(self.message)

        except Exception, e:
            mutter("aborting commit write group because of exception:")
            trace.log_exception_quietly()
            self.builder.abort()
            raise
Esempio n. 26
0
    def _commit(self, operation, message, timestamp, timezone, committer,
                specific_files, rev_id, allow_pointless, strict, verbose,
                working_tree, local, reporter, message_callback, recursive,
                exclude, possible_master_transports, lossy):
        mutter('preparing to commit')

        if working_tree is None:
            raise BzrError("working_tree must be passed into commit().")
        else:
            self.work_tree = working_tree
            self.branch = self.work_tree.branch
            if getattr(self.work_tree, 'requires_rich_root', lambda: False)():
                if not self.branch.repository.supports_rich_root():
                    raise errors.RootNotRich()
        if message_callback is None:
            if message is not None:
                if isinstance(message, str):
                    message = message.decode(get_user_encoding())
                message_callback = lambda x: message
            else:
                raise BzrError("The message or message_callback keyword"
                               " parameter is required for commit().")

        self.bound_branch = None
        self.any_entries_deleted = False
        if exclude is not None:
            self.exclude = sorted(minimum_path_selection(exclude))
        else:
            self.exclude = []
        self.local = local
        self.master_branch = None
        self.recursive = recursive
        self.rev_id = None
        # self.specific_files is None to indicate no filter, or any iterable to
        # indicate a filter - [] means no files at all, as per iter_changes.
        if specific_files is not None:
            self.specific_files = sorted(
                minimum_path_selection(specific_files))
        else:
            self.specific_files = None

        self.allow_pointless = allow_pointless
        self.message_callback = message_callback
        self.timestamp = timestamp
        self.timezone = timezone
        self.committer = committer
        self.strict = strict
        self.verbose = verbose

        self.work_tree.lock_write()
        operation.add_cleanup(self.work_tree.unlock)
        self.parents = self.work_tree.get_parent_ids()
        # We can use record_iter_changes IFF iter_changes is compatible with
        # the command line parameters, and the repository has fast delta
        # generation. See bug 347649.
        self.use_record_iter_changes = (
            not self.exclude
            and not self.branch.repository._format.supports_tree_reference
            and (self.branch.repository._format.fast_deltas
                 or len(self.parents) < 2))
        self.pb = ui.ui_factory.nested_progress_bar()
        operation.add_cleanup(self.pb.finished)
        self.basis_revid = self.work_tree.last_revision()
        self.basis_tree = self.work_tree.basis_tree()
        self.basis_tree.lock_read()
        operation.add_cleanup(self.basis_tree.unlock)
        # Cannot commit with conflicts present.
        if len(self.work_tree.conflicts()) > 0:
            raise ConflictsInTree

        # Setup the bound branch variables as needed.
        self._check_bound_branch(operation, possible_master_transports)

        # Check that the working tree is up to date
        old_revno, old_revid, new_revno = self._check_out_of_date_tree()

        # Complete configuration setup
        if reporter is not None:
            self.reporter = reporter
        elif self.reporter is None:
            self.reporter = self._select_reporter()
        if self.config_stack is None:
            self.config_stack = self.work_tree.get_config_stack()

        self._set_specific_file_ids()

        # Setup the progress bar. As the number of files that need to be
        # committed in unknown, progress is reported as stages.
        # We keep track of entries separately though and include that
        # information in the progress bar during the relevant stages.
        self.pb_stage_name = ""
        self.pb_stage_count = 0
        self.pb_stage_total = 5
        if self.bound_branch:
            # 2 extra stages: "Uploading data to master branch" and "Merging
            # tags to master branch"
            self.pb_stage_total += 2
        self.pb.show_pct = False
        self.pb.show_spinner = False
        self.pb.show_eta = False
        self.pb.show_count = True
        self.pb.show_bar = True

        self._gather_parents()
        # After a merge, a selected file commit is not supported.
        # See 'bzr help merge' for an explanation as to why.
        if len(self.parents) > 1 and self.specific_files is not None:
            raise errors.CannotCommitSelectedFileMerge(self.specific_files)
        # Excludes are a form of selected file commit.
        if len(self.parents) > 1 and self.exclude:
            raise errors.CannotCommitSelectedFileMerge(self.exclude)

        # Collect the changes
        self._set_progress_stage("Collecting changes", counter=True)
        self._lossy = lossy
        self.builder = self.branch.get_commit_builder(self.parents,
                                                      self.config_stack,
                                                      timestamp,
                                                      timezone,
                                                      committer,
                                                      self.revprops,
                                                      rev_id,
                                                      lossy=lossy)
        if not self.builder.supports_record_entry_contents and self.exclude:
            self.builder.abort()
            raise errors.ExcludesUnsupported(self.branch.repository)

        if self.builder.updates_branch and self.bound_branch:
            self.builder.abort()
            raise AssertionError(
                "bound branches not supported for commit builders "
                "that update the branch")

        try:
            self.builder.will_record_deletes()
            # find the location being committed to
            if self.bound_branch:
                master_location = self.master_branch.base
            else:
                master_location = self.branch.base

            # report the start of the commit
            self.reporter.started(new_revno, self.rev_id, master_location)

            self._update_builder_with_changes()
            self._check_pointless()

            # TODO: Now the new inventory is known, check for conflicts.
            # ADHB 2006-08-08: If this is done, populate_new_inv should not add
            # weave lines, because nothing should be recorded until it is known
            # that commit will succeed.
            self._set_progress_stage("Saving data locally")
            self.builder.finish_inventory()

            # Prompt the user for a commit message if none provided
            message = message_callback(self)
            self.message = message

            # Add revision data to the local branch
            self.rev_id = self.builder.commit(self.message)

        except Exception, e:
            mutter("aborting commit write group because of exception:")
            trace.log_exception_quietly()
            self.builder.abort()
            raise