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
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
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
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')
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
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