Salome HOME
8f12d40e6b8390b5cbbf41b6fb4221d35f561e65
[tools/sat.git] / commands / prepare.py
1 #!/usr/bin/env python
2 #-*- coding:utf-8 -*-
3 #  Copyright (C) 2010-2012  CEA/DEN
4 #
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.
9 #
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.
14 #
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
18
19 import re
20 import os
21
22 import src
23 import src.debug as DBG
24
25 PROPERTY_EXPRESSION = "^.+:.+$"
26
27 # Define all possible option for prepare command :  sat prepare <options>
28 parser = src.options.Options()
29 parser.add_option('p', 'products', 'list2', 'products',
30     _('Optional: products to prepare. This option can be'
31     ' passed several time to prepare several products.'))
32 parser.add_option('', 'properties', 'string', 'properties',
33     _('Optional: Filter the products by their properties.\n\tSyntax: '
34       '--properties <property>:<value>'))
35 parser.add_option('f', 'force', 'boolean', 'force', 
36     _("Optional: force to prepare the products in development mode."))
37 parser.add_option('', 'force_patch', 'boolean', 'force_patch', 
38     _("Optional: force to apply patch to the products in development mode."))
39
40 def get_products_list(options, cfg, logger):
41     '''method that gives the product list with their informations from 
42        configuration regarding the passed options.
43     
44     :param options Options: The Options instance that stores the commands 
45                             arguments
46     :param config Config: The global configuration
47     :param logger Logger: The logger instance to use for the display and logging
48     :return: The list of (product name, product_informations).
49     :rtype: List
50     '''
51     # Get the products to be prepared, regarding the options
52     if options.products is None:
53         # No options, get all products sources
54         products = cfg.APPLICATION.products
55     else:
56         # if option --products, check that all products of the command line
57         # are present in the application.
58         products = options.products
59         for p in products:
60             if p not in cfg.APPLICATION.products:
61                 raise src.SatException(_("Product %(product)s "
62                             "not defined in application %(application)s") %
63                         { 'product': p, 'application': cfg.VARS.application} )
64     
65     # Construct the list of tuple containing 
66     # the products name and their definition
67     products_infos = src.product.get_products_infos(products, cfg)
68     
69     # if the property option was passed, filter the list
70     if options.properties:
71         [prop, value] = options.properties.split(":")
72         products_infos = [(p_name, p_info) for 
73                           (p_name, p_info) in products_infos 
74                           if "properties" in p_info and 
75                           prop in p_info.properties and 
76                           p_info.properties[prop] == value]
77         
78     return products_infos
79
80 def remove_products(arguments, l_products_info, logger):
81     '''function that removes the products in l_products_info from arguments list.
82     
83     :param arguments str: The arguments from which to remove products
84     :param l_products_info list: List of 
85                                  (str, Config) => (product_name, product_info)
86     :param logger Logger: The logger instance to use for the display and logging
87     :return: The updated arguments.
88     :rtype: str
89     '''
90     args = str(arguments) #copy of "--products ,XDATA,TESSCODE,cmake" for example
91     largs = args.split(',')
92     DBG.write("largs", largs)
93     toRemove = [name for name, xx in l_products_info]
94     DBG.write("remove_products", toRemove)
95     removed = []
96     notRemoved = []
97     for name in largs[1:]: # skip largs[0] as "--products "
98       if name in toRemove:
99         removed.append(name)
100       else:
101         notRemoved.append(name)
102     # DBG.write(removed, removed, True)
103     logger.write("  %s\n" % ",".join(removed), 1)
104     DBG.write("notRemoved", notRemoved)
105     res = largs[0] + ",".join(notRemoved)
106     return res
107
108 def find_products_already_getted(l_products):
109     '''function that returns the list of products that have an existing source 
110        directory.
111     
112     :param l_products List: The list of products to check
113     :return: The list of product configurations that have an existing source 
114              directory.
115     :rtype: List
116     '''
117     l_res = []
118     for p_name_p_cfg in l_products:
119         __, prod_cfg = p_name_p_cfg
120         if os.path.exists(prod_cfg.source_dir):
121             l_res.append(p_name_p_cfg)
122     return l_res
123
124 def find_products_with_patchs(l_products):
125     '''function that returns the list of products that have one or more patches.
126     
127     :param l_products List: The list of products to check
128     :return: The list of product configurations that have one or more patches.
129     :rtype: List
130     '''
131     l_res = []
132     for p_name_p_cfg in l_products:
133         __, prod_cfg = p_name_p_cfg
134         l_patchs = src.get_cfg_param(prod_cfg, "patches", [])
135         if len(l_patchs)>0:
136             l_res.append(p_name_p_cfg)
137     return l_res
138
139 def description():
140     '''method that is called when salomeTools is called with --help option.
141     
142     :return: The text to display for the prepare command description.
143     :rtype: str
144     '''
145     return _("The prepare command gets the sources of "
146              "the application products and apply the patches if there is any."
147              "\n\nexample:\nsat prepare SALOME-master --products KERNEL,GUI")
148   
149 def run(args, runner, logger):
150     '''method that is called when salomeTools is called with prepare parameter.
151     '''
152     
153     # Parse the options
154     (options, args) = parser.parse_args(args)
155
156     # check that the command has been called with an application
157     src.check_config_has_application( runner.cfg )
158
159     # Verify the --properties option
160     if options.properties:
161         oExpr = re.compile(PROPERTY_EXPRESSION)
162         if not oExpr.search(options.properties):
163             msg = _('WARNING: the "--properties" options must have the '
164                     'following syntax:\n--properties <property>:<value>')
165             logger.write(src.printcolors.printcWarning(msg), 1)
166             logger.write("\n", 1)
167             options.properties = None
168
169     products_infos = get_products_list(options, runner.cfg, logger)
170
171     # Construct the arguments to pass to the clean, source and patch commands
172     args_appli = runner.cfg.VARS.application + ' '
173     args_product_opt = '--products '
174     if options.products:
175         for p_name in options.products:
176             args_product_opt += ',' + p_name
177     else:
178         for p_name, __ in products_infos:
179             if args_product_opt == '--products ':
180                 args_product_opt += p_name
181             else:
182                 args_product_opt += ',' + p_name
183
184     ldev_products = [p for p in products_infos if src.product.product_is_dev(p[1])]
185     args_product_opt_clean = args_product_opt
186     if not options.force and len(ldev_products) > 0:
187         l_products_not_getted = find_products_already_getted(ldev_products)
188         if len(l_products_not_getted) > 0:
189             msg = _("""\
190 Do not get the source of the following products in development mode
191 Use the --force option to overwrite it.
192 """)
193             logger.write(src.printcolors.printcWarning(msg), 1)
194             args_product_opt_clean = remove_products(args_product_opt_clean,
195                                                      l_products_not_getted,
196                                                      logger)
197             logger.write("\n", 1)
198
199     
200     args_product_opt_patch = args_product_opt
201     if not options.force_patch and len(ldev_products) > 0:
202         l_products_with_patchs = find_products_with_patchs(ldev_products)
203         if len(l_products_with_patchs) > 0:
204             msg = _("""\
205 do not patch the following products in development mode
206 Use the --force_patch option to overwrite it.
207 """)
208             logger.write(src.printcolors.printcWarning(msg), 1)
209             args_product_opt_patch = remove_products(args_product_opt_patch,
210                                                      l_products_with_patchs,
211                                                      logger)
212             logger.write("\n", 1)
213
214     # Construct the final commands arguments
215     args_clean = args_appli + args_product_opt_clean + " --sources"
216     args_source = args_appli + args_product_opt  
217     args_patch = args_appli + args_product_opt_patch
218
219     # If there is no more any product in the command arguments,
220     # do not call the concerned command 
221     oExpr = re.compile("^--products *$")
222     do_clean = not(oExpr.search(args_product_opt_clean))
223     do_source = not(oExpr.search(args_product_opt))
224     do_patch = not(oExpr.search(args_product_opt_patch))
225     
226     
227     # Initialize the results to a failing status
228     res_clean = 1
229     res_source = 1
230     res_patch = 1
231     
232     # Call the commands using the API
233     if do_clean:
234         msg = _("Clean the source directories ...")
235         logger.write(msg, 3)
236         logger.flush()
237         res_clean = runner.clean(args_clean, batch=True, verbose = 0,
238                                     logger_add_link = logger)
239         if res_clean == 0:
240             logger.write('%s\n' % src.printcolors.printc(src.OK_STATUS), 3)
241         else:
242             logger.write('%s\n' % src.printcolors.printc(src.KO_STATUS), 3)
243     if do_source:
244         msg = _("Get the sources of the products ...")
245         logger.write(msg, 5)
246         res_source = runner.source(args_source,
247                                     logger_add_link = logger)
248         if res_source == 0:
249             logger.write('%s\n' % src.printcolors.printc(src.OK_STATUS), 5)
250         else:
251             logger.write('%s\n' % src.printcolors.printc(src.KO_STATUS), 5)
252     if do_patch:
253         msg = _("Patch the product sources (if any) ...")
254         logger.write(msg, 5)
255         res_patch = runner.patch(args_patch,
256                                     logger_add_link = logger)
257         if res_patch == 0:
258             logger.write('%s\n' % src.printcolors.printc(src.OK_STATUS), 5)
259         else:
260             logger.write('%s\n' % src.printcolors.printc(src.KO_STATUS), 5)
261     
262     return res_clean + res_source + res_patch