xref: /OK3568_Linux_fs/yocto/poky/meta/lib/oeqa/utils/testexport.py (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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