blob: d1bf29dd5abdcaf3ae1eb42e39ef990745967be9 [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
Diana Picus052b7d32017-11-24 16:19:41 +010010from modules.utils import CommandPrinter
11from modules.utils import CommandRunner
Diana Picus5ad55422017-12-14 17:57:10 +010012from modules.utils import get_remote_branch
13from modules.utils import push_branch
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 Picus3b2ef822016-10-13 16:53:18 +030033def dump_config(config):
34 """Dump the list of projects that are enabled in the given config."""
35
Diana Picusb4307602017-04-05 19:48:39 +020036 print("Projects linked:")
Diana Picus3b2ef822016-10-13 16:53:18 +030037 enabled = config.get_enabled_subprojects()
38 if not enabled:
Diana Picusb4307602017-04-05 19:48:39 +020039 print("none")
Diana Picus3b2ef822016-10-13 16:53:18 +030040 else:
41 for subproj in sorted(enabled):
Diana Picusb4307602017-04-05 19:48:39 +020042 print(" + {}".format(subproj))
Diana Picus3b2ef822016-10-13 16:53:18 +030043
44
45def projects(args):
46 """Add/remove subprojects based on the values in args."""
47
48 proj = Proj()
Diana Picus3d1a3012017-03-14 17:38:32 +010049
Diana Picus9f756862017-12-20 10:35:08 +010050 llvm_worktree_root = args.sources
Diana Picus81089db2017-05-05 22:26:49 +020051 llvm_repos_root = args.repos
Diana Picus3b2ef822016-10-13 16:53:18 +030052 config = LLVMSourceConfig(proj, llvm_worktree_root)
53
54 if not args.add and not args.remove:
55 # Nothing to change, just print the current configuration
56 dump_config(config)
57 exit(0)
58
59 to_add = {}
60 if args.add:
61 for subproj in args.add:
62 repo = Clone(proj, os.path.join(llvm_repos_root, subproj))
63 to_add[subproj] = repo
64
65 try:
66 config.update(to_add, args.remove)
67 except (EnvironmentError, ValueError) as exc:
68 die("Failed to update subprojects because:\n{}".format(str(exc)))
69
70 dump_config(config)
71
Diana Picusefc7bda2017-06-09 19:14:08 +020072
Diana Picus95226d42017-11-01 13:16:54 +010073def push_current_branch(args):
Diana Picusefc7bda2017-06-09 19:14:08 +020074 """Push current branch to origin."""
75
76 proj = Proj()
77
Diana Picus9f756862017-12-20 10:35:08 +010078 llvm_worktree_root = args.sources
Diana Picusefc7bda2017-06-09 19:14:08 +020079 config = LLVMSourceConfig(proj, llvm_worktree_root)
80
Diana Picus95226d42017-11-01 13:16:54 +010081 llvm_worktree = Clone(proj, llvm_worktree_root)
82 local_branch = llvm_worktree.getbranch()
Diana Picusefc7bda2017-06-09 19:14:08 +020083
84 try:
Diana Picus95226d42017-11-01 13:16:54 +010085 remote_branch = get_remote_branch(llvm_worktree, local_branch)
86 config.for_each_enabled(partial(push_branch, proj, local_branch,
87 remote_branch))
88 print("Pushed to {}".format(remote_branch))
89 except (EnvironmentError, RuntimeError) as exc:
Diana Picusefc7bda2017-06-09 19:14:08 +020090 die("Failed to push branch because: " + str(exc) + str(exc.__cause__))
91
Diana Picus95226d42017-11-01 13:16:54 +010092
Diana Picus052b7d32017-11-24 16:19:41 +010093def configure_build(args):
94 """Configure a given build directory."""
95
96 proj = Proj()
97
Diana Picus9f756862017-12-20 10:35:08 +010098 llvm_worktree_root = args.sources
Diana Picus052b7d32017-11-24 16:19:41 +010099 sourceConfig = LLVMSourceConfig(proj, llvm_worktree_root)
100
101 buildConfig = LLVMBuildConfig(sourceConfig, args.build)
102
103 if args.defs:
104 args.defs = ["-D{}".format(v) for v in args.defs]
105
106 if args.dry:
107 consumer = CommandPrinter()
108 else:
109 if not os.path.exists(args.build):
110 os.makedirs(args.build)
111 consumer = CommandRunner()
112
113 try:
114 buildConfig.cmake(consumer, args.defs, args.generator)
115 except RuntimeError as exc:
116 die("Failed to configure {} because:\n{}".format(args.build, str(exc)))
117
118
Diana Picus3b2ef822016-10-13 16:53:18 +0300119##########################################################################
120# Command line parsing #
121##########################################################################
122
123# If we decide we want shorthands for the subprojects, we can append to this
124# list
Diana Picusb4307602017-04-05 19:48:39 +0200125valid_subprojects = list(LLVMSubproject.get_all_subprojects().keys())
Diana Picus3b2ef822016-10-13 16:53:18 +0300126
127options = ArgumentParser(formatter_class=RawTextHelpFormatter)
Diana Picusadb07c42017-11-22 16:12:57 +0100128subcommands = options.add_subparsers(dest="subcommand")
Diana Picus3b2ef822016-10-13 16:53:18 +0300129
130# Subcommand for adding / removing subprojects
Diana Picus36317e82017-10-31 15:35:24 +0100131projs = subcommands.add_parser(
132 "projects", help="Add/remove LLVM subprojects.\n"
133 "Adding a subproject will create a worktree for it "
134 "somewhere in the LLVM source tree, on the same git "
135 "branch as LLVM itself.\n"
136 "Removing a subproject will remove the worktree, but "
137 "not the underlying git branch.")
Diana Picus3b2ef822016-10-13 16:53:18 +0300138projs.set_defaults(run_command=projects)
139
140# TODO: Overwriting previous values is not necessarily what users expect (so for
141# instance --add S1 S2 --remove S3 --add S4 would lead to adding only S4). We
142# can do better by using action='append', which would create a list (of lists?
143# or of lists and scalars?) that we can flatten to obtain all the values passed
144# by the user.
145projs.add_argument(
146 '-a', '--add',
147 nargs='+',
148 choices=valid_subprojects,
149 metavar='subproject',
Diana Picus36317e82017-10-31 15:35:24 +0100150 help="Enable given subprojects. Valid values are:\n\t{}\n".format(
Diana Picus3b2ef822016-10-13 16:53:18 +0300151 "\n\t".join(valid_subprojects)))
152projs.add_argument(
153 '-r', '--remove',
154 nargs='+',
155 choices=valid_subprojects,
156 metavar='subproject',
Diana Picus36317e82017-10-31 15:35:24 +0100157 help="Disable given subprojects.")
Diana Picusadb07c42017-11-22 16:12:57 +0100158projs.add_argument(
159 '--repos',
160 help="Path to the directory containing the repositories for all LLVM "
161 "subprojects.")
Diana Picus9f756862017-12-20 10:35:08 +0100162projs.add_argument(
163 '--source-dir',
164 dest='sources',
165 required=True,
166 help="Path to the directory containing the LLVM worktree that we're adding "
167 "or removing subprojects from.")
Diana Picus3b2ef822016-10-13 16:53:18 +0300168
Diana Picusefc7bda2017-06-09 19:14:08 +0200169# Subcommand for pushing the current branch to origin
170push = subcommands.add_parser(
171 "push",
Diana Picus36317e82017-10-31 15:35:24 +0100172 help="Push current branch to origin linaro-local/<user>/<branch>, "
173 "for all enabled subprojects.")
Diana Picus95226d42017-11-01 13:16:54 +0100174push.set_defaults(run_command=push_current_branch)
Diana Picus9f756862017-12-20 10:35:08 +0100175push.add_argument(
176 '--source-dir',
177 dest='sources',
178 required=True,
179 help="Path to the directory containing the LLVM worktree.")
Diana Picusefc7bda2017-06-09 19:14:08 +0200180
Diana Picus052b7d32017-11-24 16:19:41 +0100181# Subcommand for configuring a build directory
182configure = subcommands.add_parser(
183 'configure',
184 help="Run CMake in the given build directory.")
185configure.add_argument(
Diana Picus9f756862017-12-20 10:35:08 +0100186 '--source-dir',
187 dest='sources',
188 required=True,
189 help="Path to the sources directory. It should contain an LLVM worktree.")
190configure.add_argument(
Diana Picus052b7d32017-11-24 16:19:41 +0100191 '--build-dir',
192 dest='build',
193 required=True,
194 help="Path to the build directory. It will be created if it does not exist")
195configure.add_argument(
196 '--cmake-generator',
197 dest='generator',
198 default='Ninja',
199 help="CMake generator to use (default is Ninja).")
200configure.add_argument(
201 '--cmake-def',
202 dest='defs',
203 metavar='VAR=VALUE',
204 default=[],
205 action='append',
206 # We add the -D in front of the variable ourselves because the argument
207 # parsing gets confused otherwise (and quoting doesn't help).
208 help="Additional CMake definitions, e.g. CMAKE_BUILD_TYPE=Release."
209 "May be passed several times. The -D is added automatically.")
210configure.add_argument(
211 '-n', '--dry-run',
212 dest='dry',
213 action='store_true',
214 default=False,
215 help="Print the CMake command instead of executing it.")
216configure.set_defaults(run_command=configure_build)
217
Diana Picus3b2ef822016-10-13 16:53:18 +0300218args = options.parse_args()
Diana Picusadb07c42017-11-22 16:12:57 +0100219if args.subcommand == "projects" and args.add and not args.repos:
220 projs.error(
221 "When adding a subproject you must also pass the --repos argument")
Diana Picus3b2ef822016-10-13 16:53:18 +0300222args.run_command(args)