diff options
Diffstat (limited to 'bitbake/lib/toaster/contrib/tts/shellutils.py')
-rw-r--r-- | bitbake/lib/toaster/contrib/tts/shellutils.py | 139 |
1 files changed, 139 insertions, 0 deletions
diff --git a/bitbake/lib/toaster/contrib/tts/shellutils.py b/bitbake/lib/toaster/contrib/tts/shellutils.py new file mode 100644 index 0000000000..2b7f0f1d2e --- /dev/null +++ b/bitbake/lib/toaster/contrib/tts/shellutils.py | |||
@@ -0,0 +1,139 @@ | |||
1 | #!/usr/bin/python | ||
2 | |||
3 | # ex:ts=4:sw=4:sts=4:et | ||
4 | # -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- | ||
5 | # | ||
6 | # Copyright (C) 2015 Alexandru Damian for Intel Corp. | ||
7 | # | ||
8 | # This program is free software; you can redistribute it and/or modify | ||
9 | # it under the terms of the GNU General Public License version 2 as | ||
10 | # published by the Free Software Foundation. | ||
11 | # | ||
12 | # This program is distributed in the hope that it will be useful, | ||
13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | # GNU General Public License for more details. | ||
16 | # | ||
17 | # You should have received a copy of the GNU General Public License along | ||
18 | # with this program; if not, write to the Free Software Foundation, Inc., | ||
19 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
20 | |||
21 | # Utilities shared by tests and other common bits of code. | ||
22 | |||
23 | import sys, os, subprocess, fcntl, errno | ||
24 | import config | ||
25 | from config import logger | ||
26 | |||
27 | |||
28 | # License warning; this code is copied from the BitBake project, file bitbake/lib/bb/utils.py | ||
29 | # The code is originally licensed GPL-2.0, and we redistribute it under still GPL-2.0 | ||
30 | |||
31 | # End of copy is marked with #ENDOFCOPY marker | ||
32 | |||
33 | def mkdirhier(directory): | ||
34 | """Create a directory like 'mkdir -p', but does not complain if | ||
35 | directory already exists like os.makedirs | ||
36 | """ | ||
37 | |||
38 | try: | ||
39 | os.makedirs(directory) | ||
40 | except OSError as e: | ||
41 | if e.errno != errno.EEXIST: | ||
42 | raise e | ||
43 | |||
44 | def lockfile(name, shared=False, retry=True): | ||
45 | """ | ||
46 | Use the file fn as a lock file, return when the lock has been acquired. | ||
47 | Returns a variable to pass to unlockfile(). | ||
48 | """ | ||
49 | config.logger.debug("take lockfile %s" % name) | ||
50 | dirname = os.path.dirname(name) | ||
51 | mkdirhier(dirname) | ||
52 | |||
53 | if not os.access(dirname, os.W_OK): | ||
54 | logger.error("Unable to acquire lock '%s', directory is not writable", | ||
55 | name) | ||
56 | sys.exit(1) | ||
57 | |||
58 | op = fcntl.LOCK_EX | ||
59 | if shared: | ||
60 | op = fcntl.LOCK_SH | ||
61 | if not retry: | ||
62 | op = op | fcntl.LOCK_NB | ||
63 | |||
64 | while True: | ||
65 | # If we leave the lockfiles lying around there is no problem | ||
66 | # but we should clean up after ourselves. This gives potential | ||
67 | # for races though. To work around this, when we acquire the lock | ||
68 | # we check the file we locked was still the lock file on disk. | ||
69 | # by comparing inode numbers. If they don't match or the lockfile | ||
70 | # no longer exists, we start again. | ||
71 | |||
72 | # This implementation is unfair since the last person to request the | ||
73 | # lock is the most likely to win it. | ||
74 | |||
75 | try: | ||
76 | lf = open(name, 'a+') | ||
77 | fileno = lf.fileno() | ||
78 | fcntl.flock(fileno, op) | ||
79 | statinfo = os.fstat(fileno) | ||
80 | if os.path.exists(lf.name): | ||
81 | statinfo2 = os.stat(lf.name) | ||
82 | if statinfo.st_ino == statinfo2.st_ino: | ||
83 | return lf | ||
84 | lf.close() | ||
85 | except Exception: | ||
86 | try: | ||
87 | lf.close() | ||
88 | except Exception: | ||
89 | pass | ||
90 | pass | ||
91 | if not retry: | ||
92 | return None | ||
93 | |||
94 | def unlockfile(lf): | ||
95 | """ | ||
96 | Unlock a file locked using lockfile() | ||
97 | """ | ||
98 | try: | ||
99 | # If we had a shared lock, we need to promote to exclusive before | ||
100 | # removing the lockfile. Attempt this, ignore failures. | ||
101 | fcntl.flock(lf.fileno(), fcntl.LOCK_EX|fcntl.LOCK_NB) | ||
102 | os.unlink(lf.name) | ||
103 | except (IOError, OSError): | ||
104 | pass | ||
105 | fcntl.flock(lf.fileno(), fcntl.LOCK_UN) | ||
106 | lf.close() | ||
107 | |||
108 | #ENDOFCOPY | ||
109 | |||
110 | |||
111 | def mk_lock_filename(): | ||
112 | our_name = os.path.basename(__file__) | ||
113 | our_name = ".%s" % ".".join(reversed(our_name.split("."))) | ||
114 | return config.LOCKFILE + our_name | ||
115 | |||
116 | |||
117 | |||
118 | class ShellCmdException(Exception): | ||
119 | pass | ||
120 | |||
121 | def run_shell_cmd(command, cwd = None): | ||
122 | if cwd is None: | ||
123 | cwd = os.getcwd() | ||
124 | |||
125 | config.logger.debug("_shellcmd: (%s) %s" % (cwd, command)) | ||
126 | p = subprocess.Popen(command, cwd = cwd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) | ||
127 | (out,err) = p.communicate() | ||
128 | p.wait() | ||
129 | if p.returncode: | ||
130 | if len(err) == 0: | ||
131 | err = "command: %s \n%s" % (command, out) | ||
132 | else: | ||
133 | err = "command: %s \n%s" % (command, err) | ||
134 | config.logger.warn("_shellcmd: error \n%s\n%s" % (out, err)) | ||
135 | raise ShellCmdException(err) | ||
136 | else: | ||
137 | #config.logger.debug("localhostbecontroller: shellcmd success\n%s" % out) | ||
138 | return out | ||
139 | |||