1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
|
--- a/src/aerie/sync.py
+++ b/src/aerie/sync.py
@@ -54,6 +54,10 @@ def clone_repo(repo: RepoConfig, release: str) -> None:
run(["git", "clone", "--branch", release, repo.sync_uri, str(repo.location)])
+def is_empty_dir(path: Path) -> bool:
+ return path.is_dir() and not any(path.iterdir())
+
+
def update_repo(repo: RepoConfig, release: str) -> None:
ensure_clean_git_tree(repo.location)
run(["git", "-C", str(repo.location), "fetch", "--prune", "origin"])
@@ -70,6 +74,9 @@ def sync_repo(repo: RepoConfig, release: str) -> None:
clone_repo(repo, release)
return
if not (repo.location / ".git").exists():
+ if is_empty_dir(repo.location):
+ clone_repo(repo, release)
+ return
raise AerieError(f"{repo.location} exists but is not a git repository")
update_repo(repo, release)
--- /dev/null
+++ b/tests/test_sync.py
@@ -0,0 +1,95 @@
+from contextlib import redirect_stdout
+from io import StringIO
+from pathlib import Path
+from tempfile import TemporaryDirectory
+import unittest
+from unittest.mock import patch
+
+from aerie.config import AerieError, ProgramConfig, RepoConfig
+from aerie.sync import sync_all, sync_repo
+
+
+def repo_config(location: Path) -> RepoConfig:
+ return RepoConfig(
+ name="srcux",
+ main_repo="srcux",
+ location=location,
+ auto_sync=True,
+ sync_type="git",
+ sync_uri="https://example.test/repo.git",
+ priority="1",
+ )
+
+
+class SyncTests(unittest.TestCase):
+ def test_sync_repo_clones_into_empty_existing_directory(self):
+ with TemporaryDirectory() as tmp:
+ location = Path(tmp) / "baldeagleos"
+ location.mkdir()
+ repo = repo_config(location)
+
+ with redirect_stdout(StringIO()), patch("aerie.sync.run") as run:
+ sync_repo(repo, "develop")
+
+ run.assert_called_once_with(
+ [
+ "git",
+ "clone",
+ "--branch",
+ "develop",
+ "https://example.test/repo.git",
+ str(location),
+ ]
+ )
+
+ def test_sync_repo_rejects_non_empty_non_git_directory(self):
+ with TemporaryDirectory() as tmp:
+ location = Path(tmp) / "baldeagleos"
+ location.mkdir()
+ (location / "README").write_text("not a git checkout\n", encoding="utf-8")
+ repo = repo_config(location)
+
+ with redirect_stdout(StringIO()), patch("aerie.sync.run") as run:
+ with self.assertRaisesRegex(AerieError, "exists but is not a git repository"):
+ sync_repo(repo, "develop")
+
+ run.assert_not_called()
+
+ def test_sync_all_clones_repo_location_created_by_path_check(self):
+ with TemporaryDirectory() as tmp:
+ tmp_path = Path(tmp)
+ location = tmp_path / "repos" / "baldeagleos"
+ repos_conf = tmp_path / "baldeagleos.conf"
+ repos_conf.write_text(
+ f"""
+[DEFAULT]
+main-repo = srcux
+
+[srcux]
+location = {location}
+auto-sync = yes
+sync-type = git
+sync-uri = https://example.test/repo.git
+priority = 1
+""",
+ encoding="utf-8",
+ )
+ config = ProgramConfig(release="develop", reposconfpath=repos_conf)
+
+ with redirect_stdout(StringIO()), patch("aerie.sync.run") as run:
+ sync_all(config)
+
+ run.assert_called_once_with(
+ [
+ "git",
+ "clone",
+ "--branch",
+ "develop",
+ "https://example.test/repo.git",
+ str(location),
+ ]
+ )
+
+
+if __name__ == "__main__":
+ unittest.main()
|