Skip to content

Commit

Permalink
app: more versatile initialization for path in config
Browse files Browse the repository at this point in the history
in case a manifest file is contained into some sub directories,
the command to init a workspace locally should be
```
west init -l sub1/sub2 --mf west.yml
```

but in that case, the west top dir is going to be into `sub1`
which is an issue.

one workaround is to use:
```
west init -l sub1 --mf sub2/west.yml
```

but in that case, the config is initialized incorrectly:
`manifest.path` contains only `sub1` and `manifest.file` is `sub2/west.yml`.

`manifest.path` should contain a path, even if `--mf` is a relative path.
`manifest.file` should only contain the filename.

this change allows any usage so that the workspace top dir is created next to `sub1`
and the manifest repo can be located into nested directories
  • Loading branch information
fouge committed Dec 18, 2024
1 parent 361004d commit 55d190c
Showing 1 changed file with 43 additions and 21 deletions.
64 changes: 43 additions & 21 deletions src/west/app/project.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,6 @@
from west import util
from west.commands import CommandError, Verbosity, WestCommand
from west.configuration import Configuration
from west.manifest import MANIFEST_REV_BRANCH as MANIFEST_REV
from west.manifest import QUAL_MANIFEST_REV_BRANCH as QUAL_MANIFEST_REV
from west.manifest import QUAL_REFS_WEST as QUAL_REFS
from west.manifest import (
ImportFlag,
Manifest,
Expand All @@ -34,8 +31,12 @@
Submodule,
_manifest_content_at,
)
from west.manifest import MANIFEST_REV_BRANCH as MANIFEST_REV
from west.manifest import QUAL_MANIFEST_REV_BRANCH as QUAL_MANIFEST_REV
from west.manifest import QUAL_REFS_WEST as QUAL_REFS
from west.manifest import is_group as is_project_group


#
# Project-related or multi-repo commands, like "init", "update",
# "diff", etc.
Expand Down Expand Up @@ -73,7 +74,7 @@ def _projects(self, ids, only_cloned=False):
return self.manifest.get_projects(ids, only_cloned=only_cloned)
except ValueError as ve:
if len(ve.args) != 2:
raise # not directly raised by get_projects()
raise # not directly raised by get_projects()

# Die with an error message on unknown or uncloned projects.
unknown, uncloned = ve.args
Expand Down Expand Up @@ -143,6 +144,7 @@ def has_output():

return has_output()


class Init(_ProjectCommand):

def __init__(self):
Expand Down Expand Up @@ -204,13 +206,13 @@ def do_add_parser(self, parser_adder):
help='''manifest repository branch or tag name
to check out first; cannot be combined with -l''')
parser.add_argument('--mf', '--manifest-file', dest='manifest_file',
help='manifest file name to use')
help='manifest file name to use, relative to "directory"')
parser.add_argument('-l', '--local', action='store_true',
help='''use "directory" as an existing local
manifest repository instead of cloning one from
MANIFEST_URL; .west is created next to "directory"
in this case, and manifest.path points at
"directory"''')
help='''use "directory" to create the workspace
from a local manifest directory, instead of cloning
one from MANIFEST_URL; .west is created next to
"directory" in this case, and manifest.path points at
the manifest file location.''')
parser.add_argument('--rename-delay', type=int,
help='''Number of seconds to wait before renaming
some temporary directories. Some filesystems like NTFS
Expand Down Expand Up @@ -273,7 +275,7 @@ def local(self, args) -> Path:
manifest_filename = args.manifest_file or 'west.yml'
manifest_file = manifest_dir / manifest_filename
topdir = manifest_dir.parent
rel_manifest = manifest_dir.name
rel_manifest = manifest_file.parent.relative_to(manifest_dir.parent)
west_dir = topdir / WEST_DIR

if not manifest_file.is_file():
Expand All @@ -287,7 +289,7 @@ def local(self, args) -> Path:
os.chdir(topdir)
self.config = Configuration(topdir=topdir)
self.config.set('manifest.path', os.fspath(rel_manifest))
self.config.set('manifest.file', manifest_filename)
self.config.set('manifest.file', manifest_file.name)

return topdir

Expand Down Expand Up @@ -412,6 +414,7 @@ def create(self, directory: Path, exist_ok: bool = True) -> None:
except Exception as e:
self.die(f"Can't create {directory}: {e}")


class List(_ProjectCommand):
def __init__(self):
super().__init__(
Expand Down Expand Up @@ -554,6 +557,7 @@ def delay(func, project):

self.inf(result, colorize=False)


class ManifestCommand(_ProjectCommand):
# The slightly weird naming is to avoid a conflict with
# west.manifest.Manifest.
Expand Down Expand Up @@ -617,7 +621,7 @@ def do_run(self, args, user_args):
'sort_keys': False}

if args.validate:
pass # nothing more to do
pass # nothing more to do
elif args.resolve:
self._die_if_manifest_project_filter('resolve')
self._dump(args, manifest.as_yaml(**dump_kwargs))
Expand Down Expand Up @@ -647,6 +651,7 @@ def _dump(self, args, to_dump):
else:
sys.stdout.write(to_dump)


class Compare(_ProjectCommand):
def __init__(self):
super().__init__(
Expand Down Expand Up @@ -809,6 +814,7 @@ def print_status(self, project):
self.small_banner('status:')
self.inf(textwrap.indent(cp.stdout.decode().rstrip(), ' ' * 4))


class Diff(_ProjectCommand):
def __init__(self):
super().__init__(
Expand Down Expand Up @@ -841,7 +847,7 @@ def do_run(self, args, user_args):
color = ['--color=always'] if self.color_ui else []
for project in self._cloned_projects(args, only_active=not args.all):
diff_commit = (
['manifest-rev'] # see #719 and #747
['manifest-rev'] # see #719 and #747
# Special-case the manifest repository while it's
# still showing up in the 'projects' list. Yet
# more evidence we should tackle #327.
Expand Down Expand Up @@ -875,6 +881,7 @@ def do_run(self, args, user_args):
elif self.verbosity <= Verbosity.INF:
self.inf(f"Empty diff in {no_diff} projects.")


class Status(_ProjectCommand):
def __init__(self):
super().__init__(
Expand Down Expand Up @@ -924,6 +931,7 @@ def do_run(self, args, user_args):
failed.append(project)
self._handle_failed(args, failed)


class Update(_ProjectCommand):

def __init__(self):
Expand Down Expand Up @@ -1238,7 +1246,7 @@ def update_submodules(self, project):
project.git(['submodule', 'sync', '--recursive'])
project.git(config_opts +
['submodule', 'update', '--init',
submodules_update_strategy, '--recursive'])
submodules_update_strategy, '--recursive'])
return
else:
# Cache used so convert to a list so that --reference can be used.
Expand All @@ -1265,8 +1273,8 @@ def update_submodules(self, project):
level=Verbosity.DBG_MORE)
project.git(config_opts +
['submodule', 'update',
'--init', submodules_update_strategy,
'--recursive'] + ref + [submodule.path])
'--init', submodules_update_strategy,
'--recursive'] + ref + [submodule.path])

def update(self, project):
if self.args.stats:
Expand Down Expand Up @@ -1658,6 +1666,7 @@ def decide_update_strategy(self, project, sha, stats, take_stats):
def project_is_active(self, project):
return self.manifest.is_active(project, extra_filter=self.group_filter)


class ForAll(_ProjectCommand):
def __init__(self):
super().__init__(
Expand Down Expand Up @@ -1737,6 +1746,7 @@ def do_run(self, args, user_args):
failed.append(project)
self._handle_failed(args, failed)


GREP_EPILOG = '''
EXAMPLES
--------
Expand Down Expand Up @@ -1835,11 +1845,12 @@ def do_run(self, args, user_args):
west config grep.color never
'''


# color.ui limitation:
# https://github.com/zephyrproject-rtos/west/issues/651

class Grep(_ProjectCommand):

# When adding a tool, make sure to check:
#
# - the 'failed' handling below for proper exit codes
Expand Down Expand Up @@ -1978,6 +1989,7 @@ def tool_args(self, tool, cmdline_args):

return ret


class Topdir(_ProjectCommand):
def __init__(self):
super().__init__(
Expand All @@ -1996,6 +2008,7 @@ def do_add_parser(self, parser_adder):
def do_run(self, args, user_args):
self.inf(PurePath(self.topdir).as_posix())


class SelfUpdate(_ProjectCommand):
def __init__(self):
super().__init__(
Expand All @@ -2009,6 +2022,7 @@ def do_add_parser(self, parser_adder):
def do_run(self, args, user_args):
self.die(self.description)


#
# Private helper routines.
#
Expand All @@ -2027,11 +2041,13 @@ def _clean_west_refspace(project):
delete_ref_cmd = ['update-ref', '-d', ref]
project.git(delete_ref_cmd)


def _update_manifest_rev(project, new_manifest_rev):
project.git(['update-ref',
'-m', f'west update: moving to {new_manifest_rev}',
QUAL_MANIFEST_REV, new_manifest_rev])


def _maybe_sha(rev):
# Return true if and only if the given revision might be a SHA.

Expand All @@ -2042,6 +2058,7 @@ def _maybe_sha(rev):

return len(rev) <= 40


def _rev_type(project, rev=None):
# Returns a "refined" revision type of rev (default:
# project.revision) as one of the following strings: 'tag', 'tree',
Expand All @@ -2067,7 +2084,7 @@ def _rev_type(project, rev=None):
return 'other'
elif stdout in ('blob', 'tree', 'tag'):
return stdout
elif stdout != 'commit': # just future-proofing
elif stdout != 'commit': # just future-proofing
return 'other'

# to tell branches, lightweight tags, and commits apart, we need rev-parse.
Expand Down Expand Up @@ -2095,6 +2112,7 @@ def _rev_type(project, rev=None):
else:
return 'other'


def _head_ok(project):
# Returns True if the reference 'HEAD' exists and is not a tag or remote
# ref (e.g. refs/remotes/origin/HEAD).
Expand All @@ -2110,6 +2128,7 @@ def _head_ok(project):
return project.git('show-ref --quiet --head /',
check=False).returncode == 0


def projects_unknown(manifest, projects):
# Retrieve the projects with get_projects(project,
# only_cloned=False). Return a pair: (projects, unknown)
Expand All @@ -2120,12 +2139,13 @@ def projects_unknown(manifest, projects):
return (manifest.get_projects(projects, only_cloned=False), None)
except ValueError as ve:
if len(ve.args) != 2:
raise # not directly raised by get_projects()
raise # not directly raised by get_projects()
unknown = ve.args[0]
if not unknown:
raise # only_cloned is False, so this "can't happen"
raise # only_cloned is False, so this "can't happen"
return (None, unknown)


#
# Special files and directories in the west workspace.
#
Expand Down Expand Up @@ -2163,6 +2183,7 @@ def projects_unknown(manifest, projects):
Regardless of the above, output is limited to cloned projects.
'''


#
# Helper class for creating format string keys that are expensive or
# undesirable to compute if not needed.
Expand Down Expand Up @@ -2190,6 +2211,7 @@ def __format__(self, format_spec):
self.as_str = str(self.obj)
return ('{:' + format_spec + '}').format(self.as_str)


#
# Logging helpers
#
Expand Down

0 comments on commit 55d190c

Please sign in to comment.