3 # Copyright (C) 2010-2012 CEA/DEN
5 # This library is free software; you can redistribute it and/or
6 # modify it under the terms of the GNU Lesser General Public
7 # License as published by the Free Software Foundation; either
8 # version 2.1 of the License.
10 # This library is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 # Lesser General Public License for more details.
15 # You should have received a copy of the GNU Lesser General Public
16 # License along with this library; if not, write to the Free Software
17 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 import src.debug as DBG
27 # Define all possible option for update command : sat update <options>
28 parser = src.options.Options()
34 _("Optional: products to update. This option accepts a comma separated list."),
36 parser.add_option('f', 'force', 'boolean', 'force',
37 _("Optional: force to update the products in development mode."))
38 parser.add_option('', 'force_patch', 'boolean', 'force_patch',
39 _("Optional: force to apply patch to the products in development mode."))
40 # parser.add_option('c', 'complete', 'boolean', 'complete',
41 # _("Optional: completion mode, only update products not present in SOURCES dir."),
45 def find_products_already_prepared(l_products):
46 """function that returns the list of products that have an existing source
49 :param l_products List: The list of products to check
50 :return: The list of product configurations that have an existing source
55 for p_name_p_cfg in l_products:
56 __, prod_cfg = p_name_p_cfg
57 if "source_dir" in prod_cfg and os.path.exists(prod_cfg.source_dir):
58 l_res.append(p_name_p_cfg)
61 def find_git_products(l_products):
63 function that returns the list of products that have an existing source
64 directory and a git configuration. Those products will be updated using :
66 git checkout TARGET_TAG
67 git pull origin TARGET_TAG --ff-only
69 Not committed dev or conflict with origin during pull will trigger an error.
71 :param l_products List: The list of products to check
72 :return: The list of product configurations that have an existing source
73 directory and a git history.
77 for p_name_p_cfg in l_products:
78 __, prod_cfg = p_name_p_cfg
79 if "source_dir" in prod_cfg and os.path.exists(prod_cfg.source_dir):
80 if prod_cfg.get_source == "git":
81 l_res.append(p_name_p_cfg)
85 def find_products_with_patchs(l_products):
86 """function that returns the list of products that have one or more patches.
88 :param l_products List: The list of products to check
89 :return: The list of product configurations that have one or more patches.
93 for p_name_p_cfg in l_products:
94 __, prod_cfg = p_name_p_cfg
95 l_patchs = src.get_cfg_param(prod_cfg, "patches", [])
97 l_res.append(p_name_p_cfg)
102 """method that is called when salomeTools is called with --help option.
104 :return: The text to display for the update command description.
108 "The update command updates the sources under git and gets the sources of "
109 "the application products and apply the patches if there is any."
110 "\n\nexample:\nsat update SALOME-master --products KERNEL,GUI"
115 This is an operation class. It is prepared though the init and launched
116 with the launch method.
118 This operation updates the products, meaning it get the missing ones, and
119 pull the TARGET_TAG for the already present ones. It prevents from erasing
120 everything, especially .git/ files.
122 In case you have uncommited work, the operation will stop.
124 In case the remote tracking branch can't be pulled fast-forward (after a
125 checkout to the matching local branch), the operation will stop.
128 def __init__(self, args, runner, logger):
130 Initialisation of the UpdateOp. The runner and the plateform are
133 :args: arguments passed to sat
134 :runner: Sat class instance
135 :logger: Current logger
137 # check that the command has been called with an application
138 src.check_config_has_application(runner.cfg)
140 # write warning if platform is not declared as supported
141 src.check_platform_is_supported(runner.cfg, logger)
144 (options, args) = parser.parse_args(args)
145 self._list_of_products = options.products
146 self._force_patch = options.force_patch
147 self._force = options.force
151 self.products_infos = src.product.get_products_list(options, self.runner.cfg, self.logger)
153 # Construct the arguments to pass to the clean, source and patch commands
154 self.args_appli = runner.cfg.VARS.application + " " # useful whitespace
158 if self._list_of_products:
159 return list(self._list_of_products)
160 return [name for name, tmp in self.products_infos]
162 def getProductsToPrepare(self):
164 Remove products that are already prepared and under git tracking so
165 that only new products (and not tracked ones) are prepared.
167 pi_already_prepared = find_git_products(self.products_infos)
168 l_already_prepared = [i for i, tmp in pi_already_prepared]
169 newList, removedList = removeInList(self.products, l_already_prepared)
170 if len(newList) == 0 and len(removedList) > 0:
171 msg = "\nAll the products are already installed, do nothing!\n"
172 self.logger.write(src.printcolors.printcWarning(msg), 1)
174 if len(removedList) > 0:
176 "\nList of already prepared products that are skipped : %s\n"
177 % ",".join(removedList)
179 self.logger.write(msg, 3)
182 def getProductsToUpdate(self):
183 pi_already_prepared = find_git_products(self.products_infos)
184 productsToUpdate = [i for i, tmp in pi_already_prepared]
185 return productsToUpdate
187 def getProductsToClean(self, listProdToPrepare):
188 ldev_products = [p for p in self.products_infos if src.product.product_is_dev(p[1])]
189 productsToClean = listProdToPrepare # default
190 if len(ldev_products) > 0:
191 l_products_not_getted = find_products_already_prepared(ldev_products)
192 listNot = [i for i, tmp in l_products_not_getted]
193 productsToClean, removedList = removeInList(listProdToPrepare, listNot)
194 if len(removedList) > 0:
197 Do not get the source of the following products in
201 msg += "\n%s\n" % ",".join(removedList)
202 self.logger.write(src.printcolors.printcWarning(msg), 1)
203 return productsToClean
205 def getProductsToPatch(self, listProdToPrepare):
206 productsToPatch = listProdToPrepare # default
207 ldev_products = [p for p in self.products_infos if src.product.product_is_dev(p[1])]
208 if not self._force_patch and len(ldev_products) > 0:
209 l_products_with_patchs = find_products_with_patchs(ldev_products)
210 listNot = [i for i, tmp in l_products_with_patchs]
211 productsToPatch, removedList = removeInList(listProdToPrepare, listNot)
212 if len(removedList) > 0:
215 Do not patch the following products in development mode.
216 Use the --force_patch option to overwrite it.
219 msg += "\n%s\n" % ",".join(removedList)
220 self.logger.write(src.printcolors.printcWarning(msg), 1)
221 return productsToPatch
224 productsToPrepare = self.getProductsToPrepare()
225 args_product_to_prepare_opt = "--products " + ",".join(productsToPrepare)
227 productsToUpdate = self.getProductsToUpdate()
228 args_product_to_update_opt = "--products " + ",".join(productsToUpdate)
230 productsToClean = self.getProductsToClean(productsToPrepare)
231 args_product_opt_clean = "--products " + ",".join(productsToClean)
233 productsToPatch = self.getProductsToPatch(productsToPrepare)
234 args_product_opt_patch = "--products " + ",".join(productsToPatch)
237 # Initialize the results to a running status
242 # Call the commands using the API
244 if len(productsToClean) > 0:
245 msg = _("Clean the source directories ...")
246 self.logger.write(msg, 3)
248 args_clean = self.args_appli + args_product_opt_clean + " --sources"
249 res_clean = self.runner.clean(args_clean, batch=True, verbose = 0, logger_add_link = self.logger)
251 self.logger.write('%s\n' % src.printcolors.printc(src.OK_STATUS), 3)
253 self.logger.write('%s\n' % src.printcolors.printc(src.KO_STATUS), 3)
254 if len(productsToPrepare) > 0:
255 msg = _("Get the sources of the products ...")
256 self.logger.write(msg, 5)
257 args_source = self.args_appli + args_product_to_prepare_opt
258 res_source = self.runner.source(args_source, logger_add_link=self.logger)
260 self.logger.write("%s\n" % src.printcolors.printc(src.OK_STATUS), 5)
262 self.logger.write("%s\n" % src.printcolors.printc(src.KO_STATUS), 5)
263 if len(productsToPatch) > 0:
264 msg = _("Patch the product sources (if any) ...")
265 self.logger.write(msg, 5)
266 args_patch = self.args_appli + args_product_opt_patch
267 res_patch = self.runner.patch(args_patch, logger_add_link=self.logger)
269 self.logger.write("%s\n" % src.printcolors.printc(src.OK_STATUS), 5)
271 self.logger.write("%s\n" % src.printcolors.printc(src.KO_STATUS), 5)
272 if len(productsToUpdate) > 0:
273 msg = _("Update the sources of the products ...")
274 self.logger.write(msg, 5)
275 args_source = self.args_appli + args_product_to_update_opt
276 res_source = self.runner.source_update(args_source, logger_add_link=self.logger)
278 self.logger.write("%s\n" % src.printcolors.printc(src.OK_STATUS), 5)
280 self.logger.write("%s\n" % src.printcolors.printc(src.KO_STATUS), 5)
281 return res_clean + res_source + res_patch
284 def run(args, runner, logger):
285 """method that is called when salomeTools is called with update parameter."""
286 updateOp = UpdateOp(args, runner, logger)
287 res = updateOp.launch()
291 def removeInList(aList, removeList):
292 """Removes elements of removeList list from aList
294 :param aList: (list) The list from which to remove elements
295 :param removeList: (list) The list which contains elements to remove
296 :return: (list, list) (list with elements removed, list of elements removed)
298 res1 = [i for i in aList if i not in removeList]
299 res2 = [i for i in aList if i in removeList]