Add repository list to package panel
Actually adding multiple repositories is disallowed for now
This commit is contained in:
@@ -75,7 +75,7 @@ class SubprocMixin:
|
|||||||
|
|
||||||
def quit(self):
|
def quit(self):
|
||||||
"""Signals the state machine to stop this operator from running."""
|
"""Signals the state machine to stop this operator from running."""
|
||||||
|
self.cancel(bpy.context)
|
||||||
self._state = 'QUIT'
|
self._state = 'QUIT'
|
||||||
|
|
||||||
def invoke(self, context, event):
|
def invoke(self, context, event):
|
||||||
@@ -87,6 +87,7 @@ class SubprocMixin:
|
|||||||
|
|
||||||
# The subprocess should just be terminated when Blender quits. Without this,
|
# The subprocess should just be terminated when Blender quits. Without this,
|
||||||
# Blender would hang while closing, until the subprocess terminates itself.
|
# Blender would hang while closing, until the subprocess terminates itself.
|
||||||
|
# TODO: Perhaps it would be better to fork when blender exits?
|
||||||
self.process = self.create_subprocess()
|
self.process = self.create_subprocess()
|
||||||
self.process.daemon = True
|
self.process.daemon = True
|
||||||
self.process.start()
|
self.process.start()
|
||||||
@@ -364,7 +365,19 @@ class PACKAGE_OT_refresh_repositories(SubprocMixin, bpy.types.Operator):
|
|||||||
bl_description = 'Check repositories for new and updated packages'
|
bl_description = 'Check repositories for new and updated packages'
|
||||||
bl_options = {'REGISTER'}
|
bl_options = {'REGISTER'}
|
||||||
|
|
||||||
log = logging.getLogger(__name__ + ".PACKAGE_OT_refresh")
|
log = logging.getLogger(__name__ + ".PACKAGE_OT_refresh_repositories")
|
||||||
|
_running = False
|
||||||
|
|
||||||
|
def invoke(self, context, event):
|
||||||
|
PACKAGE_OT_refresh_repositories._running = True
|
||||||
|
return super().invoke(context, event)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def poll(cls, context):
|
||||||
|
return not cls._running
|
||||||
|
|
||||||
|
def cancel(self, context):
|
||||||
|
PACKAGE_OT_refresh_repositories._running = False
|
||||||
|
|
||||||
def create_subprocess(self):
|
def create_subprocess(self):
|
||||||
"""Starts the download process.
|
"""Starts the download process.
|
||||||
@@ -389,17 +402,7 @@ class PACKAGE_OT_refresh_repositories(SubprocMixin, bpy.types.Operator):
|
|||||||
import pathlib
|
import pathlib
|
||||||
|
|
||||||
storage_path = pathlib.Path(bpy.utils.user_resource('CONFIG', 'packages', create=True))
|
storage_path = pathlib.Path(bpy.utils.user_resource('CONFIG', 'packages', create=True))
|
||||||
repository_url = bpy.context.user_preferences.addons[__package__].preferences.repository_url
|
repository_url = bpy.context.user_preferences.addons[__package__].preferences.repositories[0].url
|
||||||
|
|
||||||
from urllib.parse import urlsplit, urlunsplit
|
|
||||||
|
|
||||||
parsed_url = urlsplit(repository_url)
|
|
||||||
if not parsed_url.path.endswith("repo.json"):
|
|
||||||
if parsed_url.path.endswith('/'):
|
|
||||||
new_path = parsed_url.path + "repo.json"
|
|
||||||
else:
|
|
||||||
new_path = parsed_url.path + "/repo.json"
|
|
||||||
repository_url = urlunsplit((parsed_url.scheme, parsed_url.netloc, new_path, parsed_url.query, parsed_url.fragment))
|
|
||||||
|
|
||||||
proc = multiprocessing.Process(target=subproc.refresh,
|
proc = multiprocessing.Process(target=subproc.refresh,
|
||||||
args=(self.pipe_subproc, storage_path, repository_url))
|
args=(self.pipe_subproc, storage_path, repository_url))
|
||||||
@@ -518,6 +521,63 @@ class PACKAGE_OT_load_repositories(SubprocMixin, bpy.types.Operator):
|
|||||||
self.log.error('Process died without telling us! Exit code was 0 though')
|
self.log.error('Process died without telling us! Exit code was 0 though')
|
||||||
self.report({'WARNING'}, 'Error downloading package, but process finished OK. This is weird.')
|
self.report({'WARNING'}, 'Error downloading package, but process finished OK. This is weird.')
|
||||||
|
|
||||||
|
class RepositoryProperty(bpy.types.PropertyGroup):
|
||||||
|
url = bpy.props.StringProperty(name="URL")
|
||||||
|
status = bpy.props.EnumProperty(name="Status", items=[
|
||||||
|
("OK", "Okay", "FILE_TICK"),
|
||||||
|
("NOTFOUND", "Not found", "ERROR"),
|
||||||
|
("NOCONNECT", "Could not connect", "QUESTION"),
|
||||||
|
])
|
||||||
|
|
||||||
|
class PACKAGE_UL_repositories(bpy.types.UIList):
|
||||||
|
def draw_item(self, context, layout, data, item, icon, active_data, active_propname):
|
||||||
|
layout.alignment='LEFT'
|
||||||
|
if len(item.name) == 0:
|
||||||
|
layout.label(item['url'])
|
||||||
|
else:
|
||||||
|
layout.label(item.name)
|
||||||
|
|
||||||
|
def parse_repository_url(url: str) -> str:
|
||||||
|
"""Sanitize repository url"""
|
||||||
|
from urllib.parse import urlsplit, urlunsplit
|
||||||
|
parsed_url = urlsplit(url)
|
||||||
|
new_path = parsed_url.path.rstrip("repo.json")
|
||||||
|
return urlunsplit((parsed_url.scheme, parsed_url.netloc, new_path, parsed_url.query, parsed_url.fragment))
|
||||||
|
|
||||||
|
class PACKAGE_OT_add_repository(bpy.types.Operator):
|
||||||
|
bl_idname = "package.add_repository"
|
||||||
|
bl_label = "Add Repository"
|
||||||
|
|
||||||
|
url = bpy.props.StringProperty(name="Repository URL")
|
||||||
|
|
||||||
|
def invoke(self, context, event):
|
||||||
|
wm = context.window_manager
|
||||||
|
return wm.invoke_props_dialog(self)
|
||||||
|
|
||||||
|
def execute(self, context):
|
||||||
|
prefs = context.user_preferences.addons[__package__].preferences
|
||||||
|
if len(prefs.repositories) > 0:
|
||||||
|
self.report({'ERROR'}, "Only one repository at a time is currently supported")
|
||||||
|
return {'CANCELLED'}
|
||||||
|
|
||||||
|
if len(self.url) == 0:
|
||||||
|
self.report({'ERROR'}, "Repository URL not specified")
|
||||||
|
return {'CANCELLED'}
|
||||||
|
|
||||||
|
repo = prefs.repositories.add()
|
||||||
|
repo.url = parse_repository_url(self.url)
|
||||||
|
|
||||||
|
context.area.tag_redraw()
|
||||||
|
return {'FINISHED'}
|
||||||
|
|
||||||
|
class PACKAGE_OT_remove_repository(bpy.types.Operator):
|
||||||
|
bl_idname = "package.remove_repository"
|
||||||
|
bl_label = "Remove Repository"
|
||||||
|
|
||||||
|
def execute(self, context):
|
||||||
|
prefs = context.user_preferences.addons[__package__].preferences
|
||||||
|
prefs.repositories.remove(prefs.active_repository)
|
||||||
|
return {'FINISHED'}
|
||||||
|
|
||||||
class USERPREF_PT_packages(bpy.types.Panel):
|
class USERPREF_PT_packages(bpy.types.Panel):
|
||||||
bl_label = "Package Management"
|
bl_label = "Package Management"
|
||||||
@@ -539,12 +599,25 @@ class USERPREF_PT_packages(bpy.types.Panel):
|
|||||||
def draw(self, context):
|
def draw(self, context):
|
||||||
layout = self.layout
|
layout = self.layout
|
||||||
wm = context.window_manager
|
wm = context.window_manager
|
||||||
|
prefs = context.user_preferences.addons[__package__].preferences
|
||||||
|
|
||||||
main = layout.row()
|
main = layout.row()
|
||||||
spl = main.split(.12)
|
spl = main.split(.22)
|
||||||
sidebar = spl.column(align=True)
|
sidebar = spl.column(align=True)
|
||||||
pkgzone = spl.column()
|
pkgzone = spl.column()
|
||||||
|
|
||||||
|
sidebar.label("Repositories")
|
||||||
|
|
||||||
|
row = sidebar.row()
|
||||||
|
row.template_list("PACKAGE_UL_repositories", "", prefs, "repositories", prefs, "active_repository")
|
||||||
|
col = row.column(align=True)
|
||||||
|
col.operator(PACKAGE_OT_add_repository.bl_idname, text="", icon='ZOOMIN')
|
||||||
|
col.operator(PACKAGE_OT_remove_repository.bl_idname, text="", icon='ZOOMOUT')
|
||||||
|
|
||||||
|
sidebar.separator()
|
||||||
|
sidebar.operator(PACKAGE_OT_refresh_repositories.bl_idname)
|
||||||
|
|
||||||
|
sidebar.separator()
|
||||||
sidebar.label(text="Category")
|
sidebar.label(text="Category")
|
||||||
sidebar.prop(wm, "addon_filter", text="")
|
sidebar.prop(wm, "addon_filter", text="")
|
||||||
|
|
||||||
@@ -800,6 +873,12 @@ class PackageManagerPreferences(bpy.types.AddonPreferences):
|
|||||||
name='Repository URL',
|
name='Repository URL',
|
||||||
description='Temporary repository URL')
|
description='Temporary repository URL')
|
||||||
|
|
||||||
|
repositories = bpy.props.CollectionProperty(
|
||||||
|
type=RepositoryProperty,
|
||||||
|
name="Repositories",
|
||||||
|
)
|
||||||
|
active_repository = bpy.props.IntProperty()
|
||||||
|
|
||||||
def draw(self, context):
|
def draw(self, context):
|
||||||
layout = self.layout
|
layout = self.layout
|
||||||
|
|
||||||
@@ -869,6 +948,12 @@ def register():
|
|||||||
name="Install filter",
|
name="Install filter",
|
||||||
default='AVAILABLE',
|
default='AVAILABLE',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
bpy.utils.register_class(RepositoryProperty)
|
||||||
|
bpy.utils.register_class(PACKAGE_OT_add_repository)
|
||||||
|
bpy.utils.register_class(PACKAGE_OT_remove_repository)
|
||||||
|
bpy.utils.register_class(PACKAGE_UL_repositories)
|
||||||
|
|
||||||
bpy.utils.register_class(PackageManagerPreferences)
|
bpy.utils.register_class(PackageManagerPreferences)
|
||||||
|
|
||||||
|
|
||||||
@@ -883,4 +968,10 @@ def unregister():
|
|||||||
bpy.utils.unregister_class(WM_OT_package_toggle_expand)
|
bpy.utils.unregister_class(WM_OT_package_toggle_expand)
|
||||||
del bpy.types.WindowManager.package_search
|
del bpy.types.WindowManager.package_search
|
||||||
del bpy.types.WindowManager.package_install_filter
|
del bpy.types.WindowManager.package_install_filter
|
||||||
|
|
||||||
|
bpy.utils.unregister_class(RepositoryProperty)
|
||||||
|
bpy.utils.unregister_class(PACKAGE_OT_add_repository)
|
||||||
|
bpy.utils.unregister_class(PACKAGE_OT_remove_repository)
|
||||||
|
bpy.utils.unregister_class(PACKAGE_UL_repositories)
|
||||||
|
|
||||||
bpy.utils.unregister_class(PackageManagerPreferences)
|
bpy.utils.unregister_class(PackageManagerPreferences)
|
||||||
|
Reference in New Issue
Block a user