Package Manager add-on now functional, with limitations

- For now, add-ons are downloaded from http://localhost:8000/.
- Add-ons on the index.json (from	blender.org gitweb) are only displayed if they are not installed locally, or installed in the USER path.
- Only .py add-ons are supported for now, but .zip add-ons will be supported next commit.
This commit is contained in:
2016-06-24 09:18:09 -05:00
parent 52365f59ae
commit 576d04ee65
2 changed files with 212 additions and 33 deletions

View File

@@ -16,61 +16,172 @@
# ======================= END GPL LICENSE BLOCK ========================
import bpy
import addon_utils
import json
import urllib.request
import logging
import shutil
from bpy.props import StringProperty
logging.basicConfig(format='%(asctime)-15s %(levelname)8s %(name)s %(message)s',
level=logging.INFO)
log = logging.getLogger('networking')
class UpdateIndex(bpy.types.Operator):
"""Update the list of add-ons available for download"""
class WM_OT_update_index(bpy.types.Operator):
"""Check for updated list of add-ons available for download"""
bl_idname = "wm.update_index"
bl_label = "Update list of add-ons"
bl_label = "Check for updated list of add-ons"
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")
index_file = req.read()
del req
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)
return {'CANCELLED'}
# Parse downloaded file
try:
addon_list = json.loads(index_file)
except ValueError:
except ValueError as err:
self.report({'ERROR'}, "Error: JSON file could not parse.")
log.warning("ValueError: %s", err)
return {'CANCELLED'}
for addon_list["addons"] as name, content:
addon = PackageManagerAddon()
addon.name = name
addon.source = content["source"]
addon.description = content["description"]
addon.author = content["author"]
addon.wiki_url = content["wiki_url"]
addon.tracker_url = content["tracker_url"]
addon.location = content["location"]
addon.category = content["category"]
for content["version"] as item:
# TODO: add multi-version functionality
for item as version, value:
addon.version = key
addon.blender = value["blender"]
addon.support = value["support"].upper()
try:
addon.warning = content["warning"]
except Exception:
pass
addon.filename = value["filename"]
# Get the add-on preferences
prefs = bpy.context.user_preferences.addons.get("package_manager").preferences
# Clear previous list of add-ons
prefs.pm_addons.clear()
prefs.pm_addons_index = 0
print(index_file)
user_path = bpy.utils.user_resource('SCRIPTS', path="addons")
installed = addon_utils.modules()
# 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
# 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 "
"location other than USER path", name)
break
else:
# Add new add-on to the list
addon = prefs.pm_addons.add()
self.load_addon_data(addon, name, content)
return {'FINISHED'}
def load_addon_data(self, addon, module_name, content):
addon.name = content["name"]
addon.blender = '.'.join(map(str, content["blender"]))
addon.module_name = module_name
if "author" in content:
addon.author = content["author"]
if "category" in content:
addon.category = content["category"]
if "description" in content:
addon.description = content["description"]
if "filename" in content:
addon.filename = content["filename"]
if "location" in content:
addon.location = content["location"]
if "source" in content:
addon.source = content["source"]
if "support" in content:
addon.support = content["support"]
if "tracker_url" in content:
addon.tracker_url = content["tracker_url"]
if "version" in content:
# 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"]
class WM_OT_addon_download_install(bpy.types.Operator):
"""Download and install add-on"""
bl_idname = "wm.addon_download_install"
bl_label = "Download and install selected add-on"
addon = bpy.props.StringProperty()
def execute(self, context):
if self.addon is None:
return {'CANCELLED'}
# Get the add-on preferences
prefs = bpy.context.user_preferences.addons.get("package_manager").preferences
for addon in prefs.pm_addons:
if addon.module_name == self.addon:
break
else:
print("failed :(")
return {'CANCELLED'}
# TODO: specify filetype
if self.download(self.addon):
if self.install(self.addon):
return {'FINISHED'}
return {'CANCELLED'}
def download(self, addon, filetype=".py"):
filename = addon + filetype
download_path = bpy.utils.user_resource('SCRIPTS',
path="addons/package_manager/download%s" % filetype)
try:
req = urllib.request.urlopen("http://localhost:8000/%s" % filename)
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)
return False
return True
def install(self, addon, filetype=".py"):
filename = addon + filetype if filetype == ".py" else ""
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)
if filetype == ".py":
shutil.move(download_path, addon_path)
return True
def register():
bpy.utils.register_class(UpdateIndex)
bpy.utils.register_class(WM_OT_update_index)
bpy.utils.register_class(WM_OT_addon_download_install)
def unregister():
bpy.utils.unregister_class(UpdateIndex)
bpy.utils.unregister_class(WM_OT_update_index)
bpy.utils.unregister_class(WM_OT_addon_download_install)