diff --git a/fdroidserver/deploy.py b/fdroidserver/deploy.py index 848a2dc1..eeec69e8 100644 --- a/fdroidserver/deploy.py +++ b/fdroidserver/deploy.py @@ -33,6 +33,7 @@ import logging from shlex import split import shutil import git +from pathlib import Path from . import _ from . import common @@ -632,10 +633,11 @@ def update_servergitmirrors(servergitmirrors, repo_section): return options = common.get_options() + working_dir_root = Path(os.getcwd()) # right now we support only 'repo' git-mirroring if repo_section == 'repo': - git_mirror_path = 'git-mirror' + git_mirror_path = working_dir_root / 'git-mirror' dotgit = os.path.join(git_mirror_path, '.git') git_fdroiddir = os.path.join(git_mirror_path, 'fdroid') git_repodir = os.path.join(git_fdroiddir, repo_section) @@ -662,12 +664,6 @@ def update_servergitmirrors(servergitmirrors, repo_section): archive_path = os.path.join(git_mirror_path, 'fdroid', 'archive') shutil.rmtree(archive_path, ignore_errors=True) - # trailing slashes have a meaning in rsync which is not needed here, so - # make sure both paths have exactly one trailing slash - common.local_rsync(common.get_options(), - [repo_section.rstrip('/') + '/'], - git_repodir.rstrip('/') + '/') - # use custom SSH command if identity_file specified ssh_cmd = 'ssh -oBatchMode=yes' if options.identity_file is not None: @@ -692,18 +688,23 @@ def update_servergitmirrors(servergitmirrors, repo_section): enabled_remotes = [] for d in servergitmirrors: + # trailing slashes have a meaning in rsync which is not needed here, so + # make sure both paths have exactly one trailing slash + common.local_rsync(common.get_options(), + [str(working_dir_root / repo_section).rstrip('/') + '/'], + git_repodir.rstrip('/') + '/') + upload_to_servergitmirror(mirror_config=d, local_repo=repo, enabled_remotes=enabled_remotes, repo_section=repo_section, fdroid_dir=git_fdroiddir, - git_mirror_path=git_mirror_path, + git_mirror_path=str(git_mirror_path), ssh_cmd=ssh_cmd, progress=progress) - # Switch to the initial branch and unstage all files + # Switch to the initial branch repo.head.reference = initial_ref - repo.head.reset(index=True, working_tree=False) if progress: progressbar.done() @@ -729,9 +730,7 @@ def upload_to_servergitmirror(mirror_config: Dict[str, str], local_branch_name = 'index_only' else: local_branch_name = 'full' - if local_branch_name not in local_repo.heads: - local_repo.create_head(local_branch_name) - local_repo.head.reference = local_repo.heads[local_branch_name] + local_repo.git.switch('-c', local_branch_name) remote_branch_name = GIT_BRANCH remote_url = mirror_config['url'] diff --git a/tests/deploy.TestCase b/tests/deploy.TestCase index 2df20aae..9baaf5dc 100755 --- a/tests/deploy.TestCase +++ b/tests/deploy.TestCase @@ -909,50 +909,44 @@ class DeployTest(unittest.TestCase): config = {} fdroidserver.common.fill_config_defaults(config) fdroidserver.deploy.config = config - fdroidserver.deploy.config["servergitmirrors"] = [] + + os.chdir(self.testdir) repo_section = 'repo' + initial_branch = fdroidserver.deploy.GIT_BRANCH - # setup function for asserting subprocess.call invocations - call_iteration = 0 + remote_repo = Path(self.testdir) / 'remote' + remote_repo.mkdir(parents=True) + remote_git_repo = git.Repo.init( + remote_repo, initial_branch=initial_branch, bare=True + ) + fdroidserver.deploy.config["servergitmirrors"] = [{"url": str(remote_repo)}] os.chdir(self.testdir) repo = Path('repo') repo.mkdir(parents=True) - fake_apk = repo / 'Sym.apk' - with fake_apk.open('w') as fp: - fp.write('not an APK, but has the right filename') - fake_index = repo / fdroidserver.deploy.INDEX_FILES[0] - with fake_index.open('w') as fp: - fp.write('not an index, but has the right filename') + files_in_repo = fdroidserver.deploy.INDEX_FILES + ['Sym.apk'] + for filename in files_in_repo: + fake_file = repo / filename + with fake_file.open('w') as fp: + fp.write('not a real one, but has the right filename') - def update_servergitmirrors_call(cmd): - nonlocal call_iteration - if call_iteration == 0: - self.assertListEqual( - cmd, - [ - 'rsync', - '--recursive', - '--safe-links', - '--times', - '--perms', - '--one-file-system', - '--delete', - '--chmod=Da+rx,Fa-x,a+r,u+w', - '--quiet', - 'repo/', - "git-mirror/fdroid/repo/", - ], + fdroidserver.deploy.update_servergitmirrors( + fdroidserver.deploy.config["servergitmirrors"], repo_section + ) + + verify_repo = remote_git_repo.clone( + Path(self.testdir) / 'verify', + ) + + for filename in files_in_repo: + remote_file = f"fdroid/{repo_section}/{filename}" + + self.assertIsNotNone(verify_repo.working_tree_dir) + if verify_repo.working_tree_dir is not None: + self.assertTrue( + (Path(verify_repo.working_tree_dir) / remote_file).exists() ) - else: - self.fail('unexpected subprocess.call invocation') - call_iteration += 1 - return 0 - - with mock.patch('subprocess.call', side_effect=update_servergitmirrors_call): - fdroidserver.deploy.update_servergitmirrors([], repo_section) - self.assertEqual(call_iteration, 1, 'expected 1 invocations of subprocess.call') def test_update_servergitmirrors_in_index_only_mode(self): # setup parameters for this test run @@ -965,50 +959,46 @@ class DeployTest(unittest.TestCase): config = {} fdroidserver.common.fill_config_defaults(config) fdroidserver.deploy.config = config - fdroidserver.deploy.config["servergitmirrors"] = [] + + os.chdir(self.testdir) repo_section = 'repo' + initial_branch = fdroidserver.deploy.GIT_BRANCH - # setup function for asserting subprocess.call invocations - call_iteration = 0 + remote_repo = Path(self.testdir) / 'remote' + remote_repo.mkdir(parents=True) + remote_git_repo = git.Repo.init( + remote_repo, initial_branch=initial_branch, bare=True + ) + fdroidserver.deploy.config["servergitmirrors"] = [ + {"url": str(remote_repo), "index_only": True} + ] os.chdir(self.testdir) repo = Path('repo') repo.mkdir(parents=True) - fake_apk = repo / 'Sym.apk' - with fake_apk.open('w') as fp: - fp.write('not an APK, but has the right filename') - fake_index = repo / fdroidserver.deploy.INDEX_FILES[0] - with fake_index.open('w') as fp: - fp.write('not an index, but has the right filename') + files_in_repo = fdroidserver.deploy.INDEX_FILES + for filename in files_in_repo: + fake_file = repo / filename + with fake_file.open('w') as fp: + fp.write('not a real one, but has the right filename') - def update_servergitmirrors_call(cmd): - nonlocal call_iteration - if call_iteration == 0: - self.assertListEqual( - cmd, - [ - 'rsync', - '--recursive', - '--safe-links', - '--times', - '--perms', - '--one-file-system', - '--delete', - '--chmod=Da+rx,Fa-x,a+r,u+w', - '--quiet', - 'repo/', - "git-mirror/fdroid/repo/", - ], + fdroidserver.deploy.update_servergitmirrors( + fdroidserver.deploy.config["servergitmirrors"], repo_section + ) + + verify_repo = remote_git_repo.clone( + Path(self.testdir) / 'verify', + ) + + for filename in files_in_repo: + remote_file = f"fdroid/{repo_section}/{filename}" + + self.assertIsNotNone(verify_repo.working_tree_dir) + if verify_repo.working_tree_dir is not None: + self.assertTrue( + (Path(verify_repo.working_tree_dir) / remote_file).exists() ) - else: - self.fail('unexpected subprocess.call invocation') - call_iteration += 1 - return 0 - - with mock.patch('subprocess.call', side_effect=update_servergitmirrors_call): - fdroidserver.deploy.update_servergitmirrors([], repo_section) - self.assertEqual(call_iteration, 1, 'expected 1 invocations of subprocess.call') def test_upload_to_servergitmirror_in_index_only_mode(self): # setup parameters for this test run @@ -1032,8 +1022,6 @@ class DeployTest(unittest.TestCase): local_git_repo = git.Repo.init( local_git_repo_path, initial_branch=initial_branch ) - # An initial commit of the git tree is required be for other operations - local_git_repo.index.commit('Initial commit') fdroid_dir = local_git_repo_path / 'fdroid' repo_dir = fdroid_dir / repo_section