From 201b1e5e9f59bdaa3b8e6de685d28f23dd17d5e1 Mon Sep 17 00:00:00 2001 From: mvdbeek Date: Thu, 1 Apr 2021 19:07:48 +0200 Subject: [PATCH] Drop scripts/paster.py and pastescript --- lib/galaxy/util/pastescript/__init__.py | 3 - lib/galaxy/util/pastescript/loadwsgi.py | 772 ----------------- lib/galaxy/util/pastescript/serve.py | 1056 ----------------------- rolling_restart.sh | 5 - scripts/paster.py | 22 - test/unit/util/test_fix_type_error.py | 18 - 6 files changed, 1876 deletions(-) delete mode 100644 lib/galaxy/util/pastescript/__init__.py delete mode 100644 lib/galaxy/util/pastescript/loadwsgi.py delete mode 100644 lib/galaxy/util/pastescript/serve.py delete mode 100755 rolling_restart.sh delete mode 100755 scripts/paster.py delete mode 100644 test/unit/util/test_fix_type_error.py diff --git a/lib/galaxy/util/pastescript/__init__.py b/lib/galaxy/util/pastescript/__init__.py deleted file mode 100644 index 45db1d62d60..00000000000 --- a/lib/galaxy/util/pastescript/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -""" -Command for loading and serving wsgi apps taken from PasteScript -""" diff --git a/lib/galaxy/util/pastescript/loadwsgi.py b/lib/galaxy/util/pastescript/loadwsgi.py deleted file mode 100644 index f7a7226864c..00000000000 --- a/lib/galaxy/util/pastescript/loadwsgi.py +++ /dev/null @@ -1,772 +0,0 @@ -# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org) -# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php - -# Mostly taken from PasteDeploy and stripped down for Galaxy - -import inspect -import os -import re -import sys -from typing import Callable, Dict, List, Optional, Union -from urllib.parse import unquote - -import pkg_resources - -from galaxy.util.getargspec import getfullargspec -from galaxy.util.properties import NicerConfigParser - - -__all__ = ('loadapp', 'loadserver', 'loadfilter', 'appconfig') - -# ---- from paste.deploy.compat -------------------------------------- - -"""Python 2<->3 compatibility module""" - - -def print_(template, *args, **kwargs): - template = str(template) - if args: - template = template % args - elif kwargs: - template = template % kwargs - sys.stdout.writelines(template) - - -def reraise(t, e, tb): - exec('raise e from tb', dict(e=e, tb=tb)) - -# ---- from paste.deploy.util ---------------------------------------- - - -def fix_type_error(exc_info, callable, varargs, kwargs): - """ - Given an exception, this will test if the exception was due to a - signature error, and annotate the error with better information if - so. - - Usage:: - - try: - val = callable(*args, **kw) - except TypeError: - exc_info = fix_type_error(None, callable, args, kw) - raise exc_info[0], exc_info[1], exc_info[2] - """ - if exc_info is None: - exc_info = sys.exc_info() - if (exc_info[0] != TypeError - or str(exc_info[1]).find('argument') == -1 - or getattr(exc_info[1], '_type_error_fixed', False)): - return exc_info - exc_info[1]._type_error_fixed = True - argspec = inspect.formatargspec(*getfullargspec(callable)) - args = ', '.join(map(_short_repr, varargs)) - if kwargs and args: - args += ', ' - if kwargs: - kwargs = sorted(kwargs.keys()) - args += ', '.join('%s=...' % n for n in kwargs) - gotspec = '(%s)' % args - msg = '{}; got {}, wanted {}'.format(exc_info[1], gotspec, argspec) - exc_info[1].args = (msg,) - return exc_info - - -def _short_repr(v): - v = repr(v) - if len(v) > 12: - v = v[:8] + '...' + v[-4:] - return v - - -def fix_call(callable, *args, **kw): - """ - Call ``callable(*args, **kw)`` fixing any type errors that come out. - """ - try: - val = callable(*args, **kw) - except TypeError: - exc_info = fix_type_error(None, callable, args, kw) - reraise(*exc_info) - return val - - -def lookup_object(spec): - """ - Looks up a module or object from a some.module:func_name specification. - To just look up a module, omit the colon and everything after it. - """ - parts, target = spec.split(':') if ':' in spec else (spec, None) - module = __import__(parts) - - for part in parts.split('.')[1:] + ([target] if target else []): - module = getattr(module, part) - - return module - -# ---- from paste.deploy.loadwsgi ------------------------------------ - -############################################################ -# Utility functions -############################################################ - - -def import_string(s): - return pkg_resources.EntryPoint.parse("x=" + s).load(False) - - -def _aslist(obj): - """ - Turn object into a list; lists and tuples are left as-is, None - becomes [], and everything else turns into a one-element list. - """ - if obj is None: - return [] - elif isinstance(obj, (list, tuple)): - return obj - else: - return [obj] - - -def _flatten(lst): - """ - Flatten a nested list. - """ - if not isinstance(lst, (list, tuple)): - return [lst] - result = [] - for item in lst: - result.extend(_flatten(item)) - return result - - -############################################################ -# Object types -############################################################ - - -class _ObjectType: - - name: Optional[str] = None - egg_protocols: Optional[List[Union[str, List[str]]]] = None - config_prefixes: Optional[List[Union[List[str], str]]] = None - - def __init__(self): - # Normalize these variables: - self.egg_protocols = [_aslist(p) for p in _aslist(self.egg_protocols)] - self.config_prefixes = [_aslist(p) for p in _aslist(self.config_prefixes)] - - def __repr__(self): - return '<{} protocols={!r} prefixes={!r}>'.format( - self.name, self.egg_protocols, self.config_prefixes) - - def invoke(self, context): - assert context.protocol in _flatten(self.egg_protocols) - return fix_call(context.object, - context.global_conf, **context.local_conf) - - -class _App(_ObjectType): - - name = 'application' - egg_protocols = ['paste.app_factory', 'paste.composite_factory', - 'paste.composit_factory'] - config_prefixes = [['app', 'application'], ['composite', 'composit'], - 'pipeline', 'filter-app'] - - def invoke(self, context): - if context.protocol in ('paste.composit_factory', - 'paste.composite_factory'): - return fix_call(context.object, - context.loader, context.global_conf, - **context.local_conf) - elif context.protocol == 'paste.app_factory': - return fix_call(context.object, context.global_conf, **context.local_conf) - else: - assert 0, "Protocol %r unknown" % context.protocol - - -APP = _App() - - -class _Filter(_ObjectType): - name = 'filter' - egg_protocols = [['paste.filter_factory', 'paste.filter_app_factory']] - config_prefixes = ['filter'] - - def invoke(self, context): - if context.protocol == 'paste.filter_factory': - return fix_call(context.object, - context.global_conf, **context.local_conf) - elif context.protocol == 'paste.filter_app_factory': - def filter_wrapper(wsgi_app): - # This should be an object, so it has a nicer __repr__ - return fix_call(context.object, - wsgi_app, context.global_conf, - **context.local_conf) - return filter_wrapper - else: - assert 0, "Protocol %r unknown" % context.protocol - - -FILTER = _Filter() - - -class _Server(_ObjectType): - name = 'server' - egg_protocols = [['paste.server_factory', 'paste.server_runner']] - config_prefixes = ['server'] - - def invoke(self, context): - if context.protocol == 'paste.server_factory': - return fix_call(context.object, - context.global_conf, **context.local_conf) - elif context.protocol == 'paste.server_runner': - def server_wrapper(wsgi_app): - # This should be an object, so it has a nicer __repr__ - return fix_call(context.object, - wsgi_app, context.global_conf, - **context.local_conf) - return server_wrapper - else: - assert 0, "Protocol %r unknown" % context.protocol - - -SERVER = _Server() - - -# Virtual type: (@@: There's clearly something crufty here; -# this probably could be more elegant) -class _PipeLine(_ObjectType): - name = 'pipeline' - - def invoke(self, context): - app = context.app_context.create() - filters = [c.create() for c in context.filter_contexts] - filters.reverse() - for filter_ in filters: - app = filter_(app) - return app - - -PIPELINE = _PipeLine() - - -class _FilterApp(_ObjectType): - name = 'filter_app' - - def invoke(self, context): - next_app = context.next_context.create() - filter_ = context.filter_context.create() - return filter_(next_app) - - -FILTER_APP = _FilterApp() - - -class _FilterWith(_App): - name = 'filtered_with' - - def invoke(self, context): - filter_ = context.filter_context.create() - filtered = context.next_context.create() - if context.next_context.object_type is APP: - return filter_(filtered) - else: - # filtering a filter - def composed(app): - return filter_(filtered(app)) - return composed - - -FILTER_WITH = _FilterWith() - -############################################################ -# Loaders -############################################################ - - -def loadapp(uri, name=None, **kw): - return loadobj(APP, uri, name=name, **kw) - - -def loadfilter(uri, name=None, **kw): - return loadobj(FILTER, uri, name=name, **kw) - - -def loadserver(uri, name=None, **kw): - return loadobj(SERVER, uri, name=name, **kw) - - -def appconfig(uri, name=None, relative_to=None, global_conf=None): - context = loadcontext(APP, uri, name=name, - relative_to=relative_to, - global_conf=global_conf) - return context.config() - - -_loaders: Dict[str, Callable] = {} - - -def loadobj(object_type, uri, name=None, relative_to=None, - global_conf=None): - context = loadcontext( - object_type, uri, name=name, relative_to=relative_to, - global_conf=global_conf) - return context.create() - - -def loadcontext(object_type, uri, name=None, relative_to=None, - global_conf=None): - if '#' in uri: - if name is None: - uri, name = uri.split('#', 1) - else: - # @@: Ignore fragment or error? - uri = uri.split('#', 1)[0] - if name is None: - name = 'main' - if ':' not in uri: - raise LookupError("URI has no scheme: %r" % uri) - scheme, path = uri.split(':', 1) - scheme = scheme.lower() - if scheme not in _loaders: - raise LookupError( - "URI scheme not known: %r (from %s)" - % (scheme, ', '.join(_loaders.keys()))) - return _loaders[scheme]( - object_type, - uri, path, name=name, relative_to=relative_to, - global_conf=global_conf) - - -def _loadconfig(object_type, uri, path, name, relative_to, - global_conf): - isabs = os.path.isabs(path) - # De-Windowsify the paths: - path = path.replace('\\', '/') - if not isabs: - if not relative_to: - raise ValueError( - "Cannot resolve relative uri %r; no relative_to keyword " - "argument given" % uri) - relative_to = relative_to.replace('\\', '/') - if relative_to.endswith('/'): - path = relative_to + path - else: - path = relative_to + '/' + path - if path.startswith('///'): - path = path[2:] - path = unquote(path) - loader = ConfigLoader(path) - if global_conf: - loader.update_defaults(global_conf, overwrite=False) - return loader.get_context(object_type, name, global_conf) - - -_loaders['config'] = _loadconfig - - -def _loadegg(object_type, uri, spec, name, relative_to, - global_conf): - loader = EggLoader(spec) - return loader.get_context(object_type, name, global_conf) - - -_loaders['egg'] = _loadegg - - -def _loadfunc(object_type, uri, spec, name, relative_to, - global_conf): - - loader = FuncLoader(spec) - return loader.get_context(object_type, name, global_conf) - - -_loaders['call'] = _loadfunc - -############################################################ -# Loaders -############################################################ - - -class _Loader: - - def get_app(self, name=None, global_conf=None): - return self.app_context( - name=name, global_conf=global_conf).create() - - def get_filter(self, name=None, global_conf=None): - return self.filter_context( - name=name, global_conf=global_conf).create() - - def get_server(self, name=None, global_conf=None): - return self.server_context( - name=name, global_conf=global_conf).create() - - def app_context(self, name=None, global_conf=None): - return self.get_context( - APP, name=name, global_conf=global_conf) - - def filter_context(self, name=None, global_conf=None): - return self.get_context( - FILTER, name=name, global_conf=global_conf) - - def server_context(self, name=None, global_conf=None): - return self.get_context( - SERVER, name=name, global_conf=global_conf) - - _absolute_re = re.compile(r'^[a-zA-Z]+:') - - def absolute_name(self, name): - """ - Returns true if the name includes a scheme - """ - if name is None: - return False - return self._absolute_re.search(name) - - -class ConfigLoader(_Loader): - - def __init__(self, filename): - self.filename = filename = filename.strip() - defaults = { - 'here': os.path.dirname(os.path.abspath(filename)), - '__file__': os.path.abspath(filename) - } - self.parser = NicerConfigParser(filename, defaults=defaults) - self.parser.optionxform = str # Don't lower-case keys - with open(filename) as f: - self.parser.read_file(f) - - def update_defaults(self, new_defaults, overwrite=True): - for key, value in new_defaults.items(): - if not overwrite and key in self.parser._defaults: - continue - self.parser._defaults[key] = value - - def get_context(self, object_type, name=None, global_conf=None): - if self.absolute_name(name): - return loadcontext(object_type, name, - relative_to=os.path.dirname(self.filename), - global_conf=global_conf) - section = self.find_config_section( - object_type, name=name) - if global_conf is None: - global_conf = {} - else: - global_conf = global_conf.copy() - defaults = self.parser.defaults() - global_conf.update(defaults) - local_conf = {} - global_additions = {} - get_from_globals = {} - for option in self.parser.options(section): - if option.startswith('set '): - name = option[4:].strip() - global_additions[name] = global_conf[name] = ( - self.parser.get(section, option)) - elif option.startswith('get '): - name = option[4:].strip() - get_from_globals[name] = self.parser.get(section, option) - else: - if option in defaults: - # @@: It's a global option (?), so skip it - continue - local_conf[option] = self.parser.get(section, option) - for local_var, glob_var in get_from_globals.items(): - local_conf[local_var] = global_conf[glob_var] - if object_type in (APP, FILTER) and 'filter-with' in local_conf: - filter_with = local_conf.pop('filter-with') - else: - filter_with = None - if 'require' in local_conf: - for spec in local_conf['require'].split(): - pkg_resources.require(spec) - del local_conf['require'] - if section.startswith('filter-app:'): - context = self._filter_app_context( - object_type, section, name=name, - global_conf=global_conf, local_conf=local_conf, - global_additions=global_additions) - elif section.startswith('pipeline:'): - context = self._pipeline_app_context( - object_type, section, name=name, - global_conf=global_conf, local_conf=local_conf, - global_additions=global_additions) - elif 'use' in local_conf: - context = self._context_from_use( - object_type, local_conf, global_conf, global_additions, - section) - else: - context = self._context_from_explicit( - object_type, local_conf, global_conf, global_additions, - section) - if filter_with is not None: - filter_with_context = LoaderContext( - obj=None, - object_type=FILTER_WITH, - protocol=None, - global_conf=global_conf, local_conf=local_conf, - loader=self) - filter_with_context.filter_context = self.filter_context( - name=filter_with, global_conf=global_conf) - filter_with_context.next_context = context - return filter_with_context - return context - - def _context_from_use(self, object_type, local_conf, global_conf, - global_additions, section): - use = local_conf.pop('use') - context = self.get_context( - object_type, name=use, global_conf=global_conf) - context.global_conf.update(global_additions) - context.local_conf.update(local_conf) - if '__file__' in global_conf: - # use sections shouldn't overwrite the original __file__ - context.global_conf['__file__'] = global_conf['__file__'] - # @@: Should loader be overwritten? - context.loader = self - - if context.protocol is None: - # Determine protocol from section type - section_protocol = section.split(':', 1)[0] - if section_protocol in ('application', 'app'): - context.protocol = 'paste.app_factory' - elif section_protocol in ('composit', 'composite'): - context.protocol = 'paste.composit_factory' - else: - # This will work with 'server' and 'filter', otherwise it - # could fail but there is an error message already for - # bad protocols - context.protocol = 'paste.%s_factory' % section_protocol - - return context - - def _context_from_explicit(self, object_type, local_conf, global_conf, - global_addition, section): - possible = [] - for protocol_options in object_type.egg_protocols: - for protocol in protocol_options: - if protocol in local_conf: - possible.append((protocol, local_conf[protocol])) - break - if len(possible) > 1: - raise LookupError( - "Multiple protocols given in section %r: %s" - % (section, possible)) - if not possible: - raise LookupError( - "No loader given in section %r" % section) - found_protocol, found_expr = possible[0] - del local_conf[found_protocol] - value = import_string(found_expr) - context = LoaderContext( - value, object_type, found_protocol, - global_conf, local_conf, self) - return context - - def _filter_app_context(self, object_type, section, name, - global_conf, local_conf, global_additions): - if 'next' not in local_conf: - raise LookupError( - "The [%s] section in %s is missing a 'next' setting" - % (section, self.filename)) - next_name = local_conf.pop('next') - context = LoaderContext(None, FILTER_APP, None, global_conf, - local_conf, self) - context.next_context = self.get_context( - APP, next_name, global_conf) - if 'use' in local_conf: - context.filter_context = self._context_from_use( - FILTER, local_conf, global_conf, global_additions, - section) - else: - context.filter_context = self._context_from_explicit( - FILTER, local_conf, global_conf, global_additions, - section) - return context - - def _pipeline_app_context(self, object_type, section, name, - global_conf, local_conf, global_additions): - if 'pipeline' not in local_conf: - raise LookupError( - "The [%s] section in %s is missing a 'pipeline' setting" - % (section, self.filename)) - pipeline = local_conf.pop('pipeline').split() - if local_conf: - raise LookupError( - "The [%s] pipeline section in %s has extra " - "(disallowed) settings: %s" - % (', '.join(local_conf.keys()))) - context = LoaderContext(None, PIPELINE, None, global_conf, - local_conf, self) - context.app_context = self.get_context( - APP, pipeline[-1], global_conf) - context.filter_contexts = [ - self.get_context(FILTER, pname, global_conf) - for pname in pipeline[:-1]] - return context - - def find_config_section(self, object_type, name=None): - """ - Return the section name with the given name prefix (following the - same pattern as ``protocol_desc`` in ``config``. It must have the - given name, or for ``'main'`` an empty name is allowed. The - prefix must be followed by a ``:``. - - Case is *not* ignored. - """ - possible = [] - for name_options in object_type.config_prefixes: - for name_prefix in name_options: - found = self._find_sections( - self.parser.sections(), name_prefix, name) - if found: - possible.extend(found) - break - if not possible: - raise LookupError( - "No section %r (prefixed by %s) found in config %s" - % (name, - ' or '.join(map(repr, _flatten(object_type.config_prefixes))), - self.filename)) - if len(possible) > 1: - raise LookupError( - "Ambiguous section names %r for section %r (prefixed by %s) " - "found in config %s" - % (possible, name, - ' or '.join(map(repr, _flatten(object_type.config_prefixes))), - self.filename)) - return possible[0] - - def _find_sections(self, sections, name_prefix, name): - found = [] - if name is None: - if name_prefix in sections: - found.append(name_prefix) - name = 'main' - for section in sections: - if section.startswith(name_prefix + ':'): - if section[len(name_prefix) + 1:].strip() == name: - found.append(section) - return found - - -class EggLoader(_Loader): - - def __init__(self, spec): - self.spec = spec - - def get_context(self, object_type, name=None, global_conf=None): - if self.absolute_name(name): - return loadcontext(object_type, name, - global_conf=global_conf) - entry_point, protocol, ep_name = self.find_egg_entry_point( - object_type, name=name) - return LoaderContext( - entry_point, - object_type, - protocol, - global_conf or {}, {}, - self, - distribution=pkg_resources.get_distribution(self.spec), - entry_point_name=ep_name) - - def find_egg_entry_point(self, object_type, name=None): - """ - Returns the (entry_point, protocol) for the with the given - ``name``. - """ - if name is None: - name = 'main' - possible = [] - for protocol_options in object_type.egg_protocols: - for protocol in protocol_options: - pkg_resources.require(self.spec) - entry = pkg_resources.get_entry_info( - self.spec, - protocol, - name) - if entry is not None: - possible.append((entry.load(), protocol, entry.name)) - break - if not possible: - # Better exception - dist = pkg_resources.get_distribution(self.spec) - raise LookupError( - "Entry point %r not found in egg %r (dir: %s; protocols: %s; " - "entry_points: %s)" - % (name, self.spec, - dist.location, - ', '.join(_flatten(object_type.egg_protocols)), - ', '.join(_flatten([ - list((pkg_resources.get_entry_info(self.spec, prot, name) or {}).keys()) - for prot in protocol_options] or '(no entry points)')))) - if len(possible) > 1: - raise LookupError( - "Ambiguous entry points for %r in egg %r (protocols: %s)" - % (name, self.spec, ', '.join(_flatten(protocol_options)))) - return possible[0] - - -class FuncLoader(_Loader): - """ Loader that supports specifying functions inside modules, without - using eggs at all. Configuration should be in the format: - use = call:my.module.path:function_name - - Dot notation is supported in both the module and function name, e.g.: - use = call:my.module.path:object.method - """ - - def __init__(self, spec): - self.spec = spec - if ':' not in spec: - raise LookupError("Configuration not in format module:function") - - def get_context(self, object_type, name=None, global_conf=None): - obj = lookup_object(self.spec) - return LoaderContext( - obj, - object_type, - None, # determine protocol from section type - global_conf or {}, - {}, - self, - ) - - -class LoaderContext: - - def __init__(self, obj, object_type, protocol, - global_conf, local_conf, loader, - distribution=None, entry_point_name=None): - self.object = obj - self.object_type = object_type - self.protocol = protocol - # assert protocol in _flatten(object_type.egg_protocols), ( - # "Bad protocol %r; should be one of %s" - # % (protocol, ', '.join(map(repr, _flatten(object_type.egg_protocols))))) - self.global_conf = global_conf - self.local_conf = local_conf - self.loader = loader - self.distribution = distribution - self.entry_point_name = entry_point_name - - def create(self): - return self.object_type.invoke(self) - - def config(self): - conf = AttrDict(self.global_conf) - conf.update(self.local_conf) - conf.local_conf = self.local_conf - conf.global_conf = self.global_conf - conf.context = self - return conf - - -class AttrDict(dict): - """ - A dictionary that can be assigned to. - """ diff --git a/lib/galaxy/util/pastescript/serve.py b/lib/galaxy/util/pastescript/serve.py deleted file mode 100644 index a30fca3f032..00000000000 --- a/lib/galaxy/util/pastescript/serve.py +++ /dev/null @@ -1,1056 +0,0 @@ -# Most of this code is: - -# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org) -# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php - -# The server command includes the additional header: - -# For discussion of daemonizing: -# http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/278731 -# Code taken also from QP: -# http://www.mems-exchange.org/software/qp/ -# From lib/site.py - -# Galaxy originally used PasteScript and PasteDeploy for application -# loading, to maintain compatibility we've internalized some of that -# code here, stripping out uneeded functionality. - -# All top level imports from each package moved here and organized - -import atexit -import configparser -import errno -import grp -import logging -import optparse -import os -import pwd -import re -import resource -import signal -import socket -import subprocess -import sys -import textwrap -import threading -import time -from gettext import gettext as _ -from logging.config import fileConfig -from typing import Optional - -from .loadwsgi import loadapp, loadserver - - -difflib = None - -# ---- from paste.script.bool_optparse -------------------------------- - -""" -A subclass of ``optparse.OptionParser`` that allows boolean long -options (like ``--verbose``) to also take arguments (like -``--verbose=true``). Arguments *must* use ``=``. -""" - - -class BoolOptionParser(optparse.OptionParser): - - def _process_long_opt(self, rargs, values): - arg = rargs.pop(0) - - # Value explicitly attached to arg? Pretend it's the next - # argument. - if "=" in arg: - (opt, next_arg) = arg.split("=", 1) - rargs.insert(0, next_arg) - had_explicit_value = True - else: - opt = arg - had_explicit_value = False - - opt = self._match_long_opt(opt) - option = self._long_opt[opt] - if option.takes_value(): - nargs = option.nargs - if len(rargs) < nargs: - if nargs == 1: - self.error(_("%s option requires an argument") % opt) - else: - self.error(_("%s option requires %d arguments") - % (opt, nargs)) - elif nargs == 1: - value = rargs.pop(0) - else: - value = tuple(rargs[0:nargs]) - del rargs[0:nargs] - - elif had_explicit_value: - value = rargs[0].lower().strip() - del rargs[0:1] - if value in ('true', 'yes', 'on', '1', 'y', 't'): - value = None - elif value in ('false', 'no', 'off', '0', 'n', 'f'): - # Don't process - return - else: - self.error(_('%s option takes a boolean value only (true/false)') % opt) - - else: - value = None - - option.process(opt, value, values, self) - -# ---- from paste.script.command -------------------------------------- - -# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org) -# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php - - -class BadCommand(Exception): - - def __init__(self, message, exit_code=2): - self.message = message - self.exit_code = exit_code - Exception.__init__(self, message) - - def _get_message(self): - """Getter for 'message'; needed only to override deprecation - in BaseException.""" - return self.__message - - def _set_message(self, value): - """Setter for 'message'; needed only to override deprecation - in BaseException.""" - self.__message = value - - # BaseException.message has been deprecated since Python 2.6. - # To prevent DeprecationWarning from popping up over this - # pre-existing attribute, use a new property that takes lookup - # precedence. - message = property(_get_message, _set_message) - - -class NoDefault: - pass - - -# run and invoke methods moved below ServeCommand -class Command: - - def __init__(self, name): - self.command_name = name - - max_args = None - max_args_error = 'You must provide no more than %(max_args)s arguments' - min_args: Optional[int] = None - min_args_error = 'You must provide at least %(min_args)s arguments' - required_args = None - # If this command takes a configuration file, set this to 1 or -1 - # Then if invoked through #! the config file will be put into the positional - # arguments -- at the beginning with 1, at the end with -1 - takes_config_file: Optional[int] = None - - # Grouped in help messages by this: - group_name = '' - - required_args = () - description: Optional[str] = None - usage = '' - hidden = False - # This is the default verbosity level; --quiet subtracts, - # --verbose adds: - default_verbosity = 0 - # This is the default interactive state: - default_interactive = 0 - return_code = 0 - - BadCommand = BadCommand - - # Must define: - # parser - # summary - # command() - - def run(self, args): - self.parse_args(args) - - # Setup defaults: - for name, default in [('verbose', 0), - ('quiet', 0), - ('interactive', False), - ('overwrite', False)]: - if not hasattr(self.options, name): - setattr(self.options, name, default) - if getattr(self.options, 'simulate', False): - self.options.verbose = max(self.options.verbose, 1) - self.interactive = self.default_interactive - if getattr(self.options, 'interactive', False): - self.interactive += self.options.interactive - if getattr(self.options, 'no_interactive', False): - self.interactive = False - self.verbose = self.default_verbosity - self.verbose += self.options.verbose - self.verbose -= self.options.quiet - self.simulate = getattr(self.options, 'simulate', False) - - # For #! situations: - if os.environ.get('PASTE_CONFIG_FILE') and self.takes_config_file is not None: - take = self.takes_config_file - filename = os.environ.get('PASTE_CONFIG_FILE') - if take == 1: - self.args.insert(0, filename) - elif take == -1: - self.args.append(filename) - else: - assert 0, ( - "Value takes_config_file must be None, 1, or -1 (not %r)" - % take) - - if os.environ.get('PASTE_DEFAULT_QUIET'): - self.verbose = 0 - - # Validate: - if self.min_args is not None and len(self.args) < self.min_args: - raise BadCommand( - self.min_args_error % {'min_args': self.min_args, - 'actual_args': len(self.args)}) - if self.max_args is not None and len(self.args) > self.max_args: - raise BadCommand( - self.max_args_error % {'max_args': self.max_args, - 'actual_args': len(self.args)}) - for var_name, option_name in self.required_args: - if not getattr(self.options, var_name, None): - raise BadCommand( - 'You must provide the option %s' % option_name) - result = self.command() - if result is None: - return self.return_code - else: - return result - - def parse_args(self, args): - if self.usage: - usage = ' ' + self.usage - else: - usage = '' - self.parser.usage = "%prog [options]{}\n{}".format( - usage, self.summary) - self.parser.prog = self._prog_name() - if self.description: - desc = self.description - desc = textwrap.dedent(desc) - self.parser.description = desc - self.options, self.args = self.parser.parse_args(args) - - def _prog_name(self): - return '{} {}'.format(os.path.basename(sys.argv[0]), self.command_name) - - ######################################## - # Utility methods - ######################################## - - def pad(self, s, length, dir='left'): - if len(s) >= length: - return s - if dir == 'left': - return s + ' ' * (length - len(s)) - else: - return ' ' * (length - len(s)) + s - - def _standard_parser(cls, verbose=True, - interactive=False, - no_interactive=False, - simulate=False, - quiet=False, - overwrite=False): - """ - Create a standard ``OptionParser`` instance. - - Typically used like:: - - class MyCommand(Command): - parser = Command.standard_parser() - - Subclasses may redefine ``standard_parser``, so use the - nearest superclass's class method. - """ - parser = BoolOptionParser() - if verbose: - parser.add_option('-v', '--verbose', - action='count', - dest='verbose', - default=0) - if quiet: - parser.add_option('-q', '--quiet', - action='count', - dest='quiet', - default=0) - if no_interactive: - parser.add_option('--no-interactive', - action="count", - dest="no_interactive", - default=0) - if interactive: - parser.add_option('-i', '--interactive', - action='count', - dest='interactive', - default=0) - if simulate: - parser.add_option('-n', '--simulate', - action='store_true', - dest='simulate', - default=False) - if overwrite: - parser.add_option('-f', '--overwrite', - dest="overwrite", - action="store_true", - help="Overwrite files (warnings will be emitted for non-matching files otherwise)") - return parser - - standard_parser = classmethod(_standard_parser) - - def quote_first_command_arg(self, arg): - """ - There's a bug in Windows when running an executable that's - located inside a path with a space in it. This method handles - that case, or on non-Windows systems or an executable with no - spaces, it just leaves well enough alone. - """ - if sys.platform != 'win32' or ' ' not in arg: - # Problem does not apply: - return arg - try: - import win32api - except ImportError: - raise ValueError( - "The executable %r contains a space, and in order to " - "handle this issue you must have the win32api module " - "installed" % arg) - arg = win32api.GetShortPathName(arg) - return arg - - def parse_vars(self, args): - """ - Given variables like ``['a=b', 'c=d']`` turns it into ``{'a': - 'b', 'c': 'd'}`` - """ - result = {} - for arg in args: - if '=' not in arg: - raise BadCommand( - 'Variable assignment %r invalid (no "=")' - % arg) - name, value = arg.split('=', 1) - result[name] = value - return result - - def logging_file_config(self, config_file): - """ - Setup logging via the logging module's fileConfig function with the - specified ``config_file``, if applicable. - - ConfigParser defaults are specified for the special ``__file__`` - and ``here`` variables, similar to PasteDeploy config loading. - """ - parser = configparser.ConfigParser() - parser.read([config_file]) - if parser.has_section('loggers'): - config_file = os.path.abspath(config_file) - fileConfig(config_file, dict(__file__=config_file, - here=os.path.dirname(config_file))) - - -class NotFoundCommand(Command): - - def run(self, args): - print('Command %r not known (you may need to run setup.py egg_info)' - % self.command_name) - commands = list() - commands.sort() - if not commands: - print('No commands registered.') - print('Have you installed Paste Script?') - print('(try running python setup.py develop)') - return 2 - print('Known commands:') - longest = max([len(n) for n, c in commands]) - for name, command in commands: - print(' {} {}'.format(self.pad(name, length=longest), - command.load().summary)) - return 2 - - -# ---- From paste.script.serve ---------------------------------------- - -MAXFD = 1024 - -jython = sys.platform.startswith('java') - - -class DaemonizeException(Exception): - pass - - -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: Optional[str] = """\ - 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[:] - - if (getattr(self.options, 'daemon', False) - and getattr(self.options, 'reload', False)): - raise BadCommand('The --daemon and --reload options may not be used together') - - 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: - print("Could not stop daemon") - # It's ok to continue trying to restart if stop_daemon returns - # a 1, otherwise shortcut and return. - if cmd == 'restart' and result != 1: - return result - if cmd == 'stop': - return result - self.options.daemon = True - - if cmd == 'start': - self.options.daemon = True - - 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 OSError as 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 OSError as ioe: - msg = 'Error: Unable to write to pid file: %s' % ioe - raise BadCommand(msg) - writeable_pid_file.close() - - if getattr(self.options, 'daemon', False): - try: - self.daemonize() - except DaemonizeException as ex: - if self.verbose > 0: - print(str(ex)) - return - - if (self.options.monitor_restart and not - os.environ.get(self._monitor_environ_key)): - return self.restart_with_monitor() - - if self.options.pid_file: - self.record_pid(self.options.pid_file) - - if self.options.log_file: - stdout_log = LazyWriter(self.options.log_file, 'a') - sys.stdout = stdout_log - sys.stderr = stdout_log - logging.basicConfig(stream=stdout_log) - - log_fn = app_spec - if log_fn.startswith('config:'): - log_fn = app_spec[len('config:'):] - elif log_fn.startswith('egg:'): - log_fn = None - if log_fn: - log_fn = os.path.join(base, log_fn) - self.logging_file_config(log_fn) - - server = loadserver(server_spec, name=server_name, relative_to=base, global_conf=vars) - - app = loadapp(app_spec, name=app_name, relative_to=base, global_conf=vars) - - if self.verbose > 0: - if hasattr(os, 'getpid'): - msg = 'Starting server in PID %i.' % os.getpid() - else: - msg = 'Starting server.' - print(msg) - - def serve(): - try: - server(app) - except (SystemExit, KeyboardInterrupt) as e: - if self.verbose > 1: - raise - if str(e): - msg = ' ' + str(e) - else: - msg = '' - print('Exiting%s (-v to see traceback)' % msg) - except AttributeError as e: - # Capturing bad error response from paste - if str(e) == "'WSGIThreadPoolServer' object has no attribute 'thread_pool'": - raise OSError(98, 'Address already in use') - else: - raise AttributeError(e) - - if jython_monitor: - # JythonMonitor has to be ran from the main thread - threading.Thread(target=serve).start() - print('Starting Jython file monitor') - jython_monitor.periodic_reload() - else: - serve() - - def daemonize(self): - pid = live_pidfile(self.options.pid_file) - if pid: - raise DaemonizeException( - "Daemon is already running (PID: %s from PID file %s)" - % (pid, self.options.pid_file)) - - if self.verbose > 0: - print('Entering daemon mode') - pid = os.fork() - if pid: - # The forked process also has a handle on resources, so we - # *don't* want proper termination of the process, we just - # want to exit quick (which os._exit() does) - os._exit(0) - # Make this the session leader - os.setsid() - # Fork again for good measure! - pid = os.fork() - if pid: - os._exit(0) - - # @@: Should we set the umask and cwd now? - - maxfd = resource.getrlimit(resource.RLIMIT_NOFILE)[1] - if maxfd == resource.RLIM_INFINITY: - maxfd = MAXFD - # Iterate through and close all file descriptors. - for fd in range(0, maxfd): - try: - os.close(fd) - except OSError: # ERROR, fd wasn't open to begin with (ignored) - pass - - if hasattr(os, "devnull"): - REDIRECT_TO = os.devnull - else: - REDIRECT_TO = "/dev/null" - os.open(REDIRECT_TO, os.O_RDWR) # standard input (0) - # Duplicate standard input to standard output and standard error. - os.dup2(0, 1) # standard output (1) - os.dup2(0, 2) # standard error (2) - - def record_pid(self, pid_file): - pid = os.getpid() - if self.verbose > 1: - print(f'Writing PID {pid} to {pid_file}') - f = open(pid_file, 'w') - f.write(str(pid)) - f.close() - atexit.register(_remove_pid_file, pid, pid_file, self.verbose) - - def stop_daemon(self): - pid_file = self.options.pid_file or 'paster.pid' - if not os.path.exists(pid_file): - print('No PID file exists in %s' % pid_file) - return 1 - pid = read_pidfile(pid_file) - if not pid: - print("Not a valid PID file in %s" % pid_file) - return 1 - pid = live_pidfile(pid_file) - if not pid: - print("PID in %s is not valid (deleting)" % pid_file) - try: - os.unlink(pid_file) - except OSError as e: - print("Could not delete: %s" % e) - return 2 - return 1 - for _i in range(10): - if not live_pidfile(pid_file): - break - os.kill(pid, signal.SIGTERM) - time.sleep(1) - else: - print("failed to kill web process %s" % pid) - return 3 - if os.path.exists(pid_file): - os.unlink(pid_file) - return 0 - - def show_status(self): - pid_file = self.options.pid_file or 'paster.pid' - if not os.path.exists(pid_file): - print('No PID file %s' % pid_file) - return 1 - pid = read_pidfile(pid_file) - if not pid: - print('No PID in file %s' % pid_file) - return 1 - pid = live_pidfile(pid_file) - if not pid: - print(f'PID {pid} in {pid_file} is not running') - return 1 - print('Server running in PID %s' % pid) - return 0 - - def restart_with_reloader(self): - self.restart_with_monitor(reloader=True) - - def restart_with_monitor(self, reloader=False): - if self.verbose > 0: - if reloader: - print('Starting subprocess with file monitor') - else: - print('Starting subprocess with monitor parent') - while 1: - args = [self.quote_first_command_arg(sys.executable)] + sys.argv - new_environ = os.environ.copy() - if reloader: - new_environ[self._reloader_environ_key] = 'true' - else: - new_environ[self._monitor_environ_key] = 'true' - proc = None - try: - try: - _turn_sigterm_into_systemexit() - proc = subprocess.Popen(args, env=new_environ) - exit_code = proc.wait() - proc = None - except KeyboardInterrupt: - print('^C caught in monitor process') - if self.verbose > 1: - raise - return 1 - finally: - if proc is not None and hasattr(os, 'kill'): - try: - os.kill(proc.pid, signal.SIGTERM) - except OSError: - pass - - if reloader: - # Reloader always exits with code 3; but if we are - # a monitor, any exit code will restart - if exit_code != 3: - return exit_code - if self.verbose > 0: - print('-' * 20, 'Restarting', '-' * 20) - - def change_user_group(self, user, group): - if not user and not group: - return - uid = gid = None - if group: - try: - gid = int(group) - group = grp.getgrgid(gid).gr_name - except ValueError: - 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 {}:{} ({}:{})'.format( - user, group or '(unknown)', uid, gid)) - if hasattr(os, 'initgroups'): - os.initgroups(user, gid) - else: - os.setgroups([e.gr_gid for e in grp.getgrall() - if user in e.gr_mem] + [gid]) - if gid: - os.setgid(gid) - if uid: - os.setuid(uid) - - -class LazyWriter: - - """ - File-like object that opens a file lazily when it is first written - to. - """ - - def __init__(self, filename, mode='w'): - self.filename = filename - self.fileobj = None - self.lock = threading.Lock() - self.mode = mode - - def open(self): - if self.fileobj is None: - self.lock.acquire() - try: - if self.fileobj is None: - self.fileobj = open(self.filename, self.mode) - finally: - self.lock.release() - return self.fileobj - - def write(self, text): - fileobj = self.open() - fileobj.write(text) - fileobj.flush() - - def writelines(self, text): - fileobj = self.open() - fileobj.writelines(text) - fileobj.flush() - - def flush(self): - self.open().flush() - - -def live_pidfile(pidfile): - """(pidfile:str) -> int | None - Returns an int found in the named file, if there is one, - and if there is a running process with that process id. - Return None if no such process exists. - """ - pid = read_pidfile(pidfile) - if pid: - try: - os.kill(int(pid), 0) - return pid - except OSError as e: - if e.errno == errno.EPERM: - return pid - return None - - -def read_pidfile(filename): - if os.path.exists(filename): - try: - f = open(filename) - content = f.read() - f.close() - return int(content.strip()) - except (ValueError, OSError): - return None - else: - return None - - -def _remove_pid_file(written_pid, filename, verbosity): - current_pid = os.getpid() - if written_pid != current_pid: - # A forked process must be exiting, not the process that - # wrote the PID file - return - if not os.path.exists(filename): - return - f = open(filename) - content = f.read().strip() - f.close() - try: - pid_in_file = int(content) - except ValueError: - pass - else: - if pid_in_file != current_pid: - print("PID file {} contains {}, not expected PID {}".format( - filename, pid_in_file, current_pid)) - return - if verbosity > 0: - print("Removing PID file %s" % filename) - try: - os.unlink(filename) - return - except OSError as e: - # Record, but don't give traceback - print("Cannot remove PID file: %s" % e) - # well, at least lets not leave the invalid PID around... - try: - f = open(filename, 'w') - f.write('') - f.close() - except OSError as e: - print(f'Stale PID left in file: {filename} ({e:e})') - else: - print('Stale PID removed') - - -def ensure_port_cleanup(bound_addresses, maxtries=30, sleeptime=2): - """ - This makes sure any open ports are closed. - - Does this by connecting to them until they give connection - refused. Servers should call like:: - - import paste.script - ensure_port_cleanup([80, 443]) - """ - atexit.register(_cleanup_ports, bound_addresses, maxtries=maxtries, - sleeptime=sleeptime) - - -def _cleanup_ports(bound_addresses, maxtries=30, sleeptime=2): - # Wait for the server to bind to the port. - for bound_address in bound_addresses: - for _i in range(maxtries): - sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - try: - sock.connect(bound_address) - except OSError as e: - if e.errno != errno.ECONNREFUSED: - raise - break - else: - time.sleep(sleeptime) - else: - raise SystemExit('Timeout waiting for port.') - sock.close() - - -def _turn_sigterm_into_systemexit(): - """ - Attempts to turn a SIGTERM exception into a SystemExit exception. - """ - - def handle_term(signo, frame): - raise SystemExit - signal.signal(signal.SIGTERM, handle_term) - - -# ---- from paste.script.command -------------------------------------- -python_version = sys.version.splitlines()[0].strip() - -parser = optparse.OptionParser(add_help_option=False, - # version='%s from %s (python %s)' - # % (dist, dist.location, python_version), - usage='%prog [paster_options] COMMAND [command_options]') - -parser.add_option( - '-h', '--help', - action='store_true', - dest='do_help', - help="Show this help message") -parser.disable_interspersed_args() - -# @@: Add an option to run this in another Python interpreter - -commands = { - 'serve': ServeCommand -} - - -def run(args=None): - if (not args and len(sys.argv) >= 2 and os.environ.get('_') - and sys.argv[0] != os.environ['_'] and os.environ['_'] == sys.argv[1]): - # probably it's an exe execution - args = ['exe', os.environ['_']] + sys.argv[2:] - if args is None: - args = sys.argv[1:] - options, args = parser.parse_args(args) - options.base_parser = parser - if options.do_help: - args = ['help'] + args - if not args: - print('Usage: %s COMMAND' % sys.argv[0]) - args = ['help'] - command_name = args[0] - if command_name not in commands: - command = NotFoundCommand - else: - command = commands[command_name] - invoke(command, command_name, options, args[1:]) - - -def invoke(command, command_name, options, args): - try: - runner = command(command_name) - exit_code = runner.run(args) - except BadCommand as e: - print(e) - exit_code = e.exit_code - sys.exit(exit_code) diff --git a/rolling_restart.sh b/rolling_restart.sh deleted file mode 100755 index 9ad66136294..00000000000 --- a/rolling_restart.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/sh - -cd `dirname $0` - -GALAXY_RUN_ALL=1 ./run.sh restart --wait diff --git a/scripts/paster.py b/scripts/paster.py deleted file mode 100755 index 12fe39da16f..00000000000 --- a/scripts/paster.py +++ /dev/null @@ -1,22 +0,0 @@ -""" -Bootstrap the Galaxy framework. - -This should not be called directly! Use the run.sh script in Galaxy's -top level directly. -""" - -import os -import sys - -sys.path.insert(1, os.path.abspath(os.path.join(os.path.dirname(__file__), os.pardir, 'lib'))) - -from galaxy.util.pastescript import serve -from check_python import check_python # noqa: I100, I201 - -# ensure supported version -try: - check_python() -except Exception: - sys.exit(1) - -serve.run() diff --git a/test/unit/util/test_fix_type_error.py b/test/unit/util/test_fix_type_error.py deleted file mode 100644 index ca9e415ebc7..00000000000 --- a/test/unit/util/test_fix_type_error.py +++ /dev/null @@ -1,18 +0,0 @@ -from galaxy.util.pastescript.loadwsgi import fix_type_error - -argtype = '' -EXP_STRING = "a_func() got multiple values for%s argument 'kwarg'; got (1, 2, kwarg=...), wanted (argone, kwarg=True)" % argtype - - -def a_func(argone, kwarg=True): - pass - - -def test_fix_type_error(): - args = [1, 2] - kwargs = {'kwarg': False} - try: - a_func(*args, **kwargs) - except TypeError: - exc_info = fix_type_error(None, a_func, args, kwargs) - assert exc_info[1].args[0] == EXP_STRING