Merge pull request #210 from Feuermurmel/setup

Fix for #209 and assorted enhancements.
This commit is contained in:
Mattias Andrée [mˈa.tːiː.ˌas ˈanː.drˌeː] 2014-09-09 02:15:51 +00:00
commit 9e555ff3e0

226
setup.py
View file

@ -48,7 +48,7 @@ SYMBOLIC = 'symbolic'
class Setup(): class Setup():
def __init__(self): def __init__(self):
usage_script = '\033[34;1msetup.py\033[21;39m' usage_script = '\033[34;1msetup.py\033[21;39m'
usage_help = '(version | help)' usage_help = '(--version | --help)'
usage_proc = '[\033[4mconfigurations\033[24m] ([build] | prebuilt | install | (uninstall|clean)[-old] | view)' usage_proc = '[\033[4mconfigurations\033[24m] ([build] | prebuilt | install | (uninstall|clean)[-old] | view)'
usage = '%s %s\n%s %s' % (usage_script, usage_help, usage_script, usage_proc) usage = '%s %s\n%s %s' % (usage_script, usage_help, usage_script, usage_proc)
@ -240,16 +240,19 @@ class Setup():
self.free = False self.free = False
def checkFreedom(): def checkFreedom():
if self.free is None: if self.free is None:
if (opts.opts['--version'] is None) and ((len(opts.files) != 1) or (opts.files[0] != 'version')): print()
print('') print('You need to select your freedom, add --freedom=strict or --freedom=partial.')
print('You need to select your freedom, add --freedom=strict or --freedom=partial.') print()
print('') print('--freedom=strict will install only ponies that are completely free.')
print('--freedom=strict will install only ponies that are completely free.') print('--freedom=partial will install all ponies, even if they are not free.')
print('--freedom=partial will install all ponies, even if they are not free.') print()
print('') print()
print('') exit(255)
exit(255)
def setup_config():
self.viewconf(conf)
os.umask(0o022)
if (opts.opts['---DESTDIR'] is not None) and (opts.opts['--dest-dir'] is None): if (opts.opts['---DESTDIR'] is not None) and (opts.opts['--dest-dir'] is None):
destdir = opts.opts['---DESTDIR'][0] destdir = opts.opts['---DESTDIR'][0]
if len(destdir) > 0: if len(destdir) > 0:
@ -259,51 +262,59 @@ class Setup():
prefix = opts.opts['---PREFIX'][0] prefix = opts.opts['---PREFIX'][0]
if len(prefix) > 0: if len(prefix) > 0:
opts.opts['--prefix'] = [prefix] opts.opts['--prefix'] = [prefix]
if (len(opts.files) > 1) or (opts.opts['--help'] is not None) or ((len(opts.files) == 1) and (opts.files[0] == 'help')): if opts.opts['--help'] is not None:
opts.help() opts.help()
elif (opts.opts['--version'] is not None) or ((len(opts.files) == 1) and (opts.files[0] == 'version')): elif opts.opts['--version'] is not None:
print('Ponysay %s installer' % (PONYSAY_VERSION)) print('Ponysay %s installer' % (PONYSAY_VERSION))
elif len(opts.files) != 1:
opts.print_fatal('A single command is expected on the command line.')
opts.usage()
else: else:
if len(opts.files) == 0:
opts.files = ['build']
method = opts.files[0] method = opts.files[0]
if method == 'clean': self.clean() if method == 'clean': self.clean()
elif method == 'clean-old': self.cleanOld() elif method == 'clean-old': self.cleanOld()
else: else:
conf = self.configure(opts.opts) conf = self.configure(opts.opts)
self.viewconf(conf)
os.umask(0o022)
if method == 'build': if method == 'build':
checkFreedom() checkFreedom()
setup_config()
self.build(conf) self.build(conf)
elif method == 'prebuilt': elif method == 'prebuilt':
checkFreedom() checkFreedom()
setup_config()
self.applyDestDir(conf) self.applyDestDir(conf)
self.install(conf) self.install(conf)
elif method == 'install': elif method == 'install':
checkFreedom() checkFreedom()
setup_config()
self.build(conf) self.build(conf)
self.applyDestDir(conf) self.applyDestDir(conf)
self.install(conf) self.install(conf)
self.clean() self.clean()
elif method == 'uninstall': elif method == 'uninstall':
setup_config()
self.uninstall(conf) self.uninstall(conf)
elif method == 'uninstall-old': elif method == 'uninstall-old':
setup_config()
self.uninstallOld(conf) self.uninstallOld(conf)
elif not method == 'view': elif method == 'view':
opts.help() setup_config()
else:
''' opts.print_fatal('Unknown command: {}', method)
Display configurations opts.usage()
'''
def viewconf(self, conf): def viewconf(self, conf):
'''
Display configurations
'''
RED = '\033[31m%s\033[39m' RED = '\033[31m%s\033[39m'
GREEN = '%s\033[32m%s\033[39m' GREEN = '%s\033[32m%s\033[39m'
YELLOW = '\033[33m%s\033[39m' YELLOW = '\033[33m%s\033[39m'
@ -351,11 +362,12 @@ class Setup():
else: print(RED % ('Installing \033[1mnot\033[21m only fully free parts of the package')) else: print(RED % ('Installing \033[1mnot\033[21m only fully free parts of the package'))
print() print()
'''
Compile ponysay
'''
def build(self, conf): def build(self, conf):
'''
Compile ponysay
'''
print('\033[1;34m::\033[39mCompiling...\033[21m') print('\033[1;34m::\033[39mCompiling...\033[21m')
def compressCommand(ext): def compressCommand(ext):
@ -556,11 +568,12 @@ class Setup():
Popen(params, stdin=PIPE, stdout=PIPE, stderr=PIPE).communicate() Popen(params, stdin=PIPE, stdout=PIPE, stderr=PIPE).communicate()
print() print()
'''
Install compiled ponysay
'''
def install(self, conf): def install(self, conf):
'''
Install compiled ponysay
'''
print('\033[1;34m::\033[39mInstalling...\033[21m') print('\033[1;34m::\033[39mInstalling...\033[21m')
dests = [] dests = []
@ -642,11 +655,12 @@ class Setup():
for file in miscfiles: for file in miscfiles:
self.cp(False, file[0], [conf[file[0]]], Setup.validateFreedom if self.free else None) self.cp(False, file[0], [conf[file[0]]], Setup.validateFreedom if self.free else None)
print() print()
'''
Uninstall ponysay
'''
def uninstall(self, conf): def uninstall(self, conf):
'''
Uninstall ponysay
'''
print('\033[1;34m::\033[39mUninstalling...\033[21m') print('\033[1;34m::\033[39mUninstalling...\033[21m')
(files, dirs, infos) = ([], [], []) (files, dirs, infos) = ([], [], [])
@ -699,11 +713,12 @@ class Setup():
self.removeLists(files, dirs) self.removeLists(files, dirs)
print() print()
'''
Uninstall file ponysay no longer uses
'''
def uninstallOld(self, conf): def uninstallOld(self, conf):
'''
Uninstall file ponysay no longer uses
'''
print('\033[1;34m::\033[39mUninstalling old files...\033[21m') print('\033[1;34m::\033[39mUninstalling old files...\033[21m')
instdir = conf['~prefix~'] + '/usr' instdir = conf['~prefix~'] + '/usr'
@ -719,11 +734,12 @@ class Setup():
self.removeLists(files, dirs) self.removeLists(files, dirs)
print() print()
'''
Remove compiled files
'''
def clean(self): def clean(self):
'''
Remove compiled files
'''
print('\033[1;34m::\033[39mCleaning...\033[21m') print('\033[1;34m::\033[39mCleaning...\033[21m')
files = ['ponysay.info', 'ponysay.info.gz', 'ponysay.info.xz', 'ponysay.pdf.gz', 'ponysay.pdf.xz', 'ponysay.install', 'ponysay.zip'] files = ['ponysay.info', 'ponysay.info.gz', 'ponysay.info.xz', 'ponysay.pdf.gz', 'ponysay.pdf.xz', 'ponysay.install', 'ponysay.zip']
@ -746,10 +762,11 @@ class Setup():
self.removeLists(files, dirs) self.removeLists(files, dirs)
print() print()
'''
Remove compiled files ponysay is no longer compiling
'''
def cleanOld(self): def cleanOld(self):
'''
Remove compiled files ponysay is no longer compiling
'''
print('\033[1;34m::\033[39mCleaning old files...\033[21m') print('\033[1;34m::\033[39mCleaning old files...\033[21m')
files = ['truncater', 'ponysaytruncater', 'ponysay.py.install', 'ponysay.install~', 'ponysay.zip'] files = ['truncater', 'ponysaytruncater', 'ponysay.py.install', 'ponysay.install~', 'ponysay.zip']
@ -763,11 +780,12 @@ class Setup():
self.removeLists(files, dirs) self.removeLists(files, dirs)
print() print()
'''
Removes listed files and directories
'''
def removeLists(self, files, dirs): def removeLists(self, files, dirs):
'''
Removes listed files and directories
'''
for file in files: for file in files:
if os.path.isfile(file) or os.path.islink(file): if os.path.isfile(file) or os.path.islink(file):
print('Unlinking file %s' % (file)) print('Unlinking file %s' % (file))
@ -792,12 +810,13 @@ class Setup():
os.rmdir(dir) os.rmdir(dir)
else: else:
break; break;
'''
Check whether a file is fully free
'''
@staticmethod @staticmethod
def validateFreedom(filename): def validateFreedom(filename):
'''
Check whether a file is fully free
'''
if not os.path.isdir(filename): if not os.path.isdir(filename):
if filename.endswith('.pony') and (filename != '.pony') and not filename.endswith('/.pony'): if filename.endswith('.pony') and (filename != '.pony') and not filename.endswith('/.pony'):
with open(filename, 'rb') as file: with open(filename, 'rb') as file:
@ -812,11 +831,12 @@ class Setup():
return line[1].lower() == 'yes' return line[1].lower() == 'yes'
return False return False
return True return True
'''
Copys a files or directory to multiple destinations
'''
def cp(self, recursive, source, destinations, validatehook = None): def cp(self, recursive, source, destinations, validatehook = None):
'''
Copys a files or directory to multiple destinations
'''
if validatehook is not None: if validatehook is not None:
if not validatehook(source): if not validatehook(source):
print('Ignoring installation of file %s (did not pass validation process made by setup settings)' % source) print('Ignoring installation of file %s (did not pass validation process made by setup settings)' % source)
@ -890,11 +910,12 @@ class Setup():
if os.path.exists(dest): if os.path.exists(dest):
os.unlink(dest) os.unlink(dest)
self.symlink(target, dest) self.symlink(target, dest)
'''
Create a symlink with a relative path
'''
def symlink(self, target, dest): def symlink(self, target, dest):
'''
Create a symlink with a relative path
'''
if target.startswith('./') or target.startswith('../'): if target.startswith('./') or target.startswith('../'):
os.symlink(target, dest) os.symlink(target, dest)
elif '/' not in target: elif '/' not in target:
@ -914,10 +935,11 @@ class Setup():
os.symlink('/'.join(targets), dest) os.symlink('/'.join(targets), dest)
'''
Parses configurations
'''
def configure(self, opts): def configure(self, opts):
'''
Parses configurations
'''
(defaults, conf) = ({}, {}) (defaults, conf) = ({}, {})
for command in commands: for command in commands:
@ -1070,15 +1092,18 @@ class Setup():
ARGUMENTLESS = 0 ARGUMENTLESS = 0
ARGUMENTED = 1 ARGUMENTED = 1
'''
Simple argument parser, a strip down of the one in ponysay and slitly modified
'''
class ArgParser(): class ArgParser():
''' '''
Constructor. Simple argument parser, a strip down of the one in ponysay and slitly modified
The short description is printed on same line as the program name
''' '''
def __init__(self, program, description, usage, longdescription = None): def __init__(self, program, description, usage, longdescription = None):
'''
Constructor.
The short description is printed on same line as the program name
'''
self.__program = program self.__program = program
self.__description = description self.__description = description
self.__usage = usage self.__usage = usage
@ -1086,27 +1111,30 @@ class ArgParser():
self.__arguments = [] self.__arguments = []
(self.opts, self.optmap) = ({}, {}) (self.opts, self.optmap) = ({}, {})
'''
Add option that takes no arguments
'''
def add_argumentless(self, alternatives, help = None): def add_argumentless(self, alternatives, help = None):
'''
Add option that takes no arguments
'''
ARGUMENTLESS ARGUMENTLESS
self.__arguments.append((ARGUMENTLESS, alternatives, None, help)) self.__arguments.append((ARGUMENTLESS, alternatives, None, help))
(stdalt, self.opts[stdalt]) = (alternatives[0], None) (stdalt, self.opts[stdalt]) = (alternatives[0], None)
for alt in alternatives: self.optmap[alt] = (stdalt, ARGUMENTLESS) for alt in alternatives: self.optmap[alt] = (stdalt, ARGUMENTLESS)
'''
Add option that takes one argument
'''
def add_argumented(self, alternatives, arg, help = None): def add_argumented(self, alternatives, arg, help = None):
'''
Add option that takes one argument
'''
self.__arguments.append((ARGUMENTED, alternatives, arg, help)) self.__arguments.append((ARGUMENTED, alternatives, arg, help))
(stdalt, self.opts[stdalt]) = (alternatives[0], None) (stdalt, self.opts[stdalt]) = (alternatives[0], None)
for alt in alternatives: self.optmap[alt] = (stdalt, ARGUMENTED) for alt in alternatives: self.optmap[alt] = (stdalt, ARGUMENTED)
'''
Parse arguments
'''
def parse(self, argv = sys.argv): def parse(self, argv = sys.argv):
'''
Parse arguments
'''
self.argcount = len(argv) - 1 self.argcount = len(argv) - 1
self.files = [] self.files = []
(argqueue, optqueue, get) = ([], [], False) (argqueue, optqueue, get) = ([], [], False)
@ -1129,13 +1157,13 @@ class ArgParser():
optqueue.append(arg_opt) optqueue.append(arg_opt)
argqueue.append(arg[arg.index('=') + 1:]) argqueue.append(arg[arg.index('=') + 1:])
else: else:
sys.stderr.write('%s: fatal: unrecognised option %s. see --help or the manual\n' % (self.__program, arg)) self.print_fatal('Unrecognized option {}. Use --help or consult the manual.', arg)
exit(-1) exit(-1)
elif (arg in self.optmap) and (self.optmap[arg][1] == ARGUMENTED): elif (arg in self.optmap) and (self.optmap[arg][1] == ARGUMENTED):
optqueue.append(arg) optqueue.append(arg)
get = True get = True
else: else:
sys.stderr.write('%s: fatal: unrecognised option %s. see --help or the manual\n' % (self.__program, arg)) self.print_fatal('Unrecognized option {}. Use --help or consult the manual.', arg)
exit(-1) exit(-1)
else: else:
self.files.append(arg) self.files.append(arg)
@ -1149,14 +1177,17 @@ class ArgParser():
if (opt not in self.opts) or (self.opts[opt] is None): if (opt not in self.opts) or (self.opts[opt] is None):
self.opts[opt] = [arg] self.opts[opt] = [arg]
else: else:
sys.stderr.write('%s: fatal: duplicate option %s\n' % (self.__program, arg)) self.print_fatal('duplicate option {}', arg)
exit(-1) exit(-1)
''' def print_fatal(self, message, *args):
Prints a colourful help message sys.stderr.write('{}: fatal: {}\n'.format(self.__program, message.format(*args)))
'''
def help(self): def usage(self):
print('\033[1m%s\033[21m - %s\n' % (self.__program, self.__description)) '''
Print a short usage message.
'''
if self.__longdescription is not None: if self.__longdescription is not None:
print(self.__longdescription) print(self.__longdescription)
print() print()
@ -1165,8 +1196,21 @@ class ArgParser():
for line in self.__usage.split('\n'): for line in self.__usage.split('\n'):
if first: first = False if first: first = False
else: print(' or', end='') else: print(' or', end='')
print('\t%s' % (line)) print('\t{}'.format(line))
print('\n\033[1mCONFIGURATIONS:\033[21m\n')
print()
def help(self):
'''
Prints a colourful help message.
'''
# The usage should be terse so this header is only included in the help command.
print('\033[1m{}\033[21m - {}\n'.format(self.__program, self.__description))
self.usage()
print('\033[1mCONFIGURATIONS:\033[21m\n')
for opt in self.__arguments: for opt in self.__arguments:
(opt_type, opt_alts, opt_arg, opt_help) = opt[0:4] (opt_type, opt_alts, opt_arg, opt_help) = opt[0:4]
if opt_help is not None: if opt_help is not None: