From 3807a881643cddf62fe92c9109a801c6aaec3fe2 Mon Sep 17 00:00:00 2001 From: Alexander Sulfrian Date: Mon, 22 Feb 2016 18:05:09 +0100 Subject: [PATCH] Options: migrated tools/git_commit.py to new parser --- tools/git_commit.py | 286 ++++++++++++++++++++------------------------ 1 file changed, 131 insertions(+), 155 deletions(-) diff --git a/tools/git_commit.py b/tools/git_commit.py index cc4061f255..cba317d683 100755 --- a/tools/git_commit.py +++ b/tools/git_commit.py @@ -3,37 +3,27 @@ back to git. To use this script, enable the Trigger plugin, put this script in /var/lib/bcfg2/Trigger/, and create /etc/bcfg2-commit.conf. -The config file, /etc/bcfg2-commit.conf, may contain four options in -the [global] section: - -* "config" is the path to the Bcfg2 server config file. (Default: - /etc/bcfg2.conf) -* "commit" is a comma-separated list of globs giving the paths that - should be committed back to the repository. Default is 'SSLCA/*, - SSHbase/*, Cfg/*', which will commit data back for SSLCA, SSHbase, - Cfg, FileProbes, etc., but not, for instance, Probes/probed.xml. +The config file, /etc/bcfg2-commit.conf, may contain four options: + +* "config" in [global] is the path to the Bcfg2 server config file. + (Default: /etc/bcfg2.conf) +* "commit" in [global] is a comma-separated list of globs giving the + paths that should be committed back to the repository. Default is + 'SSLCA/*, SSHbase/*, Cfg/*', which will commit data back for SSLCA, + SSHbase, Cfg, FileProbes, etc., but not, for instance, Probes/probed.xml. You may wish to add Metadata/clients.xml to the commit list. -* "debug" and "verbose" let you set the log level for git_commit.py - itself. +* "debug" and "verbose" in [logging] let you set the log level for + git_commit.py itself. """ - import os import sys import git import logging -import Bcfg2.Logger import Bcfg2.Options -from Bcfg2.Compat import ConfigParser +import Bcfg2.Logger from fnmatch import fnmatch -# config file path -CONFIG = "/etc/bcfg2-commit.conf" - -# config defaults. all config options are in the [global] section -DEFAULTS = dict(config='/etc/bcfg2.conf', - commit="SSLCA/*, SSHbase/*, Cfg/*") - def list_changed_files(repo): return [d for d in repo.index.diff(None) @@ -41,141 +31,127 @@ def list_changed_files(repo): not d.renamed and not d.new_file)] -def add_to_commit(patterns, path, repo, relpath): - progname = os.path.basename(sys.argv[0]) - logger = logging.getLogger(progname) - for pattern in patterns: - if fnmatch(path, os.path.join(relpath, pattern)): - logger.debug("%s: Adding %s to commit" % (progname, path)) - repo.index.add([path]) - return True - return False - - -def parse_options(): - config = ConfigParser.SafeConfigParser(DEFAULTS) - config.read(CONFIG) - - optinfo = dict( - profile=Bcfg2.Options.CLIENT_PROFILE, - dryrun=Bcfg2.Options.CLIENT_DRYRUN, - groups=Bcfg2.Options.Option("Groups", - default=[], - cmd="-g", - odesc=':', - cook=Bcfg2.Options.colon_split)) - optinfo.update(Bcfg2.Options.CLI_COMMON_OPTIONS) - optinfo.update(Bcfg2.Options.SERVER_COMMON_OPTIONS) - argv = [Bcfg2.Options.CFILE.cmd, config.get("global", "config")] - argv.extend(sys.argv[1:]) - setup = Bcfg2.Options.OptionParser(optinfo, argv=argv) - setup.parse(argv) - - setup['commit'] = Bcfg2.Options.list_split(config.get("global", - "commit")) - for opt in ['debug', 'verbose']: - try: - setup[opt] = config.getboolean("global", opt) - except ConfigParser.NoOptionError: - pass - - try: - hostname = setup['args'][0] - except IndexError: - print(setup.hm) - raise SystemExit(1) - return (setup, hostname) - - -def setup_logging(setup): - progname = os.path.basename(sys.argv[0]) - log_args = dict(to_syslog=setup['syslog'], to_console=sys.stdout.isatty(), - to_file=setup['logging'], level=logging.WARNING) - if setup['debug']: - log_args['level'] = logging.DEBUG - elif setup['verbose']: - log_args['level'] = logging.INFO - Bcfg2.Logger.setup_logging(progname, **log_args) - return logging.getLogger(progname) - - -def main(): - progname = os.path.basename(sys.argv[0]) - setup, hostname = parse_options() - logger = setup_logging(setup) - if setup['dryrun']: - logger.info("%s: In dry-run mode, changes will not be committed" % - progname) - - if setup['vcs_root']: - gitroot = os.path.realpath(setup['vcs_root']) - else: - gitroot = os.path.realpath(setup['repo']) - logger.info("%s: Using Git repo at %s" % (progname, gitroot)) - try: - repo = git.Repo(gitroot) - except: # pylint: disable=W0702 - logger.error("%s: Error setting up Git repo at %s: %s" % - (progname, gitroot, sys.exc_info()[1])) - return 1 - - # canonicalize the repo path so that git will recognize it as - # being inside the git repo - bcfg2root = os.path.realpath(setup['repo']) - - if not bcfg2root.startswith(gitroot): - logger.error("%s: Bcfg2 repo %s is not inside Git repo %s" % - (progname, bcfg2root, gitroot)) - return 1 - - # relative path to Bcfg2 root from VCS root - if gitroot == bcfg2root: - relpath = '' - else: - relpath = bcfg2root[len(gitroot) + 1:] - - new = 0 - changed = 0 - logger.debug("%s: Untracked files: %s" % (progname, repo.untracked_files)) - for path in repo.untracked_files: - if add_to_commit(setup['commit'], path, repo, relpath): - new += 1 +class CLI(object): + options = [ + Bcfg2.Options.BooleanOption( + '-n', '--dry-run', help='Do not actually commit something'), + Bcfg2.Options.PathOption( + '-c', '--config', action=Bcfg2.Options.ConfigFileAction, + help='Configuration file', default='/etc/bcfg2-commit.conf'), + Bcfg2.Options.Common.repository, + Bcfg2.Options.Common.syslog, + + Bcfg2.Options.PathOption( + cf=('server', 'vcs_root'), default='', + help='VCS repository root'), + Bcfg2.Options.Option( + cf=('global', 'commit'), type=Bcfg2.Options.Types.comma_list, + default=['SSLCA/*', 'SSHbase/*', 'Cfg/*'], help=''), + Bcfg2.Options.PathOption( + cf=('global', 'config'), action=Bcfg2.Options.ConfigFileAction, + default='/etc/bcfg2.conf'), + + # Trigger arguments + Bcfg2.Options.PositionalArgument('hostname', help='Client hostname'), + Bcfg2.Options.Option('-p', '--profile', metavar='', + help='Client profile'), + Bcfg2.Options.Option('-g', '--groups', metavar='', + help='All client groups'), + ] + + def __init__(self): + Bcfg2.Options.get_parser( + description='Trigger script to commit selected changes to a local ' + 'repository back to git.', + components=[self, Bcfg2.Logger._OptionContainer]).parse() + self.progname = os.path.basename(sys.argv[0]) + self.logger = logging.getLogger(self.progname) + + def add_to_commit(self, repo, path, relpath): + for pattern in Bcfg2.Options.setup.commit: + if fnmatch(path, os.path.join(relpath, pattern)): + self.logger.debug('Adding %s to commit' % path) + repo.index.add([path]) + return True + return False + + def run(self): + if Bcfg2.Options.setup.dry_run: + self.logger.info('In dry-run mode, changes will not be committed') + + if 'vcs_root' in Bcfg2.Options.setup: + gitroot = Bcfg2.Options.setup.vcs_root + + if not Bcfg2.Options.setup.repository.startswith(gitroot): + logger.error('Bcfg2 repo %s is not inside Git repo %s' % + (Bcfg2.Options.setup.repository, gitroot)) + return 1 + + relpath = Bcfg2.Options.setup.repository[len(gitroot) + 1:] else: - logger.debug("%s: Not adding %s to commit" % (progname, path)) - logger.debug("%s: Untracked files after building commit: %s" % - (progname, repo.untracked_files)) - - changes = list_changed_files(repo) - logger.info("%s: Changed files: %s" % (progname, - [d.a_blob.path for d in changes])) - for diff in changes: - if add_to_commit(setup['commit'], diff.a_blob.path, repo, relpath): - changed += 1 - else: - logger.debug("%s: Not adding %s to commit" % (progname, - diff.a_blob.path)) - logger.info("%s: Changed files after building commit: %s" % - (progname, [d.a_blob.path for d in list_changed_files(repo)])) - - if new + changed > 0: - logger.debug("%s: Committing %s new files and %s changed files" % - (progname, new, changed)) - if setup['dryrun']: - logger.warning("%s: In dry-run mode, skipping commit and push" % - progname) + gitroot = Bcfg2.Options.setup.repository + relpath = '' + + self.logger.info('Using Git repo at %s' % gitroot) + + try: + repo = git.Repo(gitroot) + except: # pylint: disable=W0702 + self.logger.error('Error setting up Git repo at %s: %s' % + (gitroot, sys.exc_info()[1])) + return 1 + + new = 0 + changed = 0 + self.logger.debug('Untracked files: %s' % repo.untracked_files) + for path in repo.untracked_files: + if self.add_to_commit(repo, path, relpath): + new += 1 + else: + self.logger.debug('Not adding %s to commit' % path) + + self.logger.debug('Untracked files after building commit: %s' % + repo.untracked_files) + + changes = list_changed_files(repo) + self.logger.info('Changed files: %s' % + [d.a_blob.path for d in changes]) + + for diff in changes: + if self.add_to_commit(repo, diff.a_blob.path, relpath): + changed += 1 + else: + self.logger.debug('Not adding %s to commit' % + diff.a_blob.path) + self.logger.info('Changed files after building commit: %s' % + [d.a_blob.path for d in list_changed_files(repo)]) + + if new + changed > 0: + self.logger.debug('Committing %s new files and %s changed files' % + (new, changed)) + + if Bcfg2.Options.setup.dry_run: + self.logger.warning('In dry-run mode, skipping commit ' + 'and push') + else: + output = repo.index.commit('Auto-commit with %s from %s run' % + (self.progname, + Bcfg2.Options.setup.hostname)) + if output: + self.logger.debug(output) + + if 'origin' in repo.remotes: + remote = repo.remote() + self.logger.debug('Pushing to remote %s at %s' % + (remote, remote.url)) + output = remote.push() + if output: + self.logger.debug(output) + else: + self.logger.info('Not pushing because there is no origin') else: - output = repo.index.commit("Auto-commit with %s from %s run" % - (progname, hostname)) - if output: - logger.debug("%s: %s" % (progname, output)) - remote = repo.remote() - logger.debug("%s: Pushing to remote %s at %s" % (progname, remote, - remote.url)) - output = remote.push() - if output: - logger.debug("%s: %s" % (progname, output)) - else: - logger.info("%s: No changes to commit" % progname) + self.logger.info('No changes to commit') + if __name__ == '__main__': - sys.exit(main()) + sys.exit(CLI().run())