svn.py 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. # ex:ts=4:sw=4:sts=4:et
  2. # -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
  3. """
  4. BitBake 'Fetch' implementation for svn.
  5. """
  6. # Copyright (C) 2003, 2004 Chris Larson
  7. # Copyright (C) 2004 Marcin Juszkiewicz
  8. #
  9. # SPDX-License-Identifier: GPL-2.0-only
  10. #
  11. # Based on functions from the base bb module, Copyright 2003 Holger Schurig
  12. import os
  13. import sys
  14. import logging
  15. import bb
  16. import re
  17. from bb.fetch2 import FetchMethod
  18. from bb.fetch2 import FetchError
  19. from bb.fetch2 import MissingParameterError
  20. from bb.fetch2 import runfetchcmd
  21. from bb.fetch2 import logger
  22. class Svn(FetchMethod):
  23. """Class to fetch a module or modules from svn repositories"""
  24. def supports(self, ud, d):
  25. """
  26. Check to see if a given url can be fetched with svn.
  27. """
  28. return ud.type in ['svn']
  29. def urldata_init(self, ud, d):
  30. """
  31. init svn specific variable within url data
  32. """
  33. if not "module" in ud.parm:
  34. raise MissingParameterError('module', ud.url)
  35. ud.basecmd = d.getVar("FETCHCMD_svn") or "/usr/bin/env svn --non-interactive --trust-server-cert"
  36. ud.module = ud.parm["module"]
  37. if not "path_spec" in ud.parm:
  38. ud.path_spec = ud.module
  39. else:
  40. ud.path_spec = ud.parm["path_spec"]
  41. # Create paths to svn checkouts
  42. svndir = d.getVar("SVNDIR") or (d.getVar("DL_DIR") + "/svn")
  43. relpath = self._strip_leading_slashes(ud.path)
  44. ud.pkgdir = os.path.join(svndir, ud.host, relpath)
  45. ud.moddir = os.path.join(ud.pkgdir, ud.module)
  46. # Protects the repository from concurrent updates, e.g. from two
  47. # recipes fetching different revisions at the same time
  48. ud.svnlock = os.path.join(ud.pkgdir, "svn.lock")
  49. ud.setup_revisions(d)
  50. if 'rev' in ud.parm:
  51. ud.revision = ud.parm['rev']
  52. ud.localfile = d.expand('%s_%s_%s_%s_.tar.gz' % (ud.module.replace('/', '.'), ud.host, ud.path.replace('/', '.'), ud.revision))
  53. def _buildsvncommand(self, ud, d, command):
  54. """
  55. Build up an svn commandline based on ud
  56. command is "fetch", "update", "info"
  57. """
  58. proto = ud.parm.get('protocol', 'svn')
  59. svn_ssh = None
  60. if proto == "svn+ssh" and "ssh" in ud.parm:
  61. svn_ssh = ud.parm["ssh"]
  62. svnroot = ud.host + ud.path
  63. options = []
  64. options.append("--no-auth-cache")
  65. if ud.user:
  66. options.append("--username %s" % ud.user)
  67. if ud.pswd:
  68. options.append("--password %s" % ud.pswd)
  69. if command == "info":
  70. svncmd = "%s info %s %s://%s/%s/" % (ud.basecmd, " ".join(options), proto, svnroot, ud.module)
  71. elif command == "log1":
  72. svncmd = "%s log --limit 1 %s %s://%s/%s/" % (ud.basecmd, " ".join(options), proto, svnroot, ud.module)
  73. else:
  74. suffix = ""
  75. if ud.revision:
  76. options.append("-r %s" % ud.revision)
  77. suffix = "@%s" % (ud.revision)
  78. if command == "fetch":
  79. transportuser = ud.parm.get("transportuser", "")
  80. svncmd = "%s co %s %s://%s%s/%s%s %s" % (ud.basecmd, " ".join(options), proto, transportuser, svnroot, ud.module, suffix, ud.path_spec)
  81. elif command == "update":
  82. svncmd = "%s update %s" % (ud.basecmd, " ".join(options))
  83. else:
  84. raise FetchError("Invalid svn command %s" % command, ud.url)
  85. if svn_ssh:
  86. svncmd = "SVN_SSH=\"%s\" %s" % (svn_ssh, svncmd)
  87. return svncmd
  88. def download(self, ud, d):
  89. """Fetch url"""
  90. logger.debug(2, "Fetch: checking for module directory '" + ud.moddir + "'")
  91. lf = bb.utils.lockfile(ud.svnlock)
  92. try:
  93. if os.access(os.path.join(ud.moddir, '.svn'), os.R_OK):
  94. svnupdatecmd = self._buildsvncommand(ud, d, "update")
  95. logger.info("Update " + ud.url)
  96. # We need to attempt to run svn upgrade first in case its an older working format
  97. try:
  98. runfetchcmd(ud.basecmd + " upgrade", d, workdir=ud.moddir)
  99. except FetchError:
  100. pass
  101. logger.debug(1, "Running %s", svnupdatecmd)
  102. bb.fetch2.check_network_access(d, svnupdatecmd, ud.url)
  103. runfetchcmd(svnupdatecmd, d, workdir=ud.moddir)
  104. else:
  105. svnfetchcmd = self._buildsvncommand(ud, d, "fetch")
  106. logger.info("Fetch " + ud.url)
  107. # check out sources there
  108. bb.utils.mkdirhier(ud.pkgdir)
  109. logger.debug(1, "Running %s", svnfetchcmd)
  110. bb.fetch2.check_network_access(d, svnfetchcmd, ud.url)
  111. runfetchcmd(svnfetchcmd, d, workdir=ud.pkgdir)
  112. scmdata = ud.parm.get("scmdata", "")
  113. if scmdata == "keep":
  114. tar_flags = ""
  115. else:
  116. tar_flags = "--exclude='.svn'"
  117. # tar them up to a defined filename
  118. runfetchcmd("tar %s -czf %s %s" % (tar_flags, ud.localpath, ud.path_spec), d,
  119. cleanup=[ud.localpath], workdir=ud.pkgdir)
  120. finally:
  121. bb.utils.unlockfile(lf)
  122. def clean(self, ud, d):
  123. """ Clean SVN specific files and dirs """
  124. bb.utils.remove(ud.localpath)
  125. bb.utils.remove(ud.moddir, True)
  126. def supports_srcrev(self):
  127. return True
  128. def _revision_key(self, ud, d, name):
  129. """
  130. Return a unique key for the url
  131. """
  132. return "svn:" + ud.moddir
  133. def _latest_revision(self, ud, d, name):
  134. """
  135. Return the latest upstream revision number
  136. """
  137. bb.fetch2.check_network_access(d, self._buildsvncommand(ud, d, "log1"), ud.url)
  138. output = runfetchcmd("LANG=C LC_ALL=C " + self._buildsvncommand(ud, d, "log1"), d, True)
  139. # skip the first line, as per output of svn log
  140. # then we expect the revision on the 2nd line
  141. revision = re.search('^r([0-9]*)', output.splitlines()[1]).group(1)
  142. return revision
  143. def sortable_revision(self, ud, d, name):
  144. """
  145. Return a sortable revision number which in our case is the revision number
  146. """
  147. return False, self._build_revision(ud, d)
  148. def _build_revision(self, ud, d):
  149. return ud.revision