]> git.proxmox.com Git - mirror_edk2.git/blobdiff - BaseTools/Source/Python/Common/Misc.py
BaseTools: Decouple AutoGen Objects
[mirror_edk2.git] / BaseTools / Source / Python / Common / Misc.py
index 0e0cb45ebe97519f5862642d457919cc85a4d34b..26d149c270408b7f127c52502b80f2e752ee9d76 100644 (file)
@@ -18,6 +18,7 @@ import re
 import pickle\r
 import array\r
 import shutil\r
+import filecmp\r
 from random import sample\r
 from struct import pack\r
 import uuid\r
@@ -245,13 +246,8 @@ def ProcessDuplicatedInf(Path, BaseName, Workspace):
     else:\r
         Filename = BaseName + Path.BaseName\r
 \r
-    #\r
-    # If -N is specified on command line, cache is disabled\r
-    # The directory has to be created\r
-    #\r
     DbDir = os.path.split(GlobalData.gDatabasePath)[0]\r
-    if not os.path.exists(DbDir):\r
-        os.makedirs(DbDir)\r
+\r
     #\r
     # A temporary INF is copied to database path which must have write permission\r
     # The temporary will be removed at the end of build\r
@@ -281,6 +277,7 @@ def ProcessDuplicatedInf(Path, BaseName, Workspace):
     #\r
     RtPath.Path = TempFullPath\r
     RtPath.BaseName = BaseName\r
+    RtPath.OriginalPath = Path\r
     #\r
     # If file exists, compare contents\r
     #\r
@@ -501,6 +498,60 @@ def SaveFileOnChange(File, Content, IsBinaryFile=True):
 \r
     return True\r
 \r
+## Copy source file only if it is different from the destination file\r
+#\r
+#  This method is used to copy file only if the source file and destination\r
+#  file content are different. This is quite useful to avoid duplicated\r
+#  file writing.\r
+#\r
+#   @param      SrcFile   The path of source file\r
+#   @param      Dst       The path of destination file or folder\r
+#\r
+#   @retval     True      The two files content are different and the file is copied\r
+#   @retval     False     No copy really happen\r
+#\r
+def CopyFileOnChange(SrcFile, Dst):\r
+    if not os.path.exists(SrcFile):\r
+        return False\r
+\r
+    if os.path.isdir(Dst):\r
+        DstFile = os.path.join(Dst, os.path.basename(SrcFile))\r
+    else:\r
+        DstFile = Dst\r
+\r
+    if os.path.exists(DstFile) and filecmp.cmp(SrcFile, DstFile, shallow=False):\r
+        return False\r
+\r
+    DirName = os.path.dirname(DstFile)\r
+    if not CreateDirectory(DirName):\r
+        EdkLogger.error(None, FILE_CREATE_FAILURE, "Could not create directory %s" % DirName)\r
+    else:\r
+        if DirName == '':\r
+            DirName = os.getcwd()\r
+        if not os.access(DirName, os.W_OK):\r
+            EdkLogger.error(None, PERMISSION_FAILURE, "Do not have write permission on directory %s" % DirName)\r
+\r
+    # os.replace and os.rename are the atomic operations in python 3 and 2.\r
+    # we use these two atomic operations to ensure the file copy is atomic:\r
+    # copy the src to a temp file in the dst same folder firstly, then\r
+    # replace or rename the temp file to the destination file.\r
+    with tempfile.NamedTemporaryFile(dir=DirName, delete=False) as tf:\r
+        shutil.copy(SrcFile, tf.name)\r
+        tempname = tf.name\r
+    try:\r
+        if hasattr(os, 'replace'):\r
+            os.replace(tempname, DstFile)\r
+        else:\r
+            # os.rename reqire to remove the dst on Windows, otherwise OSError will be raised.\r
+            if GlobalData.gIsWindows and os.path.exists(DstFile):\r
+                os.remove(DstFile)\r
+            os.rename(tempname, DstFile)\r
+\r
+    except IOError as X:\r
+        EdkLogger.error(None, FILE_COPY_FAILURE, ExtraData='IOError %s' % X)\r
+\r
+    return True\r
+\r
 ## Retrieve and cache the real path name in file system\r
 #\r
 #   @param      Root    The root directory of path relative to\r
@@ -598,7 +649,6 @@ def GuidValue(CName, PackageList, Inffile = None):
         if CName in GuidKeys:\r
             return P.Guids[CName]\r
     return None\r
-    return None\r
 \r
 ## A string template class\r
 #\r
@@ -1036,7 +1086,7 @@ def ParseFieldValue (Value):
             p.stderr.close()\r
         if err:\r
             raise BadExpression("DevicePath: %s" % str(err))\r
-        out = out.decode(encoding='utf-8', errors='ignore')\r
+        out = out.decode()\r
         Size = len(out.split())\r
         out = ','.join(out.split())\r
         return '{' + out + '}', Size\r
@@ -1405,6 +1455,7 @@ class PathClass(object):
         self.TagName = TagName\r
         self.ToolCode = ToolCode\r
         self.ToolChainFamily = ToolChainFamily\r
+        self.OriginalPath = self\r
 \r
     ## Convert the object of this class to a string\r
     #\r