LSSTApplications  11.0-13-gbb96280,12.1.rc1,12.1.rc1+1,12.1.rc1+2,12.1.rc1+5,12.1.rc1+8,12.1.rc1-1-g06d7636+1,12.1.rc1-1-g253890b+5,12.1.rc1-1-g3d31b68+7,12.1.rc1-1-g3db6b75+1,12.1.rc1-1-g5c1385a+3,12.1.rc1-1-g83b2247,12.1.rc1-1-g90cb4cf+6,12.1.rc1-1-g91da24b+3,12.1.rc1-2-g3521f8a,12.1.rc1-2-g39433dd+4,12.1.rc1-2-g486411b+2,12.1.rc1-2-g4c2be76,12.1.rc1-2-gc9c0491,12.1.rc1-2-gda2cd4f+6,12.1.rc1-3-g3391c73+2,12.1.rc1-3-g8c1bd6c+1,12.1.rc1-3-gcf4b6cb+2,12.1.rc1-4-g057223e+1,12.1.rc1-4-g19ed13b+2,12.1.rc1-4-g30492a7
LSSTDataManagementBasePackage
svn.py
Go to the documentation of this file.
1 #
2 # A simple python interface to svn, using os.popen
3 #
4 # If ever we want to do anything clever, we should use one of
5 # the supported svn/python packages
6 #
7 from __future__ import absolute_import, division, print_function
8 import os
9 import re
10 import sys
11 
12 
13 def isSvnFile(file):
14  """Is file under svn control?"""
15 
16  return re.search(r"is not a working copy",
17  "".join(os.popen("svn info %s 2>&1" % file).readlines())) is None
18 
19 
20 def getInfo(file="."):
21  """Return a dictionary of all the information returned by "svn info" for the specified file"""
22 
23  if not isSvnFile(file):
24  raise RuntimeError("%s is not under svn control" % file)
25 
26  infoList = os.popen("svn info %s" % file).readlines()
27 
28  info = {}
29  for line in infoList:
30  mat = re.search(r"^([^:]+)\s*:\s*(.*)", line)
31  if mat:
32  info[mat.group(1)] = mat.group(2)
33 
34  return info
35 
36 
37 def isTrunk(file="."):
38  """Is file on the trunk?"""
39 
40  info = getInfo(file)
41 
42  return re.search(r"/trunk($|/)", info["URL"]) is not None
43 
44 
45 def revision(file=None, lastChanged=False):
46  """Return file's Revision as a string; if file is None return
47  a tuple (oldestRevision, youngestRevision, flags) as reported
48  by svnversion; e.g. (4123, 4168, ("M", "S")) (oldestRevision
49  and youngestRevision may be equal)
50  """
51 
52  if file:
53  info = getInfo(file)
54 
55  if lastChanged:
56  return info["Last Changed Rev"]
57  else:
58  return info["Revision"]
59 
60  if lastChanged:
61  raise RuntimeError("lastChanged makes no sense if file is None")
62 
63  res = os.popen("svnversion . 2>&1").readline()
64 
65  if res == "exported\n":
66  raise RuntimeError("No svn revision information is available")
67 
68  versionRe = r"^(?P<oldest>\d+)(:(?P<youngest>\d+))?(?P<flags>[MS]*)"
69  mat = re.search(versionRe, res)
70  if mat:
71  matches = mat.groupdict()
72  if not matches["youngest"]:
73  matches["youngest"] = matches["oldest"]
74  # OK, we have only one revision present. Find the newest revision
75  # that actually changed anything in this product and ignore "oldest" (#522)
76  res = os.popen("svnversion --committed . 2>&1").readline()
77  mat = re.search(versionRe, res)
78  if mat:
79  matches = mat.groupdict()
80  return matches["youngest"], matches["youngest"], tuple(matches["flags"])
81 
82  return matches["oldest"], matches["youngest"], tuple(matches["flags"])
83 
84  raise RuntimeError("svnversion returned unexpected result \"%s\"" % res[:-1])
85 
86 
87 #
88 # -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
89 #
90 def guessVersionName(HeadURL):
91  """Guess a version name given a HeadURL"""
92 
93  if re.search(r"/trunk$", HeadURL):
94  versionName = ""
95  elif re.search(r"/branches/(.+)$", HeadURL):
96  versionName = "branch_%s+" % re.search(r"/branches/(.+)$", HeadURL).group(1)
97  elif re.search(r"/tags/(.+)$", HeadURL):
98  versionName = "%s" % re.search(r"/tags/(.*)$", HeadURL).group(1)
99 
100  return versionName # no need for a "+svnXXXX"
101  elif re.search(r"/tickets/(\d+)$", HeadURL):
102  versionName = "ticket_%s+" % re.search(r"/tickets/(\d+)$", HeadURL).group(1)
103  else:
104  print("Unable to guess versionName name from %s" % HeadURL, file=sys.stderr)
105  versionName = "unknown+"
106 
107  try: # Try to lookup the svn versionName
108  (oldest, youngest, flags) = revision()
109 
110  okVersion = True
111  if "M" in flags:
112  msg = "You are installing, but have unchecked in files"
113  okVersion = False
114  if "S" in flags:
115  msg = "You are installing, but have switched SVN URLs"
116  okVersion = False
117  if oldest != youngest:
118  msg = "You have a range of revisions in your tree (%s:%s); adopting %s" % \
119  (oldest, youngest, youngest)
120  okVersion = False
121 
122  if not okVersion:
123  raise RuntimeError("Problem with determining svn revision: %s" % msg)
124 
125  versionName += "svn" + youngest
126  except IOError:
127  return "unknown"
128 
129  return versionName
130 
131 
132 def parseVersionName(versionName):
133  """A callback that knows about the LSST convention that a tagname such as
134  ticket_374
135  means the top of ticket 374, and
136  ticket_374+svn6021
137  means revision 6021 on ticket 374. You may replace "ticket" with "branch" if you wish
138 
139  The "versionName" may actually be the directory part of a URL, and ".../(branches|tags|tickets)/tagname"
140  is also supported
141  """
142 
143  mat = re.search(r"/(branche|tag|ticket)s/(\d+(?:\.\d+)*)(?:([-+])((svn)?(\d+)))?$", versionName)
144  if not mat:
145  mat = re.search(r"/(branch|ticket)_(\d+)(?:([-+])svn(\d+))?$", versionName)
146  if mat:
147  type = mat.group(1)
148  if type == "branches":
149  type = "branch"
150  ticket = mat.group(2)
151  pm = mat.group(3) # + or -
152  revision = mat.group(4)
153  if revision:
154  revision = re.sub("^svn", "", revision)
155 
156  return (type, ticket, revision, pm)
157 
158  return (None, None, None, None)