xref: /aosp_15_r20/external/toolchain-utils/cros_utils/misc.py (revision 760c253c1ed00ce9abd48f8546f08516e57485fe)
1*760c253cSXin Li# -*- coding: utf-8 -*-
2*760c253cSXin Li# Copyright 2013 The ChromiumOS Authors
3*760c253cSXin Li# Use of this source code is governed by a BSD-style license that can be
4*760c253cSXin Li# found in the LICENSE file.
5*760c253cSXin Li
6*760c253cSXin Li"""Utilities for toolchain build."""
7*760c253cSXin Li
8*760c253cSXin Li
9*760c253cSXin Li__author__ = "[email protected] (Ahmad Sharif)"
10*760c253cSXin Li
11*760c253cSXin Lifrom contextlib import contextmanager
12*760c253cSXin Liimport os
13*760c253cSXin Liimport re
14*760c253cSXin Liimport shutil
15*760c253cSXin Liimport sys
16*760c253cSXin Li
17*760c253cSXin Lifrom cros_utils import command_executer
18*760c253cSXin Lifrom cros_utils import logger
19*760c253cSXin Li
20*760c253cSXin Li
21*760c253cSXin LiCHROMEOS_SCRIPTS_DIR = "/mnt/host/source/src/scripts"
22*760c253cSXin LiTOOLCHAIN_UTILS_PATH = (
23*760c253cSXin Li    "/mnt/host/source/src/third_party/toolchain-utils/"
24*760c253cSXin Li    "cros_utils/toolchain_utils.sh"
25*760c253cSXin Li)
26*760c253cSXin Li
27*760c253cSXin Li
28*760c253cSXin Lidef GetChromeOSVersionFromLSBVersion(lsb_version):
29*760c253cSXin Li    """Get Chromeos version from Lsb version."""
30*760c253cSXin Li    ce = command_executer.GetCommandExecuter()
31*760c253cSXin Li    command = (
32*760c253cSXin Li        "git ls-remote "
33*760c253cSXin Li        "https://chromium.googlesource.com/chromiumos/manifest.git "
34*760c253cSXin Li        "refs/heads/release-R*"
35*760c253cSXin Li    )
36*760c253cSXin Li    ret, out, _ = ce.RunCommandWOutput(command, print_to_console=False)
37*760c253cSXin Li    assert ret == 0, "Command %s failed" % command
38*760c253cSXin Li    lower = []
39*760c253cSXin Li    for line in out.splitlines():
40*760c253cSXin Li        mo = re.search(r"refs/heads/release-R(\d+)-(\d+)\.B", line)
41*760c253cSXin Li        if mo:
42*760c253cSXin Li            revision = int(mo.group(1))
43*760c253cSXin Li            build = int(mo.group(2))
44*760c253cSXin Li            lsb_build = int(lsb_version.split(".")[0])
45*760c253cSXin Li            if lsb_build > build:
46*760c253cSXin Li                lower.append(revision)
47*760c253cSXin Li    lower = sorted(lower)
48*760c253cSXin Li    if lower:
49*760c253cSXin Li        return "R%d-%s" % (lower[-1] + 1, lsb_version)
50*760c253cSXin Li    else:
51*760c253cSXin Li        return "Unknown"
52*760c253cSXin Li
53*760c253cSXin Li
54*760c253cSXin Lidef ApplySubs(string, *substitutions):
55*760c253cSXin Li    for pattern, replacement in substitutions:
56*760c253cSXin Li        string = re.sub(pattern, replacement, string)
57*760c253cSXin Li    return string
58*760c253cSXin Li
59*760c253cSXin Li
60*760c253cSXin Lidef UnitToNumber(unit_num, base=1000):
61*760c253cSXin Li    """Convert a number with unit to float."""
62*760c253cSXin Li    unit_dict = {"kilo": base, "mega": base**2, "giga": base**3}
63*760c253cSXin Li    unit_num = unit_num.lower()
64*760c253cSXin Li    mo = re.search(r"(\d*)(.+)?", unit_num)
65*760c253cSXin Li    number = mo.group(1)
66*760c253cSXin Li    unit = mo.group(2)
67*760c253cSXin Li    if not unit:
68*760c253cSXin Li        return float(number)
69*760c253cSXin Li    for k, v in unit_dict.items():
70*760c253cSXin Li        if k.startswith(unit):
71*760c253cSXin Li            return float(number) * v
72*760c253cSXin Li    raise RuntimeError("Unit: %s not found in byte: %s!" % (unit, unit_num))
73*760c253cSXin Li
74*760c253cSXin Li
75*760c253cSXin Lidef GetFilenameFromString(string):
76*760c253cSXin Li    return ApplySubs(
77*760c253cSXin Li        string,
78*760c253cSXin Li        (r"/", "__"),
79*760c253cSXin Li        (r"\s", "_"),
80*760c253cSXin Li        (r'[\\$="?^]', ""),
81*760c253cSXin Li    )
82*760c253cSXin Li
83*760c253cSXin Li
84*760c253cSXin Lidef GetRoot(scr_name):
85*760c253cSXin Li    """Break up pathname into (dir+name)."""
86*760c253cSXin Li    abs_path = os.path.abspath(scr_name)
87*760c253cSXin Li    return (os.path.dirname(abs_path), os.path.basename(abs_path))
88*760c253cSXin Li
89*760c253cSXin Li
90*760c253cSXin Lidef GetChromeOSKeyFile(chromeos_root):
91*760c253cSXin Li    return os.path.join(
92*760c253cSXin Li        chromeos_root,
93*760c253cSXin Li        "chromite",
94*760c253cSXin Li        "ssh_keys",
95*760c253cSXin Li        "testing_rsa",
96*760c253cSXin Li    )
97*760c253cSXin Li
98*760c253cSXin Li
99*760c253cSXin Lidef GetInsideChrootPath(chromeos_root, file_path):
100*760c253cSXin Li    sys.path.insert(0, chromeos_root)
101*760c253cSXin Li
102*760c253cSXin Li    from chromite.lib import path_util
103*760c253cSXin Li
104*760c253cSXin Li    return path_util.ToChrootPath(path=file_path, source_path=chromeos_root)
105*760c253cSXin Li
106*760c253cSXin Li
107*760c253cSXin Lidef GetOutsideChrootPath(chromeos_root, file_path):
108*760c253cSXin Li    sys.path.insert(0, chromeos_root)
109*760c253cSXin Li
110*760c253cSXin Li    from chromite.lib import path_util
111*760c253cSXin Li
112*760c253cSXin Li    return path_util.FromChrootPath(path=file_path, source_path=chromeos_root)
113*760c253cSXin Li
114*760c253cSXin Li
115*760c253cSXin Lidef FormatQuotedCommand(command):
116*760c253cSXin Li    return ApplySubs(command, ('"', r"\""))
117*760c253cSXin Li
118*760c253cSXin Li
119*760c253cSXin Lidef FormatCommands(commands):
120*760c253cSXin Li    return ApplySubs(
121*760c253cSXin Li        str(commands), ("&&", "&&\n"), (";", ";\n"), (r"\n+\s*", "\n")
122*760c253cSXin Li    )
123*760c253cSXin Li
124*760c253cSXin Li
125*760c253cSXin Lidef GetImageDir(chromeos_root, board):
126*760c253cSXin Li    return GetOutsideChrootPath(
127*760c253cSXin Li        chromeos_root,
128*760c253cSXin Li        os.path.join(chromeos_root, "src", "build", "images", board),
129*760c253cSXin Li    )
130*760c253cSXin Li
131*760c253cSXin Li
132*760c253cSXin Lidef LabelLatestImage(chromeos_root, board, label, vanilla_path=None):
133*760c253cSXin Li    image_dir = GetImageDir(chromeos_root, board)
134*760c253cSXin Li    latest_image_dir = os.path.join(image_dir, "latest")
135*760c253cSXin Li    latest_image_dir = os.path.realpath(latest_image_dir)
136*760c253cSXin Li    latest_image_dir = os.path.basename(latest_image_dir)
137*760c253cSXin Li    retval = 0
138*760c253cSXin Li    with WorkingDirectory(image_dir):
139*760c253cSXin Li        command = "ln -sf -T %s %s" % (latest_image_dir, label)
140*760c253cSXin Li        ce = command_executer.GetCommandExecuter()
141*760c253cSXin Li        retval = ce.RunCommand(command)
142*760c253cSXin Li        if retval:
143*760c253cSXin Li            return retval
144*760c253cSXin Li        if vanilla_path:
145*760c253cSXin Li            command = "ln -sf -T %s %s" % (vanilla_path, "vanilla")
146*760c253cSXin Li            retval2 = ce.RunCommand(command)
147*760c253cSXin Li            return retval2
148*760c253cSXin Li    return retval
149*760c253cSXin Li
150*760c253cSXin Li
151*760c253cSXin Lidef DoesLabelExist(chromeos_root, board, label):
152*760c253cSXin Li    image_label = os.path.join(GetImageDir(chromeos_root, board), label)
153*760c253cSXin Li    return os.path.exists(image_label)
154*760c253cSXin Li
155*760c253cSXin Li
156*760c253cSXin Lidef GetBuildPackagesCommand(board, usepkg=False, debug=False):
157*760c253cSXin Li    if usepkg:
158*760c253cSXin Li        usepkg_flag = "--usepkg"
159*760c253cSXin Li    else:
160*760c253cSXin Li        usepkg_flag = "--nousepkg"
161*760c253cSXin Li    if debug:
162*760c253cSXin Li        withdebug_flag = "--withdebug"
163*760c253cSXin Li    else:
164*760c253cSXin Li        withdebug_flag = "--nowithdebug"
165*760c253cSXin Li    return (
166*760c253cSXin Li        "%s/build_packages %s --withdev --withtest --withautotest "
167*760c253cSXin Li        "--skip_toolchain_update %s --board=%s "
168*760c253cSXin Li        "--accept_licenses=@CHROMEOS"
169*760c253cSXin Li        % (CHROMEOS_SCRIPTS_DIR, usepkg_flag, withdebug_flag, board)
170*760c253cSXin Li    )
171*760c253cSXin Li
172*760c253cSXin Li
173*760c253cSXin Lidef GetBuildImageCommand(board, dev=False):
174*760c253cSXin Li    dev_args = ""
175*760c253cSXin Li    if dev:
176*760c253cSXin Li        dev_args = "--noenable_rootfs_verification --disk_layout=2gb-rootfs"
177*760c253cSXin Li    return "%s/build_image --board=%s %s test" % (
178*760c253cSXin Li        CHROMEOS_SCRIPTS_DIR,
179*760c253cSXin Li        board,
180*760c253cSXin Li        dev_args,
181*760c253cSXin Li    )
182*760c253cSXin Li
183*760c253cSXin Li
184*760c253cSXin Lidef GetSetupBoardCommand(board, usepkg=None, force=None):
185*760c253cSXin Li    """Get setup_board command."""
186*760c253cSXin Li    options = []
187*760c253cSXin Li
188*760c253cSXin Li    if usepkg:
189*760c253cSXin Li        options.append("--usepkg")
190*760c253cSXin Li    else:
191*760c253cSXin Li        options.append("--nousepkg")
192*760c253cSXin Li
193*760c253cSXin Li    if force:
194*760c253cSXin Li        options.append("--force")
195*760c253cSXin Li
196*760c253cSXin Li    options.append("--accept-licenses=@CHROMEOS")
197*760c253cSXin Li
198*760c253cSXin Li    return "setup_board --board=%s %s" % (board, " ".join(options))
199*760c253cSXin Li
200*760c253cSXin Li
201*760c253cSXin Lidef CanonicalizePath(path):
202*760c253cSXin Li    path = os.path.expanduser(path)
203*760c253cSXin Li    path = os.path.realpath(path)
204*760c253cSXin Li    return path
205*760c253cSXin Li
206*760c253cSXin Li
207*760c253cSXin Lidef GetCtargetFromBoard(board, chromeos_root):
208*760c253cSXin Li    """Get Ctarget from board."""
209*760c253cSXin Li    base_board = board.split("_")[0]
210*760c253cSXin Li    command = "source %s; get_ctarget_from_board %s" % (
211*760c253cSXin Li        TOOLCHAIN_UTILS_PATH,
212*760c253cSXin Li        base_board,
213*760c253cSXin Li    )
214*760c253cSXin Li    ce = command_executer.GetCommandExecuter()
215*760c253cSXin Li    ret, out, _ = ce.ChrootRunCommandWOutput(chromeos_root, command)
216*760c253cSXin Li    if ret != 0:
217*760c253cSXin Li        raise ValueError("Board %s is invalid!" % board)
218*760c253cSXin Li    # Remove ANSI escape sequences.
219*760c253cSXin Li    out = StripANSIEscapeSequences(out)
220*760c253cSXin Li    return out.strip()
221*760c253cSXin Li
222*760c253cSXin Li
223*760c253cSXin Lidef GetArchFromBoard(board, chromeos_root):
224*760c253cSXin Li    """Get Arch from board."""
225*760c253cSXin Li    base_board = board.split("_")[0]
226*760c253cSXin Li    command = "source %s; get_board_arch %s" % (
227*760c253cSXin Li        TOOLCHAIN_UTILS_PATH,
228*760c253cSXin Li        base_board,
229*760c253cSXin Li    )
230*760c253cSXin Li    ce = command_executer.GetCommandExecuter()
231*760c253cSXin Li    ret, out, _ = ce.ChrootRunCommandWOutput(chromeos_root, command)
232*760c253cSXin Li    if ret != 0:
233*760c253cSXin Li        raise ValueError("Board %s is invalid!" % board)
234*760c253cSXin Li    # Remove ANSI escape sequences.
235*760c253cSXin Li    out = StripANSIEscapeSequences(out)
236*760c253cSXin Li    return out.strip()
237*760c253cSXin Li
238*760c253cSXin Li
239*760c253cSXin Lidef GetGccLibsDestForBoard(board, chromeos_root):
240*760c253cSXin Li    """Get gcc libs destination from board."""
241*760c253cSXin Li    arch = GetArchFromBoard(board, chromeos_root)
242*760c253cSXin Li    if arch == "x86":
243*760c253cSXin Li        return "/build/%s/usr/lib/gcc/" % board
244*760c253cSXin Li    if arch == "amd64":
245*760c253cSXin Li        return "/build/%s/usr/lib64/gcc/" % board
246*760c253cSXin Li    if arch == "arm":
247*760c253cSXin Li        return "/build/%s/usr/lib/gcc/" % board
248*760c253cSXin Li    if arch == "arm64":
249*760c253cSXin Li        return "/build/%s/usr/lib/gcc/" % board
250*760c253cSXin Li    raise ValueError("Arch %s is invalid!" % arch)
251*760c253cSXin Li
252*760c253cSXin Li
253*760c253cSXin Lidef StripANSIEscapeSequences(string):
254*760c253cSXin Li    string = re.sub(r"\x1b\[[0-9]*[a-zA-Z]", "", string)
255*760c253cSXin Li    return string
256*760c253cSXin Li
257*760c253cSXin Li
258*760c253cSXin Lidef GetChromeSrcDir():
259*760c253cSXin Li    return "var/cache/distfiles/target/chrome-src/src"
260*760c253cSXin Li
261*760c253cSXin Li
262*760c253cSXin Lidef GetEnvStringFromDict(env_dict):
263*760c253cSXin Li    return " ".join(['%s="%s"' % var for var in env_dict.items()])
264*760c253cSXin Li
265*760c253cSXin Li
266*760c253cSXin Lidef MergeEnvStringWithDict(env_string, env_dict, prepend=True):
267*760c253cSXin Li    """Merge env string with dict."""
268*760c253cSXin Li    if not env_string.strip():
269*760c253cSXin Li        return GetEnvStringFromDict(env_dict)
270*760c253cSXin Li    override_env_list = []
271*760c253cSXin Li    ce = command_executer.GetCommandExecuter()
272*760c253cSXin Li    for k, v in env_dict.items():
273*760c253cSXin Li        v = v.strip("\"'")
274*760c253cSXin Li        if prepend:
275*760c253cSXin Li            new_env = '%s="%s $%s"' % (k, v, k)
276*760c253cSXin Li        else:
277*760c253cSXin Li            new_env = '%s="$%s %s"' % (k, k, v)
278*760c253cSXin Li        command = "; ".join([env_string, new_env, "echo $%s" % k])
279*760c253cSXin Li        ret, out, _ = ce.RunCommandWOutput(command)
280*760c253cSXin Li        override_env_list.append("%s=%r" % (k, out.strip()))
281*760c253cSXin Li    ret = env_string + " " + " ".join(override_env_list)
282*760c253cSXin Li    return ret.strip()
283*760c253cSXin Li
284*760c253cSXin Li
285*760c253cSXin Lidef GetAllImages(chromeos_root, board):
286*760c253cSXin Li    ce = command_executer.GetCommandExecuter()
287*760c253cSXin Li    command = "find %s/src/build/images/%s -name chromiumos_test_image.bin" % (
288*760c253cSXin Li        chromeos_root,
289*760c253cSXin Li        board,
290*760c253cSXin Li    )
291*760c253cSXin Li    ret, out, _ = ce.RunCommandWOutput(command)
292*760c253cSXin Li    assert ret == 0, "Could not run command: %s" % command
293*760c253cSXin Li    return out.splitlines()
294*760c253cSXin Li
295*760c253cSXin Li
296*760c253cSXin Lidef IsFloat(text):
297*760c253cSXin Li    if text is None:
298*760c253cSXin Li        return False
299*760c253cSXin Li    try:
300*760c253cSXin Li        float(text)
301*760c253cSXin Li        return True
302*760c253cSXin Li    except ValueError:
303*760c253cSXin Li        return False
304*760c253cSXin Li
305*760c253cSXin Li
306*760c253cSXin Lidef RemoveChromeBrowserObjectFiles(chromeos_root, board):
307*760c253cSXin Li    """Remove any object files from all the posible locations."""
308*760c253cSXin Li    out_dir = GetOutsideChrootPath(
309*760c253cSXin Li        chromeos_root,
310*760c253cSXin Li        "/var/cache/chromeos-chrome/chrome-src/src/out_%s" % board,
311*760c253cSXin Li    )
312*760c253cSXin Li    if os.path.exists(out_dir):
313*760c253cSXin Li        shutil.rmtree(out_dir)
314*760c253cSXin Li        logger.GetLogger().LogCmd("rm -rf %s" % out_dir)
315*760c253cSXin Li    out_dir = GetOutsideChrootPath(
316*760c253cSXin Li        chromeos_root,
317*760c253cSXin Li        "/var/cache/chromeos-chrome/chrome-src-internal/src/out_%s" % board,
318*760c253cSXin Li    )
319*760c253cSXin Li    if os.path.exists(out_dir):
320*760c253cSXin Li        shutil.rmtree(out_dir)
321*760c253cSXin Li        logger.GetLogger().LogCmd("rm -rf %s" % out_dir)
322*760c253cSXin Li
323*760c253cSXin Li
324*760c253cSXin Li@contextmanager
325*760c253cSXin Lidef WorkingDirectory(new_dir):
326*760c253cSXin Li    """Get the working directory."""
327*760c253cSXin Li    old_dir = os.getcwd()
328*760c253cSXin Li    if old_dir != new_dir:
329*760c253cSXin Li        msg = "cd %s" % new_dir
330*760c253cSXin Li        logger.GetLogger().LogCmd(msg)
331*760c253cSXin Li    os.chdir(new_dir)
332*760c253cSXin Li    yield new_dir
333*760c253cSXin Li    if old_dir != new_dir:
334*760c253cSXin Li        msg = "cd %s" % old_dir
335*760c253cSXin Li        logger.GetLogger().LogCmd(msg)
336*760c253cSXin Li    os.chdir(old_dir)
337*760c253cSXin Li
338*760c253cSXin Li
339*760c253cSXin Lidef HasGitStagedChanges(git_dir):
340*760c253cSXin Li    """Return True if git repository has staged changes."""
341*760c253cSXin Li    command = f"cd {git_dir} && git diff --quiet --cached --exit-code HEAD"
342*760c253cSXin Li    return command_executer.GetCommandExecuter().RunCommand(
343*760c253cSXin Li        command, print_to_console=False
344*760c253cSXin Li    )
345*760c253cSXin Li
346*760c253cSXin Li
347*760c253cSXin Lidef HasGitUnstagedChanges(git_dir):
348*760c253cSXin Li    """Return True if git repository has un-staged changes."""
349*760c253cSXin Li    command = f"cd {git_dir} && git diff --quiet --exit-code HEAD"
350*760c253cSXin Li    return command_executer.GetCommandExecuter().RunCommand(
351*760c253cSXin Li        command, print_to_console=False
352*760c253cSXin Li    )
353*760c253cSXin Li
354*760c253cSXin Li
355*760c253cSXin Lidef HasGitUntrackedChanges(git_dir):
356*760c253cSXin Li    """Return True if git repository has un-tracked changes."""
357*760c253cSXin Li    command = (
358*760c253cSXin Li        f"cd {git_dir} && test -z "
359*760c253cSXin Li        "$(git ls-files --exclude-standard --others)"
360*760c253cSXin Li    )
361*760c253cSXin Li    return command_executer.GetCommandExecuter().RunCommand(
362*760c253cSXin Li        command, print_to_console=False
363*760c253cSXin Li    )
364*760c253cSXin Li
365*760c253cSXin Li
366*760c253cSXin Lidef GitGetCommitHash(git_dir, commit_symbolic_name):
367*760c253cSXin Li    """Return githash for the symbolic git commit.
368*760c253cSXin Li
369*760c253cSXin Li    For example, commit_symbolic_name could be
370*760c253cSXin Li    "cros/gcc.gnu.org/branches/gcc/gcc-4_8-mobile, this function returns the git
371*760c253cSXin Li    hash for this symbolic name.
372*760c253cSXin Li
373*760c253cSXin Li    Args:
374*760c253cSXin Li      git_dir: a git working tree.
375*760c253cSXin Li      commit_symbolic_name: a symbolic name for a particular git commit.
376*760c253cSXin Li
377*760c253cSXin Li    Returns:
378*760c253cSXin Li      The git hash for the symbolic name or None if fails.
379*760c253cSXin Li    """
380*760c253cSXin Li
381*760c253cSXin Li    command = (
382*760c253cSXin Li        f"cd {git_dir} && git log -n 1"
383*760c253cSXin Li        f' --pretty="format:%H" {commit_symbolic_name}'
384*760c253cSXin Li    )
385*760c253cSXin Li    rv, out, _ = command_executer.GetCommandExecuter().RunCommandWOutput(
386*760c253cSXin Li        command, print_to_console=False
387*760c253cSXin Li    )
388*760c253cSXin Li    if rv == 0:
389*760c253cSXin Li        return out.strip()
390*760c253cSXin Li    return None
391*760c253cSXin Li
392*760c253cSXin Li
393*760c253cSXin Lidef IsGitTreeClean(git_dir):
394*760c253cSXin Li    """Test if git tree has no local changes.
395*760c253cSXin Li
396*760c253cSXin Li    Args:
397*760c253cSXin Li      git_dir: git tree directory.
398*760c253cSXin Li
399*760c253cSXin Li    Returns:
400*760c253cSXin Li      True if git dir is clean.
401*760c253cSXin Li    """
402*760c253cSXin Li    if HasGitStagedChanges(git_dir):
403*760c253cSXin Li        logger.GetLogger().LogWarning("Git tree has staged changes.")
404*760c253cSXin Li        return False
405*760c253cSXin Li    if HasGitUnstagedChanges(git_dir):
406*760c253cSXin Li        logger.GetLogger().LogWarning("Git tree has unstaged changes.")
407*760c253cSXin Li        return False
408*760c253cSXin Li    if HasGitUntrackedChanges(git_dir):
409*760c253cSXin Li        logger.GetLogger().LogWarning("Git tree has un-tracked changes.")
410*760c253cSXin Li        return False
411*760c253cSXin Li    return True
412*760c253cSXin Li
413*760c253cSXin Li
414*760c253cSXin Lidef GetGitChangesAsList(git_dir, path=None, staged=False):
415*760c253cSXin Li    """Get changed files as a list.
416*760c253cSXin Li
417*760c253cSXin Li    Args:
418*760c253cSXin Li      git_dir: git tree directory.
419*760c253cSXin Li      path: a relative path that is part of the tree directory, could be null.
420*760c253cSXin Li      staged: whether to include staged files as well.
421*760c253cSXin Li
422*760c253cSXin Li    Returns:
423*760c253cSXin Li      A list containing all the changed files.
424*760c253cSXin Li    """
425*760c253cSXin Li    command = f"cd {git_dir} && git diff --name-only"
426*760c253cSXin Li    if staged:
427*760c253cSXin Li        command += " --cached"
428*760c253cSXin Li    if path:
429*760c253cSXin Li        command += " -- " + path
430*760c253cSXin Li    _, out, _ = command_executer.GetCommandExecuter().RunCommandWOutput(
431*760c253cSXin Li        command, print_to_console=False
432*760c253cSXin Li    )
433*760c253cSXin Li    rv = []
434*760c253cSXin Li    for line in out.splitlines():
435*760c253cSXin Li        rv.append(line)
436*760c253cSXin Li    return rv
437*760c253cSXin Li
438*760c253cSXin Li
439*760c253cSXin Lidef IsChromeOsTree(chromeos_root):
440*760c253cSXin Li    return os.path.isdir(
441*760c253cSXin Li        os.path.join(chromeos_root, "src/third_party/chromiumos-overlay")
442*760c253cSXin Li    ) and os.path.isdir(os.path.join(chromeos_root, "manifest"))
443*760c253cSXin Li
444*760c253cSXin Li
445*760c253cSXin Lidef DeleteChromeOsTree(chromeos_root, dry_run=False):
446*760c253cSXin Li    """Delete a ChromeOs tree *safely*.
447*760c253cSXin Li
448*760c253cSXin Li    Args:
449*760c253cSXin Li      chromeos_root: dir of the tree, could be a relative one (but be careful)
450*760c253cSXin Li      dry_run: only prints out the command if True
451*760c253cSXin Li
452*760c253cSXin Li    Returns:
453*760c253cSXin Li      True if everything is ok.
454*760c253cSXin Li    """
455*760c253cSXin Li    if not IsChromeOsTree(chromeos_root):
456*760c253cSXin Li        logger.GetLogger().LogWarning(
457*760c253cSXin Li            f'"{chromeos_root}" does not seem to be a'
458*760c253cSXin Li            " valid chromeos tree, do nothing."
459*760c253cSXin Li        )
460*760c253cSXin Li        return False
461*760c253cSXin Li    cmd0 = f"cd {chromeos_root} && cros_sdk --delete"
462*760c253cSXin Li    if dry_run:
463*760c253cSXin Li        print(cmd0)
464*760c253cSXin Li    else:
465*760c253cSXin Li        if (
466*760c253cSXin Li            command_executer.GetCommandExecuter().RunCommand(
467*760c253cSXin Li                cmd0, print_to_console=True
468*760c253cSXin Li            )
469*760c253cSXin Li            != 0
470*760c253cSXin Li        ):
471*760c253cSXin Li            return False
472*760c253cSXin Li
473*760c253cSXin Li    cmd1 = (
474*760c253cSXin Li        f'export CHROMEOSDIRNAME="$(dirname $(cd {chromeos_root} && pwd))" && '
475*760c253cSXin Li        f'export CHROMEOSBASENAME="$(basename $(cd {chromeos_root} && pwd))" && '
476*760c253cSXin Li        "cd $CHROMEOSDIRNAME && sudo rm -fr $CHROMEOSBASENAME"
477*760c253cSXin Li    )
478*760c253cSXin Li    if dry_run:
479*760c253cSXin Li        print(cmd1)
480*760c253cSXin Li        return True
481*760c253cSXin Li
482*760c253cSXin Li    return (
483*760c253cSXin Li        command_executer.GetCommandExecuter().RunCommand(
484*760c253cSXin Li            cmd1, print_to_console=True
485*760c253cSXin Li        )
486*760c253cSXin Li        == 0
487*760c253cSXin Li    )
488*760c253cSXin Li
489*760c253cSXin Li
490*760c253cSXin Lidef BooleanPrompt(
491*760c253cSXin Li    prompt="Do you want to continue?",
492*760c253cSXin Li    default=True,
493*760c253cSXin Li    true_value="yes",
494*760c253cSXin Li    false_value="no",
495*760c253cSXin Li    prolog=None,
496*760c253cSXin Li):
497*760c253cSXin Li    """Helper function for processing boolean choice prompts.
498*760c253cSXin Li
499*760c253cSXin Li    Args:
500*760c253cSXin Li      prompt: The question to present to the user.
501*760c253cSXin Li      default: Boolean to return if the user just presses enter.
502*760c253cSXin Li      true_value: The text to display that represents a True returned.
503*760c253cSXin Li      false_value: The text to display that represents a False returned.
504*760c253cSXin Li      prolog: The text to display before prompt.
505*760c253cSXin Li
506*760c253cSXin Li    Returns:
507*760c253cSXin Li      True or False.
508*760c253cSXin Li    """
509*760c253cSXin Li    true_value, false_value = true_value.lower(), false_value.lower()
510*760c253cSXin Li    true_text, false_text = true_value, false_value
511*760c253cSXin Li    if true_value == false_value:
512*760c253cSXin Li        raise ValueError(
513*760c253cSXin Li            "true_value and false_value must differ: got %r" % true_value
514*760c253cSXin Li        )
515*760c253cSXin Li
516*760c253cSXin Li    if default:
517*760c253cSXin Li        true_text = true_text[0].upper() + true_text[1:]
518*760c253cSXin Li    else:
519*760c253cSXin Li        false_text = false_text[0].upper() + false_text[1:]
520*760c253cSXin Li
521*760c253cSXin Li    prompt = "\n%s (%s/%s)? " % (prompt, true_text, false_text)
522*760c253cSXin Li
523*760c253cSXin Li    if prolog:
524*760c253cSXin Li        prompt = "\n%s\n%s" % (prolog, prompt)
525*760c253cSXin Li
526*760c253cSXin Li    while True:
527*760c253cSXin Li        try:
528*760c253cSXin Li            # pylint: disable=input-builtin, bad-builtin
529*760c253cSXin Li            response = input(prompt).lower()
530*760c253cSXin Li        except EOFError:
531*760c253cSXin Li            # If the user hits CTRL+D, or stdin is disabled, use the default.
532*760c253cSXin Li            print()
533*760c253cSXin Li            response = None
534*760c253cSXin Li        except KeyboardInterrupt:
535*760c253cSXin Li            # If the user hits CTRL+C, just exit the process.
536*760c253cSXin Li            print()
537*760c253cSXin Li            print("CTRL+C detected; exiting")
538*760c253cSXin Li            sys.exit()
539*760c253cSXin Li
540*760c253cSXin Li        if not response:
541*760c253cSXin Li            return default
542*760c253cSXin Li        if true_value.startswith(response):
543*760c253cSXin Li            if not false_value.startswith(response):
544*760c253cSXin Li                return True
545*760c253cSXin Li            # common prefix between the two...
546*760c253cSXin Li        elif false_value.startswith(response):
547*760c253cSXin Li            return False
548*760c253cSXin Li
549*760c253cSXin Li
550*760c253cSXin Li# pylint: disable=unused-argument
551*760c253cSXin Lidef rgb2short(r, g, b):
552*760c253cSXin Li    """Converts RGB values to xterm-256 color."""
553*760c253cSXin Li
554*760c253cSXin Li    redcolor = [255, 124, 160, 196, 9]
555*760c253cSXin Li    greencolor = [255, 118, 82, 46, 10]
556*760c253cSXin Li
557*760c253cSXin Li    if g == 0:
558*760c253cSXin Li        return redcolor[r // 52]
559*760c253cSXin Li    if r == 0:
560*760c253cSXin Li        return greencolor[g // 52]
561*760c253cSXin Li    return 4
562