blob: 24891714970116af49df642d11d599571ae72ca5 [file] [log] [blame]
Diana Picus3b2ef822016-10-13 16:53:18 +03001"""This is the main tool for handling llvm builds, bisects etc."""
2
3import os
Diana Picusadb07c42017-11-22 16:12:57 +01004from sys import argv
Diana Picus3b2ef822016-10-13 16:53:18 +03005from sys import exit
6
Diana Picus052b7d32017-11-24 16:19:41 +01007from modules.llvm import LLVMBuildConfig
Diana Picus95226d42017-11-01 13:16:54 +01008from modules.llvm import LLVMSubproject
9from modules.llvm import LLVMSourceConfig
10from modules.llvm import get_remote_branch
11from modules.llvm import push_branch
Diana Picus052b7d32017-11-24 16:19:41 +010012from modules.utils import CommandPrinter
13from modules.utils import CommandRunner
Diana Picus95226d42017-11-01 13:16:54 +010014
Diana Picus052b7d32017-11-24 16:19:41 +010015from linaropy.cd import cd
Diana Picus3b2ef822016-10-13 16:53:18 +030016from linaropy.git.clone import Clone
17from linaropy.proj import Proj
18
19from argparse import Action, ArgumentParser, RawTextHelpFormatter
Diana Picusefc7bda2017-06-09 19:14:08 +020020from functools import partial
Diana Picus3b2ef822016-10-13 16:53:18 +030021
22
23def die(message, config_to_dump=None):
24 """Print an error message and exit."""
Diana Picusb4307602017-04-05 19:48:39 +020025 print(message)
Diana Picus3b2ef822016-10-13 16:53:18 +030026
27 if config_to_dump is not None:
28 dump_config(config_to_dump)
29
30 exit(1)
31
Diana Picus3d1a3012017-03-14 17:38:32 +010032
Diana Picus3d1a3012017-03-14 17:38:32 +010033def get_worktree_root(env):
Diana Picus81089db2017-05-05 22:26:49 +020034 """Get the path to the LLVM worktree corresponding to env."""
35 return os.path.join(env, "llvm")
Diana Picus3b2ef822016-10-13 16:53:18 +030036
37
38def dump_config(config):
39 """Dump the list of projects that are enabled in the given config."""
40
Diana Picusb4307602017-04-05 19:48:39 +020041 print("Projects linked:")
Diana Picus3b2ef822016-10-13 16:53:18 +030042 enabled = config.get_enabled_subprojects()
43 if not enabled:
Diana Picusb4307602017-04-05 19:48:39 +020044 print("none")
Diana Picus3b2ef822016-10-13 16:53:18 +030045 else:
46 for subproj in sorted(enabled):
Diana Picusb4307602017-04-05 19:48:39 +020047 print(" + {}".format(subproj))
Diana Picus3b2ef822016-10-13 16:53:18 +030048
49
50def projects(args):
51 """Add/remove subprojects based on the values in args."""
52
53 proj = Proj()
Diana Picus3d1a3012017-03-14 17:38:32 +010054
55 llvm_worktree_root = get_worktree_root(args.env)
Diana Picus81089db2017-05-05 22:26:49 +020056 llvm_repos_root = args.repos
Diana Picus3b2ef822016-10-13 16:53:18 +030057 config = LLVMSourceConfig(proj, llvm_worktree_root)
58
59 if not args.add and not args.remove:
60 # Nothing to change, just print the current configuration
61 dump_config(config)
62 exit(0)
63
64 to_add = {}
65 if args.add:
66 for subproj in args.add:
67 repo = Clone(proj, os.path.join(llvm_repos_root, subproj))
68 to_add[subproj] = repo
69
70 try:
71 config.update(to_add, args.remove)
72 except (EnvironmentError, ValueError) as exc:
73 die("Failed to update subprojects because:\n{}".format(str(exc)))
74
75 dump_config(config)
76
Diana Picusefc7bda2017-06-09 19:14:08 +020077
Diana Picus95226d42017-11-01 13:16:54 +010078def push_current_branch(args):
Diana Picusefc7bda2017-06-09 19:14:08 +020079 """Push current branch to origin."""
80
81 proj = Proj()
82
83 llvm_worktree_root = get_worktree_root(args.env)
84 config = LLVMSourceConfig(proj, llvm_worktree_root)
85
Diana Picus95226d42017-11-01 13:16:54 +010086 llvm_worktree = Clone(proj, llvm_worktree_root)
87 local_branch = llvm_worktree.getbranch()
Diana Picusefc7bda2017-06-09 19:14:08 +020088
89 try:
Diana Picus95226d42017-11-01 13:16:54 +010090 remote_branch = get_remote_branch(llvm_worktree, local_branch)
91 config.for_each_enabled(partial(push_branch, proj, local_branch,
92 remote_branch))
93 print("Pushed to {}".format(remote_branch))
94 except (EnvironmentError, RuntimeError) as exc:
Diana Picusefc7bda2017-06-09 19:14:08 +020095 die("Failed to push branch because: " + str(exc) + str(exc.__cause__))
96
Diana Picus95226d42017-11-01 13:16:54 +010097
Diana Picus052b7d32017-11-24 16:19:41 +010098def configure_build(args):
99 """Configure a given build directory."""
100
101 proj = Proj()
102
103 llvm_worktree_root = get_worktree_root(args.env)
104 sourceConfig = LLVMSourceConfig(proj, llvm_worktree_root)
105
106 buildConfig = LLVMBuildConfig(sourceConfig, args.build)
107
108 if args.defs:
109 args.defs = ["-D{}".format(v) for v in args.defs]
110
111 if args.dry:
112 consumer = CommandPrinter()
113 else:
114 if not os.path.exists(args.build):
115 os.makedirs(args.build)
116 consumer = CommandRunner()
117
118 try:
119 buildConfig.cmake(consumer, args.defs, args.generator)
120 except RuntimeError as exc:
121 die("Failed to configure {} because:\n{}".format(args.build, str(exc)))
122
123
Diana Picus3b2ef822016-10-13 16:53:18 +0300124##########################################################################
125# Command line parsing #
126##########################################################################
127
128# If we decide we want shorthands for the subprojects, we can append to this
129# list
Diana Picusb4307602017-04-05 19:48:39 +0200130valid_subprojects = list(LLVMSubproject.get_all_subprojects().keys())
Diana Picus3b2ef822016-10-13 16:53:18 +0300131
132options = ArgumentParser(formatter_class=RawTextHelpFormatter)
Diana Picus81089db2017-05-05 22:26:49 +0200133options.add_argument(
134 '--env',
135 required=True,
136 help="Path to the environment to update.")
Diana Picus3d1a3012017-03-14 17:38:32 +0100137
Diana Picusadb07c42017-11-22 16:12:57 +0100138subcommands = options.add_subparsers(dest="subcommand")
Diana Picus3b2ef822016-10-13 16:53:18 +0300139
140# Subcommand for adding / removing subprojects
Diana Picus36317e82017-10-31 15:35:24 +0100141projs = subcommands.add_parser(
142 "projects", help="Add/remove LLVM subprojects.\n"
143 "Adding a subproject will create a worktree for it "
144 "somewhere in the LLVM source tree, on the same git "
145 "branch as LLVM itself.\n"
146 "Removing a subproject will remove the worktree, but "
147 "not the underlying git branch.")
Diana Picus3b2ef822016-10-13 16:53:18 +0300148projs.set_defaults(run_command=projects)
149
150# TODO: Overwriting previous values is not necessarily what users expect (so for
151# instance --add S1 S2 --remove S3 --add S4 would lead to adding only S4). We
152# can do better by using action='append', which would create a list (of lists?
153# or of lists and scalars?) that we can flatten to obtain all the values passed
154# by the user.
155projs.add_argument(
156 '-a', '--add',
157 nargs='+',
158 choices=valid_subprojects,
159 metavar='subproject',
Diana Picus36317e82017-10-31 15:35:24 +0100160 help="Enable given subprojects. Valid values are:\n\t{}\n".format(
Diana Picus3b2ef822016-10-13 16:53:18 +0300161 "\n\t".join(valid_subprojects)))
162projs.add_argument(
163 '-r', '--remove',
164 nargs='+',
165 choices=valid_subprojects,
166 metavar='subproject',
Diana Picus36317e82017-10-31 15:35:24 +0100167 help="Disable given subprojects.")
Diana Picusadb07c42017-11-22 16:12:57 +0100168projs.add_argument(
169 '--repos',
170 help="Path to the directory containing the repositories for all LLVM "
171 "subprojects.")
Diana Picus3b2ef822016-10-13 16:53:18 +0300172
Diana Picusefc7bda2017-06-09 19:14:08 +0200173# Subcommand for pushing the current branch to origin
174push = subcommands.add_parser(
175 "push",
Diana Picus36317e82017-10-31 15:35:24 +0100176 help="Push current branch to origin linaro-local/<user>/<branch>, "
177 "for all enabled subprojects.")
Diana Picus95226d42017-11-01 13:16:54 +0100178push.set_defaults(run_command=push_current_branch)
Diana Picusefc7bda2017-06-09 19:14:08 +0200179
Diana Picus052b7d32017-11-24 16:19:41 +0100180# Subcommand for configuring a build directory
181configure = subcommands.add_parser(
182 'configure',
183 help="Run CMake in the given build directory.")
184configure.add_argument(
185 '--build-dir',
186 dest='build',
187 required=True,
188 help="Path to the build directory. It will be created if it does not exist")
189configure.add_argument(
190 '--cmake-generator',
191 dest='generator',
192 default='Ninja',
193 help="CMake generator to use (default is Ninja).")
194configure.add_argument(
195 '--cmake-def',
196 dest='defs',
197 metavar='VAR=VALUE',
198 default=[],
199 action='append',
200 # We add the -D in front of the variable ourselves because the argument
201 # parsing gets confused otherwise (and quoting doesn't help).
202 help="Additional CMake definitions, e.g. CMAKE_BUILD_TYPE=Release."
203 "May be passed several times. The -D is added automatically.")
204configure.add_argument(
205 '-n', '--dry-run',
206 dest='dry',
207 action='store_true',
208 default=False,
209 help="Print the CMake command instead of executing it.")
210configure.set_defaults(run_command=configure_build)
211
Diana Picus3b2ef822016-10-13 16:53:18 +0300212args = options.parse_args()
Diana Picusadb07c42017-11-22 16:12:57 +0100213if args.subcommand == "projects" and args.add and not args.repos:
214 projs.error(
215 "When adding a subproject you must also pass the --repos argument")
Diana Picus3b2ef822016-10-13 16:53:18 +0300216args.run_command(args)