We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Local runner should write makefile to temporary dir
Instead, it writes it to the `root_uri` which might be an S3 URI, and `make`, which is used by the local runner cannot handle that.
Makefile error when `root_uri` is an S3 path
## 🐛 Bug
When running training command and having `root_uri` set to an S3 folder, this error shows up:
```
make: s3://<random_bucket_name>/predictions/Makefile: No such file or directory
make: *** No rule to make target 's3://<random_bucket_name>/predictions/Makefile'.  Stop.
```

This error disappears when `root_uri` is a local path. AWS config is right as it is able to read and write the files.

## To Reproduce

Steps to reproduce the behavior:

1. I ran the following command inside the container:
`python -m rastervision.pipeline.cli run local code/local_exp.py -a raw_uri s3://<random_bucket_name>/datafortesting/data/ -a root_uri s3://<random_bucket_name>/predictions -a test False`

<!-- Please provide the command executed, source of the get_config() function, error messages, and/or full stack traces if at all possible -->

## Expected behavior

It should run normally like it is running when `root_uri` is a local path.

## Environment

Running with docker.  **Image**: quay.io/azavea/raster-vision:pytorch-v0.13.1

## Additional context

This might be a relevant issue: #991 


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `rastervision_pipeline/rastervision/pipeline/runner/local_runner.py`
Content:
```
1 import sys
2 from os.path import dirname, join
3 from subprocess import Popen
4 
5 from rastervision.pipeline.file_system import str_to_file
6 from rastervision.pipeline.runner.runner import Runner
7 from rastervision.pipeline.utils import terminate_at_exit
8 
9 LOCAL = 'local'
10 
11 
12 class LocalRunner(Runner):
13     """Runs each command locally using different processes for each command/split.
14 
15     This is implemented by generating a Makefile and then running it using make.
16     """
17 
18     def run(self,
19             cfg_json_uri,
20             pipeline,
21             commands,
22             num_splits=1,
23             pipeline_run_name: str = 'raster-vision'):
24         num_commands = 0
25         for command in commands:
26             if command in pipeline.split_commands and num_splits > 1:
27                 num_commands += num_splits
28             else:
29                 num_commands += 1
30 
31         makefile = '.PHONY: '
32         makefile += ' '.join([str(ci) for ci in range(num_commands)])
33         makefile += '\n\n'
34 
35         makefile += 'all: '
36         makefile += ' '.join([str(ci) for ci in range(num_commands)])
37         makefile += '\n\n'
38 
39         prev_command_inds = []
40         curr_command_ind = 0
41         for command in commands:
42 
43             curr_command_inds = []
44             if command in pipeline.split_commands and num_splits > 1:
45                 for split_ind in range(num_splits):
46                     makefile += '{}: '.format(curr_command_ind)
47                     makefile += ' '.join([str(ci) for ci in prev_command_inds])
48                     makefile += '\n'
49                     invocation = (
50                         'python -m rastervision.pipeline.cli run_command '
51                         '{} {} --split-ind {} --num-splits {}').format(
52                             cfg_json_uri, command, split_ind, num_splits)
53                     makefile += '\t{}\n\n'.format(invocation)
54                     curr_command_inds.append(curr_command_ind)
55                     curr_command_ind += 1
56             else:
57                 makefile += '{}: '.format(curr_command_ind)
58                 makefile += ' '.join([str(ci) for ci in prev_command_inds])
59                 makefile += '\n'
60                 invocation = (
61                     'python -m rastervision.pipeline.cli run_command '
62                     '{} {}'.format(cfg_json_uri, command))
63                 makefile += '\t{}\n\n'.format(invocation)
64                 curr_command_inds.append(curr_command_ind)
65                 curr_command_ind += 1
66 
67             prev_command_inds = curr_command_inds
68 
69         makefile_path = join(dirname(cfg_json_uri), 'Makefile')
70         str_to_file(makefile, makefile_path)
71         process = Popen(['make', '-j', '-f', makefile_path])
72         terminate_at_exit(process)
73         exitcode = process.wait()
74         if exitcode != 0:
75             sys.exit(exitcode)
76         else:
77             return 0
78
```
--- 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()

```

diff --git a/rastervision_pipeline/rastervision/pipeline/runner/local_runner.py b/rastervision_pipeline/rastervision/pipeline/runner/local_runner.py
--- a/rastervision_pipeline/rastervision/pipeline/runner/local_runner.py
+++ b/rastervision_pipeline/rastervision/pipeline/runner/local_runner.py
@@ -2,7 +2,7 @@
 from os.path import dirname, join
 from subprocess import Popen
 
-from rastervision.pipeline.file_system import str_to_file
+from rastervision.pipeline.file_system import str_to_file, download_if_needed
 from rastervision.pipeline.runner.runner import Runner
 from rastervision.pipeline.utils import terminate_at_exit
 
@@ -68,7 +68,8 @@
 
         makefile_path = join(dirname(cfg_json_uri), 'Makefile')
         str_to_file(makefile, makefile_path)
-        process = Popen(['make', '-j', '-f', makefile_path])
+        makefile_path_local = download_if_needed(makefile_path)
+        process = Popen(['make', '-j', '-f', makefile_path_local])
         terminate_at_exit(process)
         exitcode = process.wait()
         if exitcode != 0:

{"golden_diff": "diff --git a/rastervision_pipeline/rastervision/pipeline/runner/local_runner.py b/rastervision_pipeline/rastervision/pipeline/runner/local_runner.py\n--- a/rastervision_pipeline/rastervision/pipeline/runner/local_runner.py\n+++ b/rastervision_pipeline/rastervision/pipeline/runner/local_runner.py\n@@ -2,7 +2,7 @@\n from os.path import dirname, join\n from subprocess import Popen\n \n-from rastervision.pipeline.file_system import str_to_file\n+from rastervision.pipeline.file_system import str_to_file, download_if_needed\n from rastervision.pipeline.runner.runner import Runner\n from rastervision.pipeline.utils import terminate_at_exit\n \n@@ -68,7 +68,8 @@\n \n         makefile_path = join(dirname(cfg_json_uri), 'Makefile')\n         str_to_file(makefile, makefile_path)\n-        process = Popen(['make', '-j', '-f', makefile_path])\n+        makefile_path_local = download_if_needed(makefile_path)\n+        process = Popen(['make', '-j', '-f', makefile_path_local])\n         terminate_at_exit(process)\n         exitcode = process.wait()\n         if exitcode != 0:\n", "issue": "Local runner should write makefile to temporary dir\nInstead, it writes it to the `root_uri` which might be an S3 URI, and `make`, which is used by the local runner cannot handle that.\nMakefile error when `root_uri` is an S3 path\n## \ud83d\udc1b Bug\r\nWhen running training command and having `root_uri` set to an S3 folder, this error shows up:\r\n```\r\nmake: s3://<random_bucket_name>/predictions/Makefile: No such file or directory\r\nmake: *** No rule to make target 's3://<random_bucket_name>/predictions/Makefile'.  Stop.\r\n```\r\n\r\nThis error disappears when `root_uri` is a local path. AWS config is right as it is able to read and write the files.\r\n\r\n## To Reproduce\r\n\r\nSteps to reproduce the behavior:\r\n\r\n1. I ran the following command inside the container:\r\n`python -m rastervision.pipeline.cli run local code/local_exp.py -a raw_uri s3://<random_bucket_name>/datafortesting/data/ -a root_uri s3://<random_bucket_name>/predictions -a test False`\r\n\r\n<!-- Please provide the command executed, source of the get_config() function, error messages, and/or full stack traces if at all possible -->\r\n\r\n## Expected behavior\r\n\r\nIt should run normally like it is running when `root_uri` is a local path.\r\n\r\n## Environment\r\n\r\nRunning with docker.  **Image**: quay.io/azavea/raster-vision:pytorch-v0.13.1\r\n\r\n## Additional context\r\n\r\nThis might be a relevant issue: #991 \r\n\n", "before_files": [{"content": "import sys\nfrom os.path import dirname, join\nfrom subprocess import Popen\n\nfrom rastervision.pipeline.file_system import str_to_file\nfrom rastervision.pipeline.runner.runner import Runner\nfrom rastervision.pipeline.utils import terminate_at_exit\n\nLOCAL = 'local'\n\n\nclass LocalRunner(Runner):\n    \"\"\"Runs each command locally using different processes for each command/split.\n\n    This is implemented by generating a Makefile and then running it using make.\n    \"\"\"\n\n    def run(self,\n            cfg_json_uri,\n            pipeline,\n            commands,\n            num_splits=1,\n            pipeline_run_name: str = 'raster-vision'):\n        num_commands = 0\n        for command in commands:\n            if command in pipeline.split_commands and num_splits > 1:\n                num_commands += num_splits\n            else:\n                num_commands += 1\n\n        makefile = '.PHONY: '\n        makefile += ' '.join([str(ci) for ci in range(num_commands)])\n        makefile += '\\n\\n'\n\n        makefile += 'all: '\n        makefile += ' '.join([str(ci) for ci in range(num_commands)])\n        makefile += '\\n\\n'\n\n        prev_command_inds = []\n        curr_command_ind = 0\n        for command in commands:\n\n            curr_command_inds = []\n            if command in pipeline.split_commands and num_splits > 1:\n                for split_ind in range(num_splits):\n                    makefile += '{}: '.format(curr_command_ind)\n                    makefile += ' '.join([str(ci) for ci in prev_command_inds])\n                    makefile += '\\n'\n                    invocation = (\n                        'python -m rastervision.pipeline.cli run_command '\n                        '{} {} --split-ind {} --num-splits {}').format(\n                            cfg_json_uri, command, split_ind, num_splits)\n                    makefile += '\\t{}\\n\\n'.format(invocation)\n                    curr_command_inds.append(curr_command_ind)\n                    curr_command_ind += 1\n            else:\n                makefile += '{}: '.format(curr_command_ind)\n                makefile += ' '.join([str(ci) for ci in prev_command_inds])\n                makefile += '\\n'\n                invocation = (\n                    'python -m rastervision.pipeline.cli run_command '\n                    '{} {}'.format(cfg_json_uri, command))\n                makefile += '\\t{}\\n\\n'.format(invocation)\n                curr_command_inds.append(curr_command_ind)\n                curr_command_ind += 1\n\n            prev_command_inds = curr_command_inds\n\n        makefile_path = join(dirname(cfg_json_uri), 'Makefile')\n        str_to_file(makefile, makefile_path)\n        process = Popen(['make', '-j', '-f', makefile_path])\n        terminate_at_exit(process)\n        exitcode = process.wait()\n        if exitcode != 0:\n            sys.exit(exitcode)\n        else:\n            return 0\n", "path": "rastervision_pipeline/rastervision/pipeline/runner/local_runner.py"}], "after_files": [{"content": "import sys\nfrom os.path import dirname, join\nfrom subprocess import Popen\n\nfrom rastervision.pipeline.file_system import str_to_file, download_if_needed\nfrom rastervision.pipeline.runner.runner import Runner\nfrom rastervision.pipeline.utils import terminate_at_exit\n\nLOCAL = 'local'\n\n\nclass LocalRunner(Runner):\n    \"\"\"Runs each command locally using different processes for each command/split.\n\n    This is implemented by generating a Makefile and then running it using make.\n    \"\"\"\n\n    def run(self,\n            cfg_json_uri,\n            pipeline,\n            commands,\n            num_splits=1,\n            pipeline_run_name: str = 'raster-vision'):\n        num_commands = 0\n        for command in commands:\n            if command in pipeline.split_commands and num_splits > 1:\n                num_commands += num_splits\n            else:\n                num_commands += 1\n\n        makefile = '.PHONY: '\n        makefile += ' '.join([str(ci) for ci in range(num_commands)])\n        makefile += '\\n\\n'\n\n        makefile += 'all: '\n        makefile += ' '.join([str(ci) for ci in range(num_commands)])\n        makefile += '\\n\\n'\n\n        prev_command_inds = []\n        curr_command_ind = 0\n        for command in commands:\n\n            curr_command_inds = []\n            if command in pipeline.split_commands and num_splits > 1:\n                for split_ind in range(num_splits):\n                    makefile += '{}: '.format(curr_command_ind)\n                    makefile += ' '.join([str(ci) for ci in prev_command_inds])\n                    makefile += '\\n'\n                    invocation = (\n                        'python -m rastervision.pipeline.cli run_command '\n                        '{} {} --split-ind {} --num-splits {}').format(\n                            cfg_json_uri, command, split_ind, num_splits)\n                    makefile += '\\t{}\\n\\n'.format(invocation)\n                    curr_command_inds.append(curr_command_ind)\n                    curr_command_ind += 1\n            else:\n                makefile += '{}: '.format(curr_command_ind)\n                makefile += ' '.join([str(ci) for ci in prev_command_inds])\n                makefile += '\\n'\n                invocation = (\n                    'python -m rastervision.pipeline.cli run_command '\n                    '{} {}'.format(cfg_json_uri, command))\n                makefile += '\\t{}\\n\\n'.format(invocation)\n                curr_command_inds.append(curr_command_ind)\n                curr_command_ind += 1\n\n            prev_command_inds = curr_command_inds\n\n        makefile_path = join(dirname(cfg_json_uri), 'Makefile')\n        str_to_file(makefile, makefile_path)\n        makefile_path_local = download_if_needed(makefile_path)\n        process = Popen(['make', '-j', '-f', makefile_path_local])\n        terminate_at_exit(process)\n        exitcode = process.wait()\n        if exitcode != 0:\n            sys.exit(exitcode)\n        else:\n            return 0\n", "path": "rastervision_pipeline/rastervision/pipeline/runner/local_runner.py"}]}