#!/usr/bin/env python3 # -*- coding: utf-8 -*- # ============================================================================== # Copyright and license info is available in the LICENSE file included with # the Server Deployment Package (SDP), and also available online: # https://swarm.workshop.perforce.com/projects/perforce-software-sdp/view/main/LICENSE # ------------------------------------------------------------------------------ """ NAME: ValidateContentFormat.py DESCRIPTION: This trigger is intended for file content validation as part of change-content trigger Works for YAML, XML - only checks files matching required file extensions - see below. To install, add a line to your Perforce triggers table like the following: validate-yaml change-content //....yaml "python /p4/common/bin/triggers/ValidateContentFormat.py -p %serverport% -u perforce --yaml %change% " validate-xml change-content //....xml "python /p4/common/bin/triggers/ValidateContentFormat.py -p %serverport% -u perforce --xml %change% " or (if server is standard SDP and has appropriate environment defaults for P4PORT and P4USER): validate-yaml change-content //....yaml "python /p4/common/bin/triggers/ValidateContentFormat.py --yaml %change% " validate-xml change-content //....xml "python /p4/common/bin/triggers/ValidateContentFormat.py --xml %change% " You may need to provide the full path to python executable, or edit the path to the trigger. Also, don't forget to make the file executable. """ # Python 2.7/3.3 compatibility. from __future__ import print_function import sys import re import os import P4Triggers import P4 import yaml import tempfile from lxml import etree def yaml_validator(fname): try: with open(fname, 'r') as f: content = yaml.load(f) return "" except Exception as e: return str(e) def xml_validator(fname): try: with open(fname, 'r') as f: doc = etree.parse(f) return "" except Exception as e: return str(e) # Regex extensions to search for in filenames file_extensions = {"yaml": ["\.yaml$", "\.yml$"], "xml": ["\.xml$"]} # Format validator file_validator = {"yaml": yaml_validator, "xml": xml_validator} class ValidateContentFormat(P4Triggers.P4Trigger): """See module doc string for details""" def __init__(self, *args, **kwargs): P4Triggers.P4Trigger.__init__(self, **kwargs) self.parse_args(__doc__, args) def add_parse_args(self, parser): """Specific args for this trigger - also calls super class to add common trigger args""" parser.add_argument('--yaml', default=False, action='store_true', help="Trigger validates YAML files") parser.add_argument('--xml', default=False, action='store_true', help="Trigger validates XML files") parser.add_argument('change', help="Change to process - %%change%% argument from triggers entry.") super(ValidateContentFormat, self).add_parse_args(parser) def run(self): """Runs trigger""" error_count = 0 try: self.logger.debug("ValidateContent trigger firing") self.setupP4() self.p4.connect() exts = "" if self.options.yaml: exts = file_extensions["yaml"] validator = file_validator["yaml"] elif self.options.xml: exts = file_extensions["xml"] validator = file_validator["xml"] change = self.getChange(self.options.change) for df in change.files: valid_ext = False fname = df.depotFile.lower() for ext in exts: if re.search(ext, fname): valid_ext = True break if not valid_ext: continue name_parts = df.depotFile.split("/") tfile = os.path.join(tempfile.gettempdir(), name_parts[-1]) self.logger.debug("Validating %s as local: %s" % (df.depotFile, tfile)) self.p4.run_print("-o", tfile, "%s@=%s" % (df.depotFile, self.options.change)) result = validator(tfile) self.logger.debug("Validated %s - result: %s" % (tfile, result)) if result: error_count += 1 msg = "Invalid format for %s\n%s" % (df.depotFile, result) self.logger.warning(msg) print(msg) if error_count: print("%d files failed" % error_count) return error_count except Exception: return self.reportException() if __name__ == '__main__': """ Main Program""" trigger = ValidateContentFormat(*sys.argv[1:]) sys.exit(trigger.run())