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