def _construct_path(self, obj, base_dir=None, dir_only=None, extra_dir=None, extra_dir_at_root=False, alt_name=None, obj_dir=False, **kwargs): # extra_dir should never be constructed from provided data but just # make sure there are no shenannigans afoot if extra_dir and extra_dir != os.path.normpath(extra_dir): log.warning('extra_dir is not normalized: %s', extra_dir) raise ObjectInvalid("The requested object is invalid") # ensure that any parent directory references in alt_name would not # result in a path not contained in the directory path constructed here if alt_name: if not safe_relpath(alt_name): log.warning('alt_name would locate path outside dir: %s', alt_name) raise ObjectInvalid("The requested object is invalid") # alt_name can contain parent directory references, but S3 will not # follow them, so if they are valid we normalize them out alt_name = os.path.normpath(alt_name) rel_path = os.path.join(*directory_hash_id(obj.id)) if extra_dir is not None: if extra_dir_at_root: rel_path = os.path.join(extra_dir, rel_path) else: rel_path = os.path.join(rel_path, extra_dir) # for JOB_WORK directory if obj_dir: rel_path = os.path.join(rel_path, str(obj.id)) if base_dir: base = self.extra_dirs.get(base_dir) return os.path.join(base, rel_path) # S3 folders are marked by having trailing '/' so add it now rel_path = '%s/' % rel_path if not dir_only: rel_path = os.path.join(rel_path, alt_name if alt_name else "dataset_%s.dat" % obj.id) return rel_path
def __get_rods_path(self, obj, base_dir=None, dir_only=False, extra_dir=None, extra_dir_at_root=False, alt_name=None, strip_dat=True, **kwargs): # extra_dir should never be constructed from provided data but just # make sure there are no shenannigans afoot if extra_dir and extra_dir != os.path.normpath(extra_dir): log.warning('extra_dir is not normalized: %s', extra_dir) raise ObjectInvalid("The requested object is invalid") # ensure that any parent directory references in alt_name would not # result in a path not contained in the directory path constructed here if alt_name: if not safe_relpath(alt_name): log.warning('alt_name would locate path outside dir: %s', alt_name) raise ObjectInvalid("The requested object is invalid") # alt_name can contain parent directory references, but iRODS will # not follow them, so if they are valid we normalize them out alt_name = os.path.normpath(alt_name) path = "" if extra_dir is not None: path = extra_dir # extra_dir_at_root is ignored - since the iRODS plugin does not use # the directory hash, there is only one level of subdirectory. if not dir_only: # the .dat extension is stripped when stored in iRODS # TODO: is the strip_dat kwarg the best way to implement this? if strip_dat and alt_name and alt_name.endswith('.dat'): alt_name = os.path.splitext(alt_name)[0] default_name = 'dataset_%s' % obj.id if not strip_dat: default_name += '.dat' path = path_join(path, alt_name if alt_name else default_name) path = path_join(self.root_collection_path, path) return path
def __get_rods_path( self, obj, base_dir=None, dir_only=False, extra_dir=None, extra_dir_at_root=False, alt_name=None, strip_dat=True, **kwargs ): # extra_dir should never be constructed from provided data but just # make sure there are no shenannigans afoot if extra_dir and extra_dir != os.path.normpath(extra_dir): log.warning('extra_dir is not normalized: %s', extra_dir) raise ObjectInvalid("The requested object is invalid") # ensure that any parent directory references in alt_name would not # result in a path not contained in the directory path constructed here if alt_name: if not safe_relpath(alt_name): log.warning('alt_name would locate path outside dir: %s', alt_name) raise ObjectInvalid("The requested object is invalid") # alt_name can contain parent directory references, but iRODS will # not follow them, so if they are valid we normalize them out alt_name = os.path.normpath(alt_name) path = "" if extra_dir is not None: path = extra_dir # extra_dir_at_root is ignored - since the iRODS plugin does not use # the directory hash, there is only one level of subdirectory. if not dir_only: # the .dat extension is stripped when stored in iRODS # TODO: is the strip_dat kwarg the best way to implement this? if strip_dat and alt_name and alt_name.endswith( '.dat' ): alt_name = os.path.splitext( alt_name )[0] default_name = 'dataset_%s' % obj.id if not strip_dat: default_name += '.dat' path = path_join( path, alt_name if alt_name else default_name ) path = path_join( self.root_collection_path, path ) return path
def check_archive(repository, archive): valid = [] invalid = [] errors = [] undesirable_files = [] undesirable_dirs = [] for member in archive.getmembers(): # Allow regular files and directories only if not (member.isdir() or member.isfile() or member.islnk()): errors.append( "Uploaded archives can only include regular directories and files (no symbolic links, devices, etc)." ) invalid.append(member) continue if not safe_relpath(member.name): errors.append( "Uploaded archives cannot contain files that would extract outside of the archive." ) invalid.append(member) continue if os.path.basename(member.name) in UNDESIRABLE_FILES: undesirable_files.append(member) continue head = tail = member.name try: while tail: head, tail = os.path.split(head) if tail in UNDESIRABLE_DIRS: undesirable_dirs.append(member) assert False except AssertionError: continue if repository.type == rt_util.REPOSITORY_SUITE_DEFINITION and member.name != rt_util.REPOSITORY_DEPENDENCY_DEFINITION_FILENAME: errors.append( 'Repositories of type <b>Repository suite definition</b> can contain only a single file named <b>repository_dependencies.xml</b>.' ) invalid.append(member) continue if repository.type == rt_util.TOOL_DEPENDENCY_DEFINITION and member.name != rt_util.TOOL_DEPENDENCY_DEFINITION_FILENAME: errors.append( 'Repositories of type <b>Tool dependency definition</b> can contain only a single file named <b>tool_dependencies.xml</b>.' ) invalid.append(member) continue valid.append(member) ArchiveCheckResults = namedtuple('ArchiveCheckResults', [ 'valid', 'invalid', 'undesirable_files', 'undesirable_dirs', 'errors' ]) return ArchiveCheckResults(valid, invalid, undesirable_files, undesirable_dirs, errors)
def check_archive(repository, archive): valid = [] invalid = [] errors = [] undesirable_files = [] undesirable_dirs = [] for member in archive.getmembers(): # Allow regular files and directories only if not (member.isdir() or member.isfile() or member.islnk()): errors.append("Uploaded archives can only include regular directories and files (no symbolic links, devices, etc).") invalid.append(member) continue if not safe_relpath(member.name): errors.append("Uploaded archives cannot contain files that would extract outside of the archive.") invalid.append(member) continue if os.path.basename(member.name) in UNDESIRABLE_FILES: undesirable_files.append(member) continue head = tail = member.name try: while tail: head, tail = os.path.split(head) if tail in UNDESIRABLE_DIRS: undesirable_dirs.append(member) assert False except AssertionError: continue if repository.type == rt_util.REPOSITORY_SUITE_DEFINITION and member.name != rt_util.REPOSITORY_DEPENDENCY_DEFINITION_FILENAME: errors.append('Repositories of type <b>Repository suite definition</b> can contain only a single file named <b>repository_dependencies.xml</b>.') invalid.append(member) continue if repository.type == rt_util.TOOL_DEPENDENCY_DEFINITION and member.name != rt_util.TOOL_DEPENDENCY_DEFINITION_FILENAME: errors.append('Repositories of type <b>Tool dependency definition</b> can contain only a single file named <b>tool_dependencies.xml</b>.') invalid.append(member) continue valid.append(member) ArchiveCheckResults = namedtuple('ArchiveCheckResults', ['valid', 'invalid', 'undesirable_files', 'undesirable_dirs', 'errors']) return ArchiveCheckResults(valid, invalid, undesirable_files, undesirable_dirs, errors)
def _construct_path(self, obj, old_style=False, base_dir=None, dir_only=False, extra_dir=None, extra_dir_at_root=False, alt_name=None, obj_dir=False, **kwargs): """ Construct the absolute path for accessing the object identified by `obj.id`. :type base_dir: string :param base_dir: A key in self.extra_dirs corresponding to the base directory in which this object should be created, or None to specify the default directory. :type dir_only: boolean :param dir_only: If True, check only the path where the file identified by `obj` should be located, not the dataset itself. This option applies to `extra_dir` argument as well. :type extra_dir: string :param extra_dir: Append the value of this parameter to the expected path used to access the object identified by `obj` (e.g., /files/000/<extra_dir>/dataset_10.dat). :type alt_name: string :param alt_name: Use this name as the alternative name for the returned dataset rather than the default. :type old_style: boolean param old_style: This option is used for backward compatibility. If `True` then the composed directory structure does not include a hash id (e.g., /files/dataset_10.dat (old) vs. /files/000/dataset_10.dat (new)) """ base = os.path.abspath(self.extra_dirs.get(base_dir, self.file_path)) # extra_dir should never be constructed from provided data but just # make sure there are no shenannigans afoot if extra_dir and extra_dir != os.path.normpath(extra_dir): log.warning('extra_dir is not normalized: %s', extra_dir) raise ObjectInvalid("The requested object is invalid") # ensure that any parent directory references in alt_name would not # result in a path not contained in the directory path constructed here if alt_name and not safe_relpath(alt_name): log.warning('alt_name would locate path outside dir: %s', alt_name) raise ObjectInvalid("The requested object is invalid") if old_style: if extra_dir is not None: path = os.path.join(base, extra_dir) else: path = base else: # Construct hashed path rel_path = os.path.join(*directory_hash_id(obj.id)) # Create a subdirectory for the object ID if obj_dir: rel_path = os.path.join(rel_path, str(obj.id)) # Optionally append extra_dir if extra_dir is not None: if extra_dir_at_root: rel_path = os.path.join(extra_dir, rel_path) else: rel_path = os.path.join(rel_path, extra_dir) path = os.path.join(base, rel_path) if not dir_only: path = os.path.join(path, alt_name if alt_name else "dataset_%s.dat" % obj.id) return os.path.abspath(path)
def __call__(self, environ, start_response): if 'PATH_INFO' in environ: path_info = environ['PATH_INFO'].lstrip('/') if path_info == 'repository/reset_all_metadata': self.setting_repository_metadata = True cmd = self.__get_hg_command(**environ) # The 'getbundle' command indicates that a mercurial client is getting a bundle of one or more changesets, indicating # a clone or a pull. However, we do not want to increment the times_downloaded count if we're only setting repository # metadata. if cmd == 'getbundle' and not self.setting_repository_metadata: hg_args = urlparse.parse_qs(environ['HTTP_X_HGARG_1']) # The 'common' parameter indicates the full sha-1 hash of the changeset the client currently has checked out. If # this is 0000000000000000000000000000000000000000, then the client is performing a fresh checkout. If it has any # other value, the client is getting updates to an existing checkout. if 'common' in hg_args and hg_args['common'][ -1] == '0000000000000000000000000000000000000000': # Increment the value of the times_downloaded column in the repository table for the cloned repository. if 'PATH_INFO' in environ: # Instantiate a database connection engine = sqlalchemy.create_engine(self.db_url) connection = engine.connect() path_info = environ['PATH_INFO'].lstrip('/') user_id, repository_name = self.__get_user_id_repository_name_from_path_info( connection, path_info) sql_cmd = "SELECT times_downloaded FROM repository WHERE user_id = %d AND name = '%s'" % \ ( user_id, repository_name.lower() ) result_set = connection.execute(sql_cmd) for row in result_set: # Should only be 1 row... times_downloaded = row['times_downloaded'] times_downloaded += 1 sql_cmd = "UPDATE repository SET times_downloaded = %d WHERE user_id = %d AND name = '%s'" % \ ( times_downloaded, user_id, repository_name.lower() ) connection.execute(sql_cmd) connection.close() elif cmd in ['unbundle', 'pushkey']: # This is an hg push from the command line. When doing this, the following commands, in order, # will be retrieved from environ (see the docs at http://mercurial.selenic.com/wiki/WireProtocol): # # If mercurial version >= '2.2.3': capabilities -> batch -> branchmap -> unbundle -> listkeys -> pushkey -> listkeys # # The mercurial API unbundle() ( i.e., hg push ) and pushkey() methods ultimately require authorization. # We'll force password entry every time a change set is pushed. # # When a user executes hg commit, it is not guaranteed to succeed. Mercurial records your name # and address with each change that you commit, so that you and others will later be able to # tell who made each change. Mercurial tries to automatically figure out a sensible username # to commit the change with. It will attempt each of the following methods, in order: # # 1) If you specify a -u option to the hg commit command on the command line, followed by a username, # this is always given the highest precedence. # 2) If you have set the HGUSER environment variable, this is checked next. # 3) If you create a file in your home directory called .hgrc with a username entry, that # will be used next. # 4) If you have set the EMAIL environment variable, this will be used next. # 5) Mercurial will query your system to find out your local user name and host name, and construct # a username from these components. Since this often results in a username that is not very useful, # it will print a warning if it has to do this. # # If all of these mechanisms fail, Mercurial will fail, printing an error message. In this case, it # will not let you commit until you set up a username. result = self.authentication(environ) if not isinstance( result, str) and cmd == 'unbundle' and 'wsgi.input' in environ: bundle_data_stream = environ['wsgi.input'] # Convert the incoming mercurial bundle into a json object and persit it to a temporary file for inspection. fh = tempfile.NamedTemporaryFile('wb', prefix="tmp-hg-bundle") tmp_filename = fh.name fh.close() fh = open(tmp_filename, 'wb') while 1: chunk = bundle_data_stream.read(CHUNK_SIZE) if not chunk: break fh.write(chunk) fh.close() fh = open(tmp_filename, 'rb') try: changeset_groups = json.loads(hg_util.bundle_to_json(fh)) except AttributeError: msg = 'Your version of Mercurial is not supported. Please use a version < 3.5' return self.__display_exception_remotely( start_response, msg) fh.close() try: os.unlink(tmp_filename) except: pass if changeset_groups: # Check the repository type to make sure inappropriate files are not being pushed. if 'PATH_INFO' in environ: # Ensure there are no symlinks with targets outside the repo for entry in changeset_groups: if len(entry) == 2: filename, change_list = entry if not isinstance(change_list, list): change_list = [change_list] for change in change_list: for patch in change['data']: target = patch['block'].strip() if ((patch['end'] - patch['start'] == 0) and not safe_relpath(target)): msg = "Changes include a symlink outside of the repository: %s -> %s" % ( filename, target) log.warning(msg) return self.__display_exception_remotely( start_response, msg) # Instantiate a database connection engine = sqlalchemy.create_engine(self.db_url) connection = engine.connect() path_info = environ['PATH_INFO'].lstrip('/') user_id, repository_name = self.__get_user_id_repository_name_from_path_info( connection, path_info) sql_cmd = "SELECT type FROM repository WHERE user_id = %d AND name = '%s'" % ( user_id, repository_name.lower()) result_set = connection.execute(sql_cmd) for row in result_set: # Should only be 1 row... repository_type = str(row['type']) if repository_type == rt_util.REPOSITORY_SUITE_DEFINITION: # Handle repositories of type repository_suite_definition, which can only contain a single # file named repository_dependencies.xml. for entry in changeset_groups: if len(entry) == 2: # We possibly found an altered file entry. filename, change_list = entry if filename and isinstance(filename, str): if filename == rt_util.REPOSITORY_DEPENDENCY_DEFINITION_FILENAME: # Make sure the any complex repository dependency definitions contain valid <repository> tags. is_valid, error_msg = self.repository_tags_are_valid( filename, change_list) if not is_valid: log.debug(error_msg) return self.__display_exception_remotely( start_response, error_msg) else: msg = "Only a single file named repository_dependencies.xml can be pushed to a repository " msg += "of type 'Repository suite definition'." log.debug(msg) return self.__display_exception_remotely( start_response, msg) elif repository_type == rt_util.TOOL_DEPENDENCY_DEFINITION: # Handle repositories of type tool_dependency_definition, which can only contain a single # file named tool_dependencies.xml. for entry in changeset_groups: if len(entry) == 2: # We possibly found an altered file entry. filename, change_list = entry if filename and isinstance(filename, str): if filename == rt_util.TOOL_DEPENDENCY_DEFINITION_FILENAME: # Make sure the any complex repository dependency definitions contain valid <repository> tags. is_valid, error_msg = self.repository_tags_are_valid( filename, change_list) if not is_valid: log.debug(error_msg) return self.__display_exception_remotely( start_response, error_msg) else: msg = "Only a single file named tool_dependencies.xml can be pushed to a repository " msg += "of type 'Tool dependency definition'." log.debug(msg) return self.__display_exception_remotely( start_response, msg) else: # If the changeset includes changes to dependency definition files, make sure tag sets # are not missing "toolshed" or "changeset_revision" attributes since automatically populating # them is not supported when pushing from the command line. These attributes are automatically # populated only when using the tool shed upload utility. for entry in changeset_groups: if len(entry) == 2: # We possibly found an altered file entry. filename, change_list = entry if filename and isinstance(filename, str): if filename in [ rt_util. REPOSITORY_DEPENDENCY_DEFINITION_FILENAME, rt_util. TOOL_DEPENDENCY_DEFINITION_FILENAME ]: # We check both files since tool dependency definitions files can contain complex # repository dependency definitions. is_valid, error_msg = self.repository_tags_are_valid( filename, change_list) if not is_valid: log.debug(error_msg) return self.__display_exception_remotely( start_response, error_msg) if isinstance(result, str): # Authentication was successful AUTH_TYPE.update(environ, 'basic') REMOTE_USER.update(environ, result) else: return result.wsgi_application(environ, start_response) return self.app(environ, start_response)
def __call__( self, environ, start_response ): if 'PATH_INFO' in environ: path_info = environ[ 'PATH_INFO' ].lstrip( '/' ) if path_info == 'repository/reset_all_metadata': self.setting_repository_metadata = True cmd = self.__get_hg_command( **environ ) # The 'getbundle' command indicates that a mercurial client is getting a bundle of one or more changesets, indicating # a clone or a pull. However, we do not want to increment the times_downloaded count if we're only setting repository # metadata. if cmd == 'getbundle' and not self.setting_repository_metadata: hg_args = urlparse.parse_qs( environ[ 'HTTP_X_HGARG_1' ] ) # The 'common' parameter indicates the full sha-1 hash of the changeset the client currently has checked out. If # this is 0000000000000000000000000000000000000000, then the client is performing a fresh checkout. If it has any # other value, the client is getting updates to an existing checkout. if 'common' in hg_args and hg_args[ 'common' ][-1] == '0000000000000000000000000000000000000000': # Increment the value of the times_downloaded column in the repository table for the cloned repository. if 'PATH_INFO' in environ: # Instantiate a database connection engine = sqlalchemy.create_engine( self.db_url ) connection = engine.connect() path_info = environ[ 'PATH_INFO' ].lstrip( '/' ) user_id, repository_name = self.__get_user_id_repository_name_from_path_info( connection, path_info ) sql_cmd = "SELECT times_downloaded FROM repository WHERE user_id = %d AND name = '%s'" % \ ( user_id, repository_name.lower() ) result_set = connection.execute( sql_cmd ) for row in result_set: # Should only be 1 row... times_downloaded = row[ 'times_downloaded' ] times_downloaded += 1 sql_cmd = "UPDATE repository SET times_downloaded = %d WHERE user_id = %d AND name = '%s'" % \ ( times_downloaded, user_id, repository_name.lower() ) connection.execute( sql_cmd ) connection.close() elif cmd in [ 'unbundle', 'pushkey' ]: if self.config.get('disable_push', True): msg = 'Pushing to Tool Shed is disabled. Please use Galaxy Planemo to upload your changes.' return self.__display_exception_remotely( start_response, msg ) # This is an hg push from the command line. When doing this, the following commands, in order, # will be retrieved from environ (see the docs at http://mercurial.selenic.com/wiki/WireProtocol): # # If mercurial version >= '2.2.3': capabilities -> batch -> branchmap -> unbundle -> listkeys -> pushkey -> listkeys # # The mercurial API unbundle() ( i.e., hg push ) and pushkey() methods ultimately require authorization. # We'll force password entry every time a change set is pushed. # # When a user executes hg commit, it is not guaranteed to succeed. Mercurial records your name # and address with each change that you commit, so that you and others will later be able to # tell who made each change. Mercurial tries to automatically figure out a sensible username # to commit the change with. It will attempt each of the following methods, in order: # # 1) If you specify a -u option to the hg commit command on the command line, followed by a username, # this is always given the highest precedence. # 2) If you have set the HGUSER environment variable, this is checked next. # 3) If you create a file in your home directory called .hgrc with a username entry, that # will be used next. # 4) If you have set the EMAIL environment variable, this will be used next. # 5) Mercurial will query your system to find out your local user name and host name, and construct # a username from these components. Since this often results in a username that is not very useful, # it will print a warning if it has to do this. # # If all of these mechanisms fail, Mercurial will fail, printing an error message. In this case, it # will not let you commit until you set up a username. result = self.authentication( environ ) if not isinstance( result, str ) and cmd == 'unbundle' and 'wsgi.input' in environ: bundle_data_stream = environ[ 'wsgi.input' ] # Convert the incoming mercurial bundle into a json object and persit it to a temporary file for inspection. fh = tempfile.NamedTemporaryFile( 'wb', prefix="tmp-hg-bundle" ) tmp_filename = fh.name fh.close() fh = open( tmp_filename, 'wb' ) while 1: chunk = bundle_data_stream.read( CHUNK_SIZE ) if not chunk: break fh.write( chunk ) fh.close() fh = open( tmp_filename, 'rb' ) try: changeset_groups = json.loads( hg_util.bundle_to_json( fh ) ) except AttributeError: msg = 'Your version of Mercurial is not supported. Please use a version < 3.5' return self.__display_exception_remotely( start_response, msg ) fh.close() try: os.unlink( tmp_filename ) except: pass if changeset_groups: # Check the repository type to make sure inappropriate files are not being pushed. if 'PATH_INFO' in environ: # Ensure there are no symlinks with targets outside the repo for entry in changeset_groups: if len( entry ) == 2: filename, change_list = entry if not isinstance(change_list, list): change_list = [change_list] for change in change_list: for patch in change['data']: target = patch['block'].strip() if ( ( patch['end'] - patch['start'] == 0 ) and not safe_relpath( target ) ): msg = "Changes include a symlink outside of the repository: %s -> %s" % ( filename, target ) log.warning( msg ) return self.__display_exception_remotely( start_response, msg ) # Instantiate a database connection engine = sqlalchemy.create_engine( self.db_url ) connection = engine.connect() path_info = environ[ 'PATH_INFO' ].lstrip( '/' ) user_id, repository_name = self.__get_user_id_repository_name_from_path_info( connection, path_info ) sql_cmd = "SELECT type FROM repository WHERE user_id = %d AND name = '%s'" % ( user_id, repository_name.lower() ) result_set = connection.execute( sql_cmd ) for row in result_set: # Should only be 1 row... repository_type = str( row[ 'type' ] ) if repository_type == rt_util.REPOSITORY_SUITE_DEFINITION: # Handle repositories of type repository_suite_definition, which can only contain a single # file named repository_dependencies.xml. for entry in changeset_groups: if len( entry ) == 2: # We possibly found an altered file entry. filename, change_list = entry if filename and isinstance( filename, str ): if filename == rt_util.REPOSITORY_DEPENDENCY_DEFINITION_FILENAME: # Make sure the any complex repository dependency definitions contain valid <repository> tags. is_valid, error_msg = self.repository_tags_are_valid( filename, change_list ) if not is_valid: log.debug( error_msg ) return self.__display_exception_remotely( start_response, error_msg ) else: msg = "Only a single file named repository_dependencies.xml can be pushed to a repository " msg += "of type 'Repository suite definition'." log.debug( msg ) return self.__display_exception_remotely( start_response, msg ) elif repository_type == rt_util.TOOL_DEPENDENCY_DEFINITION: # Handle repositories of type tool_dependency_definition, which can only contain a single # file named tool_dependencies.xml. for entry in changeset_groups: if len( entry ) == 2: # We possibly found an altered file entry. filename, change_list = entry if filename and isinstance( filename, str ): if filename == rt_util.TOOL_DEPENDENCY_DEFINITION_FILENAME: # Make sure the any complex repository dependency definitions contain valid <repository> tags. is_valid, error_msg = self.repository_tags_are_valid( filename, change_list ) if not is_valid: log.debug( error_msg ) return self.__display_exception_remotely( start_response, error_msg ) else: msg = "Only a single file named tool_dependencies.xml can be pushed to a repository " msg += "of type 'Tool dependency definition'." log.debug( msg ) return self.__display_exception_remotely( start_response, msg ) else: # If the changeset includes changes to dependency definition files, make sure tag sets # are not missing "toolshed" or "changeset_revision" attributes since automatically populating # them is not supported when pushing from the command line. These attributes are automatically # populated only when using the tool shed upload utility. for entry in changeset_groups: if len( entry ) == 2: # We possibly found an altered file entry. filename, change_list = entry if filename and isinstance( filename, str ): if filename in [ rt_util.REPOSITORY_DEPENDENCY_DEFINITION_FILENAME, rt_util.TOOL_DEPENDENCY_DEFINITION_FILENAME ]: # We check both files since tool dependency definitions files can contain complex # repository dependency definitions. is_valid, error_msg = self.repository_tags_are_valid( filename, change_list ) if not is_valid: log.debug( error_msg ) return self.__display_exception_remotely( start_response, error_msg ) if isinstance( result, str ): # Authentication was successful AUTH_TYPE.update( environ, 'basic' ) REMOTE_USER.update( environ, result ) else: return result.wsgi_application( environ, start_response ) return self.app( environ, start_response )