Repository: ESMCI/cime

Issue:
extend clone_case to make copy of user_mods to all files in case directory
Nancy Norton noticed that the clone_case script ignored user changes in the Tools subdirectory.  This is counterintuitive to what we would expect from cloning a case and seems like a bug.  I think Jim Edwards suggested fix below would make the routine more consistent with the definition of a clone being an almost identical copy of the original case.  I also think making the user go through some hoops (breaking links, etc.)  when they modify a critical script in the case directory is a good idea and will help to make the user aware that they are playing with fire. 

Jim Edwards comments and suggestion: 

Many of the files under the case directory are links to the source and are not intended to be modified.   We could add something such that if a user broke that link and changed the file the copy would be cloned - can you open an esmci issue on this please?


Discussion:
Is this still needed?

Resolving patch:
diff --git a/scripts/lib/CIME/case/case.py b/scripts/lib/CIME/case/case.py
--- a/scripts/lib/CIME/case/case.py
+++ b/scripts/lib/CIME/case/case.py
@@ -67,7 +67,7 @@ class Case(object):
     are listed in the following imports
     """
     from CIME.case.case_setup import case_setup
-    from CIME.case.case_clone import create_clone
+    from CIME.case.case_clone import create_clone, _copy_user_modified_to_clone
     from CIME.case.case_test  import case_test
     from CIME.case.case_submit import check_DA_settings, check_case, submit
     from CIME.case.case_st_archive import case_st_archive, restore_from_archive, \
diff --git a/scripts/lib/CIME/case/case_clone.py b/scripts/lib/CIME/case/case_clone.py
--- a/scripts/lib/CIME/case/case_clone.py
+++ b/scripts/lib/CIME/case/case_clone.py
@@ -101,6 +101,15 @@ def create_clone(self, newcase, keepexe=False, mach_dir=None, project=None,
 
     # create caseroot
     newcase.create_caseroot(clone=True)
+
+    # Many files in the case will be links back to the source tree
+    # but users may have broken links to modify files locally.  In this case
+    # copy the locally modified file.   We only want to do this for files that
+    # already exist in the clone.
+
+    self._copy_user_modified_to_clone(self.get_value("CASEROOT"), newcase.get_value("CASEROOT"))
+    self._copy_user_modified_to_clone(self.get_value("CASETOOLS"), newcase.get_value("CASETOOLS"))
+
     newcase.flush(flushall=True)
 
     # copy user_ files
@@ -161,3 +170,16 @@ def create_clone(self, newcase, keepexe=False, mach_dir=None, project=None,
     newcase.case_setup()
 
     return newcase
+
+def _copy_user_modified_to_clone(self, origpath, newpath):
+    """
+    If file_ exists and is a link in newpath, and exists but is not a
+    link in origpath, copy origpath file to newpath
+    """
+    for file_ in os.listdir(newpath):
+        if (os.path.islink(os.path.join(newpath, file_)) and
+            os.path.isfile(os.path.join(origpath, file_)) and
+            not os.path.islink(os.path.join(origpath, file_))):
+            logger.info("Copying user modified file {} to clone".format(file_))
+            os.unlink(os.path.join(newpath, file_))
+            safe_copy(os.path.join(origpath, file_), newpath)


Test patch: