浏览代码

Add support for old style formatting

Bertrand Chenal 7 年之前
父节点
当前提交
bcffb667d5
共有 2 个文件被更改,包括 38 次插入33 次删除
  1. 38 31
      byrd.py
  2. 0 2
      pkg/os.yaml

+ 38 - 31
byrd.py

@@ -268,6 +268,7 @@ class Task(Node):
         'assert': Atom,
         'assert': Atom,
         'env': EnvNode,
         'env': EnvNode,
         'multi': MultiList,
         'multi': MultiList,
+        'fmt': Atom,
     }
     }
 
 
     @classmethod
     @classmethod
@@ -307,25 +308,29 @@ class ConfigRoot(Node):
     }
     }
 
 
 
 
-
 class Env(ChainMap):
 class Env(ChainMap):
 
 
     def __init__(self, *dicts):
     def __init__(self, *dicts):
+        self.fmt_kind = 'new'
         return super().__init__(*filter(lambda x: x is not None, dicts))
         return super().__init__(*filter(lambda x: x is not None, dicts))
 
 
-    def fmt_env(self, child_env):
+    def fmt_env(self, child_env, kind=None):
         new_env = {}
         new_env = {}
         for key, val in child_env.items():
         for key, val in child_env.items():
             # env wrap-around!
             # env wrap-around!
-            new_val = self.fmt(val)
+            new_val = self.fmt(val, kind=kind)
             if new_val == val:
             if new_val == val:
                 continue
                 continue
             new_env[key] = new_val
             new_env[key] = new_val
         return Env(new_env, child_env)
         return Env(new_env, child_env)
 
 
-    def fmt_string(self, string):
+    def fmt_string(self, string, kind=None):
+        fmt_kind = kind or self.fmt_kind
         try:
         try:
-            return string.format(**self)
+            if fmt_kind == 'old':
+                return string % self
+            else:
+                return string.format(**self)
         except KeyError as exc:
         except KeyError as exc:
             msg = 'Unable to format "%s" (missing: "%s")'% (string, exc.args[0])
             msg = 'Unable to format "%s" (missing: "%s")'% (string, exc.args[0])
             candidates = gen_candidates(self.keys())
             candidates = gen_candidates(self.keys())
@@ -338,10 +343,11 @@ class Env(ChainMap):
             msg = 'Unable to format "%s", positional argument not supported'
             msg = 'Unable to format "%s", positional argument not supported'
             raise FmtException(msg)
             raise FmtException(msg)
 
 
-    def fmt(self, what):
+    def fmt(self, what, kind=None):
         if isinstance(what, str):
         if isinstance(what, str):
-            return self.fmt_string(what)
-        return self.fmt_env(what)
+            return self.fmt_string(what, kind=kind)
+        return self.fmt_env(what, kind=kind)
+
 
 
 def get_secret(service, resource, resource_id=None):
 def get_secret(service, resource, resource_id=None):
     resource_id = resource_id or resource
     resource_id = resource_id or resource
@@ -351,6 +357,7 @@ def get_secret(service, resource, resource_id=None):
         keyring.set_password(service, resource_id, secret)
         keyring.set_password(service, resource_id, secret)
     return secret
     return secret
 
 
+
 def get_passphrase(key_path):
 def get_passphrase(key_path):
     service = 'SSH private key'
     service = 'SSH private key'
     csum = md5(open(key_path, 'rb').read()).digest().hex()
     csum = md5(open(key_path, 'rb').read()).digest().hex()
@@ -396,7 +403,7 @@ def connect(host, auth):
 def run_local(cmd, env, cli):
 def run_local(cmd, env, cli):
     # Run local task
     # Run local task
     cmd = env.fmt(cmd)
     cmd = env.fmt(cmd)
-    logger.info(env.fmt('{task_desc}'))
+    logger.info(env.fmt('{task_desc}', kind='new'))
     if cli.dry_run:
     if cli.dry_run:
         logger.info('[dry-run] ' + cmd)
         logger.info('[dry-run] ' + cmd)
         return None
         return None
@@ -419,7 +426,7 @@ def run_local(cmd, env, cli):
 def run_python(task, env, cli):
 def run_python(task, env, cli):
     # Execute a piece of python localy
     # Execute a piece of python localy
     code = task.python
     code = task.python
-    logger.info(env.fmt('{task_desc}'))
+    logger.info(env.fmt('{task_desc}', kind='new'))
     if cli.dry_run:
     if cli.dry_run:
         logger.info('[dry-run] ' + code)
         logger.info('[dry-run] ' + code)
         return None
         return None
@@ -428,6 +435,7 @@ def run_python(task, env, cli):
     if task.sudo:
     if task.sudo:
         user = 'root' if task.sudo is True else task.sudo
         user = 'root' if task.sudo is True else task.sudo
         cmd = 'sudo -u {} -- {}'.format(user, cmd)
         cmd = 'sudo -u {} -- {}'.format(user, cmd)
+
     process = subprocess.Popen(
     process = subprocess.Popen(
         cmd,
         cmd,
         stdout=subprocess.PIPE,
         stdout=subprocess.PIPE,
@@ -519,7 +527,7 @@ def run_remote(task, host, env, cli):
     res = None
     res = None
     host = env.fmt(host)
     host = env.fmt(host)
     env.update({
     env.update({
-        'host': host,
+        'host': extract_host(host),
     })
     })
     if cli.dry_run:
     if cli.dry_run:
         client = None
         client = None
@@ -534,7 +542,7 @@ def run_remote(task, host, env, cli):
             else:
             else:
                  prefix = '[sudo as %s] ' % task.sudo
                  prefix = '[sudo as %s] ' % task.sudo
         msg = prefix + '{host}: {task_desc}'
         msg = prefix + '{host}: {task_desc}'
-        logger.info(env.fmt(msg))
+        logger.info(env.fmt(msg, kind='new'))
         logger.debug(TAB + TAB.join(cmd.splitlines()))
         logger.debug(TAB + TAB.join(cmd.splitlines()))
         if cli.dry_run:
         if cli.dry_run:
             logger.info('[dry-run] ' + cmd)
             logger.info('[dry-run] ' + cmd)
@@ -576,26 +584,10 @@ def run_remote(task, host, env, cli):
     return res
     return res
 
 
 
 
-def run_task(task, host, cli, parent_env=None):
+def run_task(task, host, cli, env=None):
     '''
     '''
     Execute one task on one host (or locally)
     Execute one task on one host (or locally)
     '''
     '''
-
-    # Prepare environment
-    env = Env(
-        {},
-        # Env on the task itself
-        task.get('env'),
-        # Env from parent task
-        parent_env,
-    ).new_child()
-
-    env.update({
-        'task_desc': env.fmt(task.desc),
-        'task_name': task.name,
-        'host': host or '',
-    })
-
     if task.local:
     if task.local:
         res = run_local(task.local, env, cli)
         res = run_local(task.local, env, cli)
     elif task.python:
     elif task.python:
@@ -617,7 +609,6 @@ def run_task(task, host, cli, parent_env=None):
     return res
     return res
 
 
 
 
-
 def run_batch(task, hosts, cli, global_env=None):
 def run_batch(task, hosts, cli, global_env=None):
     '''
     '''
     Run one task on a list of hosts
     Run one task on a list of hosts
@@ -625,8 +616,8 @@ def run_batch(task, hosts, cli, global_env=None):
     out = None
     out = None
     export_env = {}
     export_env = {}
     task_env = global_env.fmt(task.get('env', {}))
     task_env = global_env.fmt(task.get('env', {}))
-    parent_env = Env(export_env, task_env, global_env)
     if task.get('multi'):
     if task.get('multi'):
+        parent_env = Env(export_env, task_env, global_env)
         parent_sudo = task.sudo
         parent_sudo = task.sudo
         for pos, step in enumerate(task.multi):
         for pos, step in enumerate(task.multi):
             task_name = step.task
             task_name = step.task
@@ -656,11 +647,23 @@ def run_batch(task, hosts, cli, global_env=None):
                 export_env[step.export] = out
                 export_env[step.export] = out
 
 
     else:
     else:
+        task_env.update({
+            'task_desc': global_env.fmt(task.desc),
+            'task_name': task.name,
+        })
+        parent_env = Env(task_env, global_env)
+        if task.get('fmt'):
+            parent_env.fmt_kind = task.fmt
+
         res = None
         res = None
         if task.once and (task.local or task.python):
         if task.once and (task.local or task.python):
             res = run_task(task, None, cli, parent_env)
             res = run_task(task, None, cli, parent_env)
         elif hosts:
         elif hosts:
             for host in hosts:
             for host in hosts:
+                env_host = extract_host(host)
+                parent_env.update({
+                    'host': env_host,
+                })
                 res = run_task(task, host, cli, parent_env)
                 res = run_task(task, host, cli, parent_env)
                 if task.once:
                 if task.once:
                     break
                     break
@@ -670,6 +673,10 @@ def run_batch(task, hosts, cli, global_env=None):
     return out
     return out
 
 
 
 
+def extract_host(host_string):
+    return host_string and host_string.split('@')[-1] or ''
+
+
 def abort(msg):
 def abort(msg):
     logger.error(msg)
     logger.error(msg)
     sys.exit(1)
     sys.exit(1)

+ 0 - 2
pkg/os.yaml

@@ -89,8 +89,6 @@ tasks:
     desc: Unzip a zip file
     desc: Unzip a zip file
     run: test -d {dir} || unzip {file} -d {dir}
     run: test -d {dir} || unzip {file} -d {dir}
   patch:
   patch:
-    # Do not leave .rej file if patch was already applied.
-    # Thus the "rm" on last line.
     desc: Patch a file with a specific local diff file
     desc: Patch a file with a specific local diff file
     run: |
     run: |
       patch --ignore-whitespace --reject-file=/dev/null -uN {file} << EOF
       patch --ignore-whitespace --reject-file=/dev/null -uN {file} << EOF