1*4882a593Smuzhiyun# 2*4882a593Smuzhiyun# Copyright (C) 2015 Intel Corporation 3*4882a593Smuzhiyun# 4*4882a593Smuzhiyun# SPDX-License-Identifier: MIT 5*4882a593Smuzhiyun# 6*4882a593Smuzhiyun 7*4882a593Smuzhiyun# Provides functions to help with exporting binaries obtained from built targets 8*4882a593Smuzhiyun 9*4882a593Smuzhiyunimport os, re, glob as g, shutil as sh,sys 10*4882a593Smuzhiyunfrom time import sleep 11*4882a593Smuzhiyunfrom .commands import runCmd 12*4882a593Smuzhiyunfrom difflib import SequenceMatcher as SM 13*4882a593Smuzhiyun 14*4882a593Smuzhiyuntry: 15*4882a593Smuzhiyun import bb 16*4882a593Smuzhiyunexcept ImportError: 17*4882a593Smuzhiyun class my_log(): 18*4882a593Smuzhiyun def __init__(self): 19*4882a593Smuzhiyun pass 20*4882a593Smuzhiyun def plain(self, msg): 21*4882a593Smuzhiyun if msg: 22*4882a593Smuzhiyun print(msg) 23*4882a593Smuzhiyun def warn(self, msg): 24*4882a593Smuzhiyun if msg: 25*4882a593Smuzhiyun print("WARNING: " + msg) 26*4882a593Smuzhiyun def fatal(self, msg): 27*4882a593Smuzhiyun if msg: 28*4882a593Smuzhiyun print("FATAL:" + msg) 29*4882a593Smuzhiyun sys.exit(1) 30*4882a593Smuzhiyun bb = my_log() 31*4882a593Smuzhiyun 32*4882a593Smuzhiyun 33*4882a593Smuzhiyundef determine_if_poky_env(): 34*4882a593Smuzhiyun """ 35*4882a593Smuzhiyun used to determine if we are inside the poky env or not. Usefull for remote machine where poky is not present 36*4882a593Smuzhiyun """ 37*4882a593Smuzhiyun check_env = True if ("/scripts" and "/bitbake/bin") in os.getenv("PATH") else False 38*4882a593Smuzhiyun return check_env 39*4882a593Smuzhiyun 40*4882a593Smuzhiyun 41*4882a593Smuzhiyundef get_dest_folder(tune_features, folder_list): 42*4882a593Smuzhiyun """ 43*4882a593Smuzhiyun Function to determine what rpm deploy dir to choose for a given architecture based on TUNE_FEATURES 44*4882a593Smuzhiyun """ 45*4882a593Smuzhiyun features_list = tune_features.split(" ") 46*4882a593Smuzhiyun features_list.reverse() 47*4882a593Smuzhiyun features_list = "_".join(features_list) 48*4882a593Smuzhiyun match_rate = 0 49*4882a593Smuzhiyun best_match = None 50*4882a593Smuzhiyun for folder in folder_list: 51*4882a593Smuzhiyun curr_match_rate = SM(None, folder, features_list).ratio() 52*4882a593Smuzhiyun if curr_match_rate > match_rate: 53*4882a593Smuzhiyun match_rate = curr_match_rate 54*4882a593Smuzhiyun best_match = folder 55*4882a593Smuzhiyun return best_match 56*4882a593Smuzhiyun 57*4882a593Smuzhiyun 58*4882a593Smuzhiyundef process_binaries(d, params): 59*4882a593Smuzhiyun param_list = params 60*4882a593Smuzhiyun export_env = d.getVar("TEST_EXPORT_ONLY") 61*4882a593Smuzhiyun 62*4882a593Smuzhiyun def extract_binary(pth_to_pkg, dest_pth=None): 63*4882a593Smuzhiyun cpio_command = runCmd("which cpio") 64*4882a593Smuzhiyun rpm2cpio_command = runCmd("ls /usr/bin/rpm2cpio") 65*4882a593Smuzhiyun if (cpio_command.status != 0) and (rpm2cpio_command.status != 0): 66*4882a593Smuzhiyun bb.fatal("Either \"rpm2cpio\" or \"cpio\" tools are not available on your system." 67*4882a593Smuzhiyun "All binaries extraction processes will not be available, crashing all related tests." 68*4882a593Smuzhiyun "Please install them according to your OS recommendations") # will exit here 69*4882a593Smuzhiyun if dest_pth: 70*4882a593Smuzhiyun os.chdir(dest_pth) 71*4882a593Smuzhiyun else: 72*4882a593Smuzhiyun os.chdir("%s" % os.sep)# this is for native package 73*4882a593Smuzhiyun extract_bin_command = runCmd("%s %s | %s -idm" % (rpm2cpio_command.output, pth_to_pkg, cpio_command.output)) # semi-hardcoded because of a bug on poky's rpm2cpio 74*4882a593Smuzhiyun return extract_bin_command 75*4882a593Smuzhiyun 76*4882a593Smuzhiyun if determine_if_poky_env(): # machine with poky environment 77*4882a593Smuzhiyun exportpath = d.getVar("TEST_EXPORT_DIR") if export_env else d.getVar("DEPLOY_DIR") 78*4882a593Smuzhiyun rpm_deploy_dir = d.getVar("DEPLOY_DIR_RPM") 79*4882a593Smuzhiyun arch = get_dest_folder(d.getVar("TUNE_FEATURES"), os.listdir(rpm_deploy_dir)) 80*4882a593Smuzhiyun arch_rpm_dir = os.path.join(rpm_deploy_dir, arch) 81*4882a593Smuzhiyun extracted_bin_dir = os.path.join(exportpath,"binaries", arch, "extracted_binaries") 82*4882a593Smuzhiyun packaged_bin_dir = os.path.join(exportpath,"binaries", arch, "packaged_binaries") 83*4882a593Smuzhiyun # creating necessary directory structure in case testing is done in poky env. 84*4882a593Smuzhiyun if export_env == "0": 85*4882a593Smuzhiyun if not os.path.exists(extracted_bin_dir): bb.utils.mkdirhier(extracted_bin_dir) 86*4882a593Smuzhiyun if not os.path.exists(packaged_bin_dir): bb.utils.mkdirhier(packaged_bin_dir) 87*4882a593Smuzhiyun 88*4882a593Smuzhiyun if param_list[3] == "native": 89*4882a593Smuzhiyun if export_env == "1": #this is a native package and we only need to copy it. no need for extraction 90*4882a593Smuzhiyun native_rpm_dir = os.path.join(rpm_deploy_dir, get_dest_folder("{} nativesdk".format(d.getVar("BUILD_SYS")), os.listdir(rpm_deploy_dir))) 91*4882a593Smuzhiyun native_rpm_file_list = [item for item in os.listdir(native_rpm_dir) if re.search("nativesdk-" + param_list[0] + "-([0-9]+\.*)", item)] 92*4882a593Smuzhiyun if not native_rpm_file_list: 93*4882a593Smuzhiyun bb.warn("Couldn't find any version of {} native package. Related tests will most probably fail.".format(param_list[0])) 94*4882a593Smuzhiyun return "" 95*4882a593Smuzhiyun for item in native_rpm_file_list:# will copy all versions of package. Used version will be selected on remote machine 96*4882a593Smuzhiyun bb.plain("Copying native package file: %s" % item) 97*4882a593Smuzhiyun sh.copy(os.path.join(rpm_deploy_dir, native_rpm_dir, item), os.path.join(d.getVar("TEST_EXPORT_DIR"), "binaries", "native")) 98*4882a593Smuzhiyun else: # nothing to do here; running tests under bitbake, so we asume native binaries are in sysroots dir. 99*4882a593Smuzhiyun if param_list[1] or param_list[4]: 100*4882a593Smuzhiyun bb.warn("Native binary %s %s%s. Running tests under bitbake environment. Version can't be checked except when the test itself does it" 101*4882a593Smuzhiyun " and binary can't be removed."%(param_list[0],"has assigned ver. " + param_list[1] if param_list[1] else "", 102*4882a593Smuzhiyun ", is marked for removal" if param_list[4] else "")) 103*4882a593Smuzhiyun else:# the package is target aka DUT intended and it is either required to be delivered in an extracted form or in a packaged version 104*4882a593Smuzhiyun target_rpm_file_list = [item for item in os.listdir(arch_rpm_dir) if re.search(param_list[0] + "-([0-9]+\.*)", item)] 105*4882a593Smuzhiyun if not target_rpm_file_list: 106*4882a593Smuzhiyun bb.warn("Couldn't find any version of target package %s. Please ensure it was built. " 107*4882a593Smuzhiyun "Related tests will probably fail." % param_list[0]) 108*4882a593Smuzhiyun return "" 109*4882a593Smuzhiyun if param_list[2] == "rpm": # binary should be deployed as rpm; (other, .deb, .ipk? ; in the near future) 110*4882a593Smuzhiyun for item in target_rpm_file_list: # copying all related rpm packages. "Intuition" reasons, someone may need other versions too. Deciding later on version 111*4882a593Smuzhiyun bb.plain("Copying target specific packaged file: %s" % item) 112*4882a593Smuzhiyun sh.copy(os.path.join(arch_rpm_dir, item), packaged_bin_dir) 113*4882a593Smuzhiyun return "copied" 114*4882a593Smuzhiyun else: # it is required to extract the binary 115*4882a593Smuzhiyun if param_list[1]: # the package is versioned 116*4882a593Smuzhiyun for item in target_rpm_file_list: 117*4882a593Smuzhiyun if re.match(".*-{}-.*\.rpm".format(param_list[1]), item): 118*4882a593Smuzhiyun destination = os.path.join(extracted_bin_dir,param_list[0], param_list[1]) 119*4882a593Smuzhiyun bb.utils.mkdirhier(destination) 120*4882a593Smuzhiyun extract_binary(os.path.join(arch_rpm_dir, item), destination) 121*4882a593Smuzhiyun break 122*4882a593Smuzhiyun else: 123*4882a593Smuzhiyun bb.warn("Couldn't find the desired version %s for target binary %s. Related test cases will probably fail." % (param_list[1], param_list[0])) 124*4882a593Smuzhiyun return "" 125*4882a593Smuzhiyun return "extracted" 126*4882a593Smuzhiyun else: # no version provided, just extract one binary 127*4882a593Smuzhiyun destination = os.path.join(extracted_bin_dir,param_list[0], 128*4882a593Smuzhiyun re.search(".*-([0-9]+\.[0-9]+)-.*rpm", target_rpm_file_list[0]).group(1)) 129*4882a593Smuzhiyun bb.utils.mkdirhier(destination) 130*4882a593Smuzhiyun extract_binary(os.path.join(arch_rpm_dir, target_rpm_file_list[0]), destination) 131*4882a593Smuzhiyun return "extracted" 132*4882a593Smuzhiyun else: # remote machine 133*4882a593Smuzhiyun binaries_path = os.getenv("bin_dir")# in order to know where the binaries are, bin_dir is set as env. variable 134*4882a593Smuzhiyun if param_list[3] == "native": #need to extract the native pkg here 135*4882a593Smuzhiyun native_rpm_dir = os.path.join(binaries_path, "native") 136*4882a593Smuzhiyun native_rpm_file_list = os.listdir(native_rpm_dir) 137*4882a593Smuzhiyun for item in native_rpm_file_list: 138*4882a593Smuzhiyun if param_list[1] and re.match("nativesdk-{}-{}-.*\.rpm".format(param_list[0], param_list[1]), item): # native package has version 139*4882a593Smuzhiyun extract_binary(os.path.join(native_rpm_dir, item)) 140*4882a593Smuzhiyun break 141*4882a593Smuzhiyun else:# just copy any related native binary 142*4882a593Smuzhiyun found_version = re.match("nativesdk-{}-([0-9]+\.[0-9]+)-".format(param_list[0]), item).group(1) 143*4882a593Smuzhiyun if found_version: 144*4882a593Smuzhiyun extract_binary(os.path.join(native_rpm_dir, item)) 145*4882a593Smuzhiyun else: 146*4882a593Smuzhiyun bb.warn("Couldn't find native package %s%s. Related test cases will be influenced." % 147*4882a593Smuzhiyun (param_list[0], " with version " + param_list[1] if param_list[1] else "")) 148*4882a593Smuzhiyun return 149*4882a593Smuzhiyun 150*4882a593Smuzhiyun else: # this is for target device 151*4882a593Smuzhiyun if param_list[2] == "rpm": 152*4882a593Smuzhiyun return "No need to extract, this is an .rpm file" 153*4882a593Smuzhiyun arch = get_dest_folder(d.getVar("TUNE_FEATURES"), os.listdir(binaries_path)) 154*4882a593Smuzhiyun extracted_bin_path = os.path.join(binaries_path, arch, "extracted_binaries") 155*4882a593Smuzhiyun extracted_bin_list = [item for item in os.listdir(extracted_bin_path)] 156*4882a593Smuzhiyun packaged_bin_path = os.path.join(binaries_path, arch, "packaged_binaries") 157*4882a593Smuzhiyun packaged_bin_file_list = os.listdir(packaged_bin_path) 158*4882a593Smuzhiyun # see if the package is already in the extracted ones; maybe it was deployed when exported the env. 159*4882a593Smuzhiyun if os.path.exists(os.path.join(extracted_bin_path, param_list[0], param_list[1] if param_list[1] else "")): 160*4882a593Smuzhiyun return "binary %s is already extracted" % param_list[0] 161*4882a593Smuzhiyun else: # we need to search for it in the packaged binaries directory. It may have been shipped after export 162*4882a593Smuzhiyun for item in packaged_bin_file_list: 163*4882a593Smuzhiyun if param_list[1]: 164*4882a593Smuzhiyun if re.match("%s-%s.*rpm" % (param_list[0], param_list[1]), item): # package with version 165*4882a593Smuzhiyun if not os.path.exists(os.path.join(extracted_bin_path, param_list[0],param_list[1])): 166*4882a593Smuzhiyun os.makedirs(os.path.join(extracted_bin_path, param_list[0], param_list[1])) 167*4882a593Smuzhiyun extract_binary(os.path.join(packaged_bin_path, item), os.path.join(extracted_bin_path, param_list[0],param_list[1])) 168*4882a593Smuzhiyun bb.plain("Using {} for {}".format(os.path.join(packaged_bin_path, item), param_list[0])) 169*4882a593Smuzhiyun break 170*4882a593Smuzhiyun else: 171*4882a593Smuzhiyun if re.match("%s-.*rpm" % param_list[0], item): 172*4882a593Smuzhiyun found_version = re.match(".*-([0-9]+\.[0-9]+)-", item).group(1) 173*4882a593Smuzhiyun if not os.path.exists(os.path.join(extracted_bin_path, param_list[0], found_version)): 174*4882a593Smuzhiyun os.makedirs(os.path.join(extracted_bin_path, param_list[0], found_version)) 175*4882a593Smuzhiyun bb.plain("Used ver. %s for %s" % (found_version, param_list[0])) 176*4882a593Smuzhiyun extract_binary(os.path.join(packaged_bin_path, item), os.path.join(extracted_bin_path, param_list[0], found_version)) 177*4882a593Smuzhiyun break 178*4882a593Smuzhiyun else: 179*4882a593Smuzhiyun bb.warn("Couldn't find target package %s%s. Please ensure it is available " 180*4882a593Smuzhiyun "in either of these directories: extracted_binaries or packaged_binaries. " 181*4882a593Smuzhiyun "Related tests will probably fail." % (param_list[0], " with version " + param_list[1] if param_list[1] else "")) 182*4882a593Smuzhiyun return 183*4882a593Smuzhiyun return "Binary %s extracted successfully." % param_list[0] 184*4882a593Smuzhiyun 185*4882a593Smuzhiyun 186*4882a593Smuzhiyundef files_to_copy(base_dir): 187*4882a593Smuzhiyun """ 188*4882a593Smuzhiyun Produces a list of files relative to the base dir path sent as param 189*4882a593Smuzhiyun :return: the list of relative path files 190*4882a593Smuzhiyun """ 191*4882a593Smuzhiyun files_list = [] 192*4882a593Smuzhiyun dir_list = [base_dir] 193*4882a593Smuzhiyun count = 1 194*4882a593Smuzhiyun dir_count = 1 195*4882a593Smuzhiyun while (dir_count == 1 or dir_count != count): 196*4882a593Smuzhiyun count = dir_count 197*4882a593Smuzhiyun for dir in dir_list: 198*4882a593Smuzhiyun for item in os.listdir(dir): 199*4882a593Smuzhiyun if os.path.isdir(os.path.join(dir, item)) and os.path.join(dir, item) not in dir_list: 200*4882a593Smuzhiyun dir_list.append(os.path.join(dir, item)) 201*4882a593Smuzhiyun dir_count = len(dir_list) 202*4882a593Smuzhiyun elif os.path.join(dir, item) not in files_list and os.path.isfile(os.path.join(dir, item)): 203*4882a593Smuzhiyun files_list.append(os.path.join(dir, item)) 204*4882a593Smuzhiyun return files_list 205*4882a593Smuzhiyun 206*4882a593Smuzhiyun 207*4882a593Smuzhiyundef send_bin_to_DUT(d,params): 208*4882a593Smuzhiyun from oeqa.oetest import oeRuntimeTest 209*4882a593Smuzhiyun param_list = params 210*4882a593Smuzhiyun cleanup_list = list() 211*4882a593Smuzhiyun bins_dir = os.path.join(d.getVar("TEST_EXPORT_DIR"), "binaries") if determine_if_poky_env() \ 212*4882a593Smuzhiyun else os.getenv("bin_dir") 213*4882a593Smuzhiyun arch = get_dest_folder(d.getVar("TUNE_FEATURES"), os.listdir(bins_dir)) 214*4882a593Smuzhiyun arch_rpms_dir = os.path.join(bins_dir, arch, "packaged_binaries") 215*4882a593Smuzhiyun extracted_bin_dir = os.path.join(bins_dir, arch, "extracted_binaries", param_list[0]) 216*4882a593Smuzhiyun 217*4882a593Smuzhiyun def send_extracted_binary(): 218*4882a593Smuzhiyun bin_local_dir = os.path.join(extracted_bin_dir, param_list[1] if param_list[1] else os.listdir(extracted_bin_dir)[0]) 219*4882a593Smuzhiyun for item in files_to_copy(bin_local_dir): 220*4882a593Smuzhiyun split_path = item.split(bin_local_dir)[1] 221*4882a593Smuzhiyun path_on_DUT = split_path if split_path[0] is "/" else "/" + split_path # create the path as on DUT; eg. /usr/bin/bin_file 222*4882a593Smuzhiyun (status, output) = oeRuntimeTest.tc.target.copy_to(item, path_on_DUT) 223*4882a593Smuzhiyun if status != 0: 224*4882a593Smuzhiyun bb.warn("Failed to copy %s binary file %s on the remote target: %s" % 225*4882a593Smuzhiyun (param_list[0], "ver. " + param_list[1] if param_list[1] else "", d.getVar("MACHINE"))) 226*4882a593Smuzhiyun return 227*4882a593Smuzhiyun if param_list[4] == "rm": 228*4882a593Smuzhiyun cleanup_list.append(path_on_DUT) 229*4882a593Smuzhiyun return cleanup_list 230*4882a593Smuzhiyun 231*4882a593Smuzhiyun def send_rpm(remote_path): # if it is not required to have an extracted binary, but to send an .rpm file 232*4882a593Smuzhiyun rpm_to_send = "" 233*4882a593Smuzhiyun for item in os.listdir(arch_rpms_dir): 234*4882a593Smuzhiyun if param_list[1] and re.match("%s-%s-.*rpm"%(param_list[0], param_list[1]), item): 235*4882a593Smuzhiyun rpm_to_send = item 236*4882a593Smuzhiyun break 237*4882a593Smuzhiyun elif re.match("%s-[0-9]+\.[0-9]+-.*rpm" % param_list[0], item): 238*4882a593Smuzhiyun rpm_to_send = item 239*4882a593Smuzhiyun break 240*4882a593Smuzhiyun else: 241*4882a593Smuzhiyun bb.warn("No rpm package found for %s %s in .rpm files dir %s. Skipping deployment." % 242*4882a593Smuzhiyun (param_list[0], "ver. " + param_list[1] if param_list[1] else "", rpms_file_dir) ) 243*4882a593Smuzhiyun return 244*4882a593Smuzhiyun (status, output) = oeRuntimeTest.tc.target.copy_to(os.path.join(arch_rpms_dir, rpm_to_send), remote_path) 245*4882a593Smuzhiyun if status != 0: 246*4882a593Smuzhiyun bb.warn("Failed to copy %s on the remote target: %s" %(param_list[0], d.getVar("MACHINE"))) 247*4882a593Smuzhiyun return 248*4882a593Smuzhiyun if param_list[4] == "rm": 249*4882a593Smuzhiyun cleanup_list.append(os.path.join(remote_path, rpm_to_send)) 250*4882a593Smuzhiyun return cleanup_list 251*4882a593Smuzhiyun 252*4882a593Smuzhiyun if param_list[2] == "rpm": # send an .rpm file 253*4882a593Smuzhiyun return send_rpm("/home/root") # rpms will be sent on home dir of remote machine 254*4882a593Smuzhiyun else: 255*4882a593Smuzhiyun return send_extracted_binary() 256*4882a593Smuzhiyun 257*4882a593Smuzhiyun 258*4882a593Smuzhiyundef rm_bin(removal_list): # need to know both if the binary is sent archived and the path where it is sent if archived 259*4882a593Smuzhiyun from oeqa.oetest import oeRuntimeTest 260*4882a593Smuzhiyun for item in removal_list: 261*4882a593Smuzhiyun (status,output) = oeRuntimeTest.tc.target.run("rm " + item) 262*4882a593Smuzhiyun if status != 0: 263*4882a593Smuzhiyun bb.warn("Failed to remove: %s. Please ensure connection with the target device is up and running and " 264*4882a593Smuzhiyun "you have the needed rights." % item) 265*4882a593Smuzhiyun 266