#!/usr/bin/env python import sys import os import optparse import subprocess import re from pip.log import logger from pip.baseparser import parser from pip.exceptions import InstallationError from pip.basecommand import command_dict, load_command, load_all_commands from pip.vcs import vcs, get_src_requirement, import_vcs_support def autocomplete(): """Command and option completion for the main option parser (and options) and its subcommands (and options). Enable by sourcing one of the completion shell scripts (bash or zsh). """ # Don't complete if user hasn't sourced bash_completion file. if not os.environ.has_key('PIP_AUTO_COMPLETE'): return cwords = os.environ['COMP_WORDS'].split()[1:] cword = int(os.environ['COMP_CWORD']) try: current = cwords[cword-1] except IndexError: current = '' load_all_commands() subcommands = [cmd for cmd, cls in command_dict.items() if not cls.hidden] options = [] # subcommand if cword == 1: # show options of main parser only when necessary if current.startswith('-') or current.startswith('--'): subcommands += [opt.get_opt_string() for opt in parser.option_list if opt.help != optparse.SUPPRESS_HELP] print ' '.join(filter(lambda x: x.startswith(current), subcommands)) # subcommand options # special case: the 'help' subcommand has no options elif cwords[0] in subcommands and cwords[0] != 'help': subcommand = command_dict.get(cwords[0]) options += [(opt.get_opt_string(), opt.nargs) for opt in subcommand.parser.option_list if opt.help != optparse.SUPPRESS_HELP] # filter out previously specified options from available options prev_opts = [x.split('=')[0] for x in cwords[1:cword-1]] options = filter(lambda (x, v): x not in prev_opts, options) # filter options by current input options = [(k, v) for k, v in options if k.startswith(current)] for option in options: opt_label = option[0] # append '=' to options which require args if option[1]: opt_label += '=' print opt_label sys.exit(1) def main(initial_args=None): if initial_args is None: initial_args = sys.argv[1:] autocomplete() options, args = parser.parse_args(initial_args) if options.help and not args: args = ['help'] if not args: parser.error('You must give a command (use "pip help" see a list of commands)') command = args[0].lower() load_command(command) ## FIXME: search for a command match? if command not in command_dict: parser.error('No command by the name %(script)s %(arg)s\n (maybe you meant "%(script)s install %(arg)s")' % dict(script=os.path.basename(sys.argv[0]), arg=command)) command = command_dict[command] return command.main(initial_args, args[1:], options) ############################################################ ## Writing freeze files class FrozenRequirement(object): def __init__(self, name, req, editable, comments=()): self.name = name self.req = req self.editable = editable self.comments = comments _rev_re = re.compile(r'-r(\d+)$') _date_re = re.compile(r'-(20\d\d\d\d\d\d)$') @classmethod def from_dist(cls, dist, dependency_links, find_tags=False): location = os.path.normcase(os.path.abspath(dist.location)) comments = [] if vcs.get_backend_name(location): editable = True req = get_src_requirement(dist, location, find_tags) if req is None: logger.warn('Could not determine repository location of %s' % location) comments.append('## !! Could not determine repository location') req = dist.as_requirement() editable = False else: editable = False req = dist.as_requirement() specs = req.specs assert len(specs) == 1 and specs[0][0] == '==' version = specs[0][1] ver_match = cls._rev_re.search(version) date_match = cls._date_re.search(version) if ver_match or date_match: svn_backend = vcs.get_backend('svn') if svn_backend: svn_location = svn_backend( ).get_location(dist, dependency_links) if not svn_location: logger.warn( 'Warning: cannot find svn location for %s' % req) comments.append('## FIXME: could not find svn URL in dependency_links for this package:') else: comments.append('# Installing as editable to satisfy requirement %s:' % req) if ver_match: rev = ver_match.group(1) else: rev = '{%s}' % date_match.group(1) editable = True req = 'svn+%s@%s#egg=%s' % (svn_location, rev, cls.egg_name(dist)) return cls(dist.project_name, req, editable, comments) @staticmethod def egg_name(dist): name = dist.egg_name() match = re.search(r'-py\d\.\d$', name) if match: name = name[:match.start()] return name def __str__(self): req = self.req if self.editable: req = '-e %s' % req return '\n'.join(list(self.comments)+[str(req)])+'\n' ############################################################ ## Requirement files def call_subprocess(cmd, show_stdout=True, filter_stdout=None, cwd=None, raise_on_returncode=True, command_level=logger.DEBUG, command_desc=None, extra_environ=None): if command_desc is None: cmd_parts = [] for part in cmd: if ' ' in part or '\n' in part or '"' in part or "'" in part: part = '"%s"' % part.replace('"', '\\"') cmd_parts.append(part) command_desc = ' '.join(cmd_parts) if show_stdout: stdout = None else: stdout = subprocess.PIPE logger.log(command_level, "Running command %s" % command_desc) env = os.environ.copy() if extra_environ: env.update(extra_environ) try: proc = subprocess.Popen( cmd, stderr=subprocess.STDOUT, stdin=None, stdout=stdout, cwd=cwd, env=env) except Exception, e: logger.fatal( "Error %s while executing command %s" % (e, command_desc)) raise all_output = [] if stdout is not None: stdout = proc.stdout while 1: line = stdout.readline() if not line: break line = line.rstrip() all_output.append(line + '\n') if filter_stdout: level = filter_stdout(line) if isinstance(level, tuple): level, line = level logger.log(level, line) if not logger.stdout_level_matches(level): logger.show_progress() else: logger.info(line) else: returned_stdout, returned_stderr = proc.communicate() all_output = [returned_stdout or ''] proc.wait() if proc.returncode: if raise_on_returncode: if all_output: logger.notify('Complete output from command %s:' % command_desc) logger.notify('\n'.join(all_output) + '\n----------------------------------------') raise InstallationError( "Command %s failed with error code %s" % (command_desc, proc.returncode)) else: logger.warn( "Command %s had error code %s" % (command_desc, proc.returncode)) if stdout is not None: return ''.join(all_output) import_vcs_support() if __name__ == '__main__': exit = main() if exit: sys.exit(exit)