def diff(self, revisions, include_files=[], exclude_patterns=[], extra_args=[], **kwargs): """Perform a diff using the given revisions. If the revision spec is empty, this returns the diff of the current branch with respect to its parent. If a single revision is passed in, this returns the diff of the change introduced in that revision. If two revisions are passed in, this will do a diff between those two revisions. Args: revisions (dict): A dictionary of revisions, as returned by :py:meth:`parse_revision_spec`. include_files (list of unicode, optional): A list of files to whitelist during the diff generation. exclude_patterns (list of unicode, optional): A list of shell-style glob patterns to blacklist during diff generation. extra_args (list, unused): Additional arguments to be passed to the diff generation. Unused for Bazaar. **kwargs (dict, unused): Unused keyword arguments. Returns: dict: A dictionary containing the following keys: ``diff`` (:py:class:`bytes`): The contents of the diff to upload. ``parent_diff`` (:py:class:`bytes`, optional): The contents of the parent diff, if available. """ exclude_patterns = normalize_patterns(exclude_patterns, self.get_repository_info().path) diff = self._get_range_diff(revisions['base'], revisions['tip'], include_files, exclude_patterns) if 'parent_base' in revisions: parent_diff = self._get_range_diff(revisions['parent_base'], revisions['base'], include_files, exclude_patterns) else: parent_diff = None return { 'diff': diff, 'parent_diff': parent_diff, }
def diff(self, revisions, include_files=[], exclude_patterns=[], extra_args=[]): """Returns the diff for the given revision spec. If the revision spec is empty, this returns the diff of the current branch with respect to its parent. If a single revision is passed in, this returns the diff of the change introduced in that revision. If two revisions are passed in, this will do a diff between those two revisions. The summary and description are set if guessing is enabled. """ exclude_patterns = normalize_patterns(exclude_patterns, self.get_repository_info().path) diff = self._get_range_diff(revisions['base'], revisions['tip'], include_files, exclude_patterns) if 'parent_base' in revisions: parent_diff = self._get_range_diff( revisions['parent_base'], revisions['base'], include_files, exclude_patterns) else: parent_diff = None return { 'diff': diff, 'parent_diff': parent_diff, }
def diff(self, revisions, include_files=[], exclude_patterns=[], extra_args=[]): """Returns the diff for the given revision spec. If the revision spec is empty, this returns the diff of the current branch with respect to its parent. If a single revision is passed in, this returns the diff of the change introduced in that revision. If two revisions are passed in, this will do a diff between those two revisions. The summary and description are set if guessing is enabled. """ exclude_patterns = normalize_patterns(exclude_patterns) diff = self._get_range_diff(revisions['base'], revisions['tip'], include_files, exclude_patterns) if 'parent_base' in revisions: parent_diff = self._get_range_diff(revisions['parent_base'], revisions['base'], include_files, exclude_patterns) else: parent_diff = None return { 'diff': diff, 'parent_diff': parent_diff, }
def diff(self, revisions, include_files=[], exclude_patterns=[], extra_args=[]): """Get the diff for the given revisions. If revision_spec is empty, this will return the diff for the modified files in the working directory. If it's not empty and contains two revisions, this will do a diff between those revisions. """ exclude_patterns = normalize_patterns(exclude_patterns) include_files = include_files or [] # Diff returns "1" if differences were found. diff_cmd = ['cvs', 'diff', '-uN'] base = revisions['base'] tip = revisions['tip'] if (not (base == 'BASE' and tip == self.REVISION_WORKING_COPY)): diff_cmd.extend(['-r', base, '-r', tip]) diff = execute(diff_cmd + include_files, extra_ignore_errors=(1, ), split_lines=True) if exclude_patterns: # CVS diffs are relative to the current working directory, so the # base_dir parameter to filter_diff is unnecessary. diff = filter_diff(diff, self.INDEX_FILE_RE, exclude_patterns) return {'diff': b''.join(diff)}
def diff(self, revisions, include_files=[], exclude_patterns=[], no_renames=False, extra_args=[]): """Get the diff for the given revisions. If revision_spec is empty, this will return the diff for the modified files in the working directory. If it's not empty and contains two revisions, this will do a diff between those revisions. """ # CVS paths are always relative to the current working directory. cwd = os.getcwd() exclude_patterns = normalize_patterns(exclude_patterns, cwd, cwd) include_files = include_files or [] # Diff returns "1" if differences were found. diff_cmd = ['cvs', 'diff', '-uN'] base = revisions['base'] tip = revisions['tip'] if (not (base == 'BASE' and tip == self.REVISION_WORKING_COPY)): diff_cmd.extend(['-r', base, '-r', tip]) diff = execute(diff_cmd + include_files, extra_ignore_errors=(1,), log_output_on_error=False, split_lines=True) if exclude_patterns: # CVS diffs are relative to the current working directory, so the # base_dir parameter to filter_diff is unnecessary. diff = filter_diff(diff, self.INDEX_FILE_RE, exclude_patterns, base_dir=cwd) return { 'diff': b''.join(diff) }
def diff(self, revisions, include_files=[], exclude_patterns=[], extra_args=[], **kwargs): """Perform a diff using the given revisions. If the revision spec is empty, this returns the diff of the current branch with respect to its parent. If a single revision is passed in, this returns the diff of the change introduced in that revision. If two revisions are passed in, this will do a diff between those two revisions. Args: revisions (dict): A dictionary of revisions, as returned by :py:meth:`parse_revision_spec`. include_files (list of unicode, optional): A list of files to whitelist during the diff generation. exclude_patterns (list of unicode, optional): A list of shell-style glob patterns to blacklist during diff generation. extra_args (list, unused): Additional arguments to be passed to the diff generation. Unused for Bazaar. **kwargs (dict, unused): Unused keyword arguments. Returns: dict: A dictionary containing the following keys: ``diff`` (:py:class:`bytes`): The contents of the diff to upload. ``parent_diff`` (:py:class:`bytes`, optional): The contents of the parent diff, if available. """ exclude_patterns = normalize_patterns(exclude_patterns, self.get_repository_info().path) diff = self._get_range_diff(revisions['base'], revisions['tip'], include_files, exclude_patterns) if 'parent_base' in revisions: parent_diff = self._get_range_diff( revisions['parent_base'], revisions['base'], include_files, exclude_patterns) else: parent_diff = None return { 'diff': diff, 'parent_diff': parent_diff, }
def diff(self, revisions, include_files=[], exclude_patterns=[], no_renames=False, extra_args=[]): """Perform a diff using the given revisions. If no revisions are specified, this will do a diff of the contents of the current branch since the tracking branch (which defaults to 'master'). If one revision is specified, this will get the diff of that specific change. If two revisions are specified, this will do a diff between those two revisions. If a parent branch is specified via the command-line options, or would make sense given the requested revisions and the tracking branch, this will also return a parent diff. """ exclude_patterns = normalize_patterns(exclude_patterns, self._get_root_directory(), cwd=self.original_cwd) try: merge_base = revisions['parent_base'] except KeyError: merge_base = revisions['base'] diff_lines = self.make_diff(merge_base, revisions['base'], revisions['tip'], include_files, exclude_patterns, no_renames) if 'parent_base' in revisions: parent_diff_lines = self.make_diff(merge_base, revisions['parent_base'], revisions['base'], include_files, exclude_patterns, no_renames) base_commit_id = revisions['parent_base'] else: parent_diff_lines = None base_commit_id = revisions['base'] return { 'diff': diff_lines, 'parent_diff': parent_diff_lines, 'commit_id': revisions.get('commit_id'), 'base_commit_id': base_commit_id, }
def diff(self, revisions, include_files=[], exclude_patterns=[], extra_args=[]): """Get the diff for the given revisions. If revision_spec is empty, this will return the diff for the modified files in the working directory. If it's not empty and contains two revisions, this will do a diff between those revisions. """ exclude_patterns = normalize_patterns(exclude_patterns) include_files = include_files or [] # Diff returns "1" if differences were found. diff_cmd = ['cvs', 'diff', '-uN'] base = revisions['base'] tip = revisions['tip'] if (not (base == 'BASE' and tip == self.REVISION_WORKING_COPY)): diff_cmd.extend(['-r', base, '-r', tip]) cwd = os.getcwd() os.chdir(self._get_repository_root()) try: diff = execute(diff_cmd + include_files, extra_ignore_errors=(1,), split_lines=True, results_unicode=False) finally: os.chdir(cwd) if exclude_patterns: diff = filter_diff(diff, self.INDEX_FILE_RE, exclude_patterns, base_dir=self._get_repository_root()) return { 'diff': b''.join(diff) }
def diff(self, revisions, include_files=[], exclude_patterns=[], extra_args=[]): """Get the diff for the given revisions. If revision_spec is empty, this will return the diff for the modified files in the working directory. If it's not empty and contains two revisions, this will do a diff between those revisions. """ exclude_patterns = normalize_patterns(exclude_patterns) include_files = include_files or [] # Diff returns "1" if differences were found. diff_cmd = ['cvs', 'diff', '-uN'] base = revisions['base'] tip = revisions['tip'] if (not (base == 'BASE' and tip == self.REVISION_WORKING_COPY)): diff_cmd.extend(['-r', base, '-r', tip]) cwd = os.getcwd() os.chdir(self._get_repository_root()) try: diff = execute(diff_cmd + include_files, extra_ignore_errors=(1,), split_lines=True) finally: os.chdir(cwd) if exclude_patterns: diff = filter_diff(diff, self.INDEX_FILE_RE, exclude_patterns, base_dir=self._get_repository_root()) return { 'diff': ''.join(diff) }
def diff(self, revisions, include_files=[], exclude_patterns=[], extra_args=[]): """Perform a diff using the given revisions. If no revisions are specified, this will do a diff of the contents of the current branch since the tracking branch (which defaults to 'master'). If one revision is specified, this will get the diff of that specific change. If two revisions are specified, this will do a diff between those two revisions. If a parent branch is specified via the command line options, or would make sense given the requested revisions and the tracking branch, this will also return a parent diff. Args: revisions (dict): A dictionary of revisions, as returned by :py:meth:`parse_revision_spec`. include_files (list of unicode, optional): A list of files to whitelist during the diff generation. exclude_patterns (list of unicode, optional): A list of shell-style glob patterns to blacklist during diff generation. extra_args (list, unused): Additional arguments to be passed to the diff generation. Unused for git. Returns: dict: A dictionary containing the following keys: ``diff`` (:py:class:`bytes`): The contents of the diff to upload. ``parent_diff`` (:py:class:`bytes`, optional): The contents of the parent diff, if available. ``commit_id`` (:py:class:`unicode`, optional): The commit ID to include when posting, if available. ``base_commit_id` (:py:class:`unicode`, optional): The ID of the commit that the change is based on, if available. This is necessary for some hosting services that don't provide individual file access. """ exclude_patterns = normalize_patterns(exclude_patterns, self._git_toplevel, cwd=os.getcwd()) try: merge_base = revisions['parent_base'] except KeyError: merge_base = revisions['base'] diff_lines = self.make_diff(merge_base, revisions['base'], revisions['tip'], include_files, exclude_patterns) if 'parent_base' in revisions: parent_diff_lines = self.make_diff(merge_base, revisions['parent_base'], revisions['base'], include_files, exclude_patterns) base_commit_id = revisions['parent_base'] else: parent_diff_lines = None base_commit_id = revisions['base'] return { 'diff': diff_lines, 'parent_diff': parent_diff_lines, 'commit_id': revisions.get('commit_id'), 'base_commit_id': base_commit_id, }
def diff(self, revisions, include_files=[], exclude_patterns=[], extra_args=[]): """ Performs a diff in a Subversion repository. If the given revision spec is empty, this will do a diff of the modified files in the working directory. If the spec is a changelist, it will do a diff of the modified files in that changelist. If the spec is a single revision, it will show the changes in that revision. If the spec is two revisions, this will do a diff between the two revisions. SVN repositories do not support branches of branches in a way that makes parent diffs possible, so we never return a parent diff. """ repository_info = self.get_repository_info() # SVN paths are always relative to the root of the repository, so we # compute the current path we are checked out at and use that as the # current working directory. We use / for the base_dir because we do # not normalize the paths to be filesystem paths, but instead use SVN # paths. exclude_patterns = normalize_patterns(exclude_patterns, '/', repository_info.base_path) # Keep track of information needed for handling empty files later. empty_files_revisions = { 'base': None, 'tip': None, } base = str(revisions['base']) tip = str(revisions['tip']) diff_cmd = ['diff', '--diff-cmd=diff', '--notice-ancestry'] changelist = None if tip == self.REVISION_WORKING_COPY: # Posting the working copy diff_cmd.extend(['-r', base]) elif tip.startswith(self.REVISION_CHANGELIST_PREFIX): # Posting a changelist changelist = tip[len(self.REVISION_CHANGELIST_PREFIX):] diff_cmd.extend(['--changelist', changelist]) else: # Diff between two separate revisions. Behavior depends on whether # or not there's a working copy if self.options.repository_url: # No working copy--create 'old' and 'new' URLs if len(include_files) == 1: # If there's a single file or directory passed in, we use # that as part of the URL instead of as a separate # filename. repository_info.set_base_path(include_files[0]) include_files = [] new_url = (repository_info.path + repository_info.base_path + '@' + tip) # When the source revision is '0', assume the user wants to # upload a diff containing all the files in 'base_path' as # new files. If the base path within the repository is added to # both the old and new URLs, `svn diff` will error out, since # the base_path didn't exist at revision 0. To avoid that # error, use the repository's root URL as the source for the # diff. if base == '0': old_url = repository_info.path + '@' + base else: old_url = (repository_info.path + repository_info.base_path + '@' + base) diff_cmd.extend([old_url, new_url]) empty_files_revisions['base'] = '(revision %s)' % base empty_files_revisions['tip'] = '(revision %s)' % tip else: # Working copy--do a normal range diff diff_cmd.extend(['-r', '%s:%s' % (base, tip)]) empty_files_revisions['base'] = '(revision %s)' % base empty_files_revisions['tip'] = '(revision %s)' % tip diff_cmd.extend(include_files) if is_valid_version(self.subversion_client_version, self.SHOW_COPIES_AS_ADDS_MIN_VERSION): svn_show_copies_as_adds = getattr(self.options, 'svn_show_copies_as_adds', None) if svn_show_copies_as_adds is None: if self.history_scheduled_with_commit(changelist, include_files, exclude_patterns): sys.stderr.write("One or more files in your changeset has " "history scheduled with commit. Please " "try again with " "'--svn-show-copies-as-adds=y/n'.\n") sys.exit(1) else: if svn_show_copies_as_adds in 'Yy': diff_cmd.append("--show-copies-as-adds") diff = self._run_svn(diff_cmd, split_lines=True, results_unicode=False, log_output_on_error=False) diff = self.handle_renames(diff) if self.supports_empty_files(): diff = self._handle_empty_files(diff, diff_cmd, empty_files_revisions) diff = self.convert_to_absolute_paths(diff, repository_info) if exclude_patterns: diff = filter_diff(diff, self.INDEX_FILE_RE, exclude_patterns) return { 'diff': b''.join(diff), }
def diff(self, revisions, include_files=[], exclude_patterns=[], extra_args=[]): """ Performs a diff in a Subversion repository. If the given revision spec is empty, this will do a diff of the modified files in the working directory. If the spec is a changelist, it will do a diff of the modified files in that changelist. If the spec is a single revision, it will show the changes in that revision. If the spec is two revisions, this will do a diff between the two revisions. SVN repositories do not support branches of branches in a way that makes parent diffs possible, so we never return a parent diff. """ repository_info = self.get_repository_info() # SVN paths are always relative to the root of the repository, so we # compute the current path we are checked out at and use that as the # current working directory. We use / for the base_dir because we do # not normalize the paths to be filesystem paths, but instead use SVN # paths. exclude_patterns = normalize_patterns(exclude_patterns, '/', repository_info.base_path) # Keep track of information needed for handling empty files later. empty_files_revisions = { 'base': None, 'tip': None, } base = str(revisions['base']) tip = str(revisions['tip']) diff_cmd = ['diff', '--diff-cmd=diff', '--notice-ancestry'] changelist = None if tip == self.REVISION_WORKING_COPY: # Posting the working copy diff_cmd.extend(['-r', base]) elif tip.startswith(self.REVISION_CHANGELIST_PREFIX): # Posting a changelist changelist = tip[len(self.REVISION_CHANGELIST_PREFIX):] diff_cmd.extend(['--changelist', changelist]) else: # Diff between two separate revisions. Behavior depends on whether # or not there's a working copy if self.options.repository_url: # No working copy--create 'old' and 'new' URLs if len(include_files) == 1: # If there's a single file or directory passed in, we use # that as part of the URL instead of as a separate # filename. repository_info.set_base_path(include_files[0]) include_files = [] new_url = (repository_info.path + repository_info.base_path + '@' + tip) # When the source revision is '0', assume the user wants to # upload a diff containing all the files in 'base_path' as # new files. If the base path within the repository is added to # both the old and new URLs, `svn diff` will error out, since # the base_path didn't exist at revision 0. To avoid that # error, use the repository's root URL as the source for the # diff. if base == '0': old_url = repository_info.path + '@' + base else: old_url = (repository_info.path + repository_info.base_path + '@' + base) diff_cmd.extend([old_url, new_url]) empty_files_revisions['base'] = '(revision %s)' % base empty_files_revisions['tip'] = '(revision %s)' % tip else: # Working copy--do a normal range diff diff_cmd.extend(['-r', '%s:%s' % (base, tip)]) empty_files_revisions['base'] = '(revision %s)' % base empty_files_revisions['tip'] = '(revision %s)' % tip diff_cmd.extend(include_files) if is_valid_version(self.subversion_client_version, self.SHOW_COPIES_AS_ADDS_MIN_VERSION): svn_show_copies_as_adds = getattr( self.options, 'svn_show_copies_as_adds', None) if svn_show_copies_as_adds is None: if self.history_scheduled_with_commit(changelist, include_files, exclude_patterns): sys.stderr.write("One or more files in your changeset has " "history scheduled with commit. Please " "try again with " "'--svn-show-copies-as-adds=y/n'.\n") sys.exit(1) else: if svn_show_copies_as_adds in 'Yy': diff_cmd.append("--show-copies-as-adds") diff = self._run_svn(diff_cmd, split_lines=True, results_unicode=False, log_output_on_error=False) diff = self.handle_renames(diff) if self.supports_empty_files(): diff = self._handle_empty_files(diff, diff_cmd, empty_files_revisions) diff = self.convert_to_absolute_paths(diff, repository_info) if exclude_patterns: diff = filter_diff(diff, self.INDEX_FILE_RE, exclude_patterns) return { 'diff': b''.join(diff), }
def diff(self, revisions, include_files=[], exclude_patterns=[], extra_args=[], **kwargs): """Perform a diff using the given revisions. If no revisions are specified, this will return the diff for the modified files in the working directory. If it's not empty and contains two revisions, this will do a diff between those revisions. Args: revisions (dict): A dictionary of revisions, as returned by :py:meth:`parse_revision_spec`. include_files (list of unicode, optional): A list of files to whitelist during the diff generation. exclude_patterns (list of unicode, optional): A list of shell-style glob patterns to blacklist during diff generation. extra_args (list, unused): Additional arguments to be passed to the diff generation. Unused for CVS. **kwargs (dict, unused): Unused keyword arguments. Returns: dict: A dictionary containing the following keys: ``diff`` (:py:class:`bytes`): The contents of the diff to upload. """ # CVS paths are always relative to the current working directory. cwd = os.getcwd() exclude_patterns = normalize_patterns(exclude_patterns, cwd, cwd) include_files = include_files or [] # Diff returns "1" if differences were found. diff_cmd = ['cvs', 'diff', '-uN'] base = revisions['base'] tip = revisions['tip'] if not (base == 'BASE' and tip == self.REVISION_WORKING_COPY): diff_cmd.extend(['-r', base, '-r', tip]) diff = execute(diff_cmd + include_files, extra_ignore_errors=(1,), log_output_on_error=False, split_lines=True, results_unicode=False) if exclude_patterns: # CVS diffs are relative to the current working directory, so the # base_dir parameter to filter_diff is unnecessary. diff = filter_diff(diff, self.INDEX_FILE_RE, exclude_patterns, base_dir=cwd) return { 'diff': b''.join(diff) }
def diff(self, revisions, include_files=[], exclude_patterns=[], extra_args=[]): """ Performs a diff in a Subversion repository. If the given revision spec is empty, this will do a diff of the modified files in the working directory. If the spec is a changelist, it will do a diff of the modified files in that changelist. If the spec is a single revision, it will show the changes in that revision. If the spec is two revisions, this will do a diff between the two revisions. SVN repositories do not support branches of branches in a way that makes parent diffs possible, so we never return a parent diff. """ exclude_patterns = normalize_patterns(exclude_patterns) # Keep track of information needed for handling empty files later. empty_files_revisions = { 'base': None, 'tip': None, } base = str(revisions['base']) tip = str(revisions['tip']) repository_info = self.get_repository_info() diff_cmd = ['diff', '--diff-cmd=diff', '--notice-ancestry'] changelist = None if tip == self.REVISION_WORKING_COPY: # Posting the working copy diff_cmd.extend(['-r', base]) elif tip.startswith(self.REVISION_CHANGELIST_PREFIX): # Posting a changelist changelist = tip[len(self.REVISION_CHANGELIST_PREFIX):] diff_cmd.extend(['--changelist', changelist]) else: # Diff between two separate revisions. Behavior depends on whether # or not there's a working copy # Working copy--do a normal range diff diff_cmd.extend(['-r', '%s:%s' % (base, tip)]) empty_files_revisions['base'] = '(revision %s)' % base empty_files_revisions['tip'] = '(revision %s)' % tip diff_cmd.extend(include_files) if self.history_scheduled_with_commit(changelist): svn_show_copies_as_adds = getattr(self.options, 'svn_show_copies_as_adds', None) if svn_show_copies_as_adds is None: sys.stderr.write("One or more files in your changeset has " "history scheduled with commit. Please try " "again with '--svn-show-copies-as-adds=y/n" "'\n") sys.exit(1) else: if svn_show_copies_as_adds in 'Yy': diff_cmd.append("--show-copies-as-adds") this_dir = os.getcwd() try: if getattr(self.options, 'repository_url', None): diff_cmd.append(self.options.repository_url) diff = self._run_svn(diff_cmd, split_lines=True) finally: os.chdir(this_dir) return { 'diff': ''.join(diff), }