295 lines
9.1 KiB
Python
295 lines
9.1 KiB
Python
# This Source Code Form is subject to the terms of the Mozilla Public
|
|
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
|
from mozpack.packager.formats import (
|
|
FlatFormatter,
|
|
JarFormatter,
|
|
OmniJarFormatter,
|
|
)
|
|
from mozpack.packager import (
|
|
preprocess_manifest,
|
|
preprocess,
|
|
Component,
|
|
SimpleManifestSink,
|
|
)
|
|
from mozpack.files import (
|
|
GeneratedFile,
|
|
FileFinder,
|
|
File,
|
|
)
|
|
from mozpack.copier import (
|
|
FileCopier,
|
|
Jarrer,
|
|
)
|
|
from mozpack.errors import errors
|
|
from mozpack.files import ExecutableFile
|
|
import mozpack.path as mozpath
|
|
import buildconfig
|
|
from argparse import ArgumentParser
|
|
from collections import OrderedDict
|
|
from createprecomplete import generate_precomplete
|
|
import os
|
|
import plistlib
|
|
from io import StringIO
|
|
import subprocess
|
|
|
|
|
|
class PackagerFileFinder(FileFinder):
|
|
def get(self, path):
|
|
f = super(PackagerFileFinder, self).get(path)
|
|
# Normalize Info.plist files, and remove the MozillaDeveloper*Path
|
|
# entries which are only needed on unpackaged builds.
|
|
if mozpath.basename(path) == "Info.plist":
|
|
info = plistlib.load(f.open(), dict_type=OrderedDict)
|
|
info.pop("MozillaDeveloperObjPath", None)
|
|
info.pop("MozillaDeveloperRepoPath", None)
|
|
return GeneratedFile(plistlib.dumps(info, sort_keys=False))
|
|
return f
|
|
|
|
|
|
class RemovedFiles(GeneratedFile):
|
|
"""
|
|
File class for removed-files. Is used as a preprocessor parser.
|
|
"""
|
|
|
|
def __init__(self, copier):
|
|
self.copier = copier
|
|
GeneratedFile.__init__(self, "")
|
|
|
|
def handle_line(self, f):
|
|
f = f.strip()
|
|
if not f:
|
|
return
|
|
if self.copier.contains(f):
|
|
errors.error("Removal of packaged file(s): %s" % f)
|
|
self.content += f.encode("utf-8") + b"\n"
|
|
|
|
|
|
def split_define(define):
|
|
"""
|
|
Give a VAR[=VAL] string, returns a (VAR, VAL) tuple, where VAL defaults to
|
|
1. Numeric VALs are returned as ints.
|
|
"""
|
|
if "=" in define:
|
|
name, value = define.split("=", 1)
|
|
try:
|
|
value = int(value)
|
|
except ValueError:
|
|
pass
|
|
return (name, value)
|
|
return (define, 1)
|
|
|
|
|
|
class NoPkgFilesRemover(object):
|
|
"""
|
|
Formatter wrapper to handle NO_PKG_FILES.
|
|
"""
|
|
|
|
def __init__(self, formatter, has_manifest):
|
|
assert "NO_PKG_FILES" in os.environ
|
|
self._formatter = formatter
|
|
self._files = os.environ["NO_PKG_FILES"].split()
|
|
if has_manifest:
|
|
self._error = errors.error
|
|
self._msg = "NO_PKG_FILES contains file listed in manifest: %s"
|
|
else:
|
|
self._error = errors.warn
|
|
self._msg = "Skipping %s"
|
|
|
|
def add_base(self, base, *args):
|
|
self._formatter.add_base(base, *args)
|
|
|
|
def add(self, path, content):
|
|
if not any(mozpath.match(path, spec) for spec in self._files):
|
|
self._formatter.add(path, content)
|
|
else:
|
|
self._error(self._msg % path)
|
|
|
|
def add_manifest(self, entry):
|
|
self._formatter.add_manifest(entry)
|
|
|
|
def contains(self, path):
|
|
return self._formatter.contains(path)
|
|
|
|
|
|
def main():
|
|
parser = ArgumentParser()
|
|
parser.add_argument(
|
|
"-D",
|
|
dest="defines",
|
|
action="append",
|
|
metavar="VAR[=VAL]",
|
|
help="Define a variable",
|
|
)
|
|
parser.add_argument(
|
|
"--format",
|
|
default="omni",
|
|
help="Choose the chrome format for packaging "
|
|
+ "(omni, jar or flat ; default: %(default)s)",
|
|
)
|
|
parser.add_argument("--removals", default=None, help="removed-files source file")
|
|
parser.add_argument(
|
|
"--ignore-errors",
|
|
action="store_true",
|
|
default=False,
|
|
help="Transform errors into warnings.",
|
|
)
|
|
parser.add_argument(
|
|
"--ignore-broken-symlinks",
|
|
action="store_true",
|
|
default=False,
|
|
help="Do not fail when processing broken symlinks.",
|
|
)
|
|
parser.add_argument(
|
|
"--minify",
|
|
action="store_true",
|
|
default=False,
|
|
help="Make some files more compact while packaging",
|
|
)
|
|
parser.add_argument(
|
|
"--minify-js",
|
|
action="store_true",
|
|
help="Minify JavaScript files while packaging.",
|
|
)
|
|
parser.add_argument(
|
|
"--js-binary",
|
|
help="Path to js binary. This is used to verify "
|
|
"minified JavaScript. If this is not defined, "
|
|
"minification verification will not be performed.",
|
|
)
|
|
parser.add_argument(
|
|
"--jarlog", default="", help="File containing jar " + "access logs"
|
|
)
|
|
parser.add_argument(
|
|
"--compress",
|
|
choices=("none", "deflate"),
|
|
default="deflate",
|
|
help="Use given jar compression (default: deflate)",
|
|
)
|
|
parser.add_argument("manifest", default=None, nargs="?", help="Manifest file name")
|
|
parser.add_argument("source", help="Source directory")
|
|
parser.add_argument("destination", help="Destination directory")
|
|
parser.add_argument(
|
|
"--non-resource",
|
|
nargs="+",
|
|
metavar="PATTERN",
|
|
default=[],
|
|
help="Extra files not to be considered as resources",
|
|
)
|
|
args = parser.parse_args()
|
|
|
|
defines = dict(buildconfig.defines["ALLDEFINES"])
|
|
if args.ignore_errors:
|
|
errors.ignore_errors()
|
|
|
|
if args.defines:
|
|
for name, value in [split_define(d) for d in args.defines]:
|
|
defines[name] = value
|
|
|
|
compress = {
|
|
"none": False,
|
|
"deflate": True,
|
|
}[args.compress]
|
|
|
|
copier = FileCopier()
|
|
if args.format == "flat":
|
|
formatter = FlatFormatter(copier)
|
|
elif args.format == "jar":
|
|
formatter = JarFormatter(copier, compress=compress)
|
|
elif args.format == "omni":
|
|
formatter = OmniJarFormatter(
|
|
copier,
|
|
buildconfig.substs["OMNIJAR_NAME"],
|
|
compress=compress,
|
|
non_resources=args.non_resource,
|
|
)
|
|
else:
|
|
errors.fatal("Unknown format: %s" % args.format)
|
|
|
|
# Adjust defines according to the requested format.
|
|
if isinstance(formatter, OmniJarFormatter):
|
|
defines["MOZ_OMNIJAR"] = 1
|
|
elif "MOZ_OMNIJAR" in defines:
|
|
del defines["MOZ_OMNIJAR"]
|
|
|
|
respath = ""
|
|
if "RESPATH" in defines:
|
|
respath = SimpleManifestSink.normalize_path(defines["RESPATH"])
|
|
while respath.startswith("/"):
|
|
respath = respath[1:]
|
|
|
|
with errors.accumulate():
|
|
finder_args = dict(
|
|
minify=args.minify,
|
|
minify_js=args.minify_js,
|
|
ignore_broken_symlinks=args.ignore_broken_symlinks,
|
|
)
|
|
if args.js_binary:
|
|
finder_args["minify_js_verify_command"] = [
|
|
args.js_binary,
|
|
os.path.join(
|
|
os.path.abspath(os.path.dirname(__file__)), "js-compare-ast.js"
|
|
),
|
|
]
|
|
finder = PackagerFileFinder(args.source, find_executables=True, **finder_args)
|
|
if "NO_PKG_FILES" in os.environ:
|
|
sinkformatter = NoPkgFilesRemover(formatter, args.manifest is not None)
|
|
else:
|
|
sinkformatter = formatter
|
|
sink = SimpleManifestSink(finder, sinkformatter)
|
|
if args.manifest:
|
|
preprocess_manifest(sink, args.manifest, defines)
|
|
else:
|
|
sink.add(Component(""), "bin/*")
|
|
sink.close(args.manifest is not None)
|
|
|
|
if args.removals:
|
|
removals_in = StringIO(open(args.removals).read())
|
|
removals_in.name = args.removals
|
|
removals = RemovedFiles(copier)
|
|
preprocess(removals_in, removals, defines)
|
|
copier.add(mozpath.join(respath, "removed-files"), removals)
|
|
|
|
# If a pdb file is present and we were instructed to copy it, include it.
|
|
# Run on all OSes to capture MinGW builds
|
|
if buildconfig.substs.get("MOZ_COPY_PDBS"):
|
|
# We want to mutate the copier while we're iterating through it, so copy
|
|
# the items to a list first.
|
|
copier_items = [(p, f) for p, f in copier]
|
|
for p, f in copier_items:
|
|
if isinstance(f, ExecutableFile):
|
|
pdbname = os.path.splitext(f.inputs()[0])[0] + ".pdb"
|
|
if os.path.exists(pdbname):
|
|
copier.add(os.path.basename(pdbname), File(pdbname))
|
|
|
|
# Setup preloading
|
|
if args.jarlog:
|
|
if not os.path.exists(args.jarlog):
|
|
raise Exception("Cannot find jar log: %s" % args.jarlog)
|
|
omnijars = []
|
|
if isinstance(formatter, OmniJarFormatter):
|
|
omnijars = [
|
|
mozpath.join(base, buildconfig.substs["OMNIJAR_NAME"])
|
|
for base in sink.packager.get_bases(addons=False)
|
|
]
|
|
|
|
from mozpack.mozjar import JarLog
|
|
|
|
log = JarLog(args.jarlog)
|
|
for p, f in copier:
|
|
if not isinstance(f, Jarrer):
|
|
continue
|
|
if respath:
|
|
p = mozpath.relpath(p, respath)
|
|
if p in log:
|
|
f.preload(log[p])
|
|
elif p in omnijars:
|
|
raise Exception("No jar log data for %s" % p)
|
|
|
|
copier.copy(args.destination)
|
|
generate_precomplete(os.path.normpath(os.path.join(args.destination, respath)))
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|