blob: 9db6fd53d343a738bbdd543e2b64b412a636d998 [file] [log] [blame]
Ahmad Sharif4467f002012-12-20 12:09:49 -08001#!/usr/bin/python
Yunlian Jiangb0a02f42013-08-22 09:55:54 -07002
Han Shene4b6f222013-11-22 10:02:38 -08003# Copyright 2013 Google Inc. All Rights Reserved.
Yunlian Jiangb0a02f42013-08-22 09:55:54 -07004# Use of this source code is governed by a BSD-style license that can be
5# found in the LICENSE file.
Ahmad Shariffd356fb2012-05-07 12:02:16 -07006
7"""Utilities for toolchain build."""
8
9__author__ = "asharif@google.com (Ahmad Sharif)"
10
Ahmad Shariff395c262012-10-09 17:48:09 -070011from contextlib import contextmanager
Ahmad Shariffd356fb2012-05-07 12:02:16 -070012import os
13import re
Ahmad Sharif4467f002012-12-20 12:09:49 -080014import shutil
15import sys
16import time
17
18import lock_machine
Ahmad Shariff395c262012-10-09 17:48:09 -070019
Ahmad Shariffd356fb2012-05-07 12:02:16 -070020import command_executer
21import logger
Ahmad Shariff395c262012-10-09 17:48:09 -070022
23
24def GetChromeOSVersionFromLSBVersion(lsb_version):
Ahmad Sharif4467f002012-12-20 12:09:49 -080025 """Get Chromeos version from Lsb version."""
Ahmad Shariff395c262012-10-09 17:48:09 -070026 ce = command_executer.GetCommandExecuter()
Luis Lozano6aebeb12013-09-03 01:55:02 -070027 command = ("git ls-remote "
Luis Lozano6aae4c92013-09-10 00:00:27 -070028 "https://chromium.googlesource.com/chromiumos/manifest.git")
Ahmad Shariff395c262012-10-09 17:48:09 -070029 ret, out, _ = ce.RunCommand(command, return_output=True,
30 print_to_console=False)
31 assert ret == 0, "Command %s failed" % command
32 lower = []
33 for line in out.splitlines():
Ahmad Sharif4467f002012-12-20 12:09:49 -080034 mo = re.search(r"refs/heads/release-R(\d+)-(\d+)\.B", line)
Ahmad Shariff395c262012-10-09 17:48:09 -070035 if mo:
36 revision = int(mo.group(1))
37 build = int(mo.group(2))
38 lsb_build = int(lsb_version.split(".")[0])
39 if lsb_build > build:
40 lower.append(revision)
41 lower = sorted(lower)
42 if lower:
43 return "R%d-%s" % (lower[-1] + 1, lsb_version)
44 else:
45 return "Unknown"
Ahmad Shariffd356fb2012-05-07 12:02:16 -070046
47
48def ApplySubs(string, *substitutions):
49 for pattern, replacement in substitutions:
50 string = re.sub(pattern, replacement, string)
51 return string
52
53
Ahmad Sharif4467f002012-12-20 12:09:49 -080054def UnitToNumber(unit_num, base=1000):
55 """Convert a number with unit to float."""
Ahmad Sharif5ae8a5c2012-05-18 10:59:51 -070056 unit_dict = {"kilo": base,
57 "mega": base**2,
58 "giga": base**3}
Ahmad Sharif4467f002012-12-20 12:09:49 -080059 unit_num = unit_num.lower()
60 mo = re.search(r"(\d*)(.+)?", unit_num)
Ahmad Sharif5ae8a5c2012-05-18 10:59:51 -070061 number = mo.group(1)
62 unit = mo.group(2)
Ahmad Shariff395c262012-10-09 17:48:09 -070063 if not unit:
64 return float(number)
Ahmad Sharif5ae8a5c2012-05-18 10:59:51 -070065 for k, v in unit_dict.items():
66 if k.startswith(unit):
67 return float(number) * v
68 raise Exception("Unit: %s not found in byte: %s!" %
69 (unit,
Ahmad Sharif4467f002012-12-20 12:09:49 -080070 unit_num))
Ahmad Sharif5ae8a5c2012-05-18 10:59:51 -070071
72
Ahmad Shariffd356fb2012-05-07 12:02:16 -070073def GetFilenameFromString(string):
74 return ApplySubs(string,
Ahmad Sharif4467f002012-12-20 12:09:49 -080075 (r"/", "__"),
76 (r"\s", "_"),
77 (r"[\^\$=\"\\\?]", ""),
78 )
Ahmad Shariffd356fb2012-05-07 12:02:16 -070079
80
81def GetRoot(scr_name):
82 """Break up pathname into (dir+name)."""
83 abs_path = os.path.abspath(scr_name)
84 return (os.path.dirname(abs_path), os.path.basename(abs_path))
85
86
Ahmad Sharif4467f002012-12-20 12:09:49 -080087def GetChromeOSKeyFile(chromeos_root):
88 return os.path.join(chromeos_root,
89 "src",
90 "scripts",
91 "mod_for_test_scripts",
92 "ssh_keys",
93 "testing_rsa")
94
95
Ahmad Sharif5ae8a5c2012-05-18 10:59:51 -070096def GetChrootPath(chromeos_root):
97 return os.path.join(chromeos_root,
98 "chroot")
99
100
101def GetInsideChrootPath(chromeos_root, file_path):
102 if not file_path.startswith(GetChrootPath(chromeos_root)):
103 raise Exception("File: %s doesn't seem to be in the chroot: %s" %
104 (file_path,
105 chromeos_root))
106 return file_path[len(GetChrootPath(chromeos_root)):]
107
108
109def GetOutsideChrootPath(chromeos_root, file_path):
110 return os.path.join(GetChrootPath(chromeos_root),
111 file_path.lstrip("/"))
112
113
Ahmad Shariffd356fb2012-05-07 12:02:16 -0700114def FormatQuotedCommand(command):
115 return ApplySubs(command,
116 ("\"", "\\\""))
117
118
119def FormatCommands(commands):
120 return ApplySubs(str(commands),
121 ("&&", "&&\n"),
122 (";", ";\n"),
Ahmad Sharif4467f002012-12-20 12:09:49 -0800123 (r"\n+\s*", "\n"))
Ahmad Shariffd356fb2012-05-07 12:02:16 -0700124
125
126def GetImageDir(chromeos_root, board):
127 return os.path.join(chromeos_root,
128 "src",
129 "build",
130 "images",
131 board)
132
133
134def LabelLatestImage(chromeos_root, board, label):
135 image_dir = GetImageDir(chromeos_root, board)
136 latest_image_dir = os.path.join(image_dir, "latest")
137 latest_image_dir = os.path.realpath(latest_image_dir)
138 latest_image_dir = os.path.basename(latest_image_dir)
139 with WorkingDirectory(image_dir):
140 command = "ln -sf -T %s %s" % (latest_image_dir, label)
141 ce = command_executer.GetCommandExecuter()
142 return ce.RunCommand(command)
143
144
145def DoesLabelExist(chromeos_root, board, label):
146 image_label = os.path.join(GetImageDir(chromeos_root, board),
147 label)
148 return os.path.exists(image_label)
149
150
Luis Lozanof81680c2013-03-15 14:44:13 -0700151def GetBuildPackagesCommand(board, usepkg=False, debug=False):
Ahmad Shariffd356fb2012-05-07 12:02:16 -0700152 if usepkg:
153 usepkg_flag = "--usepkg"
154 else:
155 usepkg_flag = "--nousepkg"
Luis Lozanof81680c2013-03-15 14:44:13 -0700156 if debug:
Han Shene4b6f222013-11-22 10:02:38 -0800157 withdebug_flag = "--withdebug"
Luis Lozanof81680c2013-03-15 14:44:13 -0700158 else:
Han Shene4b6f222013-11-22 10:02:38 -0800159 withdebug_flag = "--nowithdebug"
Ahmad Shariffd356fb2012-05-07 12:02:16 -0700160 return ("./build_packages %s --withdev --withtest --withautotest "
Yunlian Jiangb0a02f42013-08-22 09:55:54 -0700161 "--skip_toolchain_update %s --board=%s "
162 "--accept_licenses=@CHROMEOS" %
Luis Lozanof81680c2013-03-15 14:44:13 -0700163 (usepkg_flag, withdebug_flag, board))
Ahmad Shariffd356fb2012-05-07 12:02:16 -0700164
165
Luis Lozanof81680c2013-03-15 14:44:13 -0700166def GetBuildImageCommand(board, dev=False):
167 dev_args = ""
168 if dev:
169 dev_args = "--noenable_rootfs_verification --disk_layout=2gb-rootfs"
170 return "./build_image --board=%s %s test" % (board, dev_args)
Ahmad Shariffd356fb2012-05-07 12:02:16 -0700171
Han Shene4b6f222013-11-22 10:02:38 -0800172
Ahmad Shariffd356fb2012-05-07 12:02:16 -0700173def GetSetupBoardCommand(board, gcc_version=None, binutils_version=None,
174 usepkg=None, force=None):
Ahmad Sharif4467f002012-12-20 12:09:49 -0800175 """Get setup_board command."""
Ahmad Shariffd356fb2012-05-07 12:02:16 -0700176 options = []
177
178 if gcc_version:
179 options.append("--gcc_version=%s" % gcc_version)
180
181 if binutils_version:
182 options.append("--binutils_version=%s" % binutils_version)
183
184 if usepkg:
185 options.append("--usepkg")
186 else:
187 options.append("--nousepkg")
188
189 if force:
190 options.append("--force")
191
Yunlian Jiangb0a02f42013-08-22 09:55:54 -0700192 options.append("--accept_licenses=@CHROMEOS")
193
Ahmad Shariffd356fb2012-05-07 12:02:16 -0700194 return "./setup_board --board=%s %s" % (board, " ".join(options))
195
196
197def CanonicalizePath(path):
198 path = os.path.expanduser(path)
199 path = os.path.realpath(path)
200 return path
201
202
203def GetCtargetFromBoard(board, chromeos_root):
Ahmad Sharif4467f002012-12-20 12:09:49 -0800204 """Get Ctarget from board."""
Ahmad Shariffd356fb2012-05-07 12:02:16 -0700205 base_board = board.split("_")[0]
206 command = ("source "
207 "../platform/dev/toolchain_utils.sh; get_ctarget_from_board %s" %
208 base_board)
209 ce = command_executer.GetCommandExecuter()
Ahmad Shariff395c262012-10-09 17:48:09 -0700210 ret, out, _ = ce.ChrootRunCommand(chromeos_root,
211 command,
212 return_output=True)
Ahmad Shariffd356fb2012-05-07 12:02:16 -0700213 if ret != 0:
214 raise ValueError("Board %s is invalid!" % board)
Ahmad Shariff395c262012-10-09 17:48:09 -0700215 # Remove ANSI escape sequences.
216 out = StripANSIEscapeSequences(out)
Ahmad Shariffd356fb2012-05-07 12:02:16 -0700217 return out.strip()
218
219
Ahmad Shariff395c262012-10-09 17:48:09 -0700220def StripANSIEscapeSequences(string):
Ahmad Sharif4467f002012-12-20 12:09:49 -0800221 string = re.sub(r"\x1b\[[0-9]*[a-zA-Z]", "", string)
Ahmad Shariff395c262012-10-09 17:48:09 -0700222 return string
223
224
Ahmad Shariffd356fb2012-05-07 12:02:16 -0700225def GetChromeSrcDir():
226 return "var/cache/distfiles/target/chrome-src/src"
227
228
229def GetEnvStringFromDict(env_dict):
230 return " ".join(["%s=\"%s\"" % var for var in env_dict.items()])
231
232
Ahmad Shariff395c262012-10-09 17:48:09 -0700233def MergeEnvStringWithDict(env_string, env_dict, prepend=True):
Ahmad Sharif4467f002012-12-20 12:09:49 -0800234 """Merge env string with dict."""
Ahmad Shariff395c262012-10-09 17:48:09 -0700235 if not env_string.strip():
236 return GetEnvStringFromDict(env_dict)
237 override_env_list = []
238 ce = command_executer.GetCommandExecuter()
239 for k, v in env_dict.items():
240 v = v.strip("\"'")
241 if prepend:
242 new_env = "%s=\"%s $%s\"" % (k, v, k)
243 else:
244 new_env = "%s=\"$%s %s\"" % (k, k, v)
245 command = "; ".join([env_string, new_env, "echo $%s" % k])
246 ret, out, _ = ce.RunCommand(command, return_output=True)
247 override_env_list.append("%s=%r" % (k, out.strip()))
248 ret = env_string + " " + " ".join(override_env_list)
249 return ret.strip()
250
251
Ahmad Shariffd356fb2012-05-07 12:02:16 -0700252def GetAllImages(chromeos_root, board):
253 ce = command_executer.GetCommandExecuter()
254 command = ("find %s/src/build/images/%s -name chromiumos_test_image.bin" %
255 (chromeos_root, board))
Ahmad Shariff395c262012-10-09 17:48:09 -0700256 ret, out, _ = ce.RunCommand(command, return_output=True)
257 assert ret == 0, "Could not run command: %s" % command
Ahmad Shariffd356fb2012-05-07 12:02:16 -0700258 return out.splitlines()
259
260
Ahmad Sharif4467f002012-12-20 12:09:49 -0800261def AcquireLock(lock_file, timeout=1200):
262 """Acquire a lock with timeout."""
263 start_time = time.time()
264 locked = False
265 abs_path = os.path.abspath(lock_file)
266 dir_path = os.path.dirname(abs_path)
267 sleep_time = min(10, timeout/10.0)
Luis Lozanof81680c2013-03-15 14:44:13 -0700268 reason = "pid: {0}, commad: {1}".format(os.getpid(),
269 sys.argv[0])
Ahmad Sharif4467f002012-12-20 12:09:49 -0800270 if not os.path.exists(dir_path):
271 try:
Luis Lozanof81680c2013-03-15 14:44:13 -0700272 with lock_machine.FileCreationMask(0002):
273 os.makedirs(dir_path)
Ahmad Sharif4467f002012-12-20 12:09:49 -0800274 except OSError:
275 print "Cannot create dir {0}, exiting...".format(dir_path)
276 exit(0)
277 while True:
Luis Lozanof81680c2013-03-15 14:44:13 -0700278 locked = (lock_machine.Lock(lock_file).NonBlockingLock(True, reason))
Ahmad Sharif4467f002012-12-20 12:09:49 -0800279 if locked:
280 break
281 time.sleep(sleep_time)
282 if time.time() - start_time > timeout:
283 logger.GetLogger().LogWarning(
284 "Could not acquire lock on this file: {0} within {1} seconds."
285 "Manually remove the file if you think the lock is stale"
286 .format(abs_path, timeout))
287 break
288 return locked
289
290
291def ReleaseLock(lock_file):
292 lock_file = os.path.abspath(lock_file)
293 ret = lock_machine.Lock(lock_file).Unlock(True)
294 assert ret, ("Could not unlock {0},"
295 "Please remove it manually".format(lock_file))
296
297
298def IsFloat(text):
299 if text is None:
300 return False
301 try:
302 float(text)
303 return True
304 except ValueError:
305 return False
306
Han Shene4b6f222013-11-22 10:02:38 -0800307
Ahmad Sharif4467f002012-12-20 12:09:49 -0800308def RemoveChromeBrowserObjectFiles(chromeos_root, board):
Han Shene4b6f222013-11-22 10:02:38 -0800309 """Remove any object files from all the posible locations."""
Ahmad Sharif4467f002012-12-20 12:09:49 -0800310 out_dir = os.path.join(
311 GetChrootPath(chromeos_root),
312 "var/cache/chromeos-chrome/chrome-src/src/out_%s" % board)
313 if os.path.exists(out_dir):
314 shutil.rmtree(out_dir)
315 logger.GetLogger().LogCmd("rm -rf %s" % out_dir)
316 out_dir = os.path.join(
317 GetChrootPath(chromeos_root),
318 "var/cache/chromeos-chrome/chrome-src-internal/src/out_%s" % board)
319 if os.path.exists(out_dir):
320 shutil.rmtree(out_dir)
321 logger.GetLogger().LogCmd("rm -rf %s" % out_dir)
322
Han Shene4b6f222013-11-22 10:02:38 -0800323
Ahmad Shariffd356fb2012-05-07 12:02:16 -0700324@contextmanager
325def WorkingDirectory(new_dir):
Ahmad Sharif4467f002012-12-20 12:09:49 -0800326 """Get the working directory."""
Ahmad Shariffd356fb2012-05-07 12:02:16 -0700327 old_dir = os.getcwd()
328 if old_dir != new_dir:
329 msg = "cd %s" % new_dir
330 logger.GetLogger().LogCmd(msg)
331 os.chdir(new_dir)
332 yield new_dir
333 if old_dir != new_dir:
334 msg = "cd %s" % old_dir
335 logger.GetLogger().LogCmd(msg)
336 os.chdir(old_dir)
Han Shen91445322013-03-20 13:43:31 -0700337
Han Shene4b6f222013-11-22 10:02:38 -0800338
Han Shen91445322013-03-20 13:43:31 -0700339def HasGitStagedChanges(git_dir):
340 """Return True if git repository has staged changes."""
Han Shene4b6f222013-11-22 10:02:38 -0800341 command = "cd {0} && git diff --quiet --cached --exit-code HEAD".format(
342 git_dir)
Han Shen91445322013-03-20 13:43:31 -0700343 return command_executer.GetCommandExecuter().RunCommand(
Han Shene4b6f222013-11-22 10:02:38 -0800344 command, print_to_console=False)
345
Han Shen91445322013-03-20 13:43:31 -0700346
347def HasGitUnstagedChanges(git_dir):
348 """Return True if git repository has un-staged changes."""
Han Shene4b6f222013-11-22 10:02:38 -0800349 command = "cd {0} && git diff --quiet --exit-code HEAD".format(git_dir)
Han Shen91445322013-03-20 13:43:31 -0700350 return command_executer.GetCommandExecuter().RunCommand(
Han Shene4b6f222013-11-22 10:02:38 -0800351 command, print_to_console=False)
352
Han Shen91445322013-03-20 13:43:31 -0700353
354def HasGitUntrackedChanges(git_dir):
355 """Return True if git repository has un-tracked changes."""
Han Shene4b6f222013-11-22 10:02:38 -0800356 command = ("cd {0} && test -z "
357 "$(git ls-files --exclude-standard --others)").format(git_dir)
Han Shen91445322013-03-20 13:43:31 -0700358 return command_executer.GetCommandExecuter().RunCommand(
Han Shene4b6f222013-11-22 10:02:38 -0800359 command, print_to_console=False)
360
Han Shen91445322013-03-20 13:43:31 -0700361
362def IsGitTreeClean(git_dir):
Han Shene4b6f222013-11-22 10:02:38 -0800363 """Test if git tree has no local changes.
364
365 Args:
366 git_dir: git tree directory.
367 Returns:
368 True if git dir is clean.
369 """
Han Shen91445322013-03-20 13:43:31 -0700370 if HasGitStagedChanges(git_dir):
371 logger.GetLogger().LogWarning("Git tree has staged changes.")
372 return False
373 if HasGitUnstagedChanges(git_dir):
374 logger.GetLogger().LogWarning("Git tree has unstaged changes.")
375 return False
376 if HasGitUntrackedChanges(git_dir):
377 logger.GetLogger().LogWarning("Git tree has un-tracked changes.")
378 return False
379 return True
380
Han Shene4b6f222013-11-22 10:02:38 -0800381
Han Shen91445322013-03-20 13:43:31 -0700382def GetGitChangesAsList(git_dir, path=None, staged=False):
Han Shene4b6f222013-11-22 10:02:38 -0800383 """Get changed files as a list.
384
385 Args:
386 git_dir: git tree directory.
387 path: a relative path that is part of the tree directory, could be null.
388 staged: whether to include staged files as well.
389 Returns:
390 A list containing all the changed files.
391 """
392 command = "cd {0} && git diff --name-only".format(git_dir)
Han Shen91445322013-03-20 13:43:31 -0700393 if staged:
Han Shene4b6f222013-11-22 10:02:38 -0800394 command += " --cached"
Han Shen91445322013-03-20 13:43:31 -0700395 if path:
Han Shene4b6f222013-11-22 10:02:38 -0800396 command += " -- " + path
Luis Lozano6aebeb12013-09-03 01:55:02 -0700397 _, out, _ = command_executer.GetCommandExecuter().RunCommand(
Han Shene4b6f222013-11-22 10:02:38 -0800398 command, return_output=True, print_to_console=False)
Han Shen91445322013-03-20 13:43:31 -0700399 rv = []
400 for line in out.splitlines():
401 rv.append(line)
402 return rv
Han Shene4b6f222013-11-22 10:02:38 -0800403
404
405def IsChromeOsTree(chromeos_root):
406 return (os.path.isdir(os.path.join(
407 chromeos_root, "src/third_party/chromiumos-overlay")) and
408 os.path.isdir(os.path.join(
409 chromeos_root, "manifest")))
410
411
412def DeleteChromeOsTree(chromeos_root, dry_run=False):
413 """Delete a ChromeOs tree *safely*.
414
415 Args:
416 chromeos_root: dir of the tree, could be a relative one (but be careful)
417 dry_run: only prints out the command if True
418
419 Returns:
420 True if everything is ok.
421 """
422 if not IsChromeOsTree(chromeos_root):
423 logger.GetLogger().LogWarning(
424 '"{0}" does not seem to be a valid chromeos tree, do nothing.'.format(
425 chromeos_root))
426 return False
427 cmd0 = "cd {0} && cros_sdk --delete".format(chromeos_root)
428 if dry_run:
429 print cmd0
430 else:
431 if command_executer.GetCommandExecuter().RunCommand(
432 cmd0, return_output=False, print_to_console=True) != 0:
433 return False
434
435 cmd1 = ('export CHROMEOSDIRNAME="$(dirname $(cd {0} && pwd))" && '
436 'export CHROMEOSBASENAME="$(basename $(cd {0} && pwd))" && '
437 'cd $CHROMEOSDIRNAME && sudo rm -fr $CHROMEOSBASENAME').format(
438 chromeos_root)
439 if dry_run:
440 print cmd1
441 return True
442
443 return command_executer.GetCommandExecuter().RunCommand(
444 cmd1, return_output=False, print_to_console=True) == 0