zip operator
This commit is contained in:
parent
cbbe8be0d8
commit
12e6e2643b
@ -20,4 +20,209 @@
|
||||
|
||||
# <pep8 compliant>
|
||||
|
||||
__version__ = "1.21"
|
||||
__version__ = '1.21'
|
||||
|
||||
bl_info = {
|
||||
"name": "Blender Asset Tracer",
|
||||
"author": "Campbell Barton, Sybren A. St\u00fcvel, Lo\u00efc Charri\u00e8re, Cl\u00e9ment Ducarteron, Mario Hawat, Joseph Henry",
|
||||
"version": (1, 21, 0),
|
||||
"blender": (2, 80, 0),
|
||||
"location": "File > External Data > BAT",
|
||||
"description": "Utility for packing blend files",
|
||||
"warning": "",
|
||||
"wiki_url": "https://developer.blender.org/project/profile/79/",
|
||||
"category": "Import-Export",
|
||||
}
|
||||
|
||||
# Reset root module name if folder has an unexpected name
|
||||
# (like "blender_asset_tracer-main" from zip-dl)
|
||||
import sys
|
||||
if __name__ != "blender_asset_tracer":
|
||||
sys.modules["blender_asset_tracer"] = sys.modules[__name__]
|
||||
|
||||
try:
|
||||
import bpy
|
||||
from bpy.types import Operator
|
||||
from bpy_extras.io_utils import ExportHelper
|
||||
_HAS_BPY = True
|
||||
except ImportError:
|
||||
_HAS_BPY = False
|
||||
|
||||
if _HAS_BPY:
|
||||
import zipfile
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
import tempfile
|
||||
from pathlib import Path, PurePath
|
||||
|
||||
from blender_asset_tracer.pack import zipped
|
||||
from blender_asset_tracer import blendfile
|
||||
from . import preferences
|
||||
|
||||
# Match the CLI's default: skip dangling pointers gracefully instead of crashing.
|
||||
# Production blend files often have references to missing linked libraries.
|
||||
blendfile.set_strict_pointer_mode(False)
|
||||
|
||||
class ExportBatPack(Operator, ExportHelper):
|
||||
bl_idname = "export_bat.pack"
|
||||
bl_label = "Export to Archive using BAT"
|
||||
filename_ext = ".zip"
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return bpy.data.is_saved
|
||||
|
||||
def execute(self, context):
|
||||
outfname = bpy.path.ensure_ext(self.filepath, ".zip")
|
||||
self.report({'INFO'}, 'Executing ZipPacker ...')
|
||||
|
||||
with zipped.ZipPacker(
|
||||
Path(bpy.data.filepath),
|
||||
Path(bpy.data.filepath).parent,
|
||||
str(self.filepath)) as packer:
|
||||
packer.strategise()
|
||||
packer.execute()
|
||||
self.report({'INFO'}, 'Packing successful!')
|
||||
|
||||
with zipfile.ZipFile(str(self.filepath)) as inzip:
|
||||
inzip.testzip()
|
||||
|
||||
self.report({'INFO'}, 'Written to %s' % outfname)
|
||||
return {'FINISHED'}
|
||||
|
||||
def open_folder(folderpath):
|
||||
"""Open the folder at the path given with cmd relative to user's OS."""
|
||||
from shutil import which
|
||||
my_os = sys.platform
|
||||
if my_os.startswith(('linux', 'freebsd')):
|
||||
cmd = 'xdg-open'
|
||||
elif my_os.startswith('win'):
|
||||
cmd = 'explorer'
|
||||
if not folderpath:
|
||||
return
|
||||
else:
|
||||
cmd = 'open'
|
||||
|
||||
if not folderpath:
|
||||
return
|
||||
|
||||
folderpath = str(folderpath)
|
||||
if os.path.isfile(folderpath):
|
||||
select = False
|
||||
if my_os.startswith('win'):
|
||||
cmd = 'explorer /select,'
|
||||
select = True
|
||||
elif my_os.startswith(('linux', 'freebsd')):
|
||||
if which('nemo'):
|
||||
cmd = 'nemo --no-desktop'
|
||||
select = True
|
||||
elif which('nautilus'):
|
||||
cmd = 'nautilus --no-desktop'
|
||||
select = True
|
||||
if not select:
|
||||
folderpath = os.path.dirname(folderpath)
|
||||
|
||||
folderpath = os.path.normpath(folderpath)
|
||||
fullcmd = cmd.split() + [folderpath]
|
||||
subprocess.Popen(fullcmd)
|
||||
|
||||
class BAT_OT_export_zip(Operator, ExportHelper):
|
||||
"""Export current blendfile with hierarchy preservation"""
|
||||
bl_label = "BAT Pack - keep hierarchy"
|
||||
bl_idname = "bat.export_zip"
|
||||
|
||||
filename_ext = '.zip'
|
||||
|
||||
root_dir: bpy.props.StringProperty(
|
||||
name="Root",
|
||||
description='Top Level Folder of your project.'
|
||||
'\nFor now Copy/Paste correct folder by hand if default is incorrect.'
|
||||
'\n!!! Everything outside won\'t be zipped !!!',
|
||||
)
|
||||
|
||||
use_zip: bpy.props.BoolProperty(
|
||||
name="Output as ZIP",
|
||||
description="If enabled, pack into a ZIP archive. If disabled, copy to a directory.",
|
||||
default=True,
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return bpy.data.is_saved
|
||||
|
||||
def execute(self, context):
|
||||
from blender_asset_tracer.pack import Packer
|
||||
from blender_asset_tracer.pack.zipped import ZipPacker
|
||||
|
||||
bfile = Path(bpy.data.filepath)
|
||||
project = Path(self.root_dir) if self.root_dir else bfile.parent
|
||||
target = str(self.filepath)
|
||||
|
||||
if self.use_zip:
|
||||
target = bpy.path.ensure_ext(target, ".zip")
|
||||
packer_cls = ZipPacker
|
||||
else:
|
||||
if target.lower().endswith('.zip'):
|
||||
target = target[:-4]
|
||||
packer_cls = Packer
|
||||
|
||||
self.report({'INFO'}, 'Packing with hierarchy...')
|
||||
|
||||
with packer_cls(bfile, project, target,
|
||||
keep_hierarchy=True) as packer:
|
||||
packer.strategise()
|
||||
packer.execute()
|
||||
|
||||
if self.use_zip:
|
||||
with zipfile.ZipFile(target) as inzip:
|
||||
inzip.testzip()
|
||||
log_output = Path(tempfile.gettempdir(), 'README.txt')
|
||||
with open(log_output, 'w') as log:
|
||||
log.write("Packed with BAT (keep-hierarchy mode)")
|
||||
log.write(f"\nBlend file: {bpy.data.filepath}")
|
||||
with zipfile.ZipFile(target, 'a') as zipObj:
|
||||
zipObj.write(log_output, log_output.name)
|
||||
|
||||
self.report({'INFO'}, 'Written to %s' % target)
|
||||
open_folder(Path(target).parent)
|
||||
return {'FINISHED'}
|
||||
|
||||
def menu_func(self, context):
|
||||
layout = self.layout
|
||||
layout.separator()
|
||||
layout.operator(ExportBatPack.bl_idname)
|
||||
filepath = layout.operator(BAT_OT_export_zip.bl_idname)
|
||||
|
||||
try:
|
||||
prefs = preferences.get_addon_prefs()
|
||||
root_dir_env = None
|
||||
if prefs.use_env_root:
|
||||
root_dir_env = os.getenv('ZIP_ROOT')
|
||||
if not root_dir_env:
|
||||
root_dir_env = os.getenv('PROJECT_ROOT')
|
||||
if not root_dir_env:
|
||||
root_dir_env = prefs.root_default
|
||||
filepath.root_dir = '' if root_dir_env is None else root_dir_env
|
||||
except Exception:
|
||||
filepath.root_dir = os.getenv('ZIP_ROOT') or os.getenv('PROJECT_ROOT') or ''
|
||||
|
||||
classes = (
|
||||
ExportBatPack,
|
||||
BAT_OT_export_zip,
|
||||
)
|
||||
|
||||
def register():
|
||||
preferences.register()
|
||||
for cls in classes:
|
||||
bpy.utils.register_class(cls)
|
||||
bpy.types.TOPBAR_MT_file_external_data.append(menu_func)
|
||||
|
||||
def unregister():
|
||||
for cls in classes:
|
||||
bpy.utils.unregister_class(cls)
|
||||
preferences.unregister()
|
||||
bpy.types.TOPBAR_MT_file_external_data.remove(menu_func)
|
||||
|
||||
if __name__ == "__main__":
|
||||
register()
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user