Skip to content

Commit a81f4d4

Browse files
auto-cache: fetch from remote only if necessary
Enables fully offline work with auto-cache.: Skip remote fetches when a commit or tag is used, and the revision is already available within the auto-cache.
1 parent 76890ef commit a81f4d4

File tree

1 file changed

+30
-9
lines changed

1 file changed

+30
-9
lines changed

src/west/app/project.py

Lines changed: 30 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1177,9 +1177,9 @@ def do_add_parser(self, parser_adder):
11771177
'--auto-cache',
11781178
help='''automatically setup local cache repositories
11791179
in a flat folder hierarchy, but with an additional
1180-
subfolder (hashed name) for different remote URLs.
1181-
Each local cache repository is automatically cloned
1182-
on first usage and synced on subsequent clones.
1180+
subfolder (hashed name) for different remote URLs. Each
1181+
local cache repository is automatically cloned on first
1182+
usage and synced on subsequent fetches (if necessary).
11831183
This cache has the lowest priority (Prio 2).''',
11841184
)
11851185

@@ -1203,7 +1203,8 @@ def do_add_parser(self, parser_adder):
12031203
workspace setup.
12041204
Only in case of auto-cache the 'west update' process updates the local
12051205
caches first, which then serve as the source for pulling changes into
1206-
the workspace.
1206+
the workspace. Thereby, the auto-cache only fetches updates from remote
1207+
if the specified revision is not already present in the local cache.
12071208
12081209
Example: Assume your manifest describes this workspace structure:
12091210
(workspace)
@@ -1233,7 +1234,8 @@ def do_add_parser(self, parser_adder):
12331234
folder hierarchy is setup automatically. Each repository is stored under a
12341235
directory named after the basename of its remote URL. To prevent conflicts
12351236
between repos with same name, a hash of the remote URL is used as subfolder.
1236-
Note: Each local cache repo is automatically synced on subsequent updates.
1237+
Note: Each local cache repo is automatically synced on subsequent updates on
1238+
demand (if the requested revision is not already contained within the cache).
12371239
(auto cache directory)
12381240
├── bar.git
12391241
│ ├── <hash>
@@ -1757,13 +1759,29 @@ def handle_auto_cache(self, project):
17571759
# Then clone the repository into the local cache.
17581760
cache_dir_parent = Path(cache_dir).parent
17591761
cache_dir_parent.mkdir(parents=True, exist_ok=True)
1762+
self.dbg(f'{project.name}: create auto-cache for {project.url} in {cache_dir}')
17601763
project.git(
17611764
['clone', '--mirror', '--', project.url, os.fspath(cache_dir)], cwd=cache_dir_parent
17621765
)
17631766
self.create_auto_cache_info(project, cache_dir)
17641767
else:
1765-
# The local cache already exists. Sync it with remote.
1766-
project.git(['remote', 'update', '--prune'], cwd=cache_dir)
1768+
# check if the remote update can be skipped
1769+
if self.fs != 'always':
1770+
# Determine the type of the project revision by checking if it is
1771+
# already contained in the auto-cache.
1772+
# If it is an already available tag or a commit, the remote
1773+
# update can be skipped. Otherwise the auto-cache must be updated.
1774+
rev_type = _rev_type(project, cwd=cache_dir)
1775+
if rev_type in ('tag', 'commit'):
1776+
self.dbg(
1777+
f'{project.name}: auto-cache remote update is skipped '
1778+
f'as it already contains {rev_type} {project.revision}'
1779+
)
1780+
return
1781+
1782+
# The auto-cache needs to be updated. Sync with remote.
1783+
self.dbg(f'{project.name}: update auto-cache ({cache_dir}) with remote')
1784+
project.git(['remote', 'update', '--prune'], cwd=cache_dir, check=False)
17671785

17681786
def init_project(self, project):
17691787
# update() helper. Initialize an uncloned project repository.
@@ -2472,7 +2490,7 @@ def _maybe_sha(rev):
24722490
return len(rev) <= 40
24732491

24742492

2475-
def _rev_type(project, rev=None):
2493+
def _rev_type(project, rev=None, cwd=None):
24762494
# Returns a "refined" revision type of rev (default:
24772495
# project.revision) as one of the following strings: 'tag', 'tree',
24782496
# 'blob', 'commit', 'branch', 'other'.
@@ -2490,7 +2508,9 @@ def _rev_type(project, rev=None):
24902508
# update" specific logic.
24912509
if not rev:
24922510
rev = project.revision
2493-
cp = project.git(['cat-file', '-t', rev], check=False, capture_stdout=True, capture_stderr=True)
2511+
cp = project.git(
2512+
['cat-file', '-t', rev], cwd=cwd, check=False, capture_stdout=True, capture_stderr=True
2513+
)
24942514
stdout = cp.stdout.decode('utf-8').strip()
24952515
if cp.returncode:
24962516
return 'other'
@@ -2505,6 +2525,7 @@ def _rev_type(project, rev=None):
25052525
check=False,
25062526
capture_stdout=True,
25072527
capture_stderr=True,
2528+
cwd=cwd,
25082529
)
25092530
if cp.returncode:
25102531
# This can happen if the ref name is ambiguous, e.g.:

0 commit comments

Comments
 (0)