class RepoConfiguration(object): """ Read configuration from repository. """ DEFAULT_CONFIG = dedent("""\ [autorebuild] enabled = false """) def __init__(self, dir_path='', file_name=REPO_CONFIG_FILE): self._config_parser = ConfigParser() self.container = {} # Set default options self._config_parser.readfp(StringIO(self.DEFAULT_CONFIG)) config_path = os.path.join(dir_path, file_name) if os.path.exists(config_path): self._config_parser.read(config_path) file_path = os.path.join(dir_path, REPO_CONTAINER_CONFIG) if os.path.exists(file_path): with open(file_path) as f: self.container = (yaml.load(f) or {}) def is_autorebuild_enabled(self): return self._config_parser.getboolean('autorebuild', 'enabled')
def getboolean(self, section, option, retint=False): # pylint: disable=arguments-differ ret = ConfigParser.getboolean(self, section, option) if not retint: return ret return int(ret)
class RepoConfiguration(object): """ Read configuration from repository. """ DEFAULT_CONFIG = dedent("""\ [autorebuild] enabled = false """) def __init__(self, dir_path='', file_name=REPO_CONFIG_FILE, depth=None): self._config_parser = ConfigParser() self.container = {} self.depth = depth or 0 self.autorebuild = {} # Set default options self._config_parser.readfp(StringIO(self.DEFAULT_CONFIG)) # pylint: disable=W1505; py2 config_path = os.path.join(dir_path, file_name) if os.path.exists(config_path): self._config_parser.read(config_path) file_path = os.path.join(dir_path, REPO_CONTAINER_CONFIG) if os.path.exists(file_path): with open(file_path) as f: try: self.container = yaml.safe_load(f) or {} except yaml.scanner.ScannerError as e: msg = ('Failed to parse YAML file "{file}": {reason}' .format(file=REPO_CONTAINER_CONFIG, reason=e)) raise OsbsException(msg) # container values may be set to None container_compose = self.container.get('compose') or {} modules = container_compose.get('modules') or [] self.autorebuild = self.container.get('autorebuild') or {} self.container_module_specs = [] value_errors = [] for module in modules: try: self.container_module_specs.append(ModuleSpec.from_str(module)) except ValueError as e: value_errors.append(e) if value_errors: raise ValueError(value_errors) def is_autorebuild_enabled(self): return self._config_parser.getboolean('autorebuild', 'enabled')
def load(self): schemes = [defaultScheme] parser = ConfigParser() parser.read(settings.DASHBOARD_CONF) for option, default_value in defaultUIConfig.items(): if parser.has_option('ui', option): try: self.ui_config[option] = parser.getint('ui', option) except ValueError: self.ui_config[option] = parser.get('ui', option) else: self.ui_config[option] = default_value if parser.has_option('ui', 'automatic_variants'): self.ui_config['automatic_variants'] = parser.getboolean('ui', 'automatic_variants') else: self.ui_config['automatic_variants'] = True self.ui_config['keyboard_shortcuts'] = defaultKeyboardShortcuts.copy() if parser.has_section('keyboard-shortcuts'): self.ui_config['keyboard_shortcuts'].update( parser.items('keyboard-shortcuts') ) for section in parser.sections(): if section in ('ui', 'keyboard-shortcuts'): continue scheme = parser.get(section, 'scheme') fields = [] for match in fieldRegex.finditer(scheme): field = match.group(1) if parser.has_option(section, '%s.label' % field): label = parser.get(section, '%s.label' % field) else: label = field fields.append({ 'name' : field, 'label' : label }) schemes.append({ 'name' : section, 'pattern' : scheme, 'fields' : fields, }) self.schemes = schemes
def parse_config(config_file=DEFAULT_CONFIG_FILE): if not os.path.exists(config_file): config_dict = dict(DEFAULT_OPTIONS) config_dict['requirement_dev'] = config_dict['requirement'] return config_dict config_dict = {} config = ConfigParser(DEFAULT_OPTIONS) config.read(config_file) config_dict['requirement'] = config.get('pip-save', 'requirement') config_dict['use_compatible'] = config.getboolean('pip-save', 'use_compatible') config_dict['requirement_dev'] = config.get('pip-save', 'requirement_dev') return config_dict
def serve(args): config = ConfigParser({'port': '8080', 'db': None}) config.read([CONFIG_FILE]) port = int(args.port or int(config.get('app', 'port'))) view_path = getattr(args, 'view_path', None) controller_path = getattr(args, 'controller_path', None) if args.cdn is None: if config.has_option('app', 'cdn'): cdn = config.getboolean('app', 'cdn') else: cdn = True else: cdn = args.cdn server.serve(db=config.get('app', 'db'), port=port, verbose=args.verbose, view_path=view_path, controller_path=controller_path, cdn=cdn)
class RepoConfiguration(object): """ Read configuration from repository. """ DEFAULT_CONFIG = dedent("""\ [autorebuild] enabled = false """) def __init__(self, dir_path='', file_name=REPO_CONFIG_FILE): self._config_parser = ConfigParser() # Set default options self._config_parser.readfp(StringIO(self.DEFAULT_CONFIG)) config_path = os.path.join(dir_path, file_name) if os.path.exists(config_path): self._config_parser.read(config_path) def is_autorebuild_enabled(self): return self._config_parser.getboolean('autorebuild', 'enabled')
class SetupConfig(object): """Wrapper around the setup.cfg file if available. One reason is to cleanup setup.cfg from these settings:: [egg_info] tag_build = dev tag_svn_revision = true Another is for optional zest.releaser-specific settings:: [zest.releaser] no-input = yes """ config_filename = SETUP_CONFIG_FILE def __init__(self): """Grab the configuration (overridable for test purposes)""" # If there is a setup.cfg in the package, parse it if not os.path.exists(os.path.join(utils.PACKAGE_ROOT, self.config_filename)): self.config = None return self.config = ConfigParser() with codecs.open(self.config_filename, 'r', 'utf8') as fp: self.config.readfp(fp) def has_bad_commands(self): if self.config is None: return False if not self.config.has_section('egg_info'): # bail out early as the main section is not there return False bad = False # Check 1. if self.config.has_option('egg_info', 'tag_build'): # Might still be empty. value = self.config.get('egg_info', 'tag_build') if value: logger.warn("%s has [egg_info] tag_build set to %r", self.config_filename, value) bad = True # Check 2. if self.config.has_option('egg_info', 'tag_svn_revision'): if self.config.getboolean('egg_info', 'tag_svn_revision'): value = self.config.get('egg_info', 'tag_svn_revision') logger.warn("%s has [egg_info] tag_svn_revision set to %r", self.config_filename, value) bad = True return bad def fix_config(self): if not self.has_bad_commands(): logger.warn("Cannot fix already fine %s.", self.config_filename) return if self.config.has_option('egg_info', 'tag_build'): self.config.set('egg_info', 'tag_build', '') if self.config.has_option('egg_info', 'tag_svn_revision'): self.config.set('egg_info', 'tag_svn_revision', 'false') new_setup = open(self.config_filename, 'w') try: self.config.write(new_setup) finally: new_setup.close() logger.info("New setup.cfg contents:") print(''.join(open(self.config_filename).readlines())) def no_input(self): """Return whether the user wants to run in no-input mode. Enable this mode by adding a ``no-input`` option:: [zest.releaser] no-input = yes The default when this option has not been set is False. Standard config rules apply, so you can use upper or lower or mixed case and specify 0, false, no or off for boolean False, and 1, on, true or yes for boolean True. """ default = False if self.config is None: return default try: result = self.config.getboolean('zest.releaser', 'no-input') except (NoSectionError, NoOptionError, ValueError): return default return result def python_file_with_version(self): """Return Python filename with ``__version__`` marker, if configured. Enable this by adding a ``python-file-with-version`` option:: [zest.releaser] python-file-with-version = reinout/maurits.py Return None when nothing has been configured. """ default = None if self.config is None: return default try: result = self.config.get( 'zest.releaser', 'python-file-with-version') except (NoSectionError, NoOptionError, ValueError): return default return result
def loadini(struct, configfile): """Loads .ini configuration file and stores its values in struct""" config_path = os.path.expanduser(configfile) config = ConfigParser() defaults = { 'general': { 'arg_spec': True, 'auto_display_list': True, 'autocomplete_mode': default_completion, 'color_scheme': 'default', 'complete_magic_methods': True, 'dedent_after': 1, 'editor': os.environ.get('VISUAL', os.environ.get('EDITOR', 'vi')), 'flush_output': True, 'highlight_show_source': True, 'hist_duplicates': True, 'hist_file': '~/.pythonhist', 'hist_length': 100, 'paste_time': 0.02, 'pastebin_confirm': True, 'pastebin_expiry': '1week', 'pastebin_helper': '', 'pastebin_removal_url': 'https://bpaste.net/remove/$removal_id', 'pastebin_show_url': 'https://bpaste.net/show/$paste_id', 'pastebin_url': 'https://bpaste.net/json/new', 'save_append_py': False, 'single_undo_time': 1.0, 'syntax': True, 'tab_length': 4, 'unicode_box': True }, 'keyboard': { 'backspace': 'C-h', 'beginning_of_line': 'C-a', 'clear_line': 'C-u', 'clear_screen': 'C-l', 'clear_word': 'C-w', 'copy_clipboard': 'F10', 'cut_to_buffer': 'C-k', 'delete': 'C-d', 'down_one_line': 'C-n', 'edit_config': 'F3', 'edit_current_block': 'C-x', 'end_of_line': 'C-e', 'exit': '', 'external_editor': 'F7', 'help': 'F1', 'last_output': 'F9', 'left': 'C-b', 'pastebin': 'F8', 'reimport': 'F6', 'right': 'C-f', 'save': 'C-s', 'search': 'C-o', 'show_source': 'F2', 'suspend': 'C-z', 'toggle_file_watch': 'F5', 'transpose_chars': 'C-t', 'undo': 'C-r', 'up_one_line': 'C-p', 'yank_from_buffer': 'C-y' }, 'cli': { 'suggestion_width': 0.8, 'trim_prompts': False, }, 'curtsies': { 'list_above': False, 'right_arrow_completion': True, }} default_keys_to_commands = dict((value, key) for (key, value) in iteritems(defaults['keyboard'])) fill_config_with_default_values(config, defaults) if not config.read(config_path): # No config file. If the user has it in the old place then complain if os.path.isfile(os.path.expanduser('~/.bpython.ini')): sys.stderr.write("Error: It seems that you have a config file at " "~/.bpython.ini. Please move your config file to " "%s\n" % default_config_path()) sys.exit(1) def get_key_no_doublebind(command): default_commands_to_keys = defaults['keyboard'] requested_key = config.get('keyboard', command) try: default_command = default_keys_to_commands[requested_key] if (default_commands_to_keys[default_command] == config.get('keyboard', default_command)): setattr(struct, '%s_key' % default_command, '') except KeyError: pass return requested_key struct.config_path = config_path struct.dedent_after = config.getint('general', 'dedent_after') struct.tab_length = config.getint('general', 'tab_length') struct.auto_display_list = config.getboolean('general', 'auto_display_list') struct.syntax = config.getboolean('general', 'syntax') struct.arg_spec = config.getboolean('general', 'arg_spec') struct.paste_time = config.getfloat('general', 'paste_time') struct.single_undo_time = config.getfloat('general', 'single_undo_time') struct.highlight_show_source = config.getboolean('general', 'highlight_show_source') struct.hist_file = config.get('general', 'hist_file') struct.editor = config.get('general', 'editor') struct.hist_length = config.getint('general', 'hist_length') struct.hist_duplicates = config.getboolean('general', 'hist_duplicates') struct.flush_output = config.getboolean('general', 'flush_output') struct.pastebin_key = get_key_no_doublebind('pastebin') struct.copy_clipboard_key = get_key_no_doublebind('copy_clipboard') struct.save_key = get_key_no_doublebind('save') struct.search_key = get_key_no_doublebind('search') struct.show_source_key = get_key_no_doublebind('show_source') struct.suspend_key = get_key_no_doublebind('suspend') struct.toggle_file_watch_key = get_key_no_doublebind('toggle_file_watch') struct.undo_key = get_key_no_doublebind('undo') struct.reimport_key = get_key_no_doublebind('reimport') struct.up_one_line_key = get_key_no_doublebind('up_one_line') struct.down_one_line_key = get_key_no_doublebind('down_one_line') struct.cut_to_buffer_key = get_key_no_doublebind('cut_to_buffer') struct.yank_from_buffer_key = get_key_no_doublebind('yank_from_buffer') struct.clear_word_key = get_key_no_doublebind('clear_word') struct.backspace_key = get_key_no_doublebind('backspace') struct.clear_line_key = get_key_no_doublebind('clear_line') struct.clear_screen_key = get_key_no_doublebind('clear_screen') struct.delete_key = get_key_no_doublebind('delete') struct.left_key = get_key_no_doublebind('left') struct.right_key = get_key_no_doublebind('right') struct.end_of_line_key = get_key_no_doublebind('end_of_line') struct.beginning_of_line_key = get_key_no_doublebind('beginning_of_line') struct.transpose_chars_key = get_key_no_doublebind('transpose_chars') struct.clear_line_key = get_key_no_doublebind('clear_line') struct.clear_screen_key = get_key_no_doublebind('clear_screen') struct.exit_key = get_key_no_doublebind('exit') struct.last_output_key = get_key_no_doublebind('last_output') struct.edit_config_key = get_key_no_doublebind('edit_config') struct.edit_current_block_key = get_key_no_doublebind('edit_current_block') struct.external_editor_key = get_key_no_doublebind('external_editor') struct.help_key = get_key_no_doublebind('help') struct.pastebin_confirm = config.getboolean('general', 'pastebin_confirm') struct.pastebin_url = config.get('general', 'pastebin_url') struct.pastebin_show_url = config.get('general', 'pastebin_show_url') struct.pastebin_removal_url = config.get('general', 'pastebin_removal_url') struct.pastebin_expiry = config.get('general', 'pastebin_expiry') struct.pastebin_helper = config.get('general', 'pastebin_helper') struct.cli_suggestion_width = config.getfloat('cli', 'suggestion_width') struct.cli_trim_prompts = config.getboolean('cli', 'trim_prompts') struct.complete_magic_methods = config.getboolean('general', 'complete_magic_methods') struct.autocomplete_mode = config.get('general', 'autocomplete_mode') struct.save_append_py = config.getboolean('general', 'save_append_py') struct.curtsies_list_above = config.getboolean('curtsies', 'list_above') struct.curtsies_right_arrow_completion = \ config.getboolean('curtsies', 'right_arrow_completion') color_scheme_name = config.get('general', 'color_scheme') default_colors = { 'keyword': 'y', 'name': 'c', 'comment': 'b', 'string': 'm', 'error': 'r', 'number': 'G', 'operator': 'Y', 'punctuation': 'y', 'token': 'C', 'background': 'd', 'output': 'w', 'main': 'c', 'paren': 'R', 'prompt': 'c', 'prompt_more': 'g', 'right_arrow_suggestion': 'K', } if color_scheme_name == 'default': struct.color_scheme = default_colors else: struct.color_scheme = dict() theme_filename = color_scheme_name + '.theme' path = os.path.expanduser(os.path.join(get_config_home(), theme_filename)) try: load_theme(struct, path, struct.color_scheme, default_colors) except EnvironmentError: sys.stderr.write("Could not load theme '%s'.\n" % (color_scheme_name, )) sys.exit(1) # checks for valid key configuration this part still sucks for key in (struct.pastebin_key, struct.save_key): key_dispatch[key] # expand path of history file struct.hist_file = os.path.expanduser(struct.hist_file) # verify completion mode if struct.autocomplete_mode not in bpython.autocomplete.ALL_MODES: struct.autocomplete_mode = default_completion # set box drawing characters if config.getboolean('general', 'unicode_box') and supports_box_chars(): struct.left_border = u'│' struct.right_border = u'│' struct.top_border = u'─' struct.bottom_border = u'─' struct.left_bottom_corner = u'└' struct.right_bottom_corner = u'┘' struct.left_top_corner = u'┌' struct.right_top_corner = u'┐' else: struct.left_border = u'|' struct.right_border = u'|' struct.top_border = u'-' struct.bottom_border = u'-' struct.left_bottom_corner = u'+' struct.right_bottom_corner = u'+' struct.left_top_corner = u'+' struct.right_top_corner = u'+'
class Conf(object): """Base class for Python-AD tests.""" def __init__(self): fname = os.environ.get( 'PYAD_TEST_CONFIG', os.path.join(os.path.dirname(__file__), 'test.conf.example')) if fname is None: raise Error('Python-AD test configuration file not specified.') if not os.path.exists(fname): raise Error( 'Python-AD test configuration file {} does not exist.'.format( fname)) self.config = ConfigParser() self.config.read(fname) self.basedir = os.path.dirname(__file__) self._iptables = None self._domain = self.config.get('test', 'domain') self._tempfiles = [] enable_logging() self.readonly_ad_creds = None readonly_env = os.environ.get('PYAD_READONLY_CONFIG', None) if readonly_env: bits = readonly_env.rsplit('@', 1) if len(bits) == 2: creds, domain = bits bits = creds.split(':', 1) if len(bits) == 2: self._domain = domain self.readonly_ad_creds = bits elif self.config.getboolean('test', 'readonly_ad_tests'): self.readonly_ad_creds = [ config.get('test', 'ad_user_account'), config.get('test', 'ad_user_password'), ] def teardown(self): for fname in self._tempfiles: try: os.unlink(fname) except OSError: pass self._tempfiles = [] def tempfile(self, contents=None, remove=False): fd, name = tempfile.mkstemp() if contents: os.write(fd, dedent(contents)) elif remove: os.remove(name) os.close(fd) self._tempfiles.append(name) return name def read_file(self, fname): fname = os.path.join(self.basedir, fname) with open(fname, 'rb') as fin: buf = fin.read() return buf def require(self, ad_user=False, local_admin=False, ad_admin=False, firewall=False, expensive=False): if firewall: local_admin = True config = self.config if ad_user and not (self.readonly_ad_creds and all(self.readonly_ad_creds)): raise pytest.skip('test disabled by configuration') if local_admin: if not config.getboolean('test', 'intrusive_local_tests'): raise pytest.skip('test disabled by configuration') if not config.get('test', 'local_admin_account') or \ not config.get('test', 'local_admin_password'): raise pytest.skip( 'intrusive local tests enabled but no user/pw given') if ad_admin: if not config.getboolean('test', 'intrusive_ad_tests'): raise pytest.skip('test disabled by configuration') if not config.get('test', 'ad_admin_account') or \ not config.get('test', 'ad_admin_password'): raise pytest.skip( 'intrusive ad tests enabled but no user/pw given') if firewall and not self.iptables_supported: raise pytest.skip('iptables/conntrack not available') if expensive and not config.getboolean('test', 'expensive_tests'): raise pytest.skip('test disabled by configuration') def domain(self): return self._domain def ad_user_account(self): self.require(ad_user=True) return self.readonly_ad_creds[0] def ad_user_password(self): self.require(ad_user=True) return self.readonly_ad_creds[1] def local_admin_account(self): self.require(local_admin=True) return self.config.get('test', 'local_admin_account') def local_admin_password(self): self.require(local_admin=True) return self.config.get('test', 'local_admin_password') def ad_admin_account(self): self.require(ad_admin=True) return self.config.get('test', 'ad_admin_account') def ad_admin_password(self): self.require(ad_admin=True) return self.config.get('test', 'ad_admin_password') def execute_as_root(self, command): self.require(local_admin=True) child = pexpect.spawn('su -c "%s" %s' % (command, self.local_admin_account())) child.expect('.*:') child.sendline(self.local_admin_password()) child.expect(pexpect.EOF) assert not child.isalive() if child.exitstatus != 0: m = 'Root command exited with status %s' % child.exitstatus raise Error(m) return child.before def acquire_credentials(self, principal, password, ccache=None): if ccache is None: ccache = '' else: ccache = '-c %s' % ccache child = pexpect.spawn('kinit %s %s' % (principal, ccache)) child.expect(':') child.sendline(password) child.expect(pexpect.EOF) assert not child.isalive() if child.exitstatus != 0: m = 'Command kinit exited with status %s' % child.exitstatus raise Error(m) def list_credentials(self, ccache=None): if ccache is None: ccache = '' child = pexpect.spawn('klist %s' % ccache) try: child.expect('Ticket cache: ([a-zA-Z0-9_/.:-]+)\r\n') except pexpect.EOF: m = 'Command klist exited with status %s' % child.exitstatus raise Error(m) ccache = child.match.group(1) child.expect('Default principal: ([a-zA-Z0-9_/.:@-]+)\r\n') principal = child.match.group(1) creds = [] while True: i = child.expect(['\r\n', pexpect.EOF, '\d\d/\d\d/\d\d \d\d:\d\d:\d\d\s+' \ '\d\d/\d\d/\d\d \d\d:\d\d:\d\d\s+' \ '([a-zA-Z0-9_/.:@-]+)\r\n']) if i == 0: continue elif i == 1: break creds.append(child.match.group(1)) return ccache, principal, creds @property def iptables_supported(self): if self._iptables is None: try: self.execute_as_root('iptables -L -n') self.execute_as_root('conntrack -L') except Error: self._iptables = False else: self._iptables = True return self._iptables def remove_network_blocks(self): self.require(local_admin=True, firewall=True) self.execute_as_root('iptables -t nat -F') self.execute_as_root('conntrack -F') def block_outgoing_traffic(self, protocol, port): """Block outgoing traffic of type `protocol' with destination `port'.""" self.require(local_admin=True, firewall=True) # Unfortunately we cannot simply insert a rule like this: -A OUTPUT -m # udp -p udp--dport 389 -j DROP. If we do this the kernel code will # be smart and return an error when sending trying to connect or send # a datagram. In order realistically emulate a network failure we # instead redirect packets the discard port on localhost. This # complicates stopping the emulated failure though: merely flushling # the nat table is not enough. We also need to flush the conntrack # table that keeps state for NAT'ed connections even after the rule # that caused the NAT in the first place has been removed. self.execute_as_root( 'iptables -t nat -A OUTPUT -m %s -p %s --dport %d ' '-j DNAT --to-destination 127.0.0.1:9' % (protocol, protocol, port))
# parser .ini file try: cp = ConfigParser() cp.optionxform = str cp.readfp(open(inifile)) except: print("Error... problem parsing '%s' configuration file" % inifile, file=sys.stderr) sys.exit(1) if opts.runpath is not None: cp.set('analysis', 'run_dir', opts.runpath) # Check if we're running in automated mode or not try: automated = cp.getboolean('analysis', 'autonomous') except: automated = False # Check if configuration file says to submit the DAG submitdag = opts.condor_submit if not submitdag: try: submitdag = cp.getboolean('analysis', 'submit_dag') except: submitdag = False # Create DAG from ConfigParser object dag = knope.knopeDAG(cp, inifile, pulsarlist=opts.pulsarlist) if dag.error_code != 0: # check for any errors that occurred if dag.error_code in knope.KNOPE_ERROR.keys():
class RepoConfiguration(object): """ Read configuration from repository. """ DEFAULT_CONFIG = dedent("""\ [autorebuild] enabled = false """) def __init__(self, dir_path='', file_name=REPO_CONFIG_FILE, depth=None, git_uri=None, git_branch=None, git_ref=None): self._config_parser = ConfigParser() self.container = {} self.depth = depth or 0 self.autorebuild = {} # Keep track of the repo metadata in the repo configuration self.git_uri = git_uri self.git_branch = git_branch self.git_ref = git_ref self.dir_path = dir_path # Set default options self._config_parser.readfp(StringIO(self.DEFAULT_CONFIG)) # pylint: disable=W1505; py2 config_path = os.path.join(dir_path, file_name) if os.path.exists(config_path): self._config_parser.read(config_path) if self._check_repo_file_exists_with_expected_filename( expected_filename=REPO_CONTAINER_CONFIG, possible_filename_typos=REPO_CONTAINER_CONFIG_POSSIBLE_TYPOS): self._validate_container_config_file() self._check_repo_file_exists_with_expected_filename( expected_filename=REPO_CONTENT_SETS_FILE, possible_filename_typos=REPO_CONTENT_SETS_FILE_POSSIBLE_TYPOS) # container values may be set to None container_compose = self.container.get('compose') or {} modules = container_compose.get('modules') or [] self.autorebuild = self.container.get('autorebuild') or {} self.container_module_specs = [] value_errors = [] for module in modules: try: self.container_module_specs.append(ModuleSpec.from_str(module)) except ValueError as e: value_errors.append(e) if value_errors: raise ValueError(value_errors) flatpak = self.container.get('flatpak') or {} self.is_flatpak = bool(flatpak) self.flatpak_base_image = flatpak.get('base_image') self.flatpak_component = flatpak.get('component') self.flatpak_name = flatpak.get('name') def is_autorebuild_enabled(self): return self._config_parser.getboolean('autorebuild', 'enabled') def _check_repo_file_exists_with_expected_filename( self, expected_filename, possible_filename_typos): """ Checks if a file with given filename exists in repo :param str expected_filename: Expected filename to lookup in the repo :param set possible_filename_typos: Set of possible typos for expected_filename :return: boolean stating wheter expected_filename exists in repo :rtype bool :raises OsbsException: if any filename from possible_filename_typos exists in repo """ expected_file_path = os.path.join(self.dir_path, expected_filename) wrong_filename = '' for possible_filename_typo in possible_filename_typos: path = os.path.join(self.dir_path, possible_filename_typo) if os.path.exists(path): wrong_filename = possible_filename_typo break if os.path.exists(expected_file_path) and wrong_filename: msg = ( 'This repo contains both {expected_filename} and {wrong_filename} ' 'Please remove {wrong_filename}'.format( expected_filename=expected_filename, wrong_filename=wrong_filename)) raise OsbsException(msg) elif wrong_filename: msg = ( 'Repo contains wrong filename: {wrong_filename}, expected: {expected_filename}' .format(expected_filename=expected_filename, wrong_filename=wrong_filename)) raise OsbsException(msg) elif os.path.exists(expected_file_path): return True return False def _validate_container_config_file(self): try: container_config_path = os.path.join(self.dir_path, REPO_CONTAINER_CONFIG) self.container = read_yaml_from_file_path( container_config_path, 'schemas/container.json') or {} except Exception as e: msg = ( 'Failed to load or validate container file "{file}": {reason}'. format(file=container_config_path, reason=e)) raise OsbsException(msg)
class PypiConfig(object): """Wrapper around the pypi config file""" def __init__(self, config_filename=DIST_CONFIG_FILE, use_setup_cfg=True): """Grab the PyPI configuration. This is .pypirc in the home directory. It is overridable for test purposes. If there is a setup.cfg file in the current directory, we read it too. """ self.config_filename = config_filename self.use_setup_cfg = use_setup_cfg self.reload() def reload(self): """Load the config. Do the initial load of the config. Or reload it in case of problems: this is needed when a pypi upload fails, you edit the .pypirc file to fix the account settings, and tell release to retry the command. """ self._read_configfile(use_setup_cfg=self.use_setup_cfg) def _read_configfile(self, use_setup_cfg=True): """Read the PyPI config file and store it (when valid). Usually read the setup.cfg too. """ rc = self.config_filename if not os.path.isabs(rc): rc = os.path.join(os.path.expanduser('~'), self.config_filename) filenames = [rc] if use_setup_cfg: # If there is a setup.cfg in the package, parse it filenames.append('setup.cfg') files = [f for f in filenames if os.path.exists(f)] if not files: self.config = None return self.config = ConfigParser() for filename in files: with codecs.open(filename, 'r', 'utf8') as fp: self.config.readfp(fp) def is_pypi_configured(self): # Do we have configuration for releasing to at least one # pypi-compatible server? if self.config is None: return False return len(self.distutils_servers()) > 0 def get_server_config(self, server): """Get url, username, password for server. """ repository_url = DEFAULT_REPOSITORY username = None password = None if self.config.has_section(server): if self.config.has_option(server, 'repository'): repository_url = self.config.get(server, 'repository') if self.config.has_option(server, 'username'): username = self.config.get(server, 'username') if self.config.has_option(server, 'password'): password = self.config.get(server, 'password') if not username and self.config.has_option('server-login', 'username'): username = self.config.get('server-login', 'username') if not password and self.config.has_option('server-login', 'password'): password = self.config.get('server-login', 'password') return { 'repository_url': repository_url, 'username': username, 'password': password, } def distutils_servers(self): """Return a list of known distutils servers. If the config has an old pypi config, remove the default pypi server from the list. """ try: index_servers = self.config.get('distutils', 'index-servers').split() except (NoSectionError, NoOptionError): index_servers = [] if not index_servers: # If no distutils index-servers have been given, 'pypi' should be # the default. This is what twine does. if self.config.has_option('server-login', 'username'): # We have a username, so upload to pypi should work fine, even # when no explicit pypi section is in the file. return ['pypi'] # https://github.com/zestsoftware/zest.releaser/issues/199 index_servers = ['pypi'] # The servers all need to have a section in the config file. return [ server for server in index_servers if self.config.has_section(server) ] def want_release(self): """Does the user normally want to release this package. Some colleagues find it irritating to have to remember to answer the question "Check out the tag (for tweaks or pypi/distutils server upload)" with the non-default 'no' when in 99 percent of the cases they just make a release specific for a customer, so they always answer 'no' here. This is where an extra config option comes in handy: you can influence the default answer so you can just keep hitting 'Enter' until zest.releaser is done. Either in your ~/.pypirc or in a setup.cfg in a specific package, add this when you want the default answer to this question to be 'no': [zest.releaser] release = no The default when this option has not been set is True. Standard config rules apply, so you can use upper or lower or mixed case and specify 0, false, no or off for boolean False, and 1, on, true or yes for boolean True. """ return self._get_boolean('zest.releaser', 'release', default=True) def extra_message(self): """Return extra text to be added to commit messages. This can for example be used to skip CI builds. This at least works for Travis. See http://docs.travis-ci.com/user/how-to-skip-a-build/ Enable this mode by adding a ``extra-message`` option, either in the package you want to release, or in your ~/.pypirc:: [zest.releaser] extra-message = [ci skip] """ default = '' if self.config is None: return default try: result = self.config.get('zest.releaser', 'extra-message') except (NoSectionError, NoOptionError, ValueError): return default return result def create_wheel(self): """Should we create a Python wheel for this package? Either in your ~/.pypirc or in a setup.cfg in a specific package, add this when you want to create a Python wheel, next to a standard sdist: [zest.releaser] create-wheel = yes """ if not USE_WHEEL: # If the wheel package is not available, we obviously # cannot create wheels. return False return self._get_boolean('zest.releaser', 'create-wheel') def register_package(self): """Should we try to register this package with a package server? For the standard Python Package Index (PyPI), registering a package is no longer needed: this is done automatically when uploading a distribution for a package. In fact, trying to register may fail. See https://github.com/zestsoftware/zest.releaser/issues/191 So by default zest.releaser will no longer register a package. But you may be using your own package server, and registering may be wanted or even required there. In this case you will need to turn on the register function. In your setup.cfg or ~/.pypirc, use the following to ensure that register is called on the package server: [zest.releaser] register = yes Note that if you have specified multiple package servers, this option is used for all of them. There is no way to register and upload to server A, and only upload to server B. """ return self._get_boolean('zest.releaser', 'register') def no_input(self): """Return whether the user wants to run in no-input mode. Enable this mode by adding a ``no-input`` option:: [zest.releaser] no-input = yes The default when this option has not been set is False. """ return self._get_boolean('zest.releaser', 'no-input') def development_marker(self): """Return development marker to be appended in postrelease. Override the default ``.dev0`` in setup.cfg using a ``development-marker`` option:: [zest.releaser] development-marker = .dev1 Returns default of ``.dev0`` when nothing has been configured. """ default = '.dev0' if self.config is None: return default try: result = self.config.get('zest.releaser', 'development-marker') except (NoSectionError, NoOptionError, ValueError): return default return result def push_changes(self): """Return whether the user wants to push the changes to the remote. Configure this mode by adding a ``push-changes`` option:: [zest.releaser] push-changes = no The default when this option has not been set is True. """ return self._get_boolean('zest.releaser', 'push-changes', default=True) def less_zeroes(self): """Return whether the user prefers less zeroes at the end of a version. Configure this mode by adding a ``less-zeroes`` option:: [zest.releaser] less-zeroes = yes The default when this option has not been set is False. When set to true: - Instead of 1.3.0 we will suggest 1.3. - Instead of 2.0.0 we will suggest 2.0. This only makes sense for the bumpversion command. In the postrelease command we read this option too, but with the current logic it has no effect there. """ return self._get_boolean('zest.releaser', 'less-zeroes') def version_levels(self): """How many levels does the user prefer in a version number? Configure this mode by adding a ``version-levels`` option:: [zest.releaser] version-levels = 3 The default when this option has not been set is 0, which means: no preference, so use the length of the current number. This means when suggesting a next version after 1.2: - with levels=0 we will suggest 1.3: no change - with levels=1 we will still suggest 1.3, as we will not use this to remove numbers, only to add them - with levels=2 we will suggest 1.3 - with levels=3 we will suggest 1.2.1 If the current version number has more levels, we keep them. So next version for 1.2.3.4 with levels=1 is 1.2.3.5. Tweaking version-levels and less-zeroes should give you the version number strategy that you prefer. """ default = 0 if self.config is None: return default try: result = self.config.getint('zest.releaser', 'version-levels') except (NoSectionError, NoOptionError, ValueError): return default if result < 0: return default return result def _get_boolean(self, section, key, default=False): """Get a boolean from the config. Standard config rules apply, so you can use upper or lower or mixed case and specify 0, false, no or off for boolean False, and 1, on, true or yes for boolean True. """ result = default if self.config is not None: try: result = self.config.getboolean(section, key) except (NoSectionError, NoOptionError, ValueError): return result return result
class PypiConfig(object): """Wrapper around the pypi config file""" def __init__(self, config_filename=DIST_CONFIG_FILE, use_setup_cfg=True): """Grab the PyPI configuration. This is .pypirc in the home directory. It is overridable for test purposes. If there is a setup.cfg file in the current directory, we read it too. """ self.config_filename = config_filename self._read_configfile(use_setup_cfg=use_setup_cfg) def _read_configfile(self, use_setup_cfg=True): """Read the PyPI config file and store it (when valid). Usually read the setup.cfg too. """ rc = self.config_filename if not os.path.isabs(rc): rc = os.path.join(os.path.expanduser('~'), self.config_filename) filenames = [rc] if use_setup_cfg: # If there is a setup.cfg in the package, parse it filenames.append('setup.cfg') files = [f for f in filenames if os.path.exists(f)] if not files: self.config = None return self.config = ConfigParser() for filename in files: with codecs.open(filename, 'r', 'utf8') as fp: self.config.readfp(fp) def is_pypi_configured(self): # Do we have configuration for releasing to at least one # pypi-compatible server? if self.config is None: return False if self.is_old_pypi_config(): return True if self.is_new_pypi_config() and len(self.distutils_servers()) > 0: return True return False def is_old_pypi_config(self): if self.config is None: return False try: self.config.get('server-login', 'username') except (NoSectionError, NoOptionError): return False return True def is_new_pypi_config(self): try: self.config.get('distutils', 'index-servers') except (NoSectionError, NoOptionError): return False return True def distutils_servers(self): """Return a list of known distutils servers. If the config has an old pypi config, remove the default pypi server from the list. """ try: raw_index_servers = self.config.get('distutils', 'index-servers') except (NoSectionError, NoOptionError): return [] ignore_servers = [''] if self.is_old_pypi_config(): # We have already asked about uploading to pypi using the normal # upload. ignore_servers.append('pypi') # Yes, you can even have an old pypi config with a # [distutils] server list. index_servers = [ server.strip() for server in raw_index_servers.split('\n') if server.strip() not in ignore_servers] return index_servers def want_release(self): """Does the user normally want to release this package. Some colleagues find it irritating to have to remember to answer the question "Check out the tag (for tweaks or pypi/distutils server upload)" with the non-default 'no' when in 99 percent of the cases they just make a release specific for a customer, so they always answer 'no' here. This is where an extra config option comes in handy: you can influence the default answer so you can just keep hitting 'Enter' until zest.releaser is done. Either in your ~/.pypirc or in a setup.cfg in a specific package, add this when you want the default answer to this question to be 'no': [zest.releaser] release = no The default when this option has not been set is True. Standard config rules apply, so you can use upper or lower or mixed case and specify 0, false, no or off for boolean False, and 1, on, true or yes for boolean True. """ default = True if self.config is None: return default try: result = self.config.getboolean('zest.releaser', 'release') except (NoSectionError, NoOptionError, ValueError): return default return result def extra_message(self): """Return extra text to be added to commit messages. This can for example be used to skip CI builds. This at least works for Travis. See http://docs.travis-ci.com/user/how-to-skip-a-build/ Enable this mode by adding a ``extra-message`` option, either in the package you want to release, or in your ~/.pypirc:: [zest.releaser] extra-message = [ci skip] """ default = '' if self.config is None: return default try: result = self.config.get('zest.releaser', 'extra-message') except (NoSectionError, NoOptionError, ValueError): return default return result def create_wheel(self): """Should we create a Python wheel for this package? Either in your ~/.pypirc or in a setup.cfg in a specific package, add this when you want to create a Python wheel, next to a standard sdist: [zest.releaser] create-wheel = yes """ if not USE_WHEEL: # If the wheel package is not available, we obviously # cannot create wheels. return False default = False if self.config is None: return default try: result = self.config.getboolean('zest.releaser', 'create-wheel') except (NoSectionError, NoOptionError, ValueError): return default return result def no_input(self): """Return whether the user wants to run in no-input mode. Enable this mode by adding a ``no-input`` option:: [zest.releaser] no-input = yes The default when this option has not been set is False. Standard config rules apply, so you can use upper or lower or mixed case and specify 0, false, no or off for boolean False, and 1, on, true or yes for boolean True. """ default = False if self.config is None: return default try: result = self.config.getboolean('zest.releaser', 'no-input') except (NoSectionError, NoOptionError, ValueError): return default return result
def auth(self, username, password, nat=None, mtu=None, callback=None): """ Login to AniDB UDP API parameters: username - your anidb username password - your anidb password nat - if this is 1, response will have "address" in attributes with your "ip:port" (default:0) mtu - maximum transmission unit (max packet size) (default: 1400) """ # disabled, this code doesn't work with renovations # logging.debug("ok1") # if self.keepAlive: # logging.debug("ok2") # self._username = username # self._password = password # if self.is_alive() == False: # logging.debug("You wanted to keep this thing alive!") # if self._iamALIVE == False: # logging.info("Starting thread now...") # self.start() # self._iamALIVE = True # else: # logging.info("not starting thread seems like it is already running. this must be a _reAuthenticate") config = ConfigParser() config.read(self.SessionFile) needauth = False try: if config.getboolean('DEFAULT', 'loggedin'): self.lastCommandTime = config.getfloat('DEFAULT', 'lastcommandtime') timeelapsed = time() - self.lastCommandTime timeoutduration = timedelta(minutes=30).seconds if timeelapsed < timeoutduration: # we are logged in and within timeout so set up session key and assume valid self.link.session = config.get('DEFAULT', 'sessionkey') else: needauth = True else: needauth = True except: needauth = True if needauth: self.lastAuth = time() logging.debug('No valid session, so authenticating') try: self.handle(AuthCommand(username, password, 3, self.clientname, self.clientver, nat, 1, 'utf8', mtu), callback) except Exception as e: logging.debug('Auth command with exception %s', e) # we force a config file with logged out to ensure a known state if an exception occurs, forcing us to log in again config['DEFAULT'] = {'loggedin': 'yes', 'sessionkey': self.link.session, 'exception': str(e), 'lastcommandtime': repr(time())} with open(self.SessionFile, 'w') as configfile: config.write(configfile) return e logging.debug('Successfully authenticated and recording session details') config['DEFAULT'] = {'loggedin': 'yes', 'sessionkey': self.link.session, 'lastcommandtime': repr(time())} with open(self.SessionFile, 'w') as configfile: config.write(configfile) return
class PypiConfig(object): """Wrapper around the pypi config file""" def __init__(self, config_filename=DIST_CONFIG_FILE, use_setup_cfg=True): """Grab the PyPI configuration. This is .pypirc in the home directory. It is overridable for test purposes. If there is a setup.cfg file in the current directory, we read it too. """ self.config_filename = config_filename self._read_configfile(use_setup_cfg=use_setup_cfg) def _read_configfile(self, use_setup_cfg=True): """Read the PyPI config file and store it (when valid). Usually read the setup.cfg too. """ rc = self.config_filename if not os.path.isabs(rc): rc = os.path.join(os.path.expanduser('~'), self.config_filename) filenames = [rc] if use_setup_cfg: # If there is a setup.cfg in the package, parse it filenames.append('setup.cfg') files = [f for f in filenames if os.path.exists(f)] if not files: self.config = None return self.config = ConfigParser() for filename in files: with codecs.open(filename, 'r', 'utf8') as fp: self.config.readfp(fp) def is_pypi_configured(self): # Do we have configuration for releasing to at least one # pypi-compatible server? if self.config is None: return False if self.is_old_pypi_config(): return True if self.is_new_pypi_config() and len(self.distutils_servers()) > 0: return True return False def is_old_pypi_config(self): if self.config is None: return False try: self.config.get('server-login', 'username') except (NoSectionError, NoOptionError): return False return True def is_new_pypi_config(self): try: self.config.get('distutils', 'index-servers') except (NoSectionError, NoOptionError): return False return True def get_server_config(self, server): """Get url, username, password for server. """ repository_url = DEFAULT_REPOSITORY username = None password = None if self.config.has_section(server): if self.config.has_option(server, 'repository'): repository_url = self.config.get(server, 'repository') if self.config.has_option(server, 'username'): username = self.config.get(server, 'username') if self.config.has_option(server, 'password'): password = self.config.get(server, 'password') if not username and self.config.has_option('server-login', 'username'): username = self.config.get('server-login', 'username') if not password and self.config.has_option('server-login', 'password'): password = self.config.get('server-login', 'password') return { 'repository_url': repository_url, 'username': username, 'password': password, } def distutils_servers(self): """Return a list of known distutils servers. If the config has an old pypi config, remove the default pypi server from the list. """ try: raw_index_servers = self.config.get('distutils', 'index-servers') except (NoSectionError, NoOptionError): return [] ignore_servers = [''] if self.is_old_pypi_config(): # We have already asked about uploading to pypi using the normal # upload. ignore_servers.append('pypi') # Yes, you can even have an old pypi config with a # [distutils] server list. index_servers = [ server.strip() for server in raw_index_servers.split('\n') if server.strip() not in ignore_servers ] return index_servers def want_release(self): """Does the user normally want to release this package. Some colleagues find it irritating to have to remember to answer the question "Check out the tag (for tweaks or pypi/distutils server upload)" with the non-default 'no' when in 99 percent of the cases they just make a release specific for a customer, so they always answer 'no' here. This is where an extra config option comes in handy: you can influence the default answer so you can just keep hitting 'Enter' until zest.releaser is done. Either in your ~/.pypirc or in a setup.cfg in a specific package, add this when you want the default answer to this question to be 'no': [zest.releaser] release = no The default when this option has not been set is True. Standard config rules apply, so you can use upper or lower or mixed case and specify 0, false, no or off for boolean False, and 1, on, true or yes for boolean True. """ default = True if self.config is None: return default try: result = self.config.getboolean('zest.releaser', 'release') except (NoSectionError, NoOptionError, ValueError): return default return result def extra_message(self): """Return extra text to be added to commit messages. This can for example be used to skip CI builds. This at least works for Travis. See http://docs.travis-ci.com/user/how-to-skip-a-build/ Enable this mode by adding a ``extra-message`` option, either in the package you want to release, or in your ~/.pypirc:: [zest.releaser] extra-message = [ci skip] """ default = '' if self.config is None: return default try: result = self.config.get('zest.releaser', 'extra-message') except (NoSectionError, NoOptionError, ValueError): return default return result def create_wheel(self): """Should we create a Python wheel for this package? Either in your ~/.pypirc or in a setup.cfg in a specific package, add this when you want to create a Python wheel, next to a standard sdist: [zest.releaser] create-wheel = yes """ if not USE_WHEEL: # If the wheel package is not available, we obviously # cannot create wheels. return False default = False if self.config is None: return default try: result = self.config.getboolean('zest.releaser', 'create-wheel') except (NoSectionError, NoOptionError, ValueError): return default return result def no_input(self): """Return whether the user wants to run in no-input mode. Enable this mode by adding a ``no-input`` option:: [zest.releaser] no-input = yes The default when this option has not been set is False. Standard config rules apply, so you can use upper or lower or mixed case and specify 0, false, no or off for boolean False, and 1, on, true or yes for boolean True. """ default = False if self.config is None: return default try: result = self.config.getboolean('zest.releaser', 'no-input') except (NoSectionError, NoOptionError, ValueError): return default return result
def read_config(filenames=SEARCH_PATH): """Attempt to read local configuration files to determine spalloc client settings. Parameters ---------- filenames : [str, ...] Filenames to attempt to read. Later config file have higher priority. Returns ------- dict The configuration loaded. """ parser = ConfigParser() # Set default config values (NB: No read_dict in Python 2.7) parser.add_section("spalloc") for key, value in iteritems({"port": "22244", "keepalive": "60.0", "reconnect_delay": "5.0", "timeout": "5.0", "machine": "None", "tags": "None", "min_ratio": "0.333", "max_dead_boards": "0", "max_dead_links": "None", "require_torus": "False"}): parser.set("spalloc", key, value) # Attempt to read from each possible file location in turn for filename in filenames: try: with open(filename, "r") as f: parser.readfp(f, filename) except (IOError, OSError): # File did not exist, keep trying pass cfg = {} try: cfg["hostname"] = parser.get("spalloc", "hostname") except NoOptionError: cfg["hostname"] = None cfg["port"] = parser.getint("spalloc", "port") try: cfg["owner"] = parser.get("spalloc", "owner") except NoOptionError: cfg["owner"] = None if parser.get("spalloc", "keepalive") == "None": cfg["keepalive"] = None else: cfg["keepalive"] = parser.getfloat("spalloc", "keepalive") cfg["reconnect_delay"] = parser.getfloat("spalloc", "reconnect_delay") if parser.get("spalloc", "timeout") == "None": cfg["timeout"] = None else: cfg["timeout"] = parser.getfloat("spalloc", "timeout") if parser.get("spalloc", "machine") == "None": cfg["machine"] = None else: cfg["machine"] = parser.get("spalloc", "machine") if parser.get("spalloc", "tags") == "None": cfg["tags"] = None else: cfg["tags"] = list(map(str.strip, parser.get("spalloc", "tags").split(","))) cfg["min_ratio"] = parser.getfloat("spalloc", "min_ratio") if parser.get("spalloc", "max_dead_boards") == "None": cfg["max_dead_boards"] = None else: cfg["max_dead_boards"] = parser.getint("spalloc", "max_dead_boards") if parser.get("spalloc", "max_dead_links") == "None": cfg["max_dead_links"] = None else: cfg["max_dead_links"] = parser.getint("spalloc", "max_dead_links") cfg["require_torus"] = parser.getboolean("spalloc", "require_torus") return cfg
class SetupConfig(object): """Wrapper around the setup.cfg file if available. One reason is to cleanup setup.cfg from these settings:: [egg_info] tag_build = dev tag_svn_revision = true Another is for optional zest.releaser-specific settings:: [zest.releaser] python-file-with-version = reinout/maurits.py """ config_filename = SETUP_CONFIG_FILE def __init__(self): """Grab the configuration (overridable for test purposes)""" # If there is a setup.cfg in the package, parse it if not os.path.exists(self.config_filename): self.config = None return self.config = ConfigParser() with codecs.open(self.config_filename, 'r', 'utf8') as fp: self.config.readfp(fp) def development_marker(self): """Return development marker to be appended in postrelease Override the default ``.dev0`` in setup.cfg using a ``development-marker`` option:: [zest.releaser] development-marker = .dev1 Returns default of `.dev0` when nothing has been configured. """ try: result = self.config.get('zest.releaser', 'development-marker') except (NoSectionError, NoOptionError, ValueError): result = ".dev0" return result def has_bad_commands(self): if self.config is None: return False if not self.config.has_section('egg_info'): # bail out early as the main section is not there return False bad = False # Check 1. if self.config.has_option('egg_info', 'tag_build'): # Might still be empty. value = self.config.get('egg_info', 'tag_build') if value: logger.warn("%s has [egg_info] tag_build set to %r", self.config_filename, value) bad = True # Check 2. if self.config.has_option('egg_info', 'tag_svn_revision'): if self.config.getboolean('egg_info', 'tag_svn_revision'): value = self.config.get('egg_info', 'tag_svn_revision') logger.warn("%s has [egg_info] tag_svn_revision set to %r", self.config_filename, value) bad = True return bad def fix_config(self): if not self.has_bad_commands(): logger.warn("Cannot fix already fine %s.", self.config_filename) return if self.config.has_option('egg_info', 'tag_build'): self.config.set('egg_info', 'tag_build', '') if self.config.has_option('egg_info', 'tag_svn_revision'): self.config.set('egg_info', 'tag_svn_revision', 'false') new_setup = open(self.config_filename, 'w') try: self.config.write(new_setup) finally: new_setup.close() logger.info("New setup.cfg contents:") print(''.join(open(self.config_filename).readlines())) def python_file_with_version(self): """Return Python filename with ``__version__`` marker, if configured. Enable this by adding a ``python-file-with-version`` option:: [zest.releaser] python-file-with-version = reinout/maurits.py Return None when nothing has been configured. """ default = None if self.config is None: return default try: result = self.config.get( 'zest.releaser', 'python-file-with-version') except (NoSectionError, NoOptionError, ValueError): return default return result
def ini_read(config_file): def strip_item(l): return [x.strip() for x in l] cfg = ConfigParser() cfg.read(config_file) log = {} log['file'] = cfg.get('log', 'file') log['level'] = cfg.getint('log', 'level') server = {} server['protocols'] = strip_item(cfg.get('server', 'protocols').split(',')) server['listen_ip'] = cfg.get('server', 'listen_ip') server['listen_port'] = cfg.getint('server', 'listen_port') server['search'] = strip_item(cfg.get('server', 'search').split(',')) server['allowed_hosts'] = strip_item(cfg.get('server', 'allowed_hosts').split(',')) smartdns = {} smartdns['rules'] = [] for rule in strip_item(cfg.get('smartdns', 'rules').split(',')): section = 'rules_' + rule smartdns['rules'].append({ 'name': rule, 'url': cfg.get(section, 'url'), 'proxy': cfg.getboolean(section, 'proxy'), 'refresh': cfg.getint(section, 'refresh'), 'dns': strip_item(cfg.get(section, 'dns').split(',')), }) smartdns['hack_srv'] = strip_item(cfg.get('smartdns', 'hack_srv').split(',')) section = 'bogus_nxdomain' smartdns['bogus_nxdomain'] = { 'url': cfg.get(section, 'url'), 'proxy': cfg.getboolean(section, 'proxy'), 'refresh': cfg.getint(section, 'refresh'), 'hack_ip': cfg.get(section, 'hack_ip'), } section = 'proxy' smartdns['proxy'] = { 'type': cfg.get(section, 'type'), 'ip': cfg.get(section, 'ip'), 'port': cfg.getint(section, 'port'), } smartdns['upstreams'] = {} names = set() for rule in smartdns['rules']: names |= set(rule['dns']) for name in names: section = 'dns_' + name.strip() smartdns['upstreams'][name] = { 'ip': cfg.get(section, 'ip').split(','), 'port': cfg.getint(section, 'port'), 'timeout': cfg.getint(section, 'timeout'), 'proxy': cfg.getboolean(section, 'proxy'), 'tcp': cfg.getboolean(section, 'tcp'), 'priority': cfg.getint(section, 'priority'), } domains = [] for name in strip_item(cfg.get('domains', 'domain').split(',')): section = 'domain_' + name domains.append({ 'name': cfg.get(section, 'name'), 'url': cfg.get(section, 'url'), 'proxy': cfg.getboolean(section, 'proxy'), 'type': cfg.get(section, 'type'), 'refresh': cfg.getint(section, 'refresh'), }) config = { 'log': log, 'server': server, 'smartdns': smartdns, 'domains': domains, } return config
def loadini(struct, configfile): """Loads .ini configuration file and stores its values in struct""" config_path = os.path.expanduser(configfile) config = ConfigParser() defaults = { "general": { "arg_spec": True, "auto_display_list": True, "autocomplete_mode": default_completion, "color_scheme": "default", "complete_magic_methods": True, "dedent_after": 1, "default_autoreload": False, "editor": os.environ.get("VISUAL", os.environ.get("EDITOR", "vi")), "flush_output": True, "highlight_show_source": True, "hist_duplicates": True, "hist_file": "~/.pythonhist", "hist_length": 1000, "paste_time": 0.02, "pastebin_confirm": True, "pastebin_expiry": "1week", "pastebin_helper": "", "pastebin_url": "https://bpaste.net", "save_append_py": False, "single_undo_time": 1.0, "syntax": True, "tab_length": 4, "unicode_box": True, }, "keyboard": { "backspace": "C-h", "beginning_of_line": "C-a", "clear_line": "C-u", "clear_screen": "C-l", "clear_word": "C-w", "copy_clipboard": "F10", "cut_to_buffer": "C-k", "delete": "C-d", "down_one_line": "C-n", "edit_config": "F3", "edit_current_block": "C-x", "end_of_line": "C-e", "exit": "", "external_editor": "F7", "help": "F1", "incremental_search": "M-s", "last_output": "F9", "left": "C-b", "pastebin": "F8", "reimport": "F6", "reverse_incremental_search": "M-r", "right": "C-f", "save": "C-s", "search": "C-o", "show_source": "F2", "suspend": "C-z", "toggle_file_watch": "F5", "transpose_chars": "C-t", "undo": "C-r", "up_one_line": "C-p", "yank_from_buffer": "C-y", }, "cli": { "suggestion_width": 0.8, "trim_prompts": False, }, "curtsies": { "list_above": False, "right_arrow_completion": True, }, } default_keys_to_commands = dict( (value, key) for (key, value) in iteritems(defaults["keyboard"])) fill_config_with_default_values(config, defaults) try: if not config.read(config_path): # No config file. If the user has it in the old place then complain if os.path.isfile(os.path.expanduser("~/.bpython.ini")): sys.stderr.write( "Error: It seems that you have a config file at " "~/.bpython.ini. Please move your config file to " "%s\n" % default_config_path()) sys.exit(1) except UnicodeDecodeError as e: sys.stderr.write( "Error: Unable to parse config file at '{}' due to an " "encoding issue. Please make sure to fix the encoding " "of the file or remove it and then try again.\n".format( config_path)) sys.exit(1) def get_key_no_doublebind(command): default_commands_to_keys = defaults["keyboard"] requested_key = config.get("keyboard", command) try: default_command = default_keys_to_commands[requested_key] if default_commands_to_keys[default_command] == config.get( "keyboard", default_command): setattr(struct, "%s_key" % default_command, "") except KeyError: pass return requested_key struct.config_path = config_path struct.dedent_after = config.getint("general", "dedent_after") struct.tab_length = config.getint("general", "tab_length") struct.auto_display_list = config.getboolean("general", "auto_display_list") struct.syntax = config.getboolean("general", "syntax") struct.arg_spec = config.getboolean("general", "arg_spec") struct.paste_time = config.getfloat("general", "paste_time") struct.single_undo_time = config.getfloat("general", "single_undo_time") struct.highlight_show_source = config.getboolean("general", "highlight_show_source") struct.hist_file = config.get("general", "hist_file") struct.editor = config.get("general", "editor") struct.hist_length = config.getint("general", "hist_length") struct.hist_duplicates = config.getboolean("general", "hist_duplicates") struct.flush_output = config.getboolean("general", "flush_output") struct.default_autoreload = config.getboolean("general", "default_autoreload") struct.pastebin_key = get_key_no_doublebind("pastebin") struct.copy_clipboard_key = get_key_no_doublebind("copy_clipboard") struct.save_key = get_key_no_doublebind("save") struct.search_key = get_key_no_doublebind("search") struct.show_source_key = get_key_no_doublebind("show_source") struct.suspend_key = get_key_no_doublebind("suspend") struct.toggle_file_watch_key = get_key_no_doublebind("toggle_file_watch") struct.undo_key = get_key_no_doublebind("undo") struct.reimport_key = get_key_no_doublebind("reimport") struct.reverse_incremental_search_key = get_key_no_doublebind( "reverse_incremental_search") struct.incremental_search_key = get_key_no_doublebind("incremental_search") struct.up_one_line_key = get_key_no_doublebind("up_one_line") struct.down_one_line_key = get_key_no_doublebind("down_one_line") struct.cut_to_buffer_key = get_key_no_doublebind("cut_to_buffer") struct.yank_from_buffer_key = get_key_no_doublebind("yank_from_buffer") struct.clear_word_key = get_key_no_doublebind("clear_word") struct.backspace_key = get_key_no_doublebind("backspace") struct.clear_line_key = get_key_no_doublebind("clear_line") struct.clear_screen_key = get_key_no_doublebind("clear_screen") struct.delete_key = get_key_no_doublebind("delete") struct.left_key = get_key_no_doublebind("left") struct.right_key = get_key_no_doublebind("right") struct.end_of_line_key = get_key_no_doublebind("end_of_line") struct.beginning_of_line_key = get_key_no_doublebind("beginning_of_line") struct.transpose_chars_key = get_key_no_doublebind("transpose_chars") struct.exit_key = get_key_no_doublebind("exit") struct.last_output_key = get_key_no_doublebind("last_output") struct.edit_config_key = get_key_no_doublebind("edit_config") struct.edit_current_block_key = get_key_no_doublebind("edit_current_block") struct.external_editor_key = get_key_no_doublebind("external_editor") struct.help_key = get_key_no_doublebind("help") struct.pastebin_confirm = config.getboolean("general", "pastebin_confirm") struct.pastebin_url = config.get("general", "pastebin_url") struct.pastebin_expiry = config.get("general", "pastebin_expiry") struct.pastebin_helper = config.get("general", "pastebin_helper") struct.cli_suggestion_width = config.getfloat("cli", "suggestion_width") struct.cli_trim_prompts = config.getboolean("cli", "trim_prompts") struct.complete_magic_methods = config.getboolean( "general", "complete_magic_methods") struct.autocomplete_mode = config.get("general", "autocomplete_mode") struct.save_append_py = config.getboolean("general", "save_append_py") struct.curtsies_list_above = config.getboolean("curtsies", "list_above") struct.curtsies_right_arrow_completion = config.getboolean( "curtsies", "right_arrow_completion") color_scheme_name = config.get("general", "color_scheme") default_colors = { "keyword": "y", "name": "c", "comment": "b", "string": "m", "error": "r", "number": "G", "operator": "Y", "punctuation": "y", "token": "C", "background": "d", "output": "w", "main": "c", "paren": "R", "prompt": "c", "prompt_more": "g", "right_arrow_suggestion": "K", } if color_scheme_name == "default": struct.color_scheme = default_colors else: struct.color_scheme = dict() theme_filename = color_scheme_name + ".theme" path = os.path.expanduser( os.path.join(get_config_home(), theme_filename)) try: load_theme(struct, path, struct.color_scheme, default_colors) except EnvironmentError: sys.stderr.write("Could not load theme '%s'.\n" % (color_scheme_name, )) sys.exit(1) # expand path of history file struct.hist_file = os.path.expanduser(struct.hist_file) # verify completion mode if struct.autocomplete_mode not in ALL_MODES: struct.autocomplete_mode = default_completion # set box drawing characters if config.getboolean("general", "unicode_box") and supports_box_chars(): struct.left_border = "│" struct.right_border = "│" struct.top_border = "─" struct.bottom_border = "─" struct.left_bottom_corner = "└" struct.right_bottom_corner = "┘" struct.left_top_corner = "┌" struct.right_top_corner = "┐" else: struct.left_border = "|" struct.right_border = "|" struct.top_border = "-" struct.bottom_border = "-" struct.left_bottom_corner = "+" struct.right_bottom_corner = "+" struct.left_top_corner = "+" struct.right_top_corner = "+"
class RepoConfiguration(object): """ Read configuration from repository. """ DEFAULT_CONFIG = dedent("""\ [autorebuild] enabled = false """) def __init__(self, dir_path='', file_name=REPO_CONFIG_FILE, depth=None, git_uri=None, git_branch=None, git_ref=None): self._config_parser = ConfigParser() self.container = {} self.depth = depth or 0 self.autorebuild = {} # Keep track of the repo metadata in the repo configuration self.git_uri = git_uri self.git_branch = git_branch self.git_ref = git_ref # Set default options self._config_parser.readfp(StringIO(self.DEFAULT_CONFIG)) # pylint: disable=W1505; py2 config_path = os.path.join(dir_path, file_name) if os.path.exists(config_path): self._config_parser.read(config_path) file_path = os.path.join(dir_path, REPO_CONTAINER_CONFIG) if os.path.exists(file_path): try: self.container = read_yaml_from_file_path( file_path, 'schemas/container.json') or {} except Exception as e: msg = ( 'Failed to load or validate container file "{file}": {reason}' .format(file=file_path, reason=e)) raise OsbsException(msg) # container values may be set to None container_compose = self.container.get('compose') or {} modules = container_compose.get('modules') or [] self.autorebuild = self.container.get('autorebuild') or {} self.container_module_specs = [] value_errors = [] for module in modules: try: self.container_module_specs.append(ModuleSpec.from_str(module)) except ValueError as e: value_errors.append(e) if value_errors: raise ValueError(value_errors) flatpak = self.container.get('flatpak') or {} self.is_flatpak = bool(flatpak) self.flatpak_base_image = flatpak.get('base_image') self.flatpak_component = flatpak.get('component') self.flatpak_name = flatpak.get('name') def is_autorebuild_enabled(self): return self._config_parser.getboolean('autorebuild', 'enabled')
class SetupConfig(object): """Wrapper around the setup.cfg file if available. One reason is to cleanup setup.cfg from these settings:: [egg_info] tag_build = dev tag_svn_revision = true Another is for optional zest.releaser-specific settings:: [zest.releaser] python-file-with-version = reinout/maurits.py """ config_filename = SETUP_CONFIG_FILE def __init__(self): """Grab the configuration (overridable for test purposes)""" # If there is a setup.cfg in the package, parse it if not os.path.exists(self.config_filename): self.config = None return self.config = ConfigParser() with codecs.open(self.config_filename, 'r', 'utf8') as fp: self.config.readfp(fp) def has_bad_commands(self): if self.config is None: return False if not self.config.has_section('egg_info'): # bail out early as the main section is not there return False bad = False # Check 1. if self.config.has_option('egg_info', 'tag_build'): # Might still be empty. value = self.config.get('egg_info', 'tag_build') if value: logger.warn("%s has [egg_info] tag_build set to %r", self.config_filename, value) bad = True # Check 2. if self.config.has_option('egg_info', 'tag_svn_revision'): if self.config.getboolean('egg_info', 'tag_svn_revision'): value = self.config.get('egg_info', 'tag_svn_revision') logger.warn("%s has [egg_info] tag_svn_revision set to %r", self.config_filename, value) bad = True return bad def fix_config(self): if not self.has_bad_commands(): logger.warn("Cannot fix already fine %s.", self.config_filename) return if self.config.has_option('egg_info', 'tag_build'): self.config.set('egg_info', 'tag_build', '') if self.config.has_option('egg_info', 'tag_svn_revision'): self.config.set('egg_info', 'tag_svn_revision', 'false') new_setup = open(self.config_filename, 'w') try: self.config.write(new_setup) finally: new_setup.close() logger.info("New setup.cfg contents:") print(''.join(open(self.config_filename).readlines())) def python_file_with_version(self): """Return Python filename with ``__version__`` marker, if configured. Enable this by adding a ``python-file-with-version`` option:: [zest.releaser] python-file-with-version = reinout/maurits.py Return None when nothing has been configured. """ default = None if self.config is None: return default try: result = self.config.get('zest.releaser', 'python-file-with-version') except (NoSectionError, NoOptionError, ValueError): return default return result
class Bot(Client): def __init__(self, core, configfile): self.core = core self.configfile = configfile self.config = ConfigParser() self.config.read(configfile) host = self.config.get('base', 'host') port = self.config.getint('base', 'port') try: ssl = self.config.getboolean('base', 'ssl') except: ssl = False Client.__init__(self, (host, port), ssl) self.hooks = HookManager(self) self.plugins = PluginManager(self) self.hooks.install_owner(self) self.nick = None self.channels = {} superuser = self.config.get('base', 'superuser') self.allow_rules = {'*': {'ANY': 1}, superuser: {'ANY': 1000}} self.deny_rules = {} self._name = '_bot' autoload = self.config.get('base', 'autoload').split() for name in autoload: self.plugins.load(name) self.connect() def set_timer(self, fn, timestamp, owner=None): hook = TimestampHook(timestamp) hook.bind(fn, owner) self.hooks.install(hook) return hook def set_interval(self, fn, seconds, owner=None): hook = TimestampHook(time() + seconds, {'repeat': seconds}) hook.bind(fn, owner) self.hooks.install(hook) return hook def set_timeout(self, fn, seconds, owner=None): hook = TimestampHook(time() + seconds) hook.bind(fn, owner) self.hooks.install(hook) return hook def do_tick(self, timestamp): self.hooks.call_timestamp(timestamp) def privmsg(self, target, text): wraplen = 510 wraplen -= 1 + len(self.nick) # ":<nick>" wraplen -= 1 + 10 # "!<user>" wraplen -= 1 + 63 # "@<host>" wraplen -= 9 # " PRIVMSG " wraplen -= len(target) # "<target>" wraplen -= 2 # " :" for line in wrap(text, wraplen): self.send('PRIVMSG %s :%s' % (target, line)) def notice(self, target, text): wraplen = 510 wraplen -= 1 + len(self.nick) # ":<nick>" wraplen -= 1 + 10 # "!<user>" wraplen -= 1 + 63 # "@<host>" wraplen -= 8 # " NOTICE " wraplen -= len(target) # "<target>" wraplen -= 2 # " :" for line in wrap(text, wraplen): self.send('NOTICE %s :%s' % (target, line)) def join(self, channels, keys=None): if isinstance(channels, str): channels = (channels,) if channels: channel_s = ','.join(channels) if keys: if isinstance(keys, str): keys = (keys,) key_s = ','.join(keys) self.send('JOIN %s %s' % (channel_s, key_s)) pairs = list(zip(channels, keys)) for item in pairs: self.channels[item[0]] = {'key': item[1], 'joined': False, 'nicks': set()} else: self.send('JOIN %s' % channel_s) for channel in channels: self.channels[channel] = {'joined': False, 'nicks': set()} def part(self, channels, message=None): if type(channels) == str: channels = (channels,) if channels: channels = ','.join(channels) if message: self.send('PART %s :%s' % (channels, message)) else: self.send('PART %s' % channels) @hook @priority(0) def disconnect_event(self): for _, props in list(self.channels.items()): props['joined'] = False props['nicks'].clear() @hook @priority(0) def shutdown_event(self, reason): self.send('QUIT :%s' % reason) for name in self.plugins.list(): self.plugins.unload(name, True) @hook def _001_command(self, msg): self.server = msg.source self.nick = msg.param[0] @hook def _353_command(self, msg): channel = msg.param[2] if channel in self.channels and self.channels[channel]['joined']: nicks = self.channels[channel]['nicks'] for nick in msg.param[-1].split(): if nick.startswith(('~', '&', '@', '%', '+')): nicks.add(nick[1:]) else: nicks.add(nick) @hook def join_command(self, msg): channel = msg.param[0] if msg.source == self.nick: if channel not in self.channels: self.channels[channel] = {} self.channels[channel]['joined'] = True elif channel in self.channels: self.channels[channel]['nicks'].add(msg.source) @hook def kick_command(self, msg): channel = msg.param[0] if msg.param[1] == self.nick: if channel in self.channels: self.channels[channel]['joined'] = False if 'nicks' in self.channels[channel]: self.channels[channel]['nicks'].clear() elif channel in self.channels: self.channels[channel]['nicks'].remove(msg.source) @hook def nick_command(self, msg): new_nick = msg.param[0] if msg.source == self.nick: self.nick = new_nick for _, props in list(self.channels.items()): if 'nicks' in props and msg.source in props['nicks']: props['nicks'].remove(msg.source) props['nicks'].add(new_nick) @hook @priority(0) def part_command(self, msg): channel = msg.param[0] if msg.source == self.nick: if channel in self.channels: self.channels[channel]['joined'] = False if 'nicks' in self.channels[channel]: self.channels[channel]['nicks'].clear() elif channel in self.channels: self.channels[channel]['nicks'].remove(msg.source) @hook def ping_command(self, msg): self.send('PONG :%s' % msg.param[-1]) @hook @priority(0) def quit_command(self, msg): for _, props in list(self.channels.items()): if 'nicks' in props and msg.source in props['nicks']: props['nicks'].remove(msg.source)
def loadini(struct, configfile): """Loads .ini configuration file and stores its values in struct""" config_path = os.path.expanduser(configfile) config = ConfigParser() defaults = { 'general': { 'arg_spec': True, 'auto_display_list': True, 'color_scheme': 'default', 'complete_magic_methods': True, 'autocomplete_mode': default_completion, 'dedent_after': 1, 'flush_output': True, 'highlight_show_source': True, 'hist_file': '~/.pythonhist', 'hist_length': 100, 'hist_duplicates': True, 'paste_time': 0.02, 'single_undo_time': 1.0, 'syntax': True, 'tab_length': 4, 'pastebin_confirm': True, 'pastebin_url': 'https://bpaste.net/json/new', 'pastebin_show_url': 'https://bpaste.net/show/$paste_id', 'pastebin_removal_url': 'https://bpaste.net/remove/$removal_id', 'pastebin_expiry': '1week', 'pastebin_helper': '', 'save_append_py': False, 'editor': os.environ.get('VISUAL', os.environ.get('EDITOR', 'vi')), 'unicode_box': True }, 'keyboard': { 'backspace': 'C-h', 'left': 'C-b', 'right': 'C-f', 'beginning_of_line': 'C-a', 'end_of_line': 'C-e', 'transpose_chars': 'C-t', 'clear_line': 'C-u', 'clear_screen': 'C-l', 'clear_word': 'C-w', 'cut_to_buffer': 'C-k', 'delete': 'C-d', 'down_one_line': 'C-n', 'exit': '', 'external_editor': 'F7', 'edit_config': 'F3', 'edit_current_block': 'C-x', 'help': 'F1', 'last_output': 'F9', 'copy_clipboard': 'F10', 'pastebin': 'F8', 'save': 'C-s', 'show_source': 'F2', 'suspend': 'C-z', 'toggle_file_watch': 'F5', 'undo': 'C-r', 'reimport': 'F6', 'search': 'C-o', 'up_one_line': 'C-p', 'yank_from_buffer': 'C-y'}, 'cli': { 'suggestion_width': 0.8, 'trim_prompts': False, }, 'curtsies': { 'list_above': False, 'right_arrow_completion': True, }} default_keys_to_commands = dict((value, key) for (key, value) in iteritems(defaults['keyboard'])) fill_config_with_default_values(config, defaults) if not config.read(config_path): # No config file. If the user has it in the old place then complain if os.path.isfile(os.path.expanduser('~/.bpython.ini')): sys.stderr.write("Error: It seems that you have a config file at " "~/.bpython.ini. Please move your config file to " "%s\n" % default_config_path()) sys.exit(1) def get_key_no_doublebind(command): default_commands_to_keys = defaults['keyboard'] requested_key = config.get('keyboard', command) try: default_command = default_keys_to_commands[requested_key] if (default_commands_to_keys[default_command] == config.get('keyboard', default_command)): setattr(struct, '%s_key' % default_command, '') except KeyError: pass return requested_key struct.config_path = config_path struct.dedent_after = config.getint('general', 'dedent_after') struct.tab_length = config.getint('general', 'tab_length') struct.auto_display_list = config.getboolean('general', 'auto_display_list') struct.syntax = config.getboolean('general', 'syntax') struct.arg_spec = config.getboolean('general', 'arg_spec') struct.paste_time = config.getfloat('general', 'paste_time') struct.single_undo_time = config.getfloat('general', 'single_undo_time') struct.highlight_show_source = config.getboolean('general', 'highlight_show_source') struct.hist_file = config.get('general', 'hist_file') struct.editor = config.get('general', 'editor') struct.hist_length = config.getint('general', 'hist_length') struct.hist_duplicates = config.getboolean('general', 'hist_duplicates') struct.flush_output = config.getboolean('general', 'flush_output') struct.pastebin_key = get_key_no_doublebind('pastebin') struct.copy_clipboard_key = get_key_no_doublebind('copy_clipboard') struct.save_key = get_key_no_doublebind('save') struct.search_key = get_key_no_doublebind('search') struct.show_source_key = get_key_no_doublebind('show_source') struct.suspend_key = get_key_no_doublebind('suspend') struct.toggle_file_watch_key = get_key_no_doublebind('toggle_file_watch') struct.undo_key = get_key_no_doublebind('undo') struct.reimport_key = get_key_no_doublebind('reimport') struct.up_one_line_key = get_key_no_doublebind('up_one_line') struct.down_one_line_key = get_key_no_doublebind('down_one_line') struct.cut_to_buffer_key = get_key_no_doublebind('cut_to_buffer') struct.yank_from_buffer_key = get_key_no_doublebind('yank_from_buffer') struct.clear_word_key = get_key_no_doublebind('clear_word') struct.backspace_key = get_key_no_doublebind('backspace') struct.clear_line_key = get_key_no_doublebind('clear_line') struct.clear_screen_key = get_key_no_doublebind('clear_screen') struct.delete_key = get_key_no_doublebind('delete') struct.left_key = get_key_no_doublebind('left') struct.right_key = get_key_no_doublebind('right') struct.end_of_line_key = get_key_no_doublebind('end_of_line') struct.beginning_of_line_key = get_key_no_doublebind('beginning_of_line') struct.transpose_chars_key = get_key_no_doublebind('transpose_chars') struct.clear_line_key = get_key_no_doublebind('clear_line') struct.clear_screen_key = get_key_no_doublebind('clear_screen') struct.exit_key = get_key_no_doublebind('exit') struct.last_output_key = get_key_no_doublebind('last_output') struct.edit_config_key = get_key_no_doublebind('edit_config') struct.edit_current_block_key = get_key_no_doublebind('edit_current_block') struct.external_editor_key = get_key_no_doublebind('external_editor') struct.help_key = get_key_no_doublebind('help') struct.pastebin_confirm = config.getboolean('general', 'pastebin_confirm') struct.pastebin_url = config.get('general', 'pastebin_url') struct.pastebin_show_url = config.get('general', 'pastebin_show_url') struct.pastebin_removal_url = config.get('general', 'pastebin_removal_url') struct.pastebin_expiry = config.get('general', 'pastebin_expiry') struct.pastebin_helper = config.get('general', 'pastebin_helper') struct.cli_suggestion_width = config.getfloat('cli', 'suggestion_width') struct.cli_trim_prompts = config.getboolean('cli', 'trim_prompts') struct.complete_magic_methods = config.getboolean('general', 'complete_magic_methods') struct.autocomplete_mode = config.get('general', 'autocomplete_mode') struct.save_append_py = config.getboolean('general', 'save_append_py') struct.curtsies_list_above = config.getboolean('curtsies', 'list_above') struct.curtsies_right_arrow_completion = \ config.getboolean('curtsies', 'right_arrow_completion') color_scheme_name = config.get('general', 'color_scheme') default_colors = { 'keyword': 'y', 'name': 'c', 'comment': 'b', 'string': 'm', 'error': 'r', 'number': 'G', 'operator': 'Y', 'punctuation': 'y', 'token': 'C', 'background': 'd', 'output': 'w', 'main': 'c', 'paren': 'R', 'prompt': 'c', 'prompt_more': 'g', 'right_arrow_suggestion': 'K', } if color_scheme_name == 'default': struct.color_scheme = default_colors else: struct.color_scheme = dict() theme_filename = color_scheme_name + '.theme' path = os.path.expanduser(os.path.join(get_config_home(), theme_filename)) try: load_theme(struct, path, struct.color_scheme, default_colors) except EnvironmentError: sys.stderr.write("Could not load theme '%s'.\n" % (color_scheme_name, )) sys.exit(1) # checks for valid key configuration this part still sucks for key in (struct.pastebin_key, struct.save_key): key_dispatch[key] # expand path of history file struct.hist_file = os.path.expanduser(struct.hist_file) # verify completion mode if struct.autocomplete_mode not in bpython.autocomplete.ALL_MODES: struct.autocomplete_mode = default_completion # set box drawing characters if config.getboolean('general', 'unicode_box') and supports_box_chars(): struct.left_border = u'│' struct.right_border = u'│' struct.top_border = u'─' struct.bottom_border = u'─' struct.left_bottom_corner = u'└' struct.right_bottom_corner = u'┘' struct.left_top_corner = u'┌' struct.right_top_corner = u'┐' else: struct.left_border = u'|' struct.right_border = u'|' struct.top_border = u'-' struct.bottom_border = u'-' struct.left_bottom_corner = u'+' struct.right_bottom_corner = u'+' struct.left_top_corner = u'+' struct.right_top_corner = u'+'
class Conf(object): """Base class for Python-AD tests.""" def __init__(self): fname = os.environ.get( 'PYAD_TEST_CONFIG', os.path.join(os.path.dirname(__file__), 'test.conf.example') ) if fname is None: raise Error('Python-AD test configuration file not specified.') if not os.path.exists(fname): raise Error('Python-AD test configuration file {} does not exist.'.format(fname)) self.config = ConfigParser() self.config.read(fname) self.basedir = os.path.dirname(__file__) self._iptables = None self._domain = self.config.get('test', 'domain') self._tempfiles = [] enable_logging() self.readonly_ad_creds = None readonly_env = os.environ.get('PYAD_READONLY_CONFIG', None) if readonly_env: bits = readonly_env.rsplit('@', 1) if len(bits) == 2: creds, domain = bits bits = creds.split(':', 1) if len(bits) == 2: self._domain = domain self.readonly_ad_creds = bits elif self.config.getboolean('test', 'readonly_ad_tests'): self.readonly_ad_creds = [ config.get('test', 'ad_user_account'), config.get('test', 'ad_user_password'), ] def teardown(self): for fname in self._tempfiles: try: os.unlink(fname) except OSError: pass self._tempfiles = [] def tempfile(self, contents=None, remove=False): fd, name = tempfile.mkstemp() if contents: os.write(fd, dedent(contents)) elif remove: os.remove(name) os.close(fd) self._tempfiles.append(name) return name def read_file(self, fname): fname = os.path.join(self.basedir, fname) with open(fname, 'rb') as fin: buf = fin.read() return buf.decode('latin_1') if six.PY3 else buf def require(self, ad_user=False, local_admin=False, ad_admin=False, firewall=False, expensive=False): if firewall: local_admin = True config = self.config if ad_user and not ( self.readonly_ad_creds and all(self.readonly_ad_creds) ): raise pytest.skip('test disabled by configuration') if local_admin: if not config.getboolean('test', 'intrusive_local_tests'): raise pytest.skip('test disabled by configuration') if not config.get('test', 'local_admin_account') or \ not config.get('test', 'local_admin_password'): raise pytest.skip('intrusive local tests enabled but no user/pw given') if ad_admin: if not config.getboolean('test', 'intrusive_ad_tests'): raise pytest.skip('test disabled by configuration') if not config.get('test', 'ad_admin_account') or \ not config.get('test', 'ad_admin_password'): raise pytest.skip('intrusive ad tests enabled but no user/pw given') if firewall and not self.iptables_supported: raise pytest.skip('iptables/conntrack not available') if expensive and not config.getboolean('test', 'expensive_tests'): raise pytest.skip('test disabled by configuration') def domain(self): return self._domain def ad_user_account(self): self.require(ad_user=True) return self.readonly_ad_creds[0] def ad_user_password(self): self.require(ad_user=True) return self.readonly_ad_creds[1] def local_admin_account(self): self.require(local_admin=True) return self.config.get('test', 'local_admin_account') def local_admin_password(self): self.require(local_admin=True) return self.config.get('test', 'local_admin_password') def ad_admin_account(self): self.require(ad_admin=True) return self.config.get('test', 'ad_admin_account') def ad_admin_password(self): self.require(ad_admin=True) return self.config.get('test', 'ad_admin_password') def execute_as_root(self, command): self.require(local_admin=True) child = pexpect.spawn('su -c "%s" %s' % (command, self.local_admin_account())) child.expect('.*:') child.sendline(self.local_admin_password()) child.expect(pexpect.EOF) assert not child.isalive() if child.exitstatus != 0: m = 'Root command exited with status %s' % child.exitstatus raise Error(m) return child.before def acquire_credentials(self, principal, password, ccache=None): if ccache is None: ccache = '' else: ccache = '-c %s' % ccache child = pexpect.spawn('kinit %s %s' % (principal, ccache)) child.expect(':') child.sendline(password) child.expect(pexpect.EOF) assert not child.isalive() if child.exitstatus != 0: m = 'Command kinit exited with status %s' % child.exitstatus raise Error(m) def list_credentials(self, ccache=None): if ccache is None: ccache = '' child = pexpect.spawn('klist %s' % ccache) try: child.expect('Ticket cache: ([a-zA-Z0-9_/.:-]+)\r\n') except pexpect.EOF: m = 'Command klist exited with status %s' % child.exitstatus raise Error(m) ccache = child.match.group(1) child.expect('Default principal: ([a-zA-Z0-9_/.:@-]+)\r\n') principal = child.match.group(1) creds = [] while True: i = child.expect(['\r\n', pexpect.EOF, '\d\d/\d\d/\d\d \d\d:\d\d:\d\d\s+' \ '\d\d/\d\d/\d\d \d\d:\d\d:\d\d\s+' \ '([a-zA-Z0-9_/.:@-]+)\r\n']) if i == 0: continue elif i == 1: break creds.append(child.match.group(1)) return ccache, principal, creds @property def iptables_supported(self): if self._iptables is None: try: self.execute_as_root('iptables -L -n') self.execute_as_root('conntrack -L') except Error: self._iptables = False else: self._iptables = True return self._iptables def remove_network_blocks(self): self.require(local_admin=True, firewall=True) self.execute_as_root('iptables -t nat -F') self.execute_as_root('conntrack -F') def block_outgoing_traffic(self, protocol, port): """Block outgoing traffic of type `protocol' with destination `port'.""" self.require(local_admin=True, firewall=True) # Unfortunately we cannot simply insert a rule like this: -A OUTPUT -m # udp -p udp--dport 389 -j DROP. If we do this the kernel code will # be smart and return an error when sending trying to connect or send # a datagram. In order realistically emulate a network failure we # instead redirect packets the discard port on localhost. This # complicates stopping the emulated failure though: merely flushling # the nat table is not enough. We also need to flush the conntrack # table that keeps state for NAT'ed connections even after the rule # that caused the NAT in the first place has been removed. self.execute_as_root( 'iptables -t nat -A OUTPUT -m %s -p %s --dport %d ' '-j DNAT --to-destination 127.0.0.1:9' % (protocol, protocol, port) )