-
-
Notifications
You must be signed in to change notification settings - Fork 31
/
command.py
160 lines (125 loc) · 4.32 KB
/
command.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
# Copyright (C) 2017-2024 Vanessa Sochat.
# This Source Code Form is subject to the terms of the
# Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed
# with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
import os
import subprocess
import sys
from spython.logger import bot
from spython.utils import run_command as run_cmd
def init_command(self, action, flags=None):
"""
Return the initial Singularity command with any added flags.
Parameters
==========
action: the main action to perform (e.g., build)
flags: one or more additional singularity options
"""
flags = flags or []
if not isinstance(action, list):
action = [action]
cmd = ["singularity"] + flags + action
if self.quiet:
cmd.insert(1, "--quiet")
if self.debug:
cmd.insert(1, "--debug")
return cmd
def generate_bind_list(self, bindlist=None):
"""
Generate bind string will take a single string or list of binds, and
return a list that can be added to an exec or run command. For example,
the following map as follows:
['/host:/container', '/both'] --> ["--bind", "/host:/container","--bind","/both" ]
['/both'] --> ["--bind", "/both"]
'/host:container' --> ["--bind", "/host:container"]
None --> []
An empty bind or otherwise value of None should return an empty list.
The binds are also checked on the host.
Parameters
==========
bindlist: a string or list of bind mounts
"""
binds = []
# Case 1: No binds provided
if not bindlist:
return binds
# Case 2: provides a long string or non list, and must be split
if not isinstance(bindlist, list):
bindlist = bindlist.split(" ")
for bind in bindlist:
# Still cannot be None
if bind:
bot.debug("Adding bind %s" % bind)
binds += ["--bind", bind]
# Check that exists on host
host = bind.split(":")[0]
if not os.path.exists(host):
bot.error("%s does not exist on host." % bind)
sys.exit(1)
return binds
def send_command(self, cmd, sudo=False, stderr=None, stdout=None):
"""
Send command is a non interactive version of run_command, meaning
that we execute the command and return the return value, but don't
attempt to stream any content (text from the screen) back to the
user. This is useful for commands interacting with OCI bundles.
Parameters
==========
cmd: the list of commands to send to the terminal
sudo: use sudo (or not)
"""
if sudo:
cmd = ["sudo"] + cmd
process = subprocess.Popen(cmd, stderr=stderr, stdout=stdout)
result = process.communicate()
return result
def run_command(
self,
cmd,
sudo=False,
capture=True,
quiet=None,
return_result=False,
sudo_options=None,
environ=None,
background=False,
):
"""
Run_command is a wrapper for the global run_command, checking first
for sudo and exiting on error if needed. The message is returned as
a list of lines for the calling function to parse, and stdout uses
the parent process so it appears for the user.
Parameters
==========
cmd: the command to run
sudo: does the command require sudo?
quiet: if quiet set by function, overrides client setting.
return_result: return the result, if not successful (default False).
sudo_options: string or list of strings that will be passed as options to sudo
On success, returns result.
background: run the instance in the background (just Popen)
"""
# First preference to function, then to client setting
if quiet is None:
quiet = self.quiet
result = run_cmd(
cmd,
sudo=sudo,
capture=capture,
quiet=quiet,
sudo_options=sudo_options,
environ=environ,
background=background,
)
if background:
return
# If one line is returned, squash dimension
if len(result["message"]) == 1:
result["message"] = result["message"][0]
# If the user wants to return the result, just return it
if return_result:
return result
# On success, return result
if result["return_code"] == 0:
return result["message"]
return result