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