BlenderBIM Git clone repository operator (#3096)

This commit is contained in:
Bruno Postle
2023-05-14 21:10:53 +01:00
parent 5874508263
commit 7ca6f9d7a1
6 changed files with 94 additions and 15 deletions
@@ -22,6 +22,7 @@ from . import ui, prop, operator
classes = (
operator.AddFileToRepo,
operator.AddTag,
operator.CloneRepo,
operator.CommitChanges,
operator.CreateRepo,
operator.DiscardUncommitted,
@@ -57,6 +57,33 @@ class AddFileToRepo(bpy.types.Operator):
return {"FINISHED"}
class CloneRepo(bpy.types.Operator):
"""Clone a remote Git repository"""
bl_label = "Clone repository"
bl_idname = "ifcgit.clone_repo"
bl_options = {"REGISTER"}
@classmethod
def poll(cls, context):
props = context.scene.IfcGitProperties
if (
props.remote_url
and props.local_folder
and os.path.isdir(props.local_folder)
and not os.listdir(props.local_folder)
):
return True
return False
def execute(self, context):
props = context.scene.IfcGitProperties
core.clone_repo(tool.IfcGit, props.remote_url, props.local_folder, self)
refresh()
return {"FINISHED"}
class DiscardUncommitted(bpy.types.Operator):
"""Discard saved changes and update to HEAD"""
@@ -97,6 +97,17 @@ class IfcGitProperties(PropertyGroup):
description="An optional human readable description of this tag",
default="",
)
remote_url: StringProperty(
name="Git URL",
description="A URL pointing to a Git repository",
default="",
)
local_folder: StringProperty(
name="Local folder",
description="A local Git repository path",
default="",
subtype="DIR_PATH",
)
display_branch: EnumProperty(items=git_branches, update=update_revlist)
ifcgit_filter: EnumProperty(
items=[
@@ -54,6 +54,16 @@ class IFCGIT_PT_panel(bpy.types.Panel):
else:
row.label(text="No Git repository found", icon="SYSTEM")
row.label(text="No IFC project saved", icon="FILE")
box = layout.box()
row = box.row()
row.label(text="Clone a remote Git repository")
row = box.row()
row.prop(props, "remote_url")
row = box.row()
row.prop(props, "local_folder")
row = box.row()
row.operator("ifcgit.clone_repo", icon="IMPORT")
return
is_dirty = IfcGitData.data["is_dirty"]
+11 -4
View File
@@ -10,6 +10,15 @@ def add_file(ifcgit, ifc):
ifcgit.add_file_to_repo(repo, path_ifc)
def clone_repo(ifcgit, remote_url, local_folder, operator):
repo = ifcgit.clone_repo(remote_url, local_folder)
if not repo:
operator.report({"ERROR"}, "Clone failed")
return
operator.report({"INFO"}, "Repository cloned")
ifcgit.load_anyifc(repo)
def discard_uncomitted(ifcgit, ifc):
path_ifc = ifc.get_path()
# NOTE this is calling the git binary in a subprocess
@@ -30,10 +39,7 @@ def add_tag(ifcgit, repo):
def refresh_revision_list(ifcgit, repo, ifc):
ifcgit.clear_commits_list()
path_ifc = ifc.get_path()
lookup = ifcgit.tags_by_hexsha(repo)
ifcgit.get_commits_list(path_ifc, lookup)
ifcgit.refresh_revision_list(ifc.get_path())
def colourise_revision(ifcgit, context):
@@ -58,6 +64,7 @@ def switch_revision(ifcgit, ifc):
path_ifc = ifc.get_path()
ifcgit.switch_to_revision_item()
ifcgit.load_project(path_ifc)
ifcgit.refresh_revision_list(path_ifc)
def merge_branch(ifcgit, ifc, operator):
+34 -11
View File
@@ -14,6 +14,21 @@ class IfcGit:
def init_repo(cls, path_dir):
IfcGitRepo.repo = git.Repo.init(path_dir)
@classmethod
def clone_repo(cls, remote_url, local_folder):
IfcGitRepo.repo = git.Repo.clone_from(remote_url, local_folder)
return IfcGitRepo.repo
@classmethod
def load_anyifc(cls, repo):
working_dir = repo.working_dir
for item in os.listdir(working_dir):
path = os.path.join(working_dir, item)
if os.path.isfile(path) and re.match(".*\.ifc$", path, re.IGNORECASE):
cls.load_project(path)
return True
return False
@classmethod
def get_path_dir(cls, path_ifc):
return os.path.abspath(os.path.dirname(path_ifc))
@@ -39,7 +54,7 @@ class IfcGit:
if parentdir_path == path_dir:
# root folder
return None
return IfcGit.repo_from_path(parentdir_path)
return cls.repo_from_path(parentdir_path)
if repo:
IfcGitRepo.repo = repo
return repo
@@ -94,15 +109,16 @@ class IfcGit:
def get_commits_list(cls, path_ifc, lookup):
props = bpy.context.scene.IfcGitProperties
repo = cls.repo_from_path(path_ifc)
commits = list(
git.objects.commit.Commit.iter_items(
repo=IfcGitRepo.repo,
repo=repo,
rev=[props.display_branch],
)
)
commits_relevant = list(
git.objects.commit.Commit.iter_items(
repo=IfcGitRepo.repo,
repo=repo,
rev=[props.display_branch],
paths=[path_ifc],
)
@@ -131,6 +147,13 @@ class IfcGit:
# a lightweight tag has no message
list_item.tags[-1].message = tag.tag.message
@classmethod
def refresh_revision_list(cls, path_ifc):
repo = cls.repo_from_path(path_ifc)
cls.clear_commits_list()
lookup = cls.tags_by_hexsha(repo)
cls.get_commits_list(path_ifc, lookup)
@classmethod
def is_valid_ref_format(cls, string):
"""Check a bare branch or tag name is valid"""
@@ -148,7 +171,7 @@ class IfcGit:
# delete any IfcProject/* collections
for collection in bpy.data.collections:
if re.match("^IfcProject/", collection.name):
IfcGit.delete_collection(collection)
cls.delete_collection(collection)
# delete any Ifc* objects not in IfcProject/ heirarchy
for obj in bpy.data.objects:
if re.match("^Ifc", obj.name):
@@ -157,7 +180,6 @@ class IfcGit:
bpy.data.orphans_purge(do_recursive=True)
bpy.ops.bim.load_project(filepath=path_ifc)
bpy.ops.ifcgit.refresh()
@classmethod
def branches_by_hexsha(cls, repo):
@@ -230,14 +252,14 @@ class IfcGit:
return
if current_revision.committed_date > selected_revision.committed_date:
step_ids = IfcGit.ifc_diff_ids(
step_ids = cls.ifc_diff_ids(
repo,
selected_revision.hexsha,
current_revision.hexsha,
path_ifc,
)
else:
step_ids = IfcGit.ifc_diff_ids(
step_ids = cls.ifc_diff_ids(
repo,
current_revision.hexsha,
selected_revision.hexsha,
@@ -290,7 +312,7 @@ class IfcGit:
repo = IfcGitRepo.repo
item = props.ifcgit_commits[props.commit_index]
lookup = IfcGit.branches_by_hexsha(repo)
lookup = cls.branches_by_hexsha(repo)
if item.hexsha in lookup:
for branch in lookup[item.hexsha]:
if branch.name == props.display_branch:
@@ -308,7 +330,7 @@ class IfcGit:
@classmethod
def is_valid_branch_name(cls, new_branch_name):
"""Check if a branch name is valid and doesn't conflict with existing branches"""
if not IfcGit.is_valid_ref_format(new_branch_name):
if not cls.is_valid_ref_format(new_branch_name):
return False
if new_branch_name in [branch.name for branch in IfcGitRepo.repo.branches]:
return False
@@ -328,7 +350,7 @@ class IfcGit:
props = bpy.context.scene.IfcGitProperties
repo = IfcGitRepo.repo
item = props.ifcgit_commits[props.commit_index]
lookup = IfcGit.branches_by_hexsha(repo)
lookup = cls.branches_by_hexsha(repo)
if item.hexsha in lookup:
for branch in lookup[item.hexsha]:
if branch.name == props.display_branch:
@@ -356,7 +378,8 @@ class IfcGit:
props.commit_message = "Merged branch: " + props.display_branch
props.display_branch = repo.active_branch.name
IfcGit.load_project(path_ifc)
cls.load_project(path_ifc)
cls.refresh_revision_list(path_ifc)
class IfcGitRepo: