pymtt
 All Classes Namespaces Files Functions Variables Groups
Git.py
Go to the documentation of this file.
1 # -*- coding: utf-8; tab-width: 4; indent-tabs-mode: f; python-indent: 4 -*-
2 #
3 # Copyright (c) 2015-2018 Intel, Inc. All rights reserved.
4 # $COPYRIGHT$
5 #
6 # Additional copyrights may follow
7 #
8 # $HEADER$
9 #
10 
11 from __future__ import print_function
12 from future import standard_library
13 standard_library.install_aliases()
14 import os
15 from urllib.parse import urlparse
16 from FetchMTTTool import *
17 from distutils.spawn import find_executable
18 
19 ## @addtogroup Tools
20 # @{
21 # @addtogroup Fetch
22 # @section Git
23 # Plugin for getting software via Git
24 # @param module Modules (or lmod modules) to be loaded for accessing this package
25 # @param url URL to access the repository
26 # @param username Username required for accessing the repository
27 # @param password Password required for that user to access the repository
28 # @param pwfile File where password can be found
29 # @param branch Branch (if not master) to be downloaded
30 # @param pr Pull request to be downloaded
31 # @param subdir Subdirectory of interest in repository
32 # @}
34 
35  def __init__(self):
36  # initialise parent class
37  FetchMTTTool.__init__(self)
38  self.activated = False
39  # track the repos we have processed so we
40  # don't do them multiple times
41  self.done = {}
42  self.options = {}
43  self.options['module'] = (None, "Modules (or lmod modules) to be loaded for accessing this package")
44  self.options['url'] = (None, "URL to access the repository")
45  self.options['username'] = (None, "Username required for accessing the repository")
46  self.options['password'] = (None, "Password required for that user to access the repository")
47  self.options['pwfile'] = (None, "File where password can be found")
48  self.options['branch'] = (None, "Branch (if not master) to be downloaded")
49  self.options['pr'] = (None, "Pull request to be downloaded")
50  self.options['subdir'] = (None, "Subdirectory of interest in repository")
51  return
52 
53  def activate(self):
54  if not self.activated:
55  # use the automatic procedure from IPlugin
56  IPlugin.activate(self)
57  return
58 
59  def deactivate(self):
60  IPlugin.deactivate(self)
61  return
62 
63  def print_name(self):
64  return "Git"
65 
66  def print_options(self, testDef, prefix):
67  lines = testDef.printOptions(self.options)
68  for line in lines:
69  print(prefix + line)
70  return
71 
72  def execute(self, log, keyvals, testDef):
73  testDef.logger.verbose_print("Git Execute")
74  # parse any provided options - these will override the defaults
75  cmds = {}
76  testDef.parseOptions(log, self.options, keyvals, cmds)
77  # check that they gave us a URL
78  try:
79  if cmds['url'] is not None:
80  url = cmds['url']
81  except KeyError:
82  log['status'] = 1
83  log['stderr'] = "No repository URL was provided"
84  return
85  testDef.logger.verbose_print("Working repo " + url)
86  username = cmds['username']
87  password = None
88  # see if they gave us a password
89  try:
90  if cmds['password'] is not None:
91  password = cmds['password']
92  else:
93  try:
94  if cmds['pwfile'] is not None:
95  if os.path.exists(cmds['pwfile']):
96  f = open(cmds['pwfile'], 'r')
97  password = f.readline().strip()
98  f.close()
99  else:
100  log['status'] = 1;
101  log['stderr'] = "Password file " + cmds['pwfile'] + " does not exist"
102  return
103  except KeyError:
104  pass
105  except KeyError:
106  # if not, did they give us a file where we can find the password
107  try:
108  if cmds['pwfile'] is not None:
109  if os.path.exists(cmds['pwfile']):
110  f = open(cmds['pwfile'], 'r')
111  password = f.readline().strip()
112  f.close()
113  else:
114  log['status'] = 1;
115  log['stderr'] = "Password file " + cmds['pwfile'] + " does not exist"
116  return
117  except KeyError:
118  pass
119  # check for sanity - if a password was given, then
120  # we must have a username
121  if password is not None:
122  if username is None:
123  log['status'] = 1;
124  log['stderr'] = "Password without username"
125  return
126  # find the "//"
127  (leader,tail) = url.split("//", 1)
128  # put the username:password into the url
129  url = leader + "//" + username + ":" + password + "@" + tail
130  elif username is not None:
131  # find the "//"
132  (leader,tail) = url.split("//", 1)
133  # put the username:password into the url
134  url = leader + "//" + username + "@" + tail
135  testDef.logger.verbose_print("Working final repo " + url)
136  # the path component of the parser output contains
137  # the name of the repo
138  repo = os.path.basename(urlparse(url).path)
139  # check to see if we have already processed this repo
140  try:
141  if self.done[repo] is not None:
142  log['status'] = self.done[repo][0]
143  log['location'] = self.done[repo][1]
144  return
145  except KeyError:
146  pass
147  # check to see if they specified a module to use
148  # where git can be found
149  usedModule = False
150  try:
151  if cmds['modules'] is not None:
152  status,stdout,stderr = testDef.modcmd.loadModules(cmds['modules'], testDef)
153  if 0 != status:
154  log['status'] = status
155  log['stderr'] = stderr
156  return
157  usedModule = True
158  except KeyError:
159  pass
160  # now look for the executable in our path
161  if not find_executable("git"):
162  log['status'] = 1
163  log['stderr'] = "Executable git not found"
164  if usedModule:
165  # unload the modules before returning
166  status,stdout,stderr = testDef.modcmd.unloadModules(cmds['modules'], testDef)
167  if 0 != status:
168  log['status'] = status
169  log['stderr'] = stderr
170  return
171  return
172  # see if they asked for a specific branch
173  branch = None
174  try:
175  if cmds['branch'] is not None:
176  branch = cmds['branch']
177  except KeyError:
178  pass
179  # or if they asked for a specific PR
180  pr = None
181  try:
182  if cmds['pr'] is not None:
183  pr = cmds['pr']
184  except KeyError:
185  pass
186  # see if we have already serviced this one
187  for rep in self.done:
188  if rep[0] == repo:
189  # log the status from that attempt
190  log['status'] = rep[1]
191  if 0 != rep[1]:
192  log['stderr'] = "Prior attempt to clone or update repo {0} failed".format(repo)
193  if usedModule:
194  # unload the modules before returning
195  status,stdout,stderr = testDef.modcmd.unloadModules(cmds['modules'], testDef)
196  if 0 != status:
197  log['status'] = status
198  log['stderr'] = stderr
199  return
200  return
201  # record our current location
202  cwd = os.getcwd()
203 
204  dst = os.path.join(testDef.options['scratchdir'], log['section'].replace(":","_"))
205  try:
206  if not os.path.exists(dst): os.mkdir(dst)
207  except:
208  log['status'] = 1
209  log['stderr'] = "Unable to create " + dst
210  return
211 
212  # change to the scratch directory
213  os.chdir(dst)
214  # see if this software has already been cloned
215  if os.path.exists(repo):
216  if not os.path.isdir(repo):
217  log['status'] = 1
218  log['stderr'] = "Cannot update or clone repository {0} as a file of that name already exists".format(repo)
219  # track that we serviced this one
220  self.done.append((repo, 1))
221  if usedModule:
222  # unload the modules before returning
223  status,stdout,stderr = testDef.modcmd.unloadModules(keyvals['modules'], testDef)
224  if 0 != status:
225  log['status'] = status
226  log['stderr'] = stderr
227  return
228  return
229  # move to that location
230  os.chdir(repo)
231  # if they want us to leave it as-is, then we are done
232  try:
233  if cmds['asis']:
234  status = 0
235  stdout = None
236  stderr = None
237  except KeyError:
238  # since it already exists, let's just update it
239  status, stdout, stderr, _ = testDef.execmd.execute(cmds, ["git", "pull"], testDef)
240  else:
241  # clone it
242  if branch is not None:
243  status, stdout, stderr, _ = testDef.execmd.execute(cmds, ["git", "clone", "-b", branch, url], testDef)
244  else:
245  status, stdout, stderr, _ = testDef.execmd.execute(cmds, ["git", "clone", url], testDef)
246  # move into it
247  os.chdir(repo)
248  # record the result
249  log['status'] = status
250  log['stdout'] = stdout
251  log['stderr'] = stderr
252 
253  # log our absolute location so others can find it
254  log['location'] = os.getcwd()
255  # if they indicated that a specific subdirectory was
256  # the target, then modify the location accordingly
257  cmdlog = 'Fetch CMD: ' + ' '.join(cmds)
258  testDef.logger.verbose_print(cmdlog)
259  try:
260  if cmds['subdir'] is not None:
261  log['location'] = os.path.join(log['location'], cmds['subdir'])
262  except KeyError:
263  pass
264  # track that we serviced this one
265  self.done[repo] = (status, log['location'])
266  if usedModule:
267  # unload the modules before returning
268  status,stdout,stderr = testDef.modcmd.unloadModules(cmds['modules'], testDef)
269  if 0 != status:
270  log['status'] = status
271  log['stderr'] = stderr
272  return
273  # change back to the original directory
274  os.chdir(cwd)
275 
276  return
def activate
Definition: Git.py:53
def __init__
Definition: Git.py:35
Definition: Git.py:33
def print_options
Definition: Git.py:66
def execute
Definition: Git.py:72
activated
Definition: Git.py:38
def deactivate
Definition: Git.py:59
options
Definition: Git.py:42
def print_name
Definition: Git.py:63
done
Definition: Git.py:41