def test_get_state(self): """Ensure get_state() can get a value from a state file.""" temp_state = "{}/temp_sktrc".format(self.tmpdir) # Start with an empty state file. self.assertIsNone(state_file.get_state(temp_state, 'foo')) # Create an empty state file. with open(temp_state, 'w') as fileh: fileh.write('') # Test with the empty state file. self.assertIsNone(state_file.get_state(temp_state, 'foo')) # Write a normal state file. new_state = { 'foo': 'bar', 'foo2': 'bar2', } state_file.update_state(temp_state, new_state) # Test that we get the right data. self.assertEqual(state_file.get_state(temp_state, 'foo'), 'bar') self.assertEqual(state_file.get_state(temp_state, 'foo2'), 'bar2') # Try to get an option that doesn't exist. self.assertIsNone(state_file.get_state(temp_state, 'toot'))
def test_update_state(self): """Ensure update_state() writes a state file.""" temp_state = "{}/temp_sktrc".format(self.tmpdir) new_state = { 'foo': 'bar', 'foo2': 'bar2', } state_file.update_state(temp_state, new_state) config = ConfigParser.RawConfigParser() config.read(temp_state) self.assertEqual(config.get('state', 'foo'), 'bar') self.assertEqual(config.get('state', 'foo2'), 'bar2') # Test a write with an existing state file. state_file.update_state(temp_state, new_state) config = ConfigParser.RawConfigParser() config.read(temp_state) self.assertEqual(config.get('state', 'foo'), 'bar') self.assertEqual(config.get('state', 'foo2'), 'bar2')
def cmd_build(args): """ Build the kernel with specified configuration and put it into a tarball. Args: args: Command line arguments """ global retcode tstamp = datetime.datetime.strftime(datetime.datetime.now(), "%Y%m%d%H%M%S") tgz = None builder = KernelBuilder( source_dir=args.get('workdir'), basecfg=args.get('baseconfig'), cfgtype=args.get('cfgtype'), extra_make_args=args.get('makeopts'), enable_debuginfo=args.get('enable_debuginfo'), rh_configs_glob=args.get('rh_configs_glob'), make_target=args.get('make_target'), localversion=args.get('localversion') ) # Clean the kernel source with 'make mrproper' if requested. if args.get('wipe'): builder.clean_kernel_source() # Gather additional details about the build and save them to the state # file. kernel_arch = builder.build_arch make_opts = builder.assemble_make_options() state = { 'kernel_arch': kernel_arch, 'make_opts': ' '.join(make_opts) } update_state(args['rc'], state) # Write the cross compiler prefix to the state file only if the # environment variable is set: cross_compiler_prefix = builder.cross_compiler_prefix if cross_compiler_prefix: state = {'cross_compiler_prefix': cross_compiler_prefix} update_state(args['rc'], state) # Attempt to compile the kernel. package_path = None try: package_path = builder.compile_kernel() # Handle a failure if the build times out, fails, or if the build # artifacts can't be found. except (CommandTimeoutError, subprocess.CalledProcessError, ParsingError, IOError) as exc: logging.error(exc) # Update the state file with the path to the build log. state = {'buildlog': builder.buildlog} update_state(args['rc'], state) # Set the return code. retcode = SKT_FAIL # Re-raise any unexpected exceptions. except Exception: (exc, exc_type, trace) = sys.exc_info() raise exc, exc_type, trace # Get the SHA of the commit from the repo that we just compiled. buildhead = get_state(args['rc'], 'buildhead') # Handle any built tarballs. if package_path and package_path.endswith('tar.gz'): if buildhead: # Replace the filename with the SHA of the last commit in the repo. ttgz = "{}.tar.gz".format(buildhead) else: # Add a timestamp to the path if we have no commit to reference. ttgz = addtstamp(tgz, tstamp) # Rename the kernel tarball. shutil.move(package_path, ttgz) logging.info("tarball path: %s", ttgz) # Save our tarball path to the state file. state = {'tarpkg': ttgz} update_state(args['rc'], state) # Handle any RPM repositories. if package_path and 'rpm_repo' in package_path: state = {'rpm_repo': package_path} update_state(args['rc'], state) # Set a filename for the kernel config file based on the SHA of the last # commit in the repo. tconfig = '{}.config'.format(buildhead) try: # Rename the config file and save its location to our state file. shutil.copyfile(builder.get_cfgpath(), tconfig) state = {'buildconf': tconfig} update_state(args['rc'], state) # Get the kernel version string. tag = get_state(args['rc'], 'tag') krelease = builder.getrelease() if tag and tag != "": index = krelease.rfind('.') if '-' in krelease: # In case of 5.1.0-rc1.cki # (removes the -rc1 since that's in the tag already) dash = krelease.rfind('-') krelease = krelease[:dash] + krelease[index:] index = krelease.rfind('.') krelease = krelease[:index] + "-" + tag + krelease[index:] state = {'krelease': krelease} update_state(args['rc'], state) except IOError: # Kernel config failed to build tconfig = '' logging.error('No config file to copy found!')
def cmd_merge(args): """ Fetch a kernel repository, checkout particular references, and optionally apply patches from patchwork instances. Args: args: Command line arguments """ global retcode # Counter merge patch following: # idx[0]: counter of merge-ref option. # idx[1]: counter of patch option. # idx[2]: counter of pw option. idx = [0, 0, 0] # Clone the kernel tree and check out the proper ref. ktree = KernelTree( args.get('baserepo'), ref=args.get('ref'), wdir=full_path(args.get('workdir')), fetch_depth=args.get('fetch_depth') ) bhead = ktree.checkout() # Gather the subject and date of the commit that is currently checked out. bsubject = ktree.get_commit_subject(bhead) commitdate = ktree.get_commit_date(bhead) # Update the state file with what we know so far. state = { 'baserepo': args.get('baserepo'), 'basehead': bhead, 'basesubject': bsubject, 'commitdate': commitdate, 'workdir': full_path(args.get('workdir')), 'tag': get_tag(full_path(args.get('workdir'))), } update_state(args['rc'], state) # Loop over what we have been asked to merge (if applicable). for thing_to_merge in args.get('merge_queue', []): try: if thing_to_merge[0] == 'merge_ref': mbranch_ref = thing_to_merge[1].split() # Update the state file with our merge_ref data. state = { 'mergerepo_%02d' % idx[0]: mbranch_ref[0], 'mergehead_%02d' % idx[0]: bhead } update_state(args['rc'], state) # Merge the git ref. (retcode, bhead) = ktree.merge_git_ref(*mbranch_ref) if retcode: return # Increment the counter. idx[0] += 1 else: # Attempt to merge a local patch. if thing_to_merge[0] == 'patch': # Get the full path to the patch to merge. patch = os.path.abspath(thing_to_merge[1]) # Update the state file with our local patch data. state = {'localpatch_%02d' % idx[1]: patch} update_state(args['rc'], state) # Merge the patch. ktree.merge_patch_file(patch) # Increment the counter. idx[1] += 1 # Attempt to merge a patch from patchwork. elif thing_to_merge[0] == 'pw': patch = thing_to_merge[1] # Update the state file with our patchwork patch data. state = {'patchwork_%02d' % idx[2]: patch} update_state(args['rc'], state) # Merge the patch. Retrieve the Patchwork session cookie # first. session_id = get_state(args['rc'], 'patchwork_session_cookie') ktree.merge_patchwork_patch(patch, session_id) # Increment the counter. idx[2] += 1 # If the patch application failed, we should set the return code, # log an error, and update our state file. except PatchApplicationError as patch_exc: retcode = SKT_FAIL logging.error(patch_exc) # Update the state. state = {'mergelog': ktree.mergelog} update_state(args['rc'], state) return # If something else unexpected happened, re-raise the exception. except Exception: (exc, exc_type, trace) = sys.exc_info() raise exc, exc_type, trace # Get the SHA and subject of the repo after applying patches. buildhead = ktree.get_commit_hash() buildsubject = ktree.get_commit_subject() # Update the state file with the data about the current repo commit. state = { 'buildhead': buildhead, 'buildsubject': buildsubject } update_state(args['rc'], state)
def cmd_build(args): """ Build the kernel with specified configuration and put it into a tarball. Args: args: Command line arguments """ global retcode tstamp = datetime.datetime.strftime(datetime.datetime.now(), "%Y%m%d%H%M%S") tgz = None builder = KernelBuilder(source_dir=args.get('workdir'), basecfg=args.get('baseconfig'), cfgtype=args.get('cfgtype'), extra_make_args=args.get('makeopts'), enable_debuginfo=args.get('enable_debuginfo'), rh_configs_glob=args.get('rh_configs_glob'), localversion=args.get('localversion')) # Clean the kernel source with 'make mrproper' if requested. if args.get('wipe'): builder.clean_kernel_source() # Gather additional details about the build and save them to the state # file. kernel_arch = builder.build_arch cross_compiler_prefix = builder.cross_compiler_prefix make_opts = builder.assemble_make_options() state = { 'kernel_arch': kernel_arch, 'cross_compiler_prefix': cross_compiler_prefix, 'make_opts': make_opts } update_state(args['rc'], state) # Attempt to compile the kernel. try: tgz = builder.mktgz() # Handle a failure if the build times out, fails, or if the build # artifacts can't be found. except (CommandTimeoutError, subprocess.CalledProcessError, ParsingError, IOError) as exc: logging.error(exc) # Update the state file with the path to the build log. state = {'buildlog': builder.buildlog} update_state(args['rc'], state) # Set the return code. retcode = SKT_FAIL # Re-raise any unexpected exceptions. except Exception: (exc, exc_type, trace) = sys.exc_info() raise exc, exc_type, trace # Get the SHA of the commit from the repo that we just compiled. buildhead = get_state(args['rc'], 'buildhead') if tgz: if buildhead: # Replace the filename with the SHA of the last commit in the repo. ttgz = "{}.tar.gz".format(buildhead) else: # Add a timestamp to the path if we have no commit to reference. ttgz = addtstamp(tgz, tstamp) # Rename the kernel tarball. shutil.move(tgz, ttgz) logging.info("tarball path: %s", ttgz) # Save our tarball path to the state file. state = {'tarpkg': ttgz} update_state(args['rc'], state) # Set a filename for the kernel config file based on the SHA of the last # commit in the repo. tconfig = '{}.config'.format(buildhead) try: # Rename the config file and save its location to our state file. shutil.copyfile(builder.get_cfgpath(), tconfig) state = {'buildconf': tconfig} update_state(args['rc'], state) # Get the kernel version string. krelease = builder.getrelease() state = {'krelease': krelease} update_state(args['rc'], state) except IOError: # Kernel config failed to build tconfig = '' logging.error('No config file to copy found!')