| 1 |  |  | #!/usr/bin/env python3 | 
            
                                                                                                            
                            
            
                                    
            
            
                | 2 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 3 | 1 |  | """Command-line interface.""" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 4 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 5 | 1 |  | import sys | 
            
                                                                                                            
                            
            
                                    
            
            
                | 6 | 1 |  | import argparse | 
            
                                                                                                            
                            
            
                                    
            
            
                | 7 | 1 |  | import logging | 
            
                                                                                                            
                            
            
                                    
            
            
                | 8 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 9 | 1 |  | from . import CLI, VERSION, DESCRIPTION | 
            
                                                                                                            
                            
            
                                    
            
            
                | 10 | 1 |  | from . import common | 
            
                                                                                                            
                            
            
                                    
            
            
                | 11 | 1 |  | from . import commands | 
            
                                                                                                            
                            
            
                                    
            
            
                | 12 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 13 | 1 |  | log = logging.getLogger(__name__) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 14 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 15 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 16 | 1 |  | def main(args=None, function=None): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 17 |  |  |     """Process command-line arguments and run the program.""" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 18 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 19 |  |  |     # Shared options | 
            
                                                                                                            
                            
            
                                    
            
            
                | 20 | 1 |  |     debug = argparse.ArgumentParser(add_help=False) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 21 | 1 |  |     debug.add_argument('-V', '--version', action='version', version=VERSION) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 22 | 1 |  |     group = debug.add_mutually_exclusive_group() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 23 | 1 |  |     group.add_argument('-v', '--verbose', action='count', default=0, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 24 |  |  |                        help="enable verbose logging") | 
            
                                                                                                            
                            
            
                                    
            
            
                | 25 | 1 |  |     group.add_argument('-q', '--quiet', action='store_const', const=-1, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 26 |  |  |                        dest='verbose', help="only display errors and prompts") | 
            
                                                                                                            
                            
            
                                    
            
            
                | 27 | 1 |  |     project = argparse.ArgumentParser(add_help=False) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 28 | 1 |  |     project.add_argument('-r', '--root', metavar='PATH', | 
            
                                                                                                            
                            
            
                                    
            
            
                | 29 |  |  |                          help="root directory of the project") | 
            
                                                                                                            
                            
            
                                    
            
            
                | 30 | 1 |  |     depth = argparse.ArgumentParser(add_help=False) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 31 | 1 |  |     depth.add_argument('-d', '--depth', type=common.positive_int, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 32 |  |  |                        default=5, metavar="NUM", | 
            
                                                                                                            
                            
            
                                    
            
            
                | 33 |  |  |                        help="limit the number of dependency levels") | 
            
                                                                                                            
                            
            
                                    
            
            
                | 34 | 1 |  |     options = argparse.ArgumentParser(add_help=False) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 35 | 1 |  |     options.add_argument('-f', '--force', action='store_true', | 
            
                                                                                                            
                            
            
                                    
            
            
                | 36 |  |  |                          help="overwrite uncommitted changes in dependencies") | 
            
                                                                                                            
                            
            
                                    
            
            
                | 37 | 1 |  |     options.add_argument('-c', '--clean', action='store_true', | 
            
                                                                                                            
                            
            
                                    
            
            
                | 38 |  |  |                          help="keep ignored files in dependencies") | 
            
                                                                                                            
                            
            
                                    
            
            
                | 39 | 1 |  |     shared = {'formatter_class': common.WideHelpFormatter} | 
            
                                                                                                            
                            
            
                                    
            
            
                | 40 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 41 |  |  |     # Main parser | 
            
                                                                                                            
                            
            
                                    
            
            
                | 42 | 1 |  |     parser = argparse.ArgumentParser(prog=CLI, description=DESCRIPTION, | 
                            
                    |  |  |  | 
                                                                                        
                                                                                     | 
            
                                                                                                            
                            
            
                                    
            
            
                | 43 |  |  |                                      parents=[debug, project], **shared) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 44 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 45 | 1 |  |     subs = parser.add_subparsers(help="", dest='command', metavar="<command>") | 
            
                                                                                                            
                            
            
                                    
            
            
                | 46 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 47 |  |  |     # Install parser | 
            
                                                                                                            
                            
            
                                    
            
            
                | 48 | 1 |  |     info = "get the specified versions of all dependencies" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 49 | 1 |  |     sub = subs.add_parser('install', description=info.capitalize() + '.', | 
                            
                    |  |  |  | 
                                                                                        
                                                                                     | 
            
                                                                                                            
                            
            
                                    
            
            
                | 50 |  |  |                           help=info, parents=[debug, project, depth, options], | 
            
                                                                                                            
                            
            
                                    
            
            
                | 51 |  |  |                           **shared) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 52 | 1 |  |     sub.add_argument('name', nargs='*', | 
            
                                                                                                            
                            
            
                                    
            
            
                | 53 |  |  |                      help="list of dependencies names to install") | 
            
                                                                                                            
                            
            
                                    
            
            
                | 54 | 1 |  |     sub.add_argument('-e', '--fetch', action='store_true', | 
            
                                                                                                            
                            
            
                                    
            
            
                | 55 |  |  |                      help="always fetch the latest branches") | 
            
                                                                                                            
                            
            
                                    
            
            
                | 56 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 57 |  |  |     # Update parser | 
            
                                                                                                            
                            
            
                                    
            
            
                | 58 | 1 |  |     info = "update dependencies to the latest versions" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 59 | 1 |  |     sub = subs.add_parser('update', description=info.capitalize() + '.', | 
                            
                    |  |  |  | 
                                                                                        
                                                                                     | 
            
                                                                                                            
                            
            
                                    
            
            
                | 60 |  |  |                           help=info, parents=[debug, project, depth, options], | 
            
                                                                                                            
                            
            
                                    
            
            
                | 61 |  |  |                           **shared) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 62 | 1 |  |     sub.add_argument('name', nargs='*', | 
            
                                                                                                            
                            
            
                                    
            
            
                | 63 |  |  |                      help="list of dependencies names to update") | 
            
                                                                                                            
                            
            
                                    
            
            
                | 64 | 1 |  |     sub.add_argument('-a', '--all', action='store_true', dest='recurse', | 
            
                                                                                                            
                            
            
                                    
            
            
                | 65 |  |  |                      help="update all nested dependencies, recursively") | 
            
                                                                                                            
                            
            
                                    
            
            
                | 66 | 1 |  |     group = sub.add_mutually_exclusive_group() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 67 | 1 |  |     group.add_argument('-l', '--lock', | 
            
                                                                                                            
                            
            
                                    
            
            
                | 68 |  |  |                        action='store_true', dest='lock', default=None, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 69 |  |  |                        help="enable recording of versions for later reinstall") | 
            
                                                                                                            
                            
            
                                    
            
            
                | 70 | 1 |  |     group.add_argument('-L', '--no-lock', | 
            
                                                                                                            
                            
            
                                    
            
            
                | 71 |  |  |                        action='store_false', dest='lock', default=None, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 72 |  |  |                        help="disable recording of versions for later reinstall") | 
            
                                                                                                            
                            
            
                                    
            
            
                | 73 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 74 |  |  |     # Display parser | 
            
                                                                                                            
                            
            
                                    
            
            
                | 75 | 1 |  |     info = "display the current version of each dependency" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 76 | 1 |  |     sub = subs.add_parser('list', description=info.capitalize() + '.', | 
                            
                    |  |  |  | 
                                                                                        
                                                                                     | 
            
                                                                                                            
                            
            
                                    
            
            
                | 77 |  |  |                           help=info, parents=[debug, project, depth], **shared) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 78 | 1 |  |     sub.add_argument('-D', '--no-dirty', action='store_false', | 
            
                                                                                                            
                            
            
                                    
            
            
                | 79 |  |  |                      dest='allow_dirty', | 
            
                                                                                                            
                            
            
                                    
            
            
                | 80 |  |  |                      help="fail if a source has uncommitted changes") | 
            
                                                                                                            
                            
            
                                    
            
            
                | 81 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 82 |  |  |     # Lock parser | 
            
                                                                                                            
                            
            
                                    
            
            
                | 83 | 1 |  |     info = "lock the current version of each dependency" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 84 | 1 |  |     sub = subs.add_parser('lock', description=info.capitalize() + '.', | 
                            
                    |  |  |  | 
                                                                                        
                                                                                     | 
            
                                                                                                            
                            
            
                                    
            
            
                | 85 |  |  |                           help=info, parents=[debug, project], **shared) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 86 | 1 |  |     sub.add_argument('name', nargs='*', | 
            
                                                                                                            
                            
            
                                    
            
            
                | 87 |  |  |                      help="list of dependency names to lock") | 
            
                                                                                                            
                            
            
                                    
            
            
                | 88 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 89 |  |  |     # Uninstall parser | 
            
                                                                                                            
                            
            
                                    
            
            
                | 90 | 1 |  |     info = "delete all installed dependencies" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 91 | 1 |  |     sub = subs.add_parser('uninstall', description=info.capitalize() + '.', | 
                            
                    |  |  |  | 
                                                                                        
                                                                                     | 
            
                                                                                                            
                            
            
                                    
            
            
                | 92 |  |  |                           help=info, parents=[debug, project], **shared) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 93 | 1 |  |     sub.add_argument('-f', '--force', action='store_true', | 
            
                                                                                                            
                            
            
                                    
            
            
                | 94 |  |  |                      help="delete uncommitted changes in dependencies") | 
            
                                                                                                            
                            
            
                                    
            
            
                | 95 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 96 |  |  |     # Show parser | 
            
                                                                                                            
                            
            
                                    
            
            
                | 97 | 1 |  |     info = "display the path of a dependency or internal file" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 98 | 1 |  |     sub = subs.add_parser('show', description=info.capitalize() + '.', | 
                            
                    |  |  |  | 
                                                                                        
                                                                                     | 
            
                                                                                                            
                            
            
                                    
            
            
                | 99 |  |  |                           help=info, parents=[debug, project], **shared) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 100 | 1 |  |     sub.add_argument('name', nargs='*', | 
            
                                                                                                            
                            
            
                                    
            
            
                | 101 |  |  |                      help="display the path of this dependency") | 
            
                                                                                                            
                            
            
                                    
            
            
                | 102 | 1 |  |     sub.add_argument('-c', '--config', action='store_true', | 
            
                                                                                                            
                            
            
                                    
            
            
                | 103 |  |  |                      help="display the path of the config file") | 
            
                                                                                                            
                            
            
                                    
            
            
                | 104 | 1 |  |     sub.add_argument('-l', '--log', action='store_true', | 
            
                                                                                                            
                            
            
                                    
            
            
                | 105 |  |  |                      help="display the path of the log file") | 
            
                                                                                                            
                            
            
                                    
            
            
                | 106 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 107 |  |  |     # Edit parser | 
            
                                                                                                            
                            
            
                                    
            
            
                | 108 | 1 |  |     info = "open the configuration file in the default editor" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 109 | 1 |  |     sub = subs.add_parser('edit', description=info.capitalize() + '.', | 
                            
                    |  |  |  | 
                                                                                        
                                                                                     | 
            
                                                                                                            
                            
            
                                    
            
            
                | 110 |  |  |                           help=info, parents=[debug, project], **shared) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 111 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 112 |  |  |     # Parse arguments | 
            
                                                                                                            
                            
            
                                    
            
            
                | 113 | 1 |  |     namespace = parser.parse_args(args=args) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 114 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 115 |  |  |     # Configure logging | 
            
                                                                                                            
                            
            
                                    
            
            
                | 116 | 1 |  |     common.configure_logging(namespace.verbose) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 117 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 118 |  |  |     # Run the program | 
            
                                                                                                            
                            
            
                                    
            
            
                | 119 | 1 |  |     function, args, kwargs, exit_msg = _get_command(function, namespace) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 120 | 1 |  |     if function is None: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 121 | 1 |  |         parser.print_help() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 122 | 1 |  |         sys.exit(1) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 123 | 1 |  |     _run_command(function, args, kwargs, exit_msg) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 124 |  |  |  | 
            
                                                                                                            
                                                                
            
                                    
            
            
                | 125 |  |  |  | 
            
                                                                        
                            
            
                                    
            
            
                | 126 | 1 |  | def _get_command(function, namespace): | 
            
                                                                        
                            
            
                                    
            
            
                | 127 | 1 |  |     args = [] | 
            
                                                                        
                            
            
                                    
            
            
                | 128 | 1 |  |     kwargs = dict(root=namespace.root) | 
            
                                                                        
                            
            
                                    
            
            
                | 129 | 1 |  |     exit_msg = "" | 
            
                                                                        
                            
            
                                    
            
            
                | 130 |  |  |  | 
            
                                                                        
                            
            
                                    
            
            
                | 131 | 1 |  |     if namespace.command in ['install', 'update']: | 
            
                                                                        
                            
            
                                    
            
            
                | 132 | 1 |  |         function = getattr(commands, namespace.command) | 
            
                                                                        
                            
            
                                    
            
            
                | 133 | 1 |  |         args = namespace.name | 
            
                                                                        
                            
            
                                    
            
            
                | 134 | 1 |  |         kwargs.update(depth=namespace.depth, | 
            
                                                                        
                            
            
                                    
            
            
                | 135 |  |  |                       force=namespace.force, | 
            
                                                                        
                            
            
                                    
            
            
                | 136 |  |  |                       clean=namespace.clean) | 
            
                                                                        
                            
            
                                    
            
            
                | 137 | 1 |  |         if namespace.command == 'install': | 
            
                                                                        
                            
            
                                    
            
            
                | 138 | 1 |  |             kwargs.update(fetch=namespace.fetch) | 
            
                                                                        
                            
            
                                    
            
            
                | 139 | 1 |  |         if namespace.command == 'update': | 
            
                                                                        
                            
            
                                    
            
            
                | 140 | 1 |  |             kwargs.update(recurse=namespace.recurse, | 
            
                                                                        
                            
            
                                    
            
            
                | 141 |  |  |                           lock=namespace.lock) | 
            
                                                                        
                            
            
                                    
            
            
                | 142 | 1 |  |         exit_msg = "\n" + "Run again with '--force' to overwrite" | 
            
                                                                        
                            
            
                                    
            
            
                | 143 | 1 |  |     elif namespace.command == 'list': | 
            
                                                                        
                            
            
                                    
            
            
                | 144 | 1 |  |         function = commands.display | 
            
                                                                        
                            
            
                                    
            
            
                | 145 | 1 |  |         kwargs.update(dict(depth=namespace.depth, | 
            
                                                                        
                            
            
                                    
            
            
                | 146 |  |  |                            allow_dirty=namespace.allow_dirty)) | 
            
                                                                        
                            
            
                                    
            
            
                | 147 | 1 |  |     elif namespace.command == 'lock': | 
            
                                                                        
                            
            
                                    
            
            
                | 148 | 1 |  |         function = getattr(commands, namespace.command) | 
            
                                                                        
                            
            
                                    
            
            
                | 149 | 1 |  |         args = namespace.name | 
            
                                                                        
                            
            
                                    
            
            
                | 150 | 1 |  |     elif namespace.command == 'uninstall': | 
            
                                                                        
                            
            
                                    
            
            
                | 151 | 1 |  |         function = commands.delete | 
            
                                                                        
                            
            
                                    
            
            
                | 152 | 1 |  |         kwargs.update(force=namespace.force) | 
            
                                                                        
                            
            
                                    
            
            
                | 153 | 1 |  |         exit_msg = "\n" + "Run again with '--force' to ignore" | 
            
                                                                        
                            
            
                                    
            
            
                | 154 | 1 |  |     elif namespace.command == 'show': | 
            
                                                                        
                            
            
                                    
            
            
                | 155 | 1 |  |         function = commands.show | 
            
                                                                        
                            
            
                                    
            
            
                | 156 | 1 |  |         args = namespace.name | 
            
                                                                        
                            
            
                                    
            
            
                | 157 | 1 |  |         if namespace.config: | 
            
                                                                        
                            
            
                                    
            
            
                | 158 | 1 |  |             args.append('__config__') | 
            
                                                                        
                            
            
                                    
            
            
                | 159 | 1 |  |         if namespace.log: | 
            
                                                                        
                            
            
                                    
            
            
                | 160 | 1 |  |             args.append('__log__') | 
            
                                                                        
                            
            
                                    
            
            
                | 161 | 1 |  |     elif namespace.command == 'edit': | 
            
                                                                        
                            
            
                                    
            
            
                | 162 | 1 |  |         function = commands.edit | 
            
                                                                        
                            
            
                                    
            
            
                | 163 |  |  |  | 
            
                                                                        
                            
            
                                    
            
            
                | 164 | 1 |  |     return function, args, kwargs, exit_msg | 
            
                                                                                                            
                            
            
                                    
            
            
                | 165 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 166 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 167 | 1 |  | def _run_command(function, args, kwargs, exit_msg): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 168 | 1 |  |     success = False | 
            
                                                                                                            
                            
            
                                    
            
            
                | 169 | 1 |  |     try: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 170 | 1 |  |         log.debug("Running %s command...", getattr(function, '__name__', 'a')) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 171 | 1 |  |         success = function(*args, **kwargs) | 
                            
                    |  |  |  | 
                                                                                        
                                                                                     | 
            
                                                                                                            
                            
            
                                    
            
            
                | 172 | 1 |  |     except KeyboardInterrupt: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 173 | 1 |  |         log.debug("Command canceled") | 
            
                                                                                                            
                            
            
                                    
            
            
                | 174 | 1 |  |         exit_msg = "" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 175 | 1 |  |     except RuntimeError as exc: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 176 | 1 |  |         exit_msg = str(exc) + exit_msg | 
            
                                                                                                            
                            
            
                                    
            
            
                | 177 |  |  |     else: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 178 | 1 |  |         exit_msg = "" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 179 | 1 |  |     if success: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 180 | 1 |  |         log.debug("Command succeeded") | 
            
                                                                                                            
                            
            
                                    
            
            
                | 181 |  |  |     else: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 182 | 1 |  |         log.debug("Command failed") | 
            
                                                                                                            
                            
            
                                    
            
            
                | 183 | 1 |  |         sys.exit(exit_msg or 1) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 184 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 185 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 186 |  |  | if __name__ == '__main__':  # pragma: no cover (manual test) | 
            
                                                                                                            
                                                                
            
                                    
            
            
                | 187 |  |  |     main() | 
            
                                                        
            
                                    
            
            
                | 188 |  |  |  | 
            
                        
Generally, there is nothing wrong with usage of
*or**arguments. For readability of the code base, we suggest to not over-use these language constructs though.For more information, we can recommend this blog post from Ned Batchelder including its comments which also touches this aspect.