koji_build.py 3.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  1. #!/bin/env python
  2. from __future__ import print_function
  3. import argparse
  4. import os
  5. import subprocess
  6. import re
  7. def check_dir(dirpath):
  8. if not os.path.isdir(dirpath):
  9. raise Exception("Directory %s doesn't exist" % dirpath)
  10. return dirpath
  11. def check_git_repo(dirpath):
  12. cwd = os.getcwd()
  13. os.chdir(dirpath)
  14. # check that the working copy is a working directory and is clean
  15. try:
  16. subprocess.check_call(['git', 'diff-index', '--quiet', 'HEAD', '--'])
  17. ret = True
  18. except:
  19. ret = False
  20. os.chdir(cwd)
  21. return ret
  22. def get_repo_and_commit_info(dirpath):
  23. cwd = os.getcwd()
  24. os.chdir(dirpath)
  25. remote = subprocess.check_output(['git', 'config', '--get', 'remote.origin.url']).strip()
  26. # We want the exact hash for accurate build history
  27. hash = subprocess.check_output(['git', 'rev-parse', 'HEAD']).strip()
  28. os.chdir(cwd)
  29. return remote, hash
  30. def koji_url(remote, hash):
  31. if remote.startswith('git@'):
  32. remote = re.sub(r'git@(.+):', r'git+https://\1/', remote)
  33. elif remote.startswith('https://'):
  34. remote = 'git+' + remote
  35. else:
  36. raise Exception("Unrecognized remote URL")
  37. return remote + "?#" + hash
  38. def main():
  39. parser = argparse.ArgumentParser(description='Build a package or chain-build several from local git repos for RPM sources')
  40. parser.add_argument('target', help='Koji target for the build')
  41. parser.add_argument('git_repos', nargs='+',
  42. help='local path to one or more git repositories. If several are provided, '
  43. 'a chained build will be started in the order of the arguments')
  44. parser.add_argument('--scratch', action="store_true", help='Perform scratch build')
  45. parser.add_argument('--nowait', action="store_true", help='Do not wait for the build to end')
  46. args = parser.parse_args()
  47. target = args.target
  48. git_repos = [os.path.abspath(check_dir(d)) for d in args.git_repos]
  49. is_scratch = args.scratch
  50. is_nowait = args.nowait
  51. if len(git_repos) > 1 and is_scratch:
  52. parser.error("--scratch is not compatible with chained builds.")
  53. for d in git_repos:
  54. if not check_git_repo(d):
  55. parser.error("%s is not in a clean state (or is not a git repository)." % d)
  56. if len(git_repos) == 1:
  57. remote, hash = get_repo_and_commit_info(git_repos[0])
  58. url = koji_url(remote, hash)
  59. command = ['koji', 'build'] + (['--scratch'] if is_scratch else []) + [target, url] + (['--nowait'] if is_nowait else [])
  60. subprocess.check_call(['echo'] + command)
  61. subprocess.check_call(command)
  62. else:
  63. urls = []
  64. for d in git_repos:
  65. remote, hash = get_repo_and_commit_info(d)
  66. urls.append(koji_url(remote, hash))
  67. command = ['koji', 'chain-build', target] + (' : '.join(urls)).split(' ') + (['--nowait'] if is_nowait else [])
  68. subprocess.check_call(['echo'] + command)
  69. subprocess.check_call(command)
  70. if __name__ == "__main__":
  71. main()