2017-05-01 08:26:56 +08:00
|
|
|
#!/usr/bin/env python3
|
2020-11-09 12:23:58 +08:00
|
|
|
# SPDX-License-Identifier: LGPL-2.1-or-later
|
2017-02-11 04:27:18 +08:00
|
|
|
|
2017-05-01 08:26:56 +08:00
|
|
|
OUTFILE_HEADER = """#!/usr/bin/env python3
|
2020-11-09 12:23:58 +08:00
|
|
|
# SPDX-License-Identifier: LGPL-2.1-or-later
|
2017-02-11 04:27:18 +08:00
|
|
|
#
|
|
|
|
# create-sys-script.py
|
|
|
|
#
|
2018-06-12 23:15:23 +08:00
|
|
|
# © 2017 Canonical Ltd.
|
2017-02-11 04:27:18 +08:00
|
|
|
# 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
|
|
|
|
|
|
|
|
|
2017-09-29 18:27:21 +08:00
|
|
|
import os, sys
|
|
|
|
import stat
|
|
|
|
import tempfile
|
|
|
|
import filecmp
|
|
|
|
import subprocess
|
2017-02-11 04:27:18 +08:00
|
|
|
|
|
|
|
OUTFILE_MODE = 0o775
|
|
|
|
|
|
|
|
OUTFILE_FUNCS = r"""
|
|
|
|
import os, sys
|
2017-09-29 18:28:25 +08:00
|
|
|
import shutil
|
2017-02-11 04:27:18 +08:00
|
|
|
|
|
|
|
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])
|
|
|
|
|
2017-09-29 18:28:25 +08:00
|
|
|
if os.path.exists('sys'):
|
|
|
|
shutil.rmtree('sys')
|
2017-02-11 04:27:18 +08:00
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
|
|
def handle_dir(outfile, path):
|
|
|
|
m = os.lstat(path).st_mode & 0o777
|
2017-09-29 18:27:21 +08:00
|
|
|
outfile.write(f"d('{path}', {m:#o})\n")
|
2017-02-11 04:27:18 +08:00
|
|
|
|
|
|
|
|
|
|
|
def handle_link(outfile, path):
|
|
|
|
src = os.readlink(path)
|
2017-09-29 18:27:21 +08:00
|
|
|
outfile.write(f"l('{path}', '{src}')\n")
|
2017-02-11 04:27:18 +08:00
|
|
|
|
|
|
|
|
|
|
|
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:
|
2017-09-29 18:27:21 +08:00
|
|
|
r = "\n".join( escape_single_quotes(l) for l in b.split(b"\n") )
|
|
|
|
r = f"b'''{r}'''"
|
2017-02-11 04:27:18 +08:00
|
|
|
else:
|
|
|
|
r = repr(b)
|
2017-09-29 18:27:21 +08:00
|
|
|
outfile.write(f"f('{path}', {m:#o}, {r})\n")
|
2017-02-11 04:27:18 +08:00
|
|
|
|
|
|
|
|
|
|
|
def process_sysdir(outfile):
|
2017-09-29 18:27:21 +08:00
|
|
|
for (dirpath, dirnames, filenames) in os.walk('sys'):
|
2017-02-11 04:27:18 +08:00
|
|
|
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):
|
2017-09-29 18:27:21 +08:00
|
|
|
any = False
|
2017-02-11 04:27:18 +08:00
|
|
|
for (dirpath, dirnames, filenames) in os.walk("sys"):
|
2017-09-29 18:27:21 +08:00
|
|
|
any = True
|
2017-02-11 04:27:18 +08:00
|
|
|
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:
|
2017-09-29 18:27:21 +08:00
|
|
|
print(f'FAIL on "{path}"', file=sys.stderr)
|
2017-02-11 04:27:18 +08:00
|
|
|
raise
|
2017-09-29 18:27:21 +08:00
|
|
|
if not any:
|
|
|
|
exit('Nothing found!')
|
2017-02-11 04:27:18 +08:00
|
|
|
|
|
|
|
if __name__ == "__main__":
|
2017-09-29 18:27:21 +08:00
|
|
|
if len(sys.argv) < 2:
|
|
|
|
exit('Usage: create-sys-script.py /path/to/test/')
|
2017-02-11 04:27:18 +08:00
|
|
|
|
2017-09-29 18:27:21 +08:00
|
|
|
outfile = os.path.abspath(os.path.dirname(sys.argv[0]) + '/sys-script.py')
|
|
|
|
print(f'Creating {outfile} using contents of {sys.argv[1]}/sys')
|
2017-02-11 04:27:18 +08:00
|
|
|
|
2017-09-29 18:27:21 +08:00
|
|
|
os.chdir(sys.argv[1])
|
2017-02-11 04:27:18 +08:00
|
|
|
|
2017-09-29 18:27:21 +08:00
|
|
|
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)))
|
2017-02-11 04:27:18 +08:00
|
|
|
f.write(OUTFILE_FUNCS)
|
|
|
|
f.write(OUTFILE_MAIN)
|
|
|
|
process_sysdir(f)
|
|
|
|
|
|
|
|
with tempfile.TemporaryDirectory() as tmpd:
|
2017-09-29 18:27:21 +08:00
|
|
|
print(f'Recreating sys/ using {outfile} at {tmpd}')
|
|
|
|
subprocess.check_call([outfile, tmpd])
|
2017-02-11 04:27:18 +08:00
|
|
|
verify_script(tmpd)
|
|
|
|
|
2017-09-29 18:27:21 +08:00
|
|
|
print(f'Verification successful, {outfile} is correct')
|