From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from lists.gentoo.org (pigeon.gentoo.org [208.92.234.80]) by finch.gentoo.org (Postfix) with ESMTP id 297911381F3 for ; Fri, 12 Jul 2013 12:36:18 +0000 (UTC) Received: from pigeon.gentoo.org (localhost [127.0.0.1]) by pigeon.gentoo.org (Postfix) with SMTP id 33DDDE09C1; Fri, 12 Jul 2013 12:36:15 +0000 (UTC) Received: from smtp.gentoo.org (smtp.gentoo.org [140.211.166.183]) (using TLSv1 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by pigeon.gentoo.org (Postfix) with ESMTPS id A6BE6E09C1 for ; Fri, 12 Jul 2013 12:36:14 +0000 (UTC) Received: from hornbill.gentoo.org (hornbill.gentoo.org [94.100.119.163]) (using TLSv1 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by smtp.gentoo.org (Postfix) with ESMTPS id 2DBFB33E9F8 for ; Fri, 12 Jul 2013 12:36:13 +0000 (UTC) Received: from localhost.localdomain (localhost [127.0.0.1]) by hornbill.gentoo.org (Postfix) with ESMTP id C351FE468F for ; Fri, 12 Jul 2013 12:36:11 +0000 (UTC) From: "André Erdmann" To: gentoo-commits@lists.gentoo.org Content-Transfer-Encoding: 8bit Content-type: text/plain; charset=UTF-8 Reply-To: gentoo-dev@lists.gentoo.org, "André Erdmann" Message-ID: <1373632356.98ec4275cb1d98a114b8b95ecfc5643ddaa7d04c.dywi@gentoo> Subject: [gentoo-commits] proj/R_overlay:gsoc13/next commit in: roverlay/config/, roverlay/ X-VCS-Repository: proj/R_overlay X-VCS-Files: roverlay/argutil.py roverlay/config/entrymap.py roverlay/main.py X-VCS-Directories: roverlay/config/ roverlay/ X-VCS-Committer: dywi X-VCS-Committer-Name: André Erdmann X-VCS-Revision: 98ec4275cb1d98a114b8b95ecfc5643ddaa7d04c X-VCS-Branch: gsoc13/next Date: Fri, 12 Jul 2013 12:36:11 +0000 (UTC) Precedence: bulk List-Post: List-Help: List-Unsubscribe: List-Subscribe: List-Id: Gentoo Linux mail X-BeenThere: gentoo-commits@lists.gentoo.org X-Archives-Salt: 7ac4d156-ca3e-443e-b4fa-184bd599a053 X-Archives-Hash: fc5d72b5fe06179644b4f596b785c8a0 commit: 98ec4275cb1d98a114b8b95ecfc5643ddaa7d04c Author: André Erdmann mailerd de> AuthorDate: Fri Jul 12 12:32:36 2013 +0000 Commit: André Erdmann mailerd de> CommitDate: Fri Jul 12 12:32:36 2013 +0000 URL: http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=98ec4275 roverlay: setupdirs command The 'setupdirs' creates roverlay's filesystem layout (based on what has been configured). --- roverlay/argutil.py | 58 ++++++++++++++++++++++++++++++++++++++- roverlay/config/entrymap.py | 32 ++++++++++++++++++++-- roverlay/main.py | 67 ++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 153 insertions(+), 4 deletions(-) diff --git a/roverlay/argutil.py b/roverlay/argutil.py index c6fc0db..120132c 100644 --- a/roverlay/argutil.py +++ b/roverlay/argutil.py @@ -8,10 +8,30 @@ __all__ = [ 'parse_argv', ] -import os.path +import os import argparse +import pwd +import grp + import roverlay +def get_uid ( user ): + try: + return int ( user ) + #pwd.getpwuid(^).pw_uid + except ValueError: + pass + return pwd.getpwnam ( user ).pw_uid + +def get_gid ( group ): + try: + return int ( group ) + #grp.getgrgid(^).gr_gid + except ValueError: + pass + return grp.getgrnam ( group ).gr_gid + + def get_parser ( command_map, default_config_file, default_command='create' ): """Returns an arg parsers. @@ -21,6 +41,24 @@ def get_parser ( command_map, default_config_file, default_command='create' ): * default_command -- the default command """ + def is_uid ( value ): + try: + return get_uid ( value ) + except: + pass + raise argparse.ArgumentTypeError ( + "no such user/uid: {}".format ( value ) + ) + + def is_gid ( value ): + try: + return get_gid ( value ) + except: + pass + raise argparse.ArgumentTypeError ( + "no such group/gid: {}".format ( value ) + ) + def is_fs_file ( value ): f = os.path.abspath ( value ) if not os.path.isfile ( f ): @@ -353,6 +391,22 @@ def get_parser ( command_map, default_config_file, default_command='create' ): type=couldbe_stdout_or_file, ) + arg ( + '--target-uid', + metavar="", + help="setupdirs command: uid of the user that will run roverlay", + default=os.getuid(), + type=is_uid, + ) + + arg ( + '--target-gid', + metavar="", + help="setupdirs command: gid of the user that will run roverlay", + default=os.getgid(), + type=is_gid, + ) + # # TODO # arg ( # '--debug', @@ -421,6 +475,8 @@ def parse_argv ( command_map, **kw ): dump_file = p.dump_file, fixup_category_move = p.fixup_category_move, fixup_category_move_rev = p.fixup_category_move_rev, + target_uid = p.target_uid, + target_gid = p.target_gid, ) if given ( 'overlay' ): diff --git a/roverlay/config/entrymap.py b/roverlay/config/entrymap.py index de29ca7..86c17da 100644 --- a/roverlay/config/entrymap.py +++ b/roverlay/config/entrymap.py @@ -65,6 +65,17 @@ is_log_level = { 'choices' : LOG_LEVEL, 'flags' : CAPSLOCK } only_vtype = lambda x : { 'value_type': x } +# mask for want_create_dir +WANT_PRIVATE = 1 +WANT_FILEDIR = 2 +WANT_USERDIR = 4 + +WANT_PUBLIC_DIR = 0 +WANT_PUBLIC_FILEDIR = WANT_FILEDIR +WANT_PRIVATE_DIR = WANT_PRIVATE +WANT_PRIVATE_FILEDIR = WANT_PRIVATE | WANT_FILEDIR + + def _verify_distdir_strategy ( strategy, logger ): methods = set ( strategy ) if not strategy: @@ -111,12 +122,14 @@ CONFIG_ENTRY_MAP = dict ( description = '''NOT IN USE. file where resolved dep strings will be written to. ''', + want_dir_create = WANT_PRIVATE_FILEDIR | WANT_USERDIR, ), log_file_unresolvable = dict ( value_type = fs_file, description = '''file where unresolved dependency strings will be written to - ''' + ''', + want_dir_create = WANT_PRIVATE_FILEDIR | WANT_USERDIR, ), # === logging to console === @@ -154,6 +167,7 @@ CONFIG_ENTRY_MAP = dict ( path = [ 'LOG', 'FILE', 'file' ], value_type = fs_file, description = "log file to write", + want_dir_create = WANT_PRIVATE_FILEDIR | WANT_USERDIR, ), log_file_level = dict ( @@ -227,12 +241,15 @@ CONFIG_ENTRY_MAP = dict ( description = ( 'this is the directory of the overlay to be created/maintained' ), + want_dir_create = WANT_PUBLIC_DIR | WANT_USERDIR, ), overlay_additions_dir = dict ( path = [ 'OVERLAY', 'additions_dir', ], value_type = 'fs_abs:fs_dir', description = 'directory containing ebuilds and ebuild patches', + # FIXME: WANT_USERDIR or not? + want_dir_create = WANT_PRIVATE_DIR, ), overlay_eclass = dict ( @@ -279,6 +296,7 @@ CONFIG_ENTRY_MAP = dict ( 'to all package files will be created ' '(during Manifest file creation)' ), + want_dir_create = WANT_PUBLIC_DIR | WANT_USERDIR, ), overlay_distdir_strategy = dict ( @@ -316,6 +334,7 @@ CONFIG_ENTRY_MAP = dict ( path = [ 'OVERLAY', 'DISTMAP', 'dbfile', ], value_type = 'fs_file', description = 'distmap file', + want_dir_create = WANT_PRIVATE_FILEDIR | WANT_USERDIR, ), # * alias @@ -345,6 +364,7 @@ CONFIG_ENTRY_MAP = dict ( path = [ 'EBUILD', 'USE_EXPAND', 'desc_file', ], description = "USE_EXPAND flag description file", value_type = 'fs_file', + want_dir_create = WANT_PRIVATE_FILEDIR, ), ebuild_use_expand_name = dict ( @@ -358,6 +378,7 @@ CONFIG_ENTRY_MAP = dict ( path = [ 'EBUILD', 'USE_EXPAND', 'rename_file', ], description = 'file for renaming USE_EXPAND flags', value_type = 'fs_file', + want_dir_create = WANT_PRIVATE_FILEDIR, ), # * alias @@ -380,6 +401,7 @@ CONFIG_ENTRY_MAP = dict ( 'this is the directory where per-repo package directories ' 'will be created' ), + want_dir_create = WANT_PRIVATE_FILEDIR | WANT_USERDIR, ), # the repo config file(s) @@ -387,6 +409,7 @@ CONFIG_ENTRY_MAP = dict ( path = [ 'REPO', 'config_files' ], value_type = fs_abslist, description = 'list of repo config files', + want_dir_create = WANT_PRIVATE_FILEDIR, ), # this option is used to limit bandwidth usage while running rsync @@ -411,6 +434,7 @@ CONFIG_ENTRY_MAP = dict ( path = [ 'DEPRES', 'SIMPLE_RULES', 'files' ], value_type = fs_abslist, description = "list of dependency rule files", + want_dir_create = WANT_PRIVATE_FILEDIR, ), # * alias @@ -425,6 +449,7 @@ CONFIG_ENTRY_MAP = dict ( path = [ 'DESCRIPTION', 'field_definition_file' ], value_type = fs_file, description = "config file that controls DESCRIPTION file reading", + want_dir_create = WANT_PRIVATE_FILEDIR, ), # * for debugging @@ -434,7 +459,8 @@ CONFIG_ENTRY_MAP = dict ( value_type = 'fs_abs:fs_dir', description = '''if set: write description files (read from tarballs) into this directory. Leave blank / comment out to disable. - ''' + ''', + want_dir_create = WANT_PRIVATE_FILEDIR | WANT_USERDIR, ), # * alias @@ -449,6 +475,7 @@ CONFIG_ENTRY_MAP = dict ( path = [ 'PACKAGE_RULES', 'files' ], value_type = fs_abslist, description = 'list of package rule files/dirs', + want_dir_create = WANT_PRIVATE_FILEDIR, ), # * alias @@ -488,6 +515,7 @@ CONFIG_ENTRY_MAP = dict ( path = [ 'CACHEDIR', 'root', ], value_type = 'fs_dir', description = 'directory for cache data', + want_dir_create = WANT_PRIVATE_DIR | WANT_USERDIR, ), nosync = dict ( diff --git a/roverlay/main.py b/roverlay/main.py index 1513b1d..75d1e2f 100644 --- a/roverlay/main.py +++ b/roverlay/main.py @@ -63,6 +63,55 @@ class DIE ( object ): # --- DIE: exit codes --- die = DIE.die +def run_setupdirs ( config, target_uid, target_gid ): + import stat + import roverlay.util + import roverlay.config.entrymap + import roverlay.config.entryutil + + dodir = roverlay.util.dodir + find_config_path = roverlay.config.entryutil.find_config_path + + dirmode_private = stat.S_IRWXU | stat.S_IRGRP | stat.S_IXGRP + #clear_mode = ~(stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO) + #get_mode = lambda old, want_mode: ( old & clear_mode ) | want_mode + + 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, )) + + my_uid = os.getuid() + my_gid = os.getgid() + should_chown = my_uid != target_uid or my_gid != target_gid + + # 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 dirpath: + dodir ( dirpath ) + if dirmask & WANT_PRIVATE: + os.chmod ( dirpath, dirmode_private ) + if dirmask & WANT_USERDIR and should_chown: + os.chown ( dirpath, target_uid, target_gid ) + + + return os.EX_OK +# --- end of run_setupdirs (...) --- + def main_installed(): return main ( ROVERLAY_INSTALLED=True ) @@ -332,6 +381,7 @@ def main ( 'depres' : 'this is an alias to \'depres_console\'', 'nop' : 'does nothing', 'apply_rules' : 'apply package rules verbosely and exit afterwards', + 'setupdirs' : 'create configured directories etc.', } @@ -372,8 +422,16 @@ def main ( actions_done = set() set_action_done = actions_done.add + want_logging = True + do_setupdirs = False + if 'sync' in actions and OPTION ( 'nosync' ): die ( "sync command blocked by --nosync opt.", DIE.ARG ) + elif 'setupdirs' in actions: + do_setupdirs = True + want_logging = False + if len ( actions ) > 1: + die ( "setupdirs cannot be run with other commands!", DIE.USAGE ) del commands @@ -399,7 +457,8 @@ def main ( conf = roverlay.load_config_file ( config_file, - extraconf=additional_config + extraconf=additional_config, + setup_logger=want_logging, ) del config_file, additional_config except: @@ -413,6 +472,12 @@ def main ( else: raise + + if do_setupdirs: + sys.exit ( run_setupdirs ( + conf, extra_opts['target_uid'], extra_opts['target_gid'] + ) ) + if OPTION ( 'list_config' ): try: from roverlay.config.entryutil import list_entries From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from lists.gentoo.org (pigeon.gentoo.org [208.92.234.80]) by finch.gentoo.org (Postfix) with ESMTP id 6F8771381F3 for ; Fri, 12 Jul 2013 13:57:08 +0000 (UTC) Received: from pigeon.gentoo.org (localhost [127.0.0.1]) by pigeon.gentoo.org (Postfix) with SMTP id 548C5E09DB; Fri, 12 Jul 2013 13:57:06 +0000 (UTC) Received: from smtp.gentoo.org (smtp.gentoo.org [140.211.166.183]) (using TLSv1 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by pigeon.gentoo.org (Postfix) with ESMTPS id 99449E09DB for ; Fri, 12 Jul 2013 13:57:05 +0000 (UTC) Received: from hornbill.gentoo.org (hornbill.gentoo.org [94.100.119.163]) (using TLSv1 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by smtp.gentoo.org (Postfix) with ESMTPS id 6DC1C33E958 for ; Fri, 12 Jul 2013 13:57:04 +0000 (UTC) Received: from localhost.localdomain (localhost [127.0.0.1]) by hornbill.gentoo.org (Postfix) with ESMTP id F3E5BE5468 for ; Fri, 12 Jul 2013 13:57:01 +0000 (UTC) From: "André Erdmann" To: gentoo-commits@lists.gentoo.org Content-Transfer-Encoding: 8bit Content-type: text/plain; charset=UTF-8 Reply-To: gentoo-dev@lists.gentoo.org, "André Erdmann" Message-ID: <1373632356.98ec4275cb1d98a114b8b95ecfc5643ddaa7d04c.dywi@gentoo> Subject: [gentoo-commits] proj/R_overlay:master commit in: roverlay/config/, roverlay/ X-VCS-Repository: proj/R_overlay X-VCS-Files: roverlay/argutil.py roverlay/config/entrymap.py roverlay/main.py X-VCS-Directories: roverlay/config/ roverlay/ X-VCS-Committer: dywi X-VCS-Committer-Name: André Erdmann X-VCS-Revision: 98ec4275cb1d98a114b8b95ecfc5643ddaa7d04c X-VCS-Branch: master Date: Fri, 12 Jul 2013 13:57:01 +0000 (UTC) Precedence: bulk List-Post: List-Help: List-Unsubscribe: List-Subscribe: List-Id: Gentoo Linux mail X-BeenThere: gentoo-commits@lists.gentoo.org X-Archives-Salt: ca5ff4ee-2c9d-46fd-8745-4683cc4549f0 X-Archives-Hash: e2cb0e4c5594deeb76caa20173f0d84f Message-ID: <20130712135701.gHNj1GzMXIl7ri8HkNsKY_p0e_t2hmIknENghRvPz3U@z> commit: 98ec4275cb1d98a114b8b95ecfc5643ddaa7d04c Author: André Erdmann mailerd de> AuthorDate: Fri Jul 12 12:32:36 2013 +0000 Commit: André Erdmann mailerd de> CommitDate: Fri Jul 12 12:32:36 2013 +0000 URL: http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=98ec4275 roverlay: setupdirs command The 'setupdirs' creates roverlay's filesystem layout (based on what has been configured). --- roverlay/argutil.py | 58 ++++++++++++++++++++++++++++++++++++++- roverlay/config/entrymap.py | 32 ++++++++++++++++++++-- roverlay/main.py | 67 ++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 153 insertions(+), 4 deletions(-) diff --git a/roverlay/argutil.py b/roverlay/argutil.py index c6fc0db..120132c 100644 --- a/roverlay/argutil.py +++ b/roverlay/argutil.py @@ -8,10 +8,30 @@ __all__ = [ 'parse_argv', ] -import os.path +import os import argparse +import pwd +import grp + import roverlay +def get_uid ( user ): + try: + return int ( user ) + #pwd.getpwuid(^).pw_uid + except ValueError: + pass + return pwd.getpwnam ( user ).pw_uid + +def get_gid ( group ): + try: + return int ( group ) + #grp.getgrgid(^).gr_gid + except ValueError: + pass + return grp.getgrnam ( group ).gr_gid + + def get_parser ( command_map, default_config_file, default_command='create' ): """Returns an arg parsers. @@ -21,6 +41,24 @@ def get_parser ( command_map, default_config_file, default_command='create' ): * default_command -- the default command """ + def is_uid ( value ): + try: + return get_uid ( value ) + except: + pass + raise argparse.ArgumentTypeError ( + "no such user/uid: {}".format ( value ) + ) + + def is_gid ( value ): + try: + return get_gid ( value ) + except: + pass + raise argparse.ArgumentTypeError ( + "no such group/gid: {}".format ( value ) + ) + def is_fs_file ( value ): f = os.path.abspath ( value ) if not os.path.isfile ( f ): @@ -353,6 +391,22 @@ def get_parser ( command_map, default_config_file, default_command='create' ): type=couldbe_stdout_or_file, ) + arg ( + '--target-uid', + metavar="", + help="setupdirs command: uid of the user that will run roverlay", + default=os.getuid(), + type=is_uid, + ) + + arg ( + '--target-gid', + metavar="", + help="setupdirs command: gid of the user that will run roverlay", + default=os.getgid(), + type=is_gid, + ) + # # TODO # arg ( # '--debug', @@ -421,6 +475,8 @@ def parse_argv ( command_map, **kw ): dump_file = p.dump_file, fixup_category_move = p.fixup_category_move, fixup_category_move_rev = p.fixup_category_move_rev, + target_uid = p.target_uid, + target_gid = p.target_gid, ) if given ( 'overlay' ): diff --git a/roverlay/config/entrymap.py b/roverlay/config/entrymap.py index de29ca7..86c17da 100644 --- a/roverlay/config/entrymap.py +++ b/roverlay/config/entrymap.py @@ -65,6 +65,17 @@ is_log_level = { 'choices' : LOG_LEVEL, 'flags' : CAPSLOCK } only_vtype = lambda x : { 'value_type': x } +# mask for want_create_dir +WANT_PRIVATE = 1 +WANT_FILEDIR = 2 +WANT_USERDIR = 4 + +WANT_PUBLIC_DIR = 0 +WANT_PUBLIC_FILEDIR = WANT_FILEDIR +WANT_PRIVATE_DIR = WANT_PRIVATE +WANT_PRIVATE_FILEDIR = WANT_PRIVATE | WANT_FILEDIR + + def _verify_distdir_strategy ( strategy, logger ): methods = set ( strategy ) if not strategy: @@ -111,12 +122,14 @@ CONFIG_ENTRY_MAP = dict ( description = '''NOT IN USE. file where resolved dep strings will be written to. ''', + want_dir_create = WANT_PRIVATE_FILEDIR | WANT_USERDIR, ), log_file_unresolvable = dict ( value_type = fs_file, description = '''file where unresolved dependency strings will be written to - ''' + ''', + want_dir_create = WANT_PRIVATE_FILEDIR | WANT_USERDIR, ), # === logging to console === @@ -154,6 +167,7 @@ CONFIG_ENTRY_MAP = dict ( path = [ 'LOG', 'FILE', 'file' ], value_type = fs_file, description = "log file to write", + want_dir_create = WANT_PRIVATE_FILEDIR | WANT_USERDIR, ), log_file_level = dict ( @@ -227,12 +241,15 @@ CONFIG_ENTRY_MAP = dict ( description = ( 'this is the directory of the overlay to be created/maintained' ), + want_dir_create = WANT_PUBLIC_DIR | WANT_USERDIR, ), overlay_additions_dir = dict ( path = [ 'OVERLAY', 'additions_dir', ], value_type = 'fs_abs:fs_dir', description = 'directory containing ebuilds and ebuild patches', + # FIXME: WANT_USERDIR or not? + want_dir_create = WANT_PRIVATE_DIR, ), overlay_eclass = dict ( @@ -279,6 +296,7 @@ CONFIG_ENTRY_MAP = dict ( 'to all package files will be created ' '(during Manifest file creation)' ), + want_dir_create = WANT_PUBLIC_DIR | WANT_USERDIR, ), overlay_distdir_strategy = dict ( @@ -316,6 +334,7 @@ CONFIG_ENTRY_MAP = dict ( path = [ 'OVERLAY', 'DISTMAP', 'dbfile', ], value_type = 'fs_file', description = 'distmap file', + want_dir_create = WANT_PRIVATE_FILEDIR | WANT_USERDIR, ), # * alias @@ -345,6 +364,7 @@ CONFIG_ENTRY_MAP = dict ( path = [ 'EBUILD', 'USE_EXPAND', 'desc_file', ], description = "USE_EXPAND flag description file", value_type = 'fs_file', + want_dir_create = WANT_PRIVATE_FILEDIR, ), ebuild_use_expand_name = dict ( @@ -358,6 +378,7 @@ CONFIG_ENTRY_MAP = dict ( path = [ 'EBUILD', 'USE_EXPAND', 'rename_file', ], description = 'file for renaming USE_EXPAND flags', value_type = 'fs_file', + want_dir_create = WANT_PRIVATE_FILEDIR, ), # * alias @@ -380,6 +401,7 @@ CONFIG_ENTRY_MAP = dict ( 'this is the directory where per-repo package directories ' 'will be created' ), + want_dir_create = WANT_PRIVATE_FILEDIR | WANT_USERDIR, ), # the repo config file(s) @@ -387,6 +409,7 @@ CONFIG_ENTRY_MAP = dict ( path = [ 'REPO', 'config_files' ], value_type = fs_abslist, description = 'list of repo config files', + want_dir_create = WANT_PRIVATE_FILEDIR, ), # this option is used to limit bandwidth usage while running rsync @@ -411,6 +434,7 @@ CONFIG_ENTRY_MAP = dict ( path = [ 'DEPRES', 'SIMPLE_RULES', 'files' ], value_type = fs_abslist, description = "list of dependency rule files", + want_dir_create = WANT_PRIVATE_FILEDIR, ), # * alias @@ -425,6 +449,7 @@ CONFIG_ENTRY_MAP = dict ( path = [ 'DESCRIPTION', 'field_definition_file' ], value_type = fs_file, description = "config file that controls DESCRIPTION file reading", + want_dir_create = WANT_PRIVATE_FILEDIR, ), # * for debugging @@ -434,7 +459,8 @@ CONFIG_ENTRY_MAP = dict ( value_type = 'fs_abs:fs_dir', description = '''if set: write description files (read from tarballs) into this directory. Leave blank / comment out to disable. - ''' + ''', + want_dir_create = WANT_PRIVATE_FILEDIR | WANT_USERDIR, ), # * alias @@ -449,6 +475,7 @@ CONFIG_ENTRY_MAP = dict ( path = [ 'PACKAGE_RULES', 'files' ], value_type = fs_abslist, description = 'list of package rule files/dirs', + want_dir_create = WANT_PRIVATE_FILEDIR, ), # * alias @@ -488,6 +515,7 @@ CONFIG_ENTRY_MAP = dict ( path = [ 'CACHEDIR', 'root', ], value_type = 'fs_dir', description = 'directory for cache data', + want_dir_create = WANT_PRIVATE_DIR | WANT_USERDIR, ), nosync = dict ( diff --git a/roverlay/main.py b/roverlay/main.py index 1513b1d..75d1e2f 100644 --- a/roverlay/main.py +++ b/roverlay/main.py @@ -63,6 +63,55 @@ class DIE ( object ): # --- DIE: exit codes --- die = DIE.die +def run_setupdirs ( config, target_uid, target_gid ): + import stat + import roverlay.util + import roverlay.config.entrymap + import roverlay.config.entryutil + + dodir = roverlay.util.dodir + find_config_path = roverlay.config.entryutil.find_config_path + + dirmode_private = stat.S_IRWXU | stat.S_IRGRP | stat.S_IXGRP + #clear_mode = ~(stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO) + #get_mode = lambda old, want_mode: ( old & clear_mode ) | want_mode + + 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, )) + + my_uid = os.getuid() + my_gid = os.getgid() + should_chown = my_uid != target_uid or my_gid != target_gid + + # 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 dirpath: + dodir ( dirpath ) + if dirmask & WANT_PRIVATE: + os.chmod ( dirpath, dirmode_private ) + if dirmask & WANT_USERDIR and should_chown: + os.chown ( dirpath, target_uid, target_gid ) + + + return os.EX_OK +# --- end of run_setupdirs (...) --- + def main_installed(): return main ( ROVERLAY_INSTALLED=True ) @@ -332,6 +381,7 @@ def main ( 'depres' : 'this is an alias to \'depres_console\'', 'nop' : 'does nothing', 'apply_rules' : 'apply package rules verbosely and exit afterwards', + 'setupdirs' : 'create configured directories etc.', } @@ -372,8 +422,16 @@ def main ( actions_done = set() set_action_done = actions_done.add + want_logging = True + do_setupdirs = False + if 'sync' in actions and OPTION ( 'nosync' ): die ( "sync command blocked by --nosync opt.", DIE.ARG ) + elif 'setupdirs' in actions: + do_setupdirs = True + want_logging = False + if len ( actions ) > 1: + die ( "setupdirs cannot be run with other commands!", DIE.USAGE ) del commands @@ -399,7 +457,8 @@ def main ( conf = roverlay.load_config_file ( config_file, - extraconf=additional_config + extraconf=additional_config, + setup_logger=want_logging, ) del config_file, additional_config except: @@ -413,6 +472,12 @@ def main ( else: raise + + if do_setupdirs: + sys.exit ( run_setupdirs ( + conf, extra_opts['target_uid'], extra_opts['target_gid'] + ) ) + if OPTION ( 'list_config' ): try: from roverlay.config.entryutil import list_entries