From: "André Erdmann" <dywi@mailerd.de>
To: gentoo-commits@lists.gentoo.org
Subject: [gentoo-commits] proj/R_overlay:master commit in: roverlay/
Date: Tue, 10 Sep 2013 14:40:41 +0000 (UTC) [thread overview]
Message-ID: <1378824001.371a3c585e51383a05df6986f0c6b02631147cc7.dywi@gentoo> (raw)
commit: 371a3c585e51383a05df6986f0c6b02631147cc7
Author: André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Tue Sep 10 14:33:09 2013 +0000
Commit: André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Tue Sep 10 14:40:01 2013 +0000
URL: http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=371a3c58
roverlay: setupscript.py
This file provides various env objects and a main() function for setting up
roverlay.
It is meant to replace:
* the roverlay-mkconfig command (now "roverlay-setup mkconfig")
* most of the ebuild's pkg_config() and roverlay's setupdirs command
(unified in "roverlay-setup init" and more flexible/safer, e.g.
a has --pretend option that gives detailed information about what
would be done)
Additionally, it can be used to manage roverlay's hooks (besides setting up the
default hooks; TODO).
TODO notes:
* needs a cleanup
* only "--import-config symlink=root" is implemented, currently
* isn't able to handle not-installed versions of roverlay
* the replaced commands/functionality has to be removed
---
roverlay/setupscript.py | 1035 +++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 1035 insertions(+)
diff --git a/roverlay/setupscript.py b/roverlay/setupscript.py
new file mode 100644
index 0000000..2a23103
--- /dev/null
+++ b/roverlay/setupscript.py
@@ -0,0 +1,1035 @@
+# R overlay -- setup script
+# -*- coding: utf-8 -*-
+
+from __future__ import print_function
+
+import argparse
+import collections
+import errno
+import logging
+import os
+import shutil
+import stat
+import sys
+import textwrap
+
+import roverlay.argutil
+import roverlay.argparser
+import roverlay.fsutil
+import roverlay.runtime
+
+import roverlay.config.defconfig
+import roverlay.config.entrymap
+import roverlay.config.entryutil
+
+import roverlay.static.hookinfo
+
+import roverlay.util.counter
+
+if sys.hexversion >= 0x3000000:
+ read_user_input = input
+else:
+ read_user_input = raw_input
+
+
+
+
+
+
+def arg_stdout_or_fs ( value ):
+ if value == '-':
+ return value
+ else:
+ return os.path.abspath ( os.path.expanduser ( value ) )
+# --- end of arg_stdout_or_fs (...) ---
+
+
+
+
+class SetupArgParser ( roverlay.argparser.RoverlayArgumentParser ):
+ MULTIPLE_COMMANDS = False
+ COMMAND_DESCRIPTION = {
+ 'init': 'initialize roverlay\'s config and filesystem layout',
+ 'mkconfig': 'generate a config file',
+ }
+ DEFAULT_COMMAND = "init"
+
+ COMMANDS_WITH_PRETEND = frozenset ({ 'init', })
+
+ SETUP_TARGETS = ( 'version', 'actions', 'setup', 'config', 'init', )
+ PARSE_TARGETS = ( 'actions', 'setup', 'init', )
+
+
+ def setup_setup ( self ):
+ arg = self.setup_setup_minimal ( title='common options' )
+
+ arg (
+ '--output', '-O', metavar="<file|dir|->", dest='output',
+ default='-', type=arg_stdout_or_fs,
+ flags=self.ARG_WITH_DEFAULT,
+ help='output file/dir/stream used by various commands (\'-\' for stdout)',
+ )
+
+ arg (
+ '--pretend', '-p', dest='pretend',
+ flags=self.ARG_WITH_DEFAULT|self.ARG_OPT_IN,
+ help='show what would be done',
+ )
+
+ arg (
+ '--ask', '-a', dest='wait_confirm',
+ flags=self.ARG_WITH_DEFAULT|self.ARG_OPT_IN,
+ help='get confirmation before actually doing anything',
+ )
+
+ return arg
+ # --- end of setup_setup (...) ---
+
+ def parse_setup ( self ):
+ self.parse_setup_minimal()
+
+ if self.parsed ['pretend']:
+ for cmd in self.get_commands():
+ if cmd not in self.__class__.COMMANDS_WITH_PRETEND:
+ self.parser.exit (
+ "{!r} command does not support --pretend.".format ( cmd )
+ )
+ # --- end of parse_setup (...) ---
+
+ def setup_config ( self ):
+ arg = self.add_argument_group (
+ "config", title="options for the main config file"
+ )
+
+ arg (
+ '--expand-user', dest='config_expand_user',
+ flags=self.ARG_WITH_DEFAULT|self.ARG_OPT_IN,
+ help="expand \'~\' to the target user\'s home directory",
+ )
+
+ arg (
+ '--variable', '-v', metavar="<key=\"value\">", dest='config_vars',
+ default=[], action='append',
+ type=roverlay.argutil.is_config_opt,
+ help="additional variables",
+ )
+
+ return arg
+ # --- end of setup_config (...) ---
+
+ def setup_init ( self ):
+ arg = self.add_argument_group (
+ 'init', title='options for the \'init\' command'
+ )
+
+ arg (
+ '--enable-default-hooks', dest='want_default_hooks',
+ default=True,
+ flags=self.ARG_WITH_DEFAULT|self.ARG_OPT_IN,
+ help='enable/update the default hooks',
+ )
+
+ arg (
+ '--no-default-hooks', dest='want_default_hooks',
+ flags=self.ARG_SHARED|self.ARG_OPT_OUT,
+ help='disable the default hooks',
+ )
+
+ arg (
+ '--import-config', '-I', dest='import_config',
+ default="symlink",
+ choices=[
+ "disable",
+ "symlink", "symlink=root",
+ "symlink=dirs", "symlink=files",
+ "copy"
+ ],
+ metavar='<mode>',
+ flags=self.ARG_WITH_DEFAULT,
+ help=(
+ 'choose whether and how --conf-root should be imported: '
+ '%(choices)s'
+ ),
+ )
+
+ arg (
+ '--no-import-config', dest='import_config',
+ action='store_const', const='disable',
+ help='disable config import (same as \'--import-config disable\')',
+ )
+
+
+ arg (
+ '--target-uid', dest='target_uid', default=os.getuid(),
+ metavar='<uid>', type=roverlay.argutil.is_uid,
+ flags=self.ARG_WITH_DEFAULT,
+ help="uid of the user that will run roverlay",
+ )
+
+ arg (
+ '--target-gid', dest='target_gid', default=os.getgid(),
+ metavar='<gid>', type=roverlay.argutil.is_gid,
+ flags=self.ARG_WITH_DEFAULT,
+ help='gid of the user that will run roverlay',
+ )
+
+ # --- end of setup_init (...) ---
+
+ def parse_init ( self ):
+ my_uid = os.getuid()
+
+ if my_uid and self.parsed ['target_uid'] != my_uid:
+ if self.parsed ['pretend']:
+ sys.stderr.write (
+ "!!! --target-uid: users cannot configure other users.\n\n"
+ )
+ else:
+ self.parser.exit (
+ "--target-uid: users cannot configure other users."
+ )
+ # --- end of parse_init (...) ---
+
+
+# --- end of SetupArgParser ---
+
+
+class SetupEnvironment ( roverlay.runtime.IndependentRuntimeEnvironment ):
+
+ LOG_LEVEL = logging.INFO
+
+ SHARED_DIR_MODE = roverlay.fsutil.get_stat_mode ( "rwxrwxr-x" )
+ PRIVATE_DIR_MODE = roverlay.fsutil.get_stat_mode ( "rwxr-x---" )
+ SHARED_FILE_MODE = roverlay.fsutil.get_stat_mode ( "rw-rw-r--" )
+ PRIVATE_FILE_MODE = roverlay.fsutil.get_stat_mode ( "rw-r-----" )
+
+ def __init__ ( self, *args, **kwargs ):
+ super ( SetupEnvironment, self ).__init__ ( *args, **kwargs )
+
+ self.UID = os.getuid()
+ self.GID = os.getgid()
+
+ self.expanduser = None
+ self.fs_ops = None
+ self.fs_ops_virtual = None
+
+ self.want_chown = None
+ self.data_root = None
+ self.work_root = None
+ self.conf_root = None
+ self.user_conf_root = None
+ # --- end of __init__ (...) ---
+
+ def create_argparser ( self ):
+ instinfo = self.access_constant ( 'INSTALLINFO' )
+
+ return SetupArgParser (
+ description = 'roverlay setup script',
+ defaults = {
+ 'work_root' : instinfo ['workroot'],
+ 'data_root' : instinfo ['libexec'],
+ 'conf_root' : instinfo ['confroot'],
+ 'private_conf_root' : instinfo ['workroot'] + os.sep + 'config',
+ 'import_config' : 'symlink=root',
+ },
+ )
+ # --- end of create_argparser (...) ---
+
+ def _get_config_roots ( self ):
+ return (
+ os.path.realpath ( self.conf_root ),
+ os.path.realpath ( self.user_conf_root )
+ )
+ # --- end of get_config_roots (...) ---
+
+ def get_user_config_root ( self ):
+ conf_root, user_conf_root = self._get_config_roots()
+ if conf_root == user_conf_root:
+ return None
+ else:
+ return user_conf_root
+ # --- end of get_user_config_root (...) ---
+
+ def get_config_file_path ( self ):
+ return (
+ self.work_root + os.sep + self.access_constant ( 'config_file_name' )
+ )
+ # --- end of get_config_file_path (...) ---
+
+ def create_new_target_config ( self ):
+ return self.create_new_config (
+ config_str=self.create_config_file ( expand_user=True )
+ )
+ # --- end of create_new_target_config (...) ---
+
+ def _expanduser_pwd ( self, fspath ):
+ return roverlay.fsutil.pwd_expanduser (
+ fspath, self.options ['target_uid']
+ )
+ # --- end of _expanduser_pwd (...) ---
+
+ def create_config_file ( self, expand_user=False ):
+ conf_creator = roverlay.config.defconfig.RoverlayConfigCreation (
+ work_root = (
+ self.work_root if expand_user else self.options ['work_root']
+ ),
+ data_root = (
+ self.data_root if expand_user else self.options ['data_root']
+ ),
+ conf_root = (
+ self.user_conf_root if expand_user
+ else self.options ['private_conf_root']
+ ),
+ )
+
+ for kv in self.options ['config_vars']:
+ key, sepa, value = kv.partition ( '=' )
+ if not sepa:
+ raise Exception ( "bad variable given: {!r}".format ( kv ) )
+ else:
+ conf_creator.set_option ( key, value )
+
+ return conf_creator.get_str()
+ # --- end of create_config_file (...) ---
+
+ def write_config_file ( self, output=None, expand_user=None ):
+ config_file_str = self.create_config_file (
+ expand_user = (
+ self.options ['config_expand_user'] if expand_user is None
+ else expand_user
+ ),
+ )
+ if not output or output == '-':
+ self.info ( config_file_str )
+ else:
+ with open ( output, 'wt' ) as FH:
+ FH.write ( config_file_str )
+ # --- end of write_config_file (...) ---
+
+ def auto_reconfigure ( self ):
+ self.reconfigure ( self.create_config_file() )
+ # --- end of auto_reconfigure (...) ---
+
+ def setup ( self ):
+ self.PWD_INITIAL = os.getcwd()
+ self.setup_common()
+
+ # ref
+ options = self.options
+
+ target_uid = options ['target_uid']
+ target_gid = options ['target_gid']
+
+ self.want_chown = ( target_uid != self.UID or target_gid != self.GID )
+
+ if self.UID == target_uid:
+ expanduser = os.path.expanduser
+ self.expanduser = os.path.expanduser
+ else:
+ expanduser = self._expanduser_pwd
+ self.expanduser = self._expanduser_pwd
+
+ self.work_root = expanduser ( options ['work_root'] )
+ self.data_root = expanduser ( options ['data_root'] )
+ self.conf_root = expanduser ( options ['conf_root'] )
+ self.user_conf_root = expanduser ( options ['private_conf_root'] )
+
+
+ self.fs_ops_virtual = {
+ 'private_dir': roverlay.fsutil.VirtualFsOperations (
+ uid=target_uid, gid=target_gid, mode=self.PRIVATE_DIR_MODE,
+ ),
+ 'shared_dir': roverlay.fsutil.VirtualFsOperations (
+ uid=target_uid, gid=target_gid, mode=self.SHARED_DIR_MODE,
+ ),
+ 'private_file': roverlay.fsutil.VirtualFsOperations (
+ uid=target_uid, gid=target_gid, mode=self.PRIVATE_FILE_MODE,
+ ),
+ 'shared_file': roverlay.fsutil.VirtualFsOperations (
+ uid=target_uid, gid=target_gid, mode=self.SHARED_FILE_MODE,
+ ),
+ }
+
+ if options ['pretend']:
+ self.fs_ops = self.fs_ops_virtual
+ else:
+ self.fs_ops = {
+ 'private_dir': roverlay.fsutil.FsOperations (
+ uid=target_uid, gid=target_gid, mode=self.PRIVATE_DIR_MODE,
+ ),
+ 'shared_dir': roverlay.fsutil.FsOperations (
+ uid=target_uid, gid=target_gid, mode=self.SHARED_DIR_MODE,
+ ),
+ 'private_file': roverlay.fsutil.FsOperations (
+ uid=target_uid, gid=target_gid, mode=self.PRIVATE_FILE_MODE,
+ ),
+ 'shared_file': roverlay.fsutil.FsOperations (
+ uid=target_uid, gid=target_gid, mode=self.SHARED_FILE_MODE,
+ ),
+ }
+
+ # bind fs_ops
+ self.private_dir = self.fs_ops ['private_dir']
+ self.shared_dir = self.fs_ops ['shared_dir']
+ self.private_file = self.fs_ops ['private_file']
+ self.shared_file = self.fs_ops ['shared_file']
+ # --- end of setup (...) ---
+
+ def wait_confirm ( self,
+ message=None, message_inline=None,
+ prepend_newline=True, append_newline=True
+ ):
+ try:
+ if prepend_newline:
+ self.info ( '\n' )
+
+ if message is not None:
+ self.info ( str ( message ) + '\n' )
+
+ if message_inline:
+ self.info (
+ "Press Enter to continue ({!s}) ... ".format ( message_inline )
+ )
+ else:
+ self.info ( "Press Enter to continue ... " )
+
+ self.stdout.flush()
+
+ ret = read_user_input().strip()
+
+ except ( KeyboardInterrupt, EOFError ):
+ self.info ( "\n" )
+ sys.exit ( 130 )
+ else:
+ if append_newline:
+ self.info ( '\n' )
+
+ return ret
+ # --- end of wait_confirm (...) ---
+
+ def wait_confirm_can_skip ( self,
+ SKIP_WORDS=frozenset({ 'skip', 'no', 'n'}), **kwargs
+ ):
+ assert 'message_inline' not in kwargs
+
+ if self.options ['wait_confirm']:
+
+ user_reply = self.wait_confirm (
+ message_inline="type {} to skip this step".format (
+ '/'.join ( repr( word ) for word in sorted( SKIP_WORDS ) )
+ ),
+ **kwargs
+ )
+
+ return user_reply.lower() not in SKIP_WORDS
+ else:
+ return True
+ # --- end of wait_confirm (...) ---
+
+ def get_init_env ( self ):
+ return SetupInitEnvironment ( self )
+ # --- end of get_init_env (...) ---
+
+ def get_hook_env ( self ):
+ return SetupHookEnvironment ( self )
+ # --- end of get_hook_env (...) ---
+
+# --- end of SetupEnvironment ---
+
+
+class SetupSubEnvironment ( object ):
+
+ NEEDS_CONFIG_TREE = False
+
+ ACTIONS = None
+
+ def __init__ ( self, setup_env ):
+ super ( SetupSubEnvironment, self ).__init__()
+
+ self.setup_env = setup_env
+ self.stdout = setup_env.stdout
+ self.stderr = setup_env.stderr
+ self.info = setup_env.info
+ self.error = setup_env.error
+
+ if self.NEEDS_CONFIG_TREE:
+ self.config = self.setup_env.create_new_target_config()
+ else:
+ self.config = None
+
+ self.setup()
+ # --- end of __init__ (...) ---
+
+ def setup ( self ):
+ pass
+ # --- end of setup (...) ---
+
+ def run ( self, steps_to_skip=None, verbose_skip=True, steps=None ):
+ pretend = self.setup_env.options ['pretend']
+ ACTIONS = steps if steps is not None else self.ACTIONS
+
+ if ACTIONS:
+ if steps_to_skip:
+ methods_to_call = [
+ (
+ None if item[0] in steps_to_skip
+ else getattr ( self, 'do_' + item[0] )
+ ) for item in ACTIONS
+ ]
+ else:
+ methods_to_call = [
+ getattr ( self, 'do_' + item[0] ) for item in ACTIONS
+ ]
+
+ wait_confirm_can_skip = self.setup_env.wait_confirm_can_skip
+
+
+ for method, action in zip ( methods_to_call, ACTIONS ):
+ if method is None:
+ if verbose_skip:
+ self.info ( "{}: skipped.\n".format ( action[0] ) )
+
+ elif not action[1]:
+ method ( pretend=pretend )
+
+ elif wait_confirm_can_skip (
+ message=method.__doc__, append_newline=False
+ ):
+ method ( pretend=pretend )
+ else:
+ self.info ( "skipped.\n" )
+
+ else:
+ raise NotImplementedError (
+ "{}.{}()".format ( self.__class__.__name__, "do_all" )
+ )
+ # --- end of run (...) ---
+
+
+# --- end of SetupSubEnvironment ---
+
+
+class SetupInitEnvironment ( SetupSubEnvironment ):
+
+ ACTIONS = (
+ ( 'pretend', False ),
+ ( 'prepare_config_file', False ),
+ ( 'import_config', True ),
+ ( 'setupdirs', True ),
+ ( 'write_config_file', True ),
+ ( 'enable_default_hooks', True ),
+ )
+
+ NEEDS_CONFIG_TREE = True
+
+ def setup ( self ):
+ self.config_file_str = None
+ # --- end of setup (...) ---
+
+ IMPORT_CONFIG_DESC = {
+ 'disable' : False,
+ 'symlink' : 'symlink {conf_root} to {user_conf_root}',
+ 'symlink=root' : 'symlink {conf_root} to {user_conf_root}',
+ 'symlink=dirs' : (
+ 'symlink files/dirs from {conf_root} to {user_conf_root}/'
+ ),
+ 'symlink=files' : (
+ 'recursively copy {conf_root} to {user_conf_root}, '
+ 'but symlink files instead of copying them'
+ ),
+ 'copy' : 'recursively copy {conf_root} to {user_conf_root}',
+ }
+
+ def gen_pretend_options ( self ):
+ options = self.setup_env.options
+
+ def get_option ( key ):
+ val = options [key]
+ if isinstance ( val, str ):
+ return val
+ elif hasattr ( val, '__iter__' ):
+ return ' '.join ( str(x) for x in val )
+ elif isinstance ( val, bool ):
+ return "yes" if val else "no"
+ elif val is None:
+ return "<undef>"
+ else:
+ return str ( val )
+ # --- end of get_option (...) ---
+
+ comment_path = lambda a, b: a if a == b else ( a + ' (' + b + ')' )
+ get_path_option = lambda k, b: comment_path ( get_option ( k ), b )
+
+ fmt_vars = {
+ 'conf_root' : options ['conf_root'],
+ 'user_conf_root': options ['private_conf_root']
+ }
+
+ yield ( "user/uid", get_option ( 'target_uid' ) )
+ yield ( "group/gid", get_option ( 'target_gid' ) )
+
+ yield ( "work root",
+ get_path_option ( 'work_root', self.setup_env.work_root )
+ )
+ yield ( "data root",
+ get_path_option ( 'data_root', self.setup_env.data_root )
+ )
+ yield ( "roverlay\'s config root",
+ get_path_option ( 'conf_root', self.setup_env.conf_root )
+ )
+ yield ( "user\'s config root",
+ get_path_option ( 'private_conf_root', self.setup_env.user_conf_root )
+ )
+
+ import_config = get_option ( 'import_config' )
+ if import_config == 'disable':
+ yield ( "import config", "no" )
+ else:
+ yield ( "import config",
+ "yes, "
+ + self.IMPORT_CONFIG_DESC [import_config].format ( **fmt_vars )
+ )
+
+ yield ( "enable default hooks", get_option ( 'want_default_hooks' ) )
+ yield ( "additional config variables", get_option ( 'config_vars' ) )
+ # --- end of gen_pretend_options (...) ---
+
+ def gen_pretend_lines ( self, append_newline=True ):
+ options = list ( self.gen_pretend_options() )
+ COLUMNS = os.environ.get ( 'COLUMNS', 78 )
+ desc_len = min ( COLUMNS // 2,
+ 1 + max ( len(desc) for desc, value in options )
+ )
+
+ line_wrapper = textwrap.TextWrapper (
+ width=COLUMNS, initial_indent='',
+ subsequent_indent=( (desc_len+5) * ' ' ),
+ break_long_words=False, break_on_hyphens=False,
+ )
+
+
+ yield 'Configuration:'
+ for desc, value in options:
+ yield line_wrapper.fill (
+ "- {desc:<{l}}: {value}".format (
+ desc=desc, l=desc_len, value=value,
+ )
+ )
+
+ if append_newline:
+ yield ""
+ # --- end of gen_pretend_lines (...) ---
+
+ def do_pretend ( self, pretend ):
+ """Shows what would be done."""
+ self.info ( '\n'.join ( self.gen_pretend_lines() ) + '\n' )
+ # --- end of do_pretend (...) ---
+
+ def do_prepare_config_file ( self, pretend ):
+ """Creates the config file (in memory)."""
+ self.config_file_str = self.setup_env.create_config_file (
+ expand_user=self.setup_env.options ['config_expand_user']
+ )
+ # --- end of do_prepare_config_file (...) ---
+
+ def do_import_config ( self, pretend ):
+ """Imports the config."""
+ mode = self.setup_env.options ['import_config']
+ fs_ops = self.setup_env.private_dir
+ user_conf_root = self.setup_env.get_user_config_root()
+ # assert os.path.isdir ( os.path.dirname(user_conf_root) == work_root )
+
+ if user_conf_root is None and (
+ fs_ops.unlink ( self.setup_env.user_conf_root )
+ ):
+ # config_root was a symlink
+
+ if pretend:
+ user_conf_root = self.setup_env.user_conf_root
+ else:
+ user_conf_root = self.setup_env.get_user_config_root()
+
+ # -- end if
+
+
+ if user_conf_root is None:
+ self.info (
+ "user has no private config directory - skipping config import.\n"
+ )
+
+ elif mode in { 'symlink=root', 'symlink' }:
+ if not fs_ops.wipe ( user_conf_root ):
+ self.setup_env.die (
+ "failed to remove {!r}.\n".format ( user_conf_root )
+ )
+ elif not fs_ops.symlink ( self.setup_env.conf_root, user_conf_root ):
+ self.setup_env.die (
+ "could not create symlink to {!r}.".format (
+ self.setup_env.conf_root
+ )
+ )
+
+
+ pass
+ else:
+ raise NotImplementedError ( mode )
+ # --- end of do_import_config (...) ---
+
+ def do_setupdirs ( self, pretend ):
+ """Creates directories with proper permissions."""
+ create_subdir_check = roverlay.fsutil.create_subdir_check
+ config = self.config
+ find_config_path = roverlay.config.entryutil.find_config_path
+ dodir_private = self.setup_env.private_dir.dodir
+ dodir_shared = self.setup_env.shared_dir.dodir
+
+
+ WANT_USERDIR = roverlay.config.entrymap.WANT_USERDIR
+ WANT_PRIVATE = roverlay.config.entrymap.WANT_PRIVATE
+ WANT_FILEDIR = roverlay.config.entrymap.WANT_FILEDIR
+
+ listlike = lambda a: (
+ hasattr(a, '__iter__') and not isinstance(a, str)
+ )
+ iter_values = lambda b: (
+ () if b is None else (b if listlike(b) else ( b, ))
+ )
+
+ dirs_exclude = [
+ create_subdir_check ( self.setup_env.conf_root ),
+ create_subdir_check ( self.setup_env.data_root ),
+ ]
+ if self.setup_env.get_user_config_root() is None:
+ dirs_exclude.append (
+ create_subdir_check ( self.setup_env.user_conf_root )
+ )
+ else:
+ print ( self.setup_env.get_user_config_root() )
+
+ # don't print exclude/skip messages more than once per dir
+ dirs_already_excluded = set()
+
+ private_dirs = set()
+ private_dirs_chown = set()
+ shared_dirs = set()
+ shared_dirs_chown = set()
+
+ # it's not necessary to create all of the listed dirs because some of
+ # them are automatically created at runtime, but doing so results in
+ # a (mostly) complete filesystem layout
+ #
+ for config_key, entry in (
+ roverlay.config.entrymap.CONFIG_ENTRY_MAP.items()
+ ):
+ if isinstance ( entry, dict ) and 'want_dir_create' in entry:
+ for value in iter_values (
+ config.get ( find_config_path ( config_key ), None )
+ ):
+ dirmask = entry ['want_dir_create']
+ dirpath = (
+ os.path.dirname ( value.rstrip ( os.sep ) )
+ if dirmask & WANT_FILEDIR else value.rstrip ( os.sep )
+ )
+
+ if not dirpath or dirpath in dirs_already_excluded:
+ pass
+
+ elif any ( ex ( dirpath ) for ex in dirs_exclude ):
+ self.info (
+ "setupdirs: excluding {!r}\n".format ( dirpath )
+ )
+ dirs_already_excluded.add ( dirpath )
+
+ elif os.path.islink ( dirpath ):
+ self.info (
+ '{!r} is a symlink - skipping setupdir '
+ 'actions.\n'.format ( dirpath )
+ )
+ dirs_already_excluded.add ( dirpath )
+
+ elif dirmask & WANT_USERDIR:
+ if dirmask & WANT_PRIVATE:
+ private_dirs_chown.add ( dirpath )
+ else:
+ shared_dirs_chown.add ( dirpath )
+
+ elif dirmask & WANT_PRIVATE:
+ private_dirs.add ( dirpath )
+
+ else:
+ shared_dirs.add ( dirpath )
+ # -- end for
+
+
+ private_dirs -= private_dirs_chown
+ shared_dirs_chown -= private_dirs
+ shared_dirs -= shared_dirs_chown
+
+ for dirpath in shared_dirs:
+ dodir_shared ( dirpath, chown=False )
+
+ for dirpath in shared_dirs_chown:
+ dodir_shared ( dirpath, chown=True )
+
+ for dirpath in private_dirs:
+ dodir_private ( dirpath, chown=False )
+
+ for dirpath in private_dirs_chown:
+ dodir_private ( dirpath, chown=True )
+
+ self.setup_env.private_dir.chmod_chown ( self.setup_env.work_root )
+ # --- end of do_setupdirs (...) ---
+
+ def do_write_config_file ( self, pretend ):
+ """Writes the config file to disk."""
+ cfile = self.setup_env.get_config_file_path()
+ if not self.config_file_str:
+ self.setup_env.die ( "no config file created!" )
+ elif pretend:
+ self.info ( "Would write config file to {!r}.\n".format ( cfile ) )
+ else:
+ with open ( cfile, 'wt' ) as FH:
+ FH.write ( self.config_file_str )
+
+ self.setup_env.private_file.chmod_chown ( cfile )
+ # --- end of do_write_config_file (...) ---
+
+ def do_enable_default_hooks ( self, pretend ):
+ """Enables the default hooks, e.g. git history creation."""
+ hook_env = self.setup_env.get_hook_env()
+ if not hook_env.enable_defaults():
+ die ( "failed to enable hooks." )
+ # --- end of do_enable_default_hooks (...) ---
+
+# --- end of SetupInitEnvironment ---
+
+
+class HookScript ( object ):
+
+ def __init__ ( self, fspath, filename=None ):
+ super ( HookScript, self ).__init__()
+ fname = (
+ filename if filename is not None else os.path.basename ( fspath )
+ )
+
+ self.fspath = fspath
+ self.name = os.path.splitext ( fname )[0] or fname
+ static_entry = roverlay.static.hookinfo.get ( self.name, None )
+
+ if static_entry is not None:
+ self.default_events = static_entry[0]
+ self.priority = static_entry[1]
+ self.is_hidden = static_entry[2]
+ else:
+ self.default_events = False
+ self.priority = None
+ self.is_hidden = False
+ # --- end of __init__ (...) ---
+
+ def is_visible ( self ):
+ return not self.is_hidden and (
+ self.priority is None or self.priority >= 0
+ )
+ # --- end of is_visible (...) ---
+
+ def __str__ ( self ):
+ yesno = lambda k: 'y' if k else 'n'
+ return "<{cls} {name!r}, hidden={h} prio={p}>".format (
+ cls=self.__class__.__name__,
+ name=self.name,
+ h=yesno ( self.is_hidden ),
+ p=(
+ "auto" if self.priority is None else
+ ( "IGNORE" if self.priority < 0 else self.priority )
+ ),
+ )
+ # --- end of __str__ (...) ---
+
+ def set_priority_from_generator ( self, number_gen, only_if_unset=True ):
+ if self.priority is None:
+ self.priority = next ( number_gen )
+ return True
+ elif only_if_unset or self.priority < 0:
+ return False
+ else:
+ self.priority = next ( number_gen )
+ return True
+ # --- end of set_priority_from_generator (...) ---
+
+ def get_dest_name ( self, file_ext='.sh', digit_len=2 ):
+ # file_ext has to be .sh, else the script doesn't get recognized
+ # by mux.sh
+
+ prio = self.priority
+ if prio is None or prio < 0:
+ raise AssertionError ( "hook script has no priority." )
+
+ return "{prio:0>{l}d}-{fname}{f_ext}".format (
+ prio=prio, fname=self.name, f_ext=file_ext, l=digit_len,
+ )
+ # --- end of get_dest_name (...) ---
+
+
+# --- end of HookScript ---
+
+
+class HookScriptDir ( object ):
+
+ def __init__ ( self, root ):
+ super ( HookScriptDir, self ).__init__()
+
+ self.root = root
+ self._scripts = collections.OrderedDict()
+ # --- end of __init__ (...) ---
+
+ def __bool__ ( self ):
+ return bool ( self._scripts )
+ # --- end of __bool__ (...) ---
+
+ def get_script ( self, name ):
+ script = self._scripts [name]
+ return script if script.is_visible() else None
+ # --- end of get_scripts (...) ---
+
+ def iter_default_scripts ( self, unpack=False ):
+ if unpack:
+ for script in self._scripts.values():
+ if script.default_events:
+ for event in script.default_events:
+ yield ( event, script )
+ else:
+ for script in self._scripts.values():
+ if script.default_events:
+ yield script
+ # --- end of iter_default_scripts (...) ---
+
+ def get_default_scripts ( self ):
+ scripts = dict()
+ for event, script in self.iter_default_scripts ( unpack=True ):
+ if event not in scripts:
+ scripts [event] = [ script ]
+ else:
+ scripts [event].append ( script )
+
+ return scripts
+ # --- end of get_default_scripts (...) ---
+
+ def iter_scripts ( self ):
+ for script in self._scripts.values():
+ if script.is_visible():
+ yield script
+ # --- end of iter_scripts (...) ---
+
+ def scan ( self ):
+ root = self.root
+ try:
+ filenames = sorted ( os.listdir ( root ) )
+ except OSError as oserr:
+ if oserr.errno != errno.ENOENT:
+ raise
+
+ else:
+ for fname in filenames:
+ fspath = root + os.sep + fname
+ if os.path.isfile ( fspath ):
+ script_obj = HookScript ( fspath, fname )
+ self._scripts [script_obj.name] = script_obj
+ # --- end of scan (...) ---
+
+# --- end of HookScriptDir ---
+
+
+class SetupHookEnvironment ( SetupSubEnvironment ):
+
+ NEEDS_CONFIG_TREE = True
+
+ def setup ( self ):
+ additions_dir = self.config.get ( 'OVERLAY.additions_dir', None )
+ if additions_dir:
+ self.user_hook_root = os.path.join ( additions_dir, 'hooks' )
+ self.writable = self.setup_env.private_file.check_writable (
+ self.user_hook_root + os.sep + '.keep'
+ )
+ else:
+ self.user_hook_root = None
+ self.writable = None
+
+ self.hook_root = HookScriptDir (
+ os.path.join ( self.setup_env.data_root, 'hooks' )
+ )
+ self.hook_root.scan()
+ self._prio_gen = roverlay.util.counter.UnsafeCounter ( 30 )
+ # --- end of setup (...) ---
+
+ def _link_hook ( self, source, link ):
+ if os.path.lexists ( link ):
+ linkdest = os.path.realpath ( link )
+
+ message = 'Skipping activation of hook {!r} - '.format ( link )
+
+ if linkdest == source or linkdest == os.path.realpath ( source ):
+ self.info ( message + "already set up.\n" )
+ return True
+
+ elif link != linkdest:
+ # symlink or link was relative
+ self.error ( message + "is a link to another file.\n" )
+ else:
+ self.error ( message + "exists, but is not a link.\n" )
+
+ return None
+ else:
+ return self.setup_env.private_file.symlink ( source, link )
+ # --- end of _link_hook (...) ---
+
+ def link_hooks_v ( self, event_name, hooks ):
+ success = False
+
+ if self.writable and self.user_hook_root:
+ destdir = self.user_hook_root + os.sep + event_name
+ self.setup_env.private_dir.dodir ( destdir )
+
+ to_link = []
+ for script in hooks:
+ script.set_priority_from_generator ( self._prio_gen )
+ to_link.append (
+ ( script.fspath, destdir + os.sep + script.get_dest_name() )
+ )
+
+ success = True
+ for source, link_name in to_link:
+ if self._link_hook ( source, link_name ) is False:
+ success = False
+ # -- end if
+
+ return success
+ # --- end of link_hooks_v (...) ---
+
+ def enable_defaults ( self ):
+ # not strict: missing hooks are ignored
+ success = False
+ if self.hook_root:
+ success = True
+ default_hooks = self.hook_root.get_default_scripts()
+ for event, hooks in default_hooks.items():
+ if not self.link_hooks_v ( event, hooks ):
+ success = False
+ # -- end if
+
+ return success
+ # --- end of enable_defaults (...) ---
+
+
+# --- end of SetupHookEnvironment ---
+
+
+def setup_main():
+ env = SetupEnvironment()
+ env.setup()
+
+ if env.wants_command ( "mkconfig" ):
+ env.write_config_file ( env.options ['output'] )
+ elif env.wants_command ( "init" ):
+ env.get_init_env().run()
+
+
+# --- end of setup_main (...) ---
next reply other threads:[~2013-09-10 14:41 UTC|newest]
Thread overview: 159+ messages / expand[flat|nested] mbox.gz Atom feed top
2013-09-10 14:40 André Erdmann [this message]
-- strict thread matches above, loose matches on Subject: below --
2015-01-26 17:41 [gentoo-commits] proj/R_overlay:master commit in: roverlay/ André Erdmann
2015-01-26 17:41 André Erdmann
2014-07-18 16:20 André Erdmann
2014-07-18 2:50 [gentoo-commits] proj/R_overlay:wip/addition_control " André Erdmann
2014-07-18 16:20 ` [gentoo-commits] proj/R_overlay:master " André Erdmann
2014-07-18 2:28 [gentoo-commits] proj/R_overlay:wip/addition_control " André Erdmann
2014-07-18 16:20 ` [gentoo-commits] proj/R_overlay:master " André Erdmann
2014-07-16 15:14 André Erdmann
2014-06-05 22:09 André Erdmann
2014-04-01 16:38 André Erdmann
2014-02-16 16:30 André Erdmann
2014-02-15 19:49 André Erdmann
2014-02-15 19:49 André Erdmann
2014-01-25 18:14 André Erdmann
2013-12-11 18:40 André Erdmann
2013-12-11 18:40 André Erdmann
2013-09-23 15:30 André Erdmann
2013-09-20 15:57 André Erdmann
2013-09-19 15:00 André Erdmann
2013-09-17 16:40 André Erdmann
2013-09-17 16:40 André Erdmann
2013-09-17 16:40 André Erdmann
2013-09-17 16:40 André Erdmann
2013-09-16 13:43 André Erdmann
2013-09-13 15:10 André Erdmann
2013-09-12 16:36 André Erdmann
2013-09-12 16:36 André Erdmann
2013-09-12 16:36 André Erdmann
2013-09-11 11:14 André Erdmann
2013-09-11 10:19 André Erdmann
2013-09-10 14:40 André Erdmann
2013-09-10 14:40 André Erdmann
2013-09-10 14:40 André Erdmann
2013-09-06 17:27 André Erdmann
2013-09-06 17:27 André Erdmann
2013-09-03 15:50 André Erdmann
2013-09-02 12:27 André Erdmann
2013-09-02 8:44 André Erdmann
2013-08-30 14:49 André Erdmann
2013-08-30 14:49 André Erdmann
2013-08-29 12:36 André Erdmann
2013-08-29 12:36 André Erdmann
2013-08-28 15:54 André Erdmann
2013-08-27 15:39 André Erdmann
2013-08-23 13:52 André Erdmann
2013-08-23 13:52 André Erdmann
2013-08-23 13:52 André Erdmann
2013-08-19 15:42 André Erdmann
2013-08-16 14:05 André Erdmann
2013-08-16 11:02 André Erdmann
2013-08-16 10:43 André Erdmann
2013-08-16 10:43 André Erdmann
2013-08-14 14:56 André Erdmann
2013-08-14 14:56 André Erdmann
2013-08-13 8:56 André Erdmann
2013-08-13 8:56 André Erdmann
2013-08-13 8:56 André Erdmann
2013-08-12 8:28 André Erdmann
2013-08-12 8:18 André Erdmann
2013-08-07 16:10 André Erdmann
2013-08-02 14:30 André Erdmann
2013-08-02 10:34 André Erdmann
2013-08-02 10:34 André Erdmann
2013-08-01 12:44 André Erdmann
2013-08-01 12:44 André Erdmann
2013-07-29 14:56 André Erdmann
2013-07-29 8:55 André Erdmann
2013-07-26 13:02 André Erdmann
2013-07-23 7:51 André Erdmann
2013-07-23 7:51 André Erdmann
2013-07-19 18:00 [gentoo-commits] proj/R_overlay:gsoc13/next " André Erdmann
2013-07-23 7:51 ` [gentoo-commits] proj/R_overlay:master " André Erdmann
2013-07-17 18:05 [gentoo-commits] proj/R_overlay:gsoc13/next " André Erdmann
2013-07-17 18:05 ` [gentoo-commits] proj/R_overlay:master " André Erdmann
2013-07-15 22:31 [gentoo-commits] proj/R_overlay:gsoc13/next " André Erdmann
2013-07-16 16:36 ` [gentoo-commits] proj/R_overlay:master " André Erdmann
2013-07-12 13:57 André Erdmann
2013-06-22 15:24 André Erdmann
2013-06-22 15:24 André Erdmann
2013-06-22 15:24 André Erdmann
2013-06-22 15:24 André Erdmann
2013-06-19 18:58 [gentoo-commits] proj/R_overlay:gsoc13/next " André Erdmann
2013-06-22 15:24 ` [gentoo-commits] proj/R_overlay:master " André Erdmann
2013-06-19 18:58 [gentoo-commits] proj/R_overlay:gsoc13/next " André Erdmann
2013-06-19 18:59 ` [gentoo-commits] proj/R_overlay:master " André Erdmann
2013-06-13 16:34 André Erdmann
2013-06-05 18:08 [gentoo-commits] proj/R_overlay:gsoc13/next " André Erdmann
2013-06-13 16:34 ` [gentoo-commits] proj/R_overlay:master " André Erdmann
2013-06-05 18:08 [gentoo-commits] proj/R_overlay:gsoc13/next " André Erdmann
2013-06-13 16:34 ` [gentoo-commits] proj/R_overlay:master " André Erdmann
2013-06-04 21:06 André Erdmann
2013-04-25 16:44 André Erdmann
2013-04-25 16:44 André Erdmann
2013-03-05 11:27 André Erdmann
2013-02-09 20:45 André Erdmann
2013-02-05 17:48 André Erdmann
2013-02-05 17:48 André Erdmann
2013-01-30 20:16 André Erdmann
2013-01-30 20:16 André Erdmann
2013-01-28 23:54 André Erdmann
2013-01-28 23:54 André Erdmann
2013-01-28 23:54 André Erdmann
2012-10-02 10:04 André Erdmann
2012-08-20 11:16 André Erdmann
2012-08-13 18:07 André Erdmann
2012-08-09 9:26 André Erdmann
2012-08-08 23:46 André Erdmann
2012-08-08 23:46 André Erdmann
2012-08-07 8:50 André Erdmann
2012-08-02 15:14 André Erdmann
2012-08-01 7:25 André Erdmann
2012-07-31 17:51 André Erdmann
2012-07-30 8:52 André Erdmann
2012-07-30 8:52 André Erdmann
2012-07-24 16:59 [gentoo-commits] proj/R_overlay:overlay_wip " André Erdmann
2012-07-30 8:52 ` [gentoo-commits] proj/R_overlay:master " André Erdmann
2012-07-18 16:49 [gentoo-commits] proj/R_overlay:overlay_wip " André Erdmann
2012-07-30 8:52 ` [gentoo-commits] proj/R_overlay:master " André Erdmann
2012-07-16 16:15 André Erdmann
2012-07-16 16:15 André Erdmann
2012-07-16 16:15 [gentoo-commits] proj/R_overlay:depres_wip " André Erdmann
2012-07-16 16:15 ` [gentoo-commits] proj/R_overlay:master " André Erdmann
2012-07-10 17:43 André Erdmann
2012-07-09 17:19 André Erdmann
2012-07-04 18:21 André Erdmann
2012-07-04 18:21 André Erdmann
2012-07-03 17:48 André Erdmann
2012-06-28 13:29 André Erdmann
2012-06-26 15:42 André Erdmann
2012-06-25 18:19 André Erdmann
2012-06-21 16:55 André Erdmann
2012-06-20 19:03 André Erdmann
2012-06-20 19:03 André Erdmann
2012-06-18 16:27 André Erdmann
2012-06-15 20:34 André Erdmann
2012-06-15 20:34 André Erdmann
2012-06-15 20:34 André Erdmann
2012-06-15 20:34 André Erdmann
2012-06-15 20:34 André Erdmann
2012-06-15 20:34 André Erdmann
2012-06-12 17:17 André Erdmann
2012-06-06 19:52 André Erdmann
2012-06-06 19:52 André Erdmann
2012-06-06 19:52 André Erdmann
2012-06-05 17:30 André Erdmann
2012-06-04 19:07 André Erdmann
2012-06-04 19:07 André Erdmann
2012-06-04 15:43 André Erdmann
2012-06-01 16:19 André Erdmann
2012-06-01 16:19 André Erdmann
2012-06-01 15:46 André Erdmann
2012-05-31 18:24 André Erdmann
2012-05-30 20:15 André Erdmann
2012-05-30 19:36 André Erdmann
2012-05-30 19:36 André Erdmann
2012-05-30 16:09 André Erdmann
2012-05-30 16:09 André Erdmann
2012-05-30 16:09 André Erdmann
2012-05-30 16:09 André Erdmann
2012-05-30 10:58 André Erdmann
2012-05-30 10:58 André Erdmann
2012-05-30 10:58 André Erdmann
2012-05-30 10:58 André Erdmann
2012-05-29 17:09 André Erdmann
2012-05-29 17:09 André Erdmann
2012-05-29 17:09 André Erdmann
2012-05-29 17:09 André Erdmann
2012-05-29 17:09 André Erdmann
2012-05-26 13:14 André Erdmann
2012-05-26 13:14 André Erdmann
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1378824001.371a3c585e51383a05df6986f0c6b02631147cc7.dywi@gentoo \
--to=dywi@mailerd.de \
--cc=gentoo-commits@lists.gentoo.org \
--cc=gentoo-dev@lists.gentoo.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox