def command(self): if self.options.list_entry_points: return self.list_entry_points() if self.options.show_egg: return self.show_egg(self.options.show_egg) if not self.args: raise BadCommand("You must give an entry point (or --list)") pattern = self.get_pattern(self.args[0]) groups = self.get_groups_by_pattern(pattern) if not groups: raise BadCommand('No group matched %s' % self.args[0]) ep_pat = None if len(self.args) > 1: ep_pat = self.get_pattern(self.args[1]) for group in groups: desc = self.get_group_description(group) print '[%s]' % group if desc: print self.wrap(desc) print by_dist = {} self.print_entry_points_by_group(group, ep_pat)
def parse_args(self, args): if args == ['-h']: Command.parse_args(self, args) return # These are the arguments parsed normally: normal_args = [] # And these are arguments passed to the URL: extra_args = [] # This keeps track of whether we have the two required positional arguments: pos_args = 0 while args: start = args[0] if not start.startswith('-'): if pos_args < 2: pos_args += 1 normal_args.append(start) args.pop(0) continue else: normal_args.append(start) args.pop(0) continue else: found = False for option in self.ARG_OPTIONS: if start == option: normal_args.append(start) args.pop(0) if not args: raise BadCommand("Option %s takes an argument" % option) normal_args.append(args.pop(0)) found = True break elif start.startswith(option + '='): normal_args.append(start) args.pop(0) found = True break if found: continue if start in self.OTHER_OPTIONS: normal_args.append(start) args.pop(0) continue extra_args.append(start) args.pop(0) Command.parse_args(self, normal_args) # Add the extra arguments back in: self.args = self.args + extra_args
def change_user_group(self, user, group): if not user and not group: return import pwd, grp uid = gid = None if group: try: gid = int(group) group = grp.getgrgid(gid).gr_name except ValueError: import grp try: entry = grp.getgrnam(group) except KeyError: raise BadCommand("Bad group: %r; no such group exists" % group) gid = entry.gr_gid try: uid = int(user) user = pwd.getpwuid(uid).pw_name except ValueError: try: entry = pwd.getpwnam(user) except KeyError: raise BadCommand("Bad username: %r; no such user exists" % user) if not gid: gid = entry.pw_gid uid = entry.pw_uid if self.verbose > 0: print 'Changing user to %s:%s (%s:%s)' % (user, group or '(unknown)', uid, gid) if gid: os.setgid(gid) if uid: os.setuid(uid)
def command(self): if self.options.list_templates: return self.list_templates() asked_tmpls = self.options.templates or ['basic_package'] templates = [] for tmpl_name in asked_tmpls: self.extend_templates(templates, tmpl_name) if self.options.list_variables: return self.list_variables(templates) if self.verbose: print 'Selected and implied templates:' max_tmpl_name = max([len(tmpl_name) for tmpl_name, tmpl in templates]) for tmpl_name, tmpl in templates: print ' %s%s %s' % ( tmpl_name, ' '*(max_tmpl_name-len(tmpl_name)), tmpl.summary) print if not self.args: if self.interactive: dist_name = self.challenge('Enter project name') else: raise BadCommand('You must provide a PACKAGE_NAME') else: dist_name = self.args[0].lstrip(os.path.sep) templates = [tmpl for name, tmpl in templates] output_dir = os.path.join(self.options.output_dir, dist_name) pkg_name = self._bad_chars_re.sub('', dist_name.lower()) vars = {'project': dist_name, 'package': pkg_name, 'egg': pluginlib.egg_name(dist_name), } vars.update(self.parse_vars(self.args[1:])) if self.options.config and os.path.exists(self.options.config): for key, value in self.read_vars(self.options.config).items(): vars.setdefault(key, value) if self.verbose: # @@: > 1? self.display_vars(vars) if self.options.inspect_files: self.inspect_files( output_dir, templates, vars) return if not os.path.exists(output_dir): # We want to avoid asking questions in copydir if the path # doesn't exist yet copydir.all_answer = 'y' if self.options.svn_repository: self.setup_svn_repository(output_dir, dist_name) # First we want to make sure all the templates get a chance to # set their variables, all at once, with the most specialized # template going first (the last template is the most # specialized)... for template in templates[::-1]: vars = template.check_vars(vars, self) for template in templates: self.create_template( template, output_dir, vars) found_setup_py = False if os.path.exists(os.path.join(output_dir, 'setup.py')): self.run_command(sys.executable, 'setup.py', 'egg_info', cwd=output_dir, # This shouldn't be necessary, but a bug in setuptools 0.6c3 is causing a (not entirely fatal) problem that I don't want to fix right now: expect_returncode=True) found_setup_py = True elif self.verbose > 1: print 'No setup.py (cannot run egg_info)' package_dir = vars.get('package_dir', None) if package_dir: output_dir = os.path.join(output_dir, package_dir) # With no setup.py this doesn't make sense: if found_setup_py: egg_info_dir = pluginlib.egg_info_dir(output_dir, dist_name) for template in templates: for spec in template.egg_plugins: if self.verbose: print 'Adding %s to paster_plugins.txt' % spec if not self.simulate: pluginlib.add_plugin(egg_info_dir, spec) if not self.simulate: # We'll include this by default, but you can remove # it later if you want: pluginlib.add_plugin(egg_info_dir, 'PasteScript') if self.options.svn_repository: self.add_svn_repository(vars, output_dir) if self.options.config: write_vars = vars.copy() del write_vars['project'] del write_vars['package'] self.write_vars(self.options.config, write_vars)
def command(self): if self.options.list_templates: return self.list_templates() asked_tmpls = self.options.templates or ['basic_package'] templates = [] for tmpl_name in asked_tmpls: self.extend_templates(templates, tmpl_name) if self.options.list_variables: return self.list_variables(templates) if self.verbose: print 'Selected and implied templates:' max_tmpl_name = max( [len(tmpl_name) for tmpl_name, tmpl in templates]) for tmpl_name, tmpl in templates: print ' %s%s %s' % (tmpl_name, ' ' * (max_tmpl_name - len(tmpl_name)), tmpl.summary) print if not self.args: if self.interactive: dist_name = self.challenge('Enter project name') else: raise BadCommand('You must provide a PACKAGE_NAME') else: dist_name = self.args[0].lstrip(os.path.sep) templates = [tmpl for name, tmpl in templates] output_dir = os.path.join(self.options.output_dir, dist_name) pkg_name = self._bad_chars_re.sub('', dist_name.lower()) vars = { 'project': dist_name, 'package': pkg_name, 'egg': pluginlib.egg_name(dist_name), } vars.update(self.parse_vars(self.args[1:])) if self.options.config and os.path.exists(self.options.config): for key, value in self.read_vars(self.options.config).items(): vars.setdefault(key, value) if self.verbose: # @@: > 1? self.display_vars(vars) if self.options.inspect_files: self.inspect_files(output_dir, templates, vars) return if not os.path.exists(output_dir): # We want to avoid asking questions in copydir if the path # doesn't exist yet copydir.all_answer = 'y' if self.options.svn_repository: self.setup_svn_repository(output_dir, dist_name) # First we want to make sure all the templates get a chance to # set their variables, all at once, with the most specialized # template going first (the last template is the most # specialized)... for template in templates[::-1]: vars = template.check_vars(vars, self) # Gather all the templates egg_plugins into one var egg_plugins = set() for template in templates: egg_plugins.update(template.egg_plugins) egg_plugins = list(egg_plugins) egg_plugins.sort() vars['egg_plugins'] = egg_plugins for template in templates: self.create_template(template, output_dir, vars) found_setup_py = False paster_plugins_mtime = None if os.path.exists(os.path.join(output_dir, 'setup.py')): # Grab paster_plugins.txt's mtime; used to determine if the # egg_info command wrote to it try: egg_info_dir = pluginlib.egg_info_dir(output_dir, dist_name) except IOError: egg_info_dir = None if egg_info_dir is not None: plugins_path = os.path.join(egg_info_dir, 'paster_plugins.txt') if os.path.exists(plugins_path): paster_plugins_mtime = os.path.getmtime(plugins_path) self.run_command( sys.executable, 'setup.py', 'egg_info', cwd=output_dir, # This shouldn't be necessary, but a bug in setuptools 0.6c3 is causing a (not entirely fatal) problem that I don't want to fix right now: expect_returncode=True) found_setup_py = True elif self.verbose > 1: print 'No setup.py (cannot run egg_info)' package_dir = vars.get('package_dir', None) if package_dir: output_dir = os.path.join(output_dir, package_dir) # With no setup.py this doesn't make sense: if found_setup_py: # Only write paster_plugins.txt if it wasn't written by # egg_info (the correct way). leaving us to do it is # deprecated and you'll get warned egg_info_dir = pluginlib.egg_info_dir(output_dir, dist_name) plugins_path = os.path.join(egg_info_dir, 'paster_plugins.txt') if len(egg_plugins) and (not os.path.exists(plugins_path) or \ os.path.getmtime(plugins_path) == paster_plugins_mtime): if self.verbose: print >> sys.stderr, \ ('Manually creating paster_plugins.txt (deprecated! ' 'pass a paster_plugins keyword to setup() instead)') for plugin in egg_plugins: if self.verbose: print 'Adding %s to paster_plugins.txt' % plugin if not self.simulate: pluginlib.add_plugin(egg_info_dir, plugin) if self.options.svn_repository: self.add_svn_repository(vars, output_dir) if self.options.config: write_vars = vars.copy() del write_vars['project'] del write_vars['package'] self.write_vars(self.options.config, write_vars)
def command(self): vars = {} app_spec = self.args[0] url = self.args[1] url = urlparse.urljoin('/.command/', url) if self.options.config_vars: for item in self.option.config_vars: if ':' not in item: raise BadCommand( "Bad option, should be name:value : --config-var=%s" % item) name, value = item.split(':', 1) vars[name] = value headers = {} if self.options.headers: for item in self.options.headers: if ':' not in item: raise BadCommand( "Bad option, should be name:value : --header=%s" % item) name, value = item.split(':', 1) headers[name] = value.strip() if not self._scheme_re.search(app_spec): app_spec = 'config:' + app_spec if self.options.app_name: if '#' in app_spec: app_spec = app_spec.split('#', 1)[0] app_spec = app_spec + '#' + options.app_name app = loadapp(app_spec, relative_to=os.getcwd(), global_conf=vars) if self.command_name.lower() == 'post': request_method = 'POST' else: request_method = 'GET' qs = [] for item in self.args[2:]: if '=' in item: item = urllib.quote(item.split( '=', 1)[0]) + '=' + urllib.quote(item.split('=', 1)[1]) else: item = urllib.quote(item) qs.append(item) qs = '&'.join(qs) environ = { 'REQUEST_METHOD': request_method, ## FIXME: shouldn't be static (an option?): 'CONTENT_TYPE': 'text/plain', 'wsgi.run_once': True, 'wsgi.multithread': False, 'wsgi.multiprocess': False, 'wsgi.errors': sys.stderr, 'QUERY_STRING': qs, 'HTTP_ACCEPT': 'text/plain;q=1.0, */*;q=0.1', 'paste.command_request': True, } if request_method == 'POST': environ['wsgi.input'] = sys.stdin environ['CONTENT_LENGTH'] = '-1' for name, value in headers.items(): if name.lower() == 'content-type': name = 'CONTENT_TYPE' else: name = 'HTTP_' + name.upper().replace('-', '_') environ[name] = value status, headers, output, errors = raw_interactive(app, url, **environ) assert not errors, "errors should be printed directly to sys.stderr" if self.options.display_headers: for name, value in headers: sys.stdout.write('%s: %s\n' % (name, value)) sys.stdout.write('\n') sys.stdout.write(output) sys.stdout.flush() status_int = int(status.split()[0]) if status_int != 200: return status_int
class ServeCommand(Command): min_args = 0 usage = 'CONFIG_FILE [start|stop|restart|status] [var=value]' takes_config_file = 1 summary = "Serve the described application" description = """\ This command serves a web application that uses a paste.deploy configuration file for the server and application. If start/stop/restart is given, then --daemon is implied, and it will start (normal operation), stop (--stop-daemon), or do both. You can also include variable assignments like 'http_port=8080' and then use %(http_port)s in your config files. """ # used by subclasses that configure apps and servers differently requires_config_file = True parser = Command.standard_parser(quiet=True) parser.add_option('-n', '--app-name', dest='app_name', metavar='NAME', help="Load the named application (default main)") parser.add_option('-s', '--server', dest='server', metavar='SERVER_TYPE', help="Use the named server.") parser.add_option( '--server-name', dest='server_name', metavar='SECTION_NAME', help= "Use the named server as defined in the configuration file (default: main)" ) if hasattr(os, 'fork'): parser.add_option('--daemon', dest="daemon", action="store_true", help="Run in daemon (background) mode") parser.add_option( '--pid-file', dest='pid_file', metavar='FILENAME', help= "Save PID to file (default to paster.pid if running in daemon mode)") parser.add_option( '--log-file', dest='log_file', metavar='LOG_FILE', help="Save output to the given log file (redirects stdout)") parser.add_option('--reload', dest='reload', action='store_true', help="Use auto-restart file monitor") parser.add_option( '--reload-interval', dest='reload_interval', default=1, help= "Seconds between checking files (low number can cause significant CPU usage)" ) parser.add_option('--monitor-restart', dest='monitor_restart', action='store_true', help="Auto-restart server if it dies") parser.add_option( '--status', action='store_true', dest='show_status', help="Show the status of the (presumably daemonized) server") if hasattr(os, 'setuid'): # I don't think these are available on Windows parser.add_option( '--user', dest='set_user', metavar="USERNAME", help="Set the user (usually only possible when run as root)") parser.add_option( '--group', dest='set_group', metavar="GROUP", help="Set the group (usually only possible when run as root)") parser.add_option( '--stop-daemon', dest='stop_daemon', action='store_true', help= 'Stop a daemonized server (given a PID file, or default paster.pid file)' ) if jython: parser.add_option('--disable-jython-reloader', action='store_true', dest='disable_jython_reloader', help="Disable the Jython reloader") _scheme_re = re.compile(r'^[a-z][a-z]+:', re.I) default_verbosity = 1 _reloader_environ_key = 'PYTHON_RELOADER_SHOULD_RUN' _monitor_environ_key = 'PASTE_MONITOR_SHOULD_RUN' possible_subcommands = ('start', 'stop', 'restart', 'status') def command(self): if self.options.stop_daemon: return self.stop_daemon() if not hasattr(self.options, 'set_user'): # Windows case: self.options.set_user = self.options.set_group = None # @@: Is this the right stage to set the user at? self.change_user_group(self.options.set_user, self.options.set_group) if self.requires_config_file: if not self.args: raise BadCommand('You must give a config file') app_spec = self.args[0] if (len(self.args) > 1 and self.args[1] in self.possible_subcommands): cmd = self.args[1] restvars = self.args[2:] else: cmd = None restvars = self.args[1:] else: app_spec = "" if (self.args and self.args[0] in self.possible_subcommands): cmd = self.args[0] restvars = self.args[1:] else: cmd = None restvars = self.args[:] jython_monitor = False if self.options.reload: if jython and not self.options.disable_jython_reloader: # JythonMonitor raises the special SystemRestart # exception that'll cause the Jython interpreter to # reload in the existing Java process (avoiding # subprocess startup time) try: from paste.reloader import JythonMonitor except ImportError: pass else: jython_monitor = JythonMonitor( poll_interval=int(self.options.reload_interval)) if self.requires_config_file: jython_monitor.watch_file(self.args[0]) if not jython_monitor: if os.environ.get(self._reloader_environ_key): from paste import reloader if self.verbose > 1: print 'Running reloading file monitor' reloader.install(int(self.options.reload_interval)) if self.requires_config_file: reloader.watch_file(self.args[0]) else: return self.restart_with_reloader() if cmd not in (None, 'start', 'stop', 'restart', 'status'): raise BadCommand('Error: must give start|stop|restart (not %s)' % cmd) if cmd == 'status' or self.options.show_status: return self.show_status() if cmd == 'restart' or cmd == 'stop': result = self.stop_daemon() if result: if cmd == 'restart': print "Could not stop daemon; aborting" else: print "Could not stop daemon" return result if cmd == 'stop': return result app_name = self.options.app_name vars = self.parse_vars(restvars) if not self._scheme_re.search(app_spec): app_spec = 'config:' + app_spec server_name = self.options.server_name if self.options.server: server_spec = 'egg:PasteScript' assert server_name is None server_name = self.options.server else: server_spec = app_spec base = os.getcwd() if getattr(self.options, 'daemon', False): if not self.options.pid_file: self.options.pid_file = 'paster.pid' if not self.options.log_file: self.options.log_file = 'paster.log' # Ensure the log file is writeable if self.options.log_file: try: writeable_log_file = open(self.options.log_file, 'a') except IOError, ioe: msg = 'Error: Unable to write to log file: %s' % ioe raise BadCommand(msg) writeable_log_file.close() # Ensure the pid file is writeable if self.options.pid_file: try: writeable_pid_file = open(self.options.pid_file, 'a') except IOError, ioe: msg = 'Error: Unable to write to pid file: %s' % ioe raise BadCommand(msg) writeable_pid_file.close()
def command(self): if self.options.stop_daemon: return self.stop_daemon() if not hasattr(self.options, 'set_user'): # Windows case: self.options.set_user = self.options.set_group = None # @@: Is this the right stage to set the user at? self.change_user_group(self.options.set_user, self.options.set_group) if self.requires_config_file: if not self.args: raise BadCommand('You must give a config file') app_spec = self.args[0] if (len(self.args) > 1 and self.args[1] in self.possible_subcommands): cmd = self.args[1] restvars = self.args[2:] else: cmd = None restvars = self.args[1:] else: app_spec = "" if (self.args and self.args[0] in self.possible_subcommands): cmd = self.args[0] restvars = self.args[1:] else: cmd = None restvars = self.args[:] jython_monitor = False if self.options.reload: if jython and not self.options.disable_jython_reloader: # JythonMonitor raises the special SystemRestart # exception that'll cause the Jython interpreter to # reload in the existing Java process (avoiding # subprocess startup time) try: from paste.reloader import JythonMonitor except ImportError: pass else: jython_monitor = JythonMonitor( poll_interval=int(self.options.reload_interval)) if self.requires_config_file: jython_monitor.watch_file(self.args[0]) if not jython_monitor: if os.environ.get(self._reloader_environ_key): from paste import reloader if self.verbose > 1: print 'Running reloading file monitor' reloader.install(int(self.options.reload_interval)) if self.requires_config_file: reloader.watch_file(self.args[0]) else: return self.restart_with_reloader() if cmd not in (None, 'start', 'stop', 'restart', 'status'): raise BadCommand('Error: must give start|stop|restart (not %s)' % cmd) if cmd == 'status' or self.options.show_status: return self.show_status() if cmd == 'restart' or cmd == 'stop': result = self.stop_daemon() if result: if cmd == 'restart': print "Could not stop daemon; aborting" else: print "Could not stop daemon" return result if cmd == 'stop': return result app_name = self.options.app_name vars = self.parse_vars(restvars) if not self._scheme_re.search(app_spec): app_spec = 'config:' + app_spec server_name = self.options.server_name if self.options.server: server_spec = 'egg:PasteScript' assert server_name is None server_name = self.options.server else: server_spec = app_spec base = os.getcwd() if getattr(self.options, 'daemon', False): if not self.options.pid_file: self.options.pid_file = 'paster.pid' if not self.options.log_file: self.options.log_file = 'paster.log' # Ensure the log file is writeable if self.options.log_file: try: writeable_log_file = open(self.options.log_file, 'a') except IOError, ioe: msg = 'Error: Unable to write to log file: %s' % ioe raise BadCommand(msg) writeable_log_file.close()