diff --git a/package_manager/__init__.py b/package_manager/__init__.py index 4352674..5c9ca5c 100644 --- a/package_manager/__init__.py +++ b/package_manager/__init__.py @@ -56,8 +56,8 @@ class PackageManagerAddon(bpy.types.PropertyGroup): blender = StringProperty() warning = StringProperty() support = StringProperty() - filename = StringProperty() module_name = StringProperty() + download_url = StringProperty() class PackageManagerPreferences(AddonPreferences): # this must match the addon name, use '__package__' @@ -81,18 +81,17 @@ class PackageManagerPreferences(AddonPreferences): # Display selected add-on addon = self.pm_addons[self.pm_addons_index] - installed = False - for module in addon_utils.modules(): - if module.__name__ == addon.module_name: - installed = True - break + installed = any(module.__name__ == addon.module_name for module in addon_utils.modules()) col_box = layout.column() box = col_box.box() colsub = box.column() split = colsub.row().split(percentage=0.25) - split.label(text="Installed: %s" % ("Yes" if installed else "No")) + if installed and addon.version is not None: + split.label(text="Installed: Yes, v%s" % addon.version) + else: + split.label(text="Installed: No") split.separator() split.separator() split.operator("wm.addon_download_install", diff --git a/package_manager/networking.py b/package_manager/networking.py index 73656b3..5e5feac 100644 --- a/package_manager/networking.py +++ b/package_manager/networking.py @@ -18,15 +18,18 @@ import bpy import addon_utils import json -import urllib.request import logging +import os import shutil +import urllib.request +import zipfile from bpy.props import StringProperty -logging.basicConfig(format='%(asctime)-15s %(levelname)8s %(name)s %(message)s', - level=logging.INFO) log = logging.getLogger('networking') +INDEX_DOWNLOAD_URL = ("https://git.blender.org/gitweb/gitweb.cgi/" + "blender-package-manager-addon.git/blob_plain/HEAD:/addons/index.json") + class WM_OT_update_index(bpy.types.Operator): """Check for updated list of add-ons available for download""" bl_idname = "wm.update_index" @@ -35,13 +38,11 @@ class WM_OT_update_index(bpy.types.Operator): def execute(self, context): # Download the index.json file try: - req = urllib.request.urlopen("https://git.blender.org/gitweb/gitweb.cgi/" - "blender-package-manager-addon.git/blob_plain/HEAD:/addons/index.json") + req = urllib.request.urlopen(INDEX_DOWNLOAD_URL) index_file = req.read().decode('utf-8') req.close() except urllib.error.HTTPError as err: - self.report({'ERROR'}, "Error requesting update: " - + str(err.code) + " " + err.reason) + self.report({'ERROR'}, "Error requesting update: %s %s" % (str(err.code), err.reason)) return {'CANCELLED'} # Parse downloaded file @@ -64,11 +65,11 @@ class WM_OT_update_index(bpy.types.Operator): # Loop through every add-on in the parsed json for name, content in addon_list["addons"].items(): - # Skip add-ons not installed to USER directory + # Skip add-ons not installed to USER path # TODO: support above later for a in installed: if name == a.__name__ and user_path not in a.__file__: - log.warning("Not listing add-on %s, as it is installed to " + log.info("Not listing add-on %s, as it is installed to " "location other than USER path", name) break else: @@ -83,6 +84,7 @@ class WM_OT_update_index(bpy.types.Operator): addon.name = content["name"] addon.blender = '.'.join(map(str, content["blender"])) addon.module_name = module_name + addon.download_url = content["download_url"] if "author" in content: addon.author = content["author"] @@ -93,9 +95,6 @@ class WM_OT_update_index(bpy.types.Operator): if "description" in content: addon.description = content["description"] - if "filename" in content: - addon.filename = content["filename"] - if "location" in content: addon.location = content["location"] @@ -112,11 +111,11 @@ class WM_OT_update_index(bpy.types.Operator): # TODO: add multi-version functionality addon.version = '.'.join(map(str, content["version"])) - if "wiki_url" in content: - addon.wiki_url = content["wiki_url"] - if "warning" in content: addon.warning = content["warning"] + + if "wiki_url" in content: + addon.wiki_url = content["wiki_url"] class WM_OT_addon_download_install(bpy.types.Operator): @@ -132,48 +131,60 @@ class WM_OT_addon_download_install(bpy.types.Operator): # Get the add-on preferences prefs = bpy.context.user_preferences.addons.get("package_manager").preferences + + # Verify add-on is in list and find its download url + download_url = "" for addon in prefs.pm_addons: if addon.module_name == self.addon: + download_url = addon.download_url break else: - print("failed :(") return {'CANCELLED'} - # TODO: specify filetype + ext = os.path.splitext(download_url)[1] - if self.download(self.addon): - if self.install(self.addon): + # Download and install the selected add-on + if self.download(self.addon, download_url): + if self.install(self.addon, ext): return {'FINISHED'} return {'CANCELLED'} - def download(self, addon, filetype=".py"): - filename = addon + filetype + def download(self, addon, download_url): + filetype = os.path.splitext(download_url)[1] - download_path = bpy.utils.user_resource('SCRIPTS', - path="addons/package_manager/download%s" % filetype) + download_path = bpy.utils.user_resource('SCRIPTS', path="addons/package_manager/" + "download%s" % filetype) + # Download add-on and save to disk try: - req = urllib.request.urlopen("http://localhost:8000/%s" % filename) + req = urllib.request.urlopen(download_url) with open(download_path, 'wb') as download_file: shutil.copyfileobj(req, download_file) req.close() except urllib.error.HTTPError as err: - log.warning("Download failed with HTTPError: %s %s", - str(err.code), err.reason) + log.warning("Download failed with HTTPError: %s %s", str(err.code), err.reason) return False return True - def install(self, addon, filetype=".py"): - filename = addon + filetype if filetype == ".py" else "" + def install(self, addon, filetype): + filename = addon + (filetype if filetype == ".py" else "") - download_path = bpy.utils.user_resource('SCRIPTS', - path="addons/package_manager/download%s" % filetype) + download_path = bpy.utils.user_resource('SCRIPTS', path="addons/package_manager/" + "download%s" % filetype) addon_path = bpy.utils.user_resource('SCRIPTS', path="addons/%s" % filename) + # Copy downloaded add-on to USER scripts path if filetype == ".py": shutil.move(download_path, addon_path) + elif filetype == ".zip": + # Remove existing add-on + if os.path.exists(addon_path): + shutil.rmtree(addon_path) + with zipfile.ZipFile(download_path,"r") as zipped_addon: + zipped_addon.extractall(bpy.utils.user_resource('SCRIPTS', path="addons")) + return True