def build(self, force=False): """Build the documentation. Args: force: Build the docs even if the inputs have not changed. Returns: True on success; False on failure. """ deps = self.source_files + [self.config_path] if not force and not _must_build(self.output, deps): return True base = _get_source_path('') # Wipe out any old docs. shutil.rmtree(os.path.join(base, 'docs', 'api'), ignore_errors=True) # Jsdoc expects to run from the base dir. with shakaBuildHelpers.InDir(base): jsdoc = shakaBuildHelpers.get_node_binary('jsdoc') cmd_line = jsdoc + ['-c', self.config_path] if shakaBuildHelpers.execute_get_code(cmd_line) != 0: return False return True
def lint(self, fix=False, force=False): """Run CSS linter checks on the files in |self.source_files|. Args: fix: If True, ask the linter to fix what errors it can automatically. force: Run linter checks even if the inputs have not changed. Returns: True on success; False on failure. """ deps = self.source_files + [self.config_path] if not force and not _must_build(self.output, deps): return True stylelint = shakaBuildHelpers.get_node_binary('stylelint') cmd_line = stylelint + ['--config', self.config_path ] + self.source_files # Disables globbing, since that messes up our nightly tests, and we don't # use it anyway. # This is currently a flag added in a fork we maintain, but there is a pull # request in progress for this. # See: https://github.com/stylelint/stylelint/issues/4193 cmd_line += ['--disable-globbing'] if fix: cmd_line += ['--fix'] if shakaBuildHelpers.execute_get_code(cmd_line) != 0: return False # Update the timestamp of the file that tracks when we last updated. _update_timestamp(self.output) return True
def lint(self, fix=False, force=False): """Run linter checks on the files in |self.source_files|. Args: fix: If True, ask the linter to fix what errors it can automatically. force: Run linter checks even if the inputs have not changed. Returns: True on success; False on failure. """ deps = self.source_files + [self.config_path] if not force and not _must_build(self.output, deps): return True eslint = shakaBuildHelpers.get_node_binary('eslint') cmd_line = eslint + ['--config', self.config_path] + self.source_files if fix: cmd_line += ['--fix'] if shakaBuildHelpers.execute_get_code(cmd_line) != 0: return False # TODO: Add back Closure Compiler Linter # Update the timestamp of the file that tracks when we last updated. _update_timestamp(self.output) return True
def lint(self, fix=False, force=False): """Run CSS linter checks on the files in |self.source_files|. Args: fix: If True, ask the linter to fix what errors it can automatically. force: Run linter checks even if the inputs have not changed. Returns: True on success; False on failure. """ deps = self.source_files + [self.config_path] if not force and not _must_build(self.output, deps): return True stylelint = shakaBuildHelpers.get_node_binary('stylelint') cmd_line = stylelint + [ '--config', self.config_path, # The "default ignores" is something like **/node_modules/**, which # means that if we run the build scripts from inside the installed node # modules of shaka-player, all our sources will be filtered out if we # don't disable the default ignores in stylelint. '--disable-default-ignores', ] + self.source_files if fix: cmd_line += ['--fix'] if shakaBuildHelpers.execute_get_code(cmd_line) != 0: return False # Update the timestamp of the file that tracks when we last updated. _update_timestamp(self.output) return True
def check_js_lint(): """Runs the JavaScript linter.""" # TODO: things not enforced: property doc requirements logging.info('Running eslint...') eslint = shakaBuildHelpers.get_node_binary('eslint') cmd_line = eslint + get_lint_files() return shakaBuildHelpers.execute_get_code(cmd_line) == 0
def check_js_lint(): """Runs the JavaScript linter.""" # TODO: things not enforced: property doc requirements logging.info('Running eslint...') eslint = shakaBuildHelpers.get_node_binary('eslint') cmd_line = eslint + get_lint_files() return shakaBuildHelpers.execute_get_code(cmd_line) == 0
def RunCommand(self, karma_conf): """Build a command and send it to Karma for execution. Uses |self.parsed_args| and |self.karma_config| to build and run a Karma command. """ if self.parsed_args.use_xvfb and not shakaBuildHelpers.is_linux(): logging.error('xvfb can only be used on Linux') return 1 if not shakaBuildHelpers.update_node_modules(): logging.error('Failed to update node modules') return 1 karma = shakaBuildHelpers.get_node_binary('karma') cmd = ['xvfb-run', '--auto-servernum' ] if self.parsed_args.use_xvfb else [] cmd += karma + ['start'] cmd += [karma_conf] if karma_conf else [] cmd += ['--settings', json.dumps(self.karma_config)] # There is no need to print a status here as the gendep and build # calls will print their own status updates. if self.parsed_args.build: if gendeps.main([]) != 0: logging.error('Failed to generate project dependencies') return 1 if build.main(['--force'] if self.parsed_args.force else []) != 0: logging.error('Failed to build project') return 1 # Before Running the command, print the command. if self.parsed_args.print_command: logging.info('Karma Run Command') logging.info('%s', cmd) # Run the command. results = [] for run in range(self.parsed_args.runs): logging.info('Running test (%d / %d, %d failed so far)...', run + 1, self.parsed_args.runs, len(results) - results.count(0)) results.append(shakaBuildHelpers.execute_get_code(cmd)) # Print a summary of the results. if self.parsed_args.runs > 1: logging.info('All runs completed. %d / %d runs passed.', results.count(0), len(results)) logging.info('Results (exit code): %r', results) else: logging.info('Run complete') logging.info('Result (exit code): %d', results[0]) return 0 if all(result == 0 for result in results) else 1
def build_docs(_): """Builds the source code documentation.""" logging.info('Building the docs...') base = shakaBuildHelpers.get_source_base() shutil.rmtree(os.path.join(base, 'docs', 'api'), ignore_errors=True) os.chdir(base) jsdoc = shakaBuildHelpers.get_node_binary('jsdoc') cmd_line = jsdoc + ['-c', 'docs/jsdoc.conf.json'] return shakaBuildHelpers.execute_get_code(cmd_line)
def RunCommand(self, karma_conf): """Build a command and send it to Karma for execution. Uses |self.parsed_args| and |self.karma_config| to build and run a Karma command. """ if self.parsed_args.use_xvfb and not shakaBuildHelpers.is_linux(): logging.error('xvfb can only be used on Linux') return 1 if not shakaBuildHelpers.update_node_modules(): logging.error('Failed to update node modules') return 1 karma = shakaBuildHelpers.get_node_binary('karma') cmd = ['xvfb-run', '--auto-servernum'] if self.parsed_args.use_xvfb else [] cmd += karma + ['start'] cmd += [karma_conf] if karma_conf else [] cmd += ['--settings', json.dumps(self.karma_config)] # There is no need to print a status here as the gendep and build # calls will print their own status updates. if self.parsed_args.build: if gendeps.gen_deps([]) != 0: logging.error('Failed to generate project dependencies') return 1 if build.main(['--force'] if self.parsed_args.force else []) != 0: logging.error('Failed to build project') return 1 # Before Running the command, print the command. if self.parsed_args.print_command: logging.info('Karma Run Command') logging.info('%s', cmd) # Run the command. results = [] for run in range(self.parsed_args.runs): logging.info('Running test (%d / %d)...', run + 1, self.parsed_args.runs) results.append(shakaBuildHelpers.execute_get_code(cmd)) # Print a summary of the results. if self.parsed_args.runs > 1: logging.info('All runs completed. %d / %d runs passed.', results.count(0), len(results)) logging.info('Results (exit code): %r', results) else: logging.info('Run complete') logging.info('Result (exit code): %d', results[0]) return 0 if all(result == 0 for result in results) else 1
def check_html_lint(_): """Runs the HTML linter over the HTML files. Returns: True on success, False on failure. """ logging.info('Running htmlhint...') htmlhint = shakaBuildHelpers.get_node_binary('htmlhint') base = shakaBuildHelpers.get_source_base() files = ['index.html', 'demo/index.html', 'support.html'] file_paths = [os.path.join(base, x) for x in files] config_path = os.path.join(base, '.htmlhintrc') cmd_line = htmlhint + ['--config=' + config_path] + file_paths return shakaBuildHelpers.execute_get_code(cmd_line) == 0
def check_html_lint(_): """Runs the HTML linter over the HTML files. Returns: True on success, False on failure. """ logging.info('Running htmlhint...') htmlhint = shakaBuildHelpers.get_node_binary('htmlhint') base = shakaBuildHelpers.get_source_base() files = ['index.html', 'demo/index.html', 'support.html'] file_paths = [os.path.join(base, x) for x in files] config_path = os.path.join(base, '.htmlhintrc') cmd_line = htmlhint + ['--config=' + config_path] + file_paths return shakaBuildHelpers.execute_get_code(cmd_line) == 0
def main(_): """Generates the uncompiled dependencies files.""" # Update node modules if needed. if not shakaBuildHelpers.update_node_modules(): return 1 logging.info('Generating Closure dependencies...') # Make the dist/ folder, ignore errors. base = shakaBuildHelpers.get_source_base() try: os.mkdir(os.path.join(base, 'dist')) except OSError: pass os.chdir(base) make_deps = shakaBuildHelpers.get_node_binary( 'google-closure-deps', 'closure-make-deps') try: cmd_line = make_deps + [ # Folders to search for sources using goog.require/goog.provide '-r', 'demo', 'lib', 'ui', 'third_party', # Individual files to add to those '-f', 'dist/locales.js', # The path to the folder containing the Closure library's base.js '--closure-path', 'node_modules/google-closure-library/closure/goog', ] deps = shakaBuildHelpers.execute_get_output(cmd_line) # This command doesn't use exit codes for some stupid reason. # TODO: Remove when https://github.com/google/closure-library/issues/1162 # is resolved and we have upgraded. if len(deps) == 0: return 1 with open(os.path.join(base, 'dist', 'deps.js'), 'wb') as f: f.write(deps) return 0 except subprocess.CalledProcessError as e: return e.returncode
def compile(self, force=False): """Compiles the main less file in |self.main_source_file| into the |self.output| css file. Args: force: Generate the output even if the inputs have not changed. Returns: True on success; False on failure. """ if not force and not _must_build(self.output, self.all_source_files): return True lessc = shakaBuildHelpers.get_node_binary('less', 'lessc') cmd_line = lessc + [self.main_source_file, self.output] if shakaBuildHelpers.execute_get_code(cmd_line) != 0: logging.error('Externs generation failed') return False return True
def lint(self, force=False): """Run HTML linter checks on the files in |self.source_files|. Args: force: Run linter checks even if the inputs have not changed. Returns: True on success; False on failure. """ deps = self.source_files + [self.config_path] if not force and not _must_build(self.output, deps): return True htmlhint = shakaBuildHelpers.get_node_binary('htmlhint') cmd_line = htmlhint + ['--config=' + self.config_path] + self.source_files if shakaBuildHelpers.execute_get_code(cmd_line) != 0: return False # Update the timestamp of the file that tracks when we last updated. _update_timestamp(self.output) return True
def compile(self, force=False): """Compiles the main less file in |self.main_source_file| into the |self.output| css file. Args: force: Generate the output even if the inputs have not changed. Returns: True on success; False on failure. """ if not force and not _must_build(self.output, self.all_source_files): return True lessc = shakaBuildHelpers.get_node_binary('less', 'lessc') less_options = [ # Enable the "clean-CSS" plugin to minify the output and strip out comments. '--clean-css', # Output a source map of the original CSS/less files. '--source-map=' + self.output + '.map', ] cmd_line = lessc + less_options + [self.main_source_file, self.output] if shakaBuildHelpers.execute_get_code(cmd_line) != 0: logging.error('CSS compilation failed') return False # We need to prepend the license header to the compiled CSS. with open(_get_source_path('build/license-header'), 'rb') as f: license_header = f.read() with open(self.output, 'rb') as f: contents = f.read() with open(self.output, 'wb') as f: f.write(license_header) f.write(contents) return True
def GenerateTsDefs(inputs, output): """Generates TypeScript defs from Closure externs. Args: inputs: A list of paths to Closure extern files. output: A path to a TypeScript def output file. """ clutz = shakaBuildHelpers.get_node_binary('@teppeis/clutz', 'clutz') command = clutz + [ '--closure_env', 'BROWSER', '--externs', ] + inputs + [ '-o', '-', ] # Get the output of Clutz, then transform it to make it independent of Clutz # and usable directly in TypeScript projects. contents = shakaBuildHelpers.execute_get_output(command) # Remove the prefix clutz puts on all namespaces. contents = contents.replace('\xe0\xb2\xa0_\xe0\xb2\xa0.clutz.', '') # Replace "GlobalObject" (from Clutz) with TypeScript-native "object". contents = re.sub(r'\bGlobalObject\b', 'object', contents) # Remove "Global" from Clutz's Global{Date,Element,Event,EventTarget} and use # their original definitions instead. contents = re.sub(r'\bGlobal(Date|Element|Event|EventTarget)\b', r'\1', contents) # Remove "protected", which appears on some fields, and is only supported on # methods. contents = re.sub(r'^\s*protected ', '', contents, flags=re.MULTILINE) # Clutz really likes EventTargets, so it wants IAdManager to extend it twice. contents = contents.replace('extends EventTarget extends EventTarget', 'extends EventTarget') # Some types allow you to return a Promise or nothing, but the Clutz output of # "Promise | null | undefined" doesn't work in TypeScript. We need to use # "Promise | void" instead. contents = contents.replace('| null | undefined', '| void') # shaka.util.Error extends Error and implements shaka.extern.Error, but this # confuses TypeScript when both are called "Error" in context of the namespace # declaration for "shaka.util". Therefore we need to declare this # "GlobalError" type, which is already referenced by Clutz but never defined. global_error_def = 'declare class GlobalError extends Error {}\n\n' contents = global_error_def + contents # There are some types that implement multiple interfaces, such as IReleasable # and Iteratable. Also, there are tools used inside Google that (for some # reason) want to convert TS defs _BACK_ into Closure Compiler externs. When # that happens, these multiple implementors generate externs with broken # @implements annotations. Since this team can't control that process or # those tools, we need to adjust our TS defs instead. In these particular # cases, thankfully, we can just remove the reference to the IReleasable # interface, which is not needed outside the library. # TODO: This only covers one very specific pattern, and could be brittle. contents = contents.replace('implements shaka.util.IReleasable , ', 'implements ') # Finally, Clutz includes a bunch of basic defs for a browser environment # generated from Closure compiler's builtins. Remove these. sections = re.split(r'\n(?=// Generated from .*)', contents) sections = filter( lambda s: not s.startswith('// Generated from externs.zip'), sections) contents = '\n'.join(sections) + '\n' license_header_path = os.path.join(shakaBuildHelpers.get_source_base(), 'build/license-header') with open(license_header_path, 'r') as f: license_header = f.read() with open(output, 'w') as f: f.write(license_header) f.write('\n') f.write(contents)