2424from west import util
2525from west .commands import CommandError , Verbosity , WestCommand
2626from west .configuration import Configuration
27- from west .manifest import MANIFEST_REV_BRANCH as MANIFEST_REV
28- from west .manifest import QUAL_MANIFEST_REV_BRANCH as QUAL_MANIFEST_REV
29- from west .manifest import QUAL_REFS_WEST as QUAL_REFS
3027from west .manifest import (
28+ _WEST_YML ,
3129 ImportFlag ,
3230 Manifest ,
3331 ManifestImportFailed ,
3432 ManifestProject ,
3533 Submodule ,
3634 _manifest_content_at ,
3735)
36+ from west .manifest import MANIFEST_REV_BRANCH as MANIFEST_REV
37+ from west .manifest import QUAL_MANIFEST_REV_BRANCH as QUAL_MANIFEST_REV
38+ from west .manifest import QUAL_REFS_WEST as QUAL_REFS
3839from west .manifest import is_group as is_project_group
3940
4041#
@@ -155,19 +156,61 @@ def __init__(self):
155156 'init' ,
156157 'create a west workspace' ,
157158 f'''\
158- Creates a west workspace.
159-
160- With -l, creates a workspace around an existing local repository;
161- without -l, creates a workspace by cloning a manifest repository
162- by URL.
159+ Initialize a west workspace, either from a remote manifest repository or from
160+ a local manifest.
163161
164- With -m, clones the repository at that URL and uses it as the
165- manifest repository. If --mr is not given, the remote's default
166- branch will be used, if it exists.
167-
168- With neither, -m { MANIFEST_URL_DEFAULT } is assumed.
169-
170- Warning: 'west init' renames and/or deletes temporary files inside the
162+ Arguments
163+ ---------
164+ --mf
165+ The relative path to the manifest file within the manifest repository
166+ (remote or local). Config option manifest.file will be set to this value.
167+ Defaults to `{ _WEST_YML } ` if not provided.
168+
169+ --topdir
170+ Specifies the directory where west should create the workspace.
171+ The `.west` folder will be created inside this directory.
172+
173+
174+ 1. Remote Manifest Repository (default)
175+ ---------------------------------------
176+ West clones a remote repository (provided via `-m / --manifest-url`) into a new
177+ workspace. The repositoy has to contain a west manifest.
178+ Inside the new workspace, the local config option `manifest.path` is set to
179+ point at the cloned directory (relative path to the workspace).
180+
181+ If no `-m / --manifest-url` is provided, west uses Zephyr URL by default:
182+ { MANIFEST_URL_DEFAULT } .
183+
184+ The west workspace (topdir) is determined as follows:
185+ - `-t / --topdir` if provided
186+ - `[directory]` if provided
187+ - the current working directory (if neither `--topdir` nor `[directory]` are
188+ provided)
189+
190+ Note:
191+ - If both `-t / --topdir` and `[directory]` are provided, `-t / --topdir`
192+ specifies the workspace directory, while `[directory]` specifies a subfolder
193+ where the manifest repository is cloned inside the workspace.
194+ - With `--mr`, you can specify the revision (branch, tag, or sha) of the
195+ remote repository that will be cloned. It defaults to the repository's
196+ default branch (if available).
197+
198+ 2. Local Manifest
199+ -----------------
200+ If `-l / --local` is given, west initializes a new workspace from an already
201+ existing local manifest. The directory containing the manifest can be provided
202+ in positional argument `[manifest_directory]` (it defaults to current working
203+ directory if no value is provided).
204+ Inside the new workspace, the local config option `manifest.path` is set to
205+ point at the directory containing the manifest (relative path to the workspace)
206+
207+ Note: The west workspace is created in the `manifest_directory`'s parent
208+ if no other directory is provided in `--topdir`.
209+
210+
211+ Known Issues
212+ ------------
213+ 'west init' renames and/or deletes temporary files inside the
171214workspace being created. This fails on some filesystems when some
172215development tool or any other program is trying to read/index these
173216temporary files at the same time. For instance, it is required to stop
@@ -192,9 +235,10 @@ def do_add_parser(self, parser_adder):
192235 parser = self ._parser (
193236 parser_adder ,
194237 usage = '''
195-
196- %(prog)s [-m URL] [--mr REVISION] [--mf FILE] [-o=GIT_CLONE_OPTION] [directory]
197- %(prog)s -l [--mf FILE] directory
238+ remote repository:
239+ %(prog)s [-m URL] [--mr REVISION] [--mf FILE] [-o=GIT_CLONE_OPTION] [-t WORKSPACE_DIR] [directory]
240+ local manifest:
241+ %(prog)s -l [-t WORKSPACE_DIR] [--mf FILE] [manifest_directory]
198242''' ,
199243 )
200244
@@ -203,14 +247,16 @@ def do_add_parser(self, parser_adder):
203247 parser .add_argument (
204248 '-m' ,
205249 '--manifest-url' ,
206- help = '''manifest repository URL to clone;
250+ metavar = 'URL' ,
251+ help = '''remote manifest repository URL to clone;
207252 cannot be combined with -l''' ,
208253 )
209254 parser .add_argument (
210255 '-o' ,
211256 '--clone-opt' ,
212257 action = 'append' ,
213258 default = [],
259+ metavar = 'GIT_CLONE_OPTION' ,
214260 help = '''additional option to pass to 'git clone'
215261 (e.g. '-o=--depth=1'); may be given more than once;
216262 cannot be combined with -l''' ,
@@ -219,21 +265,33 @@ def do_add_parser(self, parser_adder):
219265 '--mr' ,
220266 '--manifest-rev' ,
221267 dest = 'manifest_rev' ,
268+ metavar = 'REVISION' ,
222269 help = '''manifest repository branch or tag name
223270 to check out first; cannot be combined with -l''' ,
224271 )
225- parser .add_argument (
226- '--mf' , '--manifest-file' , dest = 'manifest_file' , help = 'manifest file name to use'
227- )
228272 parser .add_argument (
229273 '-l' ,
230274 '--local' ,
231275 action = 'store_true' ,
232- help = '''use "directory" as an existing local
233- manifest repository instead of cloning one from
234- MANIFEST_URL; .west is created next to "directory"
235- in this case, and manifest.path points at
236- "directory"''' ,
276+ help = '''initialize from an already existing local
277+ manifest instead of cloning a remote manifest.''' ,
278+ )
279+ parser .add_argument (
280+ '--mf' ,
281+ '--manifest-file' ,
282+ dest = 'manifest_file' ,
283+ metavar = 'FILE' ,
284+ help = f'''manifest file to use. It is the relative
285+ path of the manifest file within the repository
286+ (remote or local). Defaults to { _WEST_YML } .''' ,
287+ )
288+ parser .add_argument (
289+ '-t' ,
290+ '--topdir' ,
291+ dest = 'topdir' ,
292+ metavar = 'WORKSPACE_DIR' ,
293+ help = '''the directory of the west workspace, where
294+ .west will be created in.''' ,
237295 )
238296 parser .add_argument (
239297 '--rename-delay' ,
@@ -249,9 +307,10 @@ def do_add_parser(self, parser_adder):
249307 'directory' ,
250308 nargs = '?' ,
251309 default = None ,
252- help = '''with -l, the path to the local manifest repository;
253- without it, the directory to create the workspace in (defaulting
254- to the current working directory in this case)''' ,
310+ metavar = 'directory' ,
311+ help = '''with --local: the path to the local manifest repository
312+ which contains a west.yml;
313+ otherwise: the directory to create the workspace in''' ,
255314 )
256315
257316 return parser
@@ -302,15 +361,19 @@ def local(self, args) -> Path:
302361 #
303362 # https://docs.python.org/3/library/pathlib.html#pathlib.PurePath.parent
304363 manifest_dir = Path (args .directory or os .getcwd ()).resolve ()
305- manifest_filename = args .manifest_file or 'west.yml'
364+ manifest_filename = args .manifest_file or _WEST_YML
306365 manifest_file = manifest_dir / manifest_filename
307- topdir = manifest_dir .parent
308- rel_manifest = manifest_dir .name
309- west_dir = topdir / WEST_DIR
310-
311366 if not manifest_file .is_file ():
312367 self .die (f'can\' t init: no { manifest_filename } found in { manifest_dir } ' )
313368
369+ topdir = Path (args .topdir or manifest_dir .parent ).resolve ()
370+
371+ if not manifest_file .is_relative_to (topdir ):
372+ self .die (f'{ manifest_file } must be relative to west topdir' )
373+
374+ rel_manifest = manifest_dir .relative_to (topdir )
375+ west_dir = topdir / WEST_DIR
376+
314377 self .banner ('Initializing from existing manifest repository' , rel_manifest )
315378 self .small_banner (f'Creating { west_dir } and local configuration file' )
316379 self .create (west_dir )
@@ -322,8 +385,21 @@ def local(self, args) -> Path:
322385 return topdir
323386
324387 def bootstrap (self , args ) -> Path :
325- topdir = Path (abspath (args .directory or os .getcwd ()))
326- self .banner ('Initializing in' , topdir )
388+ subdir = '.'
389+ if args .topdir :
390+ topdir = Path (abspath (args .topdir ))
391+ if args .directory :
392+ if not Path (abspath (args .directory )).is_relative_to (topdir ):
393+ self .die (
394+ f"directory '{ args .directory } ' must be relative "
395+ f"to west topdir '{ args .topdir } '"
396+ )
397+ subdir = os .path .relpath (args .directory , topdir )
398+ elif args .directory :
399+ topdir = Path (abspath (args .directory ))
400+ else :
401+ topdir = Path (abspath (os .getcwd ()))
402+ self .banner (f'Initializing in { topdir } ' )
327403
328404 manifest_url = args .manifest_url or MANIFEST_URL_DEFAULT
329405 if args .manifest_rev :
@@ -378,7 +454,7 @@ def bootstrap(self, args) -> Path:
378454 raise
379455
380456 # Verify the manifest file exists.
381- temp_manifest_filename = args .manifest_file or 'west.yml'
457+ temp_manifest_filename = args .manifest_file or _WEST_YML
382458 temp_manifest = tempdir / temp_manifest_filename
383459 if not temp_manifest .is_file ():
384460 self .die (
@@ -404,6 +480,7 @@ def bootstrap(self, args) -> Path:
404480 # is PurePosixPath.
405481 manifest_path = PurePath (urlparse (manifest_url ).path ).name
406482
483+ manifest_path = str (Path (subdir ) / manifest_path )
407484 manifest_abspath = topdir / manifest_path
408485
409486 # Some filesystems like NTFS can't rename files in use.
0 commit comments