prompt: You will be provided with a partial code base and an issue statement explaining a problem to resolve.
  <issue>
  pants package does not build missing docker images if previous build was cached.
  **Describe the bug**
  Pant's caching of build targets does not take into consideration that the final target does not exist.
  
  Take this example: https://www.pantsbuild.org/v2.8/docs/docker#example
  
  ```
  $ ./pants package src/docker/hw/Dockerfile
  [...]
  18:07:29.66 [INFO] Completed: Building src.python.hw/bin.pex
  18:07:31.83 [INFO] Completed: Building docker image helloworld:latest
  18:07:31.83 [INFO] Built docker image: helloworld:latest
  
  $ docker images
  REPOSITORY               TAG        IMAGE ID       CREATED         SIZE
  helloworld               latest     abcdefabcdef   6 seconds ago   420MB
  
  $ docker rmi helloworld:latest
  
  $ docker images
  REPOSITORY               TAG        IMAGE ID       CREATED         SIZE
  
  $ ./pants package src/docker/hw/Dockerfile
  19:07:31.83 [INFO] Built docker image: helloworld:latest
  
  $ docker images
  REPOSITORY               TAG        IMAGE ID       CREATED         SIZE
  ```
  If you did the equivalent commands for the `helloworld.pex` files, `pants package` would replace the missing file in the `dist/` folder.
  
  **Pants version**
  2.8rc1
  
  **OS**
  Linux
  
  
  </issue>
  <code>
  [start of src/python/pants/backend/docker/util_rules/docker_binary.py]
  1 # Copyright 2021 Pants project contributors (see CONTRIBUTORS.md).
  2 # Licensed under the Apache License, Version 2.0 (see LICENSE).
  3 
  4 from __future__ import annotations
  5 
  6 from dataclasses import dataclass
  7 from typing import Mapping
  8 
  9 from pants.backend.docker.util_rules.docker_build_args import DockerBuildArgs
  10 from pants.engine.fs import Digest
  11 from pants.engine.process import (
  12     BinaryNotFoundError,
  13     BinaryPath,
  14     BinaryPathRequest,
  15     BinaryPaths,
  16     BinaryPathTest,
  17     Process,
  18     SearchPath,
  19 )
  20 from pants.engine.rules import Get, collect_rules, rule
  21 from pants.util.logging import LogLevel
  22 from pants.util.strutil import pluralize
  23 
  24 
  25 class DockerBinary(BinaryPath):
  26     """The `docker` binary."""
  27 
  28     DEFAULT_SEARCH_PATH = SearchPath(("/usr/bin", "/bin", "/usr/local/bin"))
  29 
  30     def build_image(
  31         self,
  32         tags: tuple[str, ...],
  33         digest: Digest,
  34         dockerfile: str | None = None,
  35         build_args: DockerBuildArgs | None = None,
  36         env: Mapping[str, str] | None = None,
  37     ) -> Process:
  38         args = [self.path, "build"]
  39 
  40         for tag in tags:
  41             args.extend(["-t", tag])
  42 
  43         if build_args:
  44             for build_arg in build_args:
  45                 args.extend(["--build-arg", build_arg])
  46 
  47         if dockerfile:
  48             args.extend(["-f", dockerfile])
  49 
  50         # Add build context root.
  51         args.append(".")
  52 
  53         return Process(
  54             argv=tuple(args),
  55             description=(
  56                 f"Building docker image {tags[0]}"
  57                 + (f" +{pluralize(len(tags)-1, 'additional tag')}." if len(tags) > 1 else ".")
  58             ),
  59             env=env,
  60             input_digest=digest,
  61         )
  62 
  63     def push_image(self, tags: tuple[str, ...]) -> Process | None:
  64         if not tags:
  65             return None
  66 
  67         return Process(
  68             argv=(self.path, "push", *tags), description="Pushing docker image {tags[0]}"
  69         )
  70 
  71 
  72 @dataclass(frozen=True)
  73 class DockerBinaryRequest:
  74     search_path: SearchPath = DockerBinary.DEFAULT_SEARCH_PATH
  75 
  76 
  77 @rule(desc="Finding the `docker` binary", level=LogLevel.DEBUG)
  78 async def find_docker(docker_request: DockerBinaryRequest) -> DockerBinary:
  79     request = BinaryPathRequest(
  80         binary_name="docker",
  81         search_path=docker_request.search_path,
  82         test=BinaryPathTest(args=["-v"]),
  83     )
  84     paths = await Get(BinaryPaths, BinaryPathRequest, request)
  85     first_path = paths.first_path
  86     if not first_path:
  87         raise BinaryNotFoundError.from_request(request, rationale="interact with the docker daemon")
  88     return DockerBinary(first_path.path, first_path.fingerprint)
  89 
  90 
  91 @rule
  92 async def get_docker() -> DockerBinary:
  93     return await Get(DockerBinary, DockerBinaryRequest())
  94 
  95 
  96 def rules():
  97     return collect_rules()
  98
  [end of src/python/pants/backend/docker/util_rules/docker_binary.py]
  </code>
  
  I need you to solve this issue by generating a single patch file that I can apply directly to this repository using git apply. Please respond with a single patch file in the following format.
  <patch>
  diff --git a/file.py b/file.py
  --- a/file.py
  +++ b/file.py
  @@ -1,27 +1,35 @@
   def euclidean(a, b):
  -    while b:
  -        a, b = b, a % b
  -    return a
  +    if b == 0:
  +        return a
  +    return euclidean(b, a % b)
   
   
   def bresenham(x0, y0, x1, y1):
       points = []
       dx = abs(x1 - x0)
       dy = abs(y1 - y0)
  -    sx = 1 if x0 < x1 else -1
  -    sy = 1 if y0 < y1 else -1
  -    err = dx - dy
  +    x, y = x0, y0
  +    sx = -1 if x0 > x1 else 1
  +    sy = -1 if y0 > y1 else 1
   
  -    while True:
  -        points.append((x0, y0))
  -        if x0 == x1 and y0 == y1:
  -            break
  -        e2 = 2 * err
  -        if e2 > -dy:
  -            err -= dy
  -            x0 += sx
  -        if e2 < dx:
  -            err += dx
  -            y0 += sy
  +    if dx > dy:
  +        err = dx / 2.0
  +        while x != x1:
  +            points.append((x, y))
  +            err -= dy
  +            if err < 0:
  +                y += sy
  +                err += dx
  +            x += sx
  +    else:
  +        err = dy / 2.0
  +        while y != y1:
  +            points.append((x, y))
  +            err -= dx
  +            if err < 0:
  +                x += sx
  +                err += dy
  +            y += sy
  +
  +    points.append((x, y))
       return points
  
  </patch>
golden_diff: diff --git a/src/python/pants/backend/docker/util_rules/docker_binary.py b/src/python/pants/backend/docker/util_rules/docker_binary.py
  --- a/src/python/pants/backend/docker/util_rules/docker_binary.py
  +++ b/src/python/pants/backend/docker/util_rules/docker_binary.py
  @@ -15,6 +15,7 @@
       BinaryPaths,
       BinaryPathTest,
       Process,
  +    ProcessCacheScope,
       SearchPath,
   )
   from pants.engine.rules import Get, collect_rules, rule
  @@ -58,6 +59,7 @@
               ),
               env=env,
               input_digest=digest,
  +            cache_scope=ProcessCacheScope.PER_SESSION,
           )
   
       def push_image(self, tags: tuple[str, ...]) -> Process | None:
  @@ -65,7 +67,9 @@
               return None
   
           return Process(
  -            argv=(self.path, "push", *tags), description="Pushing docker image {tags[0]}"
  +            argv=(self.path, "push", *tags),
  +            cache_scope=ProcessCacheScope.PER_SESSION,
  +            description=f"Pushing docker image {tags[0]}",
           )
  
verification_info: {"golden_diff": "diff --git a/src/python/pants/backend/docker/util_rules/docker_binary.py b/src/python/pants/backend/docker/util_rules/docker_binary.py\n--- a/src/python/pants/backend/docker/util_rules/docker_binary.py\n+++ b/src/python/pants/backend/docker/util_rules/docker_binary.py\n@@ -15,6 +15,7 @@\n     BinaryPaths,\n     BinaryPathTest,\n     Process,\n+    ProcessCacheScope,\n     SearchPath,\n )\n from pants.engine.rules import Get, collect_rules, rule\n@@ -58,6 +59,7 @@\n             ),\n             env=env,\n             input_digest=digest,\n+            cache_scope=ProcessCacheScope.PER_SESSION,\n         )\n \n     def push_image(self, tags: tuple[str, ...]) -> Process | None:\n@@ -65,7 +67,9 @@\n             return None\n \n         return Process(\n-            argv=(self.path, \"push\", *tags), description=\"Pushing docker image {tags[0]}\"\n+            argv=(self.path, \"push\", *tags),\n+            cache_scope=ProcessCacheScope.PER_SESSION,\n+            description=f\"Pushing docker image {tags[0]}\",\n         )\n", "issue": "pants package does not build missing docker images if previous build was cached.\n**Describe the bug**\r\nPant's caching of build targets does not take into consideration that the final target does not exist.\r\n\r\nTake this example: https://www.pantsbuild.org/v2.8/docs/docker#example\r\n\r\n```\r\n$ ./pants package src/docker/hw/Dockerfile\r\n[...]\r\n18:07:29.66 [INFO] Completed: Building src.python.hw/bin.pex\r\n18:07:31.83 [INFO] Completed: Building docker image helloworld:latest\r\n18:07:31.83 [INFO] Built docker image: helloworld:latest\r\n\r\n$ docker images\r\nREPOSITORY               TAG        IMAGE ID       CREATED         SIZE\r\nhelloworld               latest     abcdefabcdef   6 seconds ago   420MB\r\n\r\n$ docker rmi helloworld:latest\r\n\r\n$ docker images\r\nREPOSITORY               TAG        IMAGE ID       CREATED         SIZE\r\n\r\n$ ./pants package src/docker/hw/Dockerfile\r\n19:07:31.83 [INFO] Built docker image: helloworld:latest\r\n\r\n$ docker images\r\nREPOSITORY               TAG        IMAGE ID       CREATED         SIZE\r\n```\r\nIf you did the equivalent commands for the `helloworld.pex` files, `pants package` would replace the missing file in the `dist/` folder.\r\n\r\n**Pants version**\r\n2.8rc1\r\n\r\n**OS**\r\nLinux\r\n\n", "before_files": [{"content": "# Copyright 2021 Pants project contributors (see CONTRIBUTORS.md).\n# Licensed under the Apache License, Version 2.0 (see LICENSE).\n\nfrom __future__ import annotations\n\nfrom dataclasses import dataclass\nfrom typing import Mapping\n\nfrom pants.backend.docker.util_rules.docker_build_args import DockerBuildArgs\nfrom pants.engine.fs import Digest\nfrom pants.engine.process import (\n    BinaryNotFoundError,\n    BinaryPath,\n    BinaryPathRequest,\n    BinaryPaths,\n    BinaryPathTest,\n    Process,\n    SearchPath,\n)\nfrom pants.engine.rules import Get, collect_rules, rule\nfrom pants.util.logging import LogLevel\nfrom pants.util.strutil import pluralize\n\n\nclass DockerBinary(BinaryPath):\n    \"\"\"The `docker` binary.\"\"\"\n\n    DEFAULT_SEARCH_PATH = SearchPath((\"/usr/bin\", \"/bin\", \"/usr/local/bin\"))\n\n    def build_image(\n        self,\n        tags: tuple[str, ...],\n        digest: Digest,\n        dockerfile: str | None = None,\n        build_args: DockerBuildArgs | None = None,\n        env: Mapping[str, str] | None = None,\n    ) -> Process:\n        args = [self.path, \"build\"]\n\n        for tag in tags:\n            args.extend([\"-t\", tag])\n\n        if build_args:\n            for build_arg in build_args:\n                args.extend([\"--build-arg\", build_arg])\n\n        if dockerfile:\n            args.extend([\"-f\", dockerfile])\n\n        # Add build context root.\n        args.append(\".\")\n\n        return Process(\n            argv=tuple(args),\n            description=(\n                f\"Building docker image {tags[0]}\"\n                + (f\" +{pluralize(len(tags)-1, 'additional tag')}.\" if len(tags) > 1 else \".\")\n            ),\n            env=env,\n            input_digest=digest,\n        )\n\n    def push_image(self, tags: tuple[str, ...]) -> Process | None:\n        if not tags:\n            return None\n\n        return Process(\n            argv=(self.path, \"push\", *tags), description=\"Pushing docker image {tags[0]}\"\n        )\n\n\n@dataclass(frozen=True)\nclass DockerBinaryRequest:\n    search_path: SearchPath = DockerBinary.DEFAULT_SEARCH_PATH\n\n\n@rule(desc=\"Finding the `docker` binary\", level=LogLevel.DEBUG)\nasync def find_docker(docker_request: DockerBinaryRequest) -> DockerBinary:\n    request = BinaryPathRequest(\n        binary_name=\"docker\",\n        search_path=docker_request.search_path,\n        test=BinaryPathTest(args=[\"-v\"]),\n    )\n    paths = await Get(BinaryPaths, BinaryPathRequest, request)\n    first_path = paths.first_path\n    if not first_path:\n        raise BinaryNotFoundError.from_request(request, rationale=\"interact with the docker daemon\")\n    return DockerBinary(first_path.path, first_path.fingerprint)\n\n\n@rule\nasync def get_docker() -> DockerBinary:\n    return await Get(DockerBinary, DockerBinaryRequest())\n\n\ndef rules():\n    return collect_rules()\n", "path": "src/python/pants/backend/docker/util_rules/docker_binary.py"}]}