prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  CSS bundles generation breaks background images relative urls
  This is a bug related to PR #1300.
  
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `Products/CMFPlone/resources/browser/combine.py`
  Content:
  ```
  1 from zExceptions import NotFound
  2 from Acquisition import aq_base
  3 from datetime import datetime
  4 from plone.registry.interfaces import IRegistry
  5 from plone.resource.file import FilesystemFile
  6 from plone.resource.interfaces import IResourceDirectory
  7 from Products.CMFPlone.interfaces import IBundleRegistry
  8 from Products.CMFPlone.interfaces.resources import (
  9     OVERRIDE_RESOURCE_DIRECTORY_NAME,
  10 )
  11 from StringIO import StringIO
  12 from zope.component import getUtility
  13 from zope.component import queryUtility
  14 
  15 PRODUCTION_RESOURCE_DIRECTORY = "production"
  16 
  17 
  18 def get_production_resource_directory():
  19     persistent_directory = queryUtility(IResourceDirectory, name="persistent")
  20     if persistent_directory is None:
  21         return ''
  22     container = persistent_directory[OVERRIDE_RESOURCE_DIRECTORY_NAME]
  23     try:
  24         production_folder = container[PRODUCTION_RESOURCE_DIRECTORY]
  25     except NotFound:
  26         return "%s/++unique++1" % PRODUCTION_RESOURCE_DIRECTORY
  27     timestamp = production_folder.readFile('timestamp.txt')
  28     return "%s/++unique++%s" % (
  29         PRODUCTION_RESOURCE_DIRECTORY, timestamp)
  30 
  31 
  32 def get_resource(context, path):
  33     if path.startswith('++plone++'):
  34         # ++plone++ resources can be customized, we return their override
  35         # value if any
  36         overrides = get_override_directory(context)
  37         filepath = path[9:]
  38         if overrides.isFile(filepath):
  39             return overrides.readFile(filepath)
  40 
  41     resource = context.unrestrictedTraverse(path)
  42     if isinstance(resource, FilesystemFile):
  43         (directory, sep, filename) = path.rpartition('/')
  44         return context.unrestrictedTraverse(directory).readFile(filename)
  45     else:
  46         if hasattr(aq_base(resource), 'GET'):
  47             # for FileResource
  48             return resource.GET()
  49         else:
  50             # any BrowserView
  51             return resource()
  52 
  53 
  54 def write_js(context, folder, meta_bundle):
  55     registry = getUtility(IRegistry)
  56     resources = []
  57 
  58     # default resources
  59     if meta_bundle == 'default' and registry.records.get(
  60         'plone.resources/jquery.js'
  61     ):
  62         resources.append(get_resource(context,
  63             registry.records['plone.resources/jquery.js'].value))
  64         resources.append(get_resource(context,
  65             registry.records['plone.resources.requirejs'].value))
  66         resources.append(get_resource(context,
  67             registry.records['plone.resources.configjs'].value))
  68 
  69     # bundles
  70     bundles = registry.collectionOfInterface(
  71         IBundleRegistry, prefix="plone.bundles", check=False)
  72     for bundle in bundles.values():
  73         if bundle.merge_with == meta_bundle and bundle.jscompilation:
  74             resources.append(get_resource(context, bundle.jscompilation))
  75 
  76     fi = StringIO()
  77     for script in resources:
  78         fi.write(script + '\n')
  79     folder.writeFile(meta_bundle + ".js", fi)
  80 
  81 
  82 def write_css(context, folder, meta_bundle):
  83     registry = getUtility(IRegistry)
  84     resources = []
  85 
  86     bundles = registry.collectionOfInterface(
  87         IBundleRegistry, prefix="plone.bundles", check=False)
  88     for bundle in bundles.values():
  89         if bundle.merge_with == meta_bundle and bundle.csscompilation:
  90             resources.append(get_resource(context, bundle.csscompilation))
  91 
  92     fi = StringIO()
  93     for script in resources:
  94         fi.write(script + '\n')
  95     folder.writeFile(meta_bundle + ".css", fi)
  96 
  97 
  98 def get_override_directory(context):
  99     persistent_directory = queryUtility(IResourceDirectory, name="persistent")
  100     if persistent_directory is None:
  101         return
  102     if OVERRIDE_RESOURCE_DIRECTORY_NAME not in persistent_directory:
  103         persistent_directory.makeDirectory(OVERRIDE_RESOURCE_DIRECTORY_NAME)
  104     return persistent_directory[OVERRIDE_RESOURCE_DIRECTORY_NAME]
  105 
  106 
  107 def combine_bundles(context):
  108     container = get_override_directory(context)
  109     if PRODUCTION_RESOURCE_DIRECTORY not in container:
  110         container.makeDirectory(PRODUCTION_RESOURCE_DIRECTORY)
  111     production_folder = container[PRODUCTION_RESOURCE_DIRECTORY]
  112 
  113     # store timestamp
  114     fi = StringIO()
  115     fi.write(datetime.now().isoformat())
  116     production_folder.writeFile("timestamp.txt", fi)
  117 
  118     # generate new combined bundles
  119     write_js(context, production_folder, 'default')
  120     write_js(context, production_folder, 'logged-in')
  121     write_css(context, production_folder, 'default')
  122     write_css(context, production_folder, 'logged-in')
  123
  ```
  --- END FILES ---
  
  Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.
  
  Here is an example:
  
  ```diff
  diff --git a/examples/server_async.py b/examples/server_async.py
  --- a/examples/server_async.py
  +++ b/examples/server_async.py
  @@ -313,4 +313,4 @@
   
   
   if __name__ == "__main__":
  -    asyncio.run(run_async_server("."), debug=True)
  +    asyncio.run(run_async_server(), debug=True)
  diff --git a/examples/server_sync.py b/examples/server_sync.py
  --- a/examples/server_sync.py
  +++ b/examples/server_sync.py
  @@ -313,5 +313,5 @@
   
   
   if __name__ == "__main__":
  -    server = run_sync_server(".")
  +    server = run_sync_server()
       server.shutdown()
  
  ```
  
golden_diff: diff --git a/Products/CMFPlone/resources/browser/combine.py b/Products/CMFPlone/resources/browser/combine.py
  --- a/Products/CMFPlone/resources/browser/combine.py
  +++ b/Products/CMFPlone/resources/browser/combine.py
  @@ -1,18 +1,20 @@
  -from zExceptions import NotFound
   from Acquisition import aq_base
   from datetime import datetime
   from plone.registry.interfaces import IRegistry
   from plone.resource.file import FilesystemFile
   from plone.resource.interfaces import IResourceDirectory
   from Products.CMFPlone.interfaces import IBundleRegistry
  -from Products.CMFPlone.interfaces.resources import (
  -    OVERRIDE_RESOURCE_DIRECTORY_NAME,
  -)
  +from Products.CMFPlone.interfaces.resources import OVERRIDE_RESOURCE_DIRECTORY_NAME  # noqa
   from StringIO import StringIO
  +from zExceptions import NotFound
   from zope.component import getUtility
   from zope.component import queryUtility
   
  +import logging
  +import re
  +
   PRODUCTION_RESOURCE_DIRECTORY = "production"
  +logger = logging.getLogger(__name__)
   
   
   def get_production_resource_directory():
  @@ -24,6 +26,8 @@
           production_folder = container[PRODUCTION_RESOURCE_DIRECTORY]
       except NotFound:
           return "%s/++unique++1" % PRODUCTION_RESOURCE_DIRECTORY
  +    if 'timestamp.txt' not in production_folder:
  +        return "%s/++unique++1" % PRODUCTION_RESOURCE_DIRECTORY
       timestamp = production_folder.readFile('timestamp.txt')
       return "%s/++unique++%s" % (
           PRODUCTION_RESOURCE_DIRECTORY, timestamp)
  @@ -38,7 +42,12 @@
           if overrides.isFile(filepath):
               return overrides.readFile(filepath)
   
  -    resource = context.unrestrictedTraverse(path)
  +    try:
  +        resource = context.unrestrictedTraverse(path)
  +    except NotFound:
  +        logger.warn(u"Could not find resource {0}. You may have to create it first.".format(path))  # noqa
  +        return
  +
       if isinstance(resource, FilesystemFile):
           (directory, sep, filename) = path.rpartition('/')
           return context.unrestrictedTraverse(directory).readFile(filename)
  @@ -71,7 +80,10 @@
           IBundleRegistry, prefix="plone.bundles", check=False)
       for bundle in bundles.values():
           if bundle.merge_with == meta_bundle and bundle.jscompilation:
  -            resources.append(get_resource(context, bundle.jscompilation))
  +            resource = get_resource(context, bundle.jscompilation)
  +            if not resource:
  +                continue
  +            resources.append(resource)
   
       fi = StringIO()
       for script in resources:
  @@ -87,7 +99,18 @@
           IBundleRegistry, prefix="plone.bundles", check=False)
       for bundle in bundles.values():
           if bundle.merge_with == meta_bundle and bundle.csscompilation:
  -            resources.append(get_resource(context, bundle.csscompilation))
  +            css = get_resource(context, bundle.csscompilation)
  +            if not css:
  +                continue
  +            (path, sep, filename) = bundle.csscompilation.rpartition('/')
  +            # Process relative urls:
  +            # we prefix with current resource path any url not starting with
  +            # '/' or http: or data:
  +            css = re.sub(
  +                r"""(url\(['"]?(?!['"]?([a-z]+:|\/)))""",
  +                r'\1%s/' % path,
  +                css)
  +            resources.append(css)
   
       fi = StringIO()
       for script in resources:
  
verification_info: {"golden_diff": "diff --git a/Products/CMFPlone/resources/browser/combine.py b/Products/CMFPlone/resources/browser/combine.py\n--- a/Products/CMFPlone/resources/browser/combine.py\n+++ b/Products/CMFPlone/resources/browser/combine.py\n@@ -1,18 +1,20 @@\n-from zExceptions import NotFound\n from Acquisition import aq_base\n from datetime import datetime\n from plone.registry.interfaces import IRegistry\n from plone.resource.file import FilesystemFile\n from plone.resource.interfaces import IResourceDirectory\n from Products.CMFPlone.interfaces import IBundleRegistry\n-from Products.CMFPlone.interfaces.resources import (\n-    OVERRIDE_RESOURCE_DIRECTORY_NAME,\n-)\n+from Products.CMFPlone.interfaces.resources import OVERRIDE_RESOURCE_DIRECTORY_NAME  # noqa\n from StringIO import StringIO\n+from zExceptions import NotFound\n from zope.component import getUtility\n from zope.component import queryUtility\n \n+import logging\n+import re\n+\n PRODUCTION_RESOURCE_DIRECTORY = \"production\"\n+logger = logging.getLogger(__name__)\n \n \n def get_production_resource_directory():\n@@ -24,6 +26,8 @@\n         production_folder = container[PRODUCTION_RESOURCE_DIRECTORY]\n     except NotFound:\n         return \"%s/++unique++1\" % PRODUCTION_RESOURCE_DIRECTORY\n+    if 'timestamp.txt' not in production_folder:\n+        return \"%s/++unique++1\" % PRODUCTION_RESOURCE_DIRECTORY\n     timestamp = production_folder.readFile('timestamp.txt')\n     return \"%s/++unique++%s\" % (\n         PRODUCTION_RESOURCE_DIRECTORY, timestamp)\n@@ -38,7 +42,12 @@\n         if overrides.isFile(filepath):\n             return overrides.readFile(filepath)\n \n-    resource = context.unrestrictedTraverse(path)\n+    try:\n+        resource = context.unrestrictedTraverse(path)\n+    except NotFound:\n+        logger.warn(u\"Could not find resource {0}. You may have to create it first.\".format(path))  # noqa\n+        return\n+\n     if isinstance(resource, FilesystemFile):\n         (directory, sep, filename) = path.rpartition('/')\n         return context.unrestrictedTraverse(directory).readFile(filename)\n@@ -71,7 +80,10 @@\n         IBundleRegistry, prefix=\"plone.bundles\", check=False)\n     for bundle in bundles.values():\n         if bundle.merge_with == meta_bundle and bundle.jscompilation:\n-            resources.append(get_resource(context, bundle.jscompilation))\n+            resource = get_resource(context, bundle.jscompilation)\n+            if not resource:\n+                continue\n+            resources.append(resource)\n \n     fi = StringIO()\n     for script in resources:\n@@ -87,7 +99,18 @@\n         IBundleRegistry, prefix=\"plone.bundles\", check=False)\n     for bundle in bundles.values():\n         if bundle.merge_with == meta_bundle and bundle.csscompilation:\n-            resources.append(get_resource(context, bundle.csscompilation))\n+            css = get_resource(context, bundle.csscompilation)\n+            if not css:\n+                continue\n+            (path, sep, filename) = bundle.csscompilation.rpartition('/')\n+            # Process relative urls:\n+            # we prefix with current resource path any url not starting with\n+            # '/' or http: or data:\n+            css = re.sub(\n+                r\"\"\"(url\\(['\"]?(?!['\"]?([a-z]+:|\\/)))\"\"\",\n+                r'\\1%s/' % path,\n+                css)\n+            resources.append(css)\n \n     fi = StringIO()\n     for script in resources:\n", "issue": "CSS bundles generation breaks background images relative urls\nThis is a bug related to PR #1300.\n\n", "before_files": [{"content": "from zExceptions import NotFound\nfrom Acquisition import aq_base\nfrom datetime import datetime\nfrom plone.registry.interfaces import IRegistry\nfrom plone.resource.file import FilesystemFile\nfrom plone.resource.interfaces import IResourceDirectory\nfrom Products.CMFPlone.interfaces import IBundleRegistry\nfrom Products.CMFPlone.interfaces.resources import (\n    OVERRIDE_RESOURCE_DIRECTORY_NAME,\n)\nfrom StringIO import StringIO\nfrom zope.component import getUtility\nfrom zope.component import queryUtility\n\nPRODUCTION_RESOURCE_DIRECTORY = \"production\"\n\n\ndef get_production_resource_directory():\n    persistent_directory = queryUtility(IResourceDirectory, name=\"persistent\")\n    if persistent_directory is None:\n        return ''\n    container = persistent_directory[OVERRIDE_RESOURCE_DIRECTORY_NAME]\n    try:\n        production_folder = container[PRODUCTION_RESOURCE_DIRECTORY]\n    except NotFound:\n        return \"%s/++unique++1\" % PRODUCTION_RESOURCE_DIRECTORY\n    timestamp = production_folder.readFile('timestamp.txt')\n    return \"%s/++unique++%s\" % (\n        PRODUCTION_RESOURCE_DIRECTORY, timestamp)\n\n\ndef get_resource(context, path):\n    if path.startswith('++plone++'):\n        # ++plone++ resources can be customized, we return their override\n        # value if any\n        overrides = get_override_directory(context)\n        filepath = path[9:]\n        if overrides.isFile(filepath):\n            return overrides.readFile(filepath)\n\n    resource = context.unrestrictedTraverse(path)\n    if isinstance(resource, FilesystemFile):\n        (directory, sep, filename) = path.rpartition('/')\n        return context.unrestrictedTraverse(directory).readFile(filename)\n    else:\n        if hasattr(aq_base(resource), 'GET'):\n            # for FileResource\n            return resource.GET()\n        else:\n            # any BrowserView\n            return resource()\n\n\ndef write_js(context, folder, meta_bundle):\n    registry = getUtility(IRegistry)\n    resources = []\n\n    # default resources\n    if meta_bundle == 'default' and registry.records.get(\n        'plone.resources/jquery.js'\n    ):\n        resources.append(get_resource(context,\n            registry.records['plone.resources/jquery.js'].value))\n        resources.append(get_resource(context,\n            registry.records['plone.resources.requirejs'].value))\n        resources.append(get_resource(context,\n            registry.records['plone.resources.configjs'].value))\n\n    # bundles\n    bundles = registry.collectionOfInterface(\n        IBundleRegistry, prefix=\"plone.bundles\", check=False)\n    for bundle in bundles.values():\n        if bundle.merge_with == meta_bundle and bundle.jscompilation:\n            resources.append(get_resource(context, bundle.jscompilation))\n\n    fi = StringIO()\n    for script in resources:\n        fi.write(script + '\\n')\n    folder.writeFile(meta_bundle + \".js\", fi)\n\n\ndef write_css(context, folder, meta_bundle):\n    registry = getUtility(IRegistry)\n    resources = []\n\n    bundles = registry.collectionOfInterface(\n        IBundleRegistry, prefix=\"plone.bundles\", check=False)\n    for bundle in bundles.values():\n        if bundle.merge_with == meta_bundle and bundle.csscompilation:\n            resources.append(get_resource(context, bundle.csscompilation))\n\n    fi = StringIO()\n    for script in resources:\n        fi.write(script + '\\n')\n    folder.writeFile(meta_bundle + \".css\", fi)\n\n\ndef get_override_directory(context):\n    persistent_directory = queryUtility(IResourceDirectory, name=\"persistent\")\n    if persistent_directory is None:\n        return\n    if OVERRIDE_RESOURCE_DIRECTORY_NAME not in persistent_directory:\n        persistent_directory.makeDirectory(OVERRIDE_RESOURCE_DIRECTORY_NAME)\n    return persistent_directory[OVERRIDE_RESOURCE_DIRECTORY_NAME]\n\n\ndef combine_bundles(context):\n    container = get_override_directory(context)\n    if PRODUCTION_RESOURCE_DIRECTORY not in container:\n        container.makeDirectory(PRODUCTION_RESOURCE_DIRECTORY)\n    production_folder = container[PRODUCTION_RESOURCE_DIRECTORY]\n\n    # store timestamp\n    fi = StringIO()\n    fi.write(datetime.now().isoformat())\n    production_folder.writeFile(\"timestamp.txt\", fi)\n\n    # generate new combined bundles\n    write_js(context, production_folder, 'default')\n    write_js(context, production_folder, 'logged-in')\n    write_css(context, production_folder, 'default')\n    write_css(context, production_folder, 'logged-in')\n", "path": "Products/CMFPlone/resources/browser/combine.py"}], "after_files": [{"content": "from Acquisition import aq_base\nfrom datetime import datetime\nfrom plone.registry.interfaces import IRegistry\nfrom plone.resource.file import FilesystemFile\nfrom plone.resource.interfaces import IResourceDirectory\nfrom Products.CMFPlone.interfaces import IBundleRegistry\nfrom Products.CMFPlone.interfaces.resources import OVERRIDE_RESOURCE_DIRECTORY_NAME  # noqa\nfrom StringIO import StringIO\nfrom zExceptions import NotFound\nfrom zope.component import getUtility\nfrom zope.component import queryUtility\n\nimport logging\nimport re\n\nPRODUCTION_RESOURCE_DIRECTORY = \"production\"\nlogger = logging.getLogger(__name__)\n\n\ndef get_production_resource_directory():\n    persistent_directory = queryUtility(IResourceDirectory, name=\"persistent\")\n    if persistent_directory is None:\n        return ''\n    container = persistent_directory[OVERRIDE_RESOURCE_DIRECTORY_NAME]\n    try:\n        production_folder = container[PRODUCTION_RESOURCE_DIRECTORY]\n    except NotFound:\n        return \"%s/++unique++1\" % PRODUCTION_RESOURCE_DIRECTORY\n    if 'timestamp.txt' not in production_folder:\n        return \"%s/++unique++1\" % PRODUCTION_RESOURCE_DIRECTORY\n    timestamp = production_folder.readFile('timestamp.txt')\n    return \"%s/++unique++%s\" % (\n        PRODUCTION_RESOURCE_DIRECTORY, timestamp)\n\n\ndef get_resource(context, path):\n    if path.startswith('++plone++'):\n        # ++plone++ resources can be customized, we return their override\n        # value if any\n        overrides = get_override_directory(context)\n        filepath = path[9:]\n        if overrides.isFile(filepath):\n            return overrides.readFile(filepath)\n\n    try:\n        resource = context.unrestrictedTraverse(path)\n    except NotFound:\n        logger.warn(u\"Could not find resource {0}. You may have to create it first.\".format(path))  # noqa\n        return\n\n    if isinstance(resource, FilesystemFile):\n        (directory, sep, filename) = path.rpartition('/')\n        return context.unrestrictedTraverse(directory).readFile(filename)\n    else:\n        if hasattr(aq_base(resource), 'GET'):\n            # for FileResource\n            return resource.GET()\n        else:\n            # any BrowserView\n            return resource()\n\n\ndef write_js(context, folder, meta_bundle):\n    registry = getUtility(IRegistry)\n    resources = []\n\n    # default resources\n    if meta_bundle == 'default' and registry.records.get(\n        'plone.resources/jquery.js'\n    ):\n        resources.append(get_resource(context,\n            registry.records['plone.resources/jquery.js'].value))\n        resources.append(get_resource(context,\n            registry.records['plone.resources.requirejs'].value))\n        resources.append(get_resource(context,\n            registry.records['plone.resources.configjs'].value))\n\n    # bundles\n    bundles = registry.collectionOfInterface(\n        IBundleRegistry, prefix=\"plone.bundles\", check=False)\n    for bundle in bundles.values():\n        if bundle.merge_with == meta_bundle and bundle.jscompilation:\n            resource = get_resource(context, bundle.jscompilation)\n            if not resource:\n                continue\n            resources.append(resource)\n\n    fi = StringIO()\n    for script in resources:\n        fi.write(script + '\\n')\n    folder.writeFile(meta_bundle + \".js\", fi)\n\n\ndef write_css(context, folder, meta_bundle):\n    registry = getUtility(IRegistry)\n    resources = []\n\n    bundles = registry.collectionOfInterface(\n        IBundleRegistry, prefix=\"plone.bundles\", check=False)\n    for bundle in bundles.values():\n        if bundle.merge_with == meta_bundle and bundle.csscompilation:\n            css = get_resource(context, bundle.csscompilation)\n            if not css:\n                continue\n            (path, sep, filename) = bundle.csscompilation.rpartition('/')\n            # Process relative urls:\n            # we prefix with current resource path any url not starting with\n            # '/' or http: or data:\n            css = re.sub(\n                r\"\"\"(url\\(['\"]?(?!['\"]?([a-z]+:|\\/)))\"\"\",\n                r'\\1%s/' % path,\n                css)\n            resources.append(css)\n\n    fi = StringIO()\n    for script in resources:\n        fi.write(script + '\\n')\n    folder.writeFile(meta_bundle + \".css\", fi)\n\n\ndef get_override_directory(context):\n    persistent_directory = queryUtility(IResourceDirectory, name=\"persistent\")\n    if persistent_directory is None:\n        return\n    if OVERRIDE_RESOURCE_DIRECTORY_NAME not in persistent_directory:\n        persistent_directory.makeDirectory(OVERRIDE_RESOURCE_DIRECTORY_NAME)\n    return persistent_directory[OVERRIDE_RESOURCE_DIRECTORY_NAME]\n\n\ndef combine_bundles(context):\n    container = get_override_directory(context)\n    if PRODUCTION_RESOURCE_DIRECTORY not in container:\n        container.makeDirectory(PRODUCTION_RESOURCE_DIRECTORY)\n    production_folder = container[PRODUCTION_RESOURCE_DIRECTORY]\n\n    # store timestamp\n    fi = StringIO()\n    fi.write(datetime.now().isoformat())\n    production_folder.writeFile(\"timestamp.txt\", fi)\n\n    # generate new combined bundles\n    write_js(context, production_folder, 'default')\n    write_js(context, production_folder, 'logged-in')\n    write_css(context, production_folder, 'default')\n    write_css(context, production_folder, 'logged-in')\n", "path": "Products/CMFPlone/resources/browser/combine.py"}]}