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
23 # Define all possible option for update command : sat update <options>
24 parser = src.options.Options()
30 _("Optional: products to update. This option accepts a comma separated list."),
37 _("Optional: force to update the products in development mode."),
44 _("Optional: force to apply patch to the products in development mode."),
46 # parser.add_option('c', 'complete', 'boolean', 'complete',
47 # _("Optional: completion mode, only update products not present in SOURCES dir."),
51 def find_products_already_prepared(l_products):
52 """function that returns the list of products that have an existing source
55 :param l_products List: The list of products to check
56 :return: The list of product configurations that have an existing source
61 for p_name_p_cfg in l_products:
62 _, prod_cfg = p_name_p_cfg
63 if "source_dir" in prod_cfg and os.path.exists(prod_cfg.source_dir):
64 l_res.append(p_name_p_cfg)
68 def find_git_products(l_products):
70 function that returns the list of products that have an existing source
71 directory and a git configuration. Those products will be updated using :
73 git checkout TARGET_TAG
74 git pull origin TARGET_TAG --ff-only
76 Not committed dev or conflict with origin during pull will trigger an error.
78 :param l_products List: The list of products to check
79 :return: The list of product configurations that have an existing source
80 directory and a git history.
84 for p_name_p_cfg in l_products:
85 _, prod_cfg = p_name_p_cfg
86 if "source_dir" in prod_cfg and os.path.exists(prod_cfg.source_dir):
87 if prod_cfg.get_source == "git":
88 l_res.append(p_name_p_cfg)
92 def find_products_with_patchs(l_products):
93 """function that returns the list of products that have one or more patches.
95 :param l_products List: The list of products to check
96 :return: The list of product configurations that have one or more patches.
100 for p_name_p_cfg in l_products:
101 _, prod_cfg = p_name_p_cfg
102 l_patchs = src.get_cfg_param(prod_cfg, "patches", [])
103 if len(l_patchs) > 0:
104 l_res.append(p_name_p_cfg)
109 """method that is called when salomeTools is called with --help option.
111 :return: The text to display for the update command description.
115 "The update command updates the sources under git and gets the sources of "
116 "the application products and apply the patches if there is any."
117 "\n\nexample:\nsat update SALOME-master --products KERNEL,GUI"
123 This is an operation class. It is prepared though the init and launched
124 with the launch method.
126 This operation updates the products, meaning it get the missing ones, and
127 pull the TARGET_TAG for the already present ones. It prevents from erasing
128 everything, especially .git/ files.
130 In case you have uncommited work, the operation will stop.
132 In case the remote tracking branch can't be pulled fast-forward (after a
133 checkout to the matching local branch), the operation will stop.
136 def __init__(self, args, runner, logger):
138 Initialisation of the UpdateOp. The runner and the plateform are
141 :args: arguments passed to sat
142 :runner: Sat class instance
143 :logger: Current logger
145 # check that the command has been called with an application
146 src.check_config_has_application(runner.cfg)
148 # write warning if platform is not declared as supported
149 src.check_platform_is_supported(runner.cfg, logger)
152 (options, args) = parser.parse_args(args)
153 self._list_of_products = options.products
154 self._force_patch = options.force_patch
155 self._force = options.force
159 self.products_infos = src.product.get_products_list(
160 options, self.runner.cfg, self.logger
163 # Construct the arguments to pass to the clean, source and patch commands
164 self.args_appli = runner.cfg.VARS.application + " " # useful whitespace
168 if self._list_of_products:
169 return list(self._list_of_products)
170 return [name for name, _ in self.products_infos]
172 def getProductsToPrepare(self):
174 Remove products that are already prepared and under git tracking so
175 that only new products (and not tracked ones) are prepared.
177 pi_already_prepared = find_git_products(self.products_infos)
178 l_already_prepared = [i for i, _ in pi_already_prepared]
179 newList, removedList = removeInList(self.products, l_already_prepared)
180 if len(newList) == 0 and len(removedList) > 0:
181 msg = "\nAll the products are already installed, do nothing!\n"
182 self.logger.write(src.printcolors.printcWarning(msg), 1)
184 if len(removedList) > 0:
186 "\nList of already prepared products that are skipped : %s\n"
187 % ",".join(removedList)
189 self.logger.write(msg, 3)
192 def getProductsToUpdate(self):
193 pi_already_prepared = find_git_products(self.products_infos)
194 productsToUpdate = [i for i, _ in pi_already_prepared]
195 return productsToUpdate
197 def getProductsToClean(self, listProdToPrepare):
199 p for p in self.products_infos if src.product.product_is_dev(p[1])
201 productsToClean = listProdToPrepare # default
202 if len(ldev_products) > 0:
203 l_products_not_getted = find_products_already_prepared(ldev_products)
204 listNot = [i for i, _ in l_products_not_getted]
205 productsToClean, removedList = removeInList(listProdToPrepare, listNot)
206 if len(removedList) > 0:
209 Do not get the source of the following products in
213 msg += "\n%s\n" % ",".join(removedList)
214 self.logger.write(src.printcolors.printcWarning(msg), 1)
215 return productsToClean
217 def getProductsToPatch(self, listProdToPrepare):
218 productsToPatch = listProdToPrepare # default
220 p for p in self.products_infos if src.product.product_is_dev(p[1])
222 if not self._force_patch and len(ldev_products) > 0:
223 l_products_with_patchs = find_products_with_patchs(ldev_products)
224 listNot = [i for i, _ in l_products_with_patchs]
225 productsToPatch, removedList = removeInList(listProdToPrepare, listNot)
226 if len(removedList) > 0:
229 Do not patch the following products in development mode.
230 Use the --force_patch option to overwrite it.
233 msg += "\n%s\n" % ",".join(removedList)
234 self.logger.write(src.printcolors.printcWarning(msg), 1)
235 return productsToPatch
238 productsToPrepare = self.getProductsToPrepare()
239 args_product_to_prepare_opt = "--products " + ",".join(productsToPrepare)
241 productsToUpdate = self.getProductsToUpdate()
242 args_product_to_update_opt = "--products " + ",".join(productsToUpdate)
244 productsToClean = self.getProductsToClean(productsToPrepare)
245 args_product_opt_clean = "--products " + ",".join(productsToClean)
247 productsToPatch = self.getProductsToPatch(productsToPrepare)
248 args_product_opt_patch = "--products " + ",".join(productsToPatch)
250 # Initialize the results to a running status
255 # Call the commands using the API
257 if len(productsToClean) > 0:
258 msg = _("Clean the source directories ...")
259 self.logger.write(msg, 3)
261 args_clean = self.args_appli + args_product_opt_clean + " --sources"
262 res_clean = self.runner.clean(
263 args_clean, batch=True, verbose=0, logger_add_link=self.logger
266 self.logger.write("%s\n" % src.printcolors.printc(src.OK_STATUS), 3)
268 self.logger.write("%s\n" % src.printcolors.printc(src.KO_STATUS), 3)
269 if len(productsToPrepare) > 0:
270 msg = _("Get the sources of the products ...")
271 self.logger.write(msg, 5)
272 args_source = self.args_appli + args_product_to_prepare_opt
273 res_source = self.runner.source(
274 args_source, logger_add_link=self.logger
277 self.logger.write("%s\n" % src.printcolors.printc(src.OK_STATUS), 5)
279 self.logger.write("%s\n" % src.printcolors.printc(src.KO_STATUS), 5)
280 if len(productsToPatch) > 0:
281 msg = _("Patch the product sources (if any) ...")
282 self.logger.write(msg, 5)
283 args_patch = self.args_appli + args_product_opt_patch
284 res_patch = self.runner.patch(args_patch, logger_add_link=self.logger)
286 self.logger.write("%s\n" % src.printcolors.printc(src.OK_STATUS), 5)
288 self.logger.write("%s\n" % src.printcolors.printc(src.KO_STATUS), 5)
289 if len(productsToUpdate) > 0:
290 msg = _("Update the sources of the products ...")
291 self.logger.write(msg, 5)
292 args_source = self.args_appli + args_product_to_update_opt
293 res_source = self.runner.source_update(
294 args_source, logger_add_link=self.logger
297 self.logger.write("%s\n" % src.printcolors.printc(src.OK_STATUS), 5)
299 self.logger.write("%s\n" % src.printcolors.printc(src.KO_STATUS), 5)
300 return res_clean + res_source + res_patch
303 def run(args, runner, logger):
304 """method that is called when salomeTools is called with update parameter."""
305 updateOp = UpdateOp(args, runner, logger)
306 res = updateOp.launch()
310 def removeInList(aList, removeList):
311 """Removes elements of removeList list from aList
313 :param aList: (list) The list from which to remove elements
314 :param removeList: (list) The list which contains elements to remove
315 :return: (list, list) (list with elements removed, list of elements removed)
317 res1 = [i for i in aList if i not in removeList]
318 res2 = [i for i in aList if i in removeList]