From b9e9f005030a131b00fc2881f49620adec828e48 Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Sun, 7 Sep 2014 19:34:20 +0200 Subject: [PATCH 1/6] setup.py: Moved docstrings into the associated functions. --- setup.py | 145 +++++++++++++++++++++++++++++++------------------------ 1 file changed, 82 insertions(+), 63 deletions(-) diff --git a/setup.py b/setup.py index 823e4b06..605d0a50 100755 --- a/setup.py +++ b/setup.py @@ -299,11 +299,12 @@ class Setup(): elif not method == 'view': opts.help() - - ''' - Display configurations - ''' + def viewconf(self, conf): + ''' + Display configurations + ''' + RED = '\033[31m%s\033[39m' GREEN = '%s\033[32m%s\033[39m' YELLOW = '\033[33m%s\033[39m' @@ -351,11 +352,12 @@ class Setup(): else: print(RED % ('Installing \033[1mnot\033[21m only fully free parts of the package')) print() - - ''' - Compile ponysay - ''' + def build(self, conf): + ''' + Compile ponysay + ''' + print('\033[1;34m::\033[39mCompiling...\033[21m') def compressCommand(ext): @@ -556,11 +558,12 @@ class Setup(): Popen(params, stdin=PIPE, stdout=PIPE, stderr=PIPE).communicate() print() - - ''' - Install compiled ponysay - ''' + def install(self, conf): + ''' + Install compiled ponysay + ''' + print('\033[1;34m::\033[39mInstalling...\033[21m') dests = [] @@ -642,11 +645,12 @@ class Setup(): for file in miscfiles: self.cp(False, file[0], [conf[file[0]]], Setup.validateFreedom if self.free else None) print() - - ''' - Uninstall ponysay - ''' + def uninstall(self, conf): + ''' + Uninstall ponysay + ''' + print('\033[1;34m::\033[39mUninstalling...\033[21m') (files, dirs, infos) = ([], [], []) @@ -699,11 +703,12 @@ class Setup(): self.removeLists(files, dirs) print() - - ''' - Uninstall file ponysay no longer uses - ''' + def uninstallOld(self, conf): + ''' + Uninstall file ponysay no longer uses + ''' + print('\033[1;34m::\033[39mUninstalling old files...\033[21m') instdir = conf['~prefix~'] + '/usr' @@ -719,11 +724,12 @@ class Setup(): self.removeLists(files, dirs) print() - - ''' - Remove compiled files - ''' + def clean(self): + ''' + Remove compiled files + ''' + 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'] @@ -746,10 +752,11 @@ class Setup(): self.removeLists(files, dirs) print() - ''' - Remove compiled files ponysay is no longer compiling - ''' def cleanOld(self): + ''' + Remove compiled files ponysay is no longer compiling + ''' + print('\033[1;34m::\033[39mCleaning old files...\033[21m') files = ['truncater', 'ponysaytruncater', 'ponysay.py.install', 'ponysay.install~', 'ponysay.zip'] @@ -763,11 +770,12 @@ class Setup(): self.removeLists(files, dirs) print() - - ''' - Removes listed files and directories - ''' + def removeLists(self, files, dirs): + ''' + Removes listed files and directories + ''' + for file in files: if os.path.isfile(file) or os.path.islink(file): print('Unlinking file %s' % (file)) @@ -792,12 +800,13 @@ class Setup(): os.rmdir(dir) else: break; - - ''' - Check whether a file is fully free - ''' + @staticmethod def validateFreedom(filename): + ''' + Check whether a file is fully free + ''' + if not os.path.isdir(filename): if filename.endswith('.pony') and (filename != '.pony') and not filename.endswith('/.pony'): with open(filename, 'rb') as file: @@ -812,11 +821,12 @@ class Setup(): return line[1].lower() == 'yes' return False return True - - ''' - Copys a files or directory to multiple destinations - ''' + def cp(self, recursive, source, destinations, validatehook = None): + ''' + Copys a files or directory to multiple destinations + ''' + if validatehook is not None: if not validatehook(source): print('Ignoring installation of file %s (did not pass validation process made by setup settings)' % source) @@ -890,11 +900,12 @@ class Setup(): if os.path.exists(dest): os.unlink(dest) self.symlink(target, dest) - - ''' - Create a symlink with a relative path - ''' + def symlink(self, target, dest): + ''' + Create a symlink with a relative path + ''' + if target.startswith('./') or target.startswith('../'): os.symlink(target, dest) elif '/' not in target: @@ -914,10 +925,11 @@ class Setup(): os.symlink('/'.join(targets), dest) - ''' - Parses configurations - ''' def configure(self, opts): + ''' + Parses configurations + ''' + (defaults, conf) = ({}, {}) for command in commands: @@ -1070,15 +1082,18 @@ class Setup(): ARGUMENTLESS = 0 ARGUMENTED = 1 -''' -Simple argument parser, a strip down of the one in ponysay and slitly modified -''' + class ArgParser(): ''' - Constructor. - The short description is printed on same line as the program name + Simple argument parser, a strip down of the one in ponysay and slitly modified ''' + 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.__description = description self.__usage = usage @@ -1086,27 +1101,30 @@ class ArgParser(): self.__arguments = [] (self.opts, self.optmap) = ({}, {}) - ''' - Add option that takes no arguments - ''' def add_argumentless(self, alternatives, help = None): + ''' + Add option that takes no arguments + ''' + ARGUMENTLESS self.__arguments.append((ARGUMENTLESS, alternatives, None, help)) (stdalt, self.opts[stdalt]) = (alternatives[0], None) for alt in alternatives: self.optmap[alt] = (stdalt, ARGUMENTLESS) - ''' - Add option that takes one argument - ''' def add_argumented(self, alternatives, arg, help = None): + ''' + Add option that takes one argument + ''' + self.__arguments.append((ARGUMENTED, alternatives, arg, help)) (stdalt, self.opts[stdalt]) = (alternatives[0], None) for alt in alternatives: self.optmap[alt] = (stdalt, ARGUMENTED) - ''' - Parse arguments - ''' def parse(self, argv = sys.argv): + ''' + Parse arguments + ''' + self.argcount = len(argv) - 1 self.files = [] (argqueue, optqueue, get) = ([], [], False) @@ -1152,10 +1170,11 @@ class ArgParser(): sys.stderr.write('%s: fatal: duplicate option %s\n' % (self.__program, arg)) exit(-1) - ''' - Prints a colourful help message - ''' def help(self): + ''' + Prints a colourful help message + ''' + print('\033[1m%s\033[21m - %s\n' % (self.__program, self.__description)) if self.__longdescription is not None: print(self.__longdescription) From 8cc55723de7952096f7b039a5ab5c39e862b34b6 Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Mon, 8 Sep 2014 20:52:09 +0200 Subject: [PATCH 2/6] setup.py: Print error message and usage when no or multiple commands are given on the command line. --- setup.py | 33 +++++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/setup.py b/setup.py index 605d0a50..a95fafc3 100755 --- a/setup.py +++ b/setup.py @@ -259,14 +259,15 @@ class Setup(): prefix = opts.opts['---PREFIX'][0] if len(prefix) > 0: 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) or ((len(opts.files) == 1) and (opts.files[0] == 'help')): opts.help() elif (opts.opts['--version'] is not None) or ((len(opts.files) == 1) and (opts.files[0] == '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: - if len(opts.files) == 0: - opts.files = ['build'] method = opts.files[0] if method == 'clean': self.clean() elif method == 'clean-old': self.cleanOld() @@ -1169,13 +1170,12 @@ class ArgParser(): else: sys.stderr.write('%s: fatal: duplicate option %s\n' % (self.__program, arg)) exit(-1) - - def help(self): + + def usage(self): ''' - Prints a colourful help message + Print a short usage message. ''' - print('\033[1m%s\033[21m - %s\n' % (self.__program, self.__description)) if self.__longdescription is not None: print(self.__longdescription) print() @@ -1184,8 +1184,21 @@ class ArgParser(): for line in self.__usage.split('\n'): if first: first = False else: print(' or', end='') - print('\t%s' % (line)) - print('\n\033[1mCONFIGURATIONS:\033[21m\n') + print('\t{}'.format(line)) + + 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: (opt_type, opt_alts, opt_arg, opt_help) = opt[0:4] if opt_help is not None: From 25682cdfe998a21ddc8bde0d848a40525005f524 Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Mon, 8 Sep 2014 21:03:02 +0200 Subject: [PATCH 3/6] setup.py: Added function to print fatal errors. --- setup.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/setup.py b/setup.py index a95fafc3..04b2f2ac 100755 --- a/setup.py +++ b/setup.py @@ -1148,13 +1148,13 @@ class ArgParser(): optqueue.append(arg_opt) argqueue.append(arg[arg.index('=') + 1:]) else: - sys.stderr.write('%s: fatal: unrecognised option %s. see --help or the manual\n' % (self.__program, arg)) + self.print_fatal('Unrecognized option {}. Use the help command or consult the manual.', arg) exit(-1) elif (arg in self.optmap) and (self.optmap[arg][1] == ARGUMENTED): optqueue.append(arg) get = True else: - sys.stderr.write('%s: fatal: unrecognised option %s. see --help or the manual\n' % (self.__program, arg)) + self.print_fatal('Unrecognized option {}. Use the help command or consult the manual.', arg) exit(-1) else: self.files.append(arg) @@ -1168,9 +1168,12 @@ class ArgParser(): if (opt not in self.opts) or (self.opts[opt] is None): self.opts[opt] = [arg] else: - sys.stderr.write('%s: fatal: duplicate option %s\n' % (self.__program, arg)) + self.print_fatal('duplicate option {}', arg) exit(-1) + def print_fatal(self, message, *args): + sys.stderr.write('{}: fatal: {}\n'.format(self.__program, message.format(*args))) + def usage(self): ''' Print a short usage message. From 4415291c0ca64b9d5e1a63d14a55d84be825dead Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Mon, 8 Sep 2014 21:14:06 +0200 Subject: [PATCH 4/6] setup.py: Removed command variants of --help and --version. The code path to handle these was confusing, as was their usage as the usage referred only to the commands while some error messages only referred to the options. --- setup.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/setup.py b/setup.py index 04b2f2ac..5334d037 100755 --- a/setup.py +++ b/setup.py @@ -48,7 +48,7 @@ SYMBOLIC = 'symbolic' class Setup(): def __init__(self): 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 = '%s %s\n%s %s' % (usage_script, usage_help, usage_script, usage_proc) @@ -260,9 +260,9 @@ class Setup(): if len(prefix) > 0: opts.opts['--prefix'] = [prefix] - if (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() - 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)) elif len(opts.files) != 1: opts.print_fatal('A single command is expected on the command line.') @@ -1148,13 +1148,13 @@ class ArgParser(): optqueue.append(arg_opt) argqueue.append(arg[arg.index('=') + 1:]) else: - self.print_fatal('Unrecognized option {}. Use the help command or consult the manual.', arg) + self.print_fatal('Unrecognized option {}. Use --help or consult the manual.', arg) exit(-1) elif (arg in self.optmap) and (self.optmap[arg][1] == ARGUMENTED): optqueue.append(arg) get = True else: - self.print_fatal('Unrecognized option {}. Use the help command or consult the manual.', arg) + self.print_fatal('Unrecognized option {}. Use --help or consult the manual.', arg) exit(-1) else: self.files.append(arg) From e5c650349b71bc7f204310dd3d1243ca8bed2f54 Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Mon, 8 Sep 2014 21:24:36 +0200 Subject: [PATCH 5/6] setup.py: checkFreedom() should not need to check whether commands have been given on the command line. --- setup.py | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/setup.py b/setup.py index 5334d037..daa0b613 100755 --- a/setup.py +++ b/setup.py @@ -240,16 +240,15 @@ class Setup(): self.free = False def checkFreedom(): if self.free is None: - if (opts.opts['--version'] is None) and ((len(opts.files) != 1) or (opts.files[0] != 'version')): - print('') - print('You need to select your freedom, add --freedom=strict or --freedom=partial.') - print('') - 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('') - print('') - exit(255) - + print() + print('You need to select your freedom, add --freedom=strict or --freedom=partial.') + print() + 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() + print() + exit(255) + if (opts.opts['---DESTDIR'] is not None) and (opts.opts['--dest-dir'] is None): destdir = opts.opts['---DESTDIR'][0] if len(destdir) > 0: From 6658221bbf1540fb773be7e3c1690c09d9720072 Mon Sep 17 00:00:00 2001 From: Michael Schwarz Date: Mon, 8 Sep 2014 21:26:09 +0200 Subject: [PATCH 6/6] setup.py: Do not print the configuration when an unknown command was given so that the printed usage is better noticed. --- setup.py | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/setup.py b/setup.py index daa0b613..6703552b 100755 --- a/setup.py +++ b/setup.py @@ -249,6 +249,10 @@ class Setup(): print() 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): destdir = opts.opts['---DESTDIR'][0] if len(destdir) > 0: @@ -272,33 +276,39 @@ class Setup(): elif method == 'clean-old': self.cleanOld() else: conf = self.configure(opts.opts) - self.viewconf(conf) - os.umask(0o022) if method == 'build': checkFreedom() + setup_config() self.build(conf) elif method == 'prebuilt': checkFreedom() + setup_config() self.applyDestDir(conf) self.install(conf) elif method == 'install': checkFreedom() + setup_config() self.build(conf) self.applyDestDir(conf) self.install(conf) self.clean() elif method == 'uninstall': + setup_config() self.uninstall(conf) elif method == 'uninstall-old': + setup_config() self.uninstallOld(conf) - elif not method == 'view': - opts.help() + elif method == 'view': + setup_config() + else: + opts.print_fatal('Unknown command: {}', method) + opts.usage() def viewconf(self, conf): '''