Sync EDKII BaseTools to BaseTools project r1903.
[efi/edk2/.git] / edk2 / BaseTools / Source / Python / PackagingTool / RmPkg.py
1 ## @file\r
2 # Install distribution package.\r
3 #\r
4 # Copyright (c) 2007, Intel Corporation\r
5 # All rights reserved. This program and the accompanying materials\r
6 # are licensed and made available under the terms and conditions of the BSD License\r
7 # which accompanies this distribution.  The full text of the license may be found at\r
8 # http://opensource.org/licenses/bsd-license.php\r
9 #\r
10 # THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11 # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12 #\r
13 \r
14 ##\r
15 # Import Modules\r
16 #\r
17 import os\r
18 import sys\r
19 import traceback\r
20 import platform\r
21 from optparse import OptionParser\r
22 \r
23 import Common.EdkLogger as EdkLogger\r
24 from Common.BuildToolError import *\r
25 from Common.Misc import *\r
26 from Common.XmlParser import *\r
27 \r
28 from IpiDb import *\r
29 from DependencyRules import *\r
30 \r
31 # Version and Copyright\r
32 VersionNumber = "0.1"\r
33 __version__ = "%prog Version " + VersionNumber\r
34 __copyright__ = "Copyright (c) 2008, Intel Corporation  All rights reserved."\r
35 \r
36 ## Check environment variables\r
37 #\r
38 #  Check environment variables that must be set for build. Currently they are\r
39 #\r
40 #   WORKSPACE           The directory all packages/platforms start from\r
41 #   EDK_TOOLS_PATH      The directory contains all tools needed by the build\r
42 #   PATH                $(EDK_TOOLS_PATH)/Bin/<sys> must be set in PATH\r
43 #\r
44 #   If any of above environment variable is not set or has error, the build\r
45 #   will be broken.\r
46 #\r
47 def CheckEnvVariable():\r
48     # check WORKSPACE\r
49     if "WORKSPACE" not in os.environ:\r
50         EdkLogger.error("RmPkg", ATTRIBUTE_NOT_AVAILABLE, "Environment variable not found",\r
51                         ExtraData="WORKSPACE")\r
52 \r
53     WorkspaceDir = os.path.normpath(os.environ["WORKSPACE"])\r
54     if not os.path.exists(WorkspaceDir):\r
55         EdkLogger.error("RmPkg", FILE_NOT_FOUND, "WORKSPACE doesn't exist", ExtraData="%s" % WorkspaceDir)\r
56     elif ' ' in WorkspaceDir:\r
57         EdkLogger.error("RmPkg", FORMAT_NOT_SUPPORTED, "No space is allowed in WORKSPACE path", \r
58                         ExtraData=WorkspaceDir)\r
59     os.environ["WORKSPACE"] = WorkspaceDir\r
60 \r
61 ## Parse command line options\r
62 #\r
63 # Using standard Python module optparse to parse command line option of this tool.\r
64 #\r
65 #   @retval Opt   A optparse.Values object containing the parsed options\r
66 #   @retval Args  Target of build command\r
67 #\r
68 def MyOptionParser():\r
69     UsageString = "%prog -g <guid> -n <version> [-y] [-q | -v] [-h]"\r
70 \r
71     Parser = OptionParser(description=__copyright__,version=__version__,prog="RmPkg",usage=UsageString)\r
72 \r
73     Parser.add_option("-?", action="help", help="show this help message and exit")\r
74 \r
75 #    Parser.add_option("-f", "--force", action="store_true", type=None, dest="ForceRemove",\r
76 #            help="Force creation - overwrite existing one.")\r
77 \r
78     Parser.add_option("-y", "--yes", action="store_true", dest="Yes",\r
79             help="Not asking for confirmation when deleting files.")\r
80 \r
81     Parser.add_option("-n", "--package-version", action="store", type="string", dest="PackageVersion",\r
82             help="The version of distribution package to be removed.")\r
83 \r
84     Parser.add_option("-g", "--package-guid", action="store", type="string", dest="PackageGuid",\r
85             help="The GUID of distribution package to be removed.")\r
86 \r
87     Parser.add_option("-q", "--quiet", action="store_const", dest="LogLevel", const=EdkLogger.QUIET,\r
88             help="Disable all messages except FATAL ERRORS.")\r
89 \r
90     Parser.add_option("-v", "--verbose", action="store_const", dest="LogLevel", const=EdkLogger.VERBOSE,\r
91             help="Turn on verbose output")\r
92 \r
93     Parser.add_option("-d", "--debug", action="store", type="int", dest="LogLevel",\r
94             help="Enable debug messages at specified level.")\r
95 \r
96     Parser.set_defaults(LogLevel=EdkLogger.INFO)\r
97 \r
98     (Opt, Args)=Parser.parse_args()\r
99 \r
100     return Opt\r
101 \r
102 ## Remove all empty dirs under the path\r
103 def RemoveEmptyDirs(Path):\r
104     # Remove all sub dirs\r
105     for Root, Dirs, Files in os.walk(Path):\r
106         for Dir in Dirs:\r
107             FullPath = os.path.normpath(os.path.join(Root, Dir))\r
108             if os.path.isdir(FullPath):\r
109                 if os.listdir(FullPath) == []:\r
110                     os.rmdir(FullPath)\r
111                 else:\r
112                     RemoveEmptyDirs(FullPath)\r
113     # Remove itself\r
114     if os.path.isdir(Path) and os.listdir(Path) == []:\r
115         os.rmdir(Path)\r
116         \r
117 \r
118 ## Tool entrance method\r
119 #\r
120 # This method mainly dispatch specific methods per the command line options.\r
121 # If no error found, return zero value so the caller of this tool can know\r
122 # if it's executed successfully or not.\r
123 #\r
124 #   @retval 0     Tool was successful\r
125 #   @retval 1     Tool failed\r
126 #\r
127 def Main():\r
128     EdkLogger.Initialize()\r
129     Options = MyOptionParser()\r
130     try:\r
131         if not Options.PackageGuid and not Options.PackageVersion:\r
132             EdkLogger.error("RmPkg", OPTION_MISSING, ExtraData="The GUID and Version of distribution package must be specified")\r
133         \r
134         if Options.LogLevel < EdkLogger.DEBUG_9:\r
135             EdkLogger.SetLevel(Options.LogLevel + 1)\r
136         else:\r
137             EdkLogger.SetLevel(Options.LogLevel)\r
138 \r
139         CheckEnvVariable()\r
140         WorkspaceDir = os.environ["WORKSPACE"]\r
141 \r
142         # Prepare check dependency\r
143         Db = IpiDatabase(os.path.normpath(os.path.join(WorkspaceDir, "Conf/DistributionPackageDatabase.db")))\r
144         Db.InitDatabase()\r
145         Dep = DependencyRules(Db)\r
146         \r
147         Guid = Options.PackageGuid\r
148         Version = Options.PackageVersion\r
149         \r
150         # Check Dp existing\r
151         if not Dep.CheckDpExists(Guid, Version):\r
152             EdkLogger.error("RmPkg", UNKNOWN_ERROR, "This distribution package are not installed!")\r
153         \r
154         # Check Dp depex\r
155         if not Dep.CheckDpDepexForRemove(Guid, Version):\r
156             print "Some packages/modules are depending on this distribution package, do you really want to remove it?"\r
157             print "Press Y to delete all files or press other keys to quit:"\r
158             Input = Input = sys.stdin.readline()\r
159             Input = Input.replace('\r', '').replace('\n', '')\r
160             if Input.upper() != 'Y':\r
161                 EdkLogger.error("RmPkg", UNKNOWN_ERROR, "User interrupt")\r
162 \r
163         # Remove all files\r
164         if not Options.Yes:\r
165             print "All files of the distribution package will be removed, do you want to continue?"\r
166             print "Press Y to remove all files or press other keys to quit:"\r
167             Input = Input = sys.stdin.readline()\r
168             Input = Input.replace('\r', '').replace('\n', '')\r
169             if Input.upper() != 'Y':\r
170                 EdkLogger.error("RmPkg", UNKNOWN_ERROR, "User interrupt")\r
171         \r
172         # Remove all files\r
173         MissingFileList = []\r
174         for Item in Db.GetDpFileList(Guid, Version):\r
175             if os.path.isfile(Item):\r
176                 print "Removing file [%s] ..." % Item\r
177                 os.remove(Item)\r
178             else:\r
179                 MissingFileList.append(Item)\r
180         \r
181         # Remove all empty dirs of package\r
182         for Item in Db.GetPackageListFromDp(Guid, Version):\r
183             Dir = os.path.dirname(Item[2])\r
184             RemoveEmptyDirs(Dir)\r
185 \r
186         # Remove all empty dirs of module\r
187         for Item in Db.GetStandaloneModuleInstallPathListFromDp(Guid, Version):\r
188             Dir = os.path.dirname(Item)\r
189             RemoveEmptyDirs(Dir)\r
190         \r
191         # update database\r
192         EdkLogger.quiet("Update Distribution Package Database ...")\r
193         Db.RemoveDpObj(Guid, Version)\r
194         EdkLogger.quiet("DONE")\r
195         \r
196     except FatalError, X:\r
197         if Options and Options.LogLevel < EdkLogger.DEBUG_9:\r
198             EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())\r
199         ReturnCode = X.args[0]\r
200     except KeyboardInterrupt:\r
201         ReturnCode = ABORT_ERROR\r
202         if Options and Options.LogLevel < EdkLogger.DEBUG_9:\r
203             EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())\r
204     except:\r
205         EdkLogger.error(\r
206                     "\nRmPkg",\r
207                     CODE_ERROR,\r
208                     "Unknown fatal error when removing package",\r
209                     ExtraData="\n(Please send email to edk2-buildtools-devel@lists.sourceforge.net for help, attaching following call stack trace!)\n",\r
210                     RaiseError=False\r
211                     )\r
212         EdkLogger.quiet("(Python %s on %s) " % (platform.python_version(), sys.platform) + traceback.format_exc())\r
213         ReturnCode = CODE_ERROR\r
214     finally:\r
215         Progressor.Abort()\r
216 \r
217 if __name__ == '__main__':\r
218     sys.exit(Main())\r