Example #1
0
class ChangeSet(object):
    """A server-side changeset.

    This represents information on a server-side changeset, which tracks
    the information on a commit and modified files for some types of
    repositories (such as Perforce).

    Not all data may be provided by the server.

    Attributes:
        bugs_closed (list of unicode):
            A list of bug IDs that were closed by this change.

        files (list of unicode):
            A list of filenames added/modified/deleted by the change.

        pending (bool):
            Whether or not the change is pending (not yet committed).
    """

    #: The changeset number/ID.
    changenum = TypedProperty(int)

    #: The summary of the change.
    summary = TypedProperty(six.text_type)

    #: The description of the change.
    description = TypedProperty(six.text_type)

    #: Testing information for the change.
    testing_done = TypedProperty(six.text_type)

    #: The destination branch.
    branch = TypedProperty(six.text_type)

    #: The username of the user who made the change.
    username = TypedProperty(six.text_type)

    def __init__(self):
        """Initialize the changeset."""
        self.changenum = None
        self.summary = ''
        self.description = ''
        self.testing_done = ''
        self.branch = ''
        self.bugs_closed = []
        self.files = []
        self.username = ''
        self.pending = False
Example #2
0
class ParsedDiffFile(object):
    """A parsed file from a diff.

    This stores information on a single file represented in a diff, including
    the contents of that file's diff, as parsed by :py:class:`DiffParser` or
    one of its subclasses.

    Parsers should set the attributes on this based on the contents of the
    diff, and should add any data found in the diff.

    This class is meant to be used internally and by subclasses of
    :py:class:`DiffParser`.

    Attributes:
        binary (bool);
            Whether this represents a binary file.

        copied (bool):
            Whether this represents a file that has been copied. The file
            may or may not be modified in the process.

        deleted (bool):
            Whether this represents a file that has been deleted.

        delete_count (int):
            The number of delete (``-``) lines found in the file.

        insert_count (int):
            The number of insert (``+``) lines found in the file.

        is_symlink (bool):
            Whether this represents a file that is a symbolic link to another
            file.

        moved (bool):
            Whether this represents a file that has been moved/renamed. The
            file may or may not be modified in the process.

        parser (DiffParser):
            The diff parser that parsed this file.

        skip (bool):
            Whether this file should be skipped by the parser. If any of the
            parser methods set this, the file will stop parsing and will be
            excluded from results.
    """

    #: The parsed original name of the file.
    #:
    #: Type:
    #:     bytes
    orig_filename = TypedProperty(bytes)

    #: The parsed file details of the original file.
    #:
    #: This will usually be a revision.
    #:
    #: Type:
    #:     bytes or reviewboard.scmtools.core.Revision
    orig_file_details = TypedProperty((bytes, Revision))

    #: The parsed modified name of the file.
    #:
    #: This may be the same as :py:attr:`orig_filename`.
    #:
    #: Type:
    #:     bytes
    modified_filename = TypedProperty(bytes)

    #: The parsed file details of the modified file.
    #:
    #: This will usually be a revision.
    #:
    #: Type:
    #:     bytes or reviewboard.scmtools.core.Revision
    modified_file_details = TypedProperty((bytes, Revision))

    #: The parsed value for an Index header.
    #:
    #: If present in the diff, this usually contains a filename, but may
    #: contain other content as well, depending on the variation of the diff
    #: format.
    #:
    #: Type:
    #:     bytes
    index_header_value = TypedProperty(bytes)

    #: The parsed original name of the file.
    #:
    #: Deprecated:
    #:     4.0:
    #:     Use :py:attr:`orig_filename` instead.
    origFile = AliasProperty('orig_filename',
                             convert_to_func=force_bytes,
                             deprecated=True,
                             deprecation_warning=RemovedInReviewBoard50Warning)

    #: The parsed file details of the original file.
    #:
    #: Deprecated:
    #:     4.0:
    #:     Use :py:attr:`orig_file_details` instead.
    origInfo = AliasProperty('orig_file_details',
                             convert_to_func=force_bytes,
                             deprecated=True,
                             deprecation_warning=RemovedInReviewBoard50Warning)

    #: The parsed original name of the file.
    #:
    #: Deprecated:
    #:     4.0:
    #:     Use :py:attr:`modified_filename` instead.
    newFile = AliasProperty('modified_filename',
                            convert_to_func=force_bytes,
                            deprecated=True,
                            deprecation_warning=RemovedInReviewBoard50Warning)

    #: The parsed file details of the modified file.
    #:
    #: Deprecated:
    #:     4.0:
    #:     Use :py:attr:`modified_file_details` instead.
    newInfo = AliasProperty('modified_file_details',
                            convert_to_func=force_bytes,
                            deprecated=True,
                            deprecation_warning=RemovedInReviewBoard50Warning)

    #: The parsed value for an Index header.
    #:
    #: Deprecated:
    #:     4.0:
    #:     Use :py:attr:`index_header_value` instead.
    index = AliasProperty('index_header_value',
                          convert_to_func=force_bytes,
                          deprecated=True,
                          deprecation_warning=RemovedInReviewBoard50Warning)

    def __init__(self, parser=None):
        """Initialize the parsed file information.

        Args:
            parser (reviewboard.diffviewer.parser.DiffParser, optional):
                The diff parser that parsed this file.
        """
        if parser is None:
            RemovedInReviewBoard50Warning.warn(
                'Diff parsers must pass themselves as a parameter when'
                'creating a ParsedDiffFile. This will be mandatory in '
                'Review Board 5.0.')

        self.parser = parser
        self.binary = False
        self.deleted = False
        self.moved = False
        self.copied = False
        self.is_symlink = False
        self.insert_count = 0
        self.delete_count = 0
        self.skip = False

        self._data_io = io.BytesIO()
        self._data = None

        self._deprecated_info = {}

    def __setitem__(self, key, value):
        """Set information on the parsed file from a diff.

        This is a legacy implementation used to help diff parsers retain
        compatibility with the old dictionary-based ways of setting parsed
        file information. Callers should be updated to set attributes instead.

        Deprecated:
            4.0:
            This will be removed in Review Board 5.0.

        Args:
            key (str):
                The key to set.

            value (object):
                The value to set.
        """
        self._warn_old_usage_deprecation()

        self._deprecated_info[key] = value
        setattr(self, key, value)

    def __getitem__(self, key):
        """Return information on the parsed file from a diff.

        This is a legacy implementation used to help diff parsers retain
        compatibility with the old dictionary-based ways of setting parsed
        file information. Callers should be updated to access attributes
        instead.

        Deprecated:
            4.0:
            This will be removed in Review Board 5.0.

        Args:
            key (str):
                The key to retrieve.

        Returns:
            object:
            The resulting value.

        Raises:
            KeyError:
                The key is invalid.
        """
        self._warn_old_usage_deprecation()

        return self._deprecated_info[key]

    def __contains__(self, key):
        """Return whether an old parsed file key has been explicitly set.

        This is a legacy implementation used to help diff parsers retain
        compatibility with the old dictionary-based ways of setting parsed
        file information. Callers should be updated to check attribute values
        instead.

        Deprecated:
            4.0:
            This will be removed in Review Board 5.0.

        Args:
            key (str):
                The key to check.

        Returns:
            bool:
            ``True`` if the key has been explicitly set by a diff parser.
            ``False`` if it has not.
        """
        self._warn_old_usage_deprecation()

        return key in self._deprecated_info

    def set(self, key, value):
        """Set information on the parsed file from a diff.

        This is a legacy implementation used to help diff parsers retain
        compatibility with the old dictionary-based ways of setting parsed
        file information. Callers should be updated to set attributes instead.

        Deprecated:
            4.0:
            This will be removed in Review Board 5.0.

        Args:
            key (str):
                The key to set.

            value (object):
                The value to set.
        """
        self._warn_old_usage_deprecation()

        self._deprecated_info[key] = value
        setattr(self, key, value)

    def get(self, key, default=None):
        """Return information on the parsed file from a diff.

        This is a legacy implementation used to help diff parsers retain
        compatibility with the old dictionary-based ways of setting parsed
        file information. Callers should be updated to access attributes
        instead.

        Deprecated:
            4.0:
            This will be removed in Review Board 5.0.

        Args:
            key (str):
                The key to retrieve.

            default (object, optional):
                The default value to return.

        Returns:
            object:
            The resulting value.
        """
        self._warn_old_usage_deprecation()

        return self._deprecated_info.get(key, default)

    def update(self, items):
        """Update information on the parsed file from a diff.

        This is a legacy implementation used to help diff parsers retain
        compatibility with the old dictionary-based ways of setting parsed
        file information. Callers should be updated to set individual
        attributes instead.

        Deprecated:
            4.0:
            This will be removed in Review Board 5.0.

        Args:
            items (dict):
                The keys and values to set.
        """
        self._warn_old_usage_deprecation()

        for key, value in six.iteritems(items):
            self._deprecated_info[key] = value
            setattr(self, key, value)

    @property
    def data(self):
        """The data for this diff.

        This must be accessed after :py:meth:`finalize` has been called.
        """
        if self._data is None:
            raise ValueError('ParsedDiffFile.data cannot be accessed until '
                             'finalize() is called.')

        return self._data

    def finalize(self):
        """Finalize the parsed diff.

        This makes the diff data available to consumers and closes the buffer
        for writing.
        """
        self._data = self._data_io.getvalue()
        self._data_io.close()

    def prepend_data(self, data):
        """Prepend data to the buffer.

        Args:
            data (bytes):
                The data to prepend.
        """
        if data:
            new_data_io = io.BytesIO()
            new_data_io.write(data)
            new_data_io.write(self._data_io.getvalue())

            self._data_io.close()
            self._data_io = new_data_io

    def append_data(self, data):
        """Append data to the buffer.

        Args:
            data (bytes):
                The data to append.
        """
        if data:
            self._data_io.write(data)

    def _warn_old_usage_deprecation(self):
        """Warn that a DiffParser is populating information in an old way."""
        if self.parser is None:
            message = (
                'Diff parsers must be updated to populate attributes on a '
                'ParsedDiffFile, instead of setting the information in a '
                'dictionary. This will be required in Review Board 5.0.')
        else:
            message = (
                '%r must be updated to populate attributes on a '
                'ParsedDiffFile, instead of setting the information in a '
                'dictionary. This will be required in Review Board 5.0.' %
                type(self.parser))

        RemovedInReviewBoard50Warning.warn(message, stacklevel=3)
Example #3
0
class Revision(object):
    """A revision in a diff or repository.

    This represents a specific revision in a tree, or a specialized indicator
    that can have special meaning.
    """

    #: The name/ID of the revision.
    name = TypedProperty(six.text_type, allow_none=False)

    def __init__(self, name):
        """Initialize the Revision.

        Args:
            name (unicode):
                The name of the revision. This may be a special name (which
                should be in all-uppercase) or a revision ID.

        Raises:
            TypeError:
                The provided name was not a Unicode string.
        """
        self.name = name

    def __bytes__(self):
        """Return a byte string representation of the revision.

        This is equivalent to fetching :py:attr:`name` and encoding to UTF-8.

        Returns:
            bytes:
            The name/ID of the revision.
        """
        return self.name.encode('utf-8')

    def __str__(self):
        """Return a Unicode string representation of the revision.

        This is equivalent to fetching :py:attr:`name`.

        Returns:
            unicode:
            The name/ID of the revision.
        """
        return self.name

    def __eq__(self, other):
        """Return whether this revision equals another.

        Args:
            other (Revision):
                The revision to compare to.

        Returns:
            bool:
            ``True`` if the two revisions are equal. ``False`` if they are
            not equal.
        """
        return self.name == force_text(other)

    def __ne__(self, other):
        """Return whether this revision is not equal to another.

        Args:
            other (Revision):
                The revision to compare to.

        Returns:
            bool:
            ``True`` if the two revisions are not equal. ``False`` if they are
            equal.
        """
        return self.name != force_text(other)

    def __repr__(self):
        """Return a string representation of this revision.

        Returns:
            unicode:
            The string representation.
        """
        return '<Revision: %s>' % self.name
Example #4
0
class Commit(object):
    """A commit in a repository."""

    #: The ID of the commit.
    #:
    #: This should be its SHA/revision.
    id = TypedProperty(six.text_type)

    #: The name or username of the author who made the commit.
    author_name = TypedProperty(six.text_type)

    #: The timestamp of the commit as a string in ISO 8601 format.
    date = TypedProperty(six.text_type)

    #: The commit message.
    message = TypedProperty(six.text_type)

    #: The contents of the commit's diff.
    #:
    #: This may be ``None``, depending on how the commit is fetched.
    diff = TypedProperty(bytes)

    #: The ID of the commit's parent.
    #:
    #: This should be its SHA/revision. If this is the first commit, this
    #: should be ``None`` or an empty string.
    parent = TypedProperty(six.text_type)

    def __init__(self, author_name='', id='', date='', message='', parent='',
                 diff=None):
        """Initialize the commit.

        All arguments are optional, and can be set later.

        Args:
            author_name (unicode, optional):
                The name of the author who made this commit. This should be
                the full name, if available, but can be the username or other
                identifier.

            id (unicode, optional):
                The ID of the commit. This should be its SHA/revision.

            date (unicode, optional):
                The timestamp of the commit as a string in ISO 8601 format.

            message (unicode, optional):
                The commit message.

            parent (unicode, optional):
                The ID of the commit's parent. This should be its SHA/revision.

            diff (bytes, optional):
                The contents of the commit's diff.
        """
        self.author_name = author_name
        self.id = id
        self.date = date
        self.message = message
        self.parent = parent

        # This field is only used when we're actually fetching the commit from
        # the server to create a new review request, and isn't part of the
        # equality test.
        self.diff = diff

    def __eq__(self, other):
        """Return whether this commit is equal to another commit.

        Args:
            other (Commit):
                The commit to compare to.

        Returns:
            bool:
            ``True`` if the two commits are equal. ``False`` if they are not.
        """
        return (self.author_name == other.author_name and
                self.id == other.id and
                self.date == other.date and
                self.message == other.message and
                self.parent == other.parent)

    def __repr__(self):
        """Return a string representation of this commit.

        Returns:
            unicode:
            The string representation.
        """
        return ('<Commit %r (author=%s; date=%s; parent=%r)>'
                % (self.id, self.author_name, self.date, self.parent))

    def split_message(self):
        """Return a split version of the commit message.

        This will separate the commit message into a summary and body, if
        possible.

        Returns:
            tuple:
            A tuple containing two string items: The summary and the commit
            message.

            If the commit message is only a single line, both items in the
            tuple will be that line.
        """
        message = self.message
        parts = message.split('\n', 1)
        summary = parts[0]

        try:
            message = parts[1]
        except IndexError:
            # If the description is only one line long, pass through--'message'
            # will still be set to what we got from get_change, and will show
            # up as being the same thing as the summary.
            pass

        return summary, message
Example #5
0
class Branch(object):
    """A branch in a repository.

    Attributes:
        default (bool):
            Whether or not this is the default branch for the repository.

            One (and only one) branch in a list of returned branches should
            have this set to ``True``.
    """

    #: The ID of the branch.
    id = TypedProperty(six.text_type, allow_none=False)

    #: The latest commit ID on the branch.
    commit = TypedProperty(six.text_type)

    #: The name of the branch.
    name = TypedProperty(six.text_type)

    def __init__(self, id, name=None, commit='', default=False):
        """Initialize the branch.

        Args:
            id (unicode):
                The ID of the branch.

            name (unicode, optional):
                The name of the branch. If not specified, this will default
                to the ID.

            commit (unicode, optional):
                The latest commit ID on the branch.

            default (bool, optional):
                Whether or not this is the default branch for the repository.
        """
        self.id = id
        self.name = name or self.id
        self.commit = commit
        self.default = default

    def __eq__(self, other):
        """Return whether this branch is equal to another branch.

        Args:
            other (Branch):
                The branch to compare to.

        Returns:
            bool:
            ``True`` if the two branches are equal. ``False`` if they are not.
        """
        return (self.id == other.id and
                self.name == other.name and
                self.commit == other.commit and
                self.default == other.default)

    def __repr__(self):
        """Return a string representation of this branch.

        Returns:
            unicode:
            The string representation.
        """
        return ('<Branch %s (name=%s; commit=%s: default=%r)>'
                % (self.id, self.name, self.commit, self.default))
Example #6
0
 class MyObject(object):
     prop = TypedProperty((int, bool), default=100)
Example #7
0
 class MyObject(object):
     prop = TypedProperty((int, bool), allow_none=False)
Example #8
0
 class MyObject(object):
     prop = TypedProperty((six.text_type, ))
Example #9
0
 class MyObject(object):
     prop = TypedProperty((int, bool))