summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorXavier Claessens <xavier.claessens@collabora.com>2020-10-10 10:45:34 -0400
committerNirbheek Chauhan <nirbheek.chauhan@gmail.com>2020-10-13 11:12:49 +0000
commitdccff1f2bcf6e7b8e42fa7bea63b8532ad29b43a (patch)
treeb82b3c81ab0b4faccc170dde067ff655dca07c40
parent3ade5bbd92b506f215f86a7d41048b22b287c673 (diff)
downloadmeson-dccff1f2bcf6e7b8e42fa7bea63b8532ad29b43a.tar.gz
msubprojects: Handle wrap-file to wrap-git case
-rw-r--r--docs/markdown/Subprojects.md3
-rw-r--r--docs/markdown/snippets/subprojects_update.md7
-rwxr-xr-xmesonbuild/msubprojects.py52
-rwxr-xr-xrun_unittests.py14
4 files changed, 57 insertions, 19 deletions
diff --git a/docs/markdown/Subprojects.md b/docs/markdown/Subprojects.md
index 446137355..7e17afa9f 100644
--- a/docs/markdown/Subprojects.md
+++ b/docs/markdown/Subprojects.md
@@ -315,6 +315,9 @@ To pull latest version of all your subprojects at once, just run the command:
- *Since 0.56.0* if the `url` specified in wrap file is different to the URL set
on `origin` for a git repository it will not be updated, unless `--reset` is
specified in which case the URL of `origin` will be reset first.
+- *Since 0.56.0* If the subproject directory is not a git repository but has a
+ `[wrap-git]` the subproject is ignored, unless `--reset` is specified in which
+ case the directory is deleted and the new repository is cloned.
### Start a topic branch across all git subprojects
diff --git a/docs/markdown/snippets/subprojects_update.md b/docs/markdown/snippets/subprojects_update.md
index f85a9ebcc..b5aa17cc5 100644
--- a/docs/markdown/snippets/subprojects_update.md
+++ b/docs/markdown/snippets/subprojects_update.md
@@ -19,13 +19,18 @@ subprojects, but at the end an error code is now returned.
The `update` subcommand has been reworked:
- In the case the URL of `origin` is different as the `url` set in wrap file,
the subproject will not be updated unless `--reset` is specified (see below).
+- In the case a subproject directory exists and is not a git repository but has
+ a `[wrap-git]`, meson used to run git commands that would wrongly apply to the
+ main project. It now skip the subproject unless `--reset` is specified (see below).
- The `--rebase` behaviour is now the default for consistency: it was
already rebasing when current branch and revision are the same, it is
less confusing to rebase when they are different too.
- Add `--reset` mode that checkout the new branch and hard reset that
branch to remote commit. This new mode guarantees that every
subproject are exactly at the wrap's revision. In addition the URL of `origin`
- is updated in case it changed in the wrap file.
+ is updated in case it changed in the wrap file. If the subproject directory is
+ not a git repository but has a `[wrap-git]` the directory is deleted and the
+ new repository is cloned.
- Local changes are always stashed first to avoid any data loss. In the
worst case scenario the user can always check reflog and stash list to
rollback.
diff --git a/mesonbuild/msubprojects.py b/mesonbuild/msubprojects.py
index 195410f4a..b628a47ca 100755
--- a/mesonbuild/msubprojects.py
+++ b/mesonbuild/msubprojects.py
@@ -3,7 +3,7 @@ import argparse
from ._pathlib import Path
from . import mlog
-from .mesonlib import quiet_git, verbose_git, GitException, Popen_safe, MesonException
+from .mesonlib import quiet_git, verbose_git, GitException, Popen_safe, MesonException, windows_proof_rmtree
from .wrap.wrap import API_ROOT, Resolver, WrapException, ALL_TYPES
from .wrap import wraptool
@@ -26,7 +26,7 @@ def update_wrapdb_file(wrap, repo_dir, options):
mlog.log(*msg)
return True
-def update_file(wrap, repo_dir, options):
+def update_file(r, wrap, repo_dir, options):
patch_url = wrap.values.get('patch_url', '')
if patch_url.startswith(API_ROOT):
return update_wrapdb_file(wrap, repo_dir, options)
@@ -116,10 +116,25 @@ def git_checkout_and_rebase(repo_dir, revision):
success = git_rebase(repo_dir, revision)
return success
-def update_git(wrap, repo_dir, options):
+def update_git(r, wrap, repo_dir, options):
if not os.path.isdir(repo_dir):
mlog.log(' -> Not used.')
return True
+ if not os.path.exists(os.path.join(repo_dir, '.git')):
+ if options.reset:
+ # Delete existing directory and redownload
+ windows_proof_rmtree(repo_dir)
+ try:
+ r.resolve(wrap.name, 'meson')
+ update_git_done(repo_dir)
+ return True
+ except WrapException as e:
+ mlog.log(' ->', mlog.red(str(e)))
+ return False
+ else:
+ mlog.log(' -> Not a git repository.')
+ mlog.log('Pass --reset option to delete directory and redownload.')
+ return False
revision = wrap.values.get('revision')
url = wrap.values.get('url')
push_url = wrap.values.get('push-url')
@@ -193,13 +208,15 @@ def update_git(wrap, repo_dir, options):
success = git_checkout_and_reset(repo_dir, revision)
else:
success = git_rebase(repo_dir, revision)
-
if success:
- git_output(['submodule', 'update', '--checkout', '--recursive'], repo_dir)
- git_show(repo_dir)
+ update_git_done(repo_dir)
return success
-def update_hg(wrap, repo_dir, options):
+def update_git_done(repo_dir):
+ git_output(['submodule', 'update', '--checkout', '--recursive'], repo_dir)
+ git_show(repo_dir)
+
+def update_hg(r, wrap, repo_dir, options):
if not os.path.isdir(repo_dir):
mlog.log(' -> Not used.')
return True
@@ -215,7 +232,7 @@ def update_hg(wrap, repo_dir, options):
subprocess.check_call(['hg', 'checkout', revno], cwd=repo_dir)
return True
-def update_svn(wrap, repo_dir, options):
+def update_svn(r, wrap, repo_dir, options):
if not os.path.isdir(repo_dir):
mlog.log(' -> Not used.')
return True
@@ -233,21 +250,21 @@ def update_svn(wrap, repo_dir, options):
subprocess.check_call(['svn', 'update', '-r', revno], cwd=repo_dir)
return True
-def update(wrap, repo_dir, options):
+def update(r, wrap, repo_dir, options):
mlog.log('Updating {}...'.format(wrap.name))
if wrap.type == 'file':
- return update_file(wrap, repo_dir, options)
+ return update_file(r, wrap, repo_dir, options)
elif wrap.type == 'git':
- return update_git(wrap, repo_dir, options)
+ return update_git(r, wrap, repo_dir, options)
elif wrap.type == 'hg':
- return update_hg(wrap, repo_dir, options)
+ return update_hg(r, wrap, repo_dir, options)
elif wrap.type == 'svn':
- return update_svn(wrap, repo_dir, options)
+ return update_svn(r, wrap, repo_dir, options)
else:
mlog.log(' -> Cannot update', wrap.type, 'subproject')
return True
-def checkout(wrap, repo_dir, options):
+def checkout(r, wrap, repo_dir, options):
if wrap.type != 'git' or not os.path.isdir(repo_dir):
return True
branch_name = options.branch_name if options.branch_name else wrap.get('revision')
@@ -260,13 +277,12 @@ def checkout(wrap, repo_dir, options):
return True
return False
-def download(wrap, repo_dir, options):
+def download(r, wrap, repo_dir, options):
mlog.log('Download {}...'.format(wrap.name))
if os.path.isdir(repo_dir):
mlog.log(' -> Already downloaded')
return True
try:
- r = Resolver(os.path.dirname(repo_dir))
r.resolve(wrap.name, 'meson')
mlog.log(' -> done')
except WrapException as e:
@@ -274,7 +290,7 @@ def download(wrap, repo_dir, options):
return False
return True
-def foreach(wrap, repo_dir, options):
+def foreach(r, wrap, repo_dir, options):
mlog.log('Executing command in {}'.format(repo_dir))
if not os.path.isdir(repo_dir):
mlog.log(' -> Not downloaded yet')
@@ -362,7 +378,7 @@ def run(options):
if types and wrap.type not in types:
continue
dirname = Path(subprojects_dir, wrap.directory).as_posix()
- if not options.subprojects_func(wrap, dirname, options):
+ if not options.subprojects_func(r, wrap, dirname, options):
failures.append(wrap.name)
if failures:
m = 'Please check logs above as command failed in some subprojects which could have been left in conflict state: '
diff --git a/run_unittests.py b/run_unittests.py
index 881b7811b..160173080 100755
--- a/run_unittests.py
+++ b/run_unittests.py
@@ -9151,6 +9151,20 @@ class SubprojectsCommandTests(BasePlatformTests):
self.assertEqual(self._git_local_branch(subp_name), '')
self.assertEqual(self._git_local_commit(subp_name), new_commit)
+ # Create a local project not in a git repository, then update it with
+ # a git wrap. Without --reset it should print error message and return
+ # failure. With --reset it should delete existing project and clone the
+ # new project.
+ subp_name = 'sub2'
+ self._create_project(self.subprojects_dir / subp_name)
+ self._git_create_remote_repo(subp_name)
+ self._wrap_create_git(subp_name)
+ with self.assertRaises(subprocess.CalledProcessError) as cm:
+ self._subprojects_cmd(['update'])
+ self.assertIn('Not a git repository', cm.exception.output)
+ self._subprojects_cmd(['update', '--reset'])
+ self.assertEqual(self._git_local_commit(subp_name), self._git_remote_commit(subp_name))
+
@skipIfNoExecutable('true')
def test_foreach(self):
self._create_project(self.subprojects_dir / 'sub_file')