Salome HOME
sat #17359 bug fix : take into account incremental mode in sat package
[tools/sat.git] / src / system.py
1 #!/usr/bin/env python
2 #-*- coding:utf-8 -*-
3 #  Copyright (C) 2010-2013  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 '''
20 In this file : all functions that do a system call, 
21 like open a browser or an editor, or call a git command
22 '''
23
24 import os
25 import subprocess
26 import time
27 import tarfile
28
29 import debug as DBG
30 import utilsSat as UTS
31 import src
32
33 from . import printcolors
34
35 def show_in_editor(editor, filePath, logger):
36     '''open filePath using editor.
37     
38     :param editor str: The editor to use.
39     :param filePath str: The path to the file to open.
40     '''
41     # default editor is vi
42     if editor is None or len(editor) == 0:
43         editor = 'vi'
44     
45     if '%s' not in editor:
46         editor += ' %s'
47
48     try:
49         # launch cmd using subprocess.Popen
50         cmd = editor % filePath
51         logger.write('Launched command:\n' + cmd + '\n', 5)
52         p = subprocess.Popen(cmd, shell=True)
53         p.communicate()
54     except:
55         logger.write(printcolors.printcError(_("Unable to edit file %s\n") 
56                                              % filePath), 1)
57
58 def git_describe(repo_path):
59     '''Use git describe --tags command to return tag description of the git repository"
60     :param repo_path str: The git repository to describe
61     '''
62     git_cmd="cd %s;git describe --tags" % repo_path
63     p = subprocess.Popen(git_cmd, shell=True,
64                     stdin=subprocess.PIPE,
65                     stdout=subprocess.PIPE,
66                     stderr=subprocess.PIPE)
67     p.wait()
68     if p.returncode != 0:
69         return False
70     else:
71         return p.stdout.readlines()[0].strip()
72
73
74 def git_extract(from_what, tag, where, logger, environment=None):
75   '''Extracts sources from a git repository.
76
77   :param from_what str: The remote git repository.
78   :param tag str: The tag.
79   :param where str: The path where to extract.
80   :param logger Logger: The logger instance to use.
81   :param environment src.environment.Environ: The environment to source when extracting.
82   :return: True if the extraction is successful
83   :rtype: boolean
84   '''
85   DBG.write("git_extract", [from_what, tag, str(where)])
86   if not where.exists():
87     where.make()
88   if tag == "master" or tag == "HEAD":
89     if src.architecture.is_windows():
90       cmd = "git clone %(remote)s %(where)s"
91     else:
92       cmd = r"""
93 set -x
94 git clone %(remote)s %(where)s
95 """
96     cmd = cmd % {'remote': from_what, 'tag': tag, 'where': str(where)}
97   else:
98     # NOTICE: this command only works with recent version of git
99     #         because --work-tree does not work with an absolute path
100     where_git = os.path.join(str(where), ".git")
101     if src.architecture.is_windows():
102       cmd = "rmdir %(where)s && git clone %(remote)s %(where)s && git --git-dir=%(where_git)s --work-tree=%(where)s checkout %(tag)s"
103     else:
104       cmd = r"""
105 set -x
106 rmdir %(where)s
107 git clone %(remote)s %(where)s && \
108 git --git-dir=%(where_git)s --work-tree=%(where)s checkout %(tag)s
109 """
110     cmd = cmd % {'remote': from_what,
111                  'tag': tag,
112                  'where': str(where),
113                  'where_git': where_git}
114
115
116   logger.logTxtFile.write("\n" + cmd + "\n")
117   logger.logTxtFile.flush()
118
119   DBG.write("cmd", cmd)
120
121   # git commands may fail sometimes for various raisons 
122   # (big module, network troubles, tuleap maintenance)
123   # therefore we give several tries
124   i_try = 0
125   max_number_of_tries = 3
126   sleep_delay = 30  # seconds
127   while (True):
128     i_try += 1
129     rc = UTS.Popen(cmd, cwd=str(where.dir()), env=environment.environ.environ, logger=logger)
130     if rc.isOk() or (i_try>=max_number_of_tries):
131       break
132     logger.write('\ngit command failed! Wait %d seconds and give an other try (%d/%d)\n' % \
133                  (sleep_delay, i_try + 1, max_number_of_tries), 3)
134     time.sleep(sleep_delay) # wait a little
135
136   return rc.isOk()
137
138
139 def git_extract_sub_dir(from_what, tag, where, sub_dir, logger, environment=None):
140   '''Extracts sources from a subtree sub_dir of a git repository.
141
142   :param from_what str: The remote git repository.
143   :param tag str: The tag.
144   :param where str: The path where to extract.
145   :param sub_dir str: The relative path of subtree to extract.
146   :param logger Logger: The logger instance to use.
147   :param environment src.environment.Environ: The environment to source when extracting.
148   :return: True if the extraction is successful
149   :rtype: boolean
150   '''
151   strWhere = str(where)
152   tmpWhere = strWhere + '_tmp'
153   parentWhere = os.path.dirname(strWhere)
154   if not os.path.exists(parentWhere):
155     logger.error("not existing directory: %s" % parentWhere)
156     return False
157   if os.path.isdir(strWhere):
158     logger.error("do not override existing directory: %s" % strWhere)
159     return False
160   aDict = {'remote': from_what,
161            'tag': tag,
162            'sub_dir': sub_dir,
163            'where': strWhere,
164            'parentWhere': parentWhere,
165            'tmpWhere': tmpWhere,
166            }
167   DBG.write("git_extract_sub_dir", aDict)
168   if not src.architecture.is_windows():
169     cmd = r"""
170 set -x
171 export tmpDir=%(tmpWhere)s && \
172 rm -rf $tmpDir
173 git clone %(remote)s $tmpDir && \
174 cd $tmpDir && \
175 git checkout %(tag)s && \
176 mv %(sub_dir)s %(where)s && \
177 git log -1 > %(where)s/README_git_log.txt && \
178 rm -rf $tmpDir
179 """ % aDict
180   else:
181     cmd = r"""
182
183 set tmpDir=%(tmpWhere)s && \
184 rm -rf $tmpDir
185 git clone %(remote)s $tmpDir && \
186 cd $tmpDir && \
187 git checkout %(tag)s && \
188 mv %(sub_dir)s %(where)s && \
189 git log -1 > %(where)s/README_git_log.txt && \
190 rm -rf $tmpDir
191 """ % aDict
192
193   DBG.write("cmd", cmd)
194
195   for nbtry in range(0,3): # retries case of network problem
196     rc = UTS.Popen(cmd, cwd=parentWhere, env=environment.environ.environ, logger=logger)
197     if rc.isOk(): break
198     time.sleep(30) # wait a little
199
200   return rc.isOk()
201
202 def archive_extract(from_what, where, logger):
203     '''Extracts sources from an archive.
204     
205     :param from_what str: The path to the archive.
206     :param where str: The path where to extract.
207     :param logger Logger: The logger instance to use.
208     :return: True if the extraction is successful
209     :rtype: boolean
210     '''
211     try:
212         archive = tarfile.open(from_what)
213         for i in archive.getmembers():
214             archive.extract(i, path=str(where))
215         return True, os.path.commonprefix(archive.getnames())
216     except Exception as exc:
217         logger.write("archive_extract: %s\n" % exc)
218         return False, None
219
220 def cvs_extract(protocol, user, server, base, tag, product, where,
221                 logger, checkout=False, environment=None):
222     '''Extracts sources from a cvs repository.
223     
224     :param protocol str: The cvs protocol.
225     :param user str: The user to be used.
226     :param server str: The remote cvs server.
227     :param base str: .
228     :param tag str: The tag.
229     :param product str: The product.
230     :param where str: The path where to extract.
231     :param logger Logger: The logger instance to use.
232     :param checkout boolean: If true use checkout cvs.
233     :param environment src.environment.Environ: The environment to source when
234                                                 extracting.
235     :return: True if the extraction is successful
236     :rtype: boolean
237     '''
238
239     opttag = ''
240     if tag is not None and len(tag) > 0:
241         opttag = '-r ' + tag
242
243     cmd = 'export'
244     if checkout:
245         cmd = 'checkout'
246     elif len(opttag) == 0:
247         opttag = '-DNOW'
248     
249     if len(protocol) > 0:
250         root = "%s@%s:%s" % (user, server, base)
251         command = "cvs -d :%(protocol)s:%(root)s %(command)s -d %(where)s %(tag)s %(product)s" % \
252             { 'protocol': protocol, 'root': root, 'where': str(where.base()),
253               'tag': opttag, 'product': product, 'command': cmd }
254     else:
255         command = "cvs -d %(root)s %(command)s -d %(where)s %(tag)s %(base)s/%(product)s" % \
256             { 'root': server, 'base': base, 'where': str(where.base()),
257               'tag': opttag, 'product': product, 'command': cmd }
258
259     logger.write(command + "\n", 5)
260
261     if not where.dir().exists():
262         where.dir().make()
263
264     logger.logTxtFile.write("\n" + command + "\n")
265     logger.logTxtFile.flush()        
266     res = subprocess.call(command,
267                           cwd=str(where.dir()),
268                           env=environment.environ.environ,
269                           shell=True,
270                           stdout=logger.logTxtFile,
271                           stderr=subprocess.STDOUT)
272     return (res == 0)
273
274 def svn_extract(user,
275                 from_what,
276                 tag,
277                 where,
278                 logger,
279                 checkout=False,
280                 environment=None):
281     '''Extracts sources from a svn repository.
282     
283     :param user str: The user to be used.
284     :param from_what str: The remote git repository.
285     :param tag str: The tag.
286     :param where str: The path where to extract.
287     :param logger Logger: The logger instance to use.
288     :param checkout boolean: If true use checkout svn.
289     :param environment src.environment.Environ: The environment to source when
290                                                 extracting.
291     :return: True if the extraction is successful
292     :rtype: boolean
293     '''
294     if not where.exists():
295         where.make()
296
297     if checkout:
298         command = "svn checkout --username %(user)s %(remote)s %(where)s" % \
299             { 'remote': from_what, 'user' : user, 'where': str(where) }
300     else:
301         command = ""
302         if os.path.exists(str(where)):
303             command = "/bin/rm -rf %(where)s && " % \
304                 { 'remote': from_what, 'where': str(where) }
305         
306         if tag == "master":
307             command += "svn export --username %(user)s %(remote)s %(where)s" % \
308                 { 'remote': from_what, 'user' : user, 'where': str(where) }       
309         else:
310             command += "svn export -r %(tag)s --username %(user)s %(remote)s %(where)s" % \
311                 { 'tag' : tag, 'remote': from_what, 'user' : user, 'where': str(where) }
312     
313     logger.logTxtFile.write(command + "\n")
314     
315     logger.write(command + "\n", 5)
316     logger.logTxtFile.write("\n" + command + "\n")
317     logger.logTxtFile.flush()
318     res = subprocess.call(command,
319                           cwd=str(where.dir()),
320                           env=environment.environ.environ,
321                           shell=True,
322                           stdout=logger.logTxtFile,
323                           stderr=subprocess.STDOUT)
324     return (res == 0)