mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-11 02:02:22 +00:00
BlenderBIM Git clone repository operator (#3096)
This commit is contained in:
@@ -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"]
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user