3 # Copyright (C) 2010-2013 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
25 parser = src.options.Options()
27 parser.add_option( 'p', 'prefix', 'string', 'prefix', _("Where the profile's "
30 parser.add_option( 'n', 'name', 'string', 'name', _("Name of the profile's "
32 "${config.PRODUCT.name}"
34 parser.add_option( 'f', 'force', 'boolean', 'force', _("Overwrites "
35 "existing sources.") )
36 parser.add_option( 'u', 'no_update', 'boolean', 'no_update', _("Does not update"
38 parser.add_option( 'v', 'version', 'string', 'version', _("Version of the "
41 parser.add_option( 's', 'slogan', 'string', 'slogan', _("Slogan of the "
44 ##################################################
47 # Class that overrides common.Reference
48 # in order to manipulate fields starting with '@'
49 class profileReference( src.pyconf.Reference ) :
52 for tt, tv in self.elements[1:]:
53 if tt == src.pyconf.DOT:
57 if self.type == src.pyconf.BACKTICK:
58 return src.pyconf.BACKTICK + s + src.pyconf.BACKTICK
59 elif self.type == src.pyconf.AT:
60 return src.pyconf.AT + s
62 return src.pyconf.DOLLAR + s
65 # Class that overrides how fields starting with '@' are read.
66 class profileConfigReader( src.pyconf.ConfigReader ) :
67 def parseMapping(self, parent, suffix):
68 if self.token[0] == src.pyconf.LCURLY:
69 self.match(src.pyconf.LCURLY)
70 rv = src.pyconf.Mapping(parent)
72 src.pyconf.makePath(object.__getattribute__(parent, 'path'),
74 self.parseMappingBody(rv)
75 self.match(src.pyconf.RCURLY)
77 self.match(src.pyconf.AT)
78 __, fn = self.match('"')
79 rv = profileReference(self, src.pyconf.AT, fn)
82 ##################################################
85 # Describes the command
87 return _("The profile command creates default profile.\nusage: sat profile "
88 "[PRODUCT] [-p|--prefix (string)] [-n|--name (string)] [-f|--force"
89 "] [-v|--version (string)] [-s|--slogan (string)]")
92 # Gets the profile name
93 def get_profile_name ( options, config ):
97 res = config.APPLICATION.name + "_PROFILE"
101 # Generates the sources of the profile
102 def generate_profile_sources( config, options, logger ):
103 #Check script app-quickstart.py exists
104 kernel_cfg = src.product.get_product_config(config, "KERNEL")
105 kernel_root_dir = kernel_cfg.install_dir
106 if not src.product.check_installation(kernel_cfg):
107 raise src.SatException(_("KERNEL is not installed"))
108 script = os.path.join(kernel_root_dir,"bin","salome","app-quickstart.py")
109 if not os.path.exists( script ):
110 raise src.SatException(_("KERNEL's install has not the script "
111 "app-quickstart.py"))
113 # Check that GUI is installed
114 gui_cfg = src.product.get_product_config(config, "GUI")
115 gui_root_dir = gui_cfg.install_dir
116 if not src.product.check_installation(gui_cfg):
117 raise src.SatException(_("GUI is not installed"))
119 #Set prefix option passed to app-quickstart.py
120 name = get_profile_name ( options, config )
121 prefix = os.path.join( options.prefix, name )
122 if os.path.exists( prefix ) :
123 if not options.force :
124 raise src.SatException( _("The path %s already exists, use option"
125 " --force to remove it." %prefix ) )
127 shutil.rmtree( prefix )
129 #Set name option passed to app-quickstart.py
130 if name.upper().endswith("_PROFILE"):
133 #Write command line that calls app-quickstart.py
134 command = "python %s --prefix=%s --name=%s --modules=_NO_ --version=%s" % (
135 script, prefix, name, options.version )
137 command += " --force"
139 command += " --slogan=%s" % options.slogan
140 logger.write("\n>" + command + "\n", 5, False)
143 os.environ["KERNEL_ROOT_DIR"] = kernel_root_dir
144 os.environ["GUI_ROOT_DIR"] = gui_root_dir
145 res = subprocess.call(command,
148 stdout=logger.logTxtFile,
149 stderr=subprocess.STDOUT)
150 #Check result of command
152 raise src.SatException(_("Cannot create application, code = %d\n")%res)
154 logger.write(_("Profile sources were generated in directory %s.\n"%prefix),
160 def update_pyconf( config, options, logger ):
162 #Save previous version
163 pyconf = config.VARS.product + '.pyconf'
164 pyconfBackup = config.VARS.product + '-backup.pyconf'
165 logger.write(_("Updating %(new)s (previous version saved "
166 "as %(old)s).") % { "new": pyconf, "old": pyconfBackup }, 3)
167 path = config.getPath( pyconf )
168 shutil.copyfile( os.path.join( path, pyconf ),
169 os.path.join( path, pyconfBackup ) )
172 cfg = src.pyconf.Config( )
173 object.__setattr__( cfg, 'reader', profileConfigReader( cfg ) )
174 cfg.load( src.pyconf.defaultStreamOpener( os.path.join( path, pyconf ) ) )
176 #Check if profile is in APPLICATION.products
177 profile = get_profile_name ( options, config )
178 if not profile in cfg.APPLICATION.products:
179 cfg.APPLICATION.products.append( profile, None )
181 #Check if profile is in APPLICATION
182 if not 'profile' in cfg.APPLICATION:
183 cfg.APPLICATION.addMapping( 'profile', src.pyconf.Mapping(), None )
184 cfg.APPLICATION.profile.addMapping( 'module', profile, None )
185 cfg.APPLICATION.profile.addMapping( 'launcher_name',
186 config.VARS.product.lower(), None )
188 #Check if profile info is in PRODUCTS
189 if not 'PRODUCTS' in cfg:
190 cfg.addMapping( 'PRODUCTS', src.pyconf.Mapping(), None )
192 if not profile in cfg.PRODUCTS:
193 cfg.PRODUCTS.addMapping( profile, src.pyconf.Mapping(), None )
194 cfg.PRODUCTS[profile].addMapping( 'default', src.pyconf.Mapping(),
196 prf = cfg.TOOLS.common.module_info[profile].default
197 prf.addMapping( 'name', profile, None )
198 prf.addMapping( 'get_source', 'archive', None )
199 prf.addMapping( 'build_source', 'cmake', None )
200 prf.addMapping( 'archive_info', src.pyconf.Mapping(), None )
201 prf.archive_info.addMapping( 'name',
202 os.path.join(os.path.abspath(options.prefix),
204 prf.addMapping( 'source_dir', src.pyconf.Reference(cfg,
206 'APPLICATION.workdir'
207 ' + $VARS.sep + "SOU'
208 'RCES" + $VARS.sep +'
210 prf.addMapping( 'build_dir', src.pyconf.Reference(cfg,
212 'APPLICATION.workdir '
213 '+ $VARS.sep + "BUILD'
214 '" + $VARS.sep + $nam'
216 prf.addMapping( 'depend', src.pyconf.Sequence(), None )
217 prf.depend.append( 'KERNEL', None )
218 prf.depend.append( 'GUI', None )
219 prf.depend.append( 'Python', None )
220 prf.depend.append( 'Sphinx', None )
221 prf.depend.append( 'qt', None )
222 prf.addMapping( 'opt_depend', src.pyconf.Sequence(), None )
225 f = file( os.path.join( path, pyconf ) , 'w')
231 def run(args, runner, logger):
232 '''method that is called when salomeTools is called with profile parameter.
234 (options, args) = parser.parse_args(args)
236 src.check_config_has_application(runner.cfg)
238 if options.prefix is None:
239 msg = _("The --%s argument is required\n") % "prefix"
240 logger.write(src.printcolors.printcWarning(msg), 1)
243 retcode = generate_profile_sources( runner.cfg, options, logger )
245 if not options.no_update :
246 update_pyconf( runner.cfg, options )