seawolf2357's picture
Add tools
a65138c verified
# -*- coding: utf-8 -*-
from __future__ import with_statement
import logging
import os.path
from storage import open_storage
from storage import resolve_path
from storage import makedirs_to_file
from storage import put_file
from storage import copy_file
from storage import iterate_files_recursively
from storage._zipfile import ZipFileStorage
from storage.fs import FileSystemStorage
from manifest import Manifest
from description import Description
logger = logging.getLogger(__name__)
def is_package(folder):
if 'META-INF' not in folder:
return False
if 'manifest.xml' not in folder['META-INF']:
return False
return True
MANIFEST_PATH = os.path.join('META-INF', 'manifest.xml')
DESCRIPTION_PATH = 'description.xml'
def add_file(stg, manifest, path, full_path, media_type):
''' add a file into the storage and manifest.
:param stg: a storage
:param manifest: an instance of Manifest
:param path: path to the file on the filesystem.
:param full_path: ``manifest:full-path`` value of ``manifest:file-entry``
:param media_type: ``manifest:media-type`` value of ``manifest:file-entry``
'''
node = makedirs_to_file(stg, full_path)
put_file(node, path)
manifest[full_path] = media_type
return node
def add_component_file(stg, manifest, path, full_path, type, platform=None):
''' add a component file.
:param stg: a storage
:param manifest: an instance of Manifest
:param path: path to the file on the filesystem.
:param full_path: ``manifest:full-path`` value of ``manifest:file-entry``
:param type: ``native``, ``Java``, ``Python`` or None
:param platform: supposed platform to run this component.
if ``type`` is None, this component is meant to be registered with
`Passive Component Registration
<http://wiki.openoffice.org/wiki/Documentation/DevGuide/Extensions/Passive_Component_Registration>`_
and the file specified with ``path`` should be an XML file, which is
defined in the document above.
For more informations, see `File Format
<http://wiki.openoffice.org/wiki/Documentation/DevGuide/Extensions/File_Format>`_.
'''
mimetype = 'application/vnd.sun.star.uno-component'
if type:
mimetype += '; ' + type
if platform:
mimetype += '; ' + platform
return add_file(stg, manifest, path, full_path, mimetype=mimetype)
def add_type_library(stg, manifest, path, full_path, type):
''' add a UNO type library.
:param stg: a storage
:param manifest: an instance of Manifest
:param type: ``RDB`` or ``Java``
'''
typelib_extensions = dict(RDB='.rdb', Java='.jar')
if type not in typelib_extensions.keys():
raise ValueError('type: unsupported value of %r' % type)
if not full_path.lower().endswith(typelib_extensions[type]):
msg = 'adding %r type library %r with name %r: really intended?'
logger.warning(msg, type, path, full_path)
mimetype = 'application/vnd.sun.star.uno-typelibrary'
mimetype += '; type=' + type
return add_file(stg, manifest, path, full_path, mimetype)
def add_basic_library(stg, manifest, path, full_path):
''' add a basic library
:param stg: a storage
:param manifest: an instance of Manifest
'''
mimetype = 'application/vnd.sun.star.basic-library'
return add_file(stg, manifest, path, full_path, mimetype=mimetype)
def add_dialog_library(stg, manifest, path, full_path):
''' add a dialog library
:param stg: a storage
:param manifest: an instance of Manifest
'''
mimetype = 'application/vnd.sun.star.dialog-library'
return add_file(stg, manifest, path, full_path, mimetype=mimetype)
def add_configuration_data_file(stg, manifest, path, full_path):
''' add a configuration data file.
:param stg: a storage
:param manifest: an instance of Manifest
'''
mimetype = 'application/vnd.sun.star.configuration-data'
return add_file(stg, manifest, path, full_path, mimetype=mimetype)
def add_configuration_schema_file(stg, manifest, path, full_path):
''' add a configuration schema file.
:param stg: a storage
:param manifest: an instance of Manifest
'''
mimetype = 'application/vnd.sun.star.configuration-schema'
return add_file(stg, manifest, path, full_path, mimetype=mimetype)
def build(package_path, manifest, description, files=dict(),
storage_factory=ZipFileStorage):
''' Build a OXT Package.
:param package_path: path to an .oxt package to be built
:param manifest: an instance of Manifest
:param description: an instance of Description
:param files: package files, in a form of (path, node) dict
:param storage_factory: storage factory for the package.
Default to ZipFileStorage
'''
assert not any(node is None for node in files.values())
assert all(path in files for path in manifest)
assert all(path in files for path in description.required_files())
logger.info('creating %s', package_path)
with storage_factory(package_path, 'w') as stg:
logger.info('writing %s', MANIFEST_PATH)
manifest_node = makedirs_to_file(stg, MANIFEST_PATH)
with manifest_node.open('w') as f:
manifest.dump(f)
logger.info('writing %s', DESCRIPTION_PATH)
desc_node = makedirs_to_file(stg, DESCRIPTION_PATH)
with desc_node.open('w') as f:
description.write(f)
for path in sorted(files):
node = files[path]
logger.info('writing %s', path)
dest = makedirs_to_file(stg, path)
copy_file(node, dest)
def build_from(package_path,
src_folder,
manifest_path=None,
description_path=None,
files=[],
excludes=[],
storage_factory=ZipFileStorage):
if manifest_path:
with file(manifest_path) as f:
manifest = Manifest()
manifest.load(f)
else:
node = resolve_path(src_folder, MANIFEST_PATH)
if node:
with node.open() as f:
manifest = Manifest()
manifest.load(f)
else:
logger.error('%s: not found' % MANIFEST_PATH)
raise IOError('%s: not found' % MANIFEST_PATH)
if description_path:
with file(description_path) as f:
description = Description.parse(f)
else:
node = resolve_path(src_folder, DESCRIPTION_PATH)
if node:
with node.open() as f:
description = Description.parse(f)
else:
raise IOError('%s: not found' % DESCRIPTION_PATH)
package_path = make_output_path(package_path, description)
package_files = dict()
from itertools import chain
required_files = chain(manifest, description.required_files())
for path in required_files:
node = resolve_path(src_folder, path)
if node is None:
raise IOError('%s: not found' % path)
package_files[path] = node
files = ((path, resolve_path(src_folder, path)) for path in files)
files = expand_folders(files)
files = exclude_files(excludes, files)
package_files.update(files)
return build(package_path, manifest, description, package_files,
storage_factory=storage_factory)
def make_output_path(path, desc=None):
if os.path.isdir(path):
dirname = path
name = ''
else:
dirname, name = os.path.split(path)
# default name will be used if not given
if name == '':
if desc is None:
raise ValueError('%s: invalid path' % path)
name = package_name_from_desc(desc)
return os.path.join(dirname, name)
def package_name_from_desc(desc):
id = desc.identifier
version = desc.version
if version:
return '-'.join([id, version]) + '.oxt'
else:
return id + '.oxt'
def expand_folders(resolved_nodes):
for path, node in resolved_nodes:
if hasattr(node, '__iter__'):
for path, node in iterate_files_recursively(node, path):
yield path, node
else:
yield path, node
def exclude_files(patterns, resolved_nodes):
from fnmatch import fnmatch
for path, node in resolved_nodes:
excluded = False
for pat in patterns:
if fnmatch(path, pat):
logger.info('exclude %s (by %s)', path, pat)
excluded = True
if not excluded:
yield path, node
def init_main():
doc = '''Usage: oxt-pkg-init [options] <package-path>
--help Print this screen.
'''
from docopt import docopt
args = docopt(doc)
logging.basicConfig(level=logging.INFO)
package_path = args['<package-path>']
manifest = Manifest()
description = Description()
with open_storage(package_path, 'w') as stg:
with makedirs_to_file(stg, MANIFEST_PATH).open('w') as f:
manifest.dump(f)
with makedirs_to_file(stg, DESCRIPTION_PATH).open('w') as f:
description.write(f)
def show_main():
doc = '''Usage: oxt-pkg-show [options] <package-path>
--help Print this screen.
'''
from docopt import docopt
args = docopt(doc)
logging.basicConfig(level=logging.INFO)
package_path = args['<package-path>']
with open_storage(package_path) as pkg:
with resolve_path(pkg, MANIFEST_PATH).open() as f:
manifest = Manifest()
manifest.load(f)
with resolve_path(pkg, DESCRIPTION_PATH).open() as f:
description = Description.parse(f)
from description import print_human_readable
print_human_readable(description, pkg)
for path in manifest:
item = manifest[path]
print path, item['media-type'],
node = resolve_path(pkg, path)
if node:
print '-- OK'
else:
print '-- MISSING'
def build_main():
doc = '''Usage: oxt-pkg-build [options] <src-folder> <add-files>...
-o OUTPUT-PATH Output path
-m MANIFEST META-INF/manifest.xml
-d DESCRIPT description.xml
-E EXCLUDE, --exclude=EXCLUDE exclude patterns; separated by %r.
--help Print this screen.
<src-folder> root folder containing package files
<add-files> additional files (relative to <src-folder>)
''' % os.pathsep
from docopt import docopt
args = docopt(doc)
logging.basicConfig(level=logging.INFO)
src_folder_path = args['<src-folder>']
add_files = args['<add-files>']
output_path = args['-o'] or '.'
manifest_path = args['-m']
description_path = args['-d']
excludes = args['--exclude'] or ''
excludes = excludes.strip().split(os.pathsep)
with FileSystemStorage(src_folder_path) as src_folder:
build_from(output_path,
src_folder,
manifest_path=manifest_path,
description_path=description_path,
files=add_files,
excludes=excludes)
def check_main():
doc = '''Usage: oxt-pkg-show [options] <package-path>
--help Print this screen.
'''
from docopt import docopt
args = docopt(doc)
logging.basicConfig(level=logging.INFO)
package_path = args['<package-path>']
with open_storage(package_path) as pkg:
with resolve_path(pkg, MANIFEST_PATH).open() as f:
manifest = Manifest()
manifest.load(f)
with resolve_path(pkg, DESCRIPTION_PATH).open() as f:
description = Description.parse(f)
missing = dict()
for path in manifest:
node = resolve_path(pkg, path)
if node is None:
missing[path] = MANIFEST_PATH
for path in description.required_files():
node = resolve_path(pkg, path)
if node is None:
missing[path] = DESCRIPTION_PATH
if missing:
for path in sorted(missing):
referer = missing[path]
logger.error('%s: MISSING (refered in %s)',
path, referer)
raise SystemExit(1)
else:
logger.info('%s: OK, identifier=%s, version=%s', package_path,
description.identifier, description.version)