class FileSystemCombinedPackageFamilyResource(PackageFamilyResource): key = "filesystem.family.combined" repository_type = "filesystem" schema = Schema({ Optional("versions"): [ And(basestring, Use(Version)) ], Optional("version_overrides"): { And(basestring, Use(VersionRange)): dict } }) @property def ext(self): return self.get("ext") @property def filepath(self): filename = "%s.%s" % (self.name, self.ext) return os.path.join(self.location, filename) def _uri(self): return self.filepath def get_last_release_time(self): try: return os.path.getmtime(self.filepath) except OSError: return 0 def iter_packages(self): # unversioned package if config.allow_unversioned_packages and not self.versions: package = self._repository.get_resource( FileSystemCombinedPackageResource.key, location=self.location, name=self.name, ext=self.ext) yield package return # versioned packages for version in self.versions: package = self._repository.get_resource( FileSystemCombinedPackageResource.key, location=self.location, name=self.name, ext=self.ext, version=str(version)) yield package def _load(self): format_ = FileFormat[self.ext] data = load_from_file(self.filepath, format_) check_format_version(self.filepath, data) return data
def _to(value): if isinstance(value, dict): d = {} for k, v in value.iteritems(): if isinstance(k, basestring): k = Required(k) if required else Optional(k) d[k] = _to(v) if allow_custom_keys: d[Optional(basestring)] = modifier or object schema = Schema(d) elif modifier: schema = And(value, modifier) else: schema = value return schema
def extensible_schema_dict(schema_dict): """Create schema dict that allows arbitrary extra keys. This helps to keep newer configs or package definitions compatible with older rez versions, that may not support newer schema fields. """ result = {Optional(basestring): object} result.update(schema_dict) return result
from rez.package_resources_ import help_schema, _commands_schema from rez.package_repository import create_memory_package_repository from rez.packages_ import Package from rez.vendor.schema.schema import Schema, Optional, Or, Use, And from rez.vendor.version.version import Version from contextlib import contextmanager import os package_request_schema = Or(basestring, And(PackageRequest, Use(str))) package_schema = Schema({ Required("name"): basestring, Optional("base"): basestring, Optional("version"): Or(basestring, And(Version, Use(str))), Optional('description'): basestring, Optional('authors'): [basestring], Optional('requires'): [package_request_schema], Optional('build_requires'): [package_request_schema], Optional('private_build_requires'): [package_request_schema], Optional('variants'): [[package_request_schema]], Optional('uuid'): basestring, Optional('config'): dict, Optional('tools'): [basestring], Optional('help'): help_schema,
kitten=dict(obi=dict(colors=["black", "white"], male=True, age=1.0), scully=dict(colors=["tabby"], male=False, age=0.5), mordor=dict(colors=["black"], male=True, age="infinite")), # bad data puppy=dict(taco=dict(colors=["brown"], male=True, age=0.6, owner="joe.bloggs"), ringo=dict(colors=["white", "grey"], male=True, age=0.8))) pet_schema = Schema({ Required("name"): basestring, Required("colors"): And([basestring], Use(set)), Required("male"): bool, Required("age"): float, Optional("owner"): basestring }) class BasePetResource(Resource): schema_error = PetResourceError def __init__(self, variables=None): super(BasePetResource, self).__init__(variables) self.validations = {} # tracks validations def _validate_key(self, key, attr, key_schema): self.validations[key] = self.validations.get(key, 0) + 1 return self._validate_key_impl(key, attr, key_schema)
# requirements of all package-related resources # base_resource_schema_dict = {Required("name"): basestring} # package family # package_family_schema_dict = base_resource_schema_dict.copy() # schema common to both package and variant # tests_schema = Schema({ Optional(basestring): Or( Or(basestring, [basestring]), { "command": Or(basestring, [basestring]), Optional("requires"): [Or(PackageRequest, And(basestring, Use(PackageRequest)))] }) }) package_base_schema_dict = base_resource_schema_dict.copy() package_base_schema_dict.update({ # basics Optional("base"): basestring, Optional("version"):
'previous_revision'] version_schema = Or(basestring, And(Version, Use(str))) package_request_schema = Or(basestring, And(PackageRequest, Use(str))) source_code_schema = Or(SourceCode, And(basestring, Use(SourceCode))) # package serialisation schema package_serialise_schema = Schema({ Required("name"): basestring, Optional("version"): version_schema, Optional("description"): basestring, Optional("authors"): [basestring], Optional("tools"): [basestring], Optional('requires'): [package_request_schema], Optional('build_requires'): [package_request_schema], Optional('private_build_requires'): [package_request_schema], Optional('variants'): [[package_request_schema]], Optional('pre_commands'): source_code_schema, Optional('commands'): source_code_schema, Optional('post_commands'): source_code_schema, Optional("help"): help_schema, Optional("uuid"): basestring,
#------------------------------------------------------------------------------ # utility schemas #------------------------------------------------------------------------------ help_schema = Or( basestring, # single help entry [[basestring]]) # multiple help entries #------------------------------------------------------------------------------ # schema dicts #------------------------------------------------------------------------------ # requirements of all package-related resources base_resource_schema_dict = { Required("name"): basestring, Optional("nice_name"): basestring } # package family package_family_schema_dict = base_resource_schema_dict.copy() # schema common to both package and variant package_base_schema_dict = base_resource_schema_dict.copy() package_base_schema_dict.update({ # basics Optional("base"): basestring, Optional("version"): Version, Optional('description'): basestring,
'pre_commands', 'post_commands', 'help', 'config', 'uuid', 'timestamp', 'release_message', 'changelog', 'vcs', 'revision', 'previous_version', 'previous_revision', 'has_plugins', 'plugin_for', 'plugin_launch_commands' ] version_schema = Or(basestring, And(Version, Use(str))) package_request_schema = Or(basestring, And(PackageRequest, Use(str))) source_code_schema = Or(SourceCode, And(basestring, Use(SourceCode))) # package serialisation schema package_serialise_schema = Schema({ Required("name"): basestring, Optional("nice_name"): basestring, Optional("version"): version_schema, Optional("description"): basestring, Optional("authors"): [basestring], Optional("tools"): [basestring], Optional("tools_info"): dict, Optional("excluded_tools"): [basestring], Optional('requires'): [package_request_schema], Optional('build_requires'): [package_request_schema], Optional('private_build_requires'): [package_request_schema], Optional('variants'): [[package_request_schema]], Optional('has_plugins'):
from rez.package_repository import create_memory_package_repository from rez.packages_ import Package from rez.package_py_utils import expand_requirement from rez.vendor.schema.schema import Schema, Optional, Or, Use, And from rez.vendor.version.version import Version from contextlib import contextmanager import os # this schema will automatically harden request strings like 'python-*'; see # the 'expand_requires' function for more info. # package_request_schema = Or(And(basestring, Use(expand_requirement)), And(PackageRequest, Use(str))) tests_schema = Schema({ Optional(basestring): Or( Or(basestring, [basestring]), { "command": Or(basestring, [basestring]), Optional("requires"): [package_request_schema] }) }) package_schema = Schema({ Required("name"): basestring, Optional("base"): basestring, Optional("version"): Or(basestring, And(Version, Use(str))), Optional('description'):
class CommandReleaseHook(ReleaseHook): commands_schema = Schema({ "command": basestring, Optional("args"): Or(And(basestring, Use(lambda x: x.strip().split())), [basestring]), Optional("user"): basestring }) schema_dict = { "print_commands": bool, "print_output": bool, "print_error": bool, "cancel_on_error": bool, "stop_on_error": bool, "pre_build_commands": [commands_schema], "pre_release_commands": [commands_schema], "post_release_commands": [commands_schema] } @classmethod def name(cls): return "command" def __init__(self, source_path): super(CommandReleaseHook, self).__init__(source_path) def execute_command(self, cmd_name, cmd_arguments, user, errors): def _err(msg): errors.append(msg) if self.settings.print_error: print >> sys.stderr, msg def _execute(cmd, arguments): try: result = cmd(*(arguments or [])) if self.settings.print_output: print result.stdout.strip() except ErrorReturnCode as e: # `e` shows the command that was run msg = "command failed:\n%s" % str(e) _err(msg) return False return True if not os.path.isfile(cmd_name): cmd_full_path = which(cmd_name) else: cmd_full_path = cmd_name if not cmd_full_path: msg = "%s: command not found" % cmd_name _err(msg) return False run_cmd = Command(cmd_full_path) if user == 'root': with sudo: return _execute(run_cmd, cmd_arguments) elif user and user != getpass.getuser(): raise NotImplementedError # TODO else: return _execute(run_cmd, cmd_arguments) def _release(self, commands, errors=None): for conf in commands: if self.settings.print_commands or config.debug("package_release"): from subprocess import list2cmdline toks = [conf["command"]] + conf.get("args", []) msg = "running command: %s" % list2cmdline(toks) if self.settings.print_commands: print msg else: print_debug(msg) if not self.execute_command(cmd_name=conf.get("command"), cmd_arguments=conf.get("args"), user=conf.get("user"), errors=errors): if self.settings.stop_on_error: return def pre_build(self, user, install_path, **kwargs): errors = [] self._release(self.settings.pre_build_commands, errors=errors) if errors and self.settings.cancel_on_error: raise ReleaseHookCancellingError( "The following pre-build commands failed:\n%s" % '\n\n'.join(errors)) def pre_release(self, user, install_path, **kwargs): errors = [] self._release(self.settings.pre_release_commands, errors=errors) if errors and self.settings.cancel_on_error: raise ReleaseHookCancellingError( "The following pre-release commands failed:\n%s" % '\n\n'.join(errors)) def post_release(self, user, install_path, variants, **kwargs): self._release(self.settings.post_release_commands)
class CommandReleaseHook(ReleaseHook): commands_schema = Schema({ "command": basestring, Optional("args"): Or(And(basestring, Use(lambda x: x.strip().split())), [basestring]), Optional("pretty_args"): bool, Optional("user"): basestring, Optional("env"): dict }) schema_dict = { "print_commands": bool, "print_output": bool, "print_error": bool, "cancel_on_error": bool, "stop_on_error": bool, "pre_build_commands": [commands_schema], "pre_release_commands": [commands_schema], "post_release_commands": [commands_schema] } @classmethod def name(cls): return "command" def __init__(self, source_path): super(CommandReleaseHook, self).__init__(source_path) def execute_command(self, cmd_name, cmd_arguments, user, errors, env=None): def _err(msg): errors.append(msg) if self.settings.print_error: print(msg, file=sys.stderr) kwargs = {} if env: kwargs["env"] = env def _execute(commands): process = Popen(commands, stdout=PIPE, stderr=STDOUT, **kwargs) stdout, _ = process.communicate() if process.returncode != 0: msg = "command failed:\n%s" % stdout _err(msg) return False if self.settings.print_output: print(stdout.strip()) return True if not os.path.isfile(cmd_name): cmd_full_path = which(cmd_name) else: cmd_full_path = cmd_name if not cmd_full_path: msg = "%s: command not found" % cmd_name _err(msg) return False cmds = [cmd_full_path] + (cmd_arguments or []) if user == 'root': cmds = ['sudo'] + cmds return _execute(cmds) elif user and user != getpass.getuser(): raise NotImplementedError # TODO else: return _execute(cmds) def pre_build(self, user, install_path, variants=None, **kwargs): errors = [] self._execute_commands(self.settings.pre_build_commands, install_path=install_path, package=self.package, errors=errors, variants=variants) if errors and self.settings.cancel_on_error: raise ReleaseHookCancellingError( "The following pre-build commands failed:\n%s" % '\n\n'.join(errors)) def pre_release(self, user, install_path, variants=None, **kwargs): errors = [] self._execute_commands(self.settings.pre_release_commands, install_path=install_path, package=self.package, errors=errors, variants=variants) if errors and self.settings.cancel_on_error: raise ReleaseHookCancellingError( "The following pre-release commands failed:\n%s" % '\n\n'.join(errors)) def post_release(self, user, install_path, variants, **kwargs): # note that the package we use here is the *installed* package, not the # developer package (self.package). Otherwise, attributes such as 'root' # will be None errors = [] if variants: package = variants[0].parent else: package = self.package self._execute_commands(self.settings.post_release_commands, install_path=install_path, package=package, errors=errors, variants=variants) if errors: print_debug("The following post-release commands failed:\n" + '\n\n'.join(errors)) def _execute_commands(self, commands, install_path, package, errors=None, variants=None): release_dict = dict(path=install_path) variant_infos = [] if variants: for variant in variants: if isinstance(variant, (int, long)): variant_infos.append(variant) else: package = variant.parent var_dict = dict(variant.resource.variables) # using '%s' will preserve potential str/unicode nature var_dict['variant_requires'] = [ '%s' % x for x in variant.resource.variant_requires ] variant_infos.append(var_dict) formatter = scoped_formatter(system=system, release=release_dict, package=package, variants=variant_infos, num_variants=len(variant_infos)) for conf in commands: program = conf["command"] env_ = None env = conf.get("env") if env: env_ = os.environ.copy() env_.update(env) # If we have, ie, a list, and format_pretty is True, it will be printed # as "1 2 3" instead of "[1, 2, 3]" formatter.__dict__['format_pretty'] = conf.get("pretty_args", True) args = conf.get("args", []) args = [formatter.format(x) for x in args] args = [expandvars(x, environ=env_) for x in args] if self.settings.print_commands or config.debug("package_release"): from subprocess import list2cmdline toks = [program] + args msgs = [] msgs.append("running command: %s" % list2cmdline(toks)) if env: for key, value in env.iteritems(): msgs.append(" with: %s=%s" % (key, value)) if self.settings.print_commands: print('\n'.join(msgs)) else: for msg in msgs: print_debug(msg) if not self.execute_command(cmd_name=program, cmd_arguments=args, user=conf.get("user"), errors=errors, env=env_): if self.settings.stop_on_error: return
from rez.vendor.schema.schema import Schema, Optional, Or, Use, And from rez.vendor.six import six from rez.vendor.version.version import Version from contextlib import contextmanager import os basestring = six.string_types[0] # this schema will automatically harden request strings like 'python-*'; see # the 'expand_requires' function for more info. # package_request_schema = Or(And(basestring, Use(expand_requirement)), And(PackageRequest, Use(str))) tests_schema = Schema({ Optional(basestring): Or( Or(basestring, [basestring]), extensible_schema_dict({ "command": Or(basestring, [basestring]), Optional("requires"): [package_request_schema], Optional("run_on"): Or(basestring, [basestring]), Optional("on_variants"): Or(bool, { "type": "requires", "value": [package_request_schema] }) })) })
'release_message', 'changelog', 'vcs', 'revision', 'previous_version', 'previous_revision'] version_schema = Or(basestring, And(Version, Use(str))) package_request_schema = Or(basestring, And(PackageRequest, Use(str))) source_code_schema = Or(SourceCode, And(basestring, Use(SourceCode))) tests_schema = Schema({ Optional(basestring): Or( Or(basestring, [basestring]), extensible_schema_dict({ "command": Or(basestring, [basestring]), Optional("requires"): [package_request_schema], Optional("run_on"): Or(basestring, [basestring]), Optional("on_variants"): Or( bool, { "type": "requires", "value": [package_request_schema] } ) }) ) })
base_resource_schema_dict = { Required("name"): basestring } # package family # package_family_schema_dict = base_resource_schema_dict.copy() # schema common to both package and variant # tests_schema = Schema({ Optional(basestring): Or( Or(basestring, [basestring]), { "command": Or(basestring, [basestring]), Optional("requires"): [ Or(PackageRequest, And(basestring, Use(PackageRequest))) ] } ) }) package_base_schema_dict = base_resource_schema_dict.copy() package_base_schema_dict.update({ # basics Optional("base"): basestring, Optional("version"): Version,
'variants', 'commands', 'pre_commands', 'post_commands', 'help', 'config', 'uuid', 'timestamp', 'release_message', 'changelog', 'vcs', 'revision', 'previous_version', 'previous_revision' ] version_schema = Or(basestring, And(Version, Use(str))) package_request_schema = Or(basestring, And(PackageRequest, Use(str))) source_code_schema = Or(SourceCode, And(basestring, Use(SourceCode))) # package serialisation schema package_serialise_schema = Schema({ Required("name"): basestring, Optional("version"): version_schema, Optional("description"): basestring, Optional("authors"): [basestring], Optional("tools"): [basestring], Optional('requires'): [package_request_schema], Optional('build_requires'): [package_request_schema], Optional('private_build_requires'): [package_request_schema], Optional('variants'): [[package_request_schema]], Optional('pre_commands'): source_code_schema, Optional('commands'): source_code_schema, Optional('post_commands'): source_code_schema,
class CommandReleaseHook(ReleaseHook): commands_schema = Schema({ "command": basestring, Optional("args"): Or(And(basestring, Use(lambda x: x.strip().split())), [basestring]), Optional("user"): basestring, Optional("env"): dict }) schema_dict = { "print_commands": bool, "print_output": bool, "print_error": bool, "cancel_on_error": bool, "stop_on_error": bool, "pre_build_commands": [commands_schema], "pre_release_commands": [commands_schema], "post_release_commands": [commands_schema] } @classmethod def name(cls): return "command" def __init__(self, source_path): super(CommandReleaseHook, self).__init__(source_path) def execute_command(self, cmd_name, cmd_arguments, user, errors, env=None): def _err(msg): errors.append(msg) if self.settings.print_error: print >> sys.stderr, msg kwargs = {} if env: kwargs["_env"] = env def _execute(cmd, arguments): try: result = cmd(*(arguments or []), **kwargs) if self.settings.print_output: print result.stdout.strip() except ErrorReturnCode as e: # `e` shows the command that was run msg = "command failed:\n%s" % str(e) _err(msg) return False return True if not os.path.isfile(cmd_name): cmd_full_path = which(cmd_name) else: cmd_full_path = cmd_name if not cmd_full_path: msg = "%s: command not found" % cmd_name _err(msg) return False run_cmd = Command(cmd_full_path) if user == 'root': with sudo: return _execute(run_cmd, cmd_arguments) elif user and user != getpass.getuser(): raise NotImplementedError # TODO else: return _execute(run_cmd, cmd_arguments) def pre_build(self, user, install_path, **kwargs): errors = [] self._execute_commands(self.settings.pre_build_commands, install_path=install_path, package=self.package, errors=errors) if errors and self.settings.cancel_on_error: raise ReleaseHookCancellingError( "The following pre-build commands failed:\n%s" % '\n\n'.join(errors)) def pre_release(self, user, install_path, **kwargs): errors = [] self._execute_commands(self.settings.pre_release_commands, install_path=install_path, package=self.package, errors=errors) if errors and self.settings.cancel_on_error: raise ReleaseHookCancellingError( "The following pre-release commands failed:\n%s" % '\n\n'.join(errors)) def post_release(self, user, install_path, variants, **kwargs): # note that the package we use here is the *installed* package, not the # developer package (self.package). Otherwise, attributes such as 'root' # will be None errors = [] if variants: package = variants[0].parent else: package = self.package self._execute_commands(self.settings.post_release_commands, install_path=install_path, package=package, errors=errors) if errors: print_debug("The following post-release commands failed:\n" + '\n\n'.join(errors)) def _execute_commands(self, commands, install_path, package, errors=None): release_dict = dict(path=install_path) formatter = scoped_formatter(system=system, release=release_dict, package=package) for conf in commands: program = conf["command"] env_ = None env = conf.get("env") if env: env_ = os.environ.copy() env_.update(env) args = conf.get("args", []) args = [formatter.format(x) for x in args] args = [expandvars(x, environ=env_) for x in args] if self.settings.print_commands or config.debug("package_release"): from subprocess import list2cmdline toks = [program] + args msgs = [] msgs.append("running command: %s" % list2cmdline(toks)) if env: for key, value in env.iteritems(): msgs.append(" with: %s=%s" % (key, value)) if self.settings.print_commands: print '\n'.join(msgs) else: for msg in msgs: print_debug(msg) if not self.execute_command(cmd_name=program, cmd_arguments=args, user=conf.get("user"), errors=errors, env=env_): if self.settings.stop_on_error: return
from rez.packages_ import Package from rez.package_py_utils import expand_requirement from rez.vendor.schema.schema import Schema, Optional, Or, Use, And from rez.vendor.version.version import Version from contextlib import contextmanager import os # this schema will automatically harden request strings like 'python-*'; see # the 'expand_requires' function for more info. # package_request_schema = Or(And(basestring, Use(expand_requirement)), And(PackageRequest, Use(str))) tests_schema = Schema({ Optional(basestring): Or( Or(basestring, [basestring]), { "command": Or(basestring, [basestring]), Optional("requires"): [package_request_schema] } ) }) package_schema = Schema({ Optional("requires_rez_version"): And(basestring, Use(Version)), Required("name"): basestring, Optional("base"): basestring, Optional("version"): Or(basestring,
from rez.utils.formatting import PackageRequest from rez.utils.data_utils import AttrDictWrapper from rez.package_resources_ import help_schema, _commands_schema from rez.package_repository import create_memory_package_repository from rez.packages_ import Package from rez.vendor.schema.schema import Schema, Optional, Or, Use, And from rez.vendor.version.version import Version from contextlib import contextmanager import os package_request_schema = Or(basestring, And(PackageRequest, Use(str))) package_schema = Schema({ Required("name"): basestring, Optional("nice_name"): basestring, Optional("base"): basestring, Optional("version"): Or(basestring, And(Version, Use(str))), Optional('description'): basestring, Optional('authors'): [basestring], Optional('requires'): [package_request_schema], Optional('build_requires'): [package_request_schema], Optional('private_build_requires'): [package_request_schema], Optional('variants'): [[package_request_schema]], Optional('has_plugins'): bool, Optional('plugin_for'): [basestring],