Skip to content

Commit 4273013

Browse files
dmachmcepl
authored andcommitted
Fix how GitStore reads project from the parent directory
1 parent 4e4c04e commit 4273013

File tree

2 files changed

+270
-77
lines changed

2 files changed

+270
-77
lines changed

osc/git_scm/store.py

Lines changed: 106 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -74,10 +74,7 @@ def get_build_project(git_repo_url: str):
7474
with tempfile.TemporaryDirectory(prefix="osc_devel_project_git") as tmp_dir:
7575
try:
7676
gitea_api.Repo.clone(gitea_conn, gitea_owner, gitea_repo, branch=gitea_branch, quiet=True, directory=tmp_dir)
77-
project_build_path = os.path.join(tmp_dir, "project.build")
78-
with open(project_build_path, "r", encoding="utf-8") as f:
79-
project_build = f.readline().strip()
80-
return project_build
77+
return GitStore(tmp_dir, check=False).project
8178
except gitea_api.GiteaException:
8279
# "_ObsPrj" repo doesn't exist
8380
return None
@@ -88,63 +85,85 @@ def get_build_project(git_repo_url: str):
8885
# "project.build" file doesn't exist
8986
return None
9087

91-
@property
92-
def git_project_dir(self):
93-
if not hasattr(self, "_git_project_dir"):
94-
self._git_project_dir = None
95-
path = self.abspath
96-
while path and path != "/":
97-
path, _ = os.path.split(path)
98-
99-
osc_path = os.path.join(path, ".osc")
100-
git_path = os.path.join(path, ".git")
101-
config_path = os.path.join(path, "_config")
102-
pbuild_path = os.path.join(path, "_pbuild")
103-
subdirs_path = os.path.join(path, "_subdirs")
104-
105-
if (os.path.isdir(osc_path) or os.path.isdir(git_path)) and (os.path.isfile(config_path) or os.path.isfile(pbuild_path)):
106-
if os.path.isfile(subdirs_path):
107-
# the _subdirs file contains a list of project subdirs that contain packages
108-
yaml = ruamel.yaml.YAML()
109-
with open(subdirs_path, "r") as f:
110-
data = yaml.load(f)
111-
112-
# ``subdirs`` is a list of directories, which have subdirectories which are packages
113-
subdirs = data.get("subdirs", [])
114-
115-
# if set to "include", then all top-level directories are packages in addition to ``subdirs``
116-
toplevel = data.get("toplevel", "")
117-
118-
if toplevel == "include":
119-
subdirs.append(".")
120-
121-
subdirs_abspath = [os.path.abspath(os.path.join(path, subdir)) for subdir in subdirs]
122-
123-
# paths listed in ``subdirs`` are never packages, their subdirs are
124-
if self.abspath in subdirs_abspath:
125-
break
126-
127-
# we're outside paths specified in subdirs -> not a package
128-
if os.path.abspath(os.path.join(self.abspath, "..")) not in subdirs_abspath:
129-
break
130-
else:
131-
# no _subdirs file and self.abspath is not directly under the project dir -> not a valid package
132-
if path != os.path.abspath(os.path.join(self.abspath, "..")):
133-
break
134-
135-
self._git_project_dir = path
136-
break
137-
return self._git_project_dir
88+
def get_project_obs_scm_store(self):
89+
from ..obs_scm import Store
90+
91+
if not self.is_package:
92+
return None
93+
94+
try:
95+
store = Store(os.path.join(self.abspath, ".."))
96+
store.assert_is_project()
97+
return store
98+
except oscerr.NoWorkingCopy:
99+
return None
100+
101+
def get_project_git_scm_store(self):
102+
if not self.is_package:
103+
return None
104+
105+
path = self.abspath
106+
while path:
107+
if path == "/":
108+
# no git repo found
109+
return None
110+
111+
path, _ = os.path.split(path)
112+
113+
if os.path.isdir(os.path.join(path, ".git")):
114+
break
115+
116+
config_path = os.path.join(path, "_config")
117+
pbuild_path = os.path.join(path, "_pbuild")
118+
subdirs_path = os.path.join(path, "_subdirs")
119+
120+
# we always stop at the top-most directory that contains .git subdir
121+
if not os.path.isfile(config_path) or os.path.isfile(pbuild_path):
122+
# it's not a project, stop traversing and return
123+
return None
124+
125+
if os.path.isfile(subdirs_path):
126+
# the _subdirs file contains a list of project subdirs that contain packages
127+
yaml = ruamel.yaml.YAML()
128+
with open(subdirs_path, "r") as f:
129+
data = yaml.load(f)
130+
131+
# ``subdirs`` is a list of directories, which have subdirectories which are packages
132+
subdirs = data.get("subdirs", [])
133+
134+
# if set to "include", then all top-level directories are packages in addition to ``subdirs``
135+
toplevel = data.get("toplevel", "")
136+
137+
if toplevel == "include":
138+
subdirs.append(".")
139+
140+
subdirs_abspath = [os.path.abspath(os.path.join(path, subdir)) for subdir in subdirs]
141+
142+
# paths listed in ``subdirs`` are never packages, their subdirs are
143+
if self.abspath in subdirs_abspath:
144+
return None
145+
146+
# we're outside paths specified in subdirs -> not a package
147+
if os.path.abspath(os.path.join(self.abspath, "..")) not in subdirs_abspath:
148+
return None
149+
else:
150+
# no _subdirs file and self.abspath is not directly under the project dir -> not a valid package
151+
if path != os.path.abspath(os.path.join(self.abspath, "..")):
152+
return None
153+
154+
return GitStore(path)
138155

139156
def __init__(self, path, check=True):
140157
self.path = path
141158
self.abspath = os.path.abspath(self.path)
142159

160+
self._apiurl = None
161+
self._package = None
162+
self._project = None
163+
143164
self.is_project = False
144165
self.is_package = False
145166

146-
self.project_obs_scm_store = None
147-
148167
if os.path.isdir(os.path.join(self.abspath, ".git")):
149168
# NOTE: we have only one store in project-git for all packages
150169
config_path = os.path.join(self.abspath, "_config")
@@ -155,16 +174,17 @@ def __init__(self, path, check=True):
155174
else:
156175
# there's .git and no _config/_pbuild in the working directory -> it's a package
157176
self.is_package = True
158-
elif self.git_project_dir:
159-
from ..obs_scm import Store
160177

161-
# there's no .git in the working directory and there's .osc, .git and _config/_pbuild in the parent directory tree -> it's a package
162-
self.is_package = True
163-
self.project_obs_scm_store = Store(self.git_project_dir, check=False)
178+
self.project_store = None
164179

165-
self._apiurl = None
166-
self._package = None
167-
self._project = None
180+
if self.project_store is None:
181+
self.project_store = self.get_project_obs_scm_store()
182+
183+
if self.project_store is None:
184+
self.project_store = self.get_project_git_scm_store()
185+
186+
if self.project_store:
187+
self.package = True
168188

169189
if check and not any([self.is_project, self.is_package]):
170190
msg = f"Directory '{self.path}' is not a Git SCM working copy"
@@ -193,9 +213,9 @@ def _run_git(self, args):
193213
@property
194214
def apiurl(self):
195215
if not self._apiurl:
196-
if self.is_package and self.project_obs_scm_store:
216+
if self.is_package and self.project_store:
197217
# read apiurl from parent directory that contains a project with .osc metadata
198-
self._apiurl = self.project_obs_scm_store.apiurl
218+
self._apiurl = self.project_store.apiurl
199219
if not self._apiurl:
200220
# HACK: use the currently configured apiurl
201221
self._apiurl = osc_conf.config["apiurl"]
@@ -208,16 +228,32 @@ def apiurl(self, value):
208228
@property
209229
def project(self):
210230
if not self._project:
211-
if self.is_package and self.project_obs_scm_store:
212-
# read project from parent directory that contains a project with .osc metadata
213-
self._project = self.project_obs_scm_store.project
214-
if not self._project:
215-
# read project from Gitea (identical owner, repo: _ObsPrj, file: project.build)
216-
origin = self._run_git(["remote", "get-url", "origin"])
217-
self._project = self.get_build_project(origin)
231+
if self.is_package:
232+
# handle _project in a package
233+
234+
if self.project_store:
235+
# read project from detected project store
236+
self._project = self.project_store.project
237+
238+
if not self._project:
239+
# read project from Gitea (identical owner, repo: _ObsPrj, file: project.build)
240+
origin = self._run_git(["remote", "get-url", "origin"])
241+
self._project = self.get_build_project(origin)
242+
243+
else:
244+
# handle _project in a project
245+
246+
if not self._project:
247+
# read project from "project.build" file
248+
path = os.path.join(self.abspath, "project.build")
249+
if os.path.exists(path):
250+
with open(path, "r", encoding="utf-8") as f:
251+
self._project = f.readline().strip()
252+
218253
if not self._project:
219254
# HACK: assume openSUSE:Factory project if project metadata is missing
220255
self._project = "openSUSE:Factory"
256+
221257
return self._project
222258

223259
@project.setter

0 commit comments

Comments
 (0)