add support for manifest filenames other than west.yml
Signed-off-by: Michael Zimmermann <michael.zimmermann@grandcentrix.net>
This commit is contained in:
parent
6350ca4f86
commit
80bf5cf381
11
README.rst
11
README.rst
|
@ -15,10 +15,10 @@ Basic Usage
|
|||
-----------
|
||||
|
||||
West lets you manage multiple Git repositories under a single directory using a
|
||||
single file, called the *west manifest file*, or *manifest* for short. The
|
||||
manifest file is named ``west.yml``. You use ``west init`` to set up this
|
||||
directory, then ``west update`` to fetch and/or update the repositories named
|
||||
in the manifest.
|
||||
single file, called the *west manifest file*, or *manifest* for short.
|
||||
By default the manifest file is named ``west.yml``.
|
||||
You use ``west init`` to set up this directory, then ``west update`` to fetch
|
||||
and/or update the repositories named in the manifest.
|
||||
|
||||
By default, west uses `upstream Zephyr's manifest file
|
||||
<https://github.com/zephyrproject-rtos/zephyr/blob/master/west.yml>`_, but west
|
||||
|
@ -45,7 +45,8 @@ What just happened:
|
|||
creating working trees in the installation directory ``zephyrproject``.
|
||||
|
||||
Use ``west init -m`` to specify another manifest repository. Use ``--mr`` to
|
||||
use a revision other than ``master``.
|
||||
use a revision other than ``master``. Use ``--mf`` to use a manifest file other
|
||||
than ``west.yml``.
|
||||
|
||||
Additional Commands
|
||||
-------------------
|
||||
|
|
|
@ -181,7 +181,7 @@ class WestApp:
|
|||
list(self.mle.args)))
|
||||
elif isinst(FileNotFoundError):
|
||||
# This should ordinarily only happen when the top
|
||||
# level west.yml is not found.
|
||||
# level manifest is not found.
|
||||
log.die(f"file not found: {self.mle.filename}")
|
||||
elif isinst(_ManifestImportDepth):
|
||||
log.die('failed, likely due to manifest import loop')
|
||||
|
|
|
@ -124,7 +124,7 @@ class Init(_ProjectCommand):
|
|||
1. Creates a .west directory and clones a manifest repository
|
||||
from a git URL to a temporary subdirectory of .west,
|
||||
.west/<tmpdir>.
|
||||
2. Parses the manifest file, .west/<tmpdir>/west.yml.
|
||||
2. Parses the manifest file, .west/<tmpdir>/<manifest.file>.
|
||||
This file's contents can specify manifest.path, the location
|
||||
of the manifest repository in the workspace, like so:
|
||||
|
||||
|
@ -161,6 +161,8 @@ class Init(_ProjectCommand):
|
|||
parser.add_argument('--mr', '--manifest-rev', dest='manifest_rev',
|
||||
help='''manifest revision to check out and use;
|
||||
cannot be combined with -l''')
|
||||
parser.add_argument('--mf', '--manifest-file', dest='manifest_file',
|
||||
help='manifest file name to use')
|
||||
parser.add_argument('-l', '--local', action='store_true',
|
||||
help='''use an existing local manifest repository
|
||||
instead of cloning one; cannot be combined with
|
||||
|
@ -212,13 +214,15 @@ class Init(_ProjectCommand):
|
|||
log.die('--mr cannot be used with -l')
|
||||
|
||||
manifest_dir = Path(args.directory or os.getcwd())
|
||||
manifest_file = manifest_dir / 'west.yml'
|
||||
manifest_filename = args.manifest_file or 'west.yml'
|
||||
manifest_file = manifest_dir / manifest_filename
|
||||
topdir = manifest_dir.parent
|
||||
rel_manifest = manifest_dir.name
|
||||
west_dir = topdir / WEST_DIR
|
||||
|
||||
if not manifest_file.is_file():
|
||||
log.die(f'can\'t init: no "west.yml" found in {manifest_dir}')
|
||||
log.die(f'can\'t init: no {manifest_filename} found in '
|
||||
f'{manifest_dir}')
|
||||
|
||||
log.banner('Initializing from existing manifest repository',
|
||||
rel_manifest)
|
||||
|
@ -226,6 +230,7 @@ class Init(_ProjectCommand):
|
|||
self.create(west_dir)
|
||||
os.chdir(topdir)
|
||||
update_config('manifest', 'path', os.fspath(rel_manifest))
|
||||
update_config('manifest', 'file', manifest_filename, topdir=topdir)
|
||||
|
||||
return topdir
|
||||
|
||||
|
@ -257,9 +262,11 @@ class Init(_ProjectCommand):
|
|||
raise
|
||||
|
||||
# Verify the manifest file exists.
|
||||
temp_manifest = tempdir / 'west.yml'
|
||||
temp_manifest_filename = args.manifest_file or 'west.yml'
|
||||
temp_manifest = tempdir / temp_manifest_filename
|
||||
if not temp_manifest.is_file():
|
||||
log.die(f'can\'t init: no "west.yml" found in {tempdir}\n'
|
||||
log.die(f'can\'t init: no {temp_manifest_filename} found in '
|
||||
f'{tempdir}\n'
|
||||
f' Hint: check --manifest-url={manifest_url} and '
|
||||
f'--manifest-rev={manifest_rev}\n'
|
||||
f' You may need to remove {west_dir} before retrying.')
|
||||
|
@ -290,6 +297,8 @@ class Init(_ProjectCommand):
|
|||
log.die(e)
|
||||
log.small_banner('setting manifest.path to', manifest_path)
|
||||
update_config('manifest', 'path', manifest_path, topdir=topdir)
|
||||
update_config('manifest', 'file', temp_manifest_filename,
|
||||
topdir=topdir)
|
||||
|
||||
return topdir
|
||||
|
||||
|
@ -640,15 +649,15 @@ class Update(_ProjectCommand):
|
|||
def __init__(self):
|
||||
super().__init__(
|
||||
'update',
|
||||
'update projects described in west.yml',
|
||||
'update projects described in west manifest',
|
||||
textwrap.dedent('''\
|
||||
Updates each project repository to the revision specified in
|
||||
the manifest file, west.yml, as follows:
|
||||
the manifest file, as follows:
|
||||
|
||||
1. Fetch the project's remote to ensure the manifest
|
||||
revision is available locally
|
||||
2. Reset the manifest-rev branch to the revision in
|
||||
west.yml
|
||||
the manifest
|
||||
3. Check out the new manifest-rev commit as a detached HEAD
|
||||
(but see "checked out branches")
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@ import shlex
|
|||
import subprocess
|
||||
import sys
|
||||
from typing import Any, Callable, Dict, Iterable, List, NoReturn, \
|
||||
NamedTuple, Optional, TYPE_CHECKING, Union
|
||||
NamedTuple, Optional, Tuple, TYPE_CHECKING, Union
|
||||
|
||||
from packaging.version import parse as parse_version
|
||||
import pykwalify.core
|
||||
|
@ -138,7 +138,7 @@ def _west_commands_merge(wc1: List[str], wc2: List[str]) -> List[str]:
|
|||
return wc1 or wc2
|
||||
|
||||
def _mpath(cp: Optional[configparser.ConfigParser] = None,
|
||||
topdir: Optional[PathType] = None) -> str:
|
||||
topdir: Optional[PathType] = None) -> Tuple[str, str]:
|
||||
# Return the value of the manifest.path configuration option
|
||||
# in *cp*, a ConfigParser. If not given, create a new one and
|
||||
# load configuration options with the given *topdir* as west
|
||||
|
@ -152,7 +152,10 @@ def _mpath(cp: Optional[configparser.ConfigParser] = None,
|
|||
cfg.read_config(configfile=cfg.ConfigFile.LOCAL, config=cp, topdir=topdir)
|
||||
|
||||
try:
|
||||
return cp.get('manifest', 'path')
|
||||
path = cp.get('manifest', 'path')
|
||||
filename = cp.get('manifest', 'file', fallback=_WEST_YML)
|
||||
|
||||
return (path, filename)
|
||||
except (configparser.NoOptionError, configparser.NoSectionError) as e:
|
||||
raise MalformedConfig('no "manifest.path" config option is set') from e
|
||||
|
||||
|
@ -308,10 +311,11 @@ def manifest_path() -> str:
|
|||
- `MalformedConfig` if the configuration file has no
|
||||
``manifest.path`` key
|
||||
|
||||
- ``FileNotFoundError`` if no ``west.yml`` exists in
|
||||
``manifest.path``
|
||||
- ``FileNotFoundError`` if no manifest file exists as determined by
|
||||
``manifest.path`` and ``manifest.file``
|
||||
'''
|
||||
ret = os.path.join(util.west_topdir(), _mpath(), _WEST_YML)
|
||||
(mpath, mname) = _mpath()
|
||||
ret = os.path.join(util.west_topdir(), mpath, mname)
|
||||
# It's kind of annoying to manually instantiate a FileNotFoundError.
|
||||
# This seems to be the best way.
|
||||
if not os.path.isfile(ret):
|
||||
|
@ -897,7 +901,7 @@ class Manifest:
|
|||
- If neither *source_file* nor *topdir* is given, the file
|
||||
system is searched for *topdir*. That workspace's
|
||||
``manifest.path`` configuration option is used to find
|
||||
*source_file*, ``topdir/<manifest.path>/west.yml``.
|
||||
*source_file*, ``topdir/<manifest.path>/<manifest.file>``.
|
||||
|
||||
- If only *source_file* is given, *topdir* is found
|
||||
starting there. The directory containing *source_file*
|
||||
|
@ -932,10 +936,10 @@ class Manifest:
|
|||
# neither source_file nor topdir: search the filesystem
|
||||
# for the workspace and use its manifest.path.
|
||||
topdir = util.west_topdir()
|
||||
mpath = _mpath(topdir=topdir)
|
||||
(mpath, mname) = _mpath(topdir=topdir)
|
||||
kwargs.update({
|
||||
'topdir': topdir,
|
||||
'source_file': os.path.join(topdir, mpath, _WEST_YML),
|
||||
'source_file': os.path.join(topdir, mpath, mname),
|
||||
'manifest_path': mpath
|
||||
})
|
||||
else:
|
||||
|
@ -960,8 +964,8 @@ class Manifest:
|
|||
|
||||
# Read manifest.path from topdir/.west/config, and use it
|
||||
# to locate source_file.
|
||||
mpath = _mpath(topdir=topdir)
|
||||
source_file = os.path.join(topdir, mpath, _WEST_YML)
|
||||
(mpath, mname) = _mpath(topdir=topdir)
|
||||
source_file = os.path.join(topdir, mpath, mname)
|
||||
kwargs.update({
|
||||
'source_file': source_file,
|
||||
'manifest_path': mpath,
|
||||
|
@ -1747,7 +1751,7 @@ class Manifest:
|
|||
except FileNotFoundError:
|
||||
# We may need to fetch a new manifest-rev, e.g. if
|
||||
# revision is a branch that didn't used to have a
|
||||
# west.yml, but now does.
|
||||
# manifest, but now does.
|
||||
content = self._importer(project, path)
|
||||
except subprocess.CalledProcessError:
|
||||
# We may need a new manifest-rev, e.g. if revision is
|
||||
|
|
|
@ -589,6 +589,70 @@ def test_init_local_missing_west_yml_failure(repos_tmpdir):
|
|||
cmd(f'init -l "{zephyr_install_dir}"')
|
||||
|
||||
|
||||
def test_init_local_with_manifest_filename(repos_tmpdir):
|
||||
# Test 'west init --mf -l' on a local repo
|
||||
|
||||
manifest = repos_tmpdir / 'repos' / 'zephyr'
|
||||
workspace = repos_tmpdir / 'workspace'
|
||||
zephyr_install_dir = workspace / 'zephyr'
|
||||
|
||||
# Do a local clone of manifest repo
|
||||
clone(str(manifest), str(zephyr_install_dir))
|
||||
os.rename(str(zephyr_install_dir / 'west.yml'),
|
||||
str(zephyr_install_dir / 'project.yml'))
|
||||
|
||||
# fails because west.yml is missing
|
||||
with pytest.raises(subprocess.CalledProcessError):
|
||||
cmd(f'init -l "{zephyr_install_dir}"')
|
||||
|
||||
# create a manifest with a syntax error so we can test if it's being parsed
|
||||
with open(zephyr_install_dir / 'west.yml', 'w') as f:
|
||||
f.write('[')
|
||||
|
||||
cwd = os.getcwd()
|
||||
cmd(f'init -l "{zephyr_install_dir}"')
|
||||
|
||||
# init with a local manifest doesn't parse the file, so let's access it
|
||||
workspace.chdir()
|
||||
with pytest.raises(subprocess.CalledProcessError):
|
||||
cmd('list')
|
||||
|
||||
os.chdir(cwd)
|
||||
shutil.move(workspace / '.west', workspace / '.west-syntaxerror')
|
||||
|
||||
# success
|
||||
cmd(f'init --mf project.yml -l "{zephyr_install_dir}"')
|
||||
workspace.chdir()
|
||||
config.read_config()
|
||||
cmd('update')
|
||||
|
||||
|
||||
def test_init_with_manifest_filename(repos_tmpdir):
|
||||
# Test 'west init --mf' on a normal repo
|
||||
|
||||
west_tmpdir = repos_tmpdir / 'workspace'
|
||||
manifest = repos_tmpdir / 'repos' / 'zephyr'
|
||||
|
||||
with open(manifest / 'west.yml', 'r') as f:
|
||||
manifest_data = f.read()
|
||||
|
||||
# also creates a west.yml with a syntax error to verify west doesn't even
|
||||
# try to load the file
|
||||
add_commit(str(manifest), 'rename manifest',
|
||||
files={'west.yml': '[', 'project.yml': manifest_data})
|
||||
|
||||
# syntax error
|
||||
with pytest.raises(subprocess.CalledProcessError):
|
||||
cmd(f'init -m "{manifest}" "{west_tmpdir}"')
|
||||
shutil.move(west_tmpdir, repos_tmpdir / 'workspace-syntaxerror')
|
||||
|
||||
# success
|
||||
cmd(f'init -m "{manifest}" --mf project.yml "{west_tmpdir}"')
|
||||
west_tmpdir.chdir()
|
||||
config.read_config()
|
||||
cmd('update')
|
||||
|
||||
|
||||
def test_extension_command_execution(west_init_tmpdir):
|
||||
with pytest.raises(subprocess.CalledProcessError):
|
||||
cmd('test-extension')
|
||||
|
|
Loading…
Reference in New Issue