python/mozbuild/mozpack/packager/unpack.py

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 # This Source Code Form is subject to the terms of the Mozilla Public
michael@0 2 # License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 3 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
michael@0 4
michael@0 5 import mozpack.path
michael@0 6 from mozpack.files import (
michael@0 7 FileFinder,
michael@0 8 DeflatedFile,
michael@0 9 ManifestFile,
michael@0 10 )
michael@0 11 from mozpack.chrome.manifest import (
michael@0 12 parse_manifest,
michael@0 13 ManifestEntryWithRelPath,
michael@0 14 ManifestResource,
michael@0 15 is_manifest,
michael@0 16 )
michael@0 17 from mozpack.mozjar import JarReader
michael@0 18 from mozpack.copier import (
michael@0 19 FileRegistry,
michael@0 20 FileCopier,
michael@0 21 )
michael@0 22 from mozpack.packager import SimplePackager
michael@0 23 from mozpack.packager.formats import (
michael@0 24 FlatFormatter,
michael@0 25 STARTUP_CACHE_PATHS,
michael@0 26 )
michael@0 27 from urlparse import urlparse
michael@0 28
michael@0 29
michael@0 30 class UnpackFinder(FileFinder):
michael@0 31 '''
michael@0 32 Special FileFinder that treats the source package directory as if it were
michael@0 33 in the flat chrome format, whatever chrome format it actually is in.
michael@0 34
michael@0 35 This means that for example, paths like chrome/browser/content/... match
michael@0 36 files under jar:chrome/browser.jar!/content/... in case of jar chrome
michael@0 37 format.
michael@0 38 '''
michael@0 39 def __init__(self, *args, **kargs):
michael@0 40 FileFinder.__init__(self, *args, **kargs)
michael@0 41 self.files = FileRegistry()
michael@0 42 self.kind = 'flat'
michael@0 43 self.omnijar = None
michael@0 44 self.jarlogs = {}
michael@0 45 self.optimizedjars = False
michael@0 46
michael@0 47 jars = set()
michael@0 48
michael@0 49 for p, f in FileFinder.find(self, '*'):
michael@0 50 # Skip the precomplete file, which is generated at packaging time.
michael@0 51 if p == 'precomplete':
michael@0 52 continue
michael@0 53 base = mozpack.path.dirname(p)
michael@0 54 # If the file is a zip/jar that is not a .xpi, and contains a
michael@0 55 # chrome.manifest, it is an omnijar. All the files it contains
michael@0 56 # go in the directory containing the omnijar. Manifests are merged
michael@0 57 # if there is a corresponding manifest in the directory.
michael@0 58 if not p.endswith('.xpi') and self._maybe_zip(f) and \
michael@0 59 (mozpack.path.basename(p) == self.omnijar or
michael@0 60 not self.omnijar):
michael@0 61 jar = self._open_jar(p, f)
michael@0 62 if 'chrome.manifest' in jar:
michael@0 63 self.kind = 'omni'
michael@0 64 self.omnijar = mozpack.path.basename(p)
michael@0 65 self._fill_with_omnijar(base, jar)
michael@0 66 continue
michael@0 67 # If the file is a manifest, scan its entries for some referencing
michael@0 68 # jar: urls. If there are some, the files contained in the jar they
michael@0 69 # point to, go under a directory named after the jar.
michael@0 70 if is_manifest(p):
michael@0 71 m = self.files[p] if self.files.contains(p) \
michael@0 72 else ManifestFile(base)
michael@0 73 for e in parse_manifest(self.base, p, f.open()):
michael@0 74 m.add(self._handle_manifest_entry(e, jars))
michael@0 75 if self.files.contains(p):
michael@0 76 continue
michael@0 77 f = m
michael@0 78 if not p in jars:
michael@0 79 self.files.add(p, f)
michael@0 80
michael@0 81 def _fill_with_omnijar(self, base, jar):
michael@0 82 for j in jar:
michael@0 83 path = mozpack.path.join(base, j.filename)
michael@0 84 if is_manifest(j.filename):
michael@0 85 m = self.files[path] if self.files.contains(path) \
michael@0 86 else ManifestFile(mozpack.path.dirname(path))
michael@0 87 for e in parse_manifest(None, path, j):
michael@0 88 m.add(e)
michael@0 89 if not self.files.contains(path):
michael@0 90 self.files.add(path, m)
michael@0 91 continue
michael@0 92 else:
michael@0 93 self.files.add(path, DeflatedFile(j))
michael@0 94
michael@0 95 def _handle_manifest_entry(self, entry, jars):
michael@0 96 jarpath = None
michael@0 97 if isinstance(entry, ManifestEntryWithRelPath) and \
michael@0 98 urlparse(entry.relpath).scheme == 'jar':
michael@0 99 jarpath, entry = self._unjarize(entry, entry.relpath)
michael@0 100 elif isinstance(entry, ManifestResource) and \
michael@0 101 urlparse(entry.target).scheme == 'jar':
michael@0 102 jarpath, entry = self._unjarize(entry, entry.target)
michael@0 103 if jarpath:
michael@0 104 # Don't defer unpacking the jar file. If we already saw
michael@0 105 # it, take (and remove) it from the registry. If we
michael@0 106 # haven't, try to find it now.
michael@0 107 if self.files.contains(jarpath):
michael@0 108 jar = self.files[jarpath]
michael@0 109 self.files.remove(jarpath)
michael@0 110 else:
michael@0 111 jar = [f for p, f in FileFinder.find(self, jarpath)]
michael@0 112 assert len(jar) == 1
michael@0 113 jar = jar[0]
michael@0 114 if not jarpath in jars:
michael@0 115 base = mozpack.path.splitext(jarpath)[0]
michael@0 116 for j in self._open_jar(jarpath, jar):
michael@0 117 self.files.add(mozpack.path.join(base,
michael@0 118 j.filename),
michael@0 119 DeflatedFile(j))
michael@0 120 jars.add(jarpath)
michael@0 121 self.kind = 'jar'
michael@0 122 return entry
michael@0 123
michael@0 124 def _open_jar(self, path, file):
michael@0 125 '''
michael@0 126 Return a JarReader for the given BaseFile instance, keeping a log of
michael@0 127 the preloaded entries it has.
michael@0 128 '''
michael@0 129 jar = JarReader(fileobj=file.open())
michael@0 130 if jar.is_optimized:
michael@0 131 self.optimizedjars = True
michael@0 132 if jar.last_preloaded:
michael@0 133 jarlog = jar.entries.keys()
michael@0 134 self.jarlogs[path] = jarlog[:jarlog.index(jar.last_preloaded) + 1]
michael@0 135 return jar
michael@0 136
michael@0 137 def find(self, path):
michael@0 138 for p in self.files.match(path):
michael@0 139 yield p, self.files[p]
michael@0 140
michael@0 141 def _maybe_zip(self, file):
michael@0 142 '''
michael@0 143 Return whether the given BaseFile looks like a ZIP/Jar.
michael@0 144 '''
michael@0 145 header = file.open().read(8)
michael@0 146 return len(header) == 8 and (header[0:2] == 'PK' or
michael@0 147 header[4:6] == 'PK')
michael@0 148
michael@0 149 def _unjarize(self, entry, relpath):
michael@0 150 '''
michael@0 151 Transform a manifest entry pointing to chrome data in a jar in one
michael@0 152 pointing to the corresponding unpacked path. Return the jar path and
michael@0 153 the new entry.
michael@0 154 '''
michael@0 155 base = entry.base
michael@0 156 jar, relpath = urlparse(relpath).path.split('!', 1)
michael@0 157 entry = entry.rebase(mozpack.path.join(base, 'jar:%s!' % jar)) \
michael@0 158 .move(mozpack.path.join(base, mozpack.path.splitext(jar)[0])) \
michael@0 159 .rebase(base)
michael@0 160 return mozpack.path.join(base, jar), entry
michael@0 161
michael@0 162
michael@0 163 def unpack(source):
michael@0 164 '''
michael@0 165 Transform a jar chrome or omnijar packaged directory into a flat package.
michael@0 166 '''
michael@0 167 copier = FileCopier()
michael@0 168 finder = UnpackFinder(source)
michael@0 169 packager = SimplePackager(FlatFormatter(copier))
michael@0 170 for p, f in finder.find('*'):
michael@0 171 if mozpack.path.split(p)[0] not in STARTUP_CACHE_PATHS:
michael@0 172 packager.add(p, f)
michael@0 173 packager.close()
michael@0 174 copier.copy(source, skip_if_older=False)

mercurial