Package backend :: Module mockremote
[hide private]
[frames] | no frames]

Source Code for Module backend.mockremote

  1  #!/usr/bin/python -tt 
  2  # by skvidal 
  3  # This program is free software; you can redistribute it and/or modify 
  4  # it under the terms of the GNU General Public License as published by 
  5  # the Free Software Foundation; either version 2 of the License, or 
  6  # (at your option) any later version. 
  7  # 
  8  # This program is distributed in the hope that it will be useful, 
  9  # but WITHOUT ANY WARRANTY; without even the implied warranty of 
 10  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 11  # GNU Library General Public License for more details. 
 12  # 
 13  # You should have received a copy of the GNU General Public License 
 14  # along with this program; if not, write to the Free Software 
 15  # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA. 
 16  # copyright 2012 Red Hat, Inc. 
 17   
 18   
 19  # take list of pkgs 
 20  # take single hostname 
 21  # send 1 pkg at a time to host 
 22  # build in remote w/mockchain 
 23  # rsync results back 
 24  # repeat 
 25  # take args from mockchain (more or less) 
 26   
 27   
 28  import os 
 29  import sys 
 30  import time 
 31  import fcntl 
 32  import pipes 
 33  import socket 
 34  import urllib 
 35  import optparse 
 36  import subprocess 
 37  from operator import methodcaller 
 38   
 39  import ansible.runner 
 40   
 41  # where we should execute mockchain from on the remote 
 42  mockchain = "/usr/bin/mockchain" 
 43  # rsync path 
 44  rsync = "/usr/bin/rsync" 
 45   
 46  DEF_REMOTE_BASEDIR = "/var/tmp" 
 47  DEF_TIMEOUT = 3600 
 48  DEF_REPOS = [] 
 49  DEF_CHROOT = None 
 50  DEF_USER = "mockbuilder" 
 51  DEF_DESTDIR = os.getcwd() 
 52  DEF_MACROS = {} 
 53  DEF_BUILDROOT_PKGS = "" 
54 55 56 -class SortedOptParser(optparse.OptionParser):
57 58 """Optparser which sorts the options by opt before outputting --help""" 59
60 - def format_help(self, formatter=None):
61 self.option_list.sort(key=methodcaller("get_opt_string")) 62 return optparse.OptionParser.format_help(self, formatter=None)
63
64 65 -def createrepo(path, lock=None):
66 if os.path.exists(path + '/repodata/repomd.xml'): 67 comm = ['/usr/bin/createrepo_c', '--database', '--ignore-lock', 68 '--update', path] 69 else: 70 comm = ['/usr/bin/createrepo_c', '--database', '--ignore-lock', path] 71 if lock: 72 lock.acquire() 73 cmd = subprocess.Popen(comm, 74 stdout=subprocess.PIPE, stderr=subprocess.PIPE) 75 out, err = cmd.communicate() 76 if lock: 77 lock.release() 78 return cmd.returncode, out, err
79
80 81 -def read_list_from_file(fn):
82 lst = [] 83 f = open(fn, "r") 84 for line in f.readlines(): 85 line = line.replace("\n", "") 86 line = line.strip() 87 if line.startswith("#"): 88 continue 89 lst.append(line) 90 91 return lst
92
93 94 -def log(lf, msg, quiet=None):
95 if lf: 96 now = time.time() 97 try: 98 with open(lf, "a") as lfh: 99 fcntl.flock(lfh, fcntl.LOCK_EX) 100 lfh.write(str(now) + ":" + msg + "\n") 101 fcntl.flock(lfh, fcntl.LOCK_UN) 102 except (IOError, OSError) as e: 103 sys.stderr.write( 104 "Could not write to logfile {0} - {1}\n".format(lf, str(e))) 105 if not quiet: 106 print(msg)
107
108 109 -def get_ans_results(results, hostname):
110 if hostname in results["dark"]: 111 return results["dark"][hostname] 112 if hostname in results["contacted"]: 113 return results["contacted"][hostname] 114 115 return {}
116
117 118 -def _create_ans_conn(hostname, username, timeout):
119 ans_conn = ansible.runner.Runner(remote_user=username, 120 host_list=hostname + ",", 121 pattern=hostname, 122 forks=1, 123 transport="ssh", 124 timeout=timeout) 125 return ans_conn
126
127 128 -def check_for_ans_error(results, hostname, err_codes=[], success_codes=[0], 129 return_on_error=["stdout", "stderr"]):
130 """ 131 Return True or False + dict 132 dict includes 'msg' 133 may include 'rc', 'stderr', 'stdout' and any other requested result codes 134 """ 135 136 err_results = {} 137 138 if "dark" in results and hostname in results["dark"]: 139 err_results["msg"] = "Error: Could not contact/connect" \ 140 " to {0}.".format(hostname) 141 142 return (True, err_results) 143 144 error = False 145 146 if err_codes or success_codes: 147 if hostname in results["contacted"]: 148 if "rc" in results["contacted"][hostname]: 149 rc = int(results["contacted"][hostname]["rc"]) 150 err_results["rc"] = rc 151 # check for err codes first 152 if rc in err_codes: 153 error = True 154 err_results["msg"] = "rc {0} matched err_codes".format(rc) 155 elif rc not in success_codes: 156 error = True 157 err_results["msg"] = "rc {0} not in success_codes".format(rc) 158 159 elif ("failed" in results["contacted"][hostname] and 160 results["contacted"][hostname]["failed"]): 161 162 error = True 163 err_results["msg"] = "results included failed as true" 164 165 if error: 166 for item in return_on_error: 167 if item in results["contacted"][hostname]: 168 err_results[item] = results["contacted"][hostname][item] 169 170 return error, err_results
171
172 173 -class MockRemoteError(Exception):
174
175 - def __init__(self, msg):
176 super(MockRemoteError, self).__init__() 177 self.msg = msg
178
179 - def __str__(self):
180 return self.msg
181
182 183 -class BuilderError(MockRemoteError):
184 pass
185
186 187 -class DefaultCallBack(object):
188
189 - def __init__(self, **kwargs):
190 self.quiet = kwargs.get("quiet", False) 191 self.logfn = kwargs.get("logfn", None)
192
193 - def start_build(self, pkg):
194 pass
195
196 - def end_build(self, pkg):
197 pass
198
199 - def start_download(self, pkg):
200 pass
201
202 - def end_download(self, pkg):
203 pass
204
205 - def error(self, msg):
206 self.log("Error: {0}".format(msg))
207
208 - def log(self, msg):
209 if not self.quiet: 210 print(msg)
211
212 213 -class CliLogCallBack(DefaultCallBack):
214
215 - def __init__(self, **kwargs):
216 DefaultCallBack.__init__(self, **kwargs)
217
218 - def start_build(self, pkg):
219 msg = "Start build: {0}".format(pkg) 220 self.log(msg)
221
222 - def end_build(self, pkg):
223 msg = "End Build: {0}".format(pkg) 224 self.log(msg)
225
226 - def start_download(self, pkg):
227 msg = "Start retrieve results for: {0}".format(pkg) 228 self.log(msg)
229
230 - def end_download(self, pkg):
231 msg = "End retrieve results for: {0}".format(pkg) 232 self.log(msg)
233
234 - def error(self, msg):
235 self.log("Error: {0}".format(msg))
236
237 - def log(self, msg):
238 log(self.logfn, msg, self.quiet)
239
240 241 -class Builder(object):
242
243 - def __init__(self, hostname, username, 244 timeout, mockremote, buildroot_pkgs):
245 246 self.hostname = hostname 247 self.username = username 248 self.timeout = timeout 249 self.chroot = mockremote.chroot 250 self.repos = mockremote.repos 251 self.mockremote = mockremote 252 253 if buildroot_pkgs is None: 254 self.buildroot_pkgs = "" 255 else: 256 self.buildroot_pkgs = buildroot_pkgs 257 258 self.checked = False 259 self._tempdir = None 260 # if we're at this point we've connected and done stuff on the host 261 self.conn = _create_ans_conn( 262 self.hostname, self.username, self.timeout) 263 self.root_conn = _create_ans_conn(self.hostname, "root", self.timeout) 264 # check out the host - make sure it can build/be contacted/etc 265 self.check()
266 267 @property
268 - def remote_build_dir(self):
269 return self.tempdir + "/build/"
270 271 @property
272 - def tempdir(self):
273 if self.mockremote.remote_tempdir: 274 return self.mockremote.remote_tempdir 275 276 if self._tempdir: 277 return self._tempdir 278 279 cmd = "/bin/mktemp -d {0}/{1}-XXXXX".format( 280 self.mockremote.remote_basedir, "mockremote") 281 282 self.conn.module_name = "shell" 283 self.conn.module_args = str(cmd) 284 results = self.conn.run() 285 tempdir = None 286 for hn, resdict in results["contacted"].items(): 287 tempdir = resdict["stdout"] 288 289 # if still nothing then we"ve broken 290 if not tempdir: 291 raise BuilderError("Could not make tmpdir on {0}".format( 292 self.hostname)) 293 294 cmd = "/bin/chmod 755 {0}".format(tempdir) 295 self.conn.module_args = str(cmd) 296 self.conn.run() 297 self._tempdir = tempdir 298 299 return self._tempdir
300 301 @tempdir.setter
302 - def tempdir(self, value):
303 self._tempdir = value
304
305 - def _get_remote_pkg_dir(self, pkg):
306 # the pkg will build into a dir by mockchain named: 307 # $tempdir/build/results/$chroot/$packagename 308 s_pkg = os.path.basename(pkg) 309 pdn = s_pkg.replace(".src.rpm", "") 310 remote_pkg_dir = os.path.normpath( 311 os.path.join(self.remote_build_dir, 312 "results", 313 self.chroot, 314 pdn)) 315 316 return remote_pkg_dir
317
318 - def modify_base_buildroot(self):
319 """ 320 Modify mock config for current chroot. 321 322 Packages in buildroot_pkgs are added to minimal buildroot 323 """ 324 325 if ("'{0} '".format(self.buildroot_pkgs) != 326 pipes.quote(str(self.buildroot_pkgs) + ' ')): 327 328 # just different test if it contains only alphanumeric characters 329 # allowed in packages name 330 raise BuilderError("Do not try this kind of attack on me") 331 332 self.root_conn.module_name = "lineinfile" 333 if self.chroot == "epel-7-x86_64": 334 self.root_conn.module_args = ( 335 "dest=/etc/mock/epel-7-x86_64.cfg" 336 " line=\"config_opts['chroot_setup_cmd'] = 'install" 337 " bash bzip2 coreutils cpio diffutils findutils" 338 " gawk gcc gcc-c++ grep gzip info make patch" 339 " redhat-release-server redhat-rpm-config rpm-build" 340 " sed shadow-utils tar unzip util-linux which xz {0}'\"" 341 " regexp=\"^.*chroot_setup_cmd.*$\"".format( 342 self.buildroot_pkgs)) 343 else: 344 self.root_conn.module_args = ( 345 "dest=/etc/mock/{0}.cfg" 346 " line=\"config_opts['chroot_setup_cmd'] =" 347 " 'install @buildsys-build {1}'\"" 348 " regexp=\"^.*chroot_setup_cmd.*$\"".format( 349 self.chroot, self.buildroot_pkgs)) 350 351 self.mockremote.callback.log( 352 "putting {0} into minimal buildroot of {1}".format( 353 self.buildroot_pkgs, self.chroot)) 354 355 results = self.root_conn.run() 356 357 is_err, err_results = check_for_ans_error( 358 results, self.hostname, success_codes=[0], 359 return_on_error=["stdout", "stderr"]) 360 361 if is_err: 362 self.mockremote.callback.log("Error: {0}".format(err_results)) 363 myresults = get_ans_results(results, self.hostname) 364 self.mockremote.callback.log("{0}".format(myresults))
365
366 - def build(self, pkg):
367 368 # build the pkg passed in 369 # add pkg to various lists 370 # check for success/failure of build 371 # return success/failure,stdout,stderr of build command 372 # returns success_bool, out, err 373 374 success = False 375 self.modify_base_buildroot() 376 377 # check if pkg is local or http 378 dest = None 379 if os.path.exists(pkg): 380 dest = os.path.normpath( 381 os.path.join(self.tempdir, os.path.basename(pkg))) 382 383 self.conn.module_name = "copy" 384 margs = "src={0} dest={1}".format(pkg, dest) 385 self.conn.module_args = margs 386 self.mockremote.callback.log( 387 "Sending {0} to {1} to build".format( 388 os.path.basename(pkg), self.hostname)) 389 390 # FIXME should probably check this but <shrug> 391 self.conn.run() 392 else: 393 dest = pkg 394 395 # construct the mockchain command 396 buildcmd = "{0} -r {1} -l {2} ".format( 397 mockchain, pipes.quote(self.chroot), 398 pipes.quote(self.remote_build_dir)) 399 400 for r in self.repos: 401 if "rawhide" in self.chroot: 402 r = r.replace("$releasever", "rawhide") 403 404 buildcmd += "-a {0} ".format(pipes.quote(r)) 405 406 if self.mockremote.macros: 407 for k, v in self.mockremote.macros.items(): 408 mock_opt = "--define={0} {1}".format(k, v) 409 buildcmd += "-m {0} ".format(pipes.quote(mock_opt)) 410 411 buildcmd += dest 412 413 # run the mockchain command async 414 # this runs it sync - FIXME 415 self.mockremote.callback.log("executing: {0}".format(buildcmd)) 416 self.conn.module_name = "shell" 417 self.conn.module_args = buildcmd 418 results = self.conn.run() 419 420 is_err, err_results = check_for_ans_error( 421 results, self.hostname, success_codes=[0], 422 return_on_error=["stdout", "stderr"]) 423 424 if is_err: 425 return (success, err_results.get("stdout", ""), 426 err_results.get("stderr", "")) 427 428 # we know the command ended successfully but not if the pkg built 429 # successfully 430 myresults = get_ans_results(results, self.hostname) 431 out = myresults.get("stdout", "") 432 err = myresults.get("stderr", "") 433 434 successfile = os.path.join(self._get_remote_pkg_dir(pkg), "success") 435 testcmd = "/usr/bin/test -f {0}".format(successfile) 436 self.conn.module_args = testcmd 437 results = self.conn.run() 438 is_err, err_results = check_for_ans_error( 439 results, self.hostname, success_codes=[0]) 440 441 if not is_err: 442 success = True 443 444 return success, out, err
445
446 - def download(self, pkg, destdir):
447 # download the pkg to destdir using rsync + ssh 448 # return success/failure, stdout, stderr 449 450 success = False 451 rpd = self._get_remote_pkg_dir(pkg) 452 # make spaces work w/our rsync command below :( 453 destdir = "'" + destdir.replace("'", "'\\''") + "'" 454 # build rsync command line from the above 455 remote_src = "{0}@{1}:{2}".format(self.username, self.hostname, rpd) 456 ssh_opts = "'ssh -o PasswordAuthentication=no -o StrictHostKeyChecking=no'" 457 command = "{0} -avH -e {1} {2} {3}/".format( 458 rsync, ssh_opts, remote_src, destdir) 459 460 cmd = subprocess.Popen(command, shell=True, 461 stdout=subprocess.PIPE, stderr=subprocess.PIPE) 462 463 # rsync results into opts.destdir 464 out, err = cmd.communicate() 465 if cmd.returncode: 466 success = False 467 else: 468 success = True 469 470 return success, out, err
471
472 - def check(self):
473 # do check of host 474 # set checked if successful 475 # return success/failure, errorlist 476 477 if self.checked: 478 return True, [] 479 480 errors = [] 481 482 try: 483 socket.gethostbyname(self.hostname) 484 except socket.gaierror: 485 raise BuilderError("{0} could not be resolved".format( 486 self.hostname)) 487 488 self.conn.module_name = "shell" 489 self.conn.module_args = "/bin/rpm -q mock rsync" 490 res = self.conn.run() 491 492 # check for mock/rsync from results 493 is_err, err_results = check_for_ans_error( 494 res, self.hostname, success_codes=[0]) 495 496 if is_err: 497 if "rc" in err_results: 498 errors.append( 499 "Warning: {0} does not have mock or rsync installed" 500 .format(self.hostname)) 501 else: 502 errors.append(err_results["msg"]) 503 504 # test for path existence for mockchain and chroot config for this 505 # chroot 506 self.conn.module_name = "shell" 507 self.conn.module_args = "/usr/bin/test -f {0}" \ 508 " && /usr/bin/test -f /etc/mock/{1}.cfg".format( 509 mockchain, self.chroot) 510 res = self.conn.run() 511 512 is_err, err_results = check_for_ans_error( 513 res, self.hostname, success_codes=[0]) 514 515 if is_err: 516 if "rc" in err_results: 517 errors.append( 518 "Warning: {0} lacks mockchain on chroot {1}".format( 519 self.hostname, self.chroot)) 520 else: 521 errors.append(err_results["msg"]) 522 523 if not errors: 524 self.checked = True 525 else: 526 msg = "\n".join(errors) 527 raise BuilderError(msg)
528
529 530 -class MockRemote(object):
531
532 - def __init__(self, builder=None, user=DEF_USER, timeout=DEF_TIMEOUT, 533 destdir=DEF_DESTDIR, chroot=DEF_CHROOT, cont=False, 534 recurse=False, repos=DEF_REPOS, callback=None, 535 remote_basedir=DEF_REMOTE_BASEDIR, remote_tempdir=None, 536 macros=DEF_MACROS, lock=None, 537 buildroot_pkgs=DEF_BUILDROOT_PKGS):
538 539 self.destdir = destdir 540 self.chroot = chroot 541 self.repos = repos 542 self.cont = cont 543 self.recurse = recurse 544 self.callback = callback 545 self.remote_basedir = remote_basedir 546 self.remote_tempdir = remote_tempdir 547 self.macros = macros 548 self.lock = lock 549 550 if not self.callback: 551 self.callback = DefaultCallBack() 552 553 self.callback.log("Setting up builder: {0}".format(builder)) 554 self.builder = Builder(builder, user, timeout, self, buildroot_pkgs) 555 556 if not self.chroot: 557 raise MockRemoteError("No chroot specified!") 558 559 self.failed = [] 560 self.finished = [] 561 self.pkg_list = []
562
563 - def _get_pkg_destpath(self, pkg):
564 s_pkg = os.path.basename(pkg) 565 pdn = s_pkg.replace(".src.rpm", "") 566 resdir = "{0}/{1}/{2}".format(self.destdir, self.chroot, pdn) 567 resdir = os.path.normpath(resdir) 568 return resdir
569
570 - def build_pkgs(self, pkgs=None):
571 572 if not pkgs: 573 pkgs = self.pkg_list 574 575 built_pkgs = [] 576 downloaded_pkgs = {} 577 578 try_again = True 579 to_be_built = pkgs 580 while try_again: 581 self.failed = [] 582 just_built = [] 583 for pkg in to_be_built: 584 pkg = urllib.unquote(str(pkg)) 585 if pkg in just_built: 586 self.callback.log( 587 "skipping duplicate pkg in this list: {0}".format(pkg)) 588 continue 589 else: 590 just_built.append(pkg) 591 592 p_path = self._get_pkg_destpath(pkg) 593 594 # check the destdir to see if these pkgs need to be built 595 if os.path.exists(p_path): 596 if os.path.exists(os.path.join(p_path, "success")): 597 self.callback.log( 598 "Skipping already built pkg {0}".format( 599 os.path.basename(pkg))) 600 601 continue 602 # if we"re asking to build it and it is marked as fail - nuke 603 # the failure and try rebuilding it 604 elif os.path.exists(os.path.join(p_path, "fail")): 605 os.unlink(os.path.join(p_path, "fail")) 606 607 # off to the builder object 608 # building 609 self.callback.start_build(pkg) 610 b_status, b_out, b_err = self.builder.build(pkg) 611 self.callback.end_build(pkg) 612 613 # downloading 614 self.callback.start_download(pkg) 615 # mockchain makes things with the chroot appended - so suck down 616 # that pkg subdir from w/i that location 617 chroot_dir = os.path.normpath( 618 os.path.join(self.destdir, self.chroot)) 619 620 d_ret, d_out, d_err = self.builder.download(pkg, chroot_dir) 621 if not d_ret: 622 msg = "Failure to download {0}: {1}".format( 623 pkg, d_out + d_err) 624 625 if not self.cont: 626 raise MockRemoteError(msg) 627 self.callback.error(msg) 628 629 self.callback.end_download(pkg) 630 # write out whatever came from the builder call into the 631 # destdir/chroot 632 if not os.path.exists(chroot_dir): 633 os.makedirs( 634 os.path.join(self.destdir, self.chroot)) 635 636 r_log = open(os.path.join(chroot_dir, "mockchain.log"), 'a') 637 fcntl.flock(r_log, fcntl.LOCK_EX) 638 r_log.write("\n\n{0}\n\n".format(pkg)) 639 r_log.write(b_out) 640 if b_err: 641 r_log.write("\nstderr\n") 642 r_log.write(b_err) 643 fcntl.flock(r_log, fcntl.LOCK_UN) 644 r_log.close() 645 646 # checking where to stick stuff 647 if not b_status: 648 if self.recurse: 649 self.failed.append(pkg) 650 self.callback.error( 651 "Error building {0}, will try again".format( 652 os.path.basename(pkg))) 653 else: 654 msg = "Error building {0}\nSee logs/results in {1}" \ 655 .format(os.path.basename(pkg), self.destdir) 656 657 if not self.cont: 658 raise MockRemoteError(msg) 659 self.callback.error(msg) 660 661 else: 662 self.callback.log("Success building {0}".format( 663 os.path.basename(pkg))) 664 built_pkgs.append(pkg) 665 # createrepo with the new pkgs 666 rc, out, err = createrepo(chroot_dir, self.lock) 667 if err.strip(): 668 self.callback.error( 669 "Error making local repo: {0}".format(chroot_dir)) 670 671 self.callback.error(str(err)) 672 # FIXME - maybe clean up .repodata and .olddata 673 # here? 674 675 if self.failed: 676 if len(self.failed) != len(to_be_built): 677 to_be_built = self.failed 678 try_again = True 679 self.callback.log( 680 "Trying to rebuild {0} failed pkgs".format( 681 len(self.failed))) 682 else: 683 self.callback.log( 684 "Tried twice - following pkgs could not be" 685 " successfully built:") 686 687 for pkg in self.failed: 688 msg = pkg 689 if pkg in downloaded_pkgs: 690 msg = downloaded_pkgs[pkg] 691 self.callback.log(msg) 692 693 try_again = False 694 else: 695 try_again = False
696
697 698 -def parse_args(args):
699 700 parser = SortedOptParser( 701 "mockremote -b hostname -u user -r chroot pkg pkg pkg") 702 parser.add_option("-r", "--root", default=DEF_CHROOT, dest="chroot", 703 help="chroot config name/base to use in the mock build") 704 parser.add_option("-c", "--continue", default=False, action="store_true", 705 dest="cont", 706 help="if a pkg fails to build, continue to the next one") 707 parser.add_option("-a", "--addrepo", default=DEF_REPOS, action="append", 708 dest="repos", 709 help="add these repo baseurls to the chroot's yum config") 710 parser.add_option("--recurse", default=False, action="store_true", 711 help="if more than one pkg and it fails to build," 712 " try to build the rest and come back to it") 713 parser.add_option("--log", default=None, dest="logfile", 714 help="log to the file named by this option," 715 " defaults to not logging") 716 parser.add_option("-b", "--builder", dest="builder", default=None, 717 help="builder to use") 718 parser.add_option("-u", dest="user", default=DEF_USER, 719 help="user to run as/connect as on builder systems") 720 parser.add_option("-t", "--timeout", dest="timeout", type="int", 721 default=DEF_TIMEOUT, 722 help="maximum time in seconds a build can take to run") 723 parser.add_option("--destdir", dest="destdir", default=DEF_DESTDIR, 724 help="place to download all the results/packages") 725 parser.add_option("--packages", dest="packages_file", default=None, 726 help="file to read list of packages from") 727 parser.add_option("-q", "--quiet", dest="quiet", default=False, 728 action="store_true", 729 help="output very little to the terminal") 730 731 opts, args = parser.parse_args(args) 732 733 if not opts.builder: 734 sys.stderr.write("Must specify a system to build on") 735 sys.exit(1) 736 737 if opts.packages_file and os.path.exists(opts.packages_file): 738 args.extend(read_list_from_file(opts.packages_file)) 739 740 # args = list(set(args)) # poor man's 'unique' - this also changes the order 741 # :( 742 743 if not args: 744 sys.stderr.write("Must specify at least one pkg to build") 745 sys.exit(1) 746 747 if not opts.chroot: 748 sys.stderr.write("Must specify a mock chroot") 749 sys.exit(1) 750 751 for url in opts.repos: 752 if not (url.startswith("http://") or 753 url.startswith("https://") or url.startswith("file://")): 754 755 sys.stderr.write("Only http[s] or file urls allowed for repos") 756 sys.exit(1) 757 758 return opts, args
759
760 761 # FIXME 762 # play with createrepo run at the end of each build 763 # need to output the things that actually worked :) 764 765 766 -def main(args):
767 768 # parse args 769 opts, pkgs = parse_args(args) 770 771 if not os.path.exists(opts.destdir): 772 os.makedirs(opts.destdir) 773 774 try: 775 # setup our callback 776 callback = CliLogCallBack(logfn=opts.logfile, quiet=opts.quiet) 777 # our mockremote instance 778 mr = MockRemote(builder=opts.builder, 779 user=opts.user, 780 timeout=opts.timeout, 781 destdir=opts.destdir, 782 chroot=opts.chroot, 783 cont=opts.cont, 784 recurse=opts.recurse, 785 repos=opts.repos, 786 callback=callback) 787 788 # FIXMES 789 # things to think about doing: 790 # output the remote tempdir when you start up 791 # output the number of pkgs 792 # output where you're writing things to 793 # consider option to sync over destdir to the remote system to use 794 # as a local repo for the build 795 # 796 797 if not opts.quiet: 798 print("Building {0} pkgs".format(len(pkgs))) 799 800 mr.build_pkgs(pkgs) 801 802 if not opts.quiet: 803 print("Output written to: {0}".format(mr.destdir)) 804 805 except MockRemoteError as e: 806 sys.stderr.write("Error on build:\n") 807 sys.stderr.write("{0}\n".format(e)) 808 return
809 810 811 if __name__ == "__main__": 812 main(sys.argv[1:]) 813