<s> from __future__ import absolute_import , print_function <EOL> __all__ = [ '<STR_LIT>' ] <EOL> import logging <EOL> import re <EOL> import base64 <EOL> import zlib <EOL> from django . conf import settings <EOL> from django . core . exceptions import SuspiciousOperation <EOL> from django . utils . encoding import force_bytes , force_text <EOL> from collections import namedtuple <EOL> from os . path import splitext <EOL> from requests . exceptions import RequestException <EOL> from simplejson import JSONDecodeError <EOL> from urlparse import urlparse , urljoin , urlsplit <EOL> try : <EOL> from OpenSSL . SSL import ZeroReturnError <EOL> except ImportError : <EOL> class ZeroReturnError ( Exception ) : <EOL> pass <EOL> from sentry import http <EOL> from sentry . constants import MAX_CULPRIT_LENGTH <EOL> from sentry . exceptions import RestrictedIPAddress <EOL> from sentry . interfaces . stacktrace import Stacktrace <EOL> from sentry . models import EventError , Release , ReleaseFile <EOL> from sentry . utils . cache import cache <EOL> from sentry . utils . files import compress_file <EOL> from sentry . utils . hashlib import md5 <EOL> from sentry . utils . http import is_valid_origin <EOL> from sentry . utils . strings import truncatechars <EOL> from . cache import SourceCache , SourceMapCache <EOL> from . sourcemaps import sourcemap_to_index , find_source <EOL> LINES_OF_CONTEXT = <NUM_LIT:5> <EOL> BASE64_SOURCEMAP_PREAMBLE = '<STR_LIT>' <EOL> BASE64_PREAMBLE_LENGTH = len ( BASE64_SOURCEMAP_PREAMBLE ) <EOL> UNKNOWN_MODULE = '<STR_LIT>' <EOL> CLEAN_MODULE_RE = re . compile ( r"""<STR_LIT>""" , re . X | re . I ) <EOL> VERSION_RE = re . compile ( r'<STR_LIT>' , re . I ) <EOL> MAX_RESOURCE_FETCHES = <NUM_LIT:100> <EOL> UrlResult = namedtuple ( '<STR_LIT>' , [ '<STR_LIT:url>' , '<STR_LIT>' , '<STR_LIT:body>' ] ) <EOL> logger = logging . getLogger ( __name__ ) <EOL> class BadSource ( Exception ) : <EOL> error_type = EventError . UNKNOWN_ERROR <EOL> def __init__ ( self , data = None ) : <EOL> if data is None : <EOL> data = { } <EOL> data . setdefault ( '<STR_LIT:type>' , self . error_type ) <EOL> super ( BadSource , self ) . __init__ ( data [ '<STR_LIT:type>' ] ) <EOL> self . data = data <EOL> class CannotFetchSource ( BadSource ) : <EOL> error_type = EventError . JS_GENERIC_FETCH_ERROR <EOL> class UnparseableSourcemap ( BadSource ) : <EOL> error_type = EventError . JS_INVALID_SOURCEMAP <EOL> def trim_line ( line , column = <NUM_LIT:0> ) : <EOL> """<STR_LIT>""" <EOL> line = line . strip ( '<STR_LIT:\n>' ) <EOL> ll = len ( line ) <EOL> if ll <= <NUM_LIT> : <EOL> return line <EOL> if column > ll : <EOL> column = ll <EOL> start = max ( column - <NUM_LIT> , <NUM_LIT:0> ) <EOL> if start < <NUM_LIT:5> : <EOL> start = <NUM_LIT:0> <EOL> end = min ( start + <NUM_LIT> , ll ) <EOL> if end > ll - <NUM_LIT:5> : <EOL> end = ll <EOL> if end == ll : <EOL> start = max ( end - <NUM_LIT> , <NUM_LIT:0> ) <EOL> line = line [ start : end ] <EOL> if end < ll : <EOL> line += '<STR_LIT>' <EOL> if start > <NUM_LIT:0> : <EOL> line = '<STR_LIT>' + line <EOL> return line <EOL> def get_source_context ( source , lineno , colno , context = LINES_OF_CONTEXT ) : <EOL> if not source : <EOL> return [ ] , '<STR_LIT>' , [ ] <EOL> if lineno > <NUM_LIT:0> : <EOL> lineno -= <NUM_LIT:1> <EOL> lower_bound = max ( <NUM_LIT:0> , lineno - context ) <EOL> upper_bound = min ( lineno + <NUM_LIT:1> + context , len ( source ) ) <EOL> try : <EOL> pre_context = map ( trim_line , source [ lower_bound : lineno ] ) <EOL> except IndexError : <EOL> pre_context = [ ] <EOL> try : <EOL> context_line = trim_line ( source [ lineno ] , colno ) <EOL> except IndexError : <EOL> context_line = '<STR_LIT>' <EOL> try : <EOL> post_context = map ( trim_line , source [ ( lineno + <NUM_LIT:1> ) : upper_bound ] ) <EOL> except IndexError : <EOL> post_context = [ ] <EOL> return pre_context , context_line , post_context <EOL> def discover_sourcemap ( result ) : <EOL> """<STR_LIT>""" <EOL> sourcemap = result . headers . get ( '<STR_LIT>' , result . headers . get ( '<STR_LIT>' ) ) <EOL> if not sourcemap : <EOL> parsed_body = result . body . split ( '<STR_LIT:\n>' ) <EOL> if len ( parsed_body ) > <NUM_LIT:10> : <EOL> possibilities = parsed_body [ : <NUM_LIT:5> ] + parsed_body [ - <NUM_LIT:5> : ] <EOL> else : <EOL> possibilities = parsed_body <EOL> for line in possibilities : <EOL> if line [ : <NUM_LIT> ] in ( '<STR_LIT>' , '<STR_LIT>' ) : <EOL> sourcemap = line [ <NUM_LIT> : ] . rstrip ( ) <EOL> if sourcemap : <EOL> sourcemap = urljoin ( result . url , sourcemap ) <EOL> return sourcemap <EOL> def fetch_release_file ( filename , release ) : <EOL> cache_key = '<STR_LIT>' % ( <EOL> release . id , <EOL> md5 ( filename ) . hexdigest ( ) , <EOL> ) <EOL> logger . debug ( '<STR_LIT>' , <EOL> filename , release . id ) <EOL> result = cache . get ( cache_key ) <EOL> if result is None : <EOL> logger . debug ( '<STR_LIT>' , <EOL> filename , release . id ) <EOL> ident = ReleaseFile . get_ident ( filename ) <EOL> try : <EOL> releasefile = ReleaseFile . objects . filter ( <EOL> release = release , <EOL> ident = ident , <EOL> ) . select_related ( '<STR_LIT:file>' ) . get ( ) <EOL> except ReleaseFile . DoesNotExist : <EOL> logger . debug ( '<STR_LIT>' , <EOL> filename , release . id ) <EOL> cache . set ( cache_key , - <NUM_LIT:1> , <NUM_LIT> ) <EOL> return None <EOL> logger . debug ( '<STR_LIT>' , <EOL> filename , releasefile . id , release . id ) <EOL> try : <EOL> with releasefile . file . getfile ( ) as fp : <EOL> z_body , body = compress_file ( fp ) <EOL> except Exception as e : <EOL> logger . exception ( unicode ( e ) ) <EOL> cache . set ( cache_key , - <NUM_LIT:1> , <NUM_LIT> ) <EOL> result = None <EOL> else : <EOL> cache . set ( cache_key , ( releasefile . file . headers , z_body , <NUM_LIT:200> ) , <NUM_LIT> ) <EOL> result = ( releasefile . file . headers , body , <NUM_LIT:200> ) <EOL> elif result == - <NUM_LIT:1> : <EOL> result = None <EOL> else : <EOL> body = zlib . decompress ( result [ <NUM_LIT:1> ] ) <EOL> result = ( result [ <NUM_LIT:0> ] , body , result [ <NUM_LIT:2> ] ) <EOL> return result <EOL> def fetch_file ( url , project = None , release = None , allow_scraping = True ) : <EOL> """<STR_LIT>""" <EOL> if release : <EOL> result = fetch_release_file ( url , release ) <EOL> else : <EOL> result = None <EOL> cache_key = '<STR_LIT>' % ( <EOL> md5 ( url ) . hexdigest ( ) , <EOL> ) <EOL> if result is None : <EOL> if not allow_scraping or not url . startswith ( ( '<STR_LIT>' , '<STR_LIT>' ) ) : <EOL> error = { <EOL> '<STR_LIT:type>' : EventError . JS_MISSING_SOURCE , <EOL> '<STR_LIT:url>' : url , <EOL> } <EOL> raise CannotFetchSource ( error ) <EOL> logger . debug ( '<STR_LIT>' , url ) <EOL> result = cache . get ( cache_key ) <EOL> if result is not None : <EOL> body = zlib . decompress ( result [ <NUM_LIT:1> ] ) <EOL> result = ( result [ <NUM_LIT:0> ] , force_text ( body ) , result [ <NUM_LIT:2> ] ) <EOL> if result is None : <EOL> domain = urlparse ( url ) . netloc <EOL> domain_key = '<STR_LIT>' % ( <EOL> md5 ( domain ) . hexdigest ( ) , <EOL> ) <EOL> domain_result = cache . get ( domain_key ) <EOL> if domain_result : <EOL> domain_result [ '<STR_LIT:url>' ] = url <EOL> raise CannotFetchSource ( domain_result ) <EOL> headers = { } <EOL> if project and is_valid_origin ( url , project = project ) : <EOL> token = project . get_option ( '<STR_LIT>' ) <EOL> if token : <EOL> headers [ '<STR_LIT>' ] = token <EOL> logger . debug ( '<STR_LIT>' , url ) <EOL> http_session = http . build_session ( ) <EOL> try : <EOL> response = http_session . get ( <EOL> url , <EOL> allow_redirects = True , <EOL> verify = False , <EOL> headers = headers , <EOL> timeout = settings . SENTRY_SOURCE_FETCH_TIMEOUT , <EOL> ) <EOL> except Exception as exc : <EOL> logger . debug ( '<STR_LIT>' , url , exc_info = True ) <EOL> if isinstance ( exc , RestrictedIPAddress ) : <EOL> error = { <EOL> '<STR_LIT:type>' : EventError . RESTRICTED_IP , <EOL> '<STR_LIT:url>' : url , <EOL> } <EOL> elif isinstance ( exc , SuspiciousOperation ) : <EOL> error = { <EOL> '<STR_LIT:type>' : EventError . SECURITY_VIOLATION , <EOL> '<STR_LIT:url>' : url , <EOL> } <EOL> elif isinstance ( exc , ( RequestException , ZeroReturnError ) ) : <EOL> error = { <EOL> '<STR_LIT:type>' : EventError . JS_GENERIC_FETCH_ERROR , <EOL> '<STR_LIT:value>' : str ( type ( exc ) ) , <EOL> '<STR_LIT:url>' : url , <EOL> } <EOL> else : <EOL> logger . exception ( unicode ( exc ) ) <EOL> error = { <EOL> '<STR_LIT:type>' : EventError . UNKNOWN_ERROR , <EOL> '<STR_LIT:url>' : url , <EOL> } <EOL> cache . set ( domain_key , error or '<STR_LIT>' , <NUM_LIT> ) <EOL> logger . warning ( '<STR_LIT>' , domain , <NUM_LIT> , <EOL> exc_info = True ) <EOL> raise CannotFetchSource ( error ) <EOL> if not response . encoding : <EOL> response . encoding = '<STR_LIT:utf-8>' <EOL> body = response . text <EOL> z_body = zlib . compress ( force_bytes ( body ) ) <EOL> headers = { k . lower ( ) : v for k , v in response . headers . items ( ) } <EOL> cache . set ( cache_key , ( headers , z_body , response . status_code ) , <NUM_LIT> ) <EOL> result = ( headers , body , response . status_code ) <EOL> if result [ <NUM_LIT:2> ] != <NUM_LIT:200> : <EOL> logger . debug ( '<STR_LIT>' , result [ <NUM_LIT:2> ] , url , <EOL> exc_info = True ) <EOL> error = { <EOL> '<STR_LIT:type>' : EventError . JS_INVALID_HTTP_CODE , <EOL> '<STR_LIT:value>' : result [ <NUM_LIT:2> ] , <EOL> '<STR_LIT:url>' : url , <EOL> } <EOL> raise CannotFetchSource ( error ) <EOL> if not isinstance ( result [ <NUM_LIT:1> ] , unicode ) : <EOL> try : <EOL> result = ( result [ <NUM_LIT:0> ] , result [ <NUM_LIT:1> ] . decode ( '<STR_LIT:utf8>' ) , result [ <NUM_LIT:2> ] ) <EOL> except UnicodeDecodeError : <EOL> error = { <EOL> '<STR_LIT:type>' : EventError . JS_INVALID_SOURCE_ENCODING , <EOL> '<STR_LIT:value>' : '<STR_LIT:utf8>' , <EOL> '<STR_LIT:url>' : url , <EOL> } <EOL> raise CannotFetchSource ( error ) <EOL> return UrlResult ( url , result [ <NUM_LIT:0> ] , result [ <NUM_LIT:1> ] ) <EOL> def fetch_sourcemap ( url , project = None , release = None , allow_scraping = True ) : <EOL> if is_data_uri ( url ) : <EOL> body = base64 . b64decode ( url [ BASE64_PREAMBLE_LENGTH : ] ) <EOL> else : <EOL> result = fetch_file ( url , project = project , release = release , <EOL> allow_scraping = allow_scraping ) <EOL> body = result . body <EOL> if body . startswith ( ( "<STR_LIT>" , "<STR_LIT>" ) ) : <EOL> body = body . split ( '<STR_LIT:\n>' , <NUM_LIT:1> ) [ <NUM_LIT:1> ] <EOL> try : <EOL> return sourcemap_to_index ( body ) <EOL> except ( JSONDecodeError , ValueError , AssertionError ) as exc : <EOL> logger . warn ( unicode ( exc ) ) <EOL> raise UnparseableSourcemap ( { <EOL> '<STR_LIT:url>' : url , <EOL> } ) <EOL> def is_data_uri ( url ) : <EOL> return url [ : BASE64_PREAMBLE_LENGTH ] == BASE64_SOURCEMAP_PREAMBLE <EOL> def generate_module ( src ) : <EOL> """<STR_LIT>""" <EOL> if not src : <EOL> return UNKNOWN_MODULE <EOL> filename , ext = splitext ( urlsplit ( src ) . path ) <EOL> if ext not in ( '<STR_LIT>' , '<STR_LIT>' , '<STR_LIT>' ) : <EOL> return UNKNOWN_MODULE <EOL> if filename . endswith ( '<STR_LIT>' ) : <EOL> filename = filename [ : - <NUM_LIT:4> ] <EOL> tokens = filename . split ( '<STR_LIT:/>' ) <EOL> for idx , token in enumerate ( tokens ) : <EOL> if VERSION_RE . match ( token ) : <EOL> return '<STR_LIT:/>' . join ( tokens [ idx + <NUM_LIT:1> : ] ) <EOL> return CLEAN_MODULE_RE . sub ( '<STR_LIT>' , filename ) or UNKNOWN_MODULE <EOL> class SourceProcessor ( object ) : <EOL> """<STR_LIT>""" <EOL> def __init__ ( self , project , max_fetches = MAX_RESOURCE_FETCHES , <EOL> allow_scraping = True ) : <EOL> self . allow_scraping = allow_scraping <EOL> self . max_fetches = max_fetches <EOL> self . fetch_count = <NUM_LIT:0> <EOL> self . cache = SourceCache ( ) <EOL> self . sourcemaps = SourceMapCache ( ) <EOL> self . project = project <EOL> def get_stacktraces ( self , data ) : <EOL> try : <EOL> stacktraces = [ <EOL> e [ '<STR_LIT>' ] <EOL> for e in data [ '<STR_LIT>' ] [ '<STR_LIT>' ] <EOL> if e . get ( '<STR_LIT>' ) <EOL> ] <EOL> except KeyError : <EOL> stacktraces = [ ] <EOL> if '<STR_LIT>' in data : <EOL> stacktraces . append ( data [ '<STR_LIT>' ] ) <EOL> return [ <EOL> ( s , Stacktrace . to_python ( s ) ) <EOL> for s in stacktraces <EOL> ] <EOL> def get_valid_frames ( self , stacktraces ) : <EOL> frames = [ ] <EOL> for _ , stacktrace in stacktraces : <EOL> frames . extend ( [ <EOL> f for f in stacktrace . frames <EOL> if f . lineno is not None <EOL> ] ) <EOL> return frames <EOL> def get_release ( self , data ) : <EOL> if not data . get ( '<STR_LIT>' ) : <EOL> return <EOL> return Release . get ( <EOL> project = self . project , <EOL> version = data [ '<STR_LIT>' ] , <EOL> ) <EOL> def process ( self , data ) : <EOL> stacktraces = self . get_stacktraces ( data ) <EOL> if not stacktraces : <EOL> logger . debug ( '<STR_LIT>' , data [ '<STR_LIT>' ] ) <EOL> return <EOL> frames = self . get_valid_frames ( stacktraces ) <EOL> if not frames : <EOL> logger . debug ( '<STR_LIT>' , data [ '<STR_LIT>' ] ) <EOL> return <EOL> data . setdefault ( '<STR_LIT>' , [ ] ) <EOL> errors = data [ '<STR_LIT>' ] <EOL> release = self . get_release ( data ) <EOL> self . populate_source_cache ( frames , release ) <EOL> errors . extend ( self . expand_frames ( frames , release ) or [ ] ) <EOL> self . ensure_module_names ( frames ) <EOL> self . fix_culprit ( data , stacktraces ) <EOL> self . update_stacktraces ( stacktraces ) <EOL> return data <EOL> def fix_culprit ( self , data , stacktraces ) : <EOL> data [ '<STR_LIT>' ] = truncatechars ( <EOL> stacktraces [ - <NUM_LIT:1> ] [ <NUM_LIT:1> ] . get_culprit_string ( ) , <EOL> MAX_CULPRIT_LENGTH , <EOL> ) <EOL> def update_stacktraces ( self , stacktraces ) : <EOL> for raw , interface in stacktraces : <EOL> raw . update ( interface . to_json ( ) ) <EOL> def ensure_module_names ( self , frames ) : <EOL> for frame in frames : <EOL> if not frame . module and frame . abs_path . startswith ( ( '<STR_LIT>' , '<STR_LIT>' , '<STR_LIT>' ) ) : <EOL> frame . module = generate_module ( frame . abs_path ) <EOL> def expand_frames ( self , frames , release ) : <EOL> last_state = None <EOL> state = None <EOL> cache = self . cache <EOL> sourcemaps = self . sourcemaps <EOL> all_errors = [ ] <EOL> for frame in frames : <EOL> errors = cache . get_errors ( frame . abs_path ) <EOL> if errors : <EOL> all_errors . extend ( errors ) <EOL> if not frame . abs_path : <EOL> continue <EOL> source = self . get_source ( frame . abs_path , release ) <EOL> if source is None : <EOL> logger . debug ( '<STR_LIT>' , frame . abs_path ) <EOL> continue <EOL> sourcemap_url , sourcemap_idx = sourcemaps . get_link ( frame . abs_path ) <EOL> if sourcemap_idx and frame . colno is None : <EOL> all_errors . append ( { <EOL> '<STR_LIT:type>' : EventError . JS_NO_COLUMN , <EOL> '<STR_LIT:url>' : force_bytes ( frame . abs_path , errors = '<STR_LIT:replace>' ) , <EOL> } ) <EOL> elif sourcemap_idx : <EOL> last_state = state <EOL> if is_data_uri ( sourcemap_url ) : <EOL> sourcemap_label = frame . abs_path <EOL> else : <EOL> sourcemap_label = sourcemap_url <EOL> try : <EOL> state = find_source ( sourcemap_idx , frame . lineno , frame . colno ) <EOL> except Exception : <EOL> state = None <EOL> all_errors . append ( { <EOL> '<STR_LIT:type>' : EventError . JS_INVALID_SOURCEMAP_LOCATION , <EOL> '<STR_LIT>' : frame . colno , <EOL> '<STR_LIT>' : frame . lineno , <EOL> '<STR_LIT:source>' : frame . abs_path , <EOL> '<STR_LIT>' : sourcemap_label , <EOL> } ) <EOL> frame . data = { <EOL> '<STR_LIT>' : frame . lineno , <EOL> '<STR_LIT>' : frame . colno , <EOL> '<STR_LIT>' : frame . function , <EOL> '<STR_LIT>' : frame . abs_path , <EOL> '<STR_LIT>' : frame . filename , <EOL> '<STR_LIT>' : sourcemap_label , <EOL> } <EOL> if state is not None : <EOL> abs_path = urljoin ( sourcemap_url , state . src ) <EOL> logger . debug ( '<STR_LIT>' , frame . abs_path , abs_path ) <EOL> source = self . get_source ( abs_path , release ) <EOL> if not source : <EOL> errors = cache . get_errors ( abs_path ) <EOL> if errors : <EOL> all_errors . extend ( errors ) <EOL> else : <EOL> all_errors . append ( { <EOL> '<STR_LIT:type>' : EventError . JS_MISSING_SOURCE , <EOL> '<STR_LIT:url>' : force_bytes ( abs_path , errors = '<STR_LIT:replace>' ) , <EOL> } ) <EOL> if state is not None : <EOL> frame . lineno = state . src_line + <NUM_LIT:1> <EOL> frame . colno = state . src_col <EOL> if last_state : <EOL> frame . function = last_state . name or frame . function <EOL> else : <EOL> frame . function = state . name or frame . function <EOL> filename = state . src <EOL> if abs_path . startswith ( '<STR_LIT>' ) : <EOL> filename = abs_path <EOL> if '<STR_LIT>' in filename : <EOL> filename = '<STR_LIT>' + abs_path . split ( '<STR_LIT>' , <NUM_LIT:1> ) [ - <NUM_LIT:1> ] <EOL> else : <EOL> filename = filename . split ( '<STR_LIT>' , <NUM_LIT:1> ) [ - <NUM_LIT:1> ] <EOL> if filename . startswith ( '<STR_LIT>' ) : <EOL> frame . in_app = False <EOL> elif filename . startswith ( '<STR_LIT>' ) : <EOL> frame . in_app = True <EOL> frame . module = generate_module ( filename ) <EOL> frame . abs_path = abs_path <EOL> frame . filename = filename <EOL> if not frame . module and abs_path . startswith ( ( '<STR_LIT>' , '<STR_LIT>' , '<STR_LIT>' ) ) : <EOL> frame . module = generate_module ( abs_path ) <EOL> elif sourcemap_url : <EOL> frame . data = { <EOL> '<STR_LIT>' : sourcemap_url , <EOL> } <EOL> frame . pre_context , frame . context_line , frame . post_context = get_source_context ( <EOL> source = source , lineno = frame . lineno , colno = frame . colno or <NUM_LIT:0> ) <EOL> if not frame . context_line : <EOL> all_errors . append ( { <EOL> '<STR_LIT:type>' : EventError . JS_INVALID_SOURCEMAP_LOCATION , <EOL> '<STR_LIT>' : frame . colno , <EOL> '<STR_LIT>' : frame . lineno , <EOL> '<STR_LIT:source>' : frame . abs_path , <EOL> } ) <EOL> return all_errors <EOL> def get_source ( self , filename , release ) : <EOL> if filename not in self . cache : <EOL> self . cache_source ( filename , release ) <EOL> return self . cache . get ( filename ) <EOL> def cache_source ( self , filename , release ) : <EOL> sourcemaps = self . sourcemaps <EOL> cache = self . cache <EOL> self . fetch_count += <NUM_LIT:1> <EOL> if self . fetch_count > self . max_fetches : <EOL> cache . add_error ( filename , { <EOL> '<STR_LIT:type>' : EventError . JS_TOO_MANY_REMOTE_SOURCES , <EOL> } ) <EOL> return <EOL> logger . debug ( '<STR_LIT>' , filename ) <EOL> try : <EOL> result = fetch_file ( filename , project = self . project , release = release , <EOL> allow_scraping = self . allow_scraping ) <EOL> except BadSource as exc : <EOL> cache . add_error ( filename , exc . data ) <EOL> return <EOL> cache . add ( filename , result . body . split ( '<STR_LIT:\n>' ) ) <EOL> cache . alias ( result . url , filename ) <EOL> sourcemap_url = discover_sourcemap ( result ) <EOL> if not sourcemap_url : <EOL> return <EOL> logger . debug ( '<STR_LIT>' , sourcemap_url [ : <NUM_LIT> ] , result . url ) <EOL> sourcemaps . link ( filename , sourcemap_url ) <EOL> if sourcemap_url in sourcemaps : <EOL> return <EOL> try : <EOL> sourcemap_idx = fetch_sourcemap ( <EOL> sourcemap_url , <EOL> project = self . project , <EOL> release = release , <EOL> allow_scraping = self . allow_scraping , <EOL> ) <EOL> except BadSource as exc : <EOL> cache . add_error ( filename , exc . data ) <EOL> return <EOL> sourcemaps . add ( sourcemap_url , sourcemap_idx ) <EOL> for source in sourcemap_idx . sources : <EOL> next_filename = urljoin ( sourcemap_url , source ) <EOL> if source in sourcemap_idx . content : <EOL> cache . add ( next_filename , sourcemap_idx . content [ source ] ) <EOL> def populate_source_cache ( self , frames , release ) : <EOL> """<STR_LIT>""" <EOL> pending_file_list = set ( ) <EOL> for f in frames : <EOL> if f . abs_path is None : <EOL> continue <EOL> if f . abs_path == '<STR_LIT>' : <EOL> continue <EOL> pending_file_list . add ( f . abs_path ) <EOL> for idx , filename in enumerate ( pending_file_list ) : <EOL> self . cache_source ( <EOL> filename = filename , <EOL> release = release , <EOL> ) </s>
