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 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179
|
#!/usr/bin/env python3
# SPDX-License-Identifier: LGPL-2.1-or-later
OUTFILE_HEADER = """#!/usr/bin/env python3
# SPDX-License-Identifier: LGPL-2.1-or-later
#
# create-sys-script.py
#
# © 2017 Canonical Ltd.
# Author: Dan Streetman <dan.streetman@canonical.com>
"""
# Use this only to (re-)create the test/sys-script.py script,
# after adding or modifying anything in the test/sys/ directory
import os, sys
import stat
import tempfile
import filecmp
import subprocess
OUTFILE_MODE = 0o775
OUTFILE_FUNCS = r"""
import os, sys
import shutil
def d(path, mode):
os.mkdir(path, mode)
def l(path, src):
os.symlink(src, path)
def f(path, mode, contents):
with open(path, "wb") as f:
f.write(contents)
os.chmod(path, mode)
"""
OUTFILE_MAIN = """
if len(sys.argv) < 2:
exit("Usage: {} <target dir>".format(sys.argv[0]))
if not os.path.isdir(sys.argv[1]):
exit("Target dir {} not found".format(sys.argv[1]))
os.chdir(sys.argv[1])
if os.path.exists('sys'):
shutil.rmtree('sys')
"""
def handle_dir(outfile, path):
m = os.lstat(path).st_mode & 0o777
outfile.write(f"d('{path}', {m:#o})\n")
def handle_link(outfile, path):
src = os.readlink(path)
outfile.write(f"l('{path}', '{src}')\n")
def escape_single_quotes(b):
# remove the b'' wrapping each line repr
r = repr(b)[2:-1]
# python escapes all ' only if there are ' and " in the string
if '"' not in r:
r = r.replace("'", r"\'")
# return line with all ' escaped
return r
def handle_file(outfile, path):
m = os.lstat(path).st_mode & 0o777
with open(path, "rb") as f:
b = f.read()
if b.count(b"\n") > 1:
r = "\n".join( escape_single_quotes(l) for l in b.split(b"\n") )
r = f"b'''{r}'''"
else:
r = repr(b)
outfile.write(f"f('{path}', {m:#o}, {r})\n")
def process_sysdir(outfile):
for (dirpath, dirnames, filenames) in os.walk('sys'):
handle_dir(outfile, dirpath)
for d in dirnames:
path = os.path.join(dirpath, d)
if stat.S_ISLNK(os.lstat(path).st_mode):
handle_link(outfile, path)
for f in filenames:
path = os.path.join(dirpath, f)
mode = os.lstat(path).st_mode
if stat.S_ISLNK(mode):
handle_link(outfile, path)
elif stat.S_ISREG(mode):
handle_file(outfile, path)
def verify_dir(tmpd, path_a):
path_b = os.path.join(tmpd, path_a)
mode_a = os.lstat(path_a).st_mode
mode_b = os.lstat(path_b).st_mode
if not stat.S_ISDIR(mode_b):
raise Exception("Not directory")
if (mode_a & 0o777) != (mode_b & 0o777):
raise Exception("Permissions mismatch")
def verify_link(tmpd, path_a):
path_b = os.path.join(tmpd, path_a)
if not stat.S_ISLNK(os.lstat(path_b).st_mode):
raise Exception("Not symlink")
if os.readlink(path_a) != os.readlink(path_b):
raise Exception("Symlink dest mismatch")
def verify_file(tmpd, path_a):
path_b = os.path.join(tmpd, path_a)
mode_a = os.lstat(path_a).st_mode
mode_b = os.lstat(path_b).st_mode
if not stat.S_ISREG(mode_b):
raise Exception("Not file")
if (mode_a & 0o777) != (mode_b & 0o777):
raise Exception("Permissions mismatch")
if not filecmp.cmp(path_a, path_b, shallow=False):
raise Exception("File contents mismatch")
def verify_script(tmpd):
any = False
for (dirpath, dirnames, filenames) in os.walk("sys"):
any = True
try:
path = dirpath
verify_dir(tmpd, path)
for d in dirnames:
path = os.path.join(dirpath, d)
if stat.S_ISLNK(os.lstat(path).st_mode):
verify_link(tmpd, path)
for f in filenames:
path = os.path.join(dirpath, f)
mode = os.lstat(path).st_mode
if stat.S_ISLNK(mode):
verify_link(tmpd, path)
elif stat.S_ISREG(mode):
verify_file(tmpd, path)
except Exception:
print(f'FAIL on "{path}"', file=sys.stderr)
raise
if not any:
exit('Nothing found!')
if __name__ == "__main__":
if len(sys.argv) < 2:
exit('Usage: create-sys-script.py /path/to/test/')
outfile = os.path.abspath(os.path.dirname(sys.argv[0]) + '/sys-script.py')
print(f'Creating {outfile} using contents of {sys.argv[1]}/sys')
os.chdir(sys.argv[1])
with open(outfile, "w") as f:
os.chmod(outfile, OUTFILE_MODE)
f.write(OUTFILE_HEADER.replace(os.path.basename(sys.argv[0]),
os.path.basename(outfile)))
f.write(OUTFILE_FUNCS)
f.write(OUTFILE_MAIN)
process_sysdir(f)
with tempfile.TemporaryDirectory() as tmpd:
print(f'Recreating sys/ using {outfile} at {tmpd}')
subprocess.check_call([outfile, tmpd])
verify_script(tmpd)
print(f'Verification successful, {outfile} is correct')
|