mirror of
https://github.com/shaka-project/shaka-player.git
synced 2026-06-13 15:46:46 +03:00
ec4bc1ddeb
These changes are necessary for compatibility with Chromecast WebDriver Server v2. - Fix a bug in Karma's flat environment support (joeyparrish/karma@9875e98) - Add a test boot file to load CAF on Chromecast devices; required by Chromecast WebDriver Server v2's redirect mode (flat environment at that level) - Also load this cast-boot file in support.html - Rename/reorganize Cast-related externs, which were messy even before the addition of CAF - Remove proxy-cast-platform.js; no longer needed as we move to flatten the test environment - Ignore error events with "null" error; these appear on Linux Chromecasts, only since including CAF - Ignore error events that are actually strings; these appear on Linux Chromecasts, only since including CAF - Disable Fuchsia in the lab until autoplay issues can be resolved
418 lines
12 KiB
Python
Executable File
418 lines
12 KiB
Python
Executable File
#!/usr/bin/env python
|
|
#
|
|
# Copyright 2016 Google LLC
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
|
|
"""Creates a build from the given commands.
|
|
|
|
A command is either an addition or a subtraction. An addition is prefixed with
|
|
a +; a subtraction is when prefixed with a -. After the character, there is a
|
|
name of a file or a @ sign and the name of a build file.
|
|
|
|
Build files are the files found in build/types. These files are simply a
|
|
newline separated list of commands to execute. So if the "+@complete" command
|
|
is given, it will open the complete file and run it (which may in turn open
|
|
other build files). Subtracting a build file will reverse all actions applied
|
|
by the given file. So "-@networking" will remove all the networking plugins,
|
|
and "-@ui" will remove the UI.
|
|
|
|
The core library is always included so does not have to be listed. The default
|
|
is to use the name 'ui'; if no commands are given, it will build the complete
|
|
build, including the UI.
|
|
|
|
Examples:
|
|
# Equivalent to +@complete
|
|
build.py
|
|
|
|
build.py +@complete
|
|
build.py +@complete -@networking
|
|
build.py +@complete -@ui
|
|
build.py --name custom +@manifests +@networking +../my_plugin.js
|
|
"""
|
|
|
|
import argparse
|
|
import logging
|
|
import os
|
|
import re
|
|
import shutil
|
|
|
|
import compiler
|
|
import generateLocalizations
|
|
import shakaBuildHelpers
|
|
|
|
|
|
shaka_version = shakaBuildHelpers.calculate_version()
|
|
|
|
common_closure_opts = [
|
|
'--jscomp_error=*',
|
|
|
|
# Turn off complaints like:
|
|
# "Private property foo_ is never modified, use the @const annotation"
|
|
'--jscomp_off=jsdocMissingConst',
|
|
|
|
# Turn off complaints like:
|
|
# "Object is a reference type with no nullability modifier that is
|
|
# explicitly set to null."
|
|
# and:
|
|
# "Property defineClass of type goog has been deprecated"
|
|
# Even the Closure Library's base.js doesn't pass these checks yet as of
|
|
# the 20200406 release.
|
|
'--jscomp_off=lintChecks',
|
|
'--jscomp_off=deprecated',
|
|
# Turn off complaints like:
|
|
# "Built-in 'Reflect.setPrototypeOf' not supported in output version es3."
|
|
'--jscomp_off=missingPolyfill',
|
|
'--extra_annotation_name=listens',
|
|
'--extra_annotation_name=exportDoc',
|
|
'--extra_annotation_name=exportInterface',
|
|
|
|
'--conformance_configs',
|
|
('%s/build/conformance.textproto' %
|
|
shakaBuildHelpers.cygwin_safe_path(shakaBuildHelpers.get_source_base())),
|
|
|
|
'--generate_exports',
|
|
]
|
|
common_closure_defines = [
|
|
'-D', 'COMPILED=true',
|
|
'-D', 'goog.ENABLE_DEBUG_LOADER=false',
|
|
]
|
|
|
|
debug_closure_opts = [
|
|
'-O', 'SIMPLE',
|
|
]
|
|
debug_closure_defines = [
|
|
'-D', 'goog.DEBUG=true',
|
|
'-D', 'goog.asserts.ENABLE_ASSERTS=true',
|
|
'-D', 'shaka.log.MAX_LOG_LEVEL=4', # shaka.log.Level.DEBUG
|
|
'-D', 'shaka.Player.version="%s-debug"' % shaka_version,
|
|
]
|
|
|
|
release_closure_opts = [
|
|
'-O', 'ADVANCED',
|
|
]
|
|
release_closure_defines = [
|
|
'-D', 'goog.DEBUG=false',
|
|
'-D', 'goog.asserts.ENABLE_ASSERTS=false',
|
|
'-D', 'shaka.log.MAX_LOG_LEVEL=0',
|
|
'-D', 'shaka.Player.version="%s"' % shaka_version,
|
|
]
|
|
|
|
|
|
class Build(object):
|
|
"""Defines a build that has been parsed from a build file.
|
|
|
|
This has exclude files even though it will not be used at the top-level. This
|
|
allows combining builds. A file will only exist in at most one set.
|
|
|
|
Members:
|
|
include - A set of files to include.
|
|
exclude - A set of files to remove.
|
|
"""
|
|
|
|
def __init__(self, include=None, exclude=None):
|
|
self.include = include or set()
|
|
self.exclude = exclude or set()
|
|
|
|
def _get_build_file_path(self, name, root):
|
|
"""Gets the full path to a build file, if it exists.
|
|
|
|
Args:
|
|
name: The string name to check.
|
|
root: The full path to the base directory.
|
|
|
|
Returns:
|
|
The full path to the build file, or None if not found.
|
|
"""
|
|
source_base = shakaBuildHelpers.get_source_base()
|
|
local_path = os.path.join(root, name)
|
|
build_path = os.path.join(source_base, 'build', 'types', name)
|
|
if (os.path.isfile(local_path) and os.path.isfile(build_path)
|
|
and local_path != build_path):
|
|
logging.error('Build file "%s" is ambiguous', name)
|
|
return None
|
|
elif os.path.isfile(local_path):
|
|
return local_path
|
|
elif os.path.isfile(build_path):
|
|
return build_path
|
|
else:
|
|
logging.error('Build file not found: %s', name)
|
|
return None
|
|
|
|
def _combine(self, other):
|
|
include_all = self.include | other.include
|
|
exclude_all = self.exclude | other.exclude
|
|
self.include = include_all - exclude_all
|
|
self.exclude = exclude_all - include_all
|
|
|
|
def reverse(self):
|
|
return Build(self.exclude, self.include)
|
|
|
|
def add_closure(self):
|
|
"""Adds the closure library and externs."""
|
|
# Add externs and closure dependencies.
|
|
self.include |= set(
|
|
[shakaBuildHelpers.get_closure_base_js_path()] +
|
|
shakaBuildHelpers.get_all_js_files('externs'))
|
|
|
|
def add_core(self):
|
|
"""Adds the core library."""
|
|
# Check that there are no files in 'core' that are removed
|
|
core_build = Build()
|
|
core_build.parse_build(['+@core'], os.getcwd())
|
|
core_files = core_build.include
|
|
if self.exclude & core_files:
|
|
logging.error('Cannot exclude files from core')
|
|
return False
|
|
self.include |= core_files
|
|
return True
|
|
|
|
def has_ui(self):
|
|
"""Returns True if the UI library is in the build."""
|
|
for path in self.include:
|
|
if 'ui' in path.split(os.path.sep):
|
|
return True
|
|
return False
|
|
|
|
def has_cast(self):
|
|
"""Returns True if the cast system is in the build."""
|
|
for path in self.include:
|
|
if 'cast' in path.split(os.path.sep):
|
|
return True
|
|
return False
|
|
|
|
def generate_localizations(self, locales, force):
|
|
localizations = compiler.GenerateLocalizations(locales)
|
|
localizations.generate(force)
|
|
self.include.add(os.path.abspath(localizations.output))
|
|
|
|
def parse_build(self, lines, root):
|
|
"""Parses a Build object from the given lines of commands.
|
|
|
|
This will recursively read and parse builds.
|
|
|
|
Args:
|
|
lines: An array of strings defining commands.
|
|
root: The full path to the base directory.
|
|
|
|
Returns:
|
|
True on success, False otherwise.
|
|
"""
|
|
for line in lines:
|
|
# Strip comments
|
|
try:
|
|
line = line[:line.index('#')]
|
|
except ValueError:
|
|
pass
|
|
|
|
# Strip whitespace and ignore empty lines.
|
|
line = line.strip()
|
|
if not line:
|
|
continue
|
|
|
|
if line[0] == '+':
|
|
is_neg = False
|
|
line = line[1:].strip()
|
|
elif line[0] == '-':
|
|
is_neg = True
|
|
line = line[1:].strip()
|
|
else:
|
|
logging.error('Operation (+/-) required')
|
|
return False
|
|
|
|
if line[0] == '@':
|
|
line = line[1:].strip()
|
|
|
|
build_path = self._get_build_file_path(line, root)
|
|
if not build_path:
|
|
return False
|
|
lines = shakaBuildHelpers.open_file(build_path).readlines()
|
|
sub_root = os.path.dirname(build_path)
|
|
|
|
# If this is a build file, then recurse and combine the builds.
|
|
sub_build = Build()
|
|
if not sub_build.parse_build(lines, sub_root):
|
|
return False
|
|
|
|
if is_neg:
|
|
self._combine(sub_build.reverse())
|
|
else:
|
|
self._combine(sub_build)
|
|
else:
|
|
if not os.path.isabs(line):
|
|
line = os.path.abspath(os.path.join(root, line))
|
|
if not os.path.isfile(line):
|
|
logging.error('Unable to find file: %s', line)
|
|
return False
|
|
|
|
if is_neg:
|
|
self.include.discard(line)
|
|
self.exclude.add(line)
|
|
else:
|
|
self.include.add(line)
|
|
self.exclude.discard(line)
|
|
|
|
return True
|
|
|
|
def build_library(self, name, langout, locales, force, is_debug):
|
|
"""Builds Shaka Player using the files in |self.include|.
|
|
|
|
Args:
|
|
name: The name of the build.
|
|
langout: Closure Compiler output language.
|
|
locales: A list of strings of locale identifiers.
|
|
force: True to rebuild, False to ignore if no changes are detected.
|
|
is_debug: True to compile for debugging, false for release.
|
|
|
|
Returns:
|
|
True on success; False on failure.
|
|
"""
|
|
self.add_closure()
|
|
if not self.add_core():
|
|
return False
|
|
if self.has_ui():
|
|
self.generate_localizations(locales, force)
|
|
# So that the UI will correctly build if the cast is disabled, add the
|
|
# dummy cast proxy.
|
|
if not self.has_cast():
|
|
self.include.add(os.path.abspath('conditional/dummy_cast_proxy.js'))
|
|
|
|
if is_debug:
|
|
name += '.debug'
|
|
|
|
build_name = 'shaka-player.' + name
|
|
closure = compiler.ClosureCompiler(self.include, build_name)
|
|
|
|
closure_opts = common_closure_opts + common_closure_defines
|
|
closure_opts += ['--language_out', langout]
|
|
if is_debug:
|
|
closure_opts += debug_closure_opts + debug_closure_defines
|
|
else:
|
|
closure_opts += release_closure_opts + release_closure_defines
|
|
|
|
if not closure.compile(closure_opts, force):
|
|
return False
|
|
|
|
source_base = shakaBuildHelpers.get_source_base()
|
|
|
|
# Don't pass local node modules to the extern generator. But don't simply
|
|
# exclude the string 'node_modules', either, since Shaka Player could be
|
|
# rebuilt after installing it as a node module.
|
|
node_modules_path = os.path.join(source_base, 'node_modules')
|
|
local_include = set([f for f in self.include if node_modules_path not in f])
|
|
extern_generator = compiler.ExternGenerator(local_include, build_name)
|
|
|
|
if not extern_generator.generate(force):
|
|
return False
|
|
|
|
generated_externs = [extern_generator.output]
|
|
shaka_externs = shakaBuildHelpers.get_all_js_files('externs')
|
|
if self.has_ui():
|
|
shaka_externs += shakaBuildHelpers.get_all_js_files('ui/externs')
|
|
ts_def_generator = compiler.TsDefGenerator(
|
|
generated_externs + shaka_externs, build_name)
|
|
|
|
if not ts_def_generator.generate(force):
|
|
return False
|
|
|
|
# Copy this file to dist/ where support.html can use it
|
|
shutil.copy(
|
|
os.path.join(source_base, 'test', 'test', 'cast-boot.js'),
|
|
os.path.join(source_base, 'dist', 'cast-boot.js'))
|
|
|
|
return True
|
|
|
|
|
|
def main(args):
|
|
parser = argparse.ArgumentParser(
|
|
description=__doc__,
|
|
formatter_class=argparse.RawDescriptionHelpFormatter)
|
|
|
|
parser.add_argument(
|
|
'--locales',
|
|
type=str,
|
|
nargs='+',
|
|
default=generateLocalizations.DEFAULT_LOCALES,
|
|
help='The list of locales to compile in (requires UI, default %(default)r)')
|
|
|
|
parser.add_argument(
|
|
'--force',
|
|
'-f',
|
|
help='Force building the library even if no files have changed.',
|
|
action='store_true')
|
|
|
|
parser.add_argument(
|
|
'--mode',
|
|
help='Specify which build mode to use.',
|
|
choices=['debug', 'release'],
|
|
default='release')
|
|
|
|
parser.add_argument(
|
|
'--debug',
|
|
help='Same as using "--mode debug".',
|
|
action='store_const',
|
|
dest='mode',
|
|
const='debug')
|
|
|
|
parser.add_argument(
|
|
'--name',
|
|
help='Set the name of the build. Uses "ui" if not given.',
|
|
type=str,
|
|
default='ui')
|
|
|
|
parser.add_argument(
|
|
'--langout',
|
|
help='Set closure compiler output language. Defaults to ECMASCRIPT5.',
|
|
type=str,
|
|
default='ECMASCRIPT5')
|
|
|
|
parsed_args, commands = parser.parse_known_args(args)
|
|
|
|
# Make the dist/ folder, ignore errors.
|
|
base = shakaBuildHelpers.get_source_base()
|
|
try:
|
|
os.mkdir(os.path.join(base, 'dist'))
|
|
except OSError:
|
|
pass
|
|
|
|
# Update node modules if needed.
|
|
if not shakaBuildHelpers.update_node_modules():
|
|
return 1
|
|
|
|
# If no commands are given then use complete by default.
|
|
if len(commands) == 0:
|
|
commands.append('+@complete')
|
|
|
|
logging.info('Compiling the library (%s, %s)...',
|
|
parsed_args.name, parsed_args.mode)
|
|
|
|
custom_build = Build()
|
|
|
|
if not custom_build.parse_build(commands, os.getcwd()):
|
|
return 1
|
|
|
|
name = parsed_args.name
|
|
langout = parsed_args.langout
|
|
locales = parsed_args.locales
|
|
force = parsed_args.force
|
|
is_debug = parsed_args.mode == 'debug'
|
|
|
|
if not custom_build.build_library(name, langout, locales, force, is_debug):
|
|
return 1
|
|
|
|
return 0
|
|
|
|
|
|
if __name__ == '__main__':
|
|
shakaBuildHelpers.run_main(main)
|