from __future__ import absolute_import
import mozpack.path as mozpath
from mozpack.files import (
BaseFinder,
FileFinder,
DeflatedFile,
ManifestFile,
)
from mozpack.chrome.manifest import (
parse_manifest,
ManifestEntryWithRelPath,
ManifestResource,
is_manifest,
)
from mozpack.mozjar import JarReader
from mozpack.copier import (
FileRegistry,
FileCopier,
)
from mozpack.packager import SimplePackager
from mozpack.packager.formats import FlatFormatter
from urlparse import urlparse
class UnpackFinder(BaseFinder):
def __init__(self, source, omnijar_name=None):
if isinstance(source, BaseFinder):
self._finder = source
else:
self._finder = FileFinder(source)
self.base = self._finder.base
self.files = FileRegistry()
self.kind = 'flat'
if omnijar_name:
self.omnijar = omnijar_name
else:
from buildconfig import substs
self.omnijar = substs.get('OMNIJAR_NAME', 'omni.ja')
self.jarlogs = {}
self.compressed = False
jars = set()
for p, f in self._finder.find('*'):
if p == 'precomplete':
continue
base = mozpath.dirname(p)
if self._maybe_zip(f) and mozpath.match(p, '**/%s' % self.omnijar):
jar = self._open_jar(p, f)
if 'chrome.manifest' in jar:
self.kind = 'omni'
self._fill_with_jar(p[:-len(self.omnijar) - 1], jar)
continue
if is_manifest(p):
m = self.files[p] if self.files.contains(p) \
else ManifestFile(base)
for e in parse_manifest(self.base, p, f.open()):
m.add(self._handle_manifest_entry(e, jars))
if self.files.contains(p):
continue
f = m
if p.endswith('.xpi') and self._maybe_zip(f):
self._fill_with_jar(p[:-4], self._open_jar(p, f))
continue
if p not in jars:
self.files.add(p, f)
def _fill_with_jar(self, base, jar):
for j in jar:
path = mozpath.join(base, j.filename)
if is_manifest(j.filename):
m = self.files[path] if self.files.contains(path) \
else ManifestFile(mozpath.dirname(path))
for e in parse_manifest(None, path, j):
m.add(e)
if not self.files.contains(path):
self.files.add(path, m)
continue
else:
self.files.add(path, DeflatedFile(j))
def _handle_manifest_entry(self, entry, jars):
jarpath = None
if isinstance(entry, ManifestEntryWithRelPath) and \
urlparse(entry.relpath).scheme == 'jar':
jarpath, entry = self._unjarize(entry, entry.relpath)
elif isinstance(entry, ManifestResource) and \
urlparse(entry.target).scheme == 'jar':
jarpath, entry = self._unjarize(entry, entry.target)
if jarpath:
if self.files.contains(jarpath):
jar = self.files[jarpath]
self.files.remove(jarpath)
else:
jar = [f for p, f in self._finder.find(jarpath)]
assert len(jar) == 1
jar = jar[0]
if jarpath not in jars:
base = mozpath.splitext(jarpath)[0]
for j in self._open_jar(jarpath, jar):
self.files.add(mozpath.join(base,
j.filename),
DeflatedFile(j))
jars.add(jarpath)
self.kind = 'jar'
return entry
def _open_jar(self, path, file):
jar = JarReader(fileobj=file.open())
self.compressed = max(self.compressed, jar.compression)
if jar.last_preloaded:
jarlog = jar.entries.keys()
self.jarlogs[path] = jarlog[:jarlog.index(jar.last_preloaded) + 1]
return jar
def find(self, path):
for p in self.files.match(path):
yield p, self.files[p]
def _maybe_zip(self, file):
header = file.open().read(8)
return len(header) == 8 and (header[0:2] == 'PK' or
header[4:6] == 'PK')
def _unjarize(self, entry, relpath):
base = entry.base
jar, relpath = urlparse(relpath).path.split('!', 1)
entry = entry.rebase(mozpath.join(base, 'jar:%s!' % jar)) \
.move(mozpath.join(base, mozpath.splitext(jar)[0])) \
.rebase(base)
return mozpath.join(base, jar), entry
def unpack_to_registry(source, registry, omnijar_name=None):
finder = UnpackFinder(source, omnijar_name)
packager = SimplePackager(FlatFormatter(registry))
for p, f in finder.find('*'):
packager.add(p, f)
packager.close()
def unpack(source, omnijar_name=None):
copier = FileCopier()
unpack_to_registry(source, copier, omnijar_name)
copier.copy(source, skip_if_older=False)