blob: 828e3bdcdfad8264e72806985414467bfbbe1978 [file] [log] [blame]
Alex Kleinda35fcf2019-03-07 16:01:15 -07001# -*- coding: utf-8 -*-
2# Copyright 2019 The Chromium OS Authors. All rights reserved.
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5
6"""Build target class and related functionality."""
7
8from __future__ import print_function
9
10import os
Alex Klein1a55dde2020-03-06 15:53:29 -070011import re
Alex Kleinda35fcf2019-03-07 16:01:15 -070012
LaMont Jonesfeffd1b2020-08-05 18:24:59 -060013from chromite.api.gen.chromiumos import common_pb2
14
Alex Kleinda35fcf2019-03-07 16:01:15 -070015
16class Error(Exception):
17 """Base module error class."""
18
19
Alex Kleindf4a4482019-09-04 15:31:17 -060020class InvalidNameError(Error):
Alex Kleinda35fcf2019-03-07 16:01:15 -070021 """Error for invalid target name argument."""
22
23
24class BuildTarget(object):
25 """Class to handle the build target information."""
26
27 def __init__(self, name, profile=None, build_root=None):
28 """Build Target init.
29
30 Args:
31 name (str): The full name of the target.
32 profile (str): The profile name.
33 build_root (str): The path to the buildroot.
34 """
35 if not name:
36 raise InvalidNameError('Name is required.')
37
Alex Klein171da612019-08-06 14:00:42 -060038 self._name = name
Alex Kleinda35fcf2019-03-07 16:01:15 -070039 self.board, _, self.variant = name.partition('_')
40 self.profile = profile
41
42 if build_root:
43 self.root = os.path.normpath(build_root)
44 else:
Alex Klein1a55dde2020-03-06 15:53:29 -070045 self.root = get_default_sysroot_path(self.name)
Alex Kleinda35fcf2019-03-07 16:01:15 -070046
Alex Klein171da612019-08-06 14:00:42 -060047 def __eq__(self, other):
48 if self.__class__ is other.__class__:
49 return (self.name == other.name and self.profile == other.profile and
50 self.root == other.root)
51
52 return NotImplemented
53
54 def __hash__(self):
55 return hash(self.name)
56
Alex Kleinaf0e0452019-06-03 18:10:01 -060057 def __str__(self):
58 return self.name
59
Alex Klein171da612019-08-06 14:00:42 -060060 @property
61 def name(self):
62 return self._name
Alex Kleinda35fcf2019-03-07 16:01:15 -070063
LaMont Jonesfeffd1b2020-08-05 18:24:59 -060064 @property
65 def as_protobuf(self):
66 return common_pb2.BuildTarget(name=self.name)
67
68 @classmethod
69 def from_protobuf(cls, message):
70 return cls(name=message.name)
71
72 @property
73 def profile_protobuf(self):
74 return common_pb2.Profile(name=self.profile)
75
Michael Mortensen125bb012020-05-21 14:02:10 -060076 def full_path(self, *args):
77 """Turn a sysroot-relative path into an absolute path."""
78 return os.path.join(self.root, *[part.lstrip(os.sep) for part in args])
79
Alex Klein309c7572020-01-27 10:55:01 -070080 def get_command(self, base_command):
81 """Get the build target's variant of the given base command.
82
83 We create wrappers for many scripts that handle the build target's
84 arguments. Build the target-specific variant for such a command.
85 e.g. emerge -> emerge-eve.
86
87 TODO: Add optional validation the command exists.
88
89 Args:
90 base_command (str): The wrapped command.
91
92 Returns:
93 str: The build target's command wrapper.
94 """
95 return '%s-%s' % (base_command, self.name)
Alex Kleine1abe2c2019-08-14 10:29:46 -060096
Alex Klein1a55dde2020-03-06 15:53:29 -070097
Alex Klein62b7e1e2020-03-09 13:36:50 -060098def get_default_sysroot_path(build_target_name=None):
99 """Get the default sysroot location or '/' if |build_target_name| is None."""
100 if build_target_name is None:
101 return '/'
102 return os.path.join('/build', build_target_name)
Alex Klein1a55dde2020-03-06 15:53:29 -0700103
104
105def is_valid_name(build_target_name):
106 """Validate |build_target_name| is a valid name."""
107 return bool(re.match(r'^[a-zA-Z0-9-_]+$', build_target_name))