import_orig.py 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477
  1. # vim: set fileencoding=utf-8 :
  2. #
  3. # (C) 2006, 2007, 2009, 2011, 2015 Guido Guenther <agx@sigxcpu.org>
  4. # This program is free software; you can redistribute it and/or modify
  5. # it under the terms of the GNU General Public License as published by
  6. # the Free Software Foundation; either version 2 of the License, or
  7. # (at your option) any later version.
  8. #
  9. # This program is distributed in the hope that it will be useful,
  10. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. # GNU General Public License for more details.
  13. #
  14. # You should have received a copy of the GNU General Public License
  15. # along with this program; if not, please see
  16. # <http://www.gnu.org/licenses/>
  17. #
  18. """Import a new upstream version into a Git repository"""
  19. from six.moves import configparser
  20. import os
  21. import sys
  22. import tempfile
  23. import gbp.command_wrappers as gbpc
  24. from gbp.deb import (DebianPkgPolicy, parse_changelog_repo)
  25. from gbp.deb.upstreamsource import DebianUpstreamSource
  26. from gbp.deb.uscan import (Uscan, UscanError)
  27. from gbp.deb.changelog import ChangeLog, NoChangeLogError
  28. from gbp.deb.git import (GitRepositoryError, DebianGitRepository)
  29. from gbp.config import GbpOptionParserDebian, GbpOptionGroup, no_upstream_branch_msg
  30. from gbp.errors import GbpError
  31. from gbp.format import format_str
  32. import gbp.log
  33. from gbp.scripts.common.import_orig import (orig_needs_repack, cleanup_tmp_tree,
  34. ask_package_name, ask_package_version,
  35. repack_source, is_link_target, download_orig)
  36. def prepare_pristine_tar(archive, pkg, version):
  37. """
  38. Prepare the upstream source for pristine tar import.
  39. This checks if the upstream source is actually a tarball
  40. and creates a symlink from I{archive}
  41. to I{<pkg>_<version>.orig.tar.<ext>} so pristine-tar will
  42. see the correct basename.
  43. @param archive: the upstream source's name
  44. @type archive: C{str}
  45. @param pkg: the source package's name
  46. @type pkg: C{str}
  47. @param version: the upstream version number
  48. @type version: C{str}
  49. @rtype: C{str}
  50. """
  51. linked = False
  52. if os.path.isdir(archive):
  53. return None
  54. ext = os.path.splitext(archive)[1]
  55. if ext in ['.tgz', '.tbz2', '.tlz', '.txz' ]:
  56. ext = ".%s" % ext[2:]
  57. link = "../%s_%s.orig.tar%s" % (pkg, version, ext)
  58. if os.path.basename(archive) != os.path.basename(link):
  59. try:
  60. if not is_link_target(archive, link):
  61. os.symlink(os.path.abspath(archive), link)
  62. linked = True
  63. except OSError as err:
  64. raise GbpError("Cannot symlink '%s' to '%s': %s" % (archive, link, err[1]))
  65. return (link, linked)
  66. else:
  67. return (archive, linked)
  68. def upstream_import_commit_msg(options, version):
  69. return options.import_msg % dict(version=version)
  70. def detect_name_and_version(repo, source, options):
  71. # Guess defaults for the package name and version from the
  72. # original tarball.
  73. guessed_package, guessed_version = source.guess_version()
  74. # Try to find the source package name
  75. try:
  76. cp = ChangeLog(filename='debian/changelog')
  77. sourcepackage = cp['Source']
  78. except NoChangeLogError:
  79. try:
  80. # Check the changelog file from the repository, in case
  81. # we're not on the debian-branch (but upstream, for
  82. # example).
  83. cp = parse_changelog_repo(repo, options.debian_branch, 'debian/changelog')
  84. sourcepackage = cp['Source']
  85. except NoChangeLogError:
  86. if options.interactive:
  87. sourcepackage = ask_package_name(guessed_package,
  88. DebianPkgPolicy.is_valid_packagename,
  89. DebianPkgPolicy.packagename_msg)
  90. else:
  91. if guessed_package:
  92. sourcepackage = guessed_package
  93. else:
  94. raise GbpError("Couldn't determine upstream package name. Use --interactive.")
  95. # Try to find the version.
  96. if options.version:
  97. version = options.version
  98. else:
  99. if options.interactive:
  100. version = ask_package_version(guessed_version,
  101. DebianPkgPolicy.is_valid_upstreamversion,
  102. DebianPkgPolicy.upstreamversion_msg)
  103. else:
  104. if guessed_version:
  105. version = guessed_version
  106. else:
  107. raise GbpError("Couldn't determine upstream version. Use '-u<version>' or --interactive.")
  108. return (sourcepackage, version)
  109. def find_source(use_uscan, args):
  110. """Find the tarball to import - either via uscan or via command line argument
  111. @return: upstream source filename or None if nothing to import
  112. @rtype: string
  113. @raise GbpError: raised on all detected errors
  114. >>> find_source(False, ['too', 'much'])
  115. Traceback (most recent call last):
  116. ...
  117. GbpError: More than one archive specified. Try --help.
  118. >>> find_source(False, [])
  119. Traceback (most recent call last):
  120. ...
  121. GbpError: No archive to import specified. Try --help.
  122. >>> find_source(True, ['tarball'])
  123. Traceback (most recent call last):
  124. ...
  125. GbpError: you can't pass both --uscan and a filename.
  126. >>> find_source(False, ['tarball']).path
  127. 'tarball'
  128. """
  129. if use_uscan:
  130. if args:
  131. raise GbpError("you can't pass both --uscan and a filename.")
  132. uscan = Uscan()
  133. gbp.log.info("Launching uscan...")
  134. try:
  135. uscan.scan()
  136. except UscanError as e:
  137. raise GbpError("%s" % e)
  138. if not uscan.uptodate:
  139. if uscan.tarball:
  140. gbp.log.info("using %s" % uscan.tarball)
  141. args.append(uscan.tarball)
  142. else:
  143. raise GbpError("uscan didn't download anything, and no source was found in ../")
  144. else:
  145. gbp.log.info("package is up to date, nothing to do.")
  146. return None
  147. if len(args) > 1: # source specified
  148. raise GbpError("More than one archive specified. Try --help.")
  149. elif len(args) == 0:
  150. raise GbpError("No archive to import specified. Try --help.")
  151. else:
  152. archive = DebianUpstreamSource(args[0])
  153. return archive
  154. def debian_branch_merge(repo, tag, version, options):
  155. try:
  156. func = globals()["debian_branch_merge_by_%s" % options.merge_mode]
  157. except KeyError:
  158. raise GbpError("%s is not a valid merge mode" % options.merge_mode)
  159. func(repo, tag, version, options)
  160. if options.postimport:
  161. epoch = ''
  162. if os.access('debian/changelog', os.R_OK):
  163. # No need to check the changelog file from the
  164. # repository, since we're certain that we're on
  165. # the debian-branch
  166. cp = ChangeLog(filename='debian/changelog')
  167. if cp.has_epoch():
  168. epoch = '%s:' % cp.epoch
  169. info = {'version': "%s%s-1" % (epoch, version)}
  170. env = {'GBP_BRANCH': options.debian_branch}
  171. gbpc.Command(format_str(options.postimport, info), extra_env=env, shell=True)()
  172. def debian_branch_merge_by_replace(repo, tag, version, options):
  173. gbp.log.info("Replacing upstream source on '%s'" % options.debian_branch)
  174. tree = [x for x in repo.list_tree("%s^{tree}" % tag)
  175. if x[-1] != 'debian']
  176. msg = "Updated version %s from '%s'" % (version, tag)
  177. # Get the current debian/ tree on the debian branch
  178. try:
  179. deb_sha = [x for x in repo.list_tree("%s^{tree}" % options.debian_branch)
  180. if x[-1] == 'debian' and x[1] == 'tree'][0][2]
  181. tree.append(['040000', 'tree', deb_sha, 'debian'])
  182. msg += "\n\nwith Debian dir %s" % deb_sha
  183. except IndexError:
  184. pass # no debian/ dir is fine
  185. sha = repo.make_tree(tree)
  186. commit = repo.commit_tree(sha, msg, ["%s^{commit}" % options.debian_branch,
  187. "%s^{commit}" % tag])
  188. repo.update_ref("refs/heads/%s" % options.debian_branch, commit,
  189. msg="gbp: Updating %s after import of %s" % (options.debian_branch,
  190. tag))
  191. repo.force_head(commit, hard=True)
  192. def debian_branch_merge_by_merge(repo, tag, version, options):
  193. gbp.log.info("Merging to '%s'" % options.debian_branch)
  194. try:
  195. repo.merge(tag)
  196. except GitRepositoryError:
  197. raise GbpError("Merge failed, please resolve.")
  198. repo.set_branch(options.debian_branch)
  199. def set_bare_repo_options(options):
  200. """Modify options for import into a bare repository"""
  201. if options.pristine_tar or options.merge:
  202. gbp.log.info("Bare repository: setting %s%s options"
  203. % (["", " '--no-pristine-tar'"][options.pristine_tar],
  204. ["", " '--no-merge'"][options.merge]))
  205. options.pristine_tar = False
  206. options.merge = False
  207. def build_parser(name):
  208. try:
  209. parser = GbpOptionParserDebian(command=os.path.basename(name), prefix='',
  210. usage='%prog [options] /path/to/upstream-version.tar.gz | --uscan')
  211. except configparser.ParsingError as err:
  212. gbp.log.err(err)
  213. return None
  214. import_group = GbpOptionGroup(parser, "import options",
  215. "pristine-tar and filtering")
  216. tag_group = GbpOptionGroup(parser, "tag options",
  217. "options related to git tag creation")
  218. branch_group = GbpOptionGroup(parser, "version and branch naming options",
  219. "version number and branch layout options")
  220. cmd_group = GbpOptionGroup(parser, "external command options", "how and when to invoke external commands and hooks")
  221. for group in [import_group, branch_group, tag_group, cmd_group ]:
  222. parser.add_option_group(group)
  223. branch_group.add_option("-u", "--upstream-version", dest="version",
  224. help="Upstream Version")
  225. branch_group.add_config_file_option(option_name="debian-branch",
  226. dest="debian_branch")
  227. branch_group.add_config_file_option(option_name="upstream-branch",
  228. dest="upstream_branch")
  229. branch_group.add_config_file_option(option_name="upstream-vcs-tag", dest="vcs_tag",
  230. help="Upstream VCS tag add to the merge commit")
  231. branch_group.add_boolean_config_file_option(option_name="merge", dest="merge")
  232. branch_group.add_config_file_option(option_name="merge-mode", dest="merge_mode")
  233. tag_group.add_boolean_config_file_option(option_name="sign-tags",
  234. dest="sign_tags")
  235. tag_group.add_config_file_option(option_name="keyid",
  236. dest="keyid")
  237. tag_group.add_config_file_option(option_name="upstream-tag",
  238. dest="upstream_tag")
  239. import_group.add_config_file_option(option_name="filter",
  240. dest="filters", action="append")
  241. import_group.add_boolean_config_file_option(option_name="pristine-tar",
  242. dest="pristine_tar")
  243. import_group.add_boolean_config_file_option(option_name="filter-pristine-tar",
  244. dest="filter_pristine_tar")
  245. import_group.add_config_file_option(option_name="import-msg",
  246. dest="import_msg")
  247. import_group.add_boolean_config_file_option(option_name="symlink-orig",
  248. dest="symlink_orig")
  249. cmd_group.add_config_file_option(option_name="postimport", dest="postimport")
  250. parser.add_boolean_config_file_option(option_name="interactive",
  251. dest='interactive')
  252. parser.add_option("-v", "--verbose", action="store_true", dest="verbose", default=False,
  253. help="verbose command execution")
  254. parser.add_config_file_option(option_name="color", dest="color", type='tristate')
  255. parser.add_config_file_option(option_name="color-scheme",
  256. dest="color_scheme")
  257. # Accepted for compatibility
  258. parser.add_option("--no-dch", dest='no_dch', action="store_true",
  259. default=False, help="deprecated - don't use.")
  260. parser.add_option("--uscan", dest='uscan', action="store_true",
  261. default=False, help="use uscan(1) to download the new tarball.")
  262. parser.add_option("--download", dest='download', action="store_true",
  263. default=False, help="Download from URL via http(s).")
  264. return parser
  265. def parse_args(argv):
  266. """Parse the command line arguments
  267. @return: options and arguments
  268. # Silence error output
  269. >>> _gbp_log_error_bak = gbp.log.error
  270. >>> gbp.log.error = lambda x: None
  271. >>> parse_args(['arg0', '--download', '--uscan'])
  272. (None, None)
  273. >>> parse_args(['arg0', '--download', 'first', 'second'])
  274. (None, None)
  275. >>> gbp.log.error = _gbp_log_error_bak
  276. """
  277. parser = build_parser(argv[0])
  278. if not parser:
  279. return None, None
  280. (options, args) = parser.parse_args(argv[1:])
  281. gbp.log.setup(options.color, options.verbose, options.color_scheme)
  282. if options.no_dch:
  283. gbp.log.warn("'--no-dch' passed. This is now the default, please remove this option.")
  284. if options.uscan and options.download:
  285. gbp.log.error("Either uscan or --download can be used, not both.")
  286. return None, None
  287. if options.download and len(args) != 1:
  288. gbp.log.error("Need exactly one URL to download not %s" % args)
  289. return None, None
  290. return options, args
  291. def main(argv):
  292. ret = 0
  293. tmpdir = ''
  294. pristine_orig = None
  295. linked = False
  296. (options, args) = parse_args(argv)
  297. if not options:
  298. return 1
  299. try:
  300. try:
  301. repo = DebianGitRepository('.')
  302. except GitRepositoryError:
  303. raise GbpError("%s is not a git repository" % (os.path.abspath('.')))
  304. # an empty repo has now branches:
  305. initial_branch = repo.get_branch()
  306. is_empty = False if initial_branch else True
  307. if not repo.has_branch(options.upstream_branch) and not is_empty:
  308. raise GbpError(no_upstream_branch_msg % options.upstream_branch)
  309. (clean, out) = repo.is_clean()
  310. if not clean and not is_empty:
  311. gbp.log.err("Repository has uncommitted changes, commit these first: ")
  312. raise GbpError(out)
  313. # Download the source
  314. if options.download:
  315. source = download_orig(args[0])
  316. else:
  317. source = find_source(options.uscan, args)
  318. if not source:
  319. return ret
  320. (sourcepackage, version) = detect_name_and_version(repo, source, options)
  321. tag = repo.version_to_tag(options.upstream_tag, version)
  322. if repo.has_tag(tag):
  323. raise GbpError("Upstream tag '%s' already exists" % tag)
  324. if repo.bare:
  325. set_bare_repo_options(options)
  326. if not source.is_dir():
  327. tmpdir = tempfile.mkdtemp(dir='../')
  328. source.unpack(tmpdir, options.filters)
  329. gbp.log.debug("Unpacked '%s' to '%s'" % (source.path, source.unpacked))
  330. if orig_needs_repack(source, options):
  331. gbp.log.debug("Filter pristine-tar: repacking '%s' from '%s'" % (source.path, source.unpacked))
  332. (source, tmpdir) = repack_source(source, sourcepackage, version, tmpdir, options.filters)
  333. (pristine_orig, linked) = prepare_pristine_tar(source.path,
  334. sourcepackage,
  335. version)
  336. # Don't mess up our repo with git metadata from an upstream tarball
  337. try:
  338. if os.path.isdir(os.path.join(source.unpacked, '.git/')):
  339. raise GbpError("The orig tarball contains .git metadata - giving up.")
  340. except OSError:
  341. pass
  342. try:
  343. upstream_branch = [ options.upstream_branch, 'master' ][is_empty]
  344. filter_msg = ["", " (filtering out %s)"
  345. % options.filters][len(options.filters) > 0]
  346. gbp.log.info("Importing '%s' to branch '%s'%s..." % (source.path,
  347. upstream_branch,
  348. filter_msg))
  349. gbp.log.info("Source package is %s" % sourcepackage)
  350. gbp.log.info("Upstream version is %s" % version)
  351. import_branch = [ options.upstream_branch, None ][is_empty]
  352. msg = upstream_import_commit_msg(options, version)
  353. if options.vcs_tag:
  354. parents = [repo.rev_parse("%s^{}" % repo.version_to_tag(options.vcs_tag, version))]
  355. else:
  356. parents = None
  357. commit = repo.commit_dir(source.unpacked,
  358. msg=msg,
  359. branch=import_branch,
  360. other_parents=parents,
  361. )
  362. if options.pristine_tar:
  363. if pristine_orig:
  364. repo.pristine_tar.commit(pristine_orig, upstream_branch)
  365. else:
  366. gbp.log.warn("'%s' not an archive, skipping pristine-tar" % source.path)
  367. repo.create_tag(name=tag,
  368. msg="Upstream version %s" % version,
  369. commit=commit,
  370. sign=options.sign_tags,
  371. keyid=options.keyid)
  372. if is_empty:
  373. repo.create_branch(options.upstream_branch, rev=commit)
  374. repo.force_head(options.upstream_branch, hard=True)
  375. if options.debian_branch != 'master':
  376. repo.rename_branch('master', options.debian_branch)
  377. elif options.merge:
  378. debian_branch_merge(repo, tag, version, options)
  379. # Update working copy and index if we've possibly updated the
  380. # checked out branch
  381. current_branch = repo.get_branch()
  382. if current_branch in [ options.upstream_branch,
  383. repo.pristine_tar_branch]:
  384. repo.force_head(current_branch, hard=True)
  385. except (gbpc.CommandExecFailed, GitRepositoryError) as err:
  386. msg = str(err) or 'Unknown error, please report a bug'
  387. raise GbpError("Import of %s failed: %s" % (source.path, msg))
  388. except GbpError as err:
  389. if str(err):
  390. gbp.log.err(err)
  391. ret = 1
  392. if pristine_orig and linked and not options.symlink_orig:
  393. os.unlink(pristine_orig)
  394. if tmpdir:
  395. cleanup_tmp_tree(tmpdir)
  396. if not ret:
  397. gbp.log.info("Successfully imported version %s of %s" % (version, source.path))
  398. return ret
  399. if __name__ == "__main__":
  400. sys.exit(main(sys.argv))
  401. # vim:et:ts=4:sw=4:et:sts=4:ai:set list listchars=tab\:»·,trail\:·: