def prepare_next_run(self, results_dir):
     # Running build log hooks only makes sense after a failed build
     # of new RPM packages. The folder results_dir/new-build/RPM
     # doesn't exist unless the build of new RPM packages has been run.
     changes_made = False
     if os.path.exists(os.path.join(results_dir, 'new-build', 'RPM')):
         changes_made = plugin_manager.build_log_hooks.run(self.spec_file, self.rebase_spec_file, **self.kwargs)
     # Save current rebase spec file content
     self.rebase_spec_file.save()
     if not self.conf.non_interactive and \
             InputHelper.get_message('Do you want to try it one more time'):
         logger.info('Now it is time to make changes to  %s if necessary.', self.rebase_spec_file.path)
     elif self.conf.non_interactive and changes_made:
         logger.info('Build log hooks made some changes to the SPEC file, starting the build process again.')
     else:
         return False
     if not self.conf.non_interactive and not \
             InputHelper.get_message('Do you want to continue with the rebuild now'):
         return False
     # Update rebase spec file content after potential manual modifications
     self.rebase_spec_file._read_spec_content()  # pylint: disable=protected-access
     self.rebase_spec_file._update_data()  # pylint: disable=protected-access
     # clear current version output directories
     if os.path.exists(os.path.join(results_dir, 'old-build')):
         shutil.rmtree(os.path.join(results_dir, 'old-build'))
     if os.path.exists(os.path.join(results_dir, 'new-build')):
         shutil.rmtree(os.path.join(results_dir, 'new-build'))
     return True
示例#2
0
 def prepare_next_run(self, results_dir):
     # Running build log hooks only makes sense after a failed build
     # of new RPM packages. The folder results_dir/new-build/RPM
     # doesn't exist unless the build of new RPM packages has been run.
     changes_made = False
     if os.path.exists(
             os.path.join(results_dir, constants.NEW_BUILD_DIR, 'RPM')):
         changes_made = plugin_manager.build_log_hooks.run(
             self.spec_file, self.rebase_spec_file, **self.kwargs)
     # Save current rebase spec file content
     self.rebase_spec_file.save()
     if not self.conf.non_interactive and \
             InputHelper.get_message('Do you want to try it one more time'):
         logger.info('Now it is time to make changes to  %s if necessary.',
                     self.rebase_spec_file.path)
     elif self.conf.non_interactive and changes_made:
         logger.info(
             'Build log hooks made some changes to the SPEC file, starting the build process again.'
         )
     else:
         return False
     if not self.conf.non_interactive and not \
             InputHelper.get_message('Do you want to continue with the rebuild now'):
         return False
     # Update rebase spec file content after potential manual modifications
     self.rebase_spec_file.reload()
     # clear current version output directories
     if os.path.exists(os.path.join(results_dir, constants.OLD_BUILD_DIR)):
         shutil.rmtree(os.path.join(results_dir, constants.OLD_BUILD_DIR))
     if os.path.exists(os.path.join(results_dir, constants.NEW_BUILD_DIR)):
         shutil.rmtree(os.path.join(results_dir, constants.NEW_BUILD_DIR))
     return True
示例#3
0
 def test_get_message(self, monkeypatch, capsys, suffix, answer, kwargs,
                      expected_input):
     question = 'bla bla'
     monkeypatch.setattr('sys.stdin', StringIO(answer))
     inp = InputHelper.get_message(question, **(kwargs or {}))
     assert capsys.readouterr()[0] == question + suffix
     assert inp is expected_input
示例#4
0
    def prepare(cls, spec, conf):
        """
        Checks if all build dependencies are installed. If not, asks user whether they should be installed.
        If he agrees, installs build dependencies using PolicyKit.

        :param spec: SpecFile object
        """
        req_pkgs = spec.get_requires()
        if not RpmHelper.all_packages_installed(req_pkgs):
            question = '\nSome build dependencies are missing. Do you want to install them now'
            if conf.non_interactive or InputHelper.get_message(question):
                if RpmHelper.install_build_dependencies(spec.get_path(), assume_yes=conf.non_interactive) != 0:
                    raise RebaseHelperError('Failed to install build dependencies')
示例#5
0
    def prepare(cls, spec, conf):
        """
        Checks if all build dependencies are installed. If not, asks user whether they should be installed.
        If he agrees, installs build dependencies using PolicyKit.

        :param spec: SpecFile object
        """
        req_pkgs = spec.get_requires()
        if not RpmHelper.all_packages_installed(req_pkgs):
            question = '\nSome build dependencies are missing. Do you want to install them now'
            if conf.non_interactive or InputHelper.get_message(question):
                if RpmHelper.install_build_dependencies(spec.get_path(), assume_yes=conf.non_interactive) != 0:
                    raise RebaseHelperError('Failed to install build dependencies')
示例#6
0
 def prepare_next_run(self, results_dir):
     changes_made = build_log_hook_runner.run(self.spec_file, self.rebase_spec_file, **self.kwargs)
     # Save current rebase spec file content
     self.rebase_spec_file.save()
     if not self.conf.non_interactive and \
             InputHelper.get_message('Do you want to try it one more time'):
         logger.info('Now it is time to make changes to  %s if necessary.', self.rebase_spec_file.path)
     elif self.conf.non_interactive and changes_made:
         logger.info('Build log hooks made some changes to the SPEC file, starting the build process again.')
     else:
         return False
     if not self.conf.non_interactive and not \
             InputHelper.get_message('Do you want to continue with the rebuild now'):
         return False
     # Update rebase spec file content after potential manual modifications
     self.rebase_spec_file._read_spec_content()  # pylint: disable=protected-access
     self.rebase_spec_file._update_data()  # pylint: disable=protected-access
     # clear current version output directories
     if os.path.exists(os.path.join(results_dir, 'old-build')):
         shutil.rmtree(os.path.join(results_dir, 'old-build'))
     if os.path.exists(os.path.join(results_dir, 'new-build')):
         shutil.rmtree(os.path.join(results_dir, 'new-build'))
     return True
示例#7
0
    def _git_rebase(cls):
        """Function performs git rebase between old and new sources"""
        def compare_commits(a, b):
            # compare commit diffs disregarding differences in blob hashes
            attributes = ('a_mode', 'b_mode', 'a_rawpath', 'b_rawpath',
                          'new_file', 'deleted_file', 'raw_rename_from',
                          'raw_rename_to', 'diff', 'change_type', 'score')
            diff1 = a.diff(a.parents[0], create_patch=True)
            diff2 = b.diff(b.parents[0], create_patch=True)
            if len(diff1) != len(diff2):
                return False
            for d1, d2 in zip(diff1, diff2):
                for attr in attributes:
                    if getattr(d1, attr) != getattr(d2, attr):
                        return False
            return True

        # in old_sources do:
        # 1) git remote add new_sources <path_to_new_sources>
        # 2) git fetch new_sources
        # 3) git rebase --onto new_sources/master <root_commit_old_sources> <last_commit_old_sources>
        if not os.path.exists(
                os.path.join(cls.old_sources, '.git', 'rebase-apply')):
            logger.info('git-rebase operation to %s is ongoing...',
                        os.path.basename(cls.new_sources))
            upstream = 'new_upstream'
            cls.old_repo.create_remote(upstream, url=cls.new_sources).fetch()
            root_commit = cls.old_repo.git.rev_list('HEAD', max_parents=0)
            last_commit = cls.old_repo.commit('HEAD')
            if cls.favor_on_conflict == 'upstream':
                strategy_option = 'ours'
            elif cls.favor_on_conflict == 'downstream':
                strategy_option = 'theirs'
            else:
                strategy_option = False
            try:
                cls.output_data = cls.old_repo.git.rebase(
                    root_commit,
                    last_commit,
                    strategy_option=strategy_option,
                    onto='{}/master'.format(upstream),
                    stdout_as_string=True)
            except git.GitCommandError as e:
                ret_code = e.status
                cls.output_data = e.stdout
            else:
                ret_code = 0
        else:
            logger.info('git-rebase operation continues...')
            try:
                cls.output_data = cls.old_repo.git.rebase(
                    '--continue', stdout_as_string=True)
            except git.GitCommandError as e:
                ret_code = e.status
                cls.output_data = e.stdout
            else:
                ret_code = 0
        logger.verbose(cls.output_data)
        patch_dictionary = {}
        modified_patches = []
        inapplicable_patches = []
        while ret_code != 0:
            if not cls.old_repo.index.unmerged_blobs(
            ) and not cls.old_repo.index.diff(cls.old_repo.commit()):
                # empty commit - conflict has been automatically resolved - skip
                try:
                    cls.output_data = cls.old_repo.git.rebase(
                        skip=True, stdout_as_string=True)
                except git.GitCommandError as e:
                    ret_code = e.status
                    cls.output_data = e.stdout
                    continue
                else:
                    break
            try:
                if os.path.isdir(
                        os.path.join(cls.old_sources, '.git', 'rebase-merge')):
                    with open(
                            os.path.join(cls.old_sources, '.git',
                                         'rebase-merge', 'msgnum')) as f:
                        next_index = int(f.readline())
                    with open(
                            os.path.join(cls.old_sources, '.git',
                                         'rebase-merge', 'end')) as f:
                        last_index = int(f.readline())
                else:
                    with open(
                            os.path.join(cls.old_sources, '.git',
                                         'rebase-apply', 'next')) as f:
                        next_index = int(f.readline())
                    with open(
                            os.path.join(cls.old_sources, '.git',
                                         'rebase-apply', 'last')) as f:
                        last_index = int(f.readline())
            except (FileNotFoundError, IOError) as e:
                raise RuntimeError(
                    'Git rebase failed with unknown reason. Please check log file'
                ) from e
            patch_name = cls.patches[next_index - 1].get_patch_name()
            inapplicable = False
            if cls.non_interactive:
                inapplicable = True
            else:
                logger.info('Failed to auto-merge patch %s', patch_name)
                unmerged = cls.old_repo.index.unmerged_blobs()
                GitHelper.run_mergetool(cls.old_repo)
                if cls.old_repo.index.unmerged_blobs():
                    if InputHelper.get_message(
                            'There are still unmerged entries. Do you want to skip this patch',
                            default_yes=False):
                        inapplicable = True
                    else:
                        continue
                if not inapplicable:
                    # check for unresolved conflicts
                    unresolved = []
                    for file in unmerged:
                        try:
                            with open(os.path.join(cls.old_sources, file),
                                      'rb') as f:
                                if [l for l in f if b'<<<<<<<' in l]:
                                    unresolved.append(file)
                        except FileNotFoundError:
                            # skip deleted files
                            continue
                    if unresolved:
                        if InputHelper.get_message(
                                'There are still unresolved conflicts. '
                                'Do you want to skip this patch',
                                default_yes=False):
                            inapplicable = True
                        else:
                            cls.old_repo.index.reset(paths=unresolved)
                            unresolved.insert(0, '--')
                            cls.old_repo.git.checkout(*unresolved,
                                                      conflict='diff3')
                            continue
            if inapplicable:
                inapplicable_patches.append(patch_name)
                try:
                    cls.output_data = cls.old_repo.git.rebase(
                        skip=True, stdout_as_string=True)
                except git.GitCommandError as e:
                    ret_code = e.status
                    cls.output_data = e.stdout
                    continue
                else:
                    break
            diff = cls.old_repo.index.diff(cls.old_repo.commit())
            if diff:
                modified_patches.append(patch_name)
            if next_index < last_index:
                if not InputHelper.get_message(
                        'Do you want to continue with another patch'):
                    raise KeyboardInterrupt
            try:
                if diff:
                    cls.output_data = cls.old_repo.git.rebase(
                        '--continue', stdout_as_string=True)
                else:
                    cls.output_data = cls.old_repo.git.rebase(
                        skip=True, stdout_as_string=True)
            except git.GitCommandError as e:
                ret_code = e.status
                cls.output_data = e.stdout
            else:
                break
        original_commits = list(
            cls.old_repo.iter_commits(rev=cls.old_repo.branches.master))
        commits = list(cls.old_repo.iter_commits())
        untouched_patches = []
        deleted_patches = []
        for patch in cls.patches:
            patch_name = patch.get_patch_name()
            original_commit = [
                c for c in original_commits
                if cls.extract_patch_name(c.message) == patch_name
            ]
            commit = [
                c for c in commits
                if cls.extract_patch_name(c.message) == patch_name
            ]
            if original_commit and commit:
                if patch_name not in modified_patches and compare_commits(
                        original_commit[0], commit[0]):
                    untouched_patches.append(patch_name)
                else:
                    base_name = os.path.join(cls.kwargs['rebased_sources_dir'],
                                             patch_name)
                    if commit[0].summary == cls.decorate_patch_name(
                            patch_name):
                        diff = cls.old_repo.git.diff(commit[0].parents[0],
                                                     commit[0],
                                                     stdout_as_string=False)
                    else:
                        diff = cls.old_repo.git.format_patch(
                            commit[0],
                            '-1',
                            stdout=True,
                            no_numbered=True,
                            no_attach=True,
                            stdout_as_string=False)
                        diff = cls.strip_patch_name(diff, patch_name)
                    with open(base_name, 'wb') as f:
                        f.write(diff)
                        f.write(b'\n')
                    if patch_name not in modified_patches:
                        modified_patches.append(patch_name)
            elif patch_name not in inapplicable_patches:
                deleted_patches.append(patch_name)
        if deleted_patches:
            patch_dictionary['deleted'] = deleted_patches
        if modified_patches:
            patch_dictionary['modified'] = modified_patches
        if inapplicable_patches:
            patch_dictionary['inapplicable'] = inapplicable_patches
        if untouched_patches:
            patch_dictionary['untouched'] = untouched_patches
        return patch_dictionary
 def test_get_message(self, monkeypatch, capsys, suffix, answer, kwargs, expected_input):
     question = 'bla bla'
     monkeypatch.setattr('sys.stdin', io.StringIO(answer))
     inp = InputHelper.get_message(question, **(kwargs or {}))
     assert capsys.readouterr()[0] == question + suffix
     assert inp is expected_input