summaryrefslogtreecommitdiff
path: root/dotbot
diff options
context:
space:
mode:
Diffstat (limited to 'dotbot')
-rw-r--r--dotbot/plugins/clean.py4
-rw-r--r--dotbot/plugins/create.py3
-rw-r--r--dotbot/plugins/link.py10
-rw-r--r--dotbot/plugins/shell.py82
-rw-r--r--dotbot/util/__init__.py1
-rw-r--r--dotbot/util/common.py34
6 files changed, 79 insertions, 55 deletions
diff --git a/dotbot/plugins/clean.py b/dotbot/plugins/clean.py
index 82d77a6..09b11d8 100644
--- a/dotbot/plugins/clean.py
+++ b/dotbot/plugins/clean.py
@@ -1,4 +1,6 @@
-import os, dotbot
+import os
+import dotbot
+
class Clean(dotbot.Plugin):
'''
diff --git a/dotbot/plugins/create.py b/dotbot/plugins/create.py
index dc119da..015645a 100644
--- a/dotbot/plugins/create.py
+++ b/dotbot/plugins/create.py
@@ -1,8 +1,5 @@
import os
-import glob
-import shutil
import dotbot
-import subprocess
class Create(dotbot.Plugin):
diff --git a/dotbot/plugins/link.py b/dotbot/plugins/link.py
index 82a61ce..6f2b562 100644
--- a/dotbot/plugins/link.py
+++ b/dotbot/plugins/link.py
@@ -2,6 +2,7 @@ import os
import glob
import shutil
import dotbot
+import dotbot.util
import subprocess
@@ -105,14 +106,7 @@ class Link(dotbot.Plugin):
return success
def _test_success(self, command):
- with open(os.devnull, 'w') as devnull:
- ret = subprocess.call(
- command,
- shell=True,
- stdout=devnull,
- stderr=devnull,
- executable=os.environ.get('SHELL'),
- )
+ ret = dotbot.util.shell_command(command, cwd=self._context.base_directory())
if ret != 0:
self._log.debug('Test \'%s\' returned false' % command)
return ret == 0
diff --git a/dotbot/plugins/shell.py b/dotbot/plugins/shell.py
index 06a9a89..3092f20 100644
--- a/dotbot/plugins/shell.py
+++ b/dotbot/plugins/shell.py
@@ -1,4 +1,8 @@
-import os, subprocess, dotbot
+import os
+import subprocess
+import dotbot
+import dotbot.util
+
class Shell(dotbot.Plugin):
'''
@@ -19,48 +23,40 @@ class Shell(dotbot.Plugin):
def _process_commands(self, data):
success = True
defaults = self._context.defaults().get('shell', {})
- with open(os.devnull, 'w') as devnull:
- for item in data:
- stdin = stdout = stderr = devnull
- quiet = False
- if defaults.get('stdin', False) == True:
- stdin = None
- if defaults.get('stdout', False) == True:
- stdout = None
- if defaults.get('stderr', False) == True:
- stderr = None
- if defaults.get('quiet', False) == True:
- quiet = True
- if isinstance(item, dict):
- cmd = item['command']
- msg = item.get('description', None)
- if 'stdin' in item:
- stdin = None if item['stdin'] == True else devnull
- if 'stdout' in item:
- stdout = None if item['stdout'] == True else devnull
- if 'stderr' in item:
- stderr = None if item['stderr'] == True else devnull
- if 'quiet' in item:
- quiet = True if item['quiet'] == True else False
- elif isinstance(item, list):
- cmd = item[0]
- msg = item[1] if len(item) > 1 else None
- else:
- cmd = item
- msg = None
- if msg is None:
- self._log.lowinfo(cmd)
- elif quiet:
- self._log.lowinfo('%s' % msg)
- else:
- self._log.lowinfo('%s [%s]' % (msg, cmd))
- executable = os.environ.get('SHELL')
- ret = subprocess.call(cmd, shell=True, stdin=stdin, stdout=stdout,
- stderr=stderr, cwd=self._context.base_directory(),
- executable=executable)
- if ret != 0:
- success = False
- self._log.warning('Command [%s] failed' % cmd)
+ for item in data:
+ stdin = defaults.get('stdin', False)
+ stdout = defaults.get('stdout', False)
+ stderr = defaults.get('stderr', False)
+ quiet = defaults.get('quiet', False)
+ if isinstance(item, dict):
+ cmd = item['command']
+ msg = item.get('description', None)
+ stdin = item.get('stdin', stdin)
+ stdout = item.get('stdout', stdout)
+ stderr = item.get('stderr', stderr)
+ quiet = item.get('quiet', quiet)
+ elif isinstance(item, list):
+ cmd = item[0]
+ msg = item[1] if len(item) > 1 else None
+ else:
+ cmd = item
+ msg = None
+ if msg is None:
+ self._log.lowinfo(cmd)
+ elif quiet:
+ self._log.lowinfo('%s' % msg)
+ else:
+ self._log.lowinfo('%s [%s]' % (msg, cmd))
+ ret = dotbot.util.shell_command(
+ cmd,
+ cwd=self._context.base_directory(),
+ enable_stdin=stdin,
+ enable_stdout=stdout,
+ enable_stderr=stderr
+ )
+ if ret != 0:
+ success = False
+ self._log.warning('Command [%s] failed' % cmd)
if success:
self._log.info('All commands have been executed')
else:
diff --git a/dotbot/util/__init__.py b/dotbot/util/__init__.py
index e69de29..0c5a8f5 100644
--- a/dotbot/util/__init__.py
+++ b/dotbot/util/__init__.py
@@ -0,0 +1 @@
+from .common import shell_command
diff --git a/dotbot/util/common.py b/dotbot/util/common.py
new file mode 100644
index 0000000..d1e2000
--- /dev/null
+++ b/dotbot/util/common.py
@@ -0,0 +1,34 @@
+import os
+import subprocess
+import platform
+
+
+def shell_command(command, cwd=None, enable_stdin=False, enable_stdout=False, enable_stderr=False):
+ with open(os.devnull, 'w') as devnull_w, open(os.devnull, 'r') as devnull_r:
+ stdin = None if enable_stdin else devnull_r
+ stdout = None if enable_stdout else devnull_w
+ stderr = None if enable_stderr else devnull_w
+ executable = os.environ.get('SHELL')
+ if platform.system() == 'Windows':
+ # We avoid setting the executable kwarg on Windows because it does
+ # not have the desired effect when combined with shell=True. It
+ # will result in the correct program being run (e.g. bash), but it
+ # will be invoked with a '/c' argument instead of a '-c' argument,
+ # which it won't understand.
+ #
+ # See https://github.com/anishathalye/dotbot/issues/219 and
+ # https://bugs.python.org/issue40467.
+ #
+ # This means that complex commands that require Bash's parsing
+ # won't work; a workaround for this is to write the command as
+ # `bash -c "..."`.
+ executable = None
+ return subprocess.call(
+ command,
+ shell=True,
+ executable=executable,
+ stdin=stdin,
+ stdout=stdout,
+ stderr=stderr,
+ cwd=cwd
+ )