def run(self, path=None): '''Executes the given file within the sandbox, as well as everything pending from any other included file, and ensure the overall consistency of the executed script(s).''' if path: self.include_file(path) for option in six.itervalues(self._options): # All options must be referenced by some @depends function if option not in self._seen: raise ConfigureError( 'Option `%s` is not handled ; reference it with a @depends' % option.option) self._value_for(option) # All implied options should exist. for implied_option in self._implied_options: value = self._resolve(implied_option.value) if value is not None: # There are two ways to end up here: either the implied option # is unknown, or it's known but there was a dependency loop # that prevented the implication from being applied. option = self._options.get(implied_option.name) if not option: raise ConfigureError( '`%s`, emitted from `%s` line %d, is unknown.' % (implied_option.option, implied_option.caller[1], implied_option.caller[2])) # If the option is known, check that the implied value doesn't # conflict with what value was attributed to the option. option_value = self._value_for_option(option) if value != option_value: reason = implied_option.reason if isinstance(reason, Option): reason = self._raw_options.get(reason) or reason.option reason = reason.split('=', 1)[0] value = OptionValue.from_(value) raise InvalidOptionError( "'%s' implied by '%s' conflicts with '%s' from the %s" % (value.format(option.option), reason, option_value.format( option.option), option_value.origin)) # All options should have been removed (handled) by now. for arg in self._helper: without_value = arg.split('=', 1)[0] msg = 'Unknown option: %s' % without_value if self._help: self._logger.warning(msg) else: raise InvalidOptionError(msg) # Run the execution queue for func, args in self._execution_queue: func(*args) if self._help: with LineIO(self.log_impl.info) as out: self._help.usage(out)
def _value_for_option(self, option): implied = {} for implied_option in self._implied_options[:]: if implied_option.name not in (option.name, option.env): continue self._implied_options.remove(implied_option) if (implied_option.when and not self._value_for(implied_option.when)): continue value = self._resolve(implied_option.value, need_help_dependency=False) if value is not None: if isinstance(value, OptionValue): pass elif value is True: value = PositiveOptionValue() elif value is False or value == (): value = NegativeOptionValue() elif isinstance(value, types.StringTypes): value = PositiveOptionValue((value, )) elif isinstance(value, tuple): value = PositiveOptionValue(value) else: raise TypeError("Unexpected type: '%s'" % type(value).__name__) opt = value.format(implied_option.option) self._helper.add(opt, 'implied') implied[opt] = implied_option try: value, option_string = self._helper.handle(option) except ConflictingOptionError as e: reason = implied[e.arg].reason if isinstance(reason, Option): reason = self._raw_options.get(reason) or reason.option reason = reason.split('=', 1)[0] raise InvalidOptionError( "'%s' implied by '%s' conflicts with '%s' from the %s" % (e.arg, reason, e.old_arg, e.old_origin)) if option_string: self._raw_options[option] = option_string when = self._conditions.get(option) if (when and not self._value_for(when, need_help_dependency=True) and value is not None and value.origin != 'default'): if value.origin == 'environment': # The value we return doesn't really matter, because of the # requirement for @depends to have the same when. return None raise InvalidOptionError( '%s is not available in this configuration' % option_string.split('=', 1)[0]) return value
def _value_for_option(self, option): implied = {} for implied_option in self._implied_options[:]: if implied_option.name not in (option.name, option.env): continue self._implied_options.remove(implied_option) if (implied_option.when and not self._value_for(implied_option.when)): continue value = self._resolve(implied_option.value) if value is not None: value = OptionValue.from_(value) opt = value.format(implied_option.option) self._helper.add(opt, 'implied') implied[opt] = implied_option try: value, option_string = self._helper.handle(option) except ConflictingOptionError as e: reason = implied[e.arg].reason if isinstance(reason, Option): reason = self._raw_options.get(reason) or reason.option reason = reason.split('=', 1)[0] raise InvalidOptionError( "'%s' implied by '%s' conflicts with '%s' from the %s" % (e.arg, reason, e.old_arg, e.old_origin)) if value.origin == 'implied': recursed_value = getattr(self, '__value_for_option').get((option,)) if recursed_value is not None: _, filename, line, _, _, _ = implied[value.format(option.option)].caller raise ConfigureError( "'%s' appears somewhere in the direct or indirect dependencies when " "resolving imply_option at %s:%d" % (option.option, filename, line)) if option_string: self._raw_options[option] = option_string when = self._conditions.get(option) # If `when` resolves to a false-ish value, we always return None. # This makes option(..., when='--foo') equivalent to # option(..., when=depends('--foo')(lambda x: x)). if when and not self._value_for(when) and value is not None: # If the option was passed explicitly, we throw an error that # the option is not available. Except when the option was passed # from the environment, because that would be too cumbersome. if value.origin not in ('default', 'environment'): raise InvalidOptionError( '%s is not available in this configuration' % option_string.split('=', 1)[0]) self._logger.log(TRACE, '%r = None', option) return None self._logger.log(TRACE, '%r = %r', option, value) return value
def run(self, path): '''Executes the given file within the sandbox, and ensure the overall consistency of the executed script.''' self.exec_file(path) # All command line arguments should have been removed (handled) by now. for arg in self._helper: without_value = arg.split('=', 1)[0] if arg in self._implied_options: frameinfo, reason = self._implied_options[arg] raise ConfigureError( '`%s`, emitted from `%s` line `%d`, was not handled.' % (without_value, frameinfo[1], frameinfo[2])) raise InvalidOptionError('Unknown option: %s' % without_value) # All options must be referenced by some @depends function for option in self._options.itervalues(): if option not in self._seen: raise ConfigureError( 'Option `%s` is not handled ; reference it with a @depends' % option.option) if self._help: with LineIO(self.log_impl.info) as out: self._help.usage(out)
def _value_for_option(self, option): implied = {} for implied_option in self._implied_options[:]: if implied_option.name not in (option.name, option.env): continue self._implied_options.remove(implied_option) value = self._resolve(implied_option.value, need_help_dependency=False) if value is not None: if isinstance(value, OptionValue): pass elif value is True: value = PositiveOptionValue() elif value is False or value == (): value = NegativeOptionValue() elif isinstance(value, types.StringTypes): value = PositiveOptionValue((value,)) elif isinstance(value, tuple): value = PositiveOptionValue(value) else: raise TypeError("Unexpected type: '%s'" % type(value).__name__) opt = value.format(implied_option.option) self._helper.add(opt, 'implied') implied[opt] = implied_option try: value, option_string = self._helper.handle(option) except ConflictingOptionError as e: reason = implied[e.arg].reason if isinstance(reason, Option): reason = self._raw_options.get(reason) or reason.option reason = reason.split('=', 1)[0] raise InvalidOptionError( "'%s' implied by '%s' conflicts with '%s' from the %s" % (e.arg, reason, e.old_arg, e.old_origin)) if option_string: self._raw_options[option] = option_string return value
def run(self, path=None): '''Executes the given file within the sandbox, as well as everything pending from any other included file, and ensure the overall consistency of the executed script(s).''' if path: self.include_file(path) for option in self._options.itervalues(): # All options must be referenced by some @depends function if option not in self._seen: raise ConfigureError( 'Option `%s` is not handled ; reference it with a @depends' % option.option ) self._value_for(option) # All implied options should exist. for implied_option in self._implied_options: value = self._resolve(implied_option.value, need_help_dependency=False) if value is not None: raise ConfigureError( '`%s`, emitted from `%s` line %d, is unknown.' % (implied_option.option, implied_option.caller[1], implied_option.caller[2])) # All options should have been removed (handled) by now. for arg in self._helper: without_value = arg.split('=', 1)[0] msg = 'Unknown option: %s' % without_value if self._help: self._logger.warning(msg) else: raise InvalidOptionError(msg) # Run the execution queue for func, args in self._execution_queue: func(*args) if self._help: with LineIO(self.log_impl.info) as out: self._help.usage(out)
def option_impl(self, *args, **kwargs): '''Implementation of option() This function creates and returns an Option() object, passing it the resolved arguments (uses the result of functions when functions are passed). In most cases, the result of this function is not expected to be used. Command line argument/environment variable parsing for this Option is handled here. ''' args = [self._resolve(arg) for arg in args] kwargs = {k: self._resolve(v) for k, v in kwargs.iteritems()} option = Option(*args, **kwargs) if option.name in self._options: raise ConfigureError('Option `%s` already defined' % self._options[option.name].option) if option.env in self._options: raise ConfigureError('Option `%s` already defined' % self._options[option.env].option) if option.name: self._options[option.name] = option if option.env: self._options[option.env] = option try: value, option_string = self._helper.handle(option) except ConflictingOptionError as e: frameinfo, reason = self._implied_options[e.arg] raise InvalidOptionError( "'%s' implied by '%s' conflicts with '%s' from the %s" % (e.arg, reason, e.old_arg, e.old_origin)) if self._help: self._help.add(option) self._option_values[option] = value self._raw_options[option] = (option_string.split('=', 1)[0] if option_string else option_string) return option
def _value_for_option(self, option): implied = {} for implied_option in self._implied_options[:]: if implied_option.name not in (option.name, option.env): continue self._implied_options.remove(implied_option) if (implied_option.when and not self._value_for(implied_option.when)): continue value = self._resolve(implied_option.value) if value is not None: if isinstance(value, OptionValue): pass elif value is True: value = PositiveOptionValue() elif value is False or value == (): value = NegativeOptionValue() elif isinstance(value, types.StringTypes): value = PositiveOptionValue((value, )) elif isinstance(value, tuple): value = PositiveOptionValue(value) else: raise TypeError("Unexpected type: '%s'" % type(value).__name__) opt = value.format(implied_option.option) self._helper.add(opt, 'implied') implied[opt] = implied_option try: value, option_string = self._helper.handle(option) except ConflictingOptionError as e: reason = implied[e.arg].reason if isinstance(reason, Option): reason = self._raw_options.get(reason) or reason.option reason = reason.split('=', 1)[0] raise InvalidOptionError( "'%s' implied by '%s' conflicts with '%s' from the %s" % (e.arg, reason, e.old_arg, e.old_origin)) if option_string: self._raw_options[option] = option_string when = self._conditions.get(option) # If `when` resolves to a false-ish value, we always return None. # This makes option(..., when='--foo') equivalent to # option(..., when=depends('--foo')(lambda x: x)). if when and not self._value_for(when) and value is not None: # If the option was passed explicitly, we throw an error that # the option is not available. Except when the option was passed # from the environment, because that would be too cumbersome. if value.origin not in ('default', 'environment'): raise InvalidOptionError( '%s is not available in this configuration' % option_string.split('=', 1)[0]) return None return value