We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Add "set_value" method to CIME.BuildTools.configure.FakeCase so that user can add needed variables
In principle this is a simple change, but I want to make sure it's acceptable. I'd like to add a set_value method to the FakeCase class in CIME.BuiltTools.configure so that the user can add the variables they want to have in their FakeCase. The utility I see is for unit-testing of buildnml. But, I think there may be other cases where you want to create a simpler Fake case without doing all the normal needed setup to create a real case. There are some offline scripts we are thinking about having this kind of utility where we know we need to setup some type of fake case, but we want to hide it from the user, and it doesn't need to be fully functional like a real case.

``` python
diff --git a/scripts/lib/CIME/BuildTools/configure.py b/scripts/lib/CIME/BuildTools/configure.py
index a74c087a5..fd7067ed7 100644
--- a/scripts/lib/CIME/BuildTools/configure.py
+++ b/scripts/lib/CIME/BuildTools/configure.py
@@ -74,6 +74,9 @@ def get_value(self, attrib):
         expect(attrib in self._vals, "FakeCase does not support getting value of '%s'" % attrib)
         return self._vals[attrib]
 
+    def set_value(self, attrib, value):
+       self._vals[attrib] = value
+
 def _generate_env_mach_specific(output_dir, machobj, compiler, mpilib, debug,
                                 sysos, unit_testing):
     """
```

@jedwards4b does this sound acceptable? If so I'll submit a simple PR for it.
@billsacks would this kind of thing possibly make LILAC easier to setup?
Add "set_value" method to CIME.BuildTools.configure.FakeCase so that user can add needed variables
In principle this is a simple change, but I want to make sure it's acceptable. I'd like to add a set_value method to the FakeCase class in CIME.BuiltTools.configure so that the user can add the variables they want to have in their FakeCase. The utility I see is for unit-testing of buildnml. But, I think there may be other cases where you want to create a simpler Fake case without doing all the normal needed setup to create a real case. There are some offline scripts we are thinking about having this kind of utility where we know we need to setup some type of fake case, but we want to hide it from the user, and it doesn't need to be fully functional like a real case.

``` python
diff --git a/scripts/lib/CIME/BuildTools/configure.py b/scripts/lib/CIME/BuildTools/configure.py
index a74c087a5..fd7067ed7 100644
--- a/scripts/lib/CIME/BuildTools/configure.py
+++ b/scripts/lib/CIME/BuildTools/configure.py
@@ -74,6 +74,9 @@ def get_value(self, attrib):
         expect(attrib in self._vals, "FakeCase does not support getting value of '%s'" % attrib)
         return self._vals[attrib]
 
+    def set_value(self, attrib, value):
+       self._vals[attrib] = value
+
 def _generate_env_mach_specific(output_dir, machobj, compiler, mpilib, debug,
                                 sysos, unit_testing):
     """
```

@jedwards4b does this sound acceptable? If so I'll submit a simple PR for it.
@billsacks would this kind of thing possibly make LILAC easier to setup?

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `CIME/BuildTools/configure.py`
Content:
```
1 #!/usr/bin/env python3
2 
3 """This script writes CIME build information to a directory.
4 
5 The pieces of information that will be written include:
6 
7 1. Machine-specific build settings (i.e. the "Macros" file).
8 2. File-specific build settings (i.e. "Depends" files).
9 3. Environment variable loads (i.e. the env_mach_specific files).
10 
11 The .env_mach_specific.sh and .env_mach_specific.csh files are specific to a
12 given compiler, MPI library, and DEBUG setting. By default, these will be the
13 machine's default compiler, the machine's default MPI library, and FALSE,
14 respectively. These can be changed by setting the environment variables
15 COMPILER, MPILIB, and DEBUG, respectively.
16 """
17 
18 from CIME.XML.standard_module_setup import *
19 from CIME.utils import (
20     expect,
21     safe_copy,
22     get_model,
23     get_src_root,
24     stringify_bool,
25     copy_local_macros_to_dir,
26 )
27 from CIME.XML.env_mach_specific import EnvMachSpecific
28 from CIME.XML.files import Files
29 from CIME.build import CmakeTmpBuildDir
30 
31 import shutil
32 
33 logger = logging.getLogger(__name__)
34 
35 
36 def configure(
37     machobj,
38     output_dir,
39     macros_format,
40     compiler,
41     mpilib,
42     debug,
43     comp_interface,
44     sysos,
45     unit_testing=False,
46     noenv=False,
47     threaded=False,
48     extra_machines_dir=None,
49 ):
50     """Add Macros, Depends, and env_mach_specific files to a directory.
51 
52     Arguments:
53     machobj - Machines argument for this machine.
54     output_dir - Directory in which to place output.
55     macros_format - Container containing the string 'Makefile' to produce
56                     Makefile Macros output, and/or 'CMake' for CMake output.
57     compiler - String containing the compiler vendor to configure for.
58     mpilib - String containing the MPI implementation to configure for.
59     debug - Boolean specifying whether debugging options are enabled.
60     unit_testing - Boolean specifying whether we're running unit tests (as
61                    opposed to a system run)
62     extra_machines_dir - String giving path to an additional directory that will be
63                          searched for cmake_macros.
64     """
65     new_cmake_macros_dir = Files(comp_interface=comp_interface).get_value(
66         "CMAKE_MACROS_DIR"
67     )
68     for form in macros_format:
69 
70         if not os.path.isfile(os.path.join(output_dir, "Macros.cmake")):
71             safe_copy(os.path.join(new_cmake_macros_dir, "Macros.cmake"), output_dir)
72         output_cmake_macros_dir = os.path.join(output_dir, "cmake_macros")
73         if not os.path.exists(output_cmake_macros_dir):
74             shutil.copytree(new_cmake_macros_dir, output_cmake_macros_dir)
75 
76         copy_local_macros_to_dir(
77             output_cmake_macros_dir, extra_machdir=extra_machines_dir
78         )
79 
80         if form == "Makefile":
81             # Use the cmake macros to generate the make macros
82             cmake_args = " -DOS={} -DMACH={} -DCOMPILER={} -DDEBUG={} -DMPILIB={} -Dcompile_threaded={} -DCASEROOT={}".format(
83                 sysos,
84                 machobj.get_machine_name(),
85                 compiler,
86                 stringify_bool(debug),
87                 mpilib,
88                 stringify_bool(threaded),
89                 output_dir,
90             )
91 
92             with CmakeTmpBuildDir(macroloc=output_dir) as cmaketmp:
93                 output = cmaketmp.get_makefile_vars(cmake_args=cmake_args)
94 
95             with open(os.path.join(output_dir, "Macros.make"), "w") as fd:
96                 fd.write(output)
97 
98     copy_depends_files(
99         machobj.get_machine_name(), machobj.machines_dir, output_dir, compiler
100     )
101     generate_env_mach_specific(
102         output_dir,
103         machobj,
104         compiler,
105         mpilib,
106         debug,
107         comp_interface,
108         sysos,
109         unit_testing,
110         threaded,
111         noenv=noenv,
112     )
113 
114 
115 def copy_depends_files(machine_name, machines_dir, output_dir, compiler):
116     """
117     Copy any system or compiler Depends files if they do not exist in the output directory
118     If there is a match for Depends.machine_name.compiler copy that and ignore the others
119     """
120     # Note, the cmake build system does not stop if Depends.mach.compiler.cmake is found
121     makefiles_done = False
122     both = "{}.{}".format(machine_name, compiler)
123     for suffix in [both, machine_name, compiler]:
124         for extra_suffix in ["", ".cmake"]:
125             if extra_suffix == "" and makefiles_done:
126                 continue
127 
128             basename = "Depends.{}{}".format(suffix, extra_suffix)
129             dfile = os.path.join(machines_dir, basename)
130             outputdfile = os.path.join(output_dir, basename)
131             if os.path.isfile(dfile):
132                 if suffix == both and extra_suffix == "":
133                     makefiles_done = True
134                 if not os.path.exists(outputdfile):
135                     safe_copy(dfile, outputdfile)
136 
137 
138 class FakeCase(object):
139     def __init__(self, compiler, mpilib, debug, comp_interface, threading=False):
140         # PIO_VERSION is needed to parse config_machines.xml but isn't otherwise used
141         # by FakeCase
142         self._vals = {
143             "COMPILER": compiler,
144             "MPILIB": mpilib,
145             "DEBUG": debug,
146             "COMP_INTERFACE": comp_interface,
147             "PIO_VERSION": 2,
148             "SMP_PRESENT": threading,
149             "MODEL": get_model(),
150             "SRCROOT": get_src_root(),
151         }
152 
153     def get_build_threaded(self):
154         return self.get_value("SMP_PRESENT")
155 
156     def get_value(self, attrib):
157         expect(
158             attrib in self._vals,
159             "FakeCase does not support getting value of '%s'" % attrib,
160         )
161         return self._vals[attrib]
162 
163 
164 def generate_env_mach_specific(
165     output_dir,
166     machobj,
167     compiler,
168     mpilib,
169     debug,
170     comp_interface,
171     sysos,
172     unit_testing,
173     threaded,
174     noenv=False,
175 ):
176     """
177     env_mach_specific generation.
178     """
179     ems_path = os.path.join(output_dir, "env_mach_specific.xml")
180     if os.path.exists(ems_path):
181         logger.warning("{} already exists, delete to replace".format(ems_path))
182         return
183 
184     ems_file = EnvMachSpecific(
185         output_dir, unit_testing=unit_testing, standalone_configure=True
186     )
187     ems_file.populate(
188         machobj,
189         attributes={"mpilib": mpilib, "compiler": compiler, "threaded": threaded},
190     )
191     ems_file.write()
192 
193     if noenv:
194         return
195 
196     fake_case = FakeCase(compiler, mpilib, debug, comp_interface)
197     ems_file.load_env(fake_case)
198     for shell in ("sh", "csh"):
199         ems_file.make_env_mach_specific_file(shell, fake_case, output_dir=output_dir)
200         shell_path = os.path.join(output_dir, ".env_mach_specific." + shell)
201         with open(shell_path, "a") as shell_file:
202             if shell == "sh":
203                 shell_file.write("\nexport COMPILER={}\n".format(compiler))
204                 shell_file.write("export MPILIB={}\n".format(mpilib))
205                 shell_file.write("export DEBUG={}\n".format(repr(debug).upper()))
206                 shell_file.write("export OS={}\n".format(sysos))
207             else:
208                 shell_file.write("\nsetenv COMPILER {}\n".format(compiler))
209                 shell_file.write("setenv MPILIB {}\n".format(mpilib))
210                 shell_file.write("setenv DEBUG {}\n".format(repr(debug).upper()))
211                 shell_file.write("setenv OS {}\n".format(sysos))
212
```
--- 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/CIME/BuildTools/configure.py b/CIME/BuildTools/configure.py
--- a/CIME/BuildTools/configure.py
+++ b/CIME/BuildTools/configure.py
@@ -153,6 +153,10 @@
     def get_build_threaded(self):
         return self.get_value("SMP_PRESENT")
 
+    def get_case_root(self):
+        """Returns the root directory for this case."""
+        return self.get_value("CASEROOT")
+
     def get_value(self, attrib):
         expect(
             attrib in self._vals,
@@ -160,6 +164,10 @@
         )
         return self._vals[attrib]
 
+    def set_value(self, attrib, value):
+        """Sets a given variable value for the case"""
+        self._vals[attrib] = value
+
 
 def generate_env_mach_specific(
     output_dir,

{"golden_diff": "diff --git a/CIME/BuildTools/configure.py b/CIME/BuildTools/configure.py\n--- a/CIME/BuildTools/configure.py\n+++ b/CIME/BuildTools/configure.py\n@@ -153,6 +153,10 @@\n     def get_build_threaded(self):\n         return self.get_value(\"SMP_PRESENT\")\n \n+    def get_case_root(self):\n+        \"\"\"Returns the root directory for this case.\"\"\"\n+        return self.get_value(\"CASEROOT\")\n+\n     def get_value(self, attrib):\n         expect(\n             attrib in self._vals,\n@@ -160,6 +164,10 @@\n         )\n         return self._vals[attrib]\n \n+    def set_value(self, attrib, value):\n+        \"\"\"Sets a given variable value for the case\"\"\"\n+        self._vals[attrib] = value\n+\n \n def generate_env_mach_specific(\n     output_dir,\n", "issue": "Add \"set_value\" method to CIME.BuildTools.configure.FakeCase so that user can add needed variables\nIn principle this is a simple change, but I want to make sure it's acceptable. I'd like to add a set_value method to the FakeCase class in CIME.BuiltTools.configure so that the user can add the variables they want to have in their FakeCase. The utility I see is for unit-testing of buildnml. But, I think there may be other cases where you want to create a simpler Fake case without doing all the normal needed setup to create a real case. There are some offline scripts we are thinking about having this kind of utility where we know we need to setup some type of fake case, but we want to hide it from the user, and it doesn't need to be fully functional like a real case.\r\n\r\n``` python\r\ndiff --git a/scripts/lib/CIME/BuildTools/configure.py b/scripts/lib/CIME/BuildTools/configure.py\r\nindex a74c087a5..fd7067ed7 100644\r\n--- a/scripts/lib/CIME/BuildTools/configure.py\r\n+++ b/scripts/lib/CIME/BuildTools/configure.py\r\n@@ -74,6 +74,9 @@ def get_value(self, attrib):\r\n         expect(attrib in self._vals, \"FakeCase does not support getting value of '%s'\" % attrib)\r\n         return self._vals[attrib]\r\n \r\n+    def set_value(self, attrib, value):\r\n+       self._vals[attrib] = value\r\n+\r\n def _generate_env_mach_specific(output_dir, machobj, compiler, mpilib, debug,\r\n                                 sysos, unit_testing):\r\n     \"\"\"\r\n```\r\n\r\n@jedwards4b does this sound acceptable? If so I'll submit a simple PR for it.\r\n@billsacks would this kind of thing possibly make LILAC easier to setup?\nAdd \"set_value\" method to CIME.BuildTools.configure.FakeCase so that user can add needed variables\nIn principle this is a simple change, but I want to make sure it's acceptable. I'd like to add a set_value method to the FakeCase class in CIME.BuiltTools.configure so that the user can add the variables they want to have in their FakeCase. The utility I see is for unit-testing of buildnml. But, I think there may be other cases where you want to create a simpler Fake case without doing all the normal needed setup to create a real case. There are some offline scripts we are thinking about having this kind of utility where we know we need to setup some type of fake case, but we want to hide it from the user, and it doesn't need to be fully functional like a real case.\r\n\r\n``` python\r\ndiff --git a/scripts/lib/CIME/BuildTools/configure.py b/scripts/lib/CIME/BuildTools/configure.py\r\nindex a74c087a5..fd7067ed7 100644\r\n--- a/scripts/lib/CIME/BuildTools/configure.py\r\n+++ b/scripts/lib/CIME/BuildTools/configure.py\r\n@@ -74,6 +74,9 @@ def get_value(self, attrib):\r\n         expect(attrib in self._vals, \"FakeCase does not support getting value of '%s'\" % attrib)\r\n         return self._vals[attrib]\r\n \r\n+    def set_value(self, attrib, value):\r\n+       self._vals[attrib] = value\r\n+\r\n def _generate_env_mach_specific(output_dir, machobj, compiler, mpilib, debug,\r\n                                 sysos, unit_testing):\r\n     \"\"\"\r\n```\r\n\r\n@jedwards4b does this sound acceptable? If so I'll submit a simple PR for it.\r\n@billsacks would this kind of thing possibly make LILAC easier to setup?\n", "before_files": [{"content": "#!/usr/bin/env python3\n\n\"\"\"This script writes CIME build information to a directory.\n\nThe pieces of information that will be written include:\n\n1. Machine-specific build settings (i.e. the \"Macros\" file).\n2. File-specific build settings (i.e. \"Depends\" files).\n3. Environment variable loads (i.e. the env_mach_specific files).\n\nThe .env_mach_specific.sh and .env_mach_specific.csh files are specific to a\ngiven compiler, MPI library, and DEBUG setting. By default, these will be the\nmachine's default compiler, the machine's default MPI library, and FALSE,\nrespectively. These can be changed by setting the environment variables\nCOMPILER, MPILIB, and DEBUG, respectively.\n\"\"\"\n\nfrom CIME.XML.standard_module_setup import *\nfrom CIME.utils import (\n    expect,\n    safe_copy,\n    get_model,\n    get_src_root,\n    stringify_bool,\n    copy_local_macros_to_dir,\n)\nfrom CIME.XML.env_mach_specific import EnvMachSpecific\nfrom CIME.XML.files import Files\nfrom CIME.build import CmakeTmpBuildDir\n\nimport shutil\n\nlogger = logging.getLogger(__name__)\n\n\ndef configure(\n    machobj,\n    output_dir,\n    macros_format,\n    compiler,\n    mpilib,\n    debug,\n    comp_interface,\n    sysos,\n    unit_testing=False,\n    noenv=False,\n    threaded=False,\n    extra_machines_dir=None,\n):\n    \"\"\"Add Macros, Depends, and env_mach_specific files to a directory.\n\n    Arguments:\n    machobj - Machines argument for this machine.\n    output_dir - Directory in which to place output.\n    macros_format - Container containing the string 'Makefile' to produce\n                    Makefile Macros output, and/or 'CMake' for CMake output.\n    compiler - String containing the compiler vendor to configure for.\n    mpilib - String containing the MPI implementation to configure for.\n    debug - Boolean specifying whether debugging options are enabled.\n    unit_testing - Boolean specifying whether we're running unit tests (as\n                   opposed to a system run)\n    extra_machines_dir - String giving path to an additional directory that will be\n                         searched for cmake_macros.\n    \"\"\"\n    new_cmake_macros_dir = Files(comp_interface=comp_interface).get_value(\n        \"CMAKE_MACROS_DIR\"\n    )\n    for form in macros_format:\n\n        if not os.path.isfile(os.path.join(output_dir, \"Macros.cmake\")):\n            safe_copy(os.path.join(new_cmake_macros_dir, \"Macros.cmake\"), output_dir)\n        output_cmake_macros_dir = os.path.join(output_dir, \"cmake_macros\")\n        if not os.path.exists(output_cmake_macros_dir):\n            shutil.copytree(new_cmake_macros_dir, output_cmake_macros_dir)\n\n        copy_local_macros_to_dir(\n            output_cmake_macros_dir, extra_machdir=extra_machines_dir\n        )\n\n        if form == \"Makefile\":\n            # Use the cmake macros to generate the make macros\n            cmake_args = \" -DOS={} -DMACH={} -DCOMPILER={} -DDEBUG={} -DMPILIB={} -Dcompile_threaded={} -DCASEROOT={}\".format(\n                sysos,\n                machobj.get_machine_name(),\n                compiler,\n                stringify_bool(debug),\n                mpilib,\n                stringify_bool(threaded),\n                output_dir,\n            )\n\n            with CmakeTmpBuildDir(macroloc=output_dir) as cmaketmp:\n                output = cmaketmp.get_makefile_vars(cmake_args=cmake_args)\n\n            with open(os.path.join(output_dir, \"Macros.make\"), \"w\") as fd:\n                fd.write(output)\n\n    copy_depends_files(\n        machobj.get_machine_name(), machobj.machines_dir, output_dir, compiler\n    )\n    generate_env_mach_specific(\n        output_dir,\n        machobj,\n        compiler,\n        mpilib,\n        debug,\n        comp_interface,\n        sysos,\n        unit_testing,\n        threaded,\n        noenv=noenv,\n    )\n\n\ndef copy_depends_files(machine_name, machines_dir, output_dir, compiler):\n    \"\"\"\n    Copy any system or compiler Depends files if they do not exist in the output directory\n    If there is a match for Depends.machine_name.compiler copy that and ignore the others\n    \"\"\"\n    # Note, the cmake build system does not stop if Depends.mach.compiler.cmake is found\n    makefiles_done = False\n    both = \"{}.{}\".format(machine_name, compiler)\n    for suffix in [both, machine_name, compiler]:\n        for extra_suffix in [\"\", \".cmake\"]:\n            if extra_suffix == \"\" and makefiles_done:\n                continue\n\n            basename = \"Depends.{}{}\".format(suffix, extra_suffix)\n            dfile = os.path.join(machines_dir, basename)\n            outputdfile = os.path.join(output_dir, basename)\n            if os.path.isfile(dfile):\n                if suffix == both and extra_suffix == \"\":\n                    makefiles_done = True\n                if not os.path.exists(outputdfile):\n                    safe_copy(dfile, outputdfile)\n\n\nclass FakeCase(object):\n    def __init__(self, compiler, mpilib, debug, comp_interface, threading=False):\n        # PIO_VERSION is needed to parse config_machines.xml but isn't otherwise used\n        # by FakeCase\n        self._vals = {\n            \"COMPILER\": compiler,\n            \"MPILIB\": mpilib,\n            \"DEBUG\": debug,\n            \"COMP_INTERFACE\": comp_interface,\n            \"PIO_VERSION\": 2,\n            \"SMP_PRESENT\": threading,\n            \"MODEL\": get_model(),\n            \"SRCROOT\": get_src_root(),\n        }\n\n    def get_build_threaded(self):\n        return self.get_value(\"SMP_PRESENT\")\n\n    def get_value(self, attrib):\n        expect(\n            attrib in self._vals,\n            \"FakeCase does not support getting value of '%s'\" % attrib,\n        )\n        return self._vals[attrib]\n\n\ndef generate_env_mach_specific(\n    output_dir,\n    machobj,\n    compiler,\n    mpilib,\n    debug,\n    comp_interface,\n    sysos,\n    unit_testing,\n    threaded,\n    noenv=False,\n):\n    \"\"\"\n    env_mach_specific generation.\n    \"\"\"\n    ems_path = os.path.join(output_dir, \"env_mach_specific.xml\")\n    if os.path.exists(ems_path):\n        logger.warning(\"{} already exists, delete to replace\".format(ems_path))\n        return\n\n    ems_file = EnvMachSpecific(\n        output_dir, unit_testing=unit_testing, standalone_configure=True\n    )\n    ems_file.populate(\n        machobj,\n        attributes={\"mpilib\": mpilib, \"compiler\": compiler, \"threaded\": threaded},\n    )\n    ems_file.write()\n\n    if noenv:\n        return\n\n    fake_case = FakeCase(compiler, mpilib, debug, comp_interface)\n    ems_file.load_env(fake_case)\n    for shell in (\"sh\", \"csh\"):\n        ems_file.make_env_mach_specific_file(shell, fake_case, output_dir=output_dir)\n        shell_path = os.path.join(output_dir, \".env_mach_specific.\" + shell)\n        with open(shell_path, \"a\") as shell_file:\n            if shell == \"sh\":\n                shell_file.write(\"\\nexport COMPILER={}\\n\".format(compiler))\n                shell_file.write(\"export MPILIB={}\\n\".format(mpilib))\n                shell_file.write(\"export DEBUG={}\\n\".format(repr(debug).upper()))\n                shell_file.write(\"export OS={}\\n\".format(sysos))\n            else:\n                shell_file.write(\"\\nsetenv COMPILER {}\\n\".format(compiler))\n                shell_file.write(\"setenv MPILIB {}\\n\".format(mpilib))\n                shell_file.write(\"setenv DEBUG {}\\n\".format(repr(debug).upper()))\n                shell_file.write(\"setenv OS {}\\n\".format(sysos))\n", "path": "CIME/BuildTools/configure.py"}], "after_files": [{"content": "#!/usr/bin/env python3\n\n\"\"\"This script writes CIME build information to a directory.\n\nThe pieces of information that will be written include:\n\n1. Machine-specific build settings (i.e. the \"Macros\" file).\n2. File-specific build settings (i.e. \"Depends\" files).\n3. Environment variable loads (i.e. the env_mach_specific files).\n\nThe .env_mach_specific.sh and .env_mach_specific.csh files are specific to a\ngiven compiler, MPI library, and DEBUG setting. By default, these will be the\nmachine's default compiler, the machine's default MPI library, and FALSE,\nrespectively. These can be changed by setting the environment variables\nCOMPILER, MPILIB, and DEBUG, respectively.\n\"\"\"\n\nfrom CIME.XML.standard_module_setup import *\nfrom CIME.utils import (\n    expect,\n    safe_copy,\n    get_model,\n    get_src_root,\n    stringify_bool,\n    copy_local_macros_to_dir,\n)\nfrom CIME.XML.env_mach_specific import EnvMachSpecific\nfrom CIME.XML.files import Files\nfrom CIME.build import CmakeTmpBuildDir\n\nimport shutil\n\nlogger = logging.getLogger(__name__)\n\n\ndef configure(\n    machobj,\n    output_dir,\n    macros_format,\n    compiler,\n    mpilib,\n    debug,\n    comp_interface,\n    sysos,\n    unit_testing=False,\n    noenv=False,\n    threaded=False,\n    extra_machines_dir=None,\n):\n    \"\"\"Add Macros, Depends, and env_mach_specific files to a directory.\n\n    Arguments:\n    machobj - Machines argument for this machine.\n    output_dir - Directory in which to place output.\n    macros_format - Container containing the string 'Makefile' to produce\n                    Makefile Macros output, and/or 'CMake' for CMake output.\n    compiler - String containing the compiler vendor to configure for.\n    mpilib - String containing the MPI implementation to configure for.\n    debug - Boolean specifying whether debugging options are enabled.\n    unit_testing - Boolean specifying whether we're running unit tests (as\n                   opposed to a system run)\n    extra_machines_dir - String giving path to an additional directory that will be\n                         searched for cmake_macros.\n    \"\"\"\n    new_cmake_macros_dir = Files(comp_interface=comp_interface).get_value(\n        \"CMAKE_MACROS_DIR\"\n    )\n    for form in macros_format:\n\n        if not os.path.isfile(os.path.join(output_dir, \"Macros.cmake\")):\n            safe_copy(os.path.join(new_cmake_macros_dir, \"Macros.cmake\"), output_dir)\n        output_cmake_macros_dir = os.path.join(output_dir, \"cmake_macros\")\n        if not os.path.exists(output_cmake_macros_dir):\n            shutil.copytree(new_cmake_macros_dir, output_cmake_macros_dir)\n\n        copy_local_macros_to_dir(\n            output_cmake_macros_dir, extra_machdir=extra_machines_dir\n        )\n\n        if form == \"Makefile\":\n            # Use the cmake macros to generate the make macros\n            cmake_args = \" -DOS={} -DMACH={} -DCOMPILER={} -DDEBUG={} -DMPILIB={} -Dcompile_threaded={} -DCASEROOT={}\".format(\n                sysos,\n                machobj.get_machine_name(),\n                compiler,\n                stringify_bool(debug),\n                mpilib,\n                stringify_bool(threaded),\n                output_dir,\n            )\n\n            with CmakeTmpBuildDir(macroloc=output_dir) as cmaketmp:\n                output = cmaketmp.get_makefile_vars(cmake_args=cmake_args)\n\n            with open(os.path.join(output_dir, \"Macros.make\"), \"w\") as fd:\n                fd.write(output)\n\n    copy_depends_files(\n        machobj.get_machine_name(), machobj.machines_dir, output_dir, compiler\n    )\n    generate_env_mach_specific(\n        output_dir,\n        machobj,\n        compiler,\n        mpilib,\n        debug,\n        comp_interface,\n        sysos,\n        unit_testing,\n        threaded,\n        noenv=noenv,\n    )\n\n\ndef copy_depends_files(machine_name, machines_dir, output_dir, compiler):\n    \"\"\"\n    Copy any system or compiler Depends files if they do not exist in the output directory\n    If there is a match for Depends.machine_name.compiler copy that and ignore the others\n    \"\"\"\n    # Note, the cmake build system does not stop if Depends.mach.compiler.cmake is found\n    makefiles_done = False\n    both = \"{}.{}\".format(machine_name, compiler)\n    for suffix in [both, machine_name, compiler]:\n        for extra_suffix in [\"\", \".cmake\"]:\n            if extra_suffix == \"\" and makefiles_done:\n                continue\n\n            basename = \"Depends.{}{}\".format(suffix, extra_suffix)\n            dfile = os.path.join(machines_dir, basename)\n            outputdfile = os.path.join(output_dir, basename)\n            if os.path.isfile(dfile):\n                if suffix == both and extra_suffix == \"\":\n                    makefiles_done = True\n                if not os.path.exists(outputdfile):\n                    safe_copy(dfile, outputdfile)\n\n\nclass FakeCase(object):\n    def __init__(self, compiler, mpilib, debug, comp_interface, threading=False):\n        # PIO_VERSION is needed to parse config_machines.xml but isn't otherwise used\n        # by FakeCase\n        self._vals = {\n            \"COMPILER\": compiler,\n            \"MPILIB\": mpilib,\n            \"DEBUG\": debug,\n            \"COMP_INTERFACE\": comp_interface,\n            \"PIO_VERSION\": 2,\n            \"SMP_PRESENT\": threading,\n            \"MODEL\": get_model(),\n            \"SRCROOT\": get_src_root(),\n        }\n\n    def get_build_threaded(self):\n        return self.get_value(\"SMP_PRESENT\")\n\n    def get_case_root(self):\n        \"\"\"Returns the root directory for this case.\"\"\"\n        return self.get_value(\"CASEROOT\")\n\n    def get_value(self, attrib):\n        expect(\n            attrib in self._vals,\n            \"FakeCase does not support getting value of '%s'\" % attrib,\n        )\n        return self._vals[attrib]\n\n    def set_value(self, attrib, value):\n        \"\"\"Sets a given variable value for the case\"\"\"\n        self._vals[attrib] = value\n\n\ndef generate_env_mach_specific(\n    output_dir,\n    machobj,\n    compiler,\n    mpilib,\n    debug,\n    comp_interface,\n    sysos,\n    unit_testing,\n    threaded,\n    noenv=False,\n):\n    \"\"\"\n    env_mach_specific generation.\n    \"\"\"\n    ems_path = os.path.join(output_dir, \"env_mach_specific.xml\")\n    if os.path.exists(ems_path):\n        logger.warning(\"{} already exists, delete to replace\".format(ems_path))\n        return\n\n    ems_file = EnvMachSpecific(\n        output_dir, unit_testing=unit_testing, standalone_configure=True\n    )\n    ems_file.populate(\n        machobj,\n        attributes={\"mpilib\": mpilib, \"compiler\": compiler, \"threaded\": threaded},\n    )\n    ems_file.write()\n\n    if noenv:\n        return\n\n    fake_case = FakeCase(compiler, mpilib, debug, comp_interface)\n    ems_file.load_env(fake_case)\n    for shell in (\"sh\", \"csh\"):\n        ems_file.make_env_mach_specific_file(shell, fake_case, output_dir=output_dir)\n        shell_path = os.path.join(output_dir, \".env_mach_specific.\" + shell)\n        with open(shell_path, \"a\") as shell_file:\n            if shell == \"sh\":\n                shell_file.write(\"\\nexport COMPILER={}\\n\".format(compiler))\n                shell_file.write(\"export MPILIB={}\\n\".format(mpilib))\n                shell_file.write(\"export DEBUG={}\\n\".format(repr(debug).upper()))\n                shell_file.write(\"export OS={}\\n\".format(sysos))\n            else:\n                shell_file.write(\"\\nsetenv COMPILER {}\\n\".format(compiler))\n                shell_file.write(\"setenv MPILIB {}\\n\".format(mpilib))\n                shell_file.write(\"setenv DEBUG {}\\n\".format(repr(debug).upper()))\n                shell_file.write(\"setenv OS {}\\n\".format(sysos))\n", "path": "CIME/BuildTools/configure.py"}]}