Changes In Branch v1.65 Through [a2a5172659] Excluding Merge-Ins
This is equivalent to a diff from ade6384a7b to a2a5172659
2020-07-30
| ||
18:54 | changed version to 1.6558 check-in: ea53e1b896 user: mmgraham tags: v1.65, v1.6558 | |
2020-07-29
| ||
17:05 | removed comments check-in: a2a5172659 user: pjhatwal tags: v1.65 | |
16:36 | fix to archive save-remove check-in: ad4842a081 user: pjhatwal tags: v1.65 | |
2017-04-19
| ||
18:14 | Merged in latest from v1.64 check-in: f72fea4b3b user: mrwellan tags: v1.65 | |
2017-04-17
| ||
17:17 | updates to home view Closed-Leaf check-in: ade6384a7b user: pjhatwal tags: v1.64-envdebug | |
2017-04-10
| ||
23:36 | fixed model in tab view check-in: 326a8e0ba4 user: pjhatwal tags: v1.64-envdebug | |
Added .fossil-settings/crnl-glob version [f093e1ab5c].
> | 1 | docs/manual/megatest_manual.html |
Modified .mtutil.scm from [3e3e4527c3] to [d53ce037aa].
1 2 3 4 5 6 7 | (use json) (use ducttape-lib) (define (get-last-runname area-path target) (let* ((run-data (with-input-from-pipe (conc "megatest -list-runs % -target " target " -fields runs:runname,event_time -dumpmode sexpr -start-dir " area-path) read))) | > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | ;; Copyright 2006-2017, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. (use json) (use ducttape-lib) (define (get-last-runname area-path target) (let* ((run-data (with-input-from-pipe (conc "megatest -list-runs % -target " target " -fields runs:runname,event_time -dumpmode sexpr -start-dir " area-path) read))) |
︙ | ︙ | |||
21 22 23 24 25 26 27 | last-name)))) (define (str-first-char->number str) (char->integer (string-ref str 0))) ;; example of how to set up and write target mappers ;; | < | | | < | | | < | | | | | | | | | | | | | | | | | | | | | | | < | | > > > > > | | 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 | last-name)))) (define (str-first-char->number str) (char->integer (string-ref str 0))) ;; example of how to set up and write target mappers ;; (add-target-mapper 'prefix-contour (lambda (target run-name area area-path reason contour mode-patt) (conc contour "/" target))) (add-target-mapper 'prefix-area-contour (lambda (target run-name area area-path reason contour mode-patt) (conc area "/" contour "/" target))) (add-runname-mapper 'corporate-ww (lambda (target run-name area area-path reason contour mode-patt) (print "corporate-ww called with: target=" target " run-name=" run-name " area=" area " area-path=" area-path " reason=" reason " contour=" contour " mode-patt=" mode-patt) (let* ((last-name (get-last-runname area-path target)) (last-letter (let* ((ch (if (string? last-name) (let ((len (string-length last-name))) (substring last-name (- len 1) len)) "a")) (chnum (str-first-char->number ch)) (a (str-first-char->number "a")) (z (str-first-char->number "z"))) (if (and (>= chnum a)(<= chnum z)) chnum #f))) (next-letter (if last-letter (list->string (list (integer->char (+ last-letter 1)))) ;; surely there is an easier way? "a"))) ;; (print "last-name: " last-name " last-letter: " last-letter " next-letter: " next-letter) (conc (seconds->wwdate (current-seconds)) next-letter)))) (add-runname-mapper 'auto (lambda (target run-name area area-path reason contour mode-patt) "auto-eh")) ;; run only areas where first letter of area name is "a" ;; (add-area-checker 'first-letter-a (lambda (area target contour) (string-match "^a.*$" area))) |
Modified COPYING from [7d7e3bd444] to [fde01ae8e7].
|
| | > | | < | > > > | | | > | | < < | | | | | | < | > | | | | | | | | | | < | > | > > > > > > > > > > | | > | | | | < | > | > | > > | | > > | | > > > | > > | > > > > | > > > > | > > > > > | > > | > | > > | | > > > > < > > > > > | > > > > | < > > | < > > > > > > > > | > > > | > > | > < > | > > > > > | > > > > | > > > > > > > > | > | > > > > > > > > | > > > | > | > > > > > > | > > | > | > > > | < | | | > | > > | < > > > > > > > | > > > | | | > > > > > > | > | > | | > | > | > > > > > > > > > > > > > > > | > | > > > | < > > > > > > > > > > > > < < < > > | > < > > | < < | | > > > > > > > > > > < | > > > > > > | > > > > > | > > > > | < > > > > > > > | > > | > | < | > > > > > > > > | > > > > > > | > > > | > > | | > > | > > > | > | | < > > | > > > > | > > > > > > > > > | > > > > | > > > | > | | | < | > > | > > > > > > | > > > > > > | > > > > > > > | > > > | | | < | | < > | | > > | > > > > > > > > > > | > > > > > > | > | > > > > > > > > > > > > > > > > | > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | | | | < | | < < < < > < | < < > > > | < < < < < | | < > | < < < < < < | | | | > | | | | | | | < | | | | | > > > | < | | | | | | | | > > | | | | | | | | | > > > > > > > > > | | | | | | | < < | | | | | < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < | < < < < < < < < < < | < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < | < | < < < < < < < < < | < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 | GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/> Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. <one line to give the program's name and a brief idea of what it does.> Copyright (C) <year> <name of author> This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>. Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: <program> Copyright (C) <year> <name of author> This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see <https://www.gnu.org/licenses/>. The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read <https://www.gnu.org/licenses/why-not-lgpl.html>. |
Modified Makefile from [a8eded8e26] to [e6e63de436].
1 2 | # make install CSCOPTS='-accumulate-profile -profile-name $(PWD)/profile-ww$(shell date +%V.%u)' # rm <files>.o ; make install CSCOPTS='-profile' ; ... ; chicken-profile | less | > > > > > > > > > > > > > > > > > | | | | | > > > > | > > > > > > > > > > | | > | | > > > | | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | > > > | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 | # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. # make install CSCOPTS='-accumulate-profile -profile-name $(PWD)/profile-ww$(shell date +%V.%u)' # rm <files>.o ; make install CSCOPTS='-profile' ; ... ; chicken-profile | less SHELL=/bin/bash PREFIX=$(PWD) CSCOPTS= INSTALL=install SRCFILES = common.scm items.scm launch.scm \ ods.scm runconfig.scm server.scm configf.scm \ db.scm keys.scm margs.scm megatest-version.scm \ process.scm runs.scm tasks.scm tests.scm genexample.scm \ http-transport.scm filedb.scm tdb.scm \ client.scm mt.scm \ ezsteps.scm lock-queue.scm sdb.scm \ rmt.scm api.scm subrun.scm \ portlogger.scm archive.scm env.scm diff-report.scm cgisetup/models/pgdb.scm # module source files MSRCFILES = ftail.scm rmtmod.scm commonmod.scm # Eggs to install (straightforward ones) EGGS=matchable readline apropos base64 regex-literals format regex-case test coops trace csv \ dot-locking posix-utils posix-extras directory-utils hostinfo tcp-server rpc csv-xml fmt \ json md5 awful http-client spiffy uri-common intarweb spiffy-request-vars \ spiffy-directory-listing ssax sxml-serializer sxml-modifications iup canvas-draw sqlite3 GUISRCF = dashboard-context-menu.scm dashboard-tests.scm dashboard-guimonitor.scm gutils.scm dcommon.scm tree.scm vg.scm OFILES = $(SRCFILES:%.scm=%.o) GOFILES = $(GUISRCF:%.scm=%.o) MOFILES = $(addprefix mofiles/,$(MSRCFILES:%.scm=%.o)) mofiles/%.o : %.scm mkdir -p mofiles csc $(CSCOPTS) -J -c $< -o mofiles/$*.o ADTLSCR=mt_laststep mt_runstep mt_ezstep HELPERS=$(addprefix $(PREFIX)/bin/,$(ADTLSCR)) DEPLOYHELPERS=$(addprefix deploytarg/,$(ADTLSCR)) MTESTHASH=$(shell fossil info|grep checkout:| awk '{print $$2}') ifeq ($(MTESTHASH),) $(error MTESTHASH is broken!) endif CSIPATH=$(shell which csi) CKPATH=$(shell dirname $(shell dirname $(CSIPATH))) # ARCHSTR=$(shell uname -m)_$(shell uname -r) # BASH_MACHTYPE=$(shell bash -c "echo \$$MACHTYPE") # ARCHSTR=$(BASH_MACHTYPE)_$(shell lsb_release -sr) ARCHSTR=$(shell if [[ -e /usr/bin/sw_vers ]]; then /usr/bin/sw_vers -productVersion; else lsb_release -sr; fi) # ARCHSTR=$(shell bash -c "echo \$$MACHTYPE") PNGFILES = $(shell cd docs/manual;ls *png) #all : $(PREFIX)/bin/.$(ARCHSTR) mtest dboard mtut ndboard all : $(PREFIX)/bin/.$(ARCHSTR) mtest dboard mtut tcmt mtest: $(OFILES) readline-fix.scm megatest.o $(MOFILES) mofiles/ftail.o mofiles/rmtmod.o mofiles/commonmod.o csc $(CSCOPTS) $(OFILES) $(MOFILES) megatest.o -o mtest showmtesthash: @echo $(MTESTHASH) dboard : $(OFILES) $(GOFILES) dashboard.scm $(MOFILES) csc $(CSCOPTS) $(OFILES) dashboard.scm $(GOFILES) $(MOFILES) -o dboard ndboard : newdashboard.scm $(OFILES) $(GOFILES) csc $(CSCOPTS) $(OFILES) $(GOFILES) newdashboard.scm -o ndboard mtut: $(OFILES) $(MOFILES) megatest-fossil-hash.scm mtut.scm csc $(CSCOPTS) $(OFILES) $(MOFILES) mtut.scm -o mtut TCMTOBJS = \ api.o \ archive.o \ cgisetup/models/pgdb.o \ client.o \ common.o \ configf.o \ db.o \ env.o \ http-transport.o \ items.o \ keys.o \ launch.o \ lock-queue.o \ margs.o \ mt.o \ megatest-version.o \ ods.o \ portlogger.o \ process.o \ rmt.o \ mofiles/rmtmod.o \ mofiles/commonmod.o \ rpc-transport.o \ runconfig.o \ runs.o \ server.o \ tasks.o \ tdb.o \ tests.o \ subrun.o \ tcmt : $(TCMTOBJS) tcmt.scm csc $(CSCOPTS) $(TCMTOBJS) tcmt.scm -o tcmt # install documentation to $(PREFIX)/docs # DOES NOT REBUILD DOCS # $(PREFIX)/share/docs/megatest_manual.html : docs/manual/megatest_manual.html mkdir -p $(PREFIX)/share/docs $(INSTALL) docs/manual/megatest_manual.html $(PREFIX)/share/docs/megatest_manual.html for png in $(PNGFILES);do $(INSTALL) docs/manual/$$png $(PREFIX)/share/docs/$$png;done # add a fake dependency so this doens't copy everytime $(PREFIX)/share/js/jquery-3.1.0.slim.min.js : # .fslckout mkdir -p $(PREFIX)/share/js fossil wiki export java-script-lib > $(PREFIX)/share/js/jquery-3.1.0.slim.min.js $(PREFIX)/share/db/mt-pg.sql : mt-pg.sql mkdir -p $(PREFIX)/share/db $(INSTALL) mt-pg.sql $(PREFIX)/share/db/mt-pg.sql #multi-dboard : multi-dboard.scm $(OFILES) $(GOFILES) # csc $(CSCOPTS) $(OFILES) $(GOFILES) multi-dboard.scm -o multi-dboard # # $(PREFIX)/bin/revtagfsl : utils/revtagfsl.scm # csc utils/revtagfsl.scm -o $(PREFIX)/bin/revtagfsl # Special dependencies for the includes tests.o db.o launch.o runs.o dashboard-tests.o dashboard-context-menu.o dashboard-guimonitor.o dashboard-main.o monitor.o dashboard.o \ archive.o megatest.o : db_records.scm tests.o runs.o dashboard.o dashboard-tests.o dashboard-context-menu.o dashboard-main.o : run_records.scm db.o ezsteps.o keys.o launch.o megatest.o monitor.o runs-for-ref.o runs.o tests.o : key_records.scm tests.o tasks.o dashboard-tasks.o : task_records.scm runs.o : test_records.scm megatest.o : megatest-fossil-hash.scm rmt.scm client.scm common.scm configf.scm dashboard-guimonitor.scm dashboard-tests.scm dashboard.scm db.scm dcommon.scm ezsteps.scm fs-transport.scm http-transport.scm index-tree.scm items.scm keys.scm launch.scm megatest.scm monitor.scm mt.scm newdashboard.scm runconfig.scm runs.scm server.scm tdb.scm tests.scm tree.scm : common_records.scm common_records.scm : altdb.scm vg.o dashboard.o : vg_records.scm dcommon.o : run_records.scm # Temporary while transitioning to new routine # runs.o : run-tests-queue-classic.scm run-tests-queue-new.scm # for the modularized stuff mofiles/rmtmod.o : mofiles/commonmod.o megatest-fossil-hash.scm : $(SRCFILES) megatest.scm *_records.scm echo "(define megatest-fossil-hash \"$(MTESTHASH)\")" > megatest-fossil-hash.new if ! diff -q megatest-fossil-hash.new megatest-fossil-hash.scm ; then echo copying .new to .scm;cp -f megatest-fossil-hash.new megatest-fossil-hash.scm;fi $(OFILES) $(GOFILES) : common_records.scm %.o : %.scm $(MOFILES) csc $(CSCOPTS) -c $< $(MOFILES) $(PREFIX)/bin/.$(ARCHSTR)/mtest : mtest utils/mk_wrapper @echo Installing to PREFIX=$(PREFIX) $(INSTALL) mtest $(PREFIX)/bin/.$(ARCHSTR)/mtest utils/mk_wrapper $(PREFIX) mtest $(PREFIX)/bin/megatest chmod a+x $(PREFIX)/bin/megatest $(PREFIX)/bin/.$(ARCHSTR)/ndboard : ndboard $(INSTALL) ndboard $(PREFIX)/bin/.$(ARCHSTR)/ndboard $(PREFIX)/bin/newdashboard : $(PREFIX)/bin/.$(ARCHSTR)/ndboard utils/mk_wrapper utils/mk_wrapper $(PREFIX) ndboard $(PREFIX)/bin/newdashboard chmod a+x $(PREFIX)/bin/newdashboard # mtutil $(PREFIX)/bin/.$(ARCHSTR)/mtut : mtut $(INSTALL) mtut $(PREFIX)/bin/.$(ARCHSTR)/mtut install-mtut : mtut $(INSTALL) mtut $(PREFIX)/bin/mtut $(PREFIX)/bin/mtutil : $(PREFIX)/bin/.$(ARCHSTR)/mtut utils/mk_wrapper utils/mk_wrapper $(PREFIX) mtut $(PREFIX)/bin/mtutil chmod a+x $(PREFIX)/bin/mtutil # mtexec mtexec: $(OFILES) $(MOFILES) megatest-fossil-hash.scm mtexec.scm csc $(CSCOPTS) $(OFILES) $(MOFILES) mtexec.scm -o mtexec $(PREFIX)/bin/.$(ARCHSTR)/mtexec : mtexec $(INSTALL) mtexec $(PREFIX)/bin/.$(ARCHSTR)/mtexec $(PREFIX)/bin/mtexec : $(PREFIX)/bin/.$(ARCHSTR)/mtexec utils/mk_wrapper utils/mk_wrapper $(PREFIX) mtexec $(PREFIX)/bin/mtexec chmod a+x $(PREFIX)/bin/mtexec # tcmt $(PREFIX)/bin/.$(ARCHSTR)/tcmt : tcmt $(INSTALL) tcmt $(PREFIX)/bin/.$(ARCHSTR)/tcmt $(PREFIX)/bin/tcmt : $(PREFIX)/bin/.$(ARCHSTR)/tcmt utils/mk_wrapper utils/mk_wrapper $(PREFIX) tcmt $(PREFIX)/bin/tcmt chmod a+x $(PREFIX)/bin/tcmt # $(PREFIX)/bin/.$(ARCHSTR)/mdboard : multi-dboard # $(INSTALL) multi-dboard $(PREFIX)/bin/.$(ARCHSTR)/mdboard # $(PREFIX)/bin/mdboard : $(PREFIX)/bin/.$(ARCHSTR)/mdboard utils/mk_wrapper # utils/mk_wrapper $(PREFIX) mdboard $(PREFIX)/bin/mdboard # chmod a+x $(PREFIX)/bin/mdboard # $(HELPERS) : utils/% # $(INSTALL) $< $@ # chmod a+x $@ $(PREFIX)/bin/mt_laststep : utils/mt_laststep $(INSTALL) $< $@ chmod a+x $@ $(PREFIX)/bin/mt_runstep : utils/mt_runstep $(INSTALL) $< $@ chmod a+x $@ $(PREFIX)/bin/serialize-env: serialize-env.scm csc serialize-env.scm $(INSTALL) serialize-env $@ $(PREFIX)/bin/mt_ezstep : utils/mt_ezstep $(INSTALL) $< $@ chmod a+x $@ $(PREFIX)/bin/mt_xterm : utils/mt_xterm $(INSTALL) $< $@ |
︙ | ︙ | |||
156 157 158 159 160 161 162 | $(INSTALL) $< $@ chmod a+x $@ $(PREFIX)/bin/nbfind : utils/nbfind $(INSTALL) $< $@ chmod a+x $@ | | | 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 | $(INSTALL) $< $@ chmod a+x $@ $(PREFIX)/bin/nbfind : utils/nbfind $(INSTALL) $< $@ chmod a+x $@ $(PREFIX)/bin/mtrunner : utils/mtrunner $(INSTALL) $< $@ chmod a+x $@ # $(PREFIX)/bin/refdb : refdb # $(INSTALL) $< $@ # chmod a+x $@ |
︙ | ︙ | |||
189 190 191 192 193 194 195 | $(PREFIX)/bin/.$(ARCHSTR)/dboard : dboard $(FILES) utils/mk_wrapper utils/mk_wrapper $(PREFIX) dboard $(PREFIX)/bin/dashboard chmod a+x $(PREFIX)/bin/dashboard $(INSTALL) dboard $(PREFIX)/bin/.$(ARCHSTR)/dboard install : $(PREFIX)/bin/.$(ARCHSTR) $(PREFIX)/bin/.$(ARCHSTR)/mtest $(PREFIX)/bin/megatest \ $(PREFIX)/bin/.$(ARCHSTR)/dboard $(PREFIX)/bin/dashboard $(HELPERS) $(PREFIX)/bin/nbfake \ | > | > > > | > > | > | 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 | $(PREFIX)/bin/.$(ARCHSTR)/dboard : dboard $(FILES) utils/mk_wrapper utils/mk_wrapper $(PREFIX) dboard $(PREFIX)/bin/dashboard chmod a+x $(PREFIX)/bin/dashboard $(INSTALL) dboard $(PREFIX)/bin/.$(ARCHSTR)/dboard install : $(PREFIX)/bin/.$(ARCHSTR) $(PREFIX)/bin/.$(ARCHSTR)/mtest $(PREFIX)/bin/megatest \ $(PREFIX)/bin/.$(ARCHSTR)/dboard $(PREFIX)/bin/dashboard $(HELPERS) $(PREFIX)/bin/nbfake \ $(PREFIX)/bin/.$(ARCHSTR)/mtexec $(PREFIX)/bin/mtexec $(PREFIX)/bin/serialize-env \ $(PREFIX)/bin/nbfind $(PREFIX)/bin/mtrunner $(PREFIX)/bin/viewscreen $(PREFIX)/bin/mt_xterm \ $(PREFIX)/share/docs/megatest_manual.html $(PREFIX)/bin/remrun \ $(PREFIX)/share/docs/megatest_manual.html $(PREFIX)/bin/remrun $(PREFIX)/bin/mtutil \ $(PREFIX)/bin/tcmt $(PREFIX)/share/db/mt-pg.sql \ $(PREFIX)/share/js/jquery-3.1.0.slim.min.js # $(PREFIX)/bin/.$(ARCHSTR)/ndboard # $(PREFIX)/bin/newdashboard $(PREFIX)/bin/.$(ARCHSTR) : mkdir -p $(PREFIX)/bin/.$(ARCHSTR) mkdir -p $(PREFIX)/bin/.$(ARCHSTR)/lib test: tests/tests.scm cd tests;csi -I .. -b -n tests.scm ext-tests/.fslckout : $(MTQA_FOSSIL) mkdir -p ext-tests cd ext-tests;fossil open --nested $(MTQA_FOSSIL) $(MTQA_FOSSIL) : fossil clone https://www.kiatoa.com/fossils/megatest_qa $(MTQA_FOSSIL) clean : rm -f $(OFILES) $(GOFILES) $(MOFILES) $(TCMTOBJS) $(PREFIX)/megatest $(PREFIX)/dashboard mtest mtutil mtut tcmt ftail.import.scm readline-fix.scm serialize-env dboard dboard.o megatest.o dashboard.o megatest-fossil-hash.* altdb.scm mofiles/*.o vg.o rm -rf share #====================================================================== # Make the records files #====================================================================== # vg_records.scm : records.sh # ./records.sh |
︙ | ︙ | |||
266 267 268 269 270 271 272 | sd : datashare-testing/sd mkdir -p /tmp/$(USER)/datashare/disk1 /tmp/$(USER)/basepath xterm : sd (export BASEPATH=/tmp/$(USER)/basepath ; export PATH="$(PWD)/datashare-testing:$(PATH)" ; xterm &) datashare-testing/spublish : spublish.scm $(OFILES) | | | > | | > | > > > > > | > | | 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 | sd : datashare-testing/sd mkdir -p /tmp/$(USER)/datashare/disk1 /tmp/$(USER)/basepath xterm : sd (export BASEPATH=/tmp/$(USER)/basepath ; export PATH="$(PWD)/datashare-testing:$(PATH)" ; xterm &) datashare-testing/spublish : spublish.scm $(OFILES) csc $(CSCOPTS) spublish.scm megatest-version.o margs.o process.o common.o -o datashare-testing/spublish datashare-testing/sretrieve : sretrieve.scm $(OFILES) csc $(CSCOPTS) sretrieve.scm megatest-version.o margs.o process.o common.o -o datashare-testing/sretrieve datashare-testing/sauthorize : sauthorize.scm $(OFILES) csc $(CSCOPTS) sauthorize.scm megatest-version.o margs.o process.o common.o -o datashare-testing/sauthorize sauth-init: mkdir -p datashare-testing rm datashare-testing/sauthorize rm datashare-testing/sretrieve rm datashare-testing/spublish sauth : sauth-init datashare-testing/sauthorize datashare-testing/sretrieve datashare-testing/spublish # base64 dot-locking \ # csv-xml z3 # "(define (toplevel-command . a) #f)" # if egrep 'version.*3.0' $(shell dirname $(shell dirname $(shell which csi)))/lib/chicken/7/readline.setup-info;then \ |
︙ | ︙ | |||
299 300 301 302 303 304 305 | if csi -ne '(use mysql-client)';then \ echo "(use mysql-client)(hash-table-set! *available-db* 'mysql #t)" >> altdb.scm; \ fi if csi -ne '(use postgresql)';then \ echo "(use postgresql)(hash-table-set! *available-db* 'postgresql #t)" >> altdb.scm;\ fi | | | > > > > > > > > > > > > > > > > > > > > | 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 | if csi -ne '(use mysql-client)';then \ echo "(use mysql-client)(hash-table-set! *available-db* 'mysql #t)" >> altdb.scm; \ fi if csi -ne '(use postgresql)';then \ echo "(use postgresql)(hash-table-set! *available-db* 'postgresql #t)" >> altdb.scm;\ fi portlogger-example : portlogger-example.scm api.o archive.o client.o common.o configf.o dashboard-tests.o dashboard-context-menu.o db.o dcommon.o ezsteps.o filedb.o genexample.o gutils.o http-transport.o items.o keys.o launch.o lock-queue.o margs.o megatest-version.o mt.o ods.o portlogger.o process.o rmt.o rpc-transport.o runconfig.o runs.o sdb.o server.o synchash.o tasks.o tdb.o tests.o tree.o csc $(CSCOPTS) portlogger-example.scm api.o archive.o client.o common.o configf.o dashboard-tests.o dashboard-context-menu.o db.o dcommon.o ezsteps.o filedb.o genexample.o gutils.o http-transport.o items.o keys.o launch.o lock-queue.o margs.o megatest-version.o mt.o ods.o portlogger.o process.o rmt.o rpc-transport.o runconfig.o runs.o sdb.o server.o synchash.o tasks.o tdb.o tests.o tree.o # create a pdf dot graphviz diagram from notations in rmt.scm rmt.pdf : rmt.scm grep ';;DOT' rmt.scm | sed -e 's/.*;;DOT //' > rmt.dot;dot -Tpdf rmt.dot -o rmt.pdf buildmanual: cd docs/manual && make wikipage=plan editwiki: cd docs/manual && ../../utils/editwiki $(wikipage) viewmanual: arora docs/manual/megatest_manual.html targets: @grep : Makefile | perl -ne '/^([A-Za-z0-9_-]+):/ && print "$$1\n"' unit : cd tests;make unit |
Modified Makefile.deploy from [244f421535] to [31c31ed198].
1 2 3 4 5 6 7 8 | # make install CSCOPTS='-accumulate-profile -profile-name $(PWD)/profile-ww$(shell date +%V.%u)' PREFIX=$(PWD) CSCOPTS= -deploy INSTALL=install SRCFILES = common.scm items.scm launch.scm \ ods.scm runconfig.scm server.scm configf.scm \ db.scm keys.scm margs.scm megatest-version.scm \ process.scm runs.scm tasks.scm tests.scm genexample.scm \ | > > > > > > > > > > > > > > > > > > > > > > | | | | > > > | > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 | # make install CSCOPTS='-accumulate-profile -profile-name $(PWD)/profile-ww$(shell date +%V.%u)' # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. # PREFIX=$(PWD) CSCOPTS= -deploy INSTALL=install CHICKEN=$(shell which csc) CHICKEN_BIN_DIR=$(shell dirname ${CHICKEN}/) CHICKEN_DIR=${CHICKEN_BIN_DIR}/.. SRCFILES = common.scm items.scm launch.scm \ ods.scm runconfig.scm server.scm configf.scm \ db.scm keys.scm margs.scm megatest-version.scm \ process.scm runs.scm tasks.scm tests.scm genexample.scm \ http-transport.scm filedb.scm tdb.scm \ client.scm daemon.scm mt.scm \ ezsteps.scm lock-queue.scm sdb.scm \ rmt.scm api.scm subrun.scm \ portlogger.scm archive.scm env.scm diff-report.scm cgisetup/models/pgdb.scm # module source files MSRCFILES = ftail.scm # Eggs to install (straightforward ones) EGGS=matchable readline apropos base64 regex-literals format regex-case test coops trace csv \ dot-locking posix-utils posix-extras directory-utils hostinfo tcp-server rpc csv-xml fmt \ json md5 awful http-client spiffy uri-common intarweb spiffy-request-vars \ spiffy-directory-listing ssax sxml-serializer sxml-modifications iup canvas-draw sqlite3 GUISRCF = dashboard-tests.scm dashboard-guimonitor.scm gutils.scm dcommon.scm tree.scm vg.scm OFILES = $(SRCFILES:%.scm=%.o) GOFILES = $(GUISRCF:%.scm=%.o) MOFILES = $(addprefix mofiles/,$(MSRCFILES:%.scm=%.o)) mofiles/%.o : %.scm mkdir -p mofiles csc $(CSCOPTS) -J -c $< -o mofiles/$*.o ADTLSCR=mt_laststep mt_runstep mt_ezstep HELPERS=$(addprefix $(PREFIX)/bin/,$(ADTLSCR)) DEPLOYHELPERS=$(addprefix deploytarg/,$(ADTLSCR)) MTESTHASH=$(shell fossil info|grep checkout:| awk '{print $$2}') CSIPATH=$(shell which csi) |
︙ | ︙ | |||
40 41 42 43 44 45 46 | ARCHSIZE=64_ IMVER=3.11 IUPVER=3.17 KTYPE=26g4 CDVER=5.10 | | | | > > > > > > | > > > > > > > > > | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | | | > > > > > > > > > > > | 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 | ARCHSIZE=64_ IMVER=3.11 IUPVER=3.17 KTYPE=26g4 CDVER=5.10 all : $(PREFIX)/bin/.$(ARCHSTR) postgres nanomsg mtest dboard mtut eggs sqlite matt iup wrappers mtest: $(OFILES) readline-fix.scm megatest.o $(MOFILES) mofiles/ftail.o mkdir -p $(PREFIX)/deploy csc $(CSCOPTS) $(OFILES) $(MOFILES) megatest.o -o $(PREFIX)/deploy/mtest cp $(CKPATH)/lib/chicken/7/chicken.import.so $(PREFIX)/deploy/mtest cp $(CKPATH)/lib/chicken/7/foreign.import.so $(PREFIX)/deploy/mtest cp $(CKPATH)/lib/chicken/7/ports.import.so $(PREFIX)/deploy/mtest cp $(CKPATH)/lib/chicken/7/data-structures.import.so $(PREFIX)/deploy/mtest cp $(CKPATH)/lib/chicken/7/posix.import.so $(PREFIX)/deploy/mtest cp $(CKPATH)/lib/chicken/7/irregex.import.so $(PREFIX)/deploy/mtest eggs: $(PREFIX)/deploy/mtest/fmt.so $(PREFIX)/deploy/mtest/fmt.so: chicken-install -deploy -p $(PREFIX)/deploy/mtest base64 format regex-case simple-exceptions typed-records apropos directory-utils spiffy http-client spiffy-request-vars spiffy-directory-listing posix-extras call-with-environment-variables csv typed-records pathname-expand json crypt dot-locking csv-xml:0.10.2 z3 sql-de-lite hostinfo rpc directory-utils spiffy http-client spiffy-request-vars spiffy-directory-listing posix-extras call-with-environment-variables rpc fmt md5:3.1.0 check-errors:1.13.0 string-utils:1.2.4 message-digest:3.1.1 csv-xml:0.10.2 sha1 ansi-escape-sequences test slice rfc3339 uuid-lib filepath srfi-19:3.3.6 readline trace lolevel cd utils/opensrc/mutils && chicken-install -deploy -p $(PREFIX)/deploy/mtest cd ducttape && chicken-install -deploy -p $(PREFIX)/deploy/mtest cp $(CHICKEN_DIR)/lib/chicken/7/chicken.import.so $(PREFIX)/deploy/mtest/ cp $(CHICKEN_DIR)/lib/chicken/7/foreign* $(PREFIX)/deploy/mtest/ cp $(CHICKEN_DIR)/lib/chicken/7/ports.import.so $(PREFIX)/deploy/mtest/ cp $(CHICKEN_DIR)/lib/chicken/7/data-structures.import.so $(PREFIX)/deploy/mtest/ cp $(CHICKEN_DIR)/lib/chicken/7/posix.import.so $(PREFIX)/deploy/mtest/ cp $(CHICKEN_DIR)/lib/chicken/7/irregex.import.so $(PREFIX)/deploy/mtest/ sqlite: $(PREFIX)/deploy/mtest/sqlite3.so $(PREFIX)/deploy/mtest/sqlite3.so: wget http://www.sqlite.org/2015/sqlite-autoconf-3090200.tar.gz tar xfz sqlite-autoconf-3090200.tar.gz cd sqlite-autoconf-3090200 cd sqlite-autoconf-3090200 && ./configure --prefix=$(PREFIX)/deploy/mtest cd sqlite-autoconf-3090200 && make cd sqlite-autoconf-3090200 && make install CSC_OPTIONS='-I$(PREFIX)/deploy/mtest/include -L$(PREFIX)/deploy/mtest/' chicken-install -deploy -p $(PREFIX)/deploy/mtest sqlite3 check-errors:1.13.0 matt: $(PREFIX)/deploy/mtest/stml.so $(PREFIX)/deploy/mtest/stml.so: wget -c -O stml.tar.gz 'http://www.kiatoa.com/fossils/stml/tarball?name=stml&uuid=trunk' tar -xzf stml.tar.gz cd stml && cp install.cfg.template install.cfg cd stml && echo "TARGDIR=`realpath $(PREFIX)/deploy/mtest`" > install.cfg cd stml && echo "LOGDIR=/tmp/stmlrun" >> install.cfg cd stml && echo "SQLITE3=$PREFIX/bin/sqlite3" >> install.cfg cd stml && cp requirements.scm.template requirements.scm cd stml && make clean -cd stml && CSCOPTS="-C -fPIC" make cd stml && chicken-install -deploy -p $(PREFIX)/deploy/mtest wget -c -O opensrc.tar.gz 'http://www.kiatoa.com/fossils/opensrc/tarball?name=opensrc&uuid=trunk' tar -xzf opensrc.tar.gz cd opensrc/mutils && chicken-install -deploy -p $(PREFIX)/deploy/mtest cd opensrc/dbi && chicken-install -deploy -p $(PREFIX)/deploy/mtest cd opensrc/margs && chicken-install -deploy -p $(PREFIX)/deploy/mtest cd opensrc/pkts && chicken-install -deploy -p $(PREFIX)/deploy/mtest nanomsg: $(PREFIX)/deploy/mtest/libnanomsg.so.1.0.0 $(PREFIX)/deploy/mtest/libnanomsg.so.1.0.0: wget --no-check-certificate https://github.com/nanomsg/nanomsg/archive/1.0.0.tar.gz mv 1.0.0 1.0.0.tar.gz tar xf 1.0.0.tar.gz cd nanomsg-1.0.0 && ./configure --prefix=$(PREFIX)/deploy/mtest cd nanomsg-1.0.0 && make cd nanomsg-1.0.0 && make install CSC_OPTIONS="-I$(PREFIX)/deploy/mtest/include -L$(PREFIX)/deploy/mtest/lib -L$(PREFIX)/deploy/mtest/lib64/" chicken-install -deploy -p $(PREFIX)/deploy/mtest nanomsg $(PREFIX)/deploy/mtest/bin/pg_config: wget -c https://ftp.postgresql.org/pub/source/v9.6.4/postgresql-9.6.4.tar.gz tar xfz postgresql-9.6.4.tar.gz cd postgresql-9.6.4 && ./configure --prefix=$(PREFIX)/deploy/mtest/ --with-openssl; cd postgresql-9.6.4 && make cd postgresql-9.6.4 && make install $(PREFIX)/deploy/mtest/postgresql.so: CSC_OPTIONS="-I$(PREFIX)/deploy/mtest/include -L$(PREFIX)/deploy/mtest/lib -L$(PREFIX)/deploy/mtest/lib64/" chicken-install -deploy -p $(PREFIX)/deploy/mtest postgresql postgres: $(PREFIX)/deploy/mtest/bin/pg_config $(PREFIX)/deploy/mtest/postgresql.so ducttape: $(PREFIX)/deploy/mtest/ducttape.so $(PREFIX)/deploy/mtest/ducttape.so: cd ducttape && chicken-install -p $(PREFIX)/deploy/mtest -deploy iup: $(PREFIX)/deploy/mtest/iup.so $(PREFIX)/deploy/mtest/iup.so: wget -c http://www.kiatoa.com/matt/chicken-build/cd/cd-${CDVER}_Linux${KTYPE}_${ARCHSIZE}lib.tar.gz wget -c http://www.kiatoa.com/matt/chicken-build/im/im-${IMVER}_Linux${KTYPE}_${ARCHSIZE}lib.tar.gz wget -c http://www.kiatoa.com/matt/chicken-build/iup/iup-${IUPVER}_Linux${KTYPE}_${ARCHSIZE}lib.tar.gz tar -xzvf cd-${CDVER}_Linux${KTYPE}_${ARCHSIZE}lib.tar.gz -C $(PREFIX)/deploy/mtest/ tar -xzvf im-${IMVER}_Linux${KTYPE}_${ARCHSIZE}lib.tar.gz -C $(PREFIX)/deploy/mtest/ tar -xzvf iup-${IUPVER}_Linux${KTYPE}_${ARCHSIZE}lib.tar.gz -C $(PREFIX)/deploy/mtest/ cp $(PREFIX)/deploy/mtest/ftgl/lib/*/* $(PREFIX)/deploy/mtest/ wget -c -O ffcall.tar.gz 'http://www.kiatoa.com/fossils/ffcall/tarball?name=ffcall&uuid=trunk' tar -xzf ffcall.tar.gz cd ffcall && ./configure --prefix=$(PREFIX)/deploy/mtest/ --enable-shared cd ffcall && make CC="gcc -fPIC" cd ffcall && make install CSC_OPTIONS="-I$(PREFIX)/include -I$(PREFIX)/deploy/mtest/include -L$(PREFIX)/deploy/mtest" chicken-install -deploy -p $(PREFIX)/deploy/mtest -D no-library-checks -feature disable-iup-web iup CSC_OPTIONS="-I$(PREFIX)/include -I$(PREFIX)/deploy/mtest//include -L$(PREFIX)/deploy/mtest" chicken-install -deploy -p $(PREFIX)/deploy/mtest -D no-library-checks canvas-draw dboard: $(OFILES) $(GOFILES) dashboard.scm $(MOFILES) csc $(CSCOPTS) $(OFILES) dashboard.scm $(GOFILES) $(MOFILES) -o $(PREFIX)/deploy/mtest/dboard2 cp $(PREFIX)/deploy/mtest/dboard2/dboard2 $(PREFIX)/deploy/mtest/dboard ndboard : newdashboard.scm $(OFILES) $(GOFILES) csc $(CSCOPTS) $(OFILES) $(GOFILES) newdashboard.scm -o $(PREFIX)/deploy/mtest/newdboard mtut : $(OFILES) megatest-fossil-hash.scm mtut.scm csc $(CSCOPTS) $(OFILES) mtut.scm -o $(PREFIX)/deploy/mtest/mtut # install documentation to $(PREFIX)/docs # DOES NOT REBUILD DOCS # $(PREFIX)/share/docs/megatest_manual.html : docs/manual/megatest_manual.html mkdir -p $(PREFIX)/share/docs $(INSTALL) docs/manual/megatest_manual.html $(PREFIX)/share/docs/megatest_manual.html for png in $(PNGFILES);do $(INSTALL) docs/manual/$$png $(PREFIX)/share/docs/$$png;done js : java-script-lib/jquery-3.1.0.slim.min.js mkdir -p $(PREFIX)/share/js cp java-script-lib/jquery-3.1.0.slim.min.js $(PREFIX)/share/js/jquery-3.1.0.slim.min.js $(PREFIX)/share/db/mt-pg.sql : mt-pg.sql mkdir -p $(PREFIX)/share/db $(INSTALL) mt-pg.sql $(PREFIX)/share/db/mt-pg.sql #multi-dboard : multi-dboard.scm $(OFILES) $(GOFILES) # csc $(CSCOPTS) $(OFILES) $(GOFILES) multi-dboard.scm -o multi-dboard # # $(PREFIX)/bin/revtagfsl : utils/revtagfsl.scm # csc utils/revtagfsl.scm -o $(PREFIX)/bin/revtagfsl |
︙ | ︙ | |||
153 154 155 156 157 158 159 160 161 162 163 164 165 166 | @echo Installing to PREFIX=$(PREFIX) $(INSTALL) mtest $(PREFIX)/bin/.$(ARCHSTR)/mtest utils/mk_wrapper $(PREFIX) mtest $(PREFIX)/bin/megatest chmod a+x $(PREFIX)/bin/megatest $(PREFIX)/bin/.$(ARCHSTR)/ndboard : ndboard $(INSTALL) ndboard $(PREFIX)/bin/.$(ARCHSTR)/ndboard $(PREFIX)/bin/newdashboard : $(PREFIX)/bin/.$(ARCHSTR)/ndboard utils/mk_wrapper utils/mk_wrapper $(PREFIX) ndboard $(PREFIX)/bin/newdashboard chmod a+x $(PREFIX)/bin/newdashboard #$(PREFIX)/bin/.$(ARCHSTR)/mdboard : multi-dboard # $(INSTALL) multi-dboard $(PREFIX)/bin/.$(ARCHSTR)/mdboard | > > > > > > > > > > > > > | 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 | @echo Installing to PREFIX=$(PREFIX) $(INSTALL) mtest $(PREFIX)/bin/.$(ARCHSTR)/mtest utils/mk_wrapper $(PREFIX) mtest $(PREFIX)/bin/megatest chmod a+x $(PREFIX)/bin/megatest $(PREFIX)/bin/.$(ARCHSTR)/ndboard : ndboard $(INSTALL) ndboard $(PREFIX)/bin/.$(ARCHSTR)/ndboard $(PREFIX)/bin/.$(ARCHSTR)/mtut : mtut $(INSTALL) mtut $(PREFIX)/bin/.$(ARCHSTR)/mtut install-mtut : mtut echo $(INSTALL) #$(INSTALL) mtut $(PREFIX)/bin/mtut $(PREFIX)/bin/mtutil : $(PREFIX)/bin/.$(ARCHSTR)/mtut utils/mk_wrapper utils/mk_wrapper $(PREFIX) mtut $(PREFIX)/bin/mtutil chmod a+x $(PREFIX)/bin/mtutil mtutil: $(PREFIX)/bin/mtutil $(PREFIX)/bin/newdashboard : $(PREFIX)/bin/.$(ARCHSTR)/ndboard utils/mk_wrapper utils/mk_wrapper $(PREFIX) ndboard $(PREFIX)/bin/newdashboard chmod a+x $(PREFIX)/bin/newdashboard #$(PREFIX)/bin/.$(ARCHSTR)/mdboard : multi-dboard # $(INSTALL) multi-dboard $(PREFIX)/bin/.$(ARCHSTR)/mdboard |
︙ | ︙ | |||
201 202 203 204 205 206 207 208 209 210 211 212 213 214 | $(INSTALL) $< $@ chmod a+x $@ $(PREFIX)/bin/loadrunner : utils/loadrunner $(INSTALL) $< $@ chmod a+x $@ # $(PREFIX)/bin/refdb : refdb # $(INSTALL) $< $@ # chmod a+x $@ deploytarg/nbfake : utils/nbfake $(INSTALL) $< $@ chmod a+x $@ | > > > > > | 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 | $(INSTALL) $< $@ chmod a+x $@ $(PREFIX)/bin/loadrunner : utils/loadrunner $(INSTALL) $< $@ chmod a+x $@ $(PREFIX)/bin/mtest-reaper: helpers/mtest-reaper.scm helpers/ducttape-lib.scm helpers/inteldate.scm helpers/mimetypes.scm make -C helpers $@ PREFIX=$(PREFIX) INSTALL=$(INSTALL) ARCHSTR=$(ARCHSTR) mtest-reaper: $(PREFIX)/bin/mtest-reaper # $(PREFIX)/bin/refdb : refdb # $(INSTALL) $< $@ # chmod a+x $@ deploytarg/nbfake : utils/nbfake $(INSTALL) $< $@ chmod a+x $@ |
︙ | ︙ | |||
224 225 226 227 228 229 230 | # install dashboard as dboard so wrapper script can be called dashboard $(PREFIX)/bin/.$(ARCHSTR)/dboard : dboard $(FILES) utils/mk_wrapper utils/mk_wrapper $(PREFIX) dboard $(PREFIX)/bin/dashboard chmod a+x $(PREFIX)/bin/dashboard $(INSTALL) dboard $(PREFIX)/bin/.$(ARCHSTR)/dboard install : $(PREFIX)/bin/.$(ARCHSTR) $(PREFIX)/bin/.$(ARCHSTR)/mtest $(PREFIX)/bin/megatest \ | | | | > > > > > | 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 | # install dashboard as dboard so wrapper script can be called dashboard $(PREFIX)/bin/.$(ARCHSTR)/dboard : dboard $(FILES) utils/mk_wrapper utils/mk_wrapper $(PREFIX) dboard $(PREFIX)/bin/dashboard chmod a+x $(PREFIX)/bin/dashboard $(INSTALL) dboard $(PREFIX)/bin/.$(ARCHSTR)/dboard install : $(PREFIX)/bin/.$(ARCHSTR) $(PREFIX)/bin/.$(ARCHSTR)/mtest $(PREFIX)/bin/megatest \ $(PREFIX)/bin/.$(ARCHSTR)/dboard $(PREFIX)/bin/dashboard $(HELPERS) $(PREFIX)/bin/nbfake \ $(PREFIX)/bin/nbfind $(PREFIX)/bin/loadrunner $(PREFIX)/bin/viewscreen $(PREFIX)/bin/mt_xterm \ $(PREFIX)/share/docs/megatest_manual.html $(PREFIX)/bin/remrun \ $(PREFIX)/share/docs/megatest_manual.html $(PREFIX)/bin/remrun $(PREFIX)/bin/mtutil \ $(PREFIX)/bin/tcmt $(PREFIX)/share/db/mt-pg.sql \ js $(PREFIX)/bin/.$(ARCHSTR) : mkdir -p $(PREFIX)/bin/.$(ARCHSTR) mkdir -p $(PREFIX)/bin/.$(ARCHSTR)/lib test: tests/tests.scm cd tests;csi -I .. -b -n tests.scm ext-tests/.fslckout : $(MTQA_FOSSIL) mkdir -p ext-tests cd ext-tests;fossil open --nested $(MTQA_FOSSIL) |
︙ | ︙ | |||
260 261 262 263 264 265 266 | #====================================================================== $(DEPLOYHELPERS) : utils/mt_* $(INSTALL) $< $@ chmod a+X $@ deploytarg/apropos.so : Makefile | > > | | | | 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 | #====================================================================== $(DEPLOYHELPERS) : utils/mt_* $(INSTALL) $< $@ chmod a+X $@ deploytarg/apropos.so : Makefile for egg in $(EGGS); do \ echo "chicken-install -p deploytarg -deploy -keep-installed $$egg "; \ chicken-install -p deploytarg -deploy -keep-installed $$egg ; \ done # for i in apropos base64 canvas-draw csv-xml directory-utils dot-locking extras fmt format hostinfo http-client intarweb json md5 message-digest posix posix-extras readline regex regex-case s11n spiffy spiffy-request-vars sqlite3 srfi-1 srfi-18 srfi-69 tcp test uri-common check-errors synch matchable sql-null tcp-server rpc blob-utils string-utils variable-item defstruct uri-generic sendfile opensll openssl lookup-table list-utils stack; do \ # chicken-install -prefix deploytarg -deploy $$i;done # deploytarg/libsqlite3.so : # CSC_OPTIONS="-Ideploytarg -Ldeploytarg" $CHICKEN_INSTALL -prefix deploytarg -deploy sqlite3 deploy : deploytarg/mtest deploytarg/dboard $(DEPLOYHELPERS) deploytarg/nbfake deploytarg/remrun deploytarg/viewsceen deploytarg/nbfind deploytarg/apropos.so # deploytarg/libiupcd.so : $(CKPATH)/lib/libiupcd.so # for i in iup im cd av call sqlite; do \ # cp $(CKPATH)/lib/lib$$i* deploytarg/ ; \ # done # cp $(CKPATH)/include/*.h deploytarg |
︙ | ︙ | |||
329 330 331 332 333 334 335 | altdb.scm : echo ";; optional alternate db setup" > altdb.scm echo "(define *available-db* (make-hash-table))" >> altdb.scm if csi -ne '(use mysql-client)';then \ echo "(use mysql-client)(hash-table-set! *available-db* 'mysql #t)" >> altdb.scm; \ fi | | | | > > > > > > > > > > > > > | 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 | altdb.scm : echo ";; optional alternate db setup" > altdb.scm echo "(define *available-db* (make-hash-table))" >> altdb.scm if csi -ne '(use mysql-client)';then \ echo "(use mysql-client)(hash-table-set! *available-db* 'mysql #t)" >> altdb.scm; \ fi # if csi -ne '(use postgresql)';then \ # echo "(use postgresql)(hash-table-set! *available-db* 'postgresql #t)" >> altdb.scm;\ # fi portlogger-example : portlogger-example.scm api.o archive.o client.o common.o configf.o daemon.o dashboard-tests.o db.o dcommon.o ezsteps.o filedb.o genexample.o gutils.o http-transport.o items.o keys.o launch.o lock-queue.o margs.o megatest-version.o mt.o ods.o portlogger.o process.o rmt.o rpc-transport.o runconfig.o runs.o sdb.o server.o synchash.o tasks.o tdb.o tests.o tree.o csc $(CSCOPTS) portlogger-example.scm api.o archive.o client.o common.o configf.o daemon.o dashboard-tests.o db.o dcommon.o ezsteps.o filedb.o genexample.o gutils.o http-transport.o items.o keys.o launch.o lock-queue.o margs.o megatest-version.o mt.o ods.o portlogger.o process.o rmt.o rpc-transport.o runconfig.o runs.o sdb.o server.o synchash.o tasks.o tdb.o tests.o tree.o # create a pdf dot graphviz diagram from notations in rmt.scm rmt.pdf : rmt.scm grep ';;DOT' rmt.scm | sed -e 's/.*;;DOT //' > rmt.dot;dot -Tpdf rmt.dot -o rmt.pdf wrappers: wrappers/cfg.sh wrappers/megatest wrappers/dashboard mkdir $(PREFIX)/deploy/mtest/.$(ARCHSTR) -p cat wrappers/cfg.sh | sed 's#PREFIX#$(PREFIX)\/deploy\/mtest#g' > $(PREFIX)/deploy/mtest/.$(ARCHSTR)/cfg.sh cat wrappers/megatest | sed 's#PREFIX#$(PREFIX)\/deploy\/mtest#g' | sed 's#ARCHSTR#.$(ARCHSTR)#g' > $(PREFIX)/deploy/mtest/megatest cat wrappers/dashboard | sed 's#PREFIX#$(PREFIX)\/deploy\/mtest#g'| sed 's#ARCHSTR#.$(ARCHSTR)#g' > $(PREFIX)/deploy/mtest/dashboard chmod +x $(PREFIX)/deploy/mtest/megatest chmod +x $(PREFIX)/deploy/mtest/dashboard |
Modified NOTES from [24a602c385] to [7c075bb80d].
1 2 3 4 5 6 7 | ===================================================================== NOTES from looking at branch v1.62-rpc ===================================================================== *last-db-access* or *db-last-access* ==> which is it to be? seen in singletest: ERROR: Unrecognised arguments: :first_err This is the first error | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. ===================================================================== NOTES from looking at branch v1.62-rpc ===================================================================== *last-db-access* or *db-last-access* ==> which is it to be? seen in singletest: ERROR: Unrecognised arguments: :first_err This is the first error |
︙ | ︙ | |||
139 140 141 142 143 144 145 | INFO: (0) Number non-cached queries 74289 INFO: (0) Average non-cached time 1055.09826488444 ms INFO: (0) Server shutdown complete. Exiting Start: 0 at Sun Apr 28 22:18:25 MST 2013 Max: 52 at Sun Apr 28 23:06:59 MST 2013 End: 6 at Sun Apr 28 23:47:51 MST 2013 | > > > > | 156 157 158 159 160 161 162 163 164 165 166 | INFO: (0) Number non-cached queries 74289 INFO: (0) Average non-cached time 1055.09826488444 ms INFO: (0) Server shutdown complete. Exiting Start: 0 at Sun Apr 28 22:18:25 MST 2013 Max: 52 at Sun Apr 28 23:06:59 MST 2013 End: 6 at Sun Apr 28 23:47:51 MST 2013 ======================================================================== |
Modified README from [412df20f12] to [c72b195649].
1 2 3 4 | Megatest To build: | > > > > > > > > > > > > > > > > > | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. Megatest To build: 1. Install chicken scheme. See opensrc repo utils/installall.sh http://www.kiatoa.com/fossils/opensrc 2. Compile with "make -j install PREFIX=/some/path" 3. To test .... |
Modified TODO from [5679234cf7] to [e0a2376de1].
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | TODO ==== . Dashboard should resist running from non-homehost Migration to inmem db plus per run db ------------------------------------- . Re-work the dbstruct data structure? .. Move main.db to global? .. [ run-id.db inmemdb last-mod last-read last-sync inuse ] . Re-work all queries to use run-id to dereference server . Open main.db directly in calls to -runtests etc. No need to talk remote? | > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. TODO ==== . Dashboard should resist running from non-homehost Migration to inmem db plus per run db ------------------------------------- . Re-work the dbstruct data structure? .. Move main.db to global? .. [ run-id.db inmemdb last-mod last-read last-sync inuse ] . Re-work all queries to use run-id to dereference server . Open main.db directly in calls to -runtests etc. No need to talk remote? . remove common:faux-lock |
Modified api.scm from [9ab20f89e3] to [a15c0cd809].
1 2 3 | ;;====================================================================== ;; Copyright 2006-2013, Matthew Welland. ;; | | | > > > > > | | > | > > > > > > > > > > > > | > > | > | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 | ;;====================================================================== ;; Copyright 2006-2013, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. ;; ;;====================================================================== (use srfi-69 posix) (declare (unit api)) (declare (uses rmt)) (declare (uses db)) (declare (uses tasks)) ;; allow these queries through without starting a server ;; (define api:read-only-queries '(get-key-val-pairs get-var get-keys get-key-vals test-toplevel-num-items get-test-info-by-id get-steps-info-by-id get-data-info-by-id test-get-rundir-from-test-id get-count-tests-running-for-testname get-count-tests-running get-count-tests-running-in-jobgroup get-previous-test-run-record get-matching-previous-test-run-records test-get-logfile-info test-get-records-for-index-file get-testinfo-state-status test-get-top-process-pid test-get-paths-matching-keynames-target-new get-prereqs-not-met get-count-tests-running-for-run-id get-run-info get-run-status get-run-state get-run-stats get-run-times get-targets get-target ;; register-run get-tests-tags get-test-times get-tests-for-run get-test-id get-tests-for-runs-mindata get-tests-for-run-mindata get-run-name-from-id get-runs simple-get-runs get-num-runs get-runs-cnt-by-patt get-all-run-ids get-prev-run-ids get-run-ids-matching-target get-runs-by-patt get-steps-data get-steps-for-test read-test-data read-test-data* login tasks-get-last testmeta-get-record have-incompletes? ;; synchash-get get-changed-record-ids get-run-record-ids get-not-completed-cnt)) (define api:write-queries '( get-keys-write ;; dummy "write" query to force server start ;; SERVERS start-server kill-server ;; TESTS test-set-state-status-by-id delete-test-records delete-old-deleted-test-records test-set-state-status test-set-top-process-pid set-state-status-and-roll-up-items update-pass-fail-counts top-test-set-per-pf-counts ;; (db:top-test-set-per-pf-counts (db:get-db *db* 5) 5 "runfirst") ;; RUNS register-run set-tests-state-status delete-run lock/unlock-run update-run-event_time mark-incomplete set-state-status-and-roll-up-run ;; STEPS teststep-set-status! delete-steps-for-test ;; TEST DATA test-data-rollup csv->test-data ;; MISC sync-inmem->db |
︙ | ︙ | |||
124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 | (debug:print 0 *default-log-port* " message: " ((condition-property-accessor 'exn 'message) exn)) (vector #f (vector exn call-chain dat))) ;; return some stuff for debug if an exception happens (cond ((not (vector? dat)) ;; it is an error to not receive a vector (vector #f (vector #f "remote must be called with a vector"))) ((> *api-process-request-count* 20) ;; 20) (debug:print 0 *default-log-port* "WARNING: api:execute-requests received an overloaded message.") (vector #f (vector #f 'overloaded))) ;; the inner vector is what gets returned. nope, don't know why. please refactor! (else (let* ((cmd-in (vector-ref dat 0)) (cmd (if (symbol? cmd-in) cmd-in (string->symbol cmd-in))) (params (vector-ref dat 1)) (start-t (current-milliseconds)) (readonly-mode (dbr:dbstruct-read-only dbstruct)) (readonly-command (member cmd api:read-only-queries)) (writecmd-in-readonly-mode (and readonly-mode (not readonly-command))) (res (if writecmd-in-readonly-mode (conc "attempt to run write command "cmd" on a read-only database") (case cmd ;;=============================================== ;; READ/WRITE QUERIES ;;=============================================== ((get-keys-write) (db:get-keys dbstruct)) ;; force a dummy "write" query to force server; for debug in -repl ;; SERVERS ((start-server) (apply server:kind-run params)) ((kill-server) (set! *server-run* #f)) ;; TESTS | > > > > > > > | > > > > > > > > > > > > > > > > | > > > > > > | | 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 | (debug:print 0 *default-log-port* " message: " ((condition-property-accessor 'exn 'message) exn)) (vector #f (vector exn call-chain dat))) ;; return some stuff for debug if an exception happens (cond ((not (vector? dat)) ;; it is an error to not receive a vector (vector #f (vector #f "remote must be called with a vector"))) ((> *api-process-request-count* 20) ;; 20) (debug:print 0 *default-log-port* "WARNING: api:execute-requests received an overloaded message.") (set! *server-overloaded* #t) (vector #f (vector #f 'overloaded))) ;; the inner vector is what gets returned. nope, don't know why. please refactor! (else (let* ((cmd-in (vector-ref dat 0)) (cmd (if (symbol? cmd-in) cmd-in (string->symbol cmd-in))) (params (vector-ref dat 1)) (start-t (current-milliseconds)) (readonly-mode (dbr:dbstruct-read-only dbstruct)) (readonly-command (member cmd api:read-only-queries)) (writecmd-in-readonly-mode (and readonly-mode (not readonly-command))) (foo (begin (common:telemetry-log (conc "api-in:"(->string cmd)) payload: `((params . ,params))) #t)) (res (if writecmd-in-readonly-mode (conc "attempt to run write command "cmd" on a read-only database") (case cmd ;;=============================================== ;; READ/WRITE QUERIES ;;=============================================== ((get-keys-write) (db:get-keys dbstruct)) ;; force a dummy "write" query to force server; for debug in -repl ;; SERVERS ((start-server) (apply server:kind-run params)) ((kill-server) (set! *server-run* #f)) ;; TESTS ;;((test-set-state-status-by-id) (apply mt:test-set-state-status-by-id dbstruct params)) ;;BB - commented out above because it was calling below, eventually, incorrectly (dbstruct passed to mt:test-set-state-status-by-id, which previosly did more, but now only passes thru to db:set-state-status-and-roll-up-items. ((test-set-state-status-by-id) ;; (define (db:set-state-status-and-roll-up-items dbstruct run-id test-name item-path state status comment) (db:set-state-status-and-roll-up-items dbstruct (list-ref params 0) ; run-id (list-ref params 1) ; test-name #f ; item-path (list-ref params 2) ; state (list-ref params 3) ; status (list-ref params 4) ; comment )) ((delete-test-records) (apply db:delete-test-records dbstruct params)) ((delete-old-deleted-test-records) (apply db:delete-old-deleted-test-records dbstruct params)) ((test-set-state-status) (apply db:test-set-state-status dbstruct params)) ((test-set-top-process-pid) (apply db:test-set-top-process-pid dbstruct params)) ((set-state-status-and-roll-up-items) (apply db:set-state-status-and-roll-up-items dbstruct params)) ((set-state-status-and-roll-up-run) (apply db:set-state-status-and-roll-up-run dbstruct params)) ((top-test-set-per-pf-counts) (apply db:top-test-set-per-pf-counts dbstruct params)) ((test-set-archive-block-id) (apply db:test-set-archive-block-id dbstruct params)) ;; RUNS ((register-run) (apply db:register-run dbstruct params)) ((set-tests-state-status) (apply db:set-tests-state-status dbstruct params)) ((delete-run) (apply db:delete-run dbstruct params)) ((lock/unlock-run) (apply db:lock/unlock-run dbstruct params)) ((update-run-event_time) (apply db:update-run-event_time dbstruct params)) ((update-run-stats) (apply db:update-run-stats dbstruct params)) ((set-var) (apply db:set-var dbstruct params)) ((del-var) (apply db:del-var dbstruct params)) ;; STEPS ((teststep-set-status!) (apply db:teststep-set-status! dbstruct params)) ((delete-steps-for-test!) (apply db:delete-steps-for-test! dbstruct params)) ;; TEST DATA ((test-data-rollup) (apply db:test-data-rollup dbstruct params)) ((csv->test-data) (apply db:csv->test-data dbstruct params)) ;; MISC ((sync-inmem->db) (let ((run-id (car params))) (db:sync-touched dbstruct run-id force-sync: #t))) ((mark-incomplete) (apply db:find-and-mark-incomplete dbstruct params)) ;; TESTMETA ((testmeta-add-record) (apply db:testmeta-add-record dbstruct params)) ((testmeta-update-field) (apply db:testmeta-update-field dbstruct params)) ((get-tests-tags) (db:get-tests-tags dbstruct)) ;; TASKS ((tasks-add) (apply tasks:add dbstruct params)) ((tasks-set-state-given-param-key) (apply tasks:set-state-given-param-key dbstruct params)) ((tasks-get-last) (apply tasks:get-last dbstruct params)) ;; NO SYNC DB ((no-sync-set) (apply db:no-sync-set *no-sync-db* params)) ((no-sync-get/default) (apply db:no-sync-get/default *no-sync-db* params)) ((no-sync-del!) (apply db:no-sync-del! *no-sync-db* params)) ((no-sync-get-lock) (apply db:no-sync-get-lock *no-sync-db* params)) ;; ARCHIVES ;; ((archive-get-allocations) ((archive-register-disk) (apply db:archive-register-disk dbstruct params)) ((archive-register-block-name)(apply db:archive-register-block-name dbstruct params)) ;; ((archive-allocate-testsuite/area-to-block)(apply db:archive-allocate-testsuite/area-to-block dbstruct block-id testsuite-name areakey)) ;;====================================================================== ;; READ ONLY QUERIES ;;====================================================================== ;; KEYS ((get-key-val-pairs) (apply db:get-key-val-pairs dbstruct params)) |
︙ | ︙ | |||
219 220 221 222 223 224 225 | ((test-toplevel-num-items) (apply db:test-toplevel-num-items dbstruct params)) ((get-test-info-by-id) (apply db:get-test-info-by-id dbstruct params)) ((test-get-rundir-from-test-id) (apply db:test-get-rundir-from-test-id dbstruct params)) ((get-count-tests-running-for-testname) (apply db:get-count-tests-running-for-testname dbstruct params)) ((get-count-tests-running) (apply db:get-count-tests-running dbstruct params)) ((get-count-tests-running-in-jobgroup) (apply db:get-count-tests-running-in-jobgroup dbstruct params)) ;; ((delete-test-step-records) (apply db:delete-test-step-records dbstruct params)) | | > | > > > > > > > > > > | > > > > > | > > > > | | 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 | ((test-toplevel-num-items) (apply db:test-toplevel-num-items dbstruct params)) ((get-test-info-by-id) (apply db:get-test-info-by-id dbstruct params)) ((test-get-rundir-from-test-id) (apply db:test-get-rundir-from-test-id dbstruct params)) ((get-count-tests-running-for-testname) (apply db:get-count-tests-running-for-testname dbstruct params)) ((get-count-tests-running) (apply db:get-count-tests-running dbstruct params)) ((get-count-tests-running-in-jobgroup) (apply db:get-count-tests-running-in-jobgroup dbstruct params)) ;; ((delete-test-step-records) (apply db:delete-test-step-records dbstruct params)) ;; ((get-previous-test-run-record) (apply db:get-previous-test-run-record dbstruct params)) ((get-matching-previous-test-run-records)(apply db:get-matching-previous-test-run-records dbstruct params)) ((test-get-logfile-info) (apply db:test-get-logfile-info dbstruct params)) ((test-get-records-for-index-file) (apply db:test-get-records-for-index-file dbstruct params)) ((get-testinfo-state-status) (apply db:get-testinfo-state-status dbstruct params)) ((test-get-top-process-pid) (apply db:test-get-top-process-pid dbstruct params)) ((test-get-paths-matching-keynames-target-new) (apply db:test-get-paths-matching-keynames-target-new dbstruct params)) ((get-prereqs-not-met) (apply db:get-prereqs-not-met dbstruct params)) ((get-count-tests-running-for-run-id) (apply db:get-count-tests-running-for-run-id dbstruct params)) ((get-not-completed-cnt) (apply db:get-not-completed-cnt dbstruct params)) ;; ((synchash-get) (apply synchash:server-get dbstruct params)) ((get-raw-run-stats) (apply db:get-raw-run-stats dbstruct params)) ((get-test-times) (apply db:get-test-times dbstruct params)) ;; RUNS ((get-run-info) (apply db:get-run-info dbstruct params)) ((get-run-status) (apply db:get-run-status dbstruct params)) ((get-run-state) (apply db:get-run-state dbstruct params)) ((set-run-status) (apply db:set-run-status dbstruct params)) ((set-run-state-status) (apply db:set-run-state-status dbstruct params)) ((get-tests-for-run) (apply db:get-tests-for-run dbstruct params)) ((get-test-id) (apply db:get-test-id dbstruct params)) ((get-tests-for-run-mindata) (apply db:get-tests-for-run-mindata dbstruct params)) ;; ((get-tests-for-runs-mindata) (apply db:get-tests-for-runs-mindata dbstruct params)) ((get-runs) (apply db:get-runs dbstruct params)) ((simple-get-runs) (apply db:simple-get-runs dbstruct params)) ((get-num-runs) (apply db:get-num-runs dbstruct params)) ((get-runs-cnt-by-patt) (apply db:get-runs-cnt-by-patt dbstruct params)) ((get-all-run-ids) (db:get-all-run-ids dbstruct)) ((get-prev-run-ids) (apply db:get-prev-run-ids dbstruct params)) ((get-run-ids-matching-target) (apply db:get-run-ids-matching-target dbstruct params)) ((get-runs-by-patt) (apply db:get-runs-by-patt dbstruct params)) ((get-run-name-from-id) (apply db:get-run-name-from-id dbstruct params)) ((get-main-run-stats) (apply db:get-main-run-stats dbstruct params)) ((get-var) (apply db:get-var dbstruct params)) ((get-run-stats) (apply db:get-run-stats dbstruct params)) ((get-run-times) (apply db:get-run-times dbstruct params)) ;; STEPS ((get-steps-data) (apply db:get-steps-data dbstruct params)) ((get-steps-for-test) (apply db:get-steps-for-test dbstruct params)) ((get-steps-info-by-id) (apply db:get-steps-info-by-id dbstruct params)) ;; TEST DATA ((read-test-data) (apply db:read-test-data dbstruct params)) ((read-test-data*) (apply db:read-test-data* dbstruct params)) ((get-data-info-by-id) (apply db:get-data-info-by-id dbstruct params)) ;; MISC ((get-latest-host-load) (apply db:get-latest-host-load dbstruct params)) ((have-incompletes?) (apply db:have-incompletes? dbstruct params)) ((login) (apply db:login dbstruct params)) ((general-call) (let ((stmtname (car params)) (run-id (cadr params)) (realparams (cddr params))) (db:general-call dbstruct stmtname realparams))) ((sdb-qry) (apply sdb:qry params)) ((ping) (current-process-id)) ((get-changed-record-ids) (apply db:get-changed-record-ids dbstruct params)) ((get-run-record-ids) (apply db:get-run-record-ids dbstruct params)) ;; TESTMETA ((testmeta-get-record) (apply db:testmeta-get-record dbstruct params)) ;; TASKS ((find-task-queue-records) (apply tasks:find-task-queue-records dbstruct params)) (else (debug:print 0 *default-log-port* "ERROR: bad api call " cmd) (conc "ERROR: BAD api call " cmd)))))) ;; save all stats (let ((delta-t (- (current-milliseconds) start-t))) (hash-table-set! *db-api-call-time* cmd (cons delta-t (hash-table-ref/default *db-api-call-time* cmd '())))) (if writecmd-in-readonly-mode (begin (common:telemetry-log (conc "api-out:"(->string cmd)) payload: `((params . ,params) (ok-res . #t))) (vector #f res)) (begin (common:telemetry-log (conc "api-out:"(->string cmd)) payload: `((params . ,params) (ok-res . #f))) (vector #t res)))))))) ;; http-server send-response ;; api:process-request ;; db:* ;; ;; NB// Runs on the server as part of the server loop ;; |
︙ | ︙ |
Modified archive.scm from [7dd47285c1] to [8417ecbb27].
1 2 | ;; Copyright 2006-2014, Matthew Welland. ;; | | | > > > > > | | > | > > > < | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | ;; Copyright 2006-2014, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. ;; ;; strftime('%m/%d/%Y %H:%M:%S','now','localtime') (use (prefix sqlite3 sqlite3:) srfi-1 posix regex regex-case srfi-69 format md5 message-digest srfi-18) (declare (unit archive)) (declare (uses db)) (declare (uses common)) (include "common_records.scm") (include "db_records.scm") |
︙ | ︙ | |||
28 29 30 31 32 33 34 | (define (archive:main linktree target runname testname itempath options) (let ((testdir (conc linktree "/" target "/" runname "/" testname "/" itempatt)) (flavor 'plain) ;; type of machine to run jobs on (maxload 1.5) ;; max allowed load for this work (adisks (archive:get-archive-disks))) ;; get testdir size ;; - hand off du to job mgr | | | 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | (define (archive:main linktree target runname testname itempath options) (let ((testdir (conc linktree "/" target "/" runname "/" testname "/" itempatt)) (flavor 'plain) ;; type of machine to run jobs on (maxload 1.5) ;; max allowed load for this work (adisks (archive:get-archive-disks))) ;; get testdir size ;; - hand off du to job mgr (if (and (common:file-exists? testdir) (file-is-writable? testdir)) (let* ((dused (jobrunner:run-job flavor ;; machine type maxload ;; max allowed load '() ;; prevars - environment vars to set for the job common:get-disk-space-used ;; if a proc call it, if a string it is a unix command (list testdir))) |
︙ | ︙ | |||
70 71 72 73 74 75 76 | (vector-ref block 2))) ;; disk-path existing-blocks))) (or (common:get-disk-with-most-free-space candidate-disks dused) (archive:allocate-new-archive-block #f #f #f)))) ;; BROKEN. testname itempath)))) ;; allocate a new archive area ;; | | > > > > > > > > > > > > > > > | | | | | | | > > | | | | | | | | | > > > > | > > | > > | < < | | | > | | | | < | < | > | | > > | > | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | > | | > > | | > > > > | > | | > > > > > | | > > > | > > > > > > > > > | | | | | | > | < < < | | | | | | | | | | | | | > > > > > > > > > > > > > > > > > > > > > > | | | | | | | > > | | | | 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 | (vector-ref block 2))) ;; disk-path existing-blocks))) (or (common:get-disk-with-most-free-space candidate-disks dused) (archive:allocate-new-archive-block #f #f #f)))) ;; BROKEN. testname itempath)))) ;; allocate a new archive area ;; (define (archive:allocate-new-archive-block blockid-cache run-area-home testsuite-name dneeded target run-name test-name) (let ((key (conc testsuite-name "/" target "/" run-name "/" test-name))) (if (hash-table-exists? blockid-cache key) (hash-table-ref blockid-cache key) (let* ((pscript (configf:lookup *configdat* "archive" "pathscript")) (pscript-cmd (conc pscript " " testsuite-name " " target " " run-name " " test-name)) (apath (if pscript (handle-exceptions exn (begin (debug:print 0 *default-log-port* "ERROR: script \"" pscript-cmd "\" failed to run properly.") (exit 1)) (with-input-from-pipe pscript-cmd read-line)) #f)) ;; this is the user-calculated archive path (adisks (archive:get-archive-disks)) (best-disk (common:get-disk-with-most-free-space adisks dneeded))) (if best-disk (let* ((bdisk-name (car best-disk)) (bdisk-path (cdr best-disk)) (area-key (substring (message-digest-string (md5-primitive) run-area-home) 0 5)) (bdisk-id (rmt:archive-register-disk bdisk-name bdisk-path (get-df bdisk-path))) (archive-name (if apath apath (let ((sec (current-seconds))) (conc (time->string (seconds->local-time sec) "%Y") "_q" (seconds->quarter sec) "/" testsuite-name "_" area-key)))) (archive-path (conc bdisk-path "/" archive-name)) (block-id (rmt:archive-register-block-name bdisk-id archive-path))) ;; (allocation-id (rmt:archive-allocate-testsuite/area-to-block block-id testsuite-name area-key))) (if block-id ;; (and block-id allocation-id) (let ((res (cons block-id archive-path))) (hash-table-set! blockid-cache key res) res) (begin (debug:print 0 *default-log-port* "WARNING: no disk found for " target ", " run-name ", " test-name ", archive-path=" archive-path) #f))) (begin (debug:print 0 *default-log-port* "WARNING: no disk found for " target ", " run-name ", " test-name ", block-id=" block-id) #f)))))) ;; no best disk found ;; archive - run bup ;; ;; 1. create the bup dir if not exists ;; 2. start the du of each directory ;; 3. gen index ;; 4. save ;; (define (archive:run-bup archive-command run-id run-name tests rp-mutex bup-mutex) ;; move the getting of archive space down into the below block so that a single run can ;; allocate as needed should a disk fill up ;; (let* ((blockid-cache (make-hash-table)) (tsname (common:get-testsuite-name)) (min-space (string->number (or (configf:lookup *configdat* "archive" "minspace") "1000"))) (arch-groups (make-hash-table)) ;; archive groups, each corrosponds to a bup area (disk-groups (make-hash-table)) ;; (test-groups (make-hash-table)) ;; these two (disk and test groups) could be combined nicely (test-dirs (make-hash-table)) (bup-exe (or (configf:lookup *configdat* "archive" "bup") "bup")) (compress (or (configf:lookup *configdat* "archive" "compress") "9")) (linktree (common:get-linktree)) ;; (configf:lookup *configdat* "setup" "linktree"))) (archiver (let ((s (configf:lookup *configdat* "archive" "archiver"))) (if s (string->symbol s) 'bup))) (archiver-cmd (case archiver ((tar) "tar cfj ARCHIVE_NAME.tar.bz2 ") ((7z) " 7z u -t7z -m0=lzma -mx=9 -mfb=64 -md=32m -ms=on ARCHIVE_NAME.7z ") (else #f))) (print-prefix "Running: ") ;; change to #f to turn off printing (preclean-spec (configf:get-section *configdat* "archive-preclean"))) ;; (tests:match patt testname itempath) ;; from the test info bin the path to the test by stem ;; (for-each (lambda (test-dat) (let* ((item-path (db:test-get-item-path test-dat)) (test-name (db:test-get-testname test-dat)) (test-id (db:test-get-id test-dat)) (run-id (db:test-get-run_id test-dat)) (target (string-intersperse (map cadr (rmt:get-key-val-pairs run-id)) "/")) (toplevel/children (and (db:test-get-is-toplevel test-dat) (> (rmt:test-toplevel-num-items run-id test-name) 0))) (test-partial-path (conc target "/" run-name "/" (db:test-make-full-name test-name item-path))) ;; note the trailing slash to get the dir inspite of it being a link (test-path (conc linktree "/" test-partial-path)) (mutex-lock! rp-mutex) (test-physical-path (if (common:file-exists? test-path) (common:real-path test-path) #f)) (mutex-unlock! rp-mutex) (partial-path-index (if test-physical-path (substring-index test-partial-path test-physical-path) #f)) (test-base (if (and partial-path-index test-physical-path ) (substring test-physical-path 0 partial-path-index) #f)) ;; we need our archive dir checked for every test to enable folks who want to store other ways. (archive-info (archive:allocate-new-archive-block blockid-cache *toppath* tsname min-space target run-name test-name)) (archive-dir (if archive-info (cdr archive-info) #f)) (archive-id (if archive-info (car archive-info) -1))) (if (not archive-dir) ;; no archive disk found, this is fatal (begin (debug:print 0 *default-log-port* "FATAL: No archive disks found. Please add disks with at least " min-space " MB space to the [archive-disks] section of megatest.config") (debug:print 0 *default-log-port* " use [archive] minspace to specify minimum available space") (debug:print 0 *default-log-port* " disks: " (string-intersperse (map cadr (archive:get-archive-disks)) "\n ")) (exit 1)) (debug:print-info 0 *default-log-port* "Using path " archive-dir " for archiving test " test-path)) ;; preclean the test directory per the spec if provided (if (not (null? preclean-spec)) ;; we've been asked to preclean before archiving (let loop ((spec (car preclean-spec)) (tail (cdr preclean-spec))) (if (> (length spec) 1) (let ((testspec (car spec)) (rules (cadr spec))) (if (tests:match testspec test-name item-path) (begin (debug:print 0 *default-log-port* "INFO: cleanup requested for " test-physical-path) (common:dir-clean-up test-physical-path rules remove-empty: #t)) (if (not (null? tail)) (loop (car tail)(cdr tail))))) (begin (debug:print 0 *default-log-port* "ERROR: bad spec line in [archive-preclean] section. \"" spec "\"") (if (not (null? tail))(loop (car tail)(cdr tail))))))) (cond (toplevel/children (debug:print 0 *default-log-port* "WARNING: cannot archive " test-name " with id " test-id " as it is a toplevel test with children")) ((not (common:file-exists? test-path)) (debug:print 0 *default-log-port* "WARNING: Cannot archive " test-name "/" item-path " as path " test-path " does not exist")) (else (debug:print 0 *default-log-port* "From test-dat=" test-dat " derived the following:\n" "test-partial-path = " test-partial-path "\n" "test-path = " test-path "\n" "test-physical-path = " test-physical-path "\n" "partial-path-index = " partial-path-index "\n" "test-base = " test-base) (hash-table-set! disk-groups test-base (cons test-physical-path (hash-table-ref/default disk-groups test-base '()))) (hash-table-set! test-groups test-base (cons test-dat (hash-table-ref/default test-groups test-base '()))) (hash-table-set! arch-groups test-base (cons archive-info (hash-table-ref/default arch-groups test-base '()))) (hash-table-set! test-dirs test-id test-path))))) ;; test-path)))) tests) (debug:print 0 *default-log-port* "INFO: DISK GROUPS=" (hash-table->alist disk-groups)) ;; for each disk-group, initialize the bup area if needed (for-each (lambda (test-base) (let* ((disk-group (hash-table-ref disk-groups test-base)) (arch-group (hash-table-ref arch-groups test-base)) (arch-info (car arch-group)) ;; don't know yet how this will work, can I get more than one possibility? (archive-id (car arch-info)) (archive-dir (cdr arch-info))) (debug:print 0 *default-log-port* "Processing disk-group " test-base) (let* ((test-paths-in (hash-table-ref disk-groups test-base)) (test-paths (if (args:get-arg "-include") (let ((subpaths (string-split (args:get-arg "-include") ","))) (apply append (map (lambda (p) (map (lambda (subp) (conc p "/" subp)) subpaths)) test-paths-in))) test-paths-in))) (if (not (common:file-exists? archive-dir)) (create-directory archive-dir #t)) (case archiver ((bup) ;; Archive using bup (let* ((bup-init-params (list "-d" archive-dir "init")) (bup-index-params (append (list "-d" archive-dir "index") test-paths)) (bup-save-params (append (list "-d" archive-dir "save" ;; (conc "--strip-path=" linktree) (conc "-" compress) ;; or (conc "--compress=" compress) "-n" (conc (common:get-testsuite-name) "-" run-id) (conc "--strip-path=" test-base) ;; if we push to the directory do we need this? ) test-paths))) (if (not (common:file-exists? (conc archive-dir "/HEAD"))) (begin ;; replace this with jobrunner stuff enventually (debug:print-info 0 *default-log-port* "Init bup in " archive-dir) ;; (mutex-lock! bup-mutex) (run-n-wait bup-exe params: bup-init-params print-cmd: print-prefix) ;; (mutex-unlock! bup-mutex) )) (debug:print-info 0 *default-log-port* "Indexing data to be archived") ;; (mutex-lock! bup-mutex) (run-n-wait bup-exe params: bup-index-params print-cmd: print-prefix) (debug:print-info 0 *default-log-port* "Archiving data with bup") (run-n-wait bup-exe params: bup-save-params print-cmd: print-prefix))) ((7z tar) (for-each (lambda (test-dat) (let* ((test-id (db:test-get-id test-dat)) (test-name (db:test-get-testname test-dat)) (item-path (db:test-get-item-path test-dat)) (test-full-name (db:test-make-full-name test-name item-path)) (run-id (db:test-get-run_id test-dat)) (target (string-intersperse (map cadr (rmt:get-key-val-pairs run-id)) "/")) (run-name (rmt:get-run-name-from-id run-id)) (source-dir (hash-table-ref test-dirs test-id)) ;; (conc test-base "/" test-name "/" item-path)) (target-dir (string-substitute "/$" "" (conc archive-dir "/" target "/" run-name "/" test-full-name)))) ;; create the test and item-path levels under archive-dir (create-directory (pathname-directory target-dir) #t) (run-n-wait (conc (string-substitute "ARCHIVE_NAME" target-dir archiver-cmd) " " "." ) print-cmd: print-prefix run-dir: source-dir))) (hash-table-ref test-groups test-base)))) ;; (mutex-unlock! bup-mutex) (for-each (lambda (test-dat) (let ((test-id (db:test-get-id test-dat)) (run-id (db:test-get-run_id test-dat))) (rmt:test-set-archive-block-id run-id test-id archive-id) (if (member (symbol->string archive-command) '("save-remove")) (begin (debug:print-info 0 *default-log-port* "remove testdat") (runs:remove-test-directory test-dat 'archive-remove))))) (hash-table-ref test-groups test-base))))) (hash-table-keys disk-groups)) #t)) (define (archive:bup-restore archive-command run-id run-name tests rp-mutex bup-mutex) ;; move the getting of archive space down into the below block so that a single run can ;; allocate as needed should a disk fill up ;; (let* ((bup-exe (or (configf:lookup *configdat* "archive" "bup") "bup")) (linktree (common:get-linktree))) ;; (configf:lookup *configdat* "setup" "linktree"))) |
︙ | ︙ | |||
231 232 233 234 235 236 237 | (toplevel/children (and (db:test-get-is-toplevel test-dat) (> (rmt:test-toplevel-num-items run-id test-name) 0))) (test-partial-path (conc target "/" run-name "/" (db:test-make-full-name test-name item-path))) ;; note the trailing slash to get the dir inspite of it being a link (test-path (conc linktree "/" test-partial-path)) ;; if the old path was not deleted then prev-test-physical-path will end up pointing to a real directory (mutex-lock! rp-mutex) | | | > > > | | 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 | (toplevel/children (and (db:test-get-is-toplevel test-dat) (> (rmt:test-toplevel-num-items run-id test-name) 0))) (test-partial-path (conc target "/" run-name "/" (db:test-make-full-name test-name item-path))) ;; note the trailing slash to get the dir inspite of it being a link (test-path (conc linktree "/" test-partial-path)) ;; if the old path was not deleted then prev-test-physical-path will end up pointing to a real directory (mutex-lock! rp-mutex) (prev-test-physical-path (if (common:file-exists? test-path) ;; (read-symbolic-link test-path #t) (common:real-path test-path) #f)) (mutex-unlock! rp-mutex) (new-test-physical-path (conc best-disk "/" test-partial-path)) (archive-block-id (db:test-get-archived test-dat)) (archive-block-info (rmt:test-get-archive-block-info archive-block-id)) (archive-path (if (vector? archive-block-info) (vector-ref archive-block-info 2) ;; look in db.scm for test-get-archive-block-info for the vector record info #f)) ;; no archive found? (archive-internal-path (conc (common:get-testsuite-name) "-" run-id "/latest/" test-partial-path)) (include-paths (args:get-arg "-include")) (exclude-pattern (args:get-arg "-exclude-rx")) (exclude-file (args:get-arg "-exclude-rx-from"))) ;; some sanity checks, move an existing path out of the way - iif it is not a toplevel with children ;; (if (and (not toplevel/children) ;; special handling needed for toplevel with children prev-test-physical-path (common:file-exists? prev-test-physical-path)) ;; what to do? abort or clean up or link it in? (let* ((base (pathname-directory prev-test-physical-path)) (dirn (pathname-file prev-test-physical-path)) (newn (conc base "/." dirn))) (debug:print-error 0 *default-log-port* "the old directory " prev-test-physical-path ", still exists! Moving it to " newn) (rename-file prev-test-physical-path newn))) (if (and archive-path ;; no point in proceeding if there is no actual archive |
︙ | ︙ | |||
285 286 287 288 289 290 291 | (debug:print-info 0 *default-log-port* "Restoring archived data to " new-test-physical-path " from archive in " archive-path " ... " archive-internal-path) ;; (mutex-lock! bup-mutex) (run-n-wait bup-exe params: bup-restore-params print-cmd: #f) ;; (mutex-unlock! bup-mutex) (mt:test-set-state-status-by-id run-id test-id "COMPLETED" #f #f))) (debug:print-error 0 *default-log-port* "No archive path in the record for run-id=" run-id " test-id=" test-id)))) (filter vector? tests)))) | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 | (debug:print-info 0 *default-log-port* "Restoring archived data to " new-test-physical-path " from archive in " archive-path " ... " archive-internal-path) ;; (mutex-lock! bup-mutex) (run-n-wait bup-exe params: bup-restore-params print-cmd: #f) ;; (mutex-unlock! bup-mutex) (mt:test-set-state-status-by-id run-id test-id "COMPLETED" #f #f))) (debug:print-error 0 *default-log-port* "No archive path in the record for run-id=" run-id " test-id=" test-id)))) (filter vector? tests)))) (define (common:get-youngest-test tests) (if (null? tests) #f (let ((res #f)) (for-each (lambda (test-dat) (let ((event-time (db:test-get-event_time test-dat))) (if (or (not res) (> event-time (db:test-get-event_time res))) (set! res test-dat)))) tests) res))) ;; from an archive get a specific path - works ONLY with bup for now ;; (define (archive:bup-get-data archive-command run-id-in run-name-in tests rp-mutex bup-mutex) (if (null? tests) (debug:print-info 0 *default-log-port* "get-data called with no matching tests to operate on.") (let* ((bup-exe (or (configf:lookup *configdat* "archive" "bup") "bup")) (linktree (common:get-linktree)) ;; (configf:lookup *configdat* "setup" "linktree"))) ;; (test-dat (common:get-youngest-test tests)) (destpath (args:get-arg "-dest"))) (cond ((null? tests) (debug:print-error 0 *default-log-port* "No test matching provided target, runname pattern and test pattern found.")) ((file-exists? destpath) (debug:print-error 0 *default-log-port* "Destination path alread exists! Please remove it before running get.")) (else (let loop ((rem-tests tests)) (let* ((test-dat (common:get-youngest-test rem-tests)) (item-path (db:test-get-item-path test-dat)) (test-name (db:test-get-testname test-dat)) (test-id (db:test-get-id test-dat)) (run-id (db:test-get-run_id test-dat)) (run-name (rmt:get-run-name-from-id run-id)) (keyvals (rmt:get-key-val-pairs run-id)) (target (string-intersperse (map cadr keyvals) "/")) (toplevel/children (and (db:test-get-is-toplevel test-dat) (> (rmt:test-toplevel-num-items run-id test-name) 0))) (test-partial-path (conc target "/" run-name "/" (db:test-make-full-name test-name item-path))) ;; note the trailing slash to get the dir inspite of it being a link (test-path (conc linktree "/" test-partial-path)) (archive-block-id (db:test-get-archived test-dat)) (archive-block-info (rmt:test-get-archive-block-info archive-block-id)) (archive-path (if (vector? archive-block-info) (vector-ref archive-block-info 2) #f)) (archive-internal-path (conc (common:get-testsuite-name) "-" run-id "/latest/" test-partial-path)) (include-paths (args:get-arg "-include")) (exclude-pattern (args:get-arg "-exclude-rx")) (exclude-file (args:get-arg "-exclude-rx-from"))) (if (and archive-path ;; no point in proceeding if there is no actual archive (not toplevel/children)) (begin (let* ((bup-restore-params (append (list "-d" archive-path "restore" "-C" (or destpath "data")) ;; " " ;; What is the empty string for? (if include-paths (map (lambda (p) (conc archive-internal-path "/" p)) (string-split include-paths ",")) (list archive-internal-path))))) (debug:print-info 0 *default-log-port* "Restoring archived data to " (or destpath "data") " from archive in " archive-path " ... " archive-internal-path) (run-n-wait bup-exe params: bup-restore-params print-cmd: #t))) (let ((new-rem-tests (filter (lambda (tdat) (or (not (eq? (db:test-get-id tdat) test-id)) (not (eq? (db:test-get-run_id tdat) run-id)))) rem-tests) )) (debug:print-info 0 *default-log-port* "No archive path in the record for run-id=" run-id " test-id=" test-id ", skipping.") (if (null? new-rem-tests) (begin (debug:print-info 0 *default-log-port* "No archives found for " target "/" run-name "...") #f) (loop new-rem-tests))))))))))) |
Added autostuff/.mtutil.scm version [7329dbfd3d].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 | ;; Copyright 2006-2017, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. (use json) (use ducttape-lib) (define (get-last-runname area-path target) (let* ((run-data (with-input-from-pipe (conc "megatest -list-runs % -target " target " -fields runs:runname,event_time -dumpmode sexpr -start-dir " area-path) read))) (if (or (not run-data) (null? run-data)) #f (let* ((name-time (let ((dat (map cdadr (alist-ref target run-data equal?)))) ;; (("runname" . "2017w07.0-0047") ("event_time" . "1487490424")) ;; (print "dat=" dat) (map (lambda (item) (cons (alist-ref "runname" item equal?) (string->number (alist-ref "event_time" item equal?)))) dat))) (sorted (sort name-time (lambda (a b)(> (cdr a)(cdr b))))) (last-name (if (null? sorted) #f (caar sorted)))) last-name)))) (define (str-first-char->number str) (char->integer (string-ref str 0))) ;; example of how to set up and write target mappers ;; NOTE: maps a *list* of targets! ;; ;; (? target run-name area area-path reason contour mode-patt) ;; (add-target-mapper 'prefix-contour (lambda (runkey area contour) (print "target: " runkey) (list (conc contour "/" runkey)))) #;(add-target-mapper 'prefix-area-contour (lambda (target run-name area area-path reason contour mode-patt) (conc area "/" contour "/" target))) (add-runname-mapper 'corporate-ww (lambda (target run-name area area-path reason contour mode-patt) (print "corporate-ww called with: target=" target " run-name=" run-name " area=" area " area-path=" area-path " reason=" reason " contour=" contour " mode-patt=" mode-patt) (let* ((last-name (get-last-runname area-path target)) (last-letter (let* ((ch (if (string? last-name) (let ((len (string-length last-name))) (substring last-name (- len 1) len)) "a")) (chnum (str-first-char->number ch)) (a (str-first-char->number "a")) (z (str-first-char->number "z"))) (if (and (>= chnum a)(<= chnum z)) chnum #f))) (next-letter (if last-letter (list->string (list (integer->char (+ last-letter 1)))) ;; surely there is an easier way? "a"))) ;; (print "last-name: " last-name " last-letter: " last-letter " next-letter: " next-letter) (conc (seconds->wwdate (current-seconds)) next-letter)))) (add-runname-mapper 'auto (lambda (target run-name area area-path reason contour mode-patt) "auto-eh")) ;; run only areas where first letter of area name is "a" ;; (add-area-checker 'first-letter-a (lambda (area target contour) (string-match "^a.*$" area))) |
Added autostuff/megatest.config version [e8ec21a182].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 | # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. ## commented out due to a bug in v1.6501 in mtutil [fields] a text b text c text [default] # usercode .mtutil.scm # areafilter area-to-run # targtrans generic-target-translator # runtrans generic-runname-translator usercode .mtutil.scm # areafilter area-to-run targtrans prefix-contour-broken # runtrans generic-runname-translator [setup] pktsdirs /mfs/home/matt/orion_automation/pkts [areas] # path-to-area map-target-script(future, optional) # someqa path=../megatestqa/someqa; targtrans=somefunc; areafilter=area-to-run # targtrans is name of scheme proc stored in .mtutil.scm, which lives in PWD where mtutil is run # the target translator can return: a/target OR (list/of targets/to apply/run) # OR #f i.e. run nothing # ext-tests path=ext-tests; targtrans=prefix-contour; ext path=/mfs/home/matt/automation_areas/megatest/ext-tests; targtrans=prefix-contour [contours] # selector=tag-expr/mode-patt quick areas=ext; selector=/QUICKPATT # quick2 areafn=check-area; selector=/QUICKPATT full areas=ext # quick areas=fullrun,ext-tests; selector=QUICKPATT/quick # full areas=fullrun,ext-tests; selector=MAXPATT/ # short areas=fullrun,ext-tests; selector=MAXPATT/ # all areas=fullrun,ext-tests # snazy selector=QUICKPATT/ [nopurpose] [access] ext matt:admin mattw:owner [accesstypes] admin run rerun resume remove set-ss rerun-clean owner run rerun resume remove rerun-all badguy set-ss [setup] maxload 1.2 [listeners] localhost:12345 contact=matt@kiatoa.com localhost:54321 contact=matt@kiatoa.com [listener] script nbfake echo [server] timeout 1 [include local.config] |
Added autostuff/runconfigs.config version [7610def712].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 | # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. # To get emacs font highlighing in the various megatest configs do this: # # Install emacs-goodies-el: # sudo apt install emacs-goodies-el # Add to your ~/.emacs file: # (add-to-list 'auto-mode-alist '("config\\'" . conf-space-mode)) # # example of a cron entry to run sync using db spec pgdb, with pgdb setting in file local.config # [a/b/c] # all:scheduled:sync cron= 0/5 * * * *;dbdest=pgdb;appendconf=/nfs/phoebe/disk1/home/mfs/matt/.sysmaint/local.config # quick:scheduled:sync cron= 0/5 * * * *;dbdest=pgdb;appendconf=/nfs/phoebe/disk1/home/mfs/matt/.sysmaint/local.config # fast:scheduled:sync-prepend cron= 0/1 * * * *;dbdest=pgdb;appendconf=/mfs/matt/.sysmaint/local.config # [scriptinc ./gentargets.sh #{getenv USER}] # [v1.23/45/67] # tip will be replaced with hashkey? # [%/%/%] doesn't work [/.*/] [v1.65/tip/dev] # file: files changes since last run trigger new run # script: script is called with unix seconds as last parameter (other parameters are preserved) # # contour:sensetype:action params data # commented out for debug quick:file:run runtrans=auto; glob=/nfs/orion/disk1/mfs_home/home/matt/automation_areas/megatest/*.scm foo.touchme # snazy:file:run runtrans=corporate-ww; glob=/home/matt/data/megatest/*.scm # short:file:run runtrans=short; glob=/home/matt/data/megatest/*.scm # script returns change-time (unix epoch), new-target-name, run-name # # quick:script:run checkfossil = http://www.kiatoa.com/fossils/megatest v1.63;\ # checkfossil = http://www.kiatoa.com/fossils/megatest_qa trunk # # fossil based trigger # # quick:fossil:run http://www.kiatoa.com/fossils/megatest=v1.65;\ http://www.kiatoa.com/fossils/megatest_qa=trunk # field allowed values # ----- -------------- # minute 0-59 # hour 0-23 # day of month 1-31 # month 1-12 (or names, future development) # day of week 0-7 (0 or 7 is Sun, or, future development, use names) # actions: # run - run a testsuite # clean - clear out runs # archive - archive runs # quick:scheduled:run cron=47 * * * * ;run-name=auto # quick:scheduled:archive cron=15 20 * * * ;run-name=%;target=%/%/% # [%] # # every friday at midnight clean "all" tests over 7d # all:scheduled:clean cron= 0 0 0 0 5;run-name=%;age=7d [v1.65/tip/dev] # # file: files changes since last run trigger new run # # script: script is called with unix seconds as last parameter (other parameters are preserved) # # # # contour:sensetype:action params data # quick:file:run run-name=auto;glob=*.scm # quick:file:clean run-name=auto; # quick:script:run run-name=auto;script=checkfossil.sh v1.63 # # # field allowed values # # ----- -------------- # # minute 0-59 # # hour 0-23 # # day of month 1-31 # # month 1-12 (or names, future development) # # day of week 0-7 (0 or 7 is Sun, or, future development, use names) # # # actions: # # run - run a testsuite # # clean - clear out runs # # archive - archive runs # quick:scheduled:run cron=47 * * * * ;run-name=auto # quick:scheduled:archive cron=15 20 * * * ;run-name=% ; # [%/%/%] # # every friday at midnight clean "all" tests over 7d all:scheduled:clean cron= 0 0 0 0 5;run-name=%;age=7d # |
Added autostuff/setup.sh version [57e9188f51].
> > | 1 2 | source /opt/chicken/4.13.0_18.04_WW45/setup-chicken4x.sh export PATH=/mfs/home/matt/orion_automation/bin:$PATH |
Deleted batchsim/Makefile version [23dda389e9].
|
| < < < < < < < < |
Deleted batchsim/batchsim.scm version [d5cdd008ec].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted batchsim/default.scm version [6d3b9494d2].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted batchsim/events.scm version [65f06322e9].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted batchsim/testing.scm version [c6005591aa].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted bin/sleeprunner version [64ce489f3b].
|
| < < < < < < < |
Deleted cgisetup/README version [c4a168dfce].
|
| < < < < < < < < < < |
Deleted cgisetup/cgi-bin/models version [39c07627cc].
|
| < |
Deleted cgisetup/cgi-bin/pages version [e2b5ed002d].
|
| < |
Deleted cgisetup/css/pjhatwal-modal.css version [3c745bf116].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted cgisetup/js/pjhatwal-modal.js version [6530096b9d].
|
| < < < < < < < < < < < < < < < |
Deleted cgisetup/megatest.config version [a123fc0679].
|
| < < < < < < < < < < < < |
Modified cgisetup/models/pgdb.scm from [d635a1d0c3] to [4136225c9c].
1 2 3 | ;;====================================================================== ;; Copyright 2017, Matthew Welland. ;; | | | > > > > > | | > > > > | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | ;;====================================================================== ;; Copyright 2017, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. ;;====================================================================== (declare (unit pgdb)) (declare (uses configf)) ;; I don't know how to mix compilation units and modules, so no module here. ;; |
︙ | ︙ | |||
88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 | exn (begin (print-call-chain) (debug:print 0 *default-log-port* "ERROR: cannot create ttype entry, " ((condition-property-accessor 'exn 'message) exn)) #f) (dbi:exec dbh "INSERT INTO ttype (target_spec) VALUES (?);" target-spec)) (pgdb:get-ttype dbh target-spec))))) ;;====================================================================== ;; R U N S ;;====================================================================== ;; given a target spec id, target and run-name return the run-id ;; if no run found return #f ;; | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | > > > > > > > | | | | | | | | | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | | | | | | 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 | exn (begin (print-call-chain) (debug:print 0 *default-log-port* "ERROR: cannot create ttype entry, " ((condition-property-accessor 'exn 'message) exn)) #f) (dbi:exec dbh "INSERT INTO ttype (target_spec) VALUES (?);" target-spec)) (pgdb:get-ttype dbh target-spec))))) ;;====================================================================== ;; T A G S ;;====================================================================== (define (pgdb:get-tag-info-by-name dbh tag) (dbi:get-one-row dbh "SELECT id,tag_name FROM tags where tag_name=?;" tag)) (define (pgdb:insert-tag dbh name ) (dbi:exec dbh "INSERT INTO tags (tag_name) VALUES (?)" name )) (define (pgdb:insert-area-tag dbh tag-id area-id ) (dbi:exec dbh "INSERT INTO area_tags (tag_id, area_id) VALUES (?,?)" tag-id area-id )) (define (pgdb:insert-run-tag dbh tag-id run-id ) (dbi:exec dbh "INSERT INTO run_tags (tag_id, run_id) VALUES (?,?)" tag-id run-id )) (define (pgdb:is-area-taged dbh area-id) (let ((area-tag-id (dbi:get-one dbh "SELECT id FROM area_tags WHERE area_id=?;" area-id))) (if area-tag-id #t #f))) (define (pgdb:is-area-taged-with-a-tag dbh tag-id area-id) (let ((area-tag-id (dbi:get-one dbh "SELECT id FROM area_tags WHERE area_id=? and tag_id=?;" area-id tag-id))) (if area-tag-id #t #f))) (define (pgdb:is-run-taged-with-a-tag dbh tag-id run-id) (let ((run-tag-id (dbi:get-one dbh "SELECT id FROM run_tags WHERE run_id=? and tag_id=?;" run-id tag-id))) (if run-tag-id #t #f))) ;;====================================================================== ;; R U N S ;;====================================================================== ;; given a target spec id, target and run-name return the run-id ;; if no run found return #f ;; (define (pgdb:get-run-id dbh spec-id target run-name area-id) (dbi:get-one dbh "SELECT id FROM runs WHERE ttype_id=? AND target=? AND run_name=? and area_id=?;" spec-id target run-name area-id)) ;; given a target spec id, target and run-name return the run-id ;; if no run found return #f ;; (define (pgdb:get-run-last-update dbh id ) (dbi:get-one dbh "SELECT last_update FROM runs WHERE id=?;" id)) ;; given a run-id return all the run info ;; (define (pgdb:get-run-info dbh run-id ) ;; to join ttype or not? (dbi:get-one-row dbh ;; 0 1 2 3 4 5 6 7 8 9 10 11 12 "SELECT id,target,ttype_id,run_name,state,status,owner,event_time,comment,fail_count,pass_count,last_update,area_id FROM runs WHERE id=? ;" run-id )) ;; refresh the data in a run record ;; (define (pgdb:refresh-run-info dbh run-id state status owner event-time comment fail-count pass-count area-id last_update publish-time) ;; area-id) (dbi:exec dbh "UPDATE runs SET state=?,status=?,owner=?,event_time=?,comment=?,fail_count=?,pass_count=?,last_update=?,publish_time=? WHERE id=? and area_id=?;" state status owner event-time comment fail-count pass-count last_update publish-time run-id area-id )) ;; given all needed info create run record ;; (define (pgdb:insert-run dbh ttype-id target run-name state status owner event-time comment fail-count pass-count area-id last-update publish-time) (dbi:exec dbh "INSERT INTO runs (ttype_id,target,run_name,state,status,owner,event_time,comment,fail_count,pass_count,area_id,last_update,publish_time) VALUES (?,?,?,?,?,?,?,?,?,?,?,?, ?);" ttype-id target run-name state status owner event-time comment fail-count pass-count area-id last-update publish-time)) ;;====================================================================== ;; T E S T - S T E P S ;;====================================================================== (define (pgdb:get-test-step-id dbh test-id stepname state) (dbi:get-one dbh "SELECT id FROM test_steps WHERE test_id=? AND stepname=? and state = ? ;" test-id stepname state)) (define (pgdb:get-test-step-last-update dbh id ) (dbi:get-one dbh "SELECT last_update FROM test_steps WHERE id=? ;" id)) (define (pgdb:insert-test-step dbh test-id stepname state status event_time comment logfile last-update ) (dbi:exec dbh "INSERT INTO test_steps (test_id,stepname,state,status,event_time,logfile,comment,last_update) VALUES (?,?,?,?,?,?,?,? );" test-id stepname state status event_time logfile comment last-update)) (define (pgdb:update-test-step dbh step-id test-id stepname state status event_time comment logfile last-update) (dbi:exec dbh "UPDATE test_steps SET test_id=?,stepname=?,state=?,status=?,event_time=?,logfile=?,comment=?,last_update=? WHERE id=?;" test-id stepname state status event_time logfile comment last-update step-id)) ;;====================================================================== ;; T E S T - D A T A ;;====================================================================== (define (pgdb:get-test-data-id dbh test-id category variable) (dbi:get-one dbh "SELECT id FROM test_data WHERE test_id=? AND category=? and variable = ? ;" test-id category variable)) (define (pgdb:get-test-data-last-update dbh test-data-id ) (dbi:get-one dbh "SELECT last_update FROM test_data WHERE id=? ;" test-data-id)) (define (pgdb:insert-test-data dbh test-id category variable value expected tol units comment status type last-update) ; (print "INSERT INTO test_data (test_id, category, variable, value, expected, tol, units, comment, status, type) ; VALUES (?,?,?,?,?,?,?,?,?,?) " test-id " " category " " variable " " value " " expected " " tol " " units " " comment " " status " " type) (if (not (string? units)) (set! units "" )) (if (not (string? variable)) (set! variable "" )) (if (not (real? value)) (set! value 0 )) (if (not (real? expected)) (set! expected 0 )) (if (not (real? tol)) (set! tol 0 )) (dbi:exec dbh "INSERT INTO test_data (test_id, category, variable, value, expected, tol, units, comment, status, type, last_update) VALUES (?,?,?,?,?,?,?,?,?,?, ?);" test-id category variable value expected tol units comment status type last-update)) (define (pgdb:update-test-data dbh data-id test-id category variable value expected tol units comment status type last-update) (dbi:exec dbh "UPDATE test_data SET test_id=?, category=?, variable=?, value=?, expected=?, tol=?, units=?, comment=?, status=?, type=?, last_update=? WHERE id=?;" test-id category variable value expected tol units comment status type last-update data-id )) ;;====================================================================== ;; T E S T S ;;====================================================================== ;; given run-id, test_name and item_path return test-id ;; (define (pgdb:get-test-id dbh run-id test-name item-path) (dbi:get-one dbh "SELECT id FROM tests WHERE run_id=? AND test_name=? AND item_path=?;" run-id test-name item-path)) (define (pgdb:get-test-last-update dbh id) (dbi:get-one dbh "SELECT last_update FROM tests WHERE id=? ;" id )) ;; create new test record ;; (define (pgdb:insert-test dbh run-id test-name item-path state status host cpuload diskfree uname run-dir log-file run-duration comment event-time archived last-update pid) (dbi:exec dbh "INSERT INTO tests (run_id,test_name,item_path,state,status,host,cpuload,diskfree,uname,rundir,final_logf,run_duration,comment,event_time,archived,last_update,attemptnum) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?);" run-id test-name item-path state status host cpuload diskfree uname run-dir log-file run-duration comment event-time archived last-update pid)) ;; update existing test record ;; (define (pgdb:update-test dbh test-id run-id test-name item-path state status host cpuload diskfree uname run-dir log-file run-duration comment event-time archived last-update pid) (dbi:exec dbh "UPDATE tests SET run_id=?,test_name=?,item_path=?,state=?,status=?,host=?,cpuload=?,diskfree=?,uname=?,rundir=?,final_logf=?,run_duration=?,comment=?,event_time=?,archived=?,last_update=?,attemptnum=? WHERE id=?;" run-id test-name item-path state status host cpuload diskfree uname run-dir log-file run-duration comment event-time archived last-update pid test-id)) (define (pgdb:get-tests dbh target-patt) (dbi:get-rows dbh "SELECT t.id,t.run_id,t.test_name,t.item_path,t.state,t.status,t.host,t.cpuload,t.diskfree,t.uname,t.rundir,t.final_logf,t.run_duration,t.comment,t.event_time,t.archived, r.id,r.target,r.ttype_id,r.run_name,r.state,r.status,r.owner,r.event_time,r.comment FROM tests AS t INNER JOIN runs AS r ON t.run_id=r.id |
︙ | ︙ |
Deleted cgisetup/pages/filter-defs-template.scm version [af1a6727be].
|
| < < < |
Deleted cgisetup/pages/home.scm version [a4707fbef0].
|
| < < < < < < < < < < < < < < < < < |
Deleted cgisetup/pages/home_ctrl.scm version [64b5eee90a].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted cgisetup/pages/home_view.scm version [f43ad9b3a3].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted cgisetup/pages/index.scm version [33603d85dd].
|
| < < < < < < < < < < < < < < < < < |
Deleted cgisetup/pages/index_ctrl.scm version [1874aaac3c].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted cgisetup/pages/index_view.scm version [5626af0f40].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted cgisetup/pages/log.scm version [b0387f7c38].
|
| < < < < < < < < < < < < < < < |
Deleted cgisetup/pages/log_ctrl.scm version [ff6468589f].
|
| < < < < < < < < < < < < < < < < < < < |
Deleted cgisetup/pages/log_view.scm version [cead0218d5].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted cgisetup/pages/run.scm version [5c8c5b7d2d].
|
| < < < < < < < < < < < < < < < |
Deleted cgisetup/pages/run_ctrl.scm version [b5550ef418].
|
| < < < < < < < < < < < < < < < < < < < < < < |
Deleted cgisetup/pages/run_view.scm version [7ccbd2143e].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted cgisetup/www/README.md version [f150458762].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted cgisetup/www/blank.html version [32bbb7ada2].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted cgisetup/www/composer.json version [05d3d25ea3].
|
| < < < < < < < < < < < < |
Deleted cgisetup/www/css/fonts/font-awesome-4.2.0/css/font-awesome.css version [6df51eee1e].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted cgisetup/www/css/fonts/font-awesome-4.2.0/css/font-awesome.min.css version [b71d1c7c31].
|
| < < < < |
Deleted cgisetup/www/css/fonts/font-awesome-4.2.0/fonts/FontAwesome.otf version [6270a4a561].
cannot compute difference between binary files
Deleted cgisetup/www/css/fonts/font-awesome-4.2.0/fonts/fontawesome-webfont.eot version [0183979056].
cannot compute difference between binary files
Deleted cgisetup/www/css/fonts/font-awesome-4.2.0/fonts/fontawesome-webfont.svg version [cd980eab6d].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted cgisetup/www/css/fonts/font-awesome-4.2.0/fonts/fontawesome-webfont.ttf version [6225ccc4ec].
cannot compute difference between binary files
Deleted cgisetup/www/css/fonts/font-awesome-4.2.0/fonts/fontawesome-webfont.woff version [7d65e0227d].
cannot compute difference between binary files
Deleted cgisetup/www/css/fonts/font-awesome-4.2.0/less/bordered-pulled.less version [0469b430cd].
|
| < < < < < < < < < < < < < < < < |
Deleted cgisetup/www/css/fonts/font-awesome-4.2.0/less/core.less version [f2cb029f6c].
|
| < < < < < < < < < < < |
Deleted cgisetup/www/css/fonts/font-awesome-4.2.0/less/fixed-width.less version [ec0c24b971].
|
| < < < < < < |
Deleted cgisetup/www/css/fonts/font-awesome-4.2.0/less/font-awesome.less version [86243ffa6d].
|
| < < < < < < < < < < < < < < < < < |
Deleted cgisetup/www/css/fonts/font-awesome-4.2.0/less/icons.less version [e844dc0672].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted cgisetup/www/css/fonts/font-awesome-4.2.0/less/larger.less version [e7119e82dc].
|
| < < < < < < < < < < < < < |
Deleted cgisetup/www/css/fonts/font-awesome-4.2.0/less/list.less version [f53bc20884].
|
| < < < < < < < < < < < < < < < < < < < |
Deleted cgisetup/www/css/fonts/font-awesome-4.2.0/less/mixins.less version [9d9ec3831c].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted cgisetup/www/css/fonts/font-awesome-4.2.0/less/path.less version [e152f9ef54].
|
| < < < < < < < < < < < < < < |
Deleted cgisetup/www/css/fonts/font-awesome-4.2.0/less/rotated-flipped.less version [95de5de900].
|
| < < < < < < < < < < < < < < < < < < < < |
Deleted cgisetup/www/css/fonts/font-awesome-4.2.0/less/spinning.less version [91c006d998].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted cgisetup/www/css/fonts/font-awesome-4.2.0/less/stacked.less version [f044077bc8].
|
| < < < < < < < < < < < < < < < < < < < < |
Deleted cgisetup/www/css/fonts/font-awesome-4.2.0/less/variables.less version [0e9208227e].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted cgisetup/www/css/fonts/font-awesome-4.2.0/scss/_bordered-pulled.scss version [e79168c54a].
|
| < < < < < < < < < < < < < < < < |
Deleted cgisetup/www/css/fonts/font-awesome-4.2.0/scss/_core.scss version [22bce64316].
|
| < < < < < < < < < < < |
Deleted cgisetup/www/css/fonts/font-awesome-4.2.0/scss/_fixed-width.scss version [224417ca26].
|
| < < < < < < |
Deleted cgisetup/www/css/fonts/font-awesome-4.2.0/scss/_icons.scss version [675189a709].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted cgisetup/www/css/fonts/font-awesome-4.2.0/scss/_larger.scss version [940e1c5ebc].
|
| < < < < < < < < < < < < < |
Deleted cgisetup/www/css/fonts/font-awesome-4.2.0/scss/_list.scss version [4b53ee0151].
|
| < < < < < < < < < < < < < < < < < < < |
Deleted cgisetup/www/css/fonts/font-awesome-4.2.0/scss/_mixins.scss version [db19fb6462].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted cgisetup/www/css/fonts/font-awesome-4.2.0/scss/_path.scss version [37bee79eab].
|
| < < < < < < < < < < < < < < |
Deleted cgisetup/www/css/fonts/font-awesome-4.2.0/scss/_rotated-flipped.scss version [ca08a0af3d].
|
| < < < < < < < < < < < < < < < < < < < < |
Deleted cgisetup/www/css/fonts/font-awesome-4.2.0/scss/_spinning.scss version [76f8e99313].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted cgisetup/www/css/fonts/font-awesome-4.2.0/scss/_stacked.scss version [cf6752ee60].
|
| < < < < < < < < < < < < < < < < < < < < |
Deleted cgisetup/www/css/fonts/font-awesome-4.2.0/scss/_variables.scss version [e7033412f3].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted cgisetup/www/css/fonts/font-awesome-4.2.0/scss/font-awesome.scss version [ed5ff46ea1].
|
| < < < < < < < < < < < < < < < < < |
Deleted cgisetup/www/css/img/breadcrumbs-bg.gif version [bdf5e25f21].
cannot compute difference between binary files
Deleted cgisetup/www/css/img/bx_loader.gif version [f67f91dafb].
cannot compute difference between binary files
Deleted cgisetup/www/css/img/controls.png version [c4f03d55c3].
cannot compute difference between binary files
Deleted cgisetup/www/css/img/fancybox/blank.gif version [2daeaa8b5f].
cannot compute difference between binary files
Deleted cgisetup/www/css/img/fancybox/fancy_close.png version [c3820930a8].
cannot compute difference between binary files
Deleted cgisetup/www/css/img/fancybox/fancy_loading.png version [c886c8e7fe].
cannot compute difference between binary files
Deleted cgisetup/www/css/img/fancybox/fancy_nav_left.png version [ee2f10fd29].
cannot compute difference between binary files
Deleted cgisetup/www/css/img/fancybox/fancy_nav_right.png version [7e98862c83].
cannot compute difference between binary files
Deleted cgisetup/www/css/img/fancybox/fancy_shadow_e.png version [9e0d596aa8].
cannot compute difference between binary files
Deleted cgisetup/www/css/img/fancybox/fancy_shadow_n.png version [42072ce3da].
cannot compute difference between binary files
Deleted cgisetup/www/css/img/fancybox/fancy_shadow_ne.png version [6d0c5b39ec].
cannot compute difference between binary files
Deleted cgisetup/www/css/img/fancybox/fancy_shadow_nw.png version [538f9a618a].
cannot compute difference between binary files
Deleted cgisetup/www/css/img/fancybox/fancy_shadow_s.png version [94d572b926].
cannot compute difference between binary files
Deleted cgisetup/www/css/img/fancybox/fancy_shadow_se.png version [0fe4def317].
cannot compute difference between binary files
Deleted cgisetup/www/css/img/fancybox/fancy_shadow_sw.png version [d0fa9d3f00].
cannot compute difference between binary files
Deleted cgisetup/www/css/img/fancybox/fancy_shadow_w.png version [f575d4486f].
cannot compute difference between binary files
Deleted cgisetup/www/css/img/fancybox/fancy_title_left.png version [54a0262138].
cannot compute difference between binary files
Deleted cgisetup/www/css/img/fancybox/fancy_title_main.png version [61975d1e8e].
cannot compute difference between binary files
Deleted cgisetup/www/css/img/fancybox/fancy_title_over.png version [78554e1809].
cannot compute difference between binary files
Deleted cgisetup/www/css/img/fancybox/fancy_title_right.png version [1c629202bb].
cannot compute difference between binary files
Deleted cgisetup/www/css/img/fancybox/fancybox-x.png version [9f8e00974d].
cannot compute difference between binary files
Deleted cgisetup/www/css/img/fancybox/fancybox-y.png version [0bf85f7799].
cannot compute difference between binary files
Deleted cgisetup/www/css/img/fancybox/fancybox.png version [bbf3f5bb2d].
cannot compute difference between binary files
Deleted cgisetup/www/css/img/fancybox/jquery.easing-1.3.pack.js version [55d99c8d1e].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted cgisetup/www/css/img/fancybox/jquery.fancybox-1.3.4.js version [7fb5ce8859].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted cgisetup/www/css/img/fancybox/jquery.fancybox-1.3.4.pack.js version [caeb31e930].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted cgisetup/www/css/img/fancybox/jquery.mousewheel-3.0.4.pack.js version [2db79bca5a].
|
| < < < < < < < < < < < < < < |
Deleted cgisetup/www/css/img/gray_jean.png version [7e5e6e302e].
cannot compute difference between binary files
Deleted cgisetup/www/css/img/icon-arrow-right.png version [3600461210].
cannot compute difference between binary files
Deleted cgisetup/www/css/jquery.fancybox-1.3.4.css version [8c8c11bef0].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted cgisetup/www/css/kickstart-buttons.css version [e2d8321fb5].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted cgisetup/www/css/kickstart-forms.css version [85b959c9d4].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted cgisetup/www/css/kickstart-grid.css version [e5abe87353].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted cgisetup/www/css/kickstart-menus.css version [f5980cf54e].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted cgisetup/www/css/kickstart-slideshow.css version [1991bc5ae2].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted cgisetup/www/css/kickstart.css version [b51fcdc518].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted cgisetup/www/css/prettify.css version [560d42dae0].
|
| < |
Deleted cgisetup/www/css/tiptip.css version [813766adb8].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted cgisetup/www/elements.html version [98bd52054e].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted cgisetup/www/example.html version [88ce3abf36].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted cgisetup/www/index.html version [c7620206b2].
|
| < < < < < < |
Deleted cgisetup/www/js/kickstart.js version [1efaf03ce2].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted cgisetup/www/license.txt version [e920630381].
|
| < < < < < < < |
Deleted cgisetup/www/style.css version [a5a2555e79].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Modified client.scm from [950fa4a4a2] to [9da8d7475d].
1 2 3 | ;; Copyright 2006-2012, Matthew Welland. ;; | | | > > > > > | | > | > > < | | < < < < | | | > | > | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 | ;; Copyright 2006-2012, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. ;;====================================================================== ;; C L I E N T S ;;====================================================================== (use srfi-18 extras tcp s11n srfi-1 posix regex srfi-69 hostinfo md5 message-digest matchable spiffy uri-common intarweb http-client spiffy-request-vars uri-common intarweb directory-utils) (declare (unit client)) (declare (uses common)) (declare (uses db)) (declare (uses tasks)) ;; tasks are where stuff is maintained about what is running. (include "common_records.scm") (include "db_records.scm") ;; client:get-signature (define (client:get-signature) (if *my-client-signature* *my-client-signature* (let ((sig (conc (get-host-name) " " (current-process-id)))) (set! *my-client-signature* sig) *my-client-signature*))) ;; Not currently used! But, I think it *should* be used!!! #;(define (client:logout serverdat) (let ((ok (and (socket? serverdat) (cdb:logout serverdat *toppath* (client:get-signature))))) ok)) #;(define (client:connect iface port) (http-transport:client-connect iface port) #;(case (server:get-transport) ((rpc) (rpc:client-connect iface port)) ((http) (http:client-connect iface port)) ((zmq) (zmq:client-connect iface port)) (else (rpc:client-connect iface port)))) (define (client:setup areapath #!key (remaining-tries 100) (failed-connects 0)) (client:setup-http areapath remaining-tries: remaining-tries failed-connects: failed-connects) #;(case (server:get-transport) ((rpc) (rpc-transport:client-setup remaining-tries: remaining-tries failed-connects: failed-connects)) ;;(client:setup-rpc run-id)) ((http)(client:setup-http areapath remaining-tries: remaining-tries failed-connects: failed-connects)) (else (rpc-transport:client-setup remaining-tries: remaining-tries failed-connects: failed-connects)))) ;; (client:setup-rpc run-id)))) ;; Do all the connection work, look up the transport type and set up the ;; connection if required. ;; |
︙ | ︙ | |||
98 99 100 101 102 103 104 | (if (and start-res ping-res) (let ((runremote (or area-dat *runremote*))) ;; it might have been generated only a few statements ago (remote-conndat-set! runremote start-res) ;; (hash-table-set! runremote run-id start-res) (debug:print-info 2 *default-log-port* "connected to " (http-transport:server-dat-make-url start-res)) start-res) (begin ;; login failed but have a server record, clean out the record and try again | | | 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 | (if (and start-res ping-res) (let ((runremote (or area-dat *runremote*))) ;; it might have been generated only a few statements ago (remote-conndat-set! runremote start-res) ;; (hash-table-set! runremote run-id start-res) (debug:print-info 2 *default-log-port* "connected to " (http-transport:server-dat-make-url start-res)) start-res) (begin ;; login failed but have a server record, clean out the record and try again (debug:print-info 0 *default-log-port* "client:setup, login unsuccessful, will attempt to start server ... start-res=" start-res ", server-dat=" server-dat) ;; had runid. Fixes part of Randy;s ticket 1405717332 (case *transport-type* ((http)(http-transport:close-connections))) (remote-conndat-set! runremote #f) ;; (hash-table-delete! runremote run-id) (thread-sleep! 1) (client:setup-http areapath remaining-tries: (- remaining-tries 1)) ))) (begin ;; no server registered ;; (server:kind-run areapath) (server:start-and-wait areapath) (debug:print-info 0 *default-log-port* "client:setup, no server registered, remaining-tries=" remaining-tries) (thread-sleep! 1) ;; (+ 5 (random (- 20 remaining-tries)))) ;; give server a little time to start up, randomize a little to avoid start storms. (client:setup-http areapath remaining-tries: (- remaining-tries 1))))))))) |
Added codescanlib.scm version [6e625610ce].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 | ;; Copyright 2006-2017, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. ;; ;; gotta compile with csc, doesn't work with csi -s for whatever reason (use srfi-69) (use matchable) (use utils) (use ports) (use extras) (use srfi-1) (use posix) (use srfi-12) ;; turn scheme file to a list of sexps, sexps of interest will be in the form of (define (<procname> <args>) <body> ) (define (load-scm-file scm-file) ;;(print "load "scm-file) (handle-exceptions exn '() (with-input-from-string (conc "(" (with-input-from-file scm-file read-all) ")" ) read))) ;; extract a list of procname, filename, args and body of procedures defined in filename, input from load-scm-file ;; -- be advised: ;; * this may be fooled by macros, since this code does not take them into account. ;; * this code does only checks for form (define (<procname> ... ) <body>) ;; so it excludes from reckoning ;; - generated functions, as in things like foo-set! from defstructs, ;; - define-inline, ( ;; - define procname (lambda .. ;; - etc... (define (get-toplevel-procs+file+args+body filename) (let* ((scm-tree (load-scm-file filename)) (procs (filter identity (map (match-lambda [('define ('uses args ...) body ...) #f] ;; filter out (define (uses ... [('define ('unit args ...) body ...) #f] ;; filter out (define (unit ... [('define ('prefix args ...) body ...) #f] ;; filter out (define (prefix ... [('define (defname args ...) body ...) ;; match (define (procname <args>) <body>) (if (atom? defname) ;; filter out things we dont understand (procname is a list, what??) (list defname filename args body) #f)] [else #f] ) scm-tree)))) procs)) ;; given a sexp, return a flat list of atoms in that sexp (define (get-atoms-in-body body) (cond ((null? body) '()) ((atom? body) (list body)) (else (apply append (map get-atoms-in-body body))))) ;; given a file, return a list of procname, file, list of atoms in said procname (define (get-procs+file+atoms file) (let* ((toplevel-proc-items (get-toplevel-procs+file+args+body file)) (res (map (lambda (item) (let* ((proc (car item)) (file (cadr item)) (args (caddr item)) (body (cadddr item)) (atoms (append (get-atoms-in-body args) (get-atoms-in-body body)))) (list proc file atoms))) toplevel-proc-items))) res)) ;; uniquify a list of atoms (define (unique-atoms lst) (let loop ((lst (flatten lst)) (res '())) (if (null? lst) (reverse res) (let ((c (car lst))) (loop (cdr lst) (if (member c res) res (cons c res))))))) ;; given a list of procname, filename, list of procs called from procname, cross reference and reverse ;; returning alist mapping procname to procname that calls said procname (define (get-callers-alist all-procs+file+calls) (let* ((all-procs (map car all-procs+file+calls)) (caller-ht (make-hash-table))) ;; let's cross reference with a hash table (for-each (lambda (proc) (hash-table-set! caller-ht proc '())) all-procs) (for-each (lambda (item) (let* ((proc (car item)) (file (cadr item)) (calls (caddr item))) (for-each (lambda (callee) (hash-table-set! caller-ht callee (cons proc (hash-table-ref caller-ht callee)))) calls))) all-procs+file+calls) (map (lambda (x) (let ((k (car x)) (r (unique-atoms (cdr x)))) (cons k r))) (hash-table->alist caller-ht)))) ;; create a handy cross-reference of callees to callers in the form of an alist. (define (get-xref all-scm-files) (let* ((all-procs+file+atoms (apply append (map get-procs+file+atoms all-scm-files))) (all-procs (map car all-procs+file+atoms)) (all-procs+file+calls ; proc calls things in calls list (map (lambda (item) (let* ((proc (car item)) (file (cadr item)) (atoms (caddr item)) (calls (filter identity (map (lambda (x) (if (and ;; (not (equal? x proc)) ;; uncomment to prevent listing self (member x all-procs)) x #f)) atoms)))) (list proc file calls))) all-procs+file+atoms)) (callers (get-callers-alist all-procs+file+calls))) callers)) |
Modified common.scm from [675cf742a5] to [5ca9ccb479].
1 2 3 | ;;====================================================================== ;; Copyright 2006-2012, Matthew Welland. ;; | | | > > > > > | | > > > > | > > | | < | < < | | | > | > > > > > > > > > > > > > > > > > > > | | > > > > > > > > > > > | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 | ;;====================================================================== ;; Copyright 2006-2012, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. ;;====================================================================== (use srfi-1 data-structures posix regex-case (prefix base64 base64:) format dot-locking csv-xml z3 udp ;; sql-de-lite hostinfo md5 message-digest typed-records directory-utils stack matchable regex posix (srfi 18) extras ;; tcp (prefix nanomsg nmsg:) (prefix sqlite3 sqlite3:) pkts (prefix dbi dbi:) ) (declare (unit common)) (declare (uses commonmod)) (import commonmod) (include "common_records.scm") ;; (require-library margs) ;; (include "margs.scm") ;; (define old-exit exit) ;; ;; (define (exit . code) ;; (if (null? code) ;; (old-exit) ;; (old-exit code))) ;; execute thunk, return value. If exception thrown, trap exception, return #f, and emit nonfatal condition note to *default-log-port* . ;; arguments - thunk, message (define (common:fail-safe thunk warning-message-on-exception) (handle-exceptions exn (begin (debug:print-info 0 *default-log-port* "notable but nonfatal condition - "warning-message-on-exception) (debug:print-info 0 *default-log-port* (string-substitute "\n?Error:" "nonfatal condition:" (with-output-to-string (lambda () (print-error-message exn) )))) (debug:print-info 0 *default-log-port* " -- continuing after nonfatal condition...") #f) (thunk))) (define getenv get-environment-variable) (define (safe-setenv key val) (if (or (substring-index "!" key) (substring-index ":" key)) ;; variables containing : are for internal use and cannot be environment variables. (debug:print-error 4 *default-log-port* "skip setting internal use only variables containing \":\" or starting with \"!\"") (if (and (string? val) (string? key)) (handle-exceptions exn (debug:print-error 0 *default-log-port* "bad value for setenv, key=" key ", value=" val) (setenv key val)) (debug:print-error 0 *default-log-port* "bad value for setenv, key=" key ", value=" val)))) (define home (getenv "HOME")) (define user (getenv "USER")) ;; returns list of fd count, socket count (define (get-file-descriptor-count #!key (pid (current-process-id ))) (list (length (glob (conc "/proc/" pid "/fd/*"))) (length (filter identity (map socket? (glob (conc "/proc/" pid "/fd/*"))))) ) ) ;; GLOBALS ;; CONTEXTS (defstruct cxt (taskdb #f) (cmutex (make-mutex))) ;; (define *contexts* (make-hash-table)) ;; (define *context-mutex* (make-mutex)) |
︙ | ︙ | |||
74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 | ;; A hash table that can be accessed by #{scheme ...} calls in ;; config files. Allows communicating between confgs ;; (define *user-hash-data* (make-hash-table)) (define *db-keys* #f) (define *configinfo* #f) ;; raw results from setup, includes toppath and table from megatest.config (define *runconfigdat* #f) ;; run configs data (define *configdat* #f) ;; megatest.config data (define *configstatus* #f) ;; status of data; 'fulldata : all processing done, #f : no data yet, 'partialdata : partial read done (define *toppath* #f) (define *already-seen-runconfig-info* #f) (define *test-meta-updated* (make-hash-table)) (define *globalexitstatus* 0) ;; attempt to work around possible thread issues (define *passnum* 0) ;; when running track calls to run-tests or similar ;; (define *alt-log-file* #f) ;; used by -log (define *common:denoise* (make-hash-table)) ;; for low noise printing (define *default-log-port* (current-error-port)) (define *time-zero* (current-seconds)) ;; for the watchdog ;; DATABASE (define *dbstruct-db* #f) ;; used to cache the dbstruct in db:setup. Goal is to remove this. ;; db stats (define *db-stats* (make-hash-table)) ;; hash of vectors < count duration-total > (define *db-stats-mutex* (make-mutex)) ;; db access | > > | 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 | ;; A hash table that can be accessed by #{scheme ...} calls in ;; config files. Allows communicating between confgs ;; (define *user-hash-data* (make-hash-table)) (define *db-keys* #f) (define *pkts-info* (make-hash-table)) ;; store stuff like the last parent here (define *configinfo* #f) ;; raw results from setup, includes toppath and table from megatest.config (define *runconfigdat* #f) ;; run configs data (define *configdat* #f) ;; megatest.config data (define *configstatus* #f) ;; status of data; 'fulldata : all processing done, #f : no data yet, 'partialdata : partial read done (define *toppath* #f) (define *already-seen-runconfig-info* #f) (define *test-meta-updated* (make-hash-table)) (define *globalexitstatus* 0) ;; attempt to work around possible thread issues (define *passnum* 0) ;; when running track calls to run-tests or similar ;; (define *alt-log-file* #f) ;; used by -log (define *common:denoise* (make-hash-table)) ;; for low noise printing (define *default-log-port* (current-error-port)) (define *time-zero* (current-seconds)) ;; for the watchdog (define *default-area-tag* "local") ;; DATABASE (define *dbstruct-db* #f) ;; used to cache the dbstruct in db:setup. Goal is to remove this. ;; db stats (define *db-stats* (make-hash-table)) ;; hash of vectors < count duration-total > (define *db-stats-mutex* (make-mutex)) ;; db access |
︙ | ︙ | |||
109 110 111 112 113 114 115 116 117 118 119 120 121 122 | (define *task-db* #f) ;; (vector db path-to-db) (define *db-access-allowed* #t) ;; flag to allow access (define *db-access-mutex* (make-mutex)) (define *db-transaction-mutex* (make-mutex)) (define *db-cache-path* #f) (define *db-with-db-mutex* (make-mutex)) (define *db-api-call-time* (make-hash-table)) ;; hash of command => (list of times) ;; SERVER (define *my-client-signature* #f) (define *transport-type* 'http) ;; override with [server] transport http|rpc|nmsg (define *runremote* #f) ;; if set up for server communication this will hold <host port> ;; (define *max-cache-size* 0) (define *logged-in-clients* (make-hash-table)) | > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 | (define *task-db* #f) ;; (vector db path-to-db) (define *db-access-allowed* #t) ;; flag to allow access (define *db-access-mutex* (make-mutex)) (define *db-transaction-mutex* (make-mutex)) (define *db-cache-path* #f) (define *db-with-db-mutex* (make-mutex)) (define *db-api-call-time* (make-hash-table)) ;; hash of command => (list of times) ;; no sync db (define *no-sync-db* #f) ;; SERVER (define *my-client-signature* #f) (define *transport-type* 'http) ;; override with [server] transport http|rpc|nmsg (define *runremote* #f) ;; if set up for server communication this will hold <host port> ;; (define *max-cache-size* 0) (define *logged-in-clients* (make-hash-table)) (define *server-id* #f) (define *server-info* #f) ;; good candidate for easily convert to non-global (define *time-to-exit* #f) (define *server-run* #t) (define *run-id* #f) (define *server-kind-run* (make-hash-table)) (define *home-host* #f) ;; (define *total-non-write-delay* 0) (define *heartbeat-mutex* (make-mutex)) (define *api-process-request-count* 0) (define *max-api-process-requests* 0) (define *server-overloaded* #f) ;; client (define *rmt-mutex* (make-mutex)) ;; remote access calls mutex ;; RPC transport (define *rpc:listener* #f) ;; KEY info (define *target* (make-hash-table)) ;; cache the target here; target is keyval1/keyval2/.../keyvalN (define *keys* (make-hash-table)) ;; cache the keys here (define *keyvals* (make-hash-table)) (define *toptest-paths* (make-hash-table)) ;; cache toptest path settings here (define *test-paths* (make-hash-table)) ;; cache test-id to test run paths here (define *test-ids* (make-hash-table)) ;; cache run-id, testname, and item-path => test-id (define *test-info* (make-hash-table)) ;; cache the test info records, update the state, status, run_duration etc. from testdat.db (define *run-info-cache* (make-hash-table)) ;; run info is stable, no need to reget (define *launch-setup-mutex* (make-mutex)) ;; need to be able to call launch:setup often so mutex it and re-call the real deal only if *toppath* not set (define *homehost-mutex* (make-mutex)) ;; Miscellaneous (define *triggers-mutex* (make-mutex)) ;; block overlapping processing of triggers (use posix-extras pathname-expand files) ;; this plugs a hole in posix-extras in recent chicken versions > 4.9) (let-values (( (chicken-release-number chicken-major-version) (apply values (map string->number (take (string-split (chicken-version) ".") 2))))) (let ((resolve-pathname-broken? (or (> chicken-release-number 4) (and (eq? 4 chicken-release-number) (> chicken-major-version 9))))) (if resolve-pathname-broken? (define ##sys#expand-home-path pathname-expand)))) (define (realpath x) (resolve-pathname (pathname-expand (or x "/dev/null")) )) (define (common:get-this-exe-fullpath #!key (argv (argv))) (let* ((this-script (cond ((and (> (length argv) 2) (string-match "^(.*/csi|csi)$" (car argv)) (string-match "^-(s|ss|sx|script)$" (cadr argv))) (caddr argv)) (else (car argv)))) (fullpath (realpath this-script))) fullpath)) (define *common:this-exe-fullpath* (common:get-this-exe-fullpath)) (define *common:this-exe-dir* (pathname-directory *common:this-exe-fullpath*)) (define *common:this-exe-name* (pathname-strip-directory *common:this-exe-fullpath*)) (define *common:logpro-exit-code->status-sym-alist* '( ( 0 . pass ) ( 1 . fail ) ( 2 . warn ) ( 3 . check ) ( 4 . waived ) ( 5 . abort ) ( 6 . skip ))) (define (common:logpro-exit-code->status-sym exit-code) (or (alist-ref exit-code *common:logpro-exit-code->status-sym-alist*) 'fail)) (define (common:worse-status-sym ss1 ss2) (let loop ((status-syms-remaining '(abort fail check skip warn waived pass))) (cond ((null? status-syms-remaining) 'fail) ((eq? (car status-syms-remaining) ss1) ss1) ((eq? (car status-syms-remaining) ss2) ss2) (else (loop (cdr status-syms-remaining)))))) (define (common:steps-can-proceed-given-status-sym status-sym) (if (member status-sym '(warn waived pass)) #t #f)) (define (status-sym->string status-sym) (case status-sym ((pass) "PASS") ((fail) "FAIL") ((warn) "WARN") ((check) "CHECK") ((waived) "WAIVED") ((abort) "ABORT") ((skip) "SKIP") (else "FAIL"))) (define (common:logpro-exit-code->test-status exit-code) (status-sym->string (common:logpro-exit-code->status-sym exit-code))) (defstruct remote (hh-dat (common:get-homehost)) ;; homehost record ( addr . hhflag ) (server-url (if *toppath* (server:check-if-running *toppath*))) ;; (server:check-if-running *toppath*) #f)) (last-server-check 0) ;; last time we checked to see if the server was alive (conndat #f) (transport *transport-type*) (server-timeout (server:expiration-timeout)) (force-server #f) (ro-mode #f) (ro-mode-checked #f)) ;; flag that indicates we have checked for ro-mode ;; launching and hosts (defstruct host (reachable #f) |
︙ | ︙ | |||
223 224 225 226 227 228 229 230 231 | (define (common:get-last-run-version-number) (string->number (substring (common:get-last-run-version) 0 6))) (define (common:set-last-run-version) (rmt:set-var "MEGATEST_VERSION" (common:version-signature))) (define (common:version-changed?) (not (equal? (common:get-last-run-version) | > > > > > | > > > > > > > > > > | | > < | > > | > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | | | > | > > > | | > > | | | | | | | | | | > > | | > > > > | | | | > > > > > | > > | | > > > > > > > > > > > > > > > > > > > > > > > | | | | | | | | | | | | 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 | (define (common:get-last-run-version-number) (string->number (substring (common:get-last-run-version) 0 6))) (define (common:set-last-run-version) (rmt:set-var "MEGATEST_VERSION" (common:version-signature))) ;; postive number if megatest version > db version ;; negative number if megatest version < db version (define (common:version-db-delta) (- megatest-version (common:get-last-run-version-number))) (define (common:version-changed?) (not (equal? (common:get-last-run-version) (common:version-signature)))) (define (common:api-changed?) (not (equal? (substring (->string megatest-version) 0 4) (substring (conc (common:get-last-run-version)) 0 4)))) (define (common:get-sync-lock-filepath) (let* ((tmp-area (common:get-db-tmp-area)) (lockfile (conc tmp-area "/megatest.db.sync-lock"))) lockfile)) ;; Move me elsewhere ... ;; RADT => Why do we meed the version check here, this is called only if version misma ;; (define (common:cleanup-db dbstruct #!key (full #f)) (apply db:multi-db-sync dbstruct 'schema ;; 'new2old 'killservers 'adj-target ;; 'old2new 'new2old ;; (if full '(dejunk) ;; '()) ) (if (common:api-changed?) (common:set-last-run-version))) (define (common:snapshot-file filepath #!key (subdir ".") ) (if (file-exists? filepath) (let* ((age-sec (lambda (file) (if (file-exists? file) (- (current-seconds) (file-modification-time file)) 1000000000))) ;; return really old value if file doesn't exist. we want to clobber it if old or not exist. (ok-flag #t) (age-mins (lambda (file) (/ (age-sec file) 60))) (age-hrs (lambda (file) (/ (age-mins file) 60))) (age-days (lambda (file) (/ (age-hrs file) 24))) (age-wks (lambda (file) (/ (age-days file) 7))) (docmd (lambda (cmd) (cond (ok-flag (let ((res (system cmd))) (cond ((eq? 0 res) #t) (else (set! ok-flag #f) (debug:print 0 *default-log-port* "ERROR: ["(common:human-time)"] Command failed with exit code " (if (< res 0) res (/ res 8)) " ["cmd"]" ) #f)))) (else (debug:print 0 *default-log-port* "ERROR: ["(common:human-time)"] Not runnining command due to prior error. ["cmd"]") #f)))) (copy (lambda (src dest) (docmd (conc "/bin/cp '"src"' '"dest"'")))) (copy+zip (lambda (src dest) (docmd (conc "gzip -c - < '"src"' > '"dest"'")))) (fullpath (realpath filepath)) (basedir (pathname-directory fullpath)) (basefile (pathname-strip-directory fullpath)) ;;(prevfile (conc filepath ".prev.gz")) (minsfile (conc basedir "/" subdir "/" basefile ".mins.gz")) (hrsfile (conc basedir "/" subdir "/" basefile ".hrs.gz")) (daysfile (conc basedir "/" subdir "/" basefile ".days.gz")) (wksfile (conc basedir "/" subdir "/" basefile ".weeks.gz"))) ;; create subdir it not exists (if (not (directory-exists? (conc basedir "/" subdir))) (docmd (conc "/bin/mkdir -p '"(conc basedir "/" subdir)"'"))) ;; copy&zip <file> to <file>.mins if not exists (if (not (file-exists? minsfile)) (copy+zip filepath minsfile)) ;; copy <file>.mins to <file>.hrs if not exists (if (not (file-exists? hrsfile)) (copy minsfile hrsfile)) ;; copy <file>.hrs to <file>.days if not exists (if (not (file-exists? daysfile)) (copy hrsfile daysfile)) ;; copy <file>.days to <file>.weeks if not exists (if (not (file-exists? wksfile)) (copy daysfile wksfile)) ;; if age(<file>.mins.gz) >= 1h: ;; copy <file>.mins.gz <file>.hrs.gz ;; copy <prev file> <file>.mins.gz (when (>= (age-mins minsfile) 1) (copy minsfile hrsfile) (copy+zip filepath minsfile)) ;; if age(<file>.hrs.gz) >= 1d: ;; copy <file>.hrs.gz <file>.days.gz ;; copy <file>.mins.gz <file>.hrs.gz (when (>= (age-days hrsfile) 1) (copy hrsfile daysfile) (copy minsfile hrsfile)) ;; if age(<file>.days.gz) >= 1w: ;; copy <file>.days.gz <file>.weeks.gz ;; copy <file>.hrs.gz <file>.days.gz (when (>= (age-wks daysfile) 1) (copy daysfile wksfile) (copy hrsfile daysfile)) #t) #f)) ;; Rotate logs, logic: ;; if > 500k and older than 1 week: ;; remove previous compressed log and compress this log ;; WARNING: This proc operates assuming that it is in the directory above the ;; logs directory you wish to log-rotate. ;; (define (common:rotate-logs) (let* ((all-files (make-hash-table)) (stats (make-hash-table)) (inc-stat (lambda (key) (hash-table-set! stats key (+ (hash-table-ref/default stats key 0) 1)))) (max-allowed (string->number (or (configf:lookup *configdat* "setup" "max-logfiles") "300")))) ;; name -> age (if (not (directory-exists? "logs"))(create-directory "logs")) (directory-fold (lambda (file rem) (handle-exceptions exn (begin (debug:print-info 2 *default-log-port* "unable to rotate log " file ", probably handled by another process, this is safe to ignore.") (debug:print 2 *default-log-port* " message: " ((condition-property-accessor 'exn 'message) exn)) ;; (print-call-chain (current-error-port)) ;; ) (let* ((fullname (conc "logs/" file)) (mod-time (file-modification-time fullname)) (file-age (- (current-seconds) mod-time))) (hash-table-set! all-files file mod-time) (if (or (and (string-match "^.*.log" file) (> (file-size fullname) 200000)) (and (string-match "^server-.*.log" file) (> (- (current-seconds) (file-modification-time fullname)) (* 8 60 60)))) (let ((gzfile (conc fullname ".gz"))) (if (common:file-exists? gzfile) (begin (debug:print-info 0 *default-log-port* "removing " gzfile) (delete-file* gzfile) (hash-table-delete! all-files gzfile) ;; needed? )) (debug:print-info 0 *default-log-port* "compressing " file) (system (conc "gzip " fullname)) (inc-stat "gzipped") (hash-table-set! all-files (conc file ".gz") file-age) ;; add the .gz file and remove the base file (hash-table-delete! all-files file) ) (if (> file-age (* (string->number (or (configf:lookup *configdat* "setup" "log-expire-days") "30")) 24 3600)) (handle-exceptions exn #f (if (directory? fullname) (begin (debug:print-error 0 *default-log-port* fullname " in logs directory is a directory! Cannot rotate it, it is best to not put subdirectories in the logs dir.") (inc-stat "directories")) (begin (delete-file* fullname) (inc-stat "deleted"))) (hash-table-delete! all-files file))))))) '() "logs") (for-each (lambda (category) (let ((quant (hash-table-ref/default stats category 0))) (if (> quant 0) (debug:print-info 0 *default-log-port* category " log files: " quant)))) `("deleted" "gzipped" "directories")) (let ((num-logs (hash-table-size all-files))) (if (> num-logs max-allowed) ;; because NFS => don't let number of logs exceed 300 (let ((files (take (sort (hash-table-keys all-files) (lambda (a b) (< (hash-table-ref all-files a)(hash-table-ref all-files b)))) (- num-logs max-allowed)))) (for-each (lambda (file) (let* ((fullname (conc "logs/" file))) (if (directory? fullname) (debug:print-error 0 *default-log-port* fullname " in logs directory is a directory! Cannot rotate it, it is best to not put subdirectories in the logs dir.") (handle-exceptions exn (debug:print-error 0 *default-log-port* "failed to remove " fullname) (delete-file* fullname))))) files) (debug:print-info 0 *default-log-port* "Deleted " (length files) " files from logs, keeping " max-allowed " files.")))))) ;; Force a megatest cleanup-db if version is changed and skip-version-check not specified ;; Do NOT check if not on homehost! ;; (define (common:exit-on-version-changed) (if (common:on-homehost?) (if (common:api-changed?) (let* ((mtconf (conc (get-environment-variable "MT_RUN_AREA_HOME") "/megatest.config")) (dbfile (conc (get-environment-variable "MT_RUN_AREA_HOME") "/megatest.db")) (read-only (not (file-write-access? dbfile))) (dbstruct (db:setup #t))) (debug:print 0 *default-log-port* "WARNING: Version mismatch!\n" " expected: " (common:version-signature) "\n" " got: " (common:get-last-run-version)) (cond ((get-environment-variable "MT_SKIP_DB_MIGRATE") #t) ((and (common:file-exists? mtconf) (common:file-exists? dbfile) (not read-only) (eq? (current-user-id)(file-owner mtconf))) ;; safe to run -cleanup-db (debug:print 0 *default-log-port* " I see you are the owner of megatest.config, attempting to cleanup and reset to new version") (handle-exceptions exn (begin (debug:print 0 *default-log-port* "Failed to switch versions.") (debug:print 0 *default-log-port* " message: " ((condition-property-accessor 'exn 'message) exn)) (print-call-chain (current-error-port)) (exit 1)) (common:cleanup-db dbstruct))) ((not (common:file-exists? mtconf)) (debug:print 0 *default-log-port* " megatest.config does not exist in this area. Cannot proceed with megatest version migration.") (exit 1)) ((not (common:file-exists? dbfile)) (debug:print 0 *default-log-port* " megatest.db does not exist in this area. Cannot proceed with megatest version migration.") (exit 1)) ((not (eq? (current-user-id)(file-owner mtconf))) (debug:print 0 *default-log-port* " You do not own megatest.db in this area. Cannot proceed with megatest version migration.") (exit 1)) (read-only (debug:print 0 *default-log-port* " You have read-only access to this area. Cannot proceed with megatest version migration.") (exit 1)) (else (debug:print 0 *default-log-port* " to switch versions you can run: \"megatest -cleanup-db\"") (exit 1))))))) ;; (begin ;; (debug:print 0 *default-log-port* "ERROR: cannot migrate version unless on homehost. Exiting.") ;; (exit 1)))) ;;====================================================================== ;; S P A R S E A R R A Y S ;;====================================================================== (define (make-sparse-array) (let ((a (make-sparse-vector))) |
︙ | ︙ | |||
388 389 390 391 392 393 394 395 396 397 398 399 400 401 | (common:to-alist (cdr dat)))) ((hash-table? dat) (map common:to-alist (hash-table->alist dat))) (else (if dat dat "")))) (define (common:low-noise-print waitval . keys) (let* ((key (string-intersperse (map conc keys) "-" )) (lasttime (hash-table-ref/default *common:denoise* key 0)) (currtime (current-seconds))) (if (> (- currtime lasttime) waitval) (begin | > > > | 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 | (common:to-alist (cdr dat)))) ((hash-table? dat) (map common:to-alist (hash-table->alist dat))) (else (if dat dat "")))) (define (common:alist-ref/default key alist default) (or (alist-ref key alist) default)) (define (common:low-noise-print waitval . keys) (let* ((key (string-intersperse (map conc keys) "-" )) (lasttime (hash-table-ref/default *common:denoise* key 0)) (currtime (current-seconds))) (if (> (- currtime lasttime) waitval) (begin |
︙ | ︙ | |||
419 420 421 422 423 424 425 | (read (open-input-string (z3:decode-buffer (base64:base64-decode instr)))))) ;; dot-locking egg seems not to work, using this for now ;; if lock is older than expire-time then remove it and try again ;; to get the lock ;; (define (common:simple-file-lock fname #!key (expire-time 300)) | | | | > | | | | > > | | | | 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 | (read (open-input-string (z3:decode-buffer (base64:base64-decode instr)))))) ;; dot-locking egg seems not to work, using this for now ;; if lock is older than expire-time then remove it and try again ;; to get the lock ;; (define (common:simple-file-lock fname #!key (expire-time 300)) (let ((fmod-time (handle-exceptions ext (current-seconds) (file-modification-time fname)))) (if (common:file-exists? fname) (if (> (- (current-seconds) fmod-time) expire-time) (begin (handle-exceptions exn #f (delete-file* fname)) (common:simple-file-lock fname expire-time: expire-time)) #f) (let ((key-string (conc (get-host-name) "-" (current-process-id)))) (with-output-to-file fname (lambda () (print key-string))) (thread-sleep! 0.25) (if (common:file-exists? fname) (handle-exceptions exn #f (with-input-from-file fname (lambda () (equal? key-string (read-line))))) #f))))) (define (common:simple-file-lock-and-wait fname #!key (expire-time 300)) (let ((end-time (+ expire-time (current-seconds)))) (let loop ((got-lock (common:simple-file-lock fname expire-time: expire-time))) (if got-lock #t |
︙ | ︙ | |||
460 461 462 463 464 465 466 | #f ;; I don't really care why this failed (at least for now) (delete-file* fname))) ;;====================================================================== ;; S T A T E S A N D S T A T U S E S ;;====================================================================== | > | > | > > > > > > > > > > | < | | | > > | > > | | > > > > | > > > > > > | 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 | #f ;; I don't really care why this failed (at least for now) (delete-file* fname))) ;;====================================================================== ;; S T A T E S A N D S T A T U S E S ;;====================================================================== ;; BBnote: *common:std-states* - dashboard filter control and test control state buttons defined here; used in set-fields-panel and dboard:make-controls (define *common:std-states* ;; for toggle buttons in dashboard '( (0 "ARCHIVED") (1 "STUCK") (2 "KILLREQ") (3 "KILLED") (4 "NOT_STARTED") (5 "COMPLETED") (6 "LAUNCHED") (7 "REMOTEHOSTSTART") (8 "RUNNING") )) (define *common:dont-roll-up-states* '("DELETED" "REMOVING" "CLEANING" "ARCHIVE_REMOVING" )) ;; BBnote: *common:std-statuses* dashboard filter control and test control status buttons defined here; used in set-fields-panel and dboard:make-controls ;; note these statuses are sorted from better to worse. ;; This sort order is important to dcommon:status-compare3 and db:set-state-status-and-roll-up-items (define *common:std-statuses* '(;; (0 "DELETED") (1 "n/a") (2 "PASS") (3 "SKIP") (4 "WARN") (5 "WAIVED") (6 "CHECK") (7 "STUCK/DEAD") (8 "DEAD") (9 "FAIL") (10 "PREQ_FAIL") (11 "PREQ_DISCARDED") (12 "ABORT"))) (define *common:ended-states* ;; states which indicate the test is stopped and will not proceed '("COMPLETED" "ARCHIVED" "KILLED" "KILLREQ" "STUCK" "INCOMPLETE" )) (define *common:badly-ended-states* ;; these roll up as CHECK, i.e. results need to be checked '("KILLED" "KILLREQ" "STUCK" "INCOMPLETE" "DEAD")) (define *common:well-ended-states* ;; an item's prereq in this state allows item to proceed '("PASS" "WARN" "CHECK" "WAIVED" "SKIP")) ;; BBnote: *common:running-states* used from db:set-state-status-and-roll-up-items (define *common:running-states* ;; test is either running or can be run '("RUNNING" "REMOTEHOSTSTART" "LAUNCHED" "STARTED")) (define *common:cant-run-states* ;; These are stopping conditions that prevent a test from being run '("COMPLETED" "KILLED" "UNKNOWN" "INCOMPLETE" "ARCHIVED")) (define *common:not-started-ok-statuses* ;; if not one of these statuses when in not_started state treat as dead '("n/a" "na" "PASS" "FAIL" "WARN" "CHECK" "WAIVED" "DEAD" "SKIP")) ;; group tests into buckets corresponding to rollup ;;; Running, completed-pass, completed-non-pass + worst status, not started. ;; filter out ;(define (common:categorize-items-for-rollup in-tests) ; ( (define (common:special-sort items order comp) (let ((items-order (map reverse order)) (acomp (or comp >))) (sort items (lambda (a b) (let ((a-num (cadr (or (assoc a items-order) '(0 0)))) |
︙ | ︙ | |||
583 584 585 586 587 588 589 590 591 592 | (define (common:get-testsuite-name) (or (configf:lookup *configdat* "setup" "area-name") ;; megatest is a flexible tool, testsuite is too limiting a description. (configf:lookup *configdat* "setup" "testsuite" ) (getenv "MT_TESTSUITE_NAME") (if (string? *toppath* ) (pathname-file *toppath*) #f))) ;; (pathname-file (current-directory))))) (define common:get-area-name common:get-testsuite-name) | > > > > > > > > > > > > > > > > > > > > > > > > > | | > > > > > > | | | | | | < < < < < < < < < < < < < > > > > > > < < | > | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < > | | | | | | | | | > > > > > | > > > > > | | > > | | | | | 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 | (define (common:get-testsuite-name) (or (configf:lookup *configdat* "setup" "area-name") ;; megatest is a flexible tool, testsuite is too limiting a description. (configf:lookup *configdat* "setup" "testsuite" ) (getenv "MT_TESTSUITE_NAME") (if (string? *toppath* ) (pathname-file *toppath*) #f))) ;; (pathname-file (current-directory))))) ;; safe getting of toppath (define (common:get-toppath areapath) (or *toppath* (if areapath (begin (set! *toppath* areapath) (setenv "MT_RUN_AREA_HOME" areapath) areapath) #f) (if (getenv "MT_RUN_AREA_HOME") (begin (set! *toppath* (getenv "MT_RUN_AREA_HOME")) *toppath*) #f) ;; last resort, look for megatest.config (let loop ((thepath (realpath "."))) (if (file-exists? (conc thepath "/megatest.config")) thepath (if (equal? thepath "/") (begin (debug:print-error 0 *default-log-port* "Unable to find megatest home directory.") #f) (loop (pathname-directory thepath))))) )) (define common:get-area-name common:get-testsuite-name) (define (common:get-db-tmp-area . junk) (if *db-cache-path* *db-cache-path* (if *toppath* ;; common:get-create-writeable-dir (handle-exceptions exn (begin (debug:print-error 0 *default-log-port* "Couldn't create path to " *db-cache-path*) (exit 1)) (let ((dbpath (common:get-create-writeable-dir (list (conc "/tmp/" (current-user-name) "/megatest_localdb/" (common:get-testsuite-name) "/" (string-translate *toppath* "/" ".")))))) ;; #t)))) (set! *db-cache-path* dbpath) dbpath)) #f))) (define (common:get-area-path-signature) (message-digest-string (md5-primitive) *toppath*)) (define (common:get-signature str) (message-digest-string (md5-primitive) str)) ;;====================================================================== ;; E X I T H A N D L I N G ;;====================================================================== (define (common:run-sync?) (and (common:on-homehost?) (args:get-arg "-server"))) ;; (let ((ohh (common:on-homehost?)) ;; (srv (args:get-arg "-server"))) ;; (and ohh srv))) ;; (debug:print-info 0 *default-log-port* "common:run-sync? ohh=" ohh ", srv=" srv) (define *wdnum* 0) (define *wdnum*mutex (make-mutex)) (define (common:human-time) (time->string (seconds->local-time (current-seconds)) "%Y-%m-%d %H:%M:%S")) ;; currently the primary job of the watchdog is to run the sync back to megatest.db from the db in /tmp ;; if we are on the homehost and we are a server (by definition we are on the homehost if we are a server) ;; (define (common:readonly-watchdog dbstruct) (thread-sleep! 0.05) ;; delay for startup (debug:print-info 13 *default-log-port* "common:readonly-watchdog entered.") ;; sync megatest.db to /tmp/.../megatst.db (let* ((sync-cool-off-duration 3) (golden-mtdb (dbr:dbstruct-mtdb dbstruct)) (golden-mtpath (db:dbdat-get-path golden-mtdb)) (tmp-mtdb (dbr:dbstruct-tmpdb dbstruct)) (tmp-mtpath (db:dbdat-get-path tmp-mtdb))) (debug:print-info 0 *default-log-port* "Read-only periodic sync thread started.") (let loop ((last-sync-time 0)) (debug:print-info 13 *default-log-port* "loop top tmp-mtpath="tmp-mtpath" golden-mtpath="golden-mtpath) (let* ((duration-since-last-sync (- (current-seconds) last-sync-time))) (debug:print-info 13 *default-log-port* "duration-since-last-sync="duration-since-last-sync) (if (and (not *time-to-exit*) (< duration-since-last-sync sync-cool-off-duration)) (thread-sleep! (- sync-cool-off-duration duration-since-last-sync))) (if (not *time-to-exit*) (let ((golden-mtdb-mtime (file-modification-time golden-mtpath)) (tmp-mtdb-mtime (file-modification-time tmp-mtpath))) (if (> golden-mtdb-mtime tmp-mtdb-mtime) (if (< golden-mtdb-mtime (- (current-seconds) 3)) ;; file has NOT been touched in past three seconds, this way multiple servers won't fight to sync back (let ((res (db:multi-db-sync dbstruct 'old2new))) (debug:print-info 13 *default-log-port* "rosync called, " res " records transferred.")))) (loop (current-seconds))) #t))) (debug:print-info 0 *default-log-port* "Exiting readonly-watchdog timer, *time-to-exit* = " *time-to-exit*" pid="(current-process-id)" mtpath="golden-mtpath))) ;; TODO: for multiple areas, we will have multiple watchdogs; and multiple threads to manage (define (common:watchdog) (debug:print-info 13 *default-log-port* "common:watchdog entered.") (if (launch:setup) (if (common:on-homehost?) (let ((dbstruct (db:setup #t))) (debug:print-info 13 *default-log-port* "after db:setup with dbstruct=" dbstruct) (cond ((dbr:dbstruct-read-only dbstruct) (debug:print-info 13 *default-log-port* "loading read-only watchdog") (common:readonly-watchdog dbstruct)) (else (debug:print-info 13 *default-log-port* "loading writable-watchdog.") (let* ((syncer (or (configf:lookup *configdat* "server" "sync-method") "brute-force-sync"))) (cond ((equal? syncer "brute-force-sync") (server:writable-watchdog-bruteforce dbstruct)) ((equal? syncer "delta-sync") (server:writable-watchdog-deltasync dbstruct)) (else (debug:print-error 0 *default-log-port* "Unknown server/sync-method specified ("syncer") - valid values are brute-force-sync and delta-sync.") (exit 1))) ;;(debug:print 1 *default-log-port* "INFO: ["(common:human-time)"] Syncer started (method="syncer")") ))) (debug:print-info 13 *default-log-port* "watchdog done.")) (debug:print-info 13 *default-log-port* "no need for watchdog on non-homehost")))) (define (std-exit-procedure) ;;(common:telemetry-log-close) (on-exit (lambda () 0)) ;;(debug:print-info 13 *default-log-port* "std-exit-procedure called; *time-to-exit*="*time-to-exit*) (let ((no-hurry (if *time-to-exit* ;; hurry up #f (begin (set! *time-to-exit* #t) #t)))) (debug:print-info 4 *default-log-port* "starting exit process, finalizing databases.") (if (and no-hurry (debug:debug-mode 18)) (rmt:print-db-stats)) (let ((th1 (make-thread (lambda () ;; thread for cleaning up, give it five seconds (if *dbstruct-db* (db:close-all *dbstruct-db*)) ;; one second allocated (if *task-db* (let ((db (cdr *task-db*))) (if (sqlite3:database? db) (begin (sqlite3:interrupt! db) (sqlite3:finalize! db #t) ;; (vector-set! *task-db* 0 #f) (set! *task-db* #f))))) (http-client#close-all-connections!) ;; (if (and *runremote* ;; (remote-conndat *runremote*)) ;; (begin ;; (http-client#close-all-connections!))) ;; for http-client (if (not (eq? *default-log-port* (current-error-port))) (close-output-port *default-log-port*)) (set! *default-log-port* (current-error-port))) "Cleanup db exit thread")) (th2 (make-thread (lambda () (debug:print 4 *default-log-port* "Attempting clean exit. Please be patient and wait a few seconds...") (if no-hurry (begin |
︙ | ︙ | |||
801 802 803 804 805 806 807 | ) ) 0) (define (std-signal-handler signum) ;; (signal-mask! signum) | | | > > > > > > > > > > > | 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 | ) ) 0) (define (std-signal-handler signum) ;; (signal-mask! signum) (set! *time-to-exit* #t) ;;(debug:print-info 13 *default-log-port* "got signal "signum) (debug:print-error 0 *default-log-port* "Received signal " signum " aaa exiting promptly") ;; (std-exit-procedure) ;; shouldn't need this since we are exiting and it will be called anyway (exit)) (define (special-signal-handler signum) ;; (signal-mask! signum) (set! *time-to-exit* #t) ;;(debug:print-info 13 *default-log-port* "got signal "signum) (debug:print-error 0 *default-log-port* "Received signal " signum " sending email befor exiting!!") ;;TODO send email to notify admin contact listed in the config that the lisner got killed ;; (std-exit-procedure) ;; shouldn't need this since we are exiting and it will be called anyway (exit)) (set-signal-handler! signal/int std-signal-handler) ;; ^C (set-signal-handler! signal/term std-signal-handler) ;; (set-signal-handler! signal/stop std-signal-handler) ;; ^Z NO, do NOT handle ^Z! ;;====================================================================== ;; M I S C U T I L S ;;====================================================================== ;; convert stuff to a number if possible |
︙ | ︙ | |||
856 857 858 859 860 861 862 | (define (common:which cmds) (if (null? cmds) #f (let loop ((hed (car cmds)) (tal (cdr cmds))) (let ((res (with-input-from-pipe (conc "which " hed) read-line))) (if (and (string? res) | | | | > > | | 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 | (define (common:which cmds) (if (null? cmds) #f (let loop ((hed (car cmds)) (tal (cdr cmds))) (let ((res (with-input-from-pipe (conc "which " hed) read-line))) (if (and (string? res) (common:file-exists? res)) res (if (null? tal) #f (loop (car tal)(cdr tal)))))))) (define (common:get-install-area) (let ((exe-path (car (argv)))) (if (common:file-exists? exe-path) (handle-exceptions exn #f (pathname-directory (pathname-directory (pathname-directory exe-path)))) #f))) ;; return first path that can be created or already exists and is writable ;; (define (common:get-create-writeable-dir dirs) (if (null? dirs) #f (let loop ((hed (car dirs)) (tal (cdr dirs))) (let ((res (or (and (directory? hed) (file-write-access? hed) hed) (handle-exceptions exn (begin (debug:print-info 0 *default-log-port* "could not create " hed ", this might cause problems down the road.") #f) (create-directory hed #t))))) (if (and (string? res) (directory? res)) res (if (null? tal) #f (loop (car tal)(cdr tal)))))))) |
︙ | ︙ | |||
922 923 924 925 926 927 928 | ;; use bash to expand a glob. Does NOT handle paths with spaces! ;; (define (common:bash-glob instr) (string-split (with-input-from-pipe (conc "/bin/bash -c \"echo " instr "\"") | | > > > > > > > > > > > > | 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 | ;; use bash to expand a glob. Does NOT handle paths with spaces! ;; (define (common:bash-glob instr) (string-split (with-input-from-pipe (conc "/bin/bash -c \"echo " instr "\"") read-line))) ;;====================================================================== ;; Some safety net stuff ;;====================================================================== ;; return input if it is a list or return null (define (common:list-or-null inlst #!key (ovrd #f)(message #f)) (if (list? inlst) inlst (begin (if message (debug:print-error 0 *default-log-port* message)) (or ovrd '())))) ;;====================================================================== ;; T A R G E T S , S T A T E , S T A T U S , ;; R U N N A M E A N D T E S T P A T T ;;====================================================================== ;; (map print (map car (hash-table->alist (read-config "runconfigs.config" #f #t)))) |
︙ | ︙ | |||
963 964 965 966 967 968 969 | (define (common:args-get-status) (or (args:get-arg "-status")(args:get-arg ":status"))) (define (common:args-get-testpatt rconf) (let* (;; (tagexpr (args:get-arg "-tagexpr")) ;; (tags-testpatt (if tagexpr (string-join (runs:get-tests-matching-tags tagexpr) ",") #f)) | | > > > > > > > > > > | | > | > > > > > > > > > > > > > | | > | | < > > | > | > > > > | | 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 | (define (common:args-get-status) (or (args:get-arg "-status")(args:get-arg ":status"))) (define (common:args-get-testpatt rconf) (let* (;; (tagexpr (args:get-arg "-tagexpr")) ;; (tags-testpatt (if tagexpr (string-join (runs:get-tests-matching-tags tagexpr) ",") #f)) (testpatt-key (or (args:get-arg "-modepatt") (args:get-arg "--modepatt") "TESTPATT")) (args-testpatt (or (args:get-arg "-testpatt") (args:get-arg "-runtests") "%")) (rtestpatt (if rconf (runconfigs-get rconf testpatt-key) #f))) (cond ((or (args:get-arg "--modepatt") (args:get-arg "-modepatt")) ;; modepatt is a forced setting, when set it MUST refer to an existing PATT in the runconfig (if rconf (let* ((patts-from-mode-patt (runconfigs-get rconf testpatt-key))) (debug:print-info 0 *default-log-port* "modepatt defined is: "testpatt-key" runconfigs values for " testpatt-key " " patts-from-mode-patt) patts-from-mode-patt) (begin (debug:print-info 0 *default-log-port* " modepatt defined is: "testpatt-key" runconfigs values for " testpatt-key) ;; " " patts-from-mode-patt) #f))) ;; We do NOT fall back to "%" ;; (tags-testpatt ;; (debug:print-info 0 *default-log-port* "-tagexpr "tagexpr" selects testpatt "tags-testpatt) ;; tags-testpatt) ((and (equal? args-testpatt "%") rtestpatt) (debug:print-info 0 *default-log-port* "testpatt defined in "testpatt-key" from runconfigs: " rtestpatt) rtestpatt) (else (debug:print-info 0 *default-log-port* "using testpatt " args-testpatt " rtestpatt:" rtestpatt) args-testpatt)))) (define (common:false-on-exception thunk #!key (message #f)) (handle-exceptions exn (begin (if message (debug:print-info 0 *default-log-port* message)) #f) (thunk) )) (define (common:file-exists? path-string #!key (silent #f)) ;; this avoids stack dumps in the case where ;;;; TODO: catch permission denied exceptions and emit appropriate warnings, eg: system error while trying to access file: "/nfs/pdx/disks/icf_env_disk001/bjbarcla/gwa/issues/mtdev/randy-slow/reproduce/q... (common:false-on-exception (lambda () (file-exists? path-string)) message: (if (not silent) (conc "Unable to access path: " path-string) #f) )) (define (common:directory-exists? path-string) ;;;; TODO: catch permission denied exceptions and emit appropriate warnings, eg: system error while trying to access file: "/nfs/pdx/disks/icf_env_disk001/bjbarcla/gwa/issues/mtdev/randy-slow/reproduce/q... (common:false-on-exception (lambda () (directory-exists? path-string)) message: (conc "Unable to access path: " path-string) )) ;; does the directory exist and do we have write access? ;; ;; returns the directory or #f ;; (define (common:directory-writable? path-string) (handle-exceptions exn #f (if (and (directory-exists? path-string) (file-write-access? path-string)) path-string #f))) (define (common:get-linktree) (or (getenv "MT_LINKTREE") (if *configdat* (configf:lookup *configdat* "setup" "linktree") #f) (if (or *toppath* (getenv "MT_RUN_AREA_HOME")) (conc (or *toppath* (getenv "MT_RUN_AREA_HOME")) "/lt") #f) (let* ((tp (common:get-toppath #f)) (lt (conc tp "/lt"))) (if (not tp)(debug:print 0 *default-log-port* "WARNING: cannot calculate best path for linktree, using " lt)) lt))) (define (common:args-get-runname) (let ((res (or (args:get-arg "-runname") (args:get-arg ":runname") (getenv "MT_RUNNAME")))) ;; (if res (set-environment-variable "MT_RUNNAME" res)) ;; not sure if this is a good idea. side effect and all ... res)) (define (common:get-fields cfgdat) (let ((fields (hash-table-ref/default cfgdat "fields" '()))) (map car fields))) (define (common:args-get-target #!key (split #f)(exit-if-bad #f)) (let* ((keys (if (hash-table? *configdat*) (common:get-fields *configdat*) '())) (numkeys (length keys)) (target (or (args:get-arg "-reqtarg") (args:get-arg "-target") (getenv "MT_TARGET"))) (tlist (if target (string-split target "/" #t) '())) (valid (if target (or (null? keys) ;; probably don't know our keys yet |
︙ | ︙ | |||
1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 | target) (if target (begin (debug:print-error 0 *default-log-port* "Invalid target, spaces or blanks not allowed \"" target "\", target should be: " (string-intersperse keys "/") ", have " tlist " for elements") (if exit-if-bad (exit 1)) #f) #f)))) ;; logic for getting homehost. Returns (host . at-home) ;; IF *toppath* is not set, wait up to five seconds trying every two seconds ;; (this is to accomodate the watchdog) ;; (define (common:get-homehost #!key (trynum 5)) ;; called often especially at start up. use mutex to eliminate collisions | > > > > > > > > > > | 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 | target) (if target (begin (debug:print-error 0 *default-log-port* "Invalid target, spaces or blanks not allowed \"" target "\", target should be: " (string-intersperse keys "/") ", have " tlist " for elements") (if exit-if-bad (exit 1)) #f) #f)))) ;; looking only (at least for now) at the MT_ variables craft the full testname ;; (define (common:get-full-test-name) (if (getenv "MT_TEST_NAME") (if (and (getenv "MT_ITEMPATH") (not (equal? (getenv "MT_ITEMPATH") ""))) (getenv "MT_TEST_NAME") (conc (getenv "MT_TEST_NAME") "/" (getenv "MT_ITEMPATH"))) #f)) ;; logic for getting homehost. Returns (host . at-home) ;; IF *toppath* is not set, wait up to five seconds trying every two seconds ;; (this is to accomodate the watchdog) ;; (define (common:get-homehost #!key (trynum 5)) ;; called often especially at start up. use mutex to eliminate collisions |
︙ | ︙ | |||
1069 1070 1071 1072 1073 1074 1075 | ;; first look in config, then look in file .homehost, create it if not found (homehost (or (configf:lookup *configdat* "server" "homehost" ) (handle-exceptions exn (if (> trynum 0) (let ((delay-time (* (- 5 trynum) 5))) (mutex-unlock! *homehost-mutex*) | | | | | 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 | ;; first look in config, then look in file .homehost, create it if not found (homehost (or (configf:lookup *configdat* "server" "homehost" ) (handle-exceptions exn (if (> trynum 0) (let ((delay-time (* (- 5 trynum) 5))) (mutex-unlock! *homehost-mutex*) (debug:print 0 *default-log-port* "ERROR: ["(common:human-time)"] Failed to read .homehost file, delaying " delay-time " seconds and trying again, message: " ((condition-property-accessor 'exn 'message) exn)) (thread-sleep! delay-time) (common:get-homehost trynum: (- trynum 1))) (begin (mutex-unlock! *homehost-mutex*) (debug:print 0 *default-log-port* "ERROR: ["(common:human-time)"] Failed to read .homehost file after trying five times. Giving up and exiting, message: " ((condition-property-accessor 'exn 'message) exn)) (exit 1))) (let ((hhf (conc *toppath* "/.homehost"))) (if (common:file-exists? hhf) (with-input-from-file hhf read-line) (if (file-write-access? *toppath*) (begin (with-output-to-file hhf (lambda () (print bestadrs))) (begin |
︙ | ︙ | |||
1105 1106 1107 1108 1109 1110 1111 | (if hh (cdr hh) #f))) ;; do we honor the caches of the config files? ;; (define (common:use-cache?) | | > | > | > > > > > > > > | < < < < < < < | 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 | (if hh (cdr hh) #f))) ;; do we honor the caches of the config files? ;; (define (common:use-cache?) (let ((res #t)) ;; priority by order of evaluation (if *configdat* ;; sillyness here. can't use setup/use-cache to know if we can use the cached files! (if (equal? (configf:lookup *configdat* "setup" "use-cache") "no") (set! res #f) (if (equal? (configf:lookup *configdat* "setup" "use-cache") "yes") (set! res #t)))) (if (args:get-arg "-no-cache")(set! res #f)) ;; overrides setting in "setup" (if (getenv "MT_USE_CACHE") (if (equal? (getenv "MT_USE_CACHE") "yes") (set! res #t) (if (equal? (getenv "MT_USE_CACHE") "no") (set! res #f)))) ;; overrides -no-cache switch res)) ;; force use of server? ;; (define (common:force-server?) (let* ((force-setting (configf:lookup *configdat* "server" "force")) (force-type (if force-setting (string->symbol force-setting) #f)) (force-result (case force-type ((#f) #f) ((always) #t) ((test) (if (args:get-arg "-execute") ;; we are in a test #t #f)) (else (debug:print 0 *default-log-port* "ERROR: Bad server force setting " force-setting ", forcing server.") #t)))) ;; default to requiring server (if force-result (begin (debug:print-info 0 *default-log-port* "forcing use of server, force setting is \"" force-setting "\".") #t) #f))) ;;====================================================================== ;; M I S C L I S T S ;;====================================================================== ;; items in lista are matched value and position in listb ;; return the remaining items in listb or #f ;; |
︙ | ︙ | |||
1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 | (loop (car tal) (cdr tal) new-rownames new-colnames (if (> curr-rownum rownum) curr-rownum rownum) (if (> curr-colnum colnum) curr-colnum colnum) )))))) ;;====================================================================== ;; S Y S T E M S T U F F ;;====================================================================== ;; lazy-safe get file mod time. on any error (file not existing etc.) return 0 ;; | > > > > > > > > > > > > > > > > > > > > > > > | 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 | (loop (car tal) (cdr tal) new-rownames new-colnames (if (> curr-rownum rownum) curr-rownum rownum) (if (> curr-colnum colnum) curr-colnum colnum) )))))) ;; if it looks like a number -> convert it to a number, else return it ;; (define (common:lazy-convert inval) (let* ((as-num (if (string? inval)(string->number inval) #f))) (or as-num inval))) ;; convert string a=1; b=2; c=a silly thing; d= ;; to '((a . 1)(b . 2)(c . "a silly thing")(d . "")) ;; (define (common:val->alist val #!key (convert #f)) (let ((val-list (string-split-fields ";\\s*" val #:infix))) (if val-list (map (lambda (x) (let ((f (string-split-fields "\\s*=\\s*" x #:infix))) (case (length f) ((0) `(,#f)) ;; null string case ((1) `(,(string->symbol (car f)))) ((2) `(,(string->symbol (car f)) . ,(let ((inval (cadr f))) (if convert (common:lazy-convert inval) inval)))) (else f)))) val-list) '()))) ;;====================================================================== ;; S Y S T E M S T U F F ;;====================================================================== ;; lazy-safe get file mod time. on any error (file not existing etc.) return 0 ;; |
︙ | ︙ | |||
1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 | ;; (if match ;; (let ((newval (string->number (cadr match)))) ;; (if (number? newval) ;; (set! cpu-load newval)))))) ;; (car load-res)) ;; cpu-load)) ;; get cpu load by reading from /proc/loadavg, return all three values ;; (define (common:get-cpu-load remote-host) | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | | | | | | > > > > > > > > > > > > > > > > > > > > > > > | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | > | | | | | | | | > > | | | | | | | | | | | | | | | | | | > | > > > | 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 | ;; (if match ;; (let ((newval (string->number (cadr match)))) ;; (if (number? newval) ;; (set! cpu-load newval)))))) ;; (car load-res)) ;; cpu-load)) ;; get values from cached info from dropping file in logs dir ;; e.g. key is host and dtype is normalized-load ;; (define (common:get-cached-info key dtype #!key (age 10)) (if *toppath* (let* ((fullpath (conc *toppath* "/.sysdata/" key "-" dtype ".log"))) (if (and (file-exists? fullpath) (file-read-access? fullpath)) (handle-exceptions exn #f (debug:print 2 *default-log-port* "reading file " fullpath) (let ((real-age (- (current-seconds)(file-change-time fullpath)))) (if (< real-age age) (handle-exceptions exn (begin (debug:print-info 1 *default-log-port* " removing bad file " fullpath) (delete-file* fullpath) #f) (with-input-from-file fullpath read)) (begin (debug:print-info 2 *default-log-port* "file " fullpath " is too old (" real-age" seconds) to trust, skipping reading it") #f)))) (begin (debug:print 2 *default-log-port* "not reading file " fullpath) #f))) #f)) (define (common:write-cached-info key dtype dat) (if *toppath* (let* ((fulldir (conc *toppath* "/.sysdata")) (fullpath (conc fulldir "/" key "-" dtype ".log"))) (if (not (file-exists? fulldir))(create-directory fulldir #t)) (handle-exceptions exn #f (with-output-to-file fullpath (lambda ()(pp dat))))) #f)) ;; get cpu load by reading from /proc/loadavg, return all three values ;; (define (common:get-cpu-load remote-host) (handle-exceptions exn '(99 99 99) (let* ((actual-hostname (or remote-host (get-host-name) "localhost"))) (or (common:get-cached-info actual-hostname "cpu-load") (let ((result (if remote-host (map (lambda (res) (if (eof-object? res) 9e99 res)) (with-input-from-pipe (conc "ssh " remote-host " cat /proc/loadavg") (lambda ()(list (read)(read)(read))))) (with-input-from-file "/proc/loadavg" (lambda ()(list (read)(read)(read))))))) (common:write-cached-info actual-hostname "cpu-load" result) result))))) ;; get normalized cpu load by reading from /proc/loadavg and /proc/cpuinfo return all three values and the number of real cpus and the number of threads ;; returns alist '((adj-cpu-load . normalized-proc-load) ... etc. ;; keys: adj-proc-load, adj-core-load, 1m-load, 5m-load, 15m-load ;; (define (common:get-normalized-cpu-load remote-host) (let ((res (common:get-normalized-cpu-load-raw remote-host)) (default `((adj-proc-load . 2) ;; there is no right answer (adj-core-load . 2) (1m-load . 2) (5m-load . 0) ;; causes a large delta - thus causing default of throttling if stuff goes wrong (15m-load . 0) (proc . 1) (core . 1) (phys . 1) (error . #t)))) (cond ((and (list? res) (> (length res) 2)) res) ((eq? res #f) default) ;; add messages? ((eq? res #f) default) ;; this would be the #eof (else default)))) (define (common:get-normalized-cpu-load-raw remote-host) (let* ((actual-host (or remote-host (get-host-name)))) ;; #f is localhost (or (common:get-cached-info actual-host "normalized-load") (let ((data (if remote-host (with-input-from-pipe (conc "ssh " remote-host " \"cat /proc/loadavg;cat /proc/cpuinfo;echo end\"") read-lines) (append (with-input-from-file "/proc/loadavg" read-lines) (with-input-from-file "/proc/cpuinfo" read-lines) (list "end")))) (load-rx (regexp "^([\\d\\.]+)\\s+([\\d\\.]+)\\s+([\\d\\.]+)\\s+.*$")) (proc-rx (regexp "^processor\\s+:\\s+(\\d+)\\s*$")) (core-rx (regexp "^core id\\s+:\\s+(\\d+)\\s*$")) (phys-rx (regexp "^physical id\\s+:\\s+(\\d+)\\s*$")) (max-num (lambda (p n)(max (string->number p) n)))) ;; (print "data=" data) (if (null? data) ;; something went wrong #f (let loop ((hed (car data)) (tal (cdr data)) (loads #f) (proc-num 0) ;; processor includes threads (phys-num 0) ;; physical chip on motherboard (core-num 0)) ;; core ;;; (print hed ", " loads ", " proc-num ", " phys-num ", " core-num) (if (null? tal) ;; have all our data, calculate normalized load and return result (let* ((act-proc (+ proc-num 1)) (act-phys (+ phys-num 1)) (act-core (+ core-num 1)) (adj-proc-load (/ (car loads) act-proc)) (adj-core-load (/ (car loads) act-core)) (result (append (list (cons 'adj-proc-load adj-proc-load) (cons 'adj-core-load adj-core-load)) (list (cons '1m-load (car loads)) (cons '5m-load (cadr loads)) (cons '15m-load (caddr loads))) (list (cons 'proc act-proc) (cons 'core act-core) (cons 'phys act-phys))))) (common:write-cached-info actual-host "normalized-load" result) result) (regex-case hed (load-rx ( x l1 l5 l15 ) (loop (car tal)(cdr tal)(map string->number (list l1 l5 l15)) proc-num phys-num core-num)) (proc-rx ( x p ) (loop (car tal)(cdr tal) loads (max-num p proc-num) phys-num core-num)) (phys-rx ( x p ) (loop (car tal)(cdr tal) loads proc-num (max-num p phys-num) core-num)) (core-rx ( x c ) (loop (car tal)(cdr tal) loads proc-num phys-num (max-num c core-num))) (else (begin ;; (print "NO MATCH: " hed) (loop (car tal)(cdr tal) loads proc-num phys-num core-num))))))))))) (define (common:unix-ping hostname) (let ((res (system (conc "ping -c 1 " hostname " > /dev/null")))) (eq? res 0))) ;; ideally put all this info into the db, no need to preserve it across moving homehost ;; ;; return list of ;; ( reachable? cpuload update-time ) (define (common:get-host-info hostname) (let* ((loadinfo (rmt:get-latest-host-load hostname)) ;; if this host happens to have been recently used by a test reuse the load data (load (car loadinfo)) (load-sample-time (cdr loadinfo)) (load-sample-age (- (current-seconds) load-sample-time)) (loadinfo-timeout-seconds 6) ;; this was 20 seconds, seems way too lax. Switch to 6 seconds (host-last-update-timeout-seconds 4) (host-rec (hash-table-ref/default *host-loads* hostname #f)) ) (cond ((< load-sample-age loadinfo-timeout-seconds) (list #t load-sample-time load)) ((and host-rec (< (current-seconds) (+ (host-last-update host-rec) host-last-update-timeout-seconds))) (list #t (host-last-update host-rec) (host-last-cpuload host-rec ))) ((common:unix-ping hostname) (list #t (current-seconds) (alist-ref 'adj-core-load (common:get-normalized-cpu-load hostname)))) ;; this is cheaper than you might think. get-normalized-cpu-load is cached for up to 5 seconds (else (list #f 0 -1) ;; bad host, don't use! )))) ;; see defstruct host at top of file. ;; host: reachable last-update last-used last-cpuload ;; (define (common:update-host-loads-table hosts-raw) (let* ((hosts (filter (lambda (x) (string-match (regexp "^\\S+$") x)) hosts-raw))) (for-each (lambda (hostname) (let* ((rec (let ((h (hash-table-ref/default *host-loads* hostname #f))) |
︙ | ︙ | |||
1479 1480 1481 1482 1483 1484 1485 | (last-reached-time (cadr host-info)) (load (caddr host-info))) (host-reachable-set! rec is-reachable) (host-last-update-set! rec last-reached-time) (host-last-cpuload-set! rec load))) hosts))) | > > > | > > > > > | | | | > > > > > > > > | > > > > > > > > > > > > | > | | | < < < < < < | | < | < < | < > | < | | | | | | | < | | | | > > | | > > > | | < > > | < < > | > > | | | | > | > | | | | | | | | | > > > > | > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 | (last-reached-time (cadr host-info)) (load (caddr host-info))) (host-reachable-set! rec is-reachable) (host-last-update-set! rec last-reached-time) (host-last-cpuload-set! rec load))) hosts))) ;; go through the hosts from least recently used to most recently used, pick the first that meets the load criteral from the ;; [host-rules] section. ;; (define (common:get-least-loaded-host hosts-raw host-type configdat) (let* ((rdat (configf:lookup configdat "host-rules" host-type)) (rules (common:val->alist (or rdat "") convert: #t)) ;; maxnload, maxnjobs, maxjobrate (maxnload (common:alist-ref/default 'maxnload rules 1.5)) ;; max normalized load (maxnjobs (common:alist-ref/default 'maxnjobs rules 1.5)) ;; max normalized number of jobs (maxjobrate (common:alist-ref/default 'maxjobrate rules (/ 1 6))) ;; max rate of submitting jobs to a given host in jobs/second (hosts (filter (lambda (x) (string-match (regexp "^\\S+$") x)) hosts-raw)) ;; (best-host #f) (get-rec (lambda (hostname) ;; (print "get-rec hostname=" hostname) (let ((h (hash-table-ref/default *host-loads* hostname #f))) (if h h (let ((h (make-host))) (hash-table-set! *host-loads* hostname h) h))))) (best-load 99999) (curr-time (current-seconds)) (get-hosts-sorted (lambda (hosts) (sort hosts (lambda (a b) (let ((a-rec (get-rec a)) (b-rec (get-rec b))) ;; (print "a=" a " a-rec=" a-rec " host-last-used=" (host-last-used a-rec)) ;; (print "b=" b " b-rec=" b-rec " host-last-used=" (host-last-used b-rec)) (< (host-last-used a-rec) (host-last-used b-rec)))))))) (debug:print 0 *default-log-port* "INFO: hosts-sorted=" (get-hosts-sorted hosts)) (if (null? hosts) #f ;; no hosts to select from. All done and giving up now. (let ((hosts-sorted (get-hosts-sorted hosts))) (common:update-host-loads-table hosts) (let loop ((hostname (car hosts-sorted)) (tal (cdr hosts-sorted)) (best-host #f)) (let* ((rec (get-rec hostname)) (reachable (host-reachable rec)) (load (host-last-cpuload rec)) (last-used (host-last-used rec)) (delta (- curr-time last-used)) (job-rate (if (> delta 0) (/ 1 delta) 999)) ;; jobs per second (new-best (cond ((not reachable) (debug:print 0 *default-log-port* "Skipping host " hostname " as it cannot be reached.") best-host) ((and (< load maxnload) ;; load is acceptable (< job-rate maxjobrate)) ;; job rate is acceptable (set! best-load load) hostname) (else best-host)))) (debug:print 0 *default-log-port* "INFO: Trying host " hostname " with load " load ", last used " delta " seconds ago, with job-rate " job-rate " for running a test." ) (if new-best (begin ;; found a host, return it (debug:print 0 *default-log-port* "INFO: Found host: " new-best " load: " load " last-used: " delta " seconds ago, with job-rate: " job-rate) (host-last-used-set! rec curr-time) new-best) (if (null? tal) #f (loop (car tal)(cdr tal) best-host))))))))) (define (common:wait-for-homehost-load maxload msg) (let* ((hh-dat (if (common:on-homehost?) ;; if we are on the homehost then pass in #f so the calls are local. #f (common:get-homehost))) (hh (if hh-dat (car hh-dat) #f))) (common:wait-for-normalized-load maxload msg hh))) (define (common:get-num-cpus remote-host) (let* ((actual-host (or remote-host (get-host-name)))) (or (common:get-cached-info actual-host "num-cpus" age: (+ 2592000 (random 3600))) ;; hosts had better not be changing the number of cpus too often! (let* ((proc (lambda () (let loop ((numcpu 0) (inl (read-line))) (if (eof-object? inl) (if (> numcpu 0) numcpu #f) ;; if zero return #f so caller knows that things are not working (loop (if (string-match "^processor\\s+:\\s+\\d+$" inl) (+ numcpu 1) numcpu) (read-line)))))) (result (if remote-host (with-input-from-pipe (conc "ssh " remote-host " cat /proc/cpuinfo") proc) (with-input-from-file "/proc/cpuinfo" proc)))) (if (and (number? result) (> result 0)) (common:write-cached-info actual-host "num-cpus" result)) result)))) ;; wait for normalized cpu load to drop below maxload ;; (define (common:wait-for-normalized-load maxload msg remote-host #!optional (rem-tries 5)) (let ((num-cpus (common:get-num-cpus remote-host))) (if num-cpus (common:wait-for-cpuload maxload num-cpus 15 msg: msg remote-host: remote-host) (begin (thread-sleep! (random 60)) ;; we failed to get num cpus. wait a bit and try again (if (> rem-tries 0) (common:wait-for-normalized-load maxload msg remote-host (- rem-tries 1)) #f))))) ;; DO NOT CALL THIS DIRECTLY. It is called from common:wait-for-normalized-load ;; (define (common:wait-for-cpuload maxload-in numcpus-in waitdelay #!key (count 1000) (msg #f)(remote-host #f)(force-maxload #f)) (let* ((loadavg (common:get-cpu-load remote-host)) (numcpus (if (<= 1 numcpus-in) ;; not possible to have zero. If we get 1, it's possible that we got the previous default, and we should check again (common:get-num-cpus remote-host) numcpus-in)) (maxload (if force-maxload maxload-in (if (number? maxload-in) (max maxload-in 0.5) 0.5))) ;; so maxload must be greater than 0.5 for now BUG - FIXME? (first (car loadavg)) (next (cadr loadavg)) (adjload (* maxload (max 1 numcpus))) ;; possible bug where numcpus (or could be maxload) is zero, crude fallback is to at least use 1 (loadjmp (- first next)) (adjwait (min (+ 300 (random 10)) (abs (* (+ (random 10)(/ (- 1000 count) 10) waitdelay) (- first adjload) )) )));; add some randomness to the time to break any alignment where netbatch dumps many jobs to machines simultaneously ;; let's let the user know once in a long while that load checking is happening but not constantly report it (if (> (random 100) 75) ;; about 25% of the time (debug:print-info 1 *default-log-port* "Checking cpuload on " (or remote-host "localhost") ", maxload: " maxload ", load: " first ", adjload: " adjload ", loadjmp: " loadjmp)) (cond ((and (> first adjload) (> count 0)) (debug:print-info 0 *default-log-port* "server start delayed " adjwait " seconds due to load " first " exceeding max of " adjload " on server " (or remote-host (get-host-name)) " (normalized load-limit: " maxload ") " (if msg msg "")) (thread-sleep! adjwait) (common:wait-for-cpuload maxload numcpus waitdelay count: (- count 1) msg: msg remote-host: remote-host)) ((and (> loadjmp numcpus) (> count 0)) (debug:print-info 0 *default-log-port* "waiting " adjwait " seconds due to load jump " loadjmp " > numcpus " numcpus (if msg msg "")) (thread-sleep! adjwait) (common:wait-for-cpuload maxload numcpus waitdelay count: (- count 1) msg: msg remote-host: remote-host))))) (define (get-uname . params) (let* ((uname-res (process:cmd-run->list (conc "uname " (if (null? params) "-a" (car params))))) (uname #f)) (if (null? (car uname-res)) "unknown" (caar uname-res)))) |
︙ | ︙ | |||
1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 | (conc (configf:lookup *configdat* "setup" "free-space-script") " " path) (lambda () (let ((res (read-line))) (if (string? res) (string->number res))))) (get-unix-df path))) (define (get-unix-df path) (let* ((df-results (process:cmd-run->list (conc "df " path))) (space-rx (regexp "([0-9]+)\\s+([0-9]+)%")) (freespc #f)) ;; (write df-results) (for-each (lambda (l) (let ((match (string-search space-rx l))) (if match (let ((newval (string->number (cadr match)))) (if (number? newval) (set! freespc newval)))))) (car df-results)) freespc)) (define (common:check-space-in-dir dirpath required) (let* ((dbspace (if (directory? dirpath) (get-df dirpath) 0))) (list (> dbspace required) dbspace required dirpath))) ;; check space in dbdir and in megatest dir ;; returns: ok/not dbspace required-space ;; (define (common:check-db-dir-space) (let* ((required (string->number (or (configf:lookup *configdat* "setup" "dbdir-space-required") | > > > > > > > > > > > > > > > > > > > > > > > > > | | 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 | (conc (configf:lookup *configdat* "setup" "free-space-script") " " path) (lambda () (let ((res (read-line))) (if (string? res) (string->number res))))) (get-unix-df path))) (define (get-free-inodes path) (if (configf:lookup *configdat* "setup" "free-inodes-script") (with-input-from-pipe (conc (configf:lookup *configdat* "setup" "free-inodes-script") " " path) (lambda () (let ((res (read-line))) (if (string? res) (string->number res))))) (get-unix-inodes path))) (define (get-unix-df path) (let* ((df-results (process:cmd-run->list (conc "df " path))) (space-rx (regexp "([0-9]+)\\s+([0-9]+)%")) (freespc #f)) ;; (write df-results) (for-each (lambda (l) (let ((match (string-search space-rx l))) (if match (let ((newval (string->number (cadr match)))) (if (number? newval) (set! freespc newval)))))) (car df-results)) freespc)) (define (get-unix-inodes path) (let* ((df-results (process:cmd-run->list (conc "df -i " path))) (space-rx (regexp "([0-9]+)\\s+([0-9]+)%")) (freenodes 0)) ;; 0 is a better failsafe than #f here. ;; (write df-results) (for-each (lambda (l) (let ((match (string-search space-rx l))) (if match (let ((newval (string->number (cadr match)))) (if (number? newval) (set! freenodes newval)))))) (car df-results)) freenodes)) (define (common:check-space-in-dir dirpath required) (let* ((dbspace (if (directory? dirpath) (get-df dirpath) 0))) (list (> dbspace required) dbspace required dirpath))) ;; check space in dbdir and in megatest dir ;; returns: ok/not dbspace required-space ;; (define (common:check-db-dir-space) (let* ((required (string->number ;; default is 1GB (or actually a billion bytes) This is the number of 1 kB blocks. (or (configf:lookup *configdat* "setup" "dbdir-space-required") "1000000"))) (dbdir (common:get-db-tmp-area)) ;; (db:get-dbdir)) (tdbspace (common:check-space-in-dir dbdir required)) (mdbspace (common:check-space-in-dir *toppath* required))) (sort (list tdbspace mdbspace) (lambda (a b) (< (cadr a)(cadr b)))))) ;; check available space in dbdir, exit if insufficient |
︙ | ︙ | |||
1649 1650 1651 1652 1653 1654 1655 | (begin (debug:print-error 0 *default-log-port* "Insufficient space in " dbdir ", require " required ", have " dbspace ", exiting now.") (exit 1))))) ;; paths is list of lists ((name path) ... ) ;; (define (common:get-disk-with-most-free-space disks minsize) | | | > > > > | > > > > > > > > > > > > > > > > > > | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > | 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 | (begin (debug:print-error 0 *default-log-port* "Insufficient space in " dbdir ", require " required ", have " dbspace ", exiting now.") (exit 1))))) ;; paths is list of lists ((name path) ... ) ;; (define (common:get-disk-with-most-free-space disks minsize) (let* ((best #f) (bestsize 0) (default-min-inodes-string "1000000") (default-min-inodes (string->number default-min-inodes-string)) (min-inodes (or (string->number (if (configf:lookup *configdat* "setup" "min_inodes") (configf:lookup *configdat* "setup" "min_inodes") default-min-inodes-string)) default-min-inodes))) (for-each (lambda (disk-num) (let* ((dirpath (cadr (assoc disk-num disks))) (freespc (cond ((not (directory? dirpath)) (if (common:low-noise-print 300 "disks not a dir " disk-num) (debug:print 0 *default-log-port* "WARNING: disk " disk-num " at path \"" dirpath "\" is not a directory - ignoring it.")) -1) ((not (file-write-access? dirpath)) (if (common:low-noise-print 300 "disks not writeable " disk-num) (debug:print 0 *default-log-port* "WARNING: disk " disk-num " at path \"" dirpath "\" is not writeable - ignoring it.")) -1) ((not (eq? (string-ref dirpath 0) #\/)) (if (common:low-noise-print 300 "disks not a proper path " disk-num) (debug:print 0 *default-log-port* "WARNING: disk " disk-num " at path \"" dirpath "\" is not a fully qualified path - ignoring it.")) -1) (else (get-df dirpath)))) (free-inodes (cond ((not (directory? dirpath)) (if (common:low-noise-print 300 "disks not a dir " disk-num) (debug:print 0 *default-log-port* "WARNING: disk " disk-num " at path \"" dirpath "\" is not a directory - ignoring it.")) -1) ((not (file-write-access? dirpath)) (if (common:low-noise-print 300 "disks not writeable " disk-num) (debug:print 0 *default-log-port* "WARNING: disk " disk-num " at path \"" dirpath "\" is not writeable - ignoring it.")) -1) ((not (eq? (string-ref dirpath 0) #\/)) (if (common:low-noise-print 300 "disks not a proper path " disk-num) (debug:print 0 *default-log-port* "WARNING: disk " disk-num " at path \"" dirpath "\" is not a fully qualified path - ignoring it.")) -1) (else (get-free-inodes dirpath)))) ;;(free-inodes (get-free-inodes dirpath)) ) (debug:print 2 *default-log-port* "INFO: disk " disk-num " path " dirpath " free space " freespc " free inodes " free-inodes) (if (and (> freespc bestsize)(> free-inodes min-inodes )) (begin (set! best (cons disk-num dirpath)) (set! bestsize freespc))) ;;(print "Processing: " disk-num " bestsize: " bestsize " best: " best " freespc: " freespc " min-inodes: " min-inodes " free-inodes: " free-inodes) )) (map car disks)) (if (and best (> bestsize minsize)) best #f))) ;; #f means no disk candidate found ;; convert a spec string to a list of vectors #( rx action rx-string ) (define (common:spec-string->list-of-specs spec-string actions) (let ((spec-strings (string-split-fields "\\s*;\\s*" spec-string #:infix)) (actions-regex (regexp (conc "^(.*)\\s+(" (string-intersperse (map conc actions) "|") ")")))) (filter (lambda (x) x) (map (lambda (s) (let ((m (string-match actions-regex s))) (if m (vector (regexp (cadr m))(string->symbol (caddr m))(cadr m)) (begin (debug:print 0 *default-log-port* "WARNING: Unrecognised rule \"" s "\" in clean-up specification.") #f)))) spec-strings)))) ;; given a list of specs rx . rule and a file return the first matching rule ;; (define (common:file-find-rule fname rules) ;; rule is vector #( rx action rx-string) (let loop ((rule (car rules)) (tail (cdr rules))) (let ((rx (vector-ref rule 0)) (rn (vector-ref rule 1))) ;; rule name (if (string-match rx fname) rule ;; return the whole rule so regex can be printed etc. (if (null? tail) #f (loop (car tail)(cdr tail))))))) ;; given a spec apply some rules to a directory ;; ;; WARNING: This function will REMOVE files - be sure your spec and path is correct! ;; ;; spec format: ;; file-regex1 action; file-regex2 action; ... ;; e.g. ;; .*\.log$ keep; .* remove ;; --> keep all .log files, remove everything else ;; limitations: ;; cannot have a rule with ; as part of the spec ;; not very flexible, would be nice to return binned file names? ;; supported rules: ;; keep - keep this file ;; remove - remove this file ;; compress - compress this file ;; (define (common:dir-clean-up path spec-string #!key (compress "gzip")(actions '(keep remove compress))(remove-empty #f)) (let* ((specs (common:spec-string->list-of-specs spec-string actions)) (keepers (make-hash-table)) (directories (make-hash-table))) (find-files path action: (lambda (p res) (let ((rule (common:file-find-rule p specs))) (cond ((directory? p)(hash-table-set! directories p #t)) (else (case (vector-ref rule 1) ((keep)(hash-table-set! keepers p rule)) ((remove) (print "Removing file " p) (delete-file p)) ((compress) (print "Compressing file " p) (system (conc compress " " p))) (else (print "No match for file " p)))))))) (if remove-empty (for-each (lambda (d) (if (null? (glob (conc d "/.*")(conc d "/*"))) (begin (print "Removing empty directory " d) (delete-directory d)))) (sort (hash-table-keys directories) (lambda (a b)(> (string-length a)(string-length b)))))) )) ;;====================================================================== ;; E N V I R O N M E N T V A R S ;;====================================================================== (define (bb-check-path #!key (msg "check-path: ")) (let ((path (or (get-environment-variable "PATH") "none"))) (debug:print-info 0 *default-log-port* (conc msg" : $PATH="path)) (if (string-match "^.*/isoenv-core/.*" path) (debug:print-error 0 *default-log-port* (conc msg" : !!ISOENV PRESENT!!")) ;; remove for prod (debug:print-info 1 *default-log-port* (conc msg" : **no isoenv present**"))))) (define (save-environment-as-files fname #!key (ignorevars (list "USER" "HOME" "DISPLAY" "LS_COLORS" "XKEYSYMDB" "EDITOR" "MAKEFLAGS" "MAKEF" "MAKEOVERRIDES"))) ;;(bb-check-path msg: "save-environment-as-files entry") (let ((envvars (get-environment-variables)) (whitesp (regexp "[^a-zA-Z0-9_\\-:,\\.\\/%$]")) (mungeval (lambda (val) (cond ((eq? val #t) "") ;; convert #t to empty string ((eq? val #f) #f) ;; convert #f to itself (still thinking about this one (else val))))) (with-output-to-file (conc fname ".csh") (lambda () (for-each (lambda (keyval) (let* ((key (car keyval)) (val (cdr keyval)) (delim (if (string-search whitesp val) "\"" ""))) (print (if (or (member key ignorevars) (string-search whitesp key)) "# setenv " "setenv ") key " " delim (mungeval val) delim))) envvars))) (with-output-to-file (conc fname ".sh") (lambda () (for-each (lambda (keyval) (let* ((key (car keyval)) (val (cdr keyval)) (delim (if (string-search whitesp val) "\"" ""))) (print (if (or (member key ignorevars) (string-search whitesp key) (string-search ":" key)) ;; internal only values to be skipped. "# export " "export ") key "=" delim (mungeval val) delim))) envvars))))) (define (common:get-param-mapping #!key (flavor #f)) "returns alist mapping string keys in testconfig/subrun to megatest command line switches; if flavor is switch-symbol, maps tcmt symbolic switches to megatest switches" (let ((default '(("tag-expr" . "-tagexpr") ("mode-patt" . "-modepatt") ("run-name" . "-runname") ("contour" . "-contour") ("target" . "-target") ("test-patt" . "-testpatt") ("msg" . "-m") ("log" . "-log") ("start-dir" . "-start-dir") ("new" . "-set-state-status")))) (if (eq? flavor 'switch-symbol) (map (lambda (x) (cons (string->symbol (conc "-" (car x))) (cdr x))) default) default))) ;; set some env vars from an alist, return an alist with original values ;; (("VAR" "value") ...) ;; a value of #f means "unset this var" ;; (define (alist->env-vars lst) (if (list? lst) (let ((res '())) (for-each (lambda (p) (let* ((var (car p)) (val (cadr p)) (prv (get-environment-variable var))) (set! res (cons (list var prv) res)) (if val (safe-setenv var (->string val)) (unsetenv var)))) lst) res) '())) ;; clear vars matching pattern, run proc, set vars back ;; if proc is a string run that string as a command with ;; system. ;; (define *common:orig-env* (let ((envvars (get-environment-variables))) (if (get-environment-variable "MT_ORIG_ENV") (with-input-from-string (z3:decode-buffer (base64:base64-decode (get-environment-variable "MT_ORIG_ENV"))) read) (filter-map (lambda (x) (if (string-match "^MT_.*" (car x)) #f x)) envvars)))) (define (common:with-orig-env proc) (let ((current-env (get-environment-variables))) (for-each (lambda (x) (unsetenv (car x))) current-env) (for-each (lambda (x) (setenv (car x) (cdr x))) *common:orig-env*) (let ((rv (cond ((string? proc)(system proc)) (proc (proc))))) (for-each (lambda (x) (unsetenv (car x))) *common:orig-env*) (for-each (lambda (x) (setenv (car x) (cdr x))) current-env) rv))) (define (common:without-vars proc . var-patts) (let ((vars (make-hash-table))) (for-each (lambda (vardat) ;; each env var (for-each (lambda (var-patt) (if (string-match var-patt (car vardat)) |
︙ | ︙ | |||
1769 1770 1771 1772 1773 1774 1775 | (proc (proc))) (hash-table-for-each vars (lambda (var val) (setenv var val))) vars)) | > | | | > | | | | | | | > > > | | 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 | (proc (proc))) (hash-table-for-each vars (lambda (var val) (setenv var val))) vars)) (define (common:run-a-command cmd #!key (with-vars #f) (with-orig-env #f)) (let* ((pre-cmd (dtests:get-pre-command)) (post-cmd (dtests:get-post-command)) (fullcmd (if (or pre-cmd post-cmd) (conc pre-cmd cmd post-cmd) (conc "viewscreen " cmd)))) (debug:print-info 02 *default-log-port* "Running command: " fullcmd) (cond (with-vars (common:without-vars fullcmd)) (with-orig-env (common:with-orig-env fullcmd)) (else (common:without-vars fullcmd "MT_.*"))))) ;;====================================================================== ;; T I M E A N D D A T E ;;====================================================================== ;; Convert strings like "5s 2h 3m" => 60x60x2 + 3x60 + 5 (define (common:hms-string->seconds tstr) (let ((parts (string-split-fields "\\w+" tstr)) (time-secs 0) ;; s=seconds, m=minutes, h=hours, d=days, M=months, y=years, w=weeks (trx (regexp "(\\d+)([smhdMyw])"))) (for-each (lambda (part) (let ((match (string-match trx part))) (if match (let ((val (string->number (cadr match))) (unt (caddr match))) (if val (set! time-secs (+ time-secs (* val (case (string->symbol unt) ((s) 1) ((m) 60) ;; minutes ((h) 3600) ((d) 86400) ((w) 604800) ((M) 2628000) ;; aproximately one month ((y) 31536000) (else #f)))))))))) parts) time-secs)) (define (seconds->hr-min-sec secs) (let* ((hrs (quotient secs 3600)) (min (quotient (- secs (* hrs 3600)) 60)) (sec (- secs (* hrs 3600)(* min 60)))) |
︙ | ︙ | |||
2089 2090 2091 2092 2093 2094 2095 | (string-intersperse (map (lambda (x) (number->string x 16)) (map string->number (string-split instr))) "/")) | > > > > > > | > > > > > > > | > | | | | | > > > > | > > > > > > > > | | | | < < < < < < < < < < < < | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | > > > > > > | 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926 2927 | (string-intersperse (map (lambda (x) (number->string x 16)) (map string->number (string-split instr))) "/")) ;;====================================================================== ;; L O C K I N G M E C H A N I S M S ;;====================================================================== ;; faux-lock is deprecated. Please use simple-lock below ;; (define (common:faux-lock keyname #!key (wait-time 8)(allow-lock-steal #t)) (if (rmt:no-sync-get/default keyname #f) ;; do not be tempted to compare to pid. locking is a one-shot action, if already locked for this pid it doesn't actually count (if (> wait-time 0) (begin (thread-sleep! 1) (if (eq? wait-time 1) ;; only one second left, steal the lock (begin (debug:print-info 0 *default-log-port* "stealing lock for " keyname) (common:faux-unlock keyname force: #t))) (common:faux-lock keyname wait-time: (- wait-time 1))) #f) (begin (rmt:no-sync-set keyname (conc (current-process-id))) (equal? (conc (current-process-id)) (conc (rmt:no-sync-get/default keyname #f)))))) (define (common:faux-unlock keyname #!key (force #f)) (if (or force (equal? (conc (current-process-id)) (conc (rmt:no-sync-get/default keyname #f)))) (begin (if (rmt:no-sync-get/default keyname #f) (rmt:no-sync-del! keyname)) #t) #f)) ;; simple lock. improve and converge on this one. ;; (define (common:simple-lock keyname) (rmt:no-sync-get-lock keyname)) (define (common:simple-unlock keyname #!key (force #f)) (rmt:no-sync-del! keyname)) ;;====================================================================== ;; ;;====================================================================== (define (common:in-running-test?) (and (args:get-arg "-execute") (get-environment-variable "MT_CMDINFO"))) (define (common:get-color-from-status status) (cond ((equal? status "PASS") "green") ((equal? status "FAIL") "red") ((equal? status "WARN") "orange") ((equal? status "KILLED") "orange") ((equal? status "KILLREQ") "purple") ((equal? status "RUNNING") "blue") ((equal? status "ABORT") "brown") (else "black"))) ;; ;;====================================================================== ;; ;; N A N O M S G C L I E N T ;; ;;====================================================================== ;; ;; ;; ;; (define (common:send-dboard-main-changed) ;; (let* ((dashboard-ips (mddb:get-dashboards))) ;; (for-each ;; (lambda (ipadr) ;; (let* ((soc (common:open-nm-req (conc "tcp://" ipadr))) ;; (msg (conc "main " *toppath*)) ;; (res (common:nm-send-receive-timeout soc msg))) ;; (if (not res) ;; couldn't reach that dashboard - remove it from db ;; (print "ERROR: couldn't reach dashboard " ipadr)) ;; res)) ;; dashboard-ips))) ;; ;; ;; ;;====================================================================== ;; ;; D A S H B O A R D D B ;; ;;====================================================================== ;; ;; (define (mddb:open-db) ;; (let* ((db (open-database (conc (get-environment-variable "HOME") "/.dashboard.db")))) ;; (set-busy-handler! db (busy-timeout 10000)) ;; (for-each ;; (lambda (qry) ;; (exec (sql db qry))) ;; (list ;; "CREATE TABLE IF NOT EXISTS vars (id INTEGER PRIMARY KEY,key TEXT, val TEXT, CONSTRAINT varsconstraint UNIQUE (key));" ;; "CREATE TABLE IF NOT EXISTS dashboards ( ;; id INTEGER PRIMARY KEY, ;; pid INTEGER, ;; username TEXT, ;; hostname TEXT, ;; ipaddr TEXT, ;; portnum INTEGER, ;; start_time TIMESTAMP DEFAULT (strftime('%s','now')), ;; CONSTRAINT hostport UNIQUE (hostname,portnum) ;; );" ;; )) ;; db)) ;; ;; ;; register a dashboard ;; ;; ;; (define (mddb:register-dashboard port) ;; (let* ((pid (current-process-id)) ;; (hostname (get-host-name)) ;; (ipaddr (server:get-best-guess-address hostname)) ;; (username (current-user-name)) ;; (car userinfo))) ;; (db (mddb:open-db))) ;; (print "Register monitor, pid: " pid ", hostname: " hostname ", port: " port ", username: " username) ;; (exec (sql db "INSERT OR REPLACE INTO dashboards (pid,username,hostname,ipaddr,portnum) VALUES (?,?,?,?,?);") ;; pid username hostname ipaddr port) ;; (close-database db))) ;; ;; ;; unregister a monitor ;; ;; ;; (define (mddb:unregister-dashboard host port) ;; (let* ((db (mddb:open-db))) ;; (print "Register unregister monitor, host:port=" host ":" port) ;; (exec (sql db "DELETE FROM dashboards WHERE hostname=? AND portnum=?;") host port) ;; (close-database db))) ;; ;; ;; get registered dashboards ;; ;; ;; (define (mddb:get-dashboards) ;; (let ((db (mddb:open-db))) ;; (query fetch-column ;; (sql db "SELECT ipaddr || ':' || portnum FROM dashboards;")))) ;;====================================================================== ;; T E S T L A U N C H I N G P E R I T E M W I T H H O S T T Y P E S ;;====================================================================== ;; ;; [hosts] ;; arm cubie01 cubie02 ;; x86_64 zeus xena myth01 ;; allhosts #{g hosts arm} #{g hosts x86_64} ;; ;; [host-types] ;; general #MTLOWESTLOAD #{g hosts allhosts} ;; arm #MTLOWESTLOAD #{g hosts arm} ;; nbgeneral nbjob run JOBCOMMAND -log $MT_LINKTREE/$MT_TARGET/$MT_RUNNAME.$MT_TESTNAME-$MT_ITEM_PATH.lgo ;; ;; [host-rules] ;; # maxnload => max normalized load ;; # maxnjobs => max jobs per cpu ;; # maxjobrate => max jobs per second ;; general maxnload=1.1; maxnjobs=1.2; maxjobrate=0.1 ;; ;; [launchers] ;; envsetup general ;; xor/%/n 4C16G ;; % nbgeneral ;; ;; [jobtools] |
︙ | ︙ | |||
2245 2246 2247 2248 2249 2250 2251 | (begin (debug:print-info 2 *default-log-port* "Have flexi-launcher match for " testname "/" itempath " = " host-type) (let ((launcher (configf:lookup configdat "host-types" host-type))) (if launcher (let* ((launcher-parts (string-split launcher)) (launcher-exe (car launcher-parts))) (if (equal? launcher-exe "#MTLOWESTLOAD") ;; this is our special case, we will find the lowest load and craft a nbfake commandline | | > > | > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985 2986 2987 2988 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005 3006 3007 3008 3009 3010 3011 3012 3013 3014 3015 3016 3017 3018 3019 3020 3021 3022 3023 3024 3025 3026 3027 3028 3029 3030 3031 3032 3033 3034 3035 3036 3037 3038 3039 3040 3041 3042 3043 3044 3045 3046 3047 3048 3049 3050 3051 3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066 3067 3068 3069 3070 3071 3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090 3091 3092 3093 3094 3095 3096 3097 3098 3099 3100 3101 3102 3103 3104 3105 3106 3107 3108 3109 3110 3111 3112 3113 3114 3115 3116 3117 3118 3119 3120 3121 3122 3123 3124 3125 3126 3127 3128 3129 3130 3131 3132 3133 3134 3135 3136 3137 3138 3139 3140 3141 3142 3143 3144 3145 3146 3147 3148 3149 3150 3151 3152 3153 3154 3155 3156 3157 3158 3159 3160 3161 3162 3163 3164 3165 3166 3167 3168 3169 3170 3171 3172 3173 3174 3175 3176 3177 3178 3179 3180 3181 3182 3183 3184 3185 3186 3187 3188 3189 3190 3191 3192 3193 3194 3195 3196 3197 3198 3199 3200 3201 3202 3203 3204 3205 3206 3207 3208 3209 3210 3211 3212 3213 3214 3215 3216 3217 3218 3219 3220 3221 3222 3223 3224 3225 3226 3227 3228 3229 3230 3231 3232 3233 3234 3235 3236 3237 3238 3239 3240 3241 3242 3243 3244 3245 3246 3247 3248 3249 3250 3251 3252 3253 3254 3255 3256 3257 3258 3259 3260 3261 3262 3263 3264 3265 3266 3267 3268 3269 3270 3271 3272 3273 3274 3275 3276 3277 3278 3279 3280 3281 3282 3283 3284 3285 3286 3287 3288 3289 3290 3291 3292 3293 3294 3295 3296 3297 3298 3299 3300 3301 3302 3303 3304 3305 3306 3307 3308 3309 3310 3311 3312 3313 3314 3315 3316 3317 3318 3319 3320 3321 3322 3323 3324 3325 3326 3327 3328 3329 3330 3331 3332 3333 3334 3335 3336 3337 3338 3339 3340 3341 3342 3343 3344 3345 3346 3347 3348 | (begin (debug:print-info 2 *default-log-port* "Have flexi-launcher match for " testname "/" itempath " = " host-type) (let ((launcher (configf:lookup configdat "host-types" host-type))) (if launcher (let* ((launcher-parts (string-split launcher)) (launcher-exe (car launcher-parts))) (if (equal? launcher-exe "#MTLOWESTLOAD") ;; this is our special case, we will find the lowest load and craft a nbfake commandline (let host-loop ((targ-host (common:get-least-loaded-host (cdr launcher-parts) host-type configdat)) (count 100)) (if targ-host (conc "remrun " targ-host) (if (> count 0) (begin (debug:print 0 *default-log-port* "INFO: Waiting for a host for host-type " host-type) (thread-sleep! (- 101 count)) (host-loop (common:get-least-loaded-host (cdr launcher-parts) host-type configdat) (- count 1))) (begin (debug:print 0 *default-log-port* "FATAL: Failed to find a host from #MTLOWESTLOAD for host-type " host-type) (exit))))) launcher)) (begin (debug:print-info 0 *default-log-port* "WARNING: no launcher found for host-type " host-type) (if (null? tal) fallback-launcher (loop (car tal)(cdr tal))))))) ;; no match, try again (if (null? tal) fallback-launcher (loop (car tal)(cdr tal)))))))) fallback-launcher))) ;;====================================================================== ;; NMSG AND NEW API ;;====================================================================== ;; nm based server experiment, keep around for now. ;; (define (nm:start-server dbconn #!key (given-host-name #f)) (let* ((srvdat (start-raw-server given-host-name: given-host-name)) (host-name (srvdat-host srvdat)) (soc (srvdat-soc srvdat))) ;; start the queue processor (save for second round of development) ;; (thread-start! (make-thread! (lambda ()(queue-processor dbconn) "Queue processor"))) ;; msg is an alist ;; 'r host:port <== where to return the data ;; 'p params <== data to apply the command to ;; 'e j|s|l <== encoding of the params. default is s (sexp), if not specified is assumed to be default ;; 'c command <== look up the function to call using this key ;; (let loop ((msg-in (nn-recv soc))) (if (not (equal? msg-in "quit")) (let* ((dat (decode msg-in)) (host-port (alist-ref 'r dat)) ;; this is for the reverse req rep where the server is a client of the original client (params (alist-ref 'p dat)) (command (let ((c (alist-ref 'c dat)))(if c (string->symbol c) #f))) (all-good (and host-port params command (hash-table-exists? *commands* command)))) (if all-good (let ((cmddat (make-qitem command: command host-port: host-port params: params))) (queue-push cmddat) ;; put request into the queue (nn-send soc "queued")) ;; reply with "queued" (print "ERROR: ["(common:human-time)"] BAD request " dat)) (loop (nn-recv soc))))) (nn-close soc))) ;;====================================================================== ;; D A S H B O A R D U S E R V I E W S ;;====================================================================== ;; first read ~/views.config if it exists, then read $MTRAH/views.config if it exists ;; (define (common:load-views-config) (let* ((view-cfgdat (make-hash-table)) (home-cfgfile (conc (get-environment-variable "HOME") "/.mtviews.config")) (mthome-cfgfile (conc *toppath* "/.mtviews.config"))) (if (common:file-exists? mthome-cfgfile) (read-config mthome-cfgfile view-cfgdat #t)) ;; we load the home dir file AFTER the MTRAH file so the user can clobber settings when running the dashboard in read-only areas (if (common:file-exists? home-cfgfile) (read-config home-cfgfile view-cfgdat #t)) view-cfgdat)) ;;====================================================================== ;; H I E R A R C H I C A L H A S H T A B L E S ;;====================================================================== ;; Every element including top element is a vector: ;; <vector subhash value> (define (hh:make-hh #!key (ht #f)(value #f)) (vector (or ht (make-hash-table)) value)) ;; used internally (define-inline (hh:set-ht! hh ht) (vector-set! hh 0 ht)) (define-inline (hh:get-ht hh) (vector-ref hh 0)) (define-inline (hh:set-value! hh value) (vector-set! hh 1 value)) (define-inline (hh:get-value hh value) (vector-ref hh 1)) ;; given a hierarchial hash and some keys look up the value ... ;; (define (hh:get hh . keys) (if (null? keys) (vector-ref hh 1) ;; we have reached the end of the line, return the value sought (let ((sub-ht (hh:get-ht hh))) (if sub-ht ;; yes, there is more hierarchy (let ((sub-hh (hash-table-ref/default sub-ht (car keys) #f))) (if sub-hh (apply hh:get sub-hh (cdr keys)) #f)) #f)))) ;; given a hierarchial hash, a value and some keys, add needed hierarcy and insert the value ;; (define (hh:set! hh value . keys) (if (null? keys) (hh:set-value! hh value) ;; we have reached the end of the line, store the value (let ((sub-ht (hh:get-ht hh))) (if sub-ht ;; yes, there is more hierarchy (let ((sub-hh (hash-table-ref/default sub-ht (car keys) #f))) (if (not sub-hh) ;; we'll need to add the next level of hierarchy (let ((new-sub-hh (hh:make-hh))) (hash-table-set! sub-ht (car keys) new-sub-hh) (apply hh:set! new-sub-hh value (cdr keys))) (apply hh:set! sub-hh value (cdr keys)))) ;; call the sub-hierhash with remaining keys (begin (hh:set-ht! hh (make-hash-table)) (apply hh:set! hh value keys)))))) ;; Manage pkts, used in servers, tests and likely other contexts so put ;; in common ;;====================================================================== (define common:pkts-spec '((default . ((parent . P) (action . a) (filename . f))) (configf . ((parent . P) (action . a) (filename . f))) (server . ((action . a) (pid . d) (ipaddr . i) (port . p) (parent . P))) (test . ((cpuuse . c) (diskuse . d) (item-path . i) (runname . r) (state . s) (target . t) (status . u) (parent . P))))) (define (common:get-pkts-dirs mtconf use-lt) (let* ((pktsdirs-str (or (configf:lookup mtconf "setup" "pktsdirs") (and use-lt (conc (or *toppath* (current-directory)) "/lt/.pkts")))) (pktsdirs (if pktsdirs-str (string-split pktsdirs-str " ") #f))) pktsdirs)) ;; use-lt is use linktree "lt" link to find pkts dir (define (common:save-pkt pktalist-in mtconf use-lt #!key (add-only #f)) ;; add-only saves the pkt only if there is a parent already (if (or add-only (hash-table-exists? *pkts-info* 'last-parent)) (let* ((parent (hash-table-ref/default *pkts-info* 'last-parent #f)) (pktalist (if parent (cons `(parent . ,parent) pktalist-in) pktalist-in))) (let-values (((uuid pkt) (alist->pkt pktalist common:pkts-spec))) (hash-table-set! *pkts-info* 'last-parent uuid) (let ((pktsdir (or (hash-table-ref/default *pkts-info* 'pkts-dir #f) (let* ((pktsdirs (common:get-pkts-dirs mtconf use-lt)) (pktsdir (car pktsdirs))) ;; assume it is there (hash-table-set! *pkts-info* 'pkts-dir pktsdir) pktsdir)))) (handle-exceptions exn (debug:print-info 0 "failed to write out packet to " pktsdir) ;; don't care if this failed for now but MUST FIX - BUG!! (if (not (file-exists? pktsdir)) (create-directory pktsdir #t)) (with-output-to-file (conc pktsdir "/" uuid ".pkt") (lambda () (print pkt))))))))) (define (common:with-queue-db mtconf proc #!key (use-lt #f)(toppath-in #f)) (let* ((pktsdirs (common:get-pkts-dirs mtconf use-lt)) (pktsdir (if pktsdirs (car pktsdirs) #f)) (toppath (or (configf:lookup mtconf "scratchdat" "toppath") toppath-in)) (pdbpath (or (configf:lookup mtconf "setup" "pdbpath") pktsdir))) (cond ((not (and pktsdir toppath pdbpath)) (debug:print 0 *default-log-port* "ERROR: settings are missing in your megatest.config for area management.") (debug:print 0 *default-log-port* " you need to have pktsdirs in the [setup] section.")) ((not (common:file-exists? pktsdir)) (debug:print 0 *default-log-port* "ERROR: pkts directory not found " pktsdir)) ((not (equal? (file-owner pktsdir)(current-effective-user-id))) (debug:print 0 *default-log-port* "ERROR: directory " pktsdir " is not owned by " (current-effective-user-name))) (else (let* ((pdb (open-queue-db pdbpath "pkts.db" schema: '("CREATE TABLE groups (id INTEGER PRIMARY KEY,groupname TEXT, CONSTRAINT group_constraint UNIQUE (groupname));")))) (proc pktsdirs pktsdir pdb) (dbi:close pdb)))))) (define (common:load-pkts-to-db mtconf #!key (use-lt #f)) (common:with-queue-db mtconf (lambda (pktsdirs pktsdir pdb) (for-each (lambda (pktsdir) ;; look at all (cond ((not (common:file-exists? pktsdir)) (debug:print 0 *default-log-port* "ERROR: packets directory " pktsdir " does not exist.")) ((not (directory? pktsdir)) (debug:print 0 *default-log-port* "ERROR: packets directory path " pktsdir " is not a directory.")) ((not (file-read-access? pktsdir)) (debug:print 0 *default-log-port* "ERROR: packets directory path " pktsdir " is not readable.")) (else (debug:print-info 0 *default-log-port* "Loading packets found in " pktsdir) (let ((pkts (glob (conc pktsdir "/*.pkt")))) (for-each (lambda (pkt) (let* ((uuid (cadr (string-match ".*/([0-9a-f]+).pkt" pkt))) (exists (lookup-by-uuid pdb uuid #f))) (if (not exists) (let* ((pktdat (string-intersperse (with-input-from-file pkt read-lines) "\n")) (apkt (pkt->alist pktdat)) (ptype (alist-ref 'T apkt))) (add-to-queue pdb pktdat uuid (or ptype 'cmd) #f 0) (debug:print 4 *default-log-port* "Added " uuid " of type " ptype " to queue")) (debug:print 4 *default-log-port* "pkt: " uuid " exists, skipping...") ))) pkts))))) pktsdirs)) use-lt: use-lt)) (define (common:get-pkt-alists pkts) (map (lambda (x) (alist-ref 'apkt x)) ;; 'pkta pulls out the alist from the read pkt pkts)) ;; given list of pkts (alist mode) return list of D cards as Unix epoch, sorted descending ;; also delete duplicates by target i.e. (car pkt) ;; (define (common:get-pkt-times pkts) (delete-duplicates (sort (map (lambda (x) `(,(alist-ref 't x) . ,(string->number (alist-ref 'D x)))) pkts) (lambda (a b)(> (cdr a)(cdr b)))) ;; sort descending (lambda (a b)(equal? (car a)(car b))))) ;; remove duplicates by target ;; accept an alist or hash table containing envvar/env value pairs (value of #f causes unset) ;; execute thunk in context of environment modified as per this list ;; restore env to prior state then return value of eval'd thunk. ;; ** this is not thread safe ** (define (common:with-env-vars delta-env-alist-or-hash-table thunk) (let* ((delta-env-alist (if (hash-table? delta-env-alist-or-hash-table) (hash-table->alist delta-env-alist-or-hash-table) delta-env-alist-or-hash-table)) (restore-thunks (filter identity (map (lambda (env-pair) (let* ((env-var (car env-pair)) (new-val (let ((tmp (cdr env-pair))) (if (list? tmp) (car tmp) tmp))) (current-val (get-environment-variable env-var)) (restore-thunk (cond ((not current-val) (lambda () (unsetenv env-var))) ((not (string? new-val)) #f) ((eq? current-val new-val) #f) (else (lambda () (setenv env-var current-val)))))) ;;(when (not (string? new-val)) ;; (debug:print 0 *default-log-port* " PROBLEM: not a string: "new-val"\n from env-alist:\n"delta-env-alist) ;; (pp delta-env-alist) ;; (exit 1)) (cond ((not new-val) ;; modify env here (unsetenv env-var)) ((string? new-val) (setenv env-var new-val))) restore-thunk)) delta-env-alist)))) (let ((rv (thunk))) (for-each (lambda (x) (x)) restore-thunks) ;; restore env to original state rv))) (define *common:thread-punchlist* (make-hash-table)) (define (common:send-thunk-to-background-thread thunk #!key (name #f)) ;;(BB> "launched thread " name) ;; we need a unique name for the thread. (let* ((realname (if name (if (not (hash-table-ref/default *common:thread-punchlist* name #f)) name (conc name"-" (symbol->string (gensym)))) (conc "anonymous-"(symbol->string (gensym))))) (realthunk (lambda () (let ((res (thunk))) (hash-table-delete! *common:thread-punchlist* realname) res))) (thread (make-thread realthunk realname))) (hash-table-set! *common:thread-punchlist* realname thread) (thread-start! thread) )) (define (common:join-backgrounded-threads) ;; may need to trap and ignore exceptions -- dunno how atomic threads are... (for-each (lambda (thread-name) (let* ((thread (hash-table-ref/default *common:thread-punchlist* thread-name #f))) (if thread (handle-exceptions exn #t ;; just ignore it, it might have died in the meantime so joining it will throw an exception (thread-join! thread)) ))) (hash-table-keys *common:thread-punchlist*))) (define *common:telemetry-log-state* 'startup) (define *common:telemetry-log-socket* #f) (define (common:telemetry-log-open) (if (eq? *common:telemetry-log-state* 'startup) (let* ((serverhost (configf:lookup *configdat* "telemetry" "host")) (serverport (configf:lookup-number *configdat* "telemetry" "port")) (user (or (get-environment-variable "USER") "unknown")) (host (or (get-environment-variable "HOST") "unknown"))) (set! *common:telemetry-log-state* (handle-exceptions exn (begin (debug:print-info 0 *default-log-port* "common-telemetry-log open udp port failure") 'broken) (if (and serverhost serverport user host) (let* ((s (udp-open-socket))) ;;(udp-bind! s #f 0) (udp-connect! s serverhost serverport) (set! *common:telemetry-log-socket* s) 'open) 'not-needed)))))) (define (common:telemetry-log event #!key (payload '())) (if (eq? *common:telemetry-log-state* 'startup) (common:telemetry-log-open)) (if (eq? 'open *common:telemetry-log-state*) (handle-exceptions exn (begin (debug:print-info 0 *default-log-port* "common-telemetry-log comms failure ; disabled (no server?)") ;;(define *common:telemetry-log-state* 'broken-or-no-server-preclose) ;;(common:telemetry-log-close) (define *common:telemetry-log-state* 'broken-or-no-server) (set! *common:telemetry-log-socket* #f) ) (if (and *common:telemetry-log-socket* event) ;; TODO - filter on event against telemetry.want-events (let* ((user (or (get-environment-variable "USER") "unknown")) (host (or (get-environment-variable "HOST") "unknown")) (start (conc "[megatest "event"]")) (toppath (or *toppath* "/dev/null")) (payload-serialized (base64:base64-encode (z3:encode-buffer (with-output-to-string (lambda () (pp payload)))))) (msg (conc user":"host":"start":"(current-process-id)":"(car (argv))":" toppath":"payload-serialized))) (udp-send *common:telemetry-log-socket* msg)))))) (define (common:telemetry-log-close) (when (or (member *common:telemetry-log-state* '(broken-or-no-server-preclose open)) *common:telemetry-log-socket*) (handle-exceptions exn (begin (define *common:telemetry-log-state* 'closed-fail) (debug:print-info 0 *default-log-port* "common-telemetry-log closure failure") ) (begin (define *common:telemetry-log-state* 'closed) (udp-close-socket *common:telemetry-log-socket*) (set! *common:telemetry-log-socket* #f))))) |
Modified common_records.scm from [0a5321af09] to [72d272b34e].
1 2 3 | ;;====================================================================== ;; Copyright 2006-2012, Matthew Welland. ;; | | | > > > > > | | > | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | ;;====================================================================== ;; Copyright 2006-2012, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. ;; ;;====================================================================== ;; (use trace) (include "altdb.scm") ;; Some of these routines use: |
︙ | ︙ | |||
145 146 147 148 149 150 151 | (lambda (frame) (let* ((this-loc (vector-ref frame 0)) (temp (string-split (->string this-loc) " ")) (this-func (if (and (list? temp) (> (length temp) 1)) (cadr temp) "???"))) (if (equal? this-func "BB>") (set! location this-loc)))) stack) | > > | | | | | | 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 | (lambda (frame) (let* ((this-loc (vector-ref frame 0)) (temp (string-split (->string this-loc) " ")) (this-func (if (and (list? temp) (> (length temp) 1)) (cadr temp) "???"))) (if (equal? this-func "BB>") (set! location this-loc)))) stack) (let* ((color-on "\x1b[1m") (color-off "\x1b[0m") (dp-args (append (list 0 *default-log-port* (conc color-on location "@"(/ (- (current-milliseconds) *BB-process-starttime*) 1000) color-off " ") ) in-args))) (apply debug:print dp-args)))) (define *BBpp_custom_expanders_list* (make-hash-table)) ;; register hash tables with BBpp. |
︙ | ︙ |
Added commonmod.scm version [c7972f9b4b].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | ;;====================================================================== ;; Copyright 2017, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. ;;====================================================================== (declare (unit commonmod)) (module commonmod * (import scheme chicken data-structures extras) (import (prefix sqlite3 sqlite3:) posix typed-records srfi-18) ;; (define (debug:print . params) #f) ;; (define (debug:print-info . params) #f) ;; ;; (define (set-functions dbgp dbgpinfo) ;; (set! debug:print dbgp) ;; (set! debug:print-info dbgpinfo)) ) |
Modified commonstructs from [23969b59c2] to [58a665f886].
1 2 3 4 5 6 7 | The database keys, runs are indexed on this keys: (db:get-keys #f) => (#("OS" "TEXT") #("FS" "TEXT") #("TAG" "TEXT")) | > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. The database keys, runs are indexed on this keys: (db:get-keys #f) => (#("OS" "TEXT") #("FS" "TEXT") #("TAG" "TEXT")) |
︙ | ︙ |
Modified configf.scm from [1be6cc85e3] to [dfa800e4cf].
1 2 3 | ;;====================================================================== ;; Copyright 2006-2012, Matthew Welland. ;; | | | > > > > > | | > > > > | | | | > > > | | | | | | | | > > > > | | | | > | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 | ;;====================================================================== ;; Copyright 2006-2012, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. ;;====================================================================== ;;====================================================================== ;; Config file handling ;;====================================================================== (use regex regex-case matchable) ;; directory-utils) (declare (unit configf)) (declare (uses process)) (declare (uses env)) (declare (uses keys)) (include "common_records.scm") ;; return list (path fullpath configname) (define (find-config configname #!key (toppath #f)) (if toppath (let ((cfname (conc toppath "/" configname))) (if (common:file-exists? cfname) (list toppath cfname configname) (list #f #f #f))) (let* ((cwd (string-split (current-directory) "/"))) (let loop ((dir cwd)) (let* ((path (conc "/" (string-intersperse dir "/"))) (fullpath (conc path "/" configname))) (if (common:file-exists? fullpath) (list path fullpath configname) (let ((remcwd (take dir (- (length dir) 1)))) (if (null? remcwd) (list #f #f #f) ;; #f #f) (loop remcwd))))))))) (define (config:assoc-safe-add alist key val #!key (metadata #f)) (let ((newalist (filter (lambda (x)(not (equal? key (car x)))) alist))) (append newalist (list (if metadata (list key val metadata) (list key val)))))) (define (configf:section-var-set! cfgdat section-name var value #!key (metadata #f)) (hash-table-set! cfgdat section-name (config:assoc-safe-add (hash-table-ref/default cfgdat section-name '()) var value metadata: metadata))) (define (config:eval-string-in-environment str) ;; (if (or (string-null? str) ;; (equal? "!" (substring str 0 1))) ;; null string or starts with ! are preserved but NOT set in the environment str (handle-exceptions exn (begin (debug:print-error 0 *default-log-port* "problem evaluating \"" str "\" in the shell environment") #f) (let ((cmdres (process:cmd-run->list (conc "echo " str)))) (if (null? cmdres) "" (caar cmdres))))) ;; ) ;;====================================================================== ;; Make the regexp's needed globally available ;;====================================================================== (define configf:include-rx (regexp "^\\[include\\s+(.*)\\]\\s*$")) (define configf:script-rx (regexp "^\\[scriptinc\\s+(\\S+)([^\\]]*)\\]\\s*$")) ;; include output from a script (define configf:section-rx (regexp "^\\[(.*)\\]\\s*$")) (define configf:blank-l-rx (regexp "^\\s*$")) (define configf:key-sys-pr (regexp "^(\\S+)\\s+\\[system\\s+(\\S+.*)\\]\\s*$")) (define configf:key-val-pr (regexp "^(\\S+)(\\s+(.*)|())$")) (define configf:key-no-val (regexp "^(\\S+)(\\s*)$")) (define configf:comment-rx (regexp "^\\s*#.*")) (define configf:cont-ln-rx (regexp "^(\\s+)(\\S+.*)$")) (define configf:settings (regexp "^\\[configf:settings\\s+(\\S+)\\s+(\\S+)]\\s*$")) ;; read a line and process any #{ ... } constructs (define configf:var-expand-regex (regexp "^(.*)#\\{(scheme|system|shell|getenv|get|runconfigs-get|rget|scm|sh|rp|gv|g|mtrah)\\s+([^\\}\\{]*)\\}(.*)")) (define (configf:system ht cmd) (system cmd) ) (define (configf:process-line l ht allow-system #!key (linenum #f)) (let loop ((res l)) (if (string? res) (let ((matchdat (string-search configf:var-expand-regex res))) (if matchdat (let* ((prestr (list-ref matchdat 1)) (cmdtype (list-ref matchdat 2)) ;; eval, system, shell, getenv (cmd (list-ref matchdat 3)) (poststr (list-ref matchdat 4)) (result #f) (start-time (current-seconds)) (cmdsym (string->symbol cmdtype)) (fullcmd (case cmdsym ((scheme scm) (conc "(lambda (ht)" cmd ")")) ((system) (conc "(lambda (ht)(configf:system ht \"" cmd "\"))")) ((shell sh) (conc "(lambda (ht)(string-translate (shell \"" cmd "\") \"\n\" \" \"))")) ((realpath rp)(conc "(lambda (ht)(common:nice-path \"" cmd "\"))")) ((getenv gv) (conc "(lambda (ht)(get-environment-variable \"" cmd "\"))")) ((mtrah) (conc "(lambda (ht)" " (let ((extra \"" cmd "\"))" " (conc (or *toppath* (get-environment-variable \"MT_RUN_AREA_HOME\"))" " (if (string-null? extra) \"\" \"/\")" " extra)))")) ((get g) (match (string-split cmd) ((sect var)(conc "(lambda (ht)(configf:lookup ht \"" sect "\" \"" var "\"))")) (else (debug:print-error 0 *default-log-port* "#{get ...} used with only one parameter, \"" cmd "\", two needed.") "(lambda (ht) #f)"))) ((runconfigs-get rget) (conc "(lambda (ht)(runconfigs-get ht \"" cmd "\"))")) ;; ((rget) (conc "(lambda (ht)(runconfigs-get ht \"" cmd "\"))")) (else "(lambda (ht)(print \"ERROR\") \"ERROR\")")))) ;; (print "fullcmd=" fullcmd) (handle-exceptions exn (begin |
︙ | ︙ | |||
174 175 176 177 178 179 180 | inl) (else (configf:process-line inl ht allow-processing))))) (if (and (string? res) (not (equal? (hash-table-ref/default settings "trim-trailing-spaces" "no") "no"))) (string-substitute "\\s+$" "" res) res)))))) | | > > > > > > > > > > > > > > > > | 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 | inl) (else (configf:process-line inl ht allow-processing))))) (if (and (string? res) (not (equal? (hash-table-ref/default settings "trim-trailing-spaces" "no") "no"))) (string-substitute "\\s+$" "" res) res)))))) (define (configf:cfgdat->env-alist section cfgdat-ht allow-system) (filter (lambda (pair) (let* ((var (car pair)) (val (cdr pair))) (cons var (cond ((and allow-system (procedure? val)) ;; if we decided to use something other than #t or #f for allow-system ('return-procs or 'return-string) , this may become problematic (val)) ((procedure? val) #f) ((string? val) val) (else "#f"))))) (append (hash-table-ref/default cfgdat-ht "default" '()) (if (equal? section "default") '() (hash-table-ref/default cfgdat-ht section '()))))) (define (calc-allow-system allow-system section sections) (if sections (and (or (equal? "default" section) (member section sections)) allow-system) ;; account for sections and return allow-system as it might be a symbol such as return-strings allow-system)) |
︙ | ︙ | |||
215 216 217 218 219 220 221 222 223 224 225 226 227 | (hash-table-keys ht)))) ht) ;; read a config file, returns hash table of alists ;; read a config file, returns hash table of alists ;; adds to ht if given (must be #f otherwise) ;; envion-patt is a regex spec that identifies sections that will be eval'd ;; in the environment on the fly ;; sections: #f => get all, else list of sections to gather ;; post-section-procs alist of section-pattern => proc, where: (proc section-name next-section-name ht curr-path) ;; apply-wildcards: #t/#f - apply vars from targets with % wildcards to all matching sections ;; | > > > > > | | > > > > > > > | | 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 | (hash-table-keys ht)))) ht) ;; read a config file, returns hash table of alists ;; read a config file, returns hash table of alists ;; adds to ht if given (must be #f otherwise) ;; allow-system: ;; #f - do not evaluate [system ;; #t - immediately evaluate [system and store result as string ;; 'return-procs -- return a proc taking ht as an argument that may be evaulated at some future time ;; 'return-string -- return a string representing a proc taking ht as an argument that may be evaulated at some future time ;; envion-patt is a regex spec that identifies sections that will be eval'd ;; in the environment on the fly ;; sections: #f => get all, else list of sections to gather ;; post-section-procs alist of section-pattern => proc, where: (proc section-name next-section-name ht curr-path) ;; apply-wildcards: #t/#f - apply vars from targets with % wildcards to all matching sections ;; (define (read-config path ht allow-system #!key (environ-patt #f) (curr-section #f) (sections #f) (settings (make-hash-table)) (keep-filenames #f) (post-section-procs '()) (apply-wildcards #t) ) (debug:print 9 *default-log-port* "START: " path) ;; (if *configdat* ;; (common:save-pkt `((action . read-config) ;; (f . ,(cond ((string? path) path) ;; ((port? path) "port") ;; (else (conc path)))) ;; (T . configf)) ;; *configdat* #t add-only: #t)) (if (and (not (port? path)) (not (common:file-exists? path))) ;; for case where we are handed a port (begin (debug:print-info 1 *default-log-port* "read-config - file not found " path " current path: " (current-directory)) ;; WARNING: This is a risky change but really, we should not return an empty hash table if no file read? #f) ;; (if (not ht)(make-hash-table) ht)) (let ((inp (if (string? path) (open-input-file path) path)) ;; we can be handed a port |
︙ | ︙ | |||
263 264 265 266 267 268 269 | (if (list? sections) ;; delete all sections except given when sections is provided (for-each (lambda (section) (if (not (member section sections)) (hash-table-delete! res section))) ;; we are using "" as a dumping ground and must remove it before returning the ht (hash-table-keys res))) (debug:print 9 *default-log-port* "END: " path) | | > | > > | > | > | | > > | > | | | | | | | > | | > > > > | | > | < > > | < < < | | > > > > > > | | | | | | | | | | | > | | | | | | | | | | | > | | | | | | | | > | | | > > | | | | | | | | | | | | | | | | | | | | | | | | > | > > > > | | | | | | > | > > > | > | > > > > > | | | | | | | | > | > | > | | | | | | | | | | | | | | > > | | > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > | 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 | (if (list? sections) ;; delete all sections except given when sections is provided (for-each (lambda (section) (if (not (member section sections)) (hash-table-delete! res section))) ;; we are using "" as a dumping ground and must remove it before returning the ht (hash-table-keys res))) (debug:print 9 *default-log-port* "END: " path) res ) ;; retval (regex-case inl (configf:comment-rx _ (loop (configf:read-line inp res (calc-allow-system allow-system curr-section-name sections) settings) curr-section-name #f #f)) (configf:blank-l-rx _ (loop (configf:read-line inp res (calc-allow-system allow-system curr-section-name sections) settings) curr-section-name #f #f)) (configf:settings ( x setting val ) (begin (hash-table-set! settings setting val) (loop (configf:read-line inp res (calc-allow-system allow-system curr-section-name sections) settings) curr-section-name #f #f))) (configf:include-rx ( x include-file ) (let* ((curr-conf-dir (pathname-directory path)) (full-conf (if (and (absolute-pathname? include-file) (file-exists? include-file)) include-file (common:nice-path (conc (if curr-conf-dir curr-conf-dir ".") "/" include-file))))) (let ((all-matches (sort (handle-exceptions exn (list) (glob full-conf)) string<=?))) (if (null? all-matches) (begin (debug:print '(2 9) #f "INFO: include file(s) matching " include-file " not found (called from " path ")") (debug:print 2 *default-log-port* " " full-conf)) (for-each (lambda (fpath) ;; (push-directory conf-dir) (debug:print 9 *default-log-port* "Including: " full-conf) (read-config fpath res allow-system environ-patt: environ-patt curr-section: curr-section-name sections: sections settings: settings keep-filenames: keep-filenames)) all-matches)) (loop (configf:read-line inp res (calc-allow-system allow-system curr-section-name sections) settings) curr-section-name #f #f)))) (configf:script-rx ( x include-script params);; handle-exceptions ;; exn ;; (begin ;; (debug:print '(0 2 9) #f "INFO: include from script " include-script " failed.") ;; (loop (configf:read-line inp res (calc-allow-system allow-system curr-section-name sections) settings) curr-section-name #f #f)) (if (and (common:file-exists? include-script)(file-execute-access? include-script)) (let* ((local-allow-system (calc-allow-system allow-system curr-section-name sections)) (env-delta (configf:cfgdat->env-alist curr-section-name res local-allow-system)) (new-inp-port (common:with-env-vars env-delta (lambda () (open-input-pipe (conc include-script " " params)))))) (debug:print '(2 9) *default-log-port* "Including from script output: " include-script) ;; (print "We got here, calling read-config next. Port is: " new-inp-port) (read-config new-inp-port res allow-system environ-patt: environ-patt curr-section: curr-section-name sections: sections settings: settings keep-filenames: keep-filenames) (close-input-port new-inp-port) (loop (configf:read-line inp res (calc-allow-system allow-system curr-section-name sections) settings) curr-section-name #f #f)) (begin (debug:print 0 *default-log-port* "Script not found or not exectutable: " include-script) (loop (configf:read-line inp res (calc-allow-system allow-system curr-section-name sections) settings) curr-section-name #f #f))) ) ;; ) (configf:section-rx ( x section-name ) (begin ;; call post-section-procs (for-each (lambda (dat) (let ((patt (car dat)) (proc (cdr dat))) (if (string-match patt curr-section-name) (proc curr-section-name section-name res path)))) post-section-procs) ;; after gathering the vars for a section and if apply-wildcards is true and if there is a wildcard in the section name process wildcards ;; NOTE: we are processing the curr-section-name, NOT section-name. (process-wildcards res curr-section-name) (if (not (hash-table-ref/default res section-name #f))(hash-table-set! res section-name '())) ;; ensure that mere mention of a section is not lost (loop (configf:read-line inp res (calc-allow-system allow-system curr-section-name sections) settings) ;; if we have the sections list then force all settings into "" and delete it later? ;; (if (or (not sections) ;; (member section-name sections)) ;; section-name "") ;; stick everything into "". NOPE: We need new strategy. Put stuff in correct sections and then delete all sections later. section-name #f #f))) (configf:key-sys-pr ( x key cmd ) (if (calc-allow-system allow-system curr-section-name sections) (let ((alist (hash-table-ref/default res curr-section-name '())) (val-proc (lambda () (let* ((start-time (current-seconds)) (local-allow-system (calc-allow-system allow-system curr-section-name sections)) (env-delta (configf:cfgdat->env-alist curr-section-name res local-allow-system)) (cmdres (process:cmd-run->list cmd delta-env-alist-or-hash-table: env-delta)) ;; BB: here is where [system is exec'd. needs to have env from other vars! (delta (- (current-seconds) start-time)) (status (cadr cmdres)) (res (car cmdres))) (debug:print-info 4 *default-log-port* "" inl "\n => " (string-intersperse res "\n")) (if (not (eq? status 0)) (begin (debug:print-error 0 *default-log-port* "problem with " inl ", return code " status " output: " cmdres))) (if (> delta 2) (debug:print-info 0 *default-log-port* "for line \"" inl "\"\n command: " cmd " took " delta " seconds to run with output:\n " res) (debug:print-info 9 *default-log-port* "for line \"" inl "\"\n command: " cmd " took " delta " seconds to run with output:\n " res)) (if (null? res) "" (string-intersperse res " ")))))) (hash-table-set! res curr-section-name (config:assoc-safe-add alist key (case (calc-allow-system allow-system curr-section-name sections) ((return-procs) val-proc) ((return-string) cmd) (else (val-proc))) metadata: metapath)) (loop (configf:read-line inp res (calc-allow-system allow-system curr-section-name sections) settings) curr-section-name #f #f)) (loop (configf:read-line inp res (calc-allow-system allow-system curr-section-name sections) settings) curr-section-name #f #f))) (configf:key-no-val ( x key val) (let* ((alist (hash-table-ref/default res curr-section-name '())) (fval (or (if (string? val) val #f) ""))) ;; fval should be either "" or " " (one or more spaces) (debug:print 10 *default-log-port* " setting: [" curr-section-name "] " key " = #t") (safe-setenv key fval) (hash-table-set! res curr-section-name (config:assoc-safe-add alist key fval metadata: metapath)) (loop (configf:read-line inp res (calc-allow-system allow-system curr-section-name sections) settings) curr-section-name key #f))) (configf:key-val-pr ( x key unk1 val unk2 ) (let* ((alist (hash-table-ref/default res curr-section-name '())) (envar (and environ-patt (string-search (regexp environ-patt) curr-section-name) ;; does the section match the envionpatt? (and (not (string-null? key)) (not (equal? "!" (substring key 0 1)))) ;; ! as leading character is a signature to NOT export to the environment ;; (string-match "^.*:.*:.*$" key) ;; ;; something:something:something reserved for triggers in runconfigs )) (realval (if envar (config:eval-string-in-environment val) val))) (debug:print-info 6 *default-log-port* "read-config env setting, envar: " envar " realval: " realval " val: " val " key: " key " curr-section-name: " curr-section-name) (if envar (safe-setenv key realval)) (debug:print 10 *default-log-port* " setting: [" curr-section-name "] " key " = " val) (hash-table-set! res curr-section-name (config:assoc-safe-add alist key realval metadata: metapath)) (loop (configf:read-line inp res (calc-allow-system allow-system curr-section-name sections) settings) curr-section-name key #f))) ;; if a continued line (configf:cont-ln-rx ( x whsp val ) (let ((alist (hash-table-ref/default res curr-section-name '()))) (if var-flag ;; if set to a string then we have a continued var (let ((newval (conc (configf:lookup res curr-section-name var-flag) "\n" ;; trim lead from the incoming whsp to support some indenting. (if lead (string-substitute (regexp lead) "" whsp) "") val))) ;; (print "val: " val "\nnewval: \"" newval "\"\nvarflag: " var-flag) (hash-table-set! res curr-section-name (config:assoc-safe-add alist var-flag newval metadata: metapath)) (loop (configf:read-line inp res (calc-allow-system allow-system curr-section-name sections) settings) curr-section-name var-flag (if lead lead whsp))) (loop (configf:read-line inp res (calc-allow-system allow-system curr-section-name sections) settings) curr-section-name #f #f)))) (else (debug:print-error 0 *default-log-port* "problem parsing " path ",\n \"" inl "\"") (set! var-flag #f) (loop (configf:read-line inp res (calc-allow-system allow-system curr-section-name sections) settings) curr-section-name #f #f)))) ) ;; end loop ))) ;; pathenvvar will set the named var to the path of the config (define (find-and-read-config fname #!key (environ-patt #f)(given-toppath #f)(pathenvvar #f)) (let* ((curr-dir (current-directory)) (configinfo (find-config fname toppath: given-toppath)) (toppath (car configinfo)) (configfile (cadr configinfo)) (set-fields (lambda (curr-section next-section ht path) (let ((field-names (if ht (common:get-fields ht) '())) (target (or (getenv "MT_TARGET")(args:get-arg "-reqtarg")(args:get-arg "-target")))) (debug:print-info 9 *default-log-port* "set-fields with field-names=" field-names " target=" target " curr-section=" curr-section " next-section=" next-section " path=" path " ht=" ht) (if (not (null? field-names))(keys:target-set-args field-names target #f)))))) (if toppath (change-directory toppath)) (if (and toppath pathenvvar)(setenv pathenvvar toppath)) (let ((configdat (if configfile (read-config configfile #f #t environ-patt: environ-patt post-section-procs: (list (cons "^fields$" set-fields)) #f)))) (if toppath (change-directory curr-dir)) (list configdat toppath configfile fname)))) (define (configf:lookup cfgdat section var) (if (hash-table? cfgdat) (let ((sectdat (hash-table-ref/default cfgdat section '()))) (if (null? sectdat) #f (let ((match (assoc var sectdat))) (if match ;; (and match (list? match)(> (length match) 1)) (cadr match) #f)) )) #f)) ;; use to have definitive setting: ;; [foo] ;; var yes ;; ;; (configf:var-is? cfgdat "foo" "var" "yes") => #t ;; (define (configf:var-is? cfgdat section var expected-val) (equal? (configf:lookup cfgdat section var) expected-val)) (define config-lookup configf:lookup) (define configf:read-file read-config) ;; safely look up a value that is expected to be a number, return ;; a default (#f unless provided) ;; (define (configf:lookup-number cfdat section varname #!key (default #f)) (let* ((val (configf:lookup *configdat* section varname)) (res (if val (string->number (string-substitute "\\s+" "" val #t)) #f))) (cond (res res) (val (debug:print 0 *default-log-port* "ERROR: no number found for [" section "], " varname ", got: " val)) (else default)))) (define (configf:section-vars cfgdat section) (let ((sectdat (hash-table-ref/default cfgdat section '()))) (if (null? sectdat) '() (map car sectdat)))) (define (configf:get-section cfgdat section) (hash-table-ref/default cfgdat section '())) (define (configf:set-section-var cfgdat section var val) (let ((sectdat (configf:get-section cfgdat section))) (hash-table-set! cfgdat section (config:assoc-safe-add sectdat var val)))) ;;(append (filter (lambda (x)(not (assoc var sectdat))) sectdat) ;; (list var val)))) (define (setup) (let* ((configf (find-config "megatest.config")) (config (if configf (read-config configf #f #t) #f))) (if config (setenv "RUN_AREA_HOME" (pathname-directory configf))) config)) |
︙ | ︙ | |||
485 486 487 488 489 490 491 | (res '())) (let ((newres (append res (list (string-substitute (regexp "\n") "\n " hed #t))))) (if (null? tal) newres (loop (car tal)(cdr tal) newres)))))) (define (configf:file->list fname) | | | 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 | (res '())) (let ((newres (append res (list (string-substitute (regexp "\n") "\n " hed #t))))) (if (null? tal) newres (loop (car tal)(cdr tal) newres)))))) (define (configf:file->list fname) (if (common:file-exists? fname) (let ((inp (open-input-file fname))) (let loop ((inl (read-line inp)) (res '())) (if (eof-object? inl) (begin (close-input-port inp) (reverse res)) |
︙ | ︙ | |||
515 516 517 518 519 520 521 | (fdat (configf:file->list fname)) (refdat (make-hash-table)) (sechash (make-hash-table)) ;; current section hash, init with hash for "default" section (new #f) ;; put the line to be used in new, if it is to be deleted the set new to #f (secname #f)) ;; step 2: Flatten multiline entries | | | | | 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 | (fdat (configf:file->list fname)) (refdat (make-hash-table)) (sechash (make-hash-table)) ;; current section hash, init with hash for "default" section (new #f) ;; put the line to be used in new, if it is to be deleted the set new to #f (secname #f)) ;; step 2: Flatten multiline entries (if (not (null? fdat))(set! fdat (configf:compress-multi-lines fdat))) ;; step 3: Modify values per contents of "indat" and remove absent values (if (not (null? fdat)) (let loop ((hed (car fdat)) (tal (cadr fdat)) (res '()) (lnum 0)) (regex-case hed (configf:comment-rx _ (set! res (append res (list hed)))) ;; (loop (read-line inp) curr-section-name #f #f)) (configf:blank-l-rx _ (set! res (append res (list hed)))) ;; (loop (read-line inp) curr-section-name #f #f)) (configf:section-rx ( x section-name ) (let ((section-hash (hash-table-ref/default refdat section-name #f))) (if (not section-hash) (let ((newhash (make-hash-table))) (hash-table-set! refdat section-name newhash) ;; was refhash - not sure that refdat is correct here (set! sechash newhash)) (set! sechash section-hash)) (set! new hed) ;; will append this at the bottom of the loop (set! secname section-name) )) ;; No need to process key cmd, let it fall though to key val (configf:key-val-pr ( x key val ) (let ((newval (configf:lookup indat secname key))) ;; was sec, bug or correct? ;; can handle newval == #f here => that means key is removed (cond ((equal? newval val) (set! res (append res (list hed)))) ((not newval) ;; key has been removed (set! new #f)) ((not (equal? newval val)) |
︙ | ︙ | |||
564 565 566 567 568 569 570 | ;; step 4: Append new values to the section (for-each (lambda (section) (let ((sdat '()) ;; append needed bits here (svars (configf:section-vars indat section))) (for-each (lambda (var) | | | | | 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 | ;; step 4: Append new values to the section (for-each (lambda (section) (let ((sdat '()) ;; append needed bits here (svars (configf:section-vars indat section))) (for-each (lambda (var) (let ((val (configf:lookup refdat section var))) (if (not val) ;; this one is new (begin (if (null? sdat)(set! sdat (list (conc "[" section "]")))) (set! sdat (append sdat (list (conc var " " val)))))))) svars) (set! fdat (append fdat sdat)))) (delete-duplicates (append required-sections (hash-table-keys indat)))) ;; step 5: Write out new file (with-output-to-file fname (lambda () (for-each (lambda (line) (print line)) (configf:expand-multi-lines fdat)))))) ;;====================================================================== ;; refdb ;;====================================================================== ;; reads a refdb into an assoc array of assoc arrays ;; returns (list dat msg) (define (configf:read-refdb refdb-path) (let ((sheets-file (conc refdb-path "/sheet-names.cfg"))) (if (not (common:file-exists? sheets-file)) (list #f (conc "ERROR: no refdb found at " refdb-path)) (if (not (file-read-access? sheets-file)) (list #f (conc "ERROR: refdb file not readable at " refdb-path)) (let* ((sheets (with-input-from-file sheets-file (lambda () (let loop ((inl (read-line)) (res '())) |
︙ | ︙ | |||
655 656 657 658 659 660 661 | (hash-table-set! ht (car section)(cdr section))) adat) ht)) ;; if (define (configf:read-alist fname) (handle-exceptions | | | | | | > | | | | | | | | | | | | | | | | | | < | | < < < | | 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 | (hash-table-set! ht (car section)(cdr section))) adat) ht)) ;; if (define (configf:read-alist fname) (handle-exceptions exn #f (configf:alist->config (with-input-from-file fname read)))) (define (configf:write-alist cdat fname) (if (not (common:faux-lock fname)) (debug:print 0 *default-log-port* "INFO: Could not get lock on " fname)) (let* ((dat (configf:config->alist cdat)) (res (begin (with-output-to-file fname ;; first write out the file (lambda () (pp dat))) (if (common:file-exists? fname) ;; now verify it is readable (if (configf:read-alist fname) #t ;; data is good. (begin (handle-exceptions exn #f (debug:print 0 *default-log-port* "WARNING: content " dat " for cache " fname " is not readable. Deleting generated file.") (delete-file fname)) #f)) #f)))) (common:faux-unlock fname) res)) ;; convert hierarchial list to ini format ;; (define (configf:config->ini data) (map (lambda (section) (let ((section-name (car section)) (section-dat (cdr section))) |
︙ | ︙ |
Deleted daemon.scm version [1e273ea0bb].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Added dashboard-context-menu.scm version [0a1e7c69d9].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 | ;;====================================================================== ;; Copyright 2006-2012, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. ;;====================================================================== ;;====================================================================== ;; implementation of context menu that pops up on ;; right click on test cell in Runs & Runs Summary Tabs ;;====================================================================== (use format fmt) (require-library iup) (import (prefix iup iup:)) (use canvas-draw) (use srfi-1 posix regex regex-case srfi-69) (use (prefix sqlite3 sqlite3:)) (declare (unit dashboard-context-menu)) (declare (uses common)) (declare (uses db)) (declare (uses gutils)) (declare (uses rmt)) (declare (uses ezsteps)) ;; (declare (uses sdb)) ;; (declare (uses filedb)) (declare (uses subrun)) (include "common_records.scm") (include "db_records.scm") (include "run_records.scm") (define (dboard:launch-testpanel run-id test-id) (let* (;; (cfg-sh (conc *common:this-exe-dir* "/cfg.sh")) ;; (cmd (conc ;; (if (common:file-exists? cfg-sh) ;; (conc "source "cfg-sh" && ") ;; "") ;; *common:this-exe-fullpath* ;; " -test " run-id "," test-id ;; " &")) (cmd (conc *common:this-exe-dir*"/../dashboard " "-test " run-id "," test-id " &"))) (system cmd))) (define (dashboard:run-menu-items run-id test-id target runname test-name testpatt item-test-path test-info) (list (iup:menu-item (conc "Rerun " testpatt) #:action (lambda (obj) ;; (print " run-id: " run-id " test-id: " test-id " target: " target " runname: " runname " test-name: " test-name " testpatt: " testpatt "item-path : " item-path) (common:run-a-command (conc "megatest -run -target " target " -runname " runname " -testpatt " testpatt " -preclean -clean-cache") ))) (iup:menu-item "Rerun Complete Run" #:action (lambda (obj) (common:run-a-command (conc "megatest -set-state-status NOT_STARTED,n/a -run -target " target " -runname " runname " -testpatt % " " -preclean -clean-cache")))) (iup:menu-item "Clean Complete Run" #:action (lambda (obj) (common:run-a-command (conc "megatest -remove-runs -target " target " -runname " runname " -testpatt % ")))) (iup:menu-item "Kill Complete Run" #:action (lambda (obj) (common:run-a-command (conc "megatest -set-state-status KILLREQ,n/a -target " target " -runname " runname " -testpatt % " " -state RUNNING,REMOTEHOSTSTART,LAUNCHED,NOT_STARTED")))) (iup:menu-item "Delete Run Data" #:action (lambda (obj) (common:run-a-command (conc "megatest -remove-runs -target " target " -runname " runname " -testpatt % " " -keep-records")))))) (define (dashboard:test-menu-items run-id test-id target runname test-name testpatt item-test-path test-info) (list (iup:menu-item (conc "Rerun " item-test-path) #:action (lambda (obj) (common:run-a-command (conc "megatest -set-state-status NOT_STARTED,n/a -run -target " target " -runname " runname " -testpatt " item-test-path " -preclean -clean-cache")))) (iup:menu-item (conc "Kill " item-test-path) #:action (lambda (obj) ;; (rmt:test-set-state-status-by-id run-id test-id "KILLREQ" #f #f) (common:run-a-command (conc "megatest -set-state-status KILLREQ,n/a -target " target " -runname " runname " -testpatt " item-test-path " -state RUNNING,REMOTEHOSTSTART,LAUNCHED")))) (iup:menu-item (conc "Delete data : " item-test-path) #:action (lambda (obj) (common:run-a-command (conc "megatest -remove-runs -target " target " -runname " runname " -testpatt " item-test-path " -keep-records")))) (iup:menu-item (conc "Clean "item-test-path) #:action (lambda (obj) (common:run-a-command (conc "megatest -remove-runs -target " target " -runname " runname " -testpatt " item-test-path)))) (iup:menu-item "Start xterm" #:action (lambda (obj) (dcommon:examine-xterm run-id test-id))) ;;(let* ((cmd (conc (car (argv)) " -xterm " run-id "," test-id "&"))) ;; (system cmd)))) (iup:menu-item "Edit testconfig" #:action (lambda (obj) (let* ((all-tests (tests:get-all)) (editor-rx (or (configf:lookup *configdat* "setup" "editor-regex") "\\b(vim?|nano|pico)\\b")) (editor (or (configf:lookup *configdat* "setup" "editor") (get-environment-variable "VISUAL") (get-environment-variable "EDITOR") "vi")) (tconfig (conc (hash-table-ref all-tests test-name) "/testconfig")) (cmd (conc (if (string-search editor-rx editor) (conc "xterm -e " editor) editor) " " tconfig " &"))) (system cmd)))))) (define (dashboard:step-logs-menu-item run-id test-id target runname test-name testpatt item-test-path test-info) (let* ((steps (tests:get-compressed-steps run-id test-id)) ;; #<stepname start end status Duration Logfile Comment id> (rundir (db:test-get-rundir test-info))) (iup:menu-item "Step logs" (apply iup:menu (map (lambda (step) (let ((stepname (vector-ref step 0)) (logfile (vector-ref step 5)) (status (vector-ref step 3))) (iup:menu-item (conc stepname "/" (if (string=? logfile "") "no log!" logfile) " (" status ")") #:action (lambda (obj) (let ((fullfile (conc rundir "/" logfile))) (if (common:file-exists? fullfile) (dcommon:run-html-viewer fullfile) (message-window (conc "file " fullfile " not found")))))))) steps))))) (define (dashboard:toplevel-menu-items run-id test-id target runname test-name testpatt item-test-path test-info) (list (iup:menu-item "Test Control Panel" #:action (lambda (obj) (dboard:launch-testpanel run-id test-id))) (dashboard:step-logs-menu-item run-id test-id target runname test-name testpatt item-test-path test-info) (iup:menu-item (conc "Rerun " item-test-path) #:action (lambda (obj) (common:run-a-command (conc "megatest -set-state-status NOT_STARTED,n/a -run -target " target " -runname " runname " -testpatt " item-test-path " -preclean -clean-cache")))) (iup:menu-item "Start xterm" #:action (lambda (obj) (dcommon:examine-xterm run-id test-id))) (iup:menu-item (conc "Kill " item-test-path) #:action (lambda (obj) ;; (rmt:test-set-state-status-by-id run-id test-id "KILLREQ" #f #f) (common:run-a-command (conc "megatest -set-state-status KILLREQ,n/a -target " target " -runname " runname " -testpatt " item-test-path " -state RUNNING,REMOTEHOSTSTART,LAUNCHED,NOT_STARTED")))) (let* ((rundir (db:test-get-rundir test-info)) (has-subrun (subrun:subrun-test-initialized? rundir))) (if has-subrun (iup:menu-item "Launch subrun dashboard" #:action (lambda (obj) (subrun:launch-dashboard rundir))) (iup:vbox))) (iup:menu-item (conc "View Log " item-test-path) #:action (lambda (obj) (let* ((rundir (db:test-get-rundir test-info)) (logf (db:test-get-final_logf test-info)) (fullfile (conc rundir "/" logf))) (if (common:file-exists? fullfile) (dcommon:run-html-viewer fullfile) (message-window (conc "file " fullfile " not found."))))) ) )) ;; example section for megatest.config: ;; ;; ;; [custom-context-menu-items] ;; #<unique var> <menu item text, can have template variables> : <command line with template %variable%s> ;; item1 custom show run-id (%run-id%):echo "%run-id%" ;; item2 custom show test-id (%test-id%):echo "%test-id%" ;; item3 custom show target (%target%):echo "%target%" ;; item4 custom show test-name (%test-name%):echo "%test-name%" ;; item5 custom show test-patt (%test-patt%):echo "%test-patt%" ;; item6 custom show test-run-dir (%test-run-dir%):echo "%test-run-dir%" ;; item7 custom show run-area-home (%run-area-home%):echo "%run-area-home%" ;; item8 custom show megatest root (%mt-root%):echo "%mt-root%" ;; item9 custom ls : ls -lrt ;; item10 custom see $MT_RUN_AREA_HOME (not yet implemented) : echo $MT_RUN_AREA_HOME (define (dashboard:custom-menu-items run-id test-id target run-name test-name testpatt item-test-path test-info) (let* ((vars (configf:section-vars *configdat* "custom-context-menu-items")) (item-path (db:test-get-item-path test-info)) (mt-root (pathname-directory (pathname-directory *common:this-exe-dir* )))) (filter-map (lambda (var) (let* ((val (configf:lookup *configdat* "custom-context-menu-items" var)) (m (string-match "^\\s*([^:]+?)\\s*:\\s*(.*?)\\s*$" val))) (if m (let* ((menu-item-text-raw (list-ref m 1)) (command-line-raw (list-ref m 2)) (subst-alist ;; template vars `(( "%run-id%" . ,run-id ) ( "%test-id%" . ,test-id ) ( "%target%" . ,target ) ( "%test-name%" . ,test-name) ( "%test-patt%" . ,testpatt) ( "%test-run-dir%" . ,(db:test-get-rundir test-info)) ( "%mt-root%" . ,mt-root) ( "%run-name%" . ,run-name) ( "%run-area-home%" . ,*toppath*) ( "%item-path%" . ,item-path) ( "%item-test-patt%" . ,item-test-path ))) (command-line ;; replace template vars (foldr (lambda (x i) (string-substitute (car x) (->string (cdr x)) i #t)) command-line-raw subst-alist)) (menu-item-text ;; replace template vars (foldr (lambda (x i) (string-substitute (car x) (->string (cdr x)) i #t)) menu-item-text-raw subst-alist))) (iup:menu-item (conc "*"menu-item-text) #:action (lambda (obj) (let* ((scheme-match (string-match "^#(\\(.*)" command-line))) ;;(BB> "cmdline is >"command-line"<") (common:with-env-vars ;; TODO: with-env-vars <runconfig target vars, env-override vars from mtest> ;; TODO: with-env-vars MT_* (runs:get-mt-env-alist run-id run-name target test-name item-path) (lambda () (if scheme-match (begin (handle-exceptions exn (print "error with custom menu scheme") (begin ;;(BB> "gonna eval it!") (eval (with-input-from-string (cadr scheme-match) read))))) (common:run-a-command command-line with-vars: #t)))))))) #f))) vars))) (define (dashboard:context-menu run-id test-id target runname test-name testpatt item-test-path test-info) (let* ((run-menu-items (dashboard:run-menu-items run-id test-id target runname test-name testpatt item-test-path test-info)) (test-menu-items (dashboard:test-menu-items run-id test-id target runname test-name testpatt item-test-path test-info)) (custom-menu-items (dashboard:custom-menu-items run-id test-id target runname test-name testpatt item-test-path test-info)) (toplevel-menu-items (dashboard:toplevel-menu-items run-id test-id target runname test-name testpatt item-test-path test-info)) ) (apply iup:menu `(,@toplevel-menu-items ,(iup:menu-item "Run" (apply iup:menu run-menu-items)) ,(iup:menu-item "Test" (apply iup:menu test-menu-items)) ,@custom-menu-items)))) |
Modified dashboard-guimonitor.scm from [10390e6373] to [9920d4908c].
1 2 3 | ;;====================================================================== ;; Copyright 2006-2012, Matthew Welland. ;; | | | > > > > > | | > | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | ;;====================================================================== ;; Copyright 2006-2012, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. ;; ;;====================================================================== ;;====================================================================== ;; Test info panel ;;====================================================================== (use format) |
︙ | ︙ |
Modified dashboard-tests.scm from [37f1a4736f] to [ce8bb20d3c].
1 2 3 | ;;====================================================================== ;; Copyright 2006-2012, Matthew Welland. ;; | | | > > > > > | | > > > > | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | ;;====================================================================== ;; Copyright 2006-2012, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. ;;====================================================================== ;;====================================================================== ;; Test info panel ;;====================================================================== (use format fmt) |
︙ | ︙ | |||
26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | (declare (uses common)) (declare (uses db)) (declare (uses gutils)) (declare (uses rmt)) (declare (uses ezsteps)) ;; (declare (uses sdb)) ;; (declare (uses filedb)) (include "common_records.scm") (include "db_records.scm") (include "run_records.scm") ;;====================================================================== ;; C O M M O N ;;====================================================================== (define *dashboard-comment-share-slot* #f) (define (dtests:get-pre-command #!key (default-override #f)) | > > > > > > > > > > > | | > > > > > > | | | 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 | (declare (uses common)) (declare (uses db)) (declare (uses gutils)) (declare (uses rmt)) (declare (uses ezsteps)) ;; (declare (uses sdb)) ;; (declare (uses filedb)) (declare (uses subrun)) (include "common_records.scm") (include "db_records.scm") (include "run_records.scm") ;;====================================================================== ;; C O M M O N ;;====================================================================== (define *dashboard-comment-share-slot* #f) (define (message-window msg) (iup:show (iup:dialog (iup:vbox (iup:label msg #:margin "40x40"))))) (define (dtests:get-pre-command #!key (default-override #f)) (let* ((orig-pre-command "export CMD='") (viewscreen-pre-command "viewscreen ") (use-viewscreen (configf:lookup *configdat* "dashboard" "use-viewscreen")) (default-pre-command (if use-viewscreen viewscreen-pre-command orig-pre-command)) (cfg-ovrd (configf:lookup *configdat* "dashboard" "pre-command"))) (or cfg-ovrd default-override default-pre-command))) ;; "xterm -geometry 180x20 -e \"")) (define (dtests:get-post-command #!key (default-override #f)) (let* ((orig-post-command (conc "';xterm -geometry 180x20 -e \"(echo; echo -n START:;date +ww%U.%w-$H:%M:%S;echo;echo $CMD;echo;$CMD)|&" "tee -a runlog-`date +ww%U.%w-%H:%M`.log;echo Press any key to continue;bash -c 'read -n 1 -s'\" &")) (viewscreen-post-command "") (use-viewscreen (configf:lookup *configdat* "dashboard" "use-viewscreen")) (default-post-command (if use-viewscreen viewscreen-post-command orig-post-command)) (cfg-ovrd (configf:lookup *configdat* "dashboard" "post-command"))) (or cfg-ovrd default-override default-post-command))) ;; ";echo Press any key to continue;bash -c 'read -n 1 -s'\" &"))) (define (test-info-panel testdat store-label widgets) (iup:frame #:title "Test Info" ; #:expand "YES" (iup:hbox ; #:expand "YES" (apply iup:vbox ; #:expand "YES" |
︙ | ︙ | |||
231 232 233 234 235 236 237 | (lambda (testdat) ;; (sdb:qry 'getstr (db:test-get-uname testdat))) ;; ) ))))) ;; if there is a submegatest create a button to launch dashboard in that area ;; (define (submegatest-panel dbstruct keydat testdat runname testconfig) | > | | < | | 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 | (lambda (testdat) ;; (sdb:qry 'getstr (db:test-get-uname testdat))) ;; ) ))))) ;; if there is a submegatest create a button to launch dashboard in that area ;; (define (submegatest-panel dbstruct keydat testdat runname testconfig) (let* ((test-run-dir (db:test-get-rundir testdat)) (subarea (subrun:get-runarea test-run-dir)) (area-exists (and subarea (common:file-exists? subarea silent: #t)))) (if subarea (iup:frame #:title "Megatest Run Info" ; #:expand "YES" (iup:button "Launch Dashboard" #:action (lambda (obj) (subrun:launch-dashboard test-run-dir)))) (iup:vbox)))) ;; use a global for setting the buttons colors ;; state status teststeps (define *state-status* (vector #f #f #f)) (define (update-state-status-buttons testdat) (let* ((state (db:test-get-state testdat)) |
︙ | ︙ | |||
338 339 340 341 342 343 344 | (iup:attribute-set! btn "BGCOLOR" newcolor)))) btns))) btns)))))) (define (dashboard-tests:run-a-step info) #t) | | > > | | | | | | | > | | > > > > | > > > | > > | | | > > | | | | > > > > | | | | > | | 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 | (iup:attribute-set! btn "BGCOLOR" newcolor)))) btns))) btns)))))) (define (dashboard-tests:run-a-step info) #t) ;; (define (dashboard-tests:step-run-control testdat stepname testconfig) ;; (let* ((mutex (make-mutex))) ;; (letrec ((dlg ;; (iup:dialog ;; #:close_cb (lambda (a)(exit)) ; #:expand "YES" ;; #:title stepname ;; (iup:vbox ; #:expand "YES" ;; (iup:label (conc "Step: " stepname "\nNB// These buttons only run the test step\nfor the purpose of debugging.\nNot all database updates are done.")) ;; (iup:button "Re-run" ;; #:expand "HORIZONTAL" ;; #:action (lambda (obj) ;; (debug:catch-and-dump (lambda () ;; (thread-start! ;; (make-thread ;; (lambda () ;; (print "BB> started ezsteps:run-from") ;; (debug:catch-and-dump ;; (lambda () ;; (ezsteps:run-from testdat stepname #t)) ;; "dashboard-tests:step-run-control -> ezstep:run-from (1)") ;; (print "BB> done ezsteps:run-from") ;; 'foo) ;; (conc "ezstep run single step " stepname))) ;; ) ;; "step-run-control action"))) ;; (iup:button "Re-run and continue" ;; #:expand "HORIZONTAL" ;; #:action (lambda (obj) ;; (debug:catch-and-dump ;; (lambda () ;; (thread-start! ;; (make-thread (lambda () ;; (ezsteps:run-from testdat stepname #f)) ;; (conc "ezstep run from step " stepname)))) ;; "dashboard-tests:step-run-control -> ezstep:run-from (2)"))) ;; (iup:button "Close" ;; #:action (lambda (obj) ;; (iup:destroy! dlg))) ;; ;; (iup:button "Refresh test data" ;; ;; #:expand "HORIZONTAL" ;; ;; #:action (lambda (obj) ;; ;; (print "Refresh test data " stepname)) ;; )))) ;; dlg))) (define (dashboard-tests:waiver run-id testdat ovrdval cmtcmd) (let* ((wpatt (configf:lookup *configdat* "setup" "waivercommentpatt")) (wregx (if (string? wpatt)(regexp wpatt) #f)) (wmesg (iup:label (if wpatt (conc "Comment must match pattern " wpatt) ""))) (comnt (iup:textbox #:action (lambda (val a b) (if wpatt |
︙ | ︙ | |||
437 438 439 440 441 442 443 | ;; These next two are intentional bad values to ensure errors if they should not ;; get filled in properly. (logfile "/this/dir/better/not/exist") (rundir (if testdat (db:test-get-rundir testdat) logfile)) ;; (testdat-path (conc rundir "/testdat.db")) ;; this gets recalculated until found | > > > > > > > > | | | | | | | | | 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 | ;; These next two are intentional bad values to ensure errors if they should not ;; get filled in properly. (logfile "/this/dir/better/not/exist") (rundir (if testdat (db:test-get-rundir testdat) logfile)) ;; (testdat-path (conc rundir "/testdat.db")) ;; this gets recalculated until found (augment-teststeps (lambda (inlov) (map (lambda (invec) (list->vector `( ,@(reverse (cdr (reverse (vector->list invec)))) "rerun this step" "restart from here" ))) inlov))) (teststeps (if testdat (augment-teststeps (tests:get-compressed-steps run-id test-id)) '())) (testfullname (if testdat (db:test-get-fullname testdat) "Gathering data ...")) (testname (if testdat (db:test-get-testname testdat) "n/a")) ;; (tests:get-testconfig testdat testname 'return-procs)) (testmeta (if testdat (let ((tm (rmt:testmeta-get-record testname))) (if tm tm (make-db:testmeta))) (make-db:testmeta))) (keystring (string-intersperse (map (lambda (keyval) ;; (conc ":" (car keyval) " " (cadr keyval))) (cadr keyval)) keydat) "/")) (item-path (db:test-get-item-path testdat)) ;; this next block was added to fix a bug where variables were ;; needed. Revisit this. (runconfig (let ((runconfigf (conc *toppath* "/runconfigs.config"))) ;; no rush but it would be good to convert this call to use runconfig:read (if (common:file-exists? runconfigf) (handle-exceptions exn #f ;; do nothing, just keep on trucking .... (setup-env-defaults runconfigf run-id (make-hash-table) keydat environ-patt: keystring)) (make-hash-table)))) (testconfig (begin ;; (runs:set-megatest-env-vars run-id inrunname: runname testname: test-name itempath: item-path) (runs:set-megatest-env-vars run-id inkeyvals: keydat inrunname: runname intarget: keystring testname: testname itempath: item-path) ;; these may be needed by the launching process (handle-exceptions exn ;; NOTE: I've no idea why this was written this way. Research, study and fix needed! (tests:get-testconfig (db:test-get-testname testdat) (db:test-get-item-path testdat) test-registry #f allow-write-cache: #f) (tests:get-testconfig (db:test-get-testname testdat) item-path test-registry #t allow-write-cache: #f)))) (viewlog (lambda (x) (if (common:file-exists? logfile) ;(system (conc "firefox " logfile "&")) (dcommon:run-html-viewer logfile) (message-window (conc "File " logfile " not found"))))) (view-a-log (lambda (lfile) (let ((lfilename (conc rundir "/" lfile))) ;; (print "lfilename: " lfilename) (if (common:file-exists? lfilename) ;(system (conc "firefox " logfile "&")) (dcommon:run-html-viewer lfilename) (message-window (conc "File " lfilename " not found")))))) (xterm (lambda (x) (if (directory-exists? rundir) (let ((shell (if (get-environment-variable "SHELL") (conc "-e " (get-environment-variable "SHELL")) ""))) (common:without-vars (conc "cd " rundir ";mt_xterm -T \"" (string-translate testfullname "()" " ") "\" " shell "&") "MT_.*")) (message-window (conc "Directory " rundir " not found"))))) (widgets (make-hash-table)) (refreshdat (lambda () (let* ((curr-mod-time (file-modification-time db-path)) ;; (max ..... (if (common:file-exists? testdat-path) ;; (file-modification-time testdat-path) ;; (begin ;; (set! testdat-path (conc rundir "/testdat.db")) ;; 0)))) (need-update (or (and (>= curr-mod-time db-mod-time) (> (current-milliseconds)(+ last-update 250))) ;; every half seconds if db touched (> (current-milliseconds)(+ last-update 10000)) ;; force update even 10 seconds request-update)) (newtestdat (if need-update ;; NOTE: BUG HIDER, try to eliminate this exception handler (handle-exceptions exn (debug:print-info 0 *default-log-port* "test db access issue in examine test for run-id " run-id ", test-id " test-id ": " ((condition-property-accessor 'exn 'message) exn)) (rmt:get-test-info-by-id run-id test-id ))))) ;; (print "INFO: need-update= " need-update " curr-mod-time = " curr-mod-time) (cond ((and need-update newtestdat) (set! testdat newtestdat) (set! teststeps (augment-teststeps (tests:get-compressed-steps run-id test-id))) (set! logfile (conc (db:test-get-rundir testdat) "/" (db:test-get-final_logf testdat))) (set! rundir ;; (filedb:get-path *fdb* (db:test-get-rundir testdat)) ;; ) (set! testfullname (db:test-get-fullname testdat)) ;; (debug:print 0 *default-log-port* "INFO: teststeps=" (intersperse teststeps "\n ")) ;; I don't see why this was implemented this way. Please comment it ... |
︙ | ︙ | |||
572 573 574 575 576 577 578 | (iup:attribute-set! lbl "TITLE" newval) ;(mutex-unlock! mx1) ))))) lbl)) (store-button store-label) (command-proc (lambda (command-text-box) (let* ((cmd (iup:attribute command-text-box "VALUE"))) | | | | 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 | (iup:attribute-set! lbl "TITLE" newval) ;(mutex-unlock! mx1) ))))) lbl)) (store-button store-label) (command-proc (lambda (command-text-box) (let* ((cmd (iup:attribute command-text-box "VALUE"))) (common:run-a-command cmd with-orig-env: #t)))) (command-text-box (iup:textbox #:expand "HORIZONTAL" #:font "Courier New, -10" #:action (lambda (obj cnum val) ;; (print "cnum=" cnum) (if (eq? cnum 13) (command-proc obj))) )) (command-launch-button (iup:button "Execute!" #:action (lambda (x) (command-proc command-text-box)))) ;; (lambda (x) ;; (let* ((cmd (iup:attribute command-text-box "VALUE")) ;; (fullcmd (conc (dtests:get-pre-command) ;; cmd |
︙ | ︙ | |||
614 615 616 617 618 619 620 | command-text-box "VALUE" (conc "megatest -remove-runs -target " keystring " -runname " runname " -testpatt " (conc testname "/" (if (equal? item-path "") "%" item-path)) " -v")))) (clean-run-execute (lambda (x) | | > | | 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 | command-text-box "VALUE" (conc "megatest -remove-runs -target " keystring " -runname " runname " -testpatt " (conc testname "/" (if (equal? item-path "") "%" item-path)) " -v")))) (clean-run-execute (lambda (x) (let ((cmd (conc ;; "megatest -remove-runs -target " keystring " -runname " runname "megatest -set-state-status NOT_STARTED,n/a -target " keystring " -runname " runname " -testpatt " (conc testname "/" (if (equal? item-path "") "%" item-path)) ";megatest -target " keystring " -runname " runname " -run -preclean -testpatt " (conc testname "/" (if (equal? item-path "") "%" item-path)) " -clean-cache" ))) (thread-start! (make-thread (lambda () (common:run-a-command cmd)) |
︙ | ︙ | |||
683 684 685 686 687 688 689 | (let ((tabs (iup:tabs ;; Replace here with matrix (let ((steps-matrix (iup:matrix #:font "Courier New, -8" #:expand "YES" #:scrollbar "YES" | | | | | > | | < | | | | > > > > > | | 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 | (let ((tabs (iup:tabs ;; Replace here with matrix (let ((steps-matrix (iup:matrix #:font "Courier New, -8" #:expand "YES" #:scrollbar "YES" #:numcol 9 #:numlin 100 #:numcol-visible 9 #:numlin-visible 5 #:click-cb (lambda (obj lin col status) ;; (if (equal? col 6) (let* ((mtrx-rc (conc lin ":" 6)) (fname (iup:attribute obj mtrx-rc)) (stepname (iup:attribute obj (conc lin ":" 1))) (comment (iup:attribute obj (conc lin ":" 7)))) (case col ((7) (print "Comment from step "stepname": "comment)) ((8) (ezsteps:spawn-run-from testdat stepname #t)) ((9) (ezsteps:spawn-run-from testdat stepname #f)) (else (view-a-log fname)))))))) ;; (let loop ((count 0)) ;; (iup:attribute-set! steps-matrix "FITTOTEXT" (conc "L" count)) ;; (if (< count 30) ;; (loop (+ count 1)))) (iup:attribute-set! steps-matrix "0:1" "Step Name") (iup:attribute-set! steps-matrix "0:2" "Start") (iup:attribute-set! steps-matrix "0:3" "End") (iup:attribute-set! steps-matrix "WIDTH3" "50") (iup:attribute-set! steps-matrix "0:4" "Status") (iup:attribute-set! steps-matrix "WIDTH4" "50") (iup:attribute-set! steps-matrix "0:5" "Duration") (iup:attribute-set! steps-matrix "0:6" "Log File") (iup:attribute-set! steps-matrix "0:7" "Comment") (iup:attribute-set! steps-matrix "0:8" "rerun only") (iup:attribute-set! steps-matrix "BGCOLOR0:9" "149 208 252") (iup:attribute-set! steps-matrix "BGCOLOR0:8" "149 208 252") (iup:attribute-set! steps-matrix "BGCOLOR0:7" "149 208 252") (iup:attribute-set! steps-matrix "0:9" "rerun & continue") (iup:attribute-set! steps-matrix "ALIGNMENT1" "ALEFT") ;; (iup:attribute-set! steps-matrix "FIXTOTEXT" "C1") (iup:attribute-set! steps-matrix "RESIZEMATRIX" "YES") (let ((proc (lambda (testdat) (dcommon:populate-steps teststeps steps-matrix run-id test-id)))) (hash-table-set! widgets "StepsMatrix" proc) (proc testdat)) steps-matrix) ;; populate the Test Data panel (iup:frame #:title "Test Data" (let ((test-data |
︙ | ︙ | |||
768 769 770 771 772 773 774 775 | (iup:callback-set! *tim* "ACTION_CB" (lambda (x) ;; Now start keeping the gui updated from the db (refreshdat) ;; update from the db here ;(thread-suspend! other-thread) (if *exit-started* (set! *exit-started* 'ok)))))))))) | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 | (iup:callback-set! *tim* "ACTION_CB" (lambda (x) ;; Now start keeping the gui updated from the db (refreshdat) ;; update from the db here ;(thread-suspend! other-thread) (if *exit-started* (set! *exit-started* 'ok)))))))))) (define (colors-similar? color1 color2) (let* ((c1 (map string->number (string-split color1))) (c2 (map string->number (string-split color2))) (delta (map (lambda (a b)(abs (- a b))) c1 c2))) (null? (filter (lambda (x)(> x 3)) delta)))) ;; Display the tests as rows of boxes on the test/task pane ;; (define (dashboard:draw-tests cnv xadj yadj tests-draw-state sorted-testnames test-records) (canvas-clear! cnv) (canvas-font-set! cnv "Helvetica, -10") (let-values (((sizex sizey sizexmm sizeymm) (canvas-size cnv)) ((originx originy) (canvas-origin cnv))) ;; (print "originx: " originx " originy: " originy) ;; (canvas-origin-set! cnv 0 (- (/ sizey 2))) (if (hash-table-ref/default tests-draw-state 'first-time #t) (begin (hash-table-set! tests-draw-state 'first-time #f) (hash-table-set! tests-draw-state 'scalef 1) (hash-table-set! tests-draw-state 'tests-info (make-hash-table)) (hash-table-set! tests-draw-state 'selected-tests (make-hash-table)) ;; set these (dcommon:initial-draw-tests cnv xadj yadj sizex sizey sizexmm sizeymm originx originy tests-draw-state sorted-testnames test-records)) (dcommon:redraw-tests cnv xadj yadj sizex sizey sizexmm sizeymm originx originy tests-draw-state sorted-testnames test-records)) )) (define (dboard:tabdat-test-patts-use vec) (let ((val (dboard:tabdat-test-patts vec)))(if val val ""))) ;;RADT => What is the if for? ;; additional setters for dboard:data (define (dboard:tabdat-test-patts-set!-use vec val) (dboard:tabdat-test-patts-set! vec (if (equal? val "") #f val))) ;; Extract the various bits of data from tabdat and create the command line equivalent that will be displayed ;; (define (dashboard:update-run-command tabdat) (let* ((cmd-tb (dboard:tabdat-command-tb tabdat)) (cmd (dboard:tabdat-command tabdat)) (test-patt (let ((tp (dboard:tabdat-test-patts tabdat))) (if (or (not tp) (equal? tp "")) "%" tp))) (states (dboard:tabdat-states tabdat)) (statuses (dboard:tabdat-statuses tabdat)) (target (let ((targ-list (dboard:tabdat-target tabdat))) (if targ-list (string-intersperse targ-list "/") "no-target-selected"))) (run-name (dboard:tabdat-run-name tabdat)) (states-str (if (or (not states) (null? states)) "" (conc " -state " (string-intersperse states ",")))) (statuses-str (if (or (not statuses) (null? statuses)) "" (conc " -status " (string-intersperse statuses ",")))) (full-cmd "megatest")) (case (string->symbol cmd) ((run) (set! full-cmd (conc full-cmd " -run" " -testpatt " test-patt " -target " target " -runname " run-name " -clean-cache" ))) ((remove-runs) (set! full-cmd (conc full-cmd " -remove-runs -runname " run-name " -target " target " -testpatt " test-patt states-str statuses-str ))) (else (set! full-cmd " no valid command "))) (iup:attribute-set! cmd-tb "VALUE" full-cmd))) (define (iuplistbox-fill-list lb items #!key (selected-item #f)) (let ((i 1)) (for-each (lambda (item) (iup:attribute-set! lb (number->string i) item) (if selected-item (if (equal? selected-item item) (iup:attribute-set! lb "VALUE" i))) ;; (number->string i)))) (set! i (+ i 1))) items) ;; (iup:attribute-set! lb "VALUE" (if selected-item selected-item "")) i)) ;; if tab-num passed in then use it, otherwise look in commondat at curr-tab-num ;; adds the updater passed in the updaters list at that hashkey ;; (define (dboard:commondat-add-updater commondat updater #!key (tab-num #f)) (let* ((tnum (or tab-num (dboard:commondat-curr-tab-num commondat))) (curr-updaters (hash-table-ref/default (dboard:commondat-updaters commondat) tnum '()))) (hash-table-set! (dboard:commondat-updaters commondat) tnum (cons updater curr-updaters)))) |
Modified dashboard.scm from [a14a45cd51] to [2679042d5f].
1 2 3 | ;;====================================================================== ;; Copyright 2006-2016, Matthew Welland. ;; | | | > > > > > | | > | > > > | > | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 | ;;====================================================================== ;; Copyright 2006-2016, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. ;; ;;====================================================================== (use format) (require-library iup) (import (prefix iup iup:)) (use canvas-draw) (import canvas-draw-iup) (use ducttape-lib) (use sqlite3 srfi-1 posix regex regex-case srfi-69 typed-records sparse-vectors) ;; defstruct (import (prefix sqlite3 sqlite3:)) (declare (uses common)) (declare (uses margs)) (declare (uses keys)) (declare (uses items)) (declare (uses db)) (declare (uses configf)) (declare (uses process)) (declare (uses launch)) (declare (uses runs)) (declare (uses dashboard-tests)) (declare (uses dashboard-guimonitor)) (declare (uses tree)) (declare (uses dcommon)) (declare (uses dashboard-context-menu)) (declare (uses vg)) (declare (uses subrun)) ;; (declare (uses dashboard-main)) (declare (uses megatest-version)) (declare (uses mt)) (include "common_records.scm") (include "db_records.scm") (include "run_records.scm") (include "task_records.scm") (include "megatest-fossil-hash.scm") (include "vg_records.scm") (define help (conc "Megatest Dashboard, documentation at http://www.kiatoa.com/fossils/megatest version " megatest-version " license GPL, Copyright (C) Matt Welland 2012-2017 Usage: dashboard [options] -h : this help -test run-id,test-id : control test identified by testid -skip-version-check : skip the version check -use-db-cache : access database via cache |
︙ | ︙ | |||
73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 | "-cols" "-run" "-test" "-xterm" "-debug" "-host" "-transport" ) (list "-h" "-use-server" "-guimonitor" "-main" "-v" "-q" "-use-db-cache" "-skip-version-check" "-repl" ) args:arg-hash 0)) (if (not (null? remargs)) (begin (print "Unrecognised arguments: " (string-intersperse remargs " ")) (exit))) (if (args:get-arg "-h") (begin (print help) (exit))) ;; TODO: Move this inside (main) ;; (if (not (launch:setup)) (begin (print "Failed to find megatest.config, exiting") (exit 1))) (if (not (common:on-homehost?)) (begin (debug:print 0 *default-log-port* "WARNING: Current policy requires running dashboard on homehost: " (common:get-homehost)))) ;; RA => Might require revert for filters ;; create a watch dog to move changes from lt/.db/*.db to megatest.db ;; ;;;(if (file-write-access? (conc *toppath* "/megatest.db")) ;;(debug:print-info 13 *default-log-port* "Before common:watchdog spawn") (thread-start! (make-thread common:watchdog "Watchdog thread")) ;;(debug:print-info 13 *default-log-port* "After common:watchdog spawn") ;; (if (not (args:get-arg "-use-db-cache")) ;; (begin ;; (debug:print-info 0 *default-log-port* "Forcing db-cache mode due to read-only access to megatest.db") ;; (hash-table-set! args:arg-hash "-use-db-cache" #t)));;;) ;;) | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 | "-cols" "-run" "-test" "-xterm" "-debug" "-host" "-transport" "-start-dir" ) (list "-h" "-use-server" "-guimonitor" "-main" "-v" "-q" "-use-db-cache" "-skip-version-check" "-repl" "-rh5.11" ;; fix to allow running on rh5.11 ) args:arg-hash 0)) ;; check for MT_* environment variables and exit if found (if (not (args:get-arg "-test")) (begin (display "Checking for MT_ vars: ") (for-each (lambda (var) (display " ")(display var) (if (get-environment-variable var) (begin (print "ERROR: environment variable " var " is set in this terminal, this will cause you problems. Exiting now.") (exit 1)))) '("MT_RUN_AREA_HOME" "MT_MEGATEST" "MT_CMDINFO" "MT_TEST_RUN_DIR" "MT_LINKTREE" "MT_TESTSUITENAME")) (print ". Done. All ok."))) (if (not (null? remargs)) (begin (print "Unrecognised arguments: " (string-intersperse remargs " ")) (exit))) (if (args:get-arg "-h") (begin (print help) (exit))) (if (args:get-arg "-start-dir") (if (directory-exists? (args:get-arg "-start-dir")) (let ((fullpath (common:real-path (args:get-arg "-start-dir")))) (setenv "PWD" fullpath) (change-directory fullpath)) (begin (debug:print-error 0 *default-log-port* "non-existant start dir " (args:get-arg "-start-dir") " specified, exiting.") (exit 1)))) ;; TODO: Move this inside (main) ;; (if (not (launch:setup)) (begin (print "Failed to find megatest.config, exiting") (exit 1))) ;; deal with RH 5.11 gtk lib or iup lib missing detachbox feature ;; first check for the switch ;; (if (or (args:get-arg "-rh5.11") (configf:lookup *configdat* "dashboard" "no-detachbox") (not (file-exists? "/etc/os-release"))) (set! iup:detachbox iup:vbox)) (if (not (common:on-homehost?)) (begin (debug:print 0 *default-log-port* "WARNING: Current policy requires running dashboard on homehost: " (common:get-homehost)))) ;; RA => Might require revert for filters ;; create a watch dog to move changes from lt/.db/*.db to megatest.db ;; ;;;(if (file-write-access? (conc *toppath* "/megatest.db")) ;;(debug:print-info 13 *default-log-port* "Before common:watchdog spawn") (thread-start! (make-thread common:watchdog "Watchdog thread")) ;;(debug:print-info 13 *default-log-port* "After common:watchdog spawn") ;; (if (not (args:get-arg "-use-db-cache")) ;; (begin ;; (debug:print-info 0 *default-log-port* "Forcing db-cache mode due to read-only access to megatest.db") ;; (hash-table-set! args:arg-hash "-use-db-cache" #t)));;;) ;;) |
︙ | ︙ | |||
202 203 204 205 206 207 208 | ;; runs ((allruns '()) : list) ;; list of dboard:rundat records ((allruns-by-id (make-hash-table)) : hash-table) ;; hash of run-id -> dboard:rundat records ((done-runs '()) : list) ;; list of runs already drawn ((not-done-runs '()) : list) ;; list of runs not yet drawn (header #f) ;; header for decoding the run records (keys #f) ;; keys for this run (i.e. target components) | | > > | | 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 | ;; runs ((allruns '()) : list) ;; list of dboard:rundat records ((allruns-by-id (make-hash-table)) : hash-table) ;; hash of run-id -> dboard:rundat records ((done-runs '()) : list) ;; list of runs already drawn ((not-done-runs '()) : list) ;; list of runs not yet drawn (header #f) ;; header for decoding the run records (keys #f) ;; keys for this run (i.e. target components) ((numruns (string->number (or (args:get-arg "-cols") (configf:lookup *configdat* "dashboard" "cols") "8"))) : number) ;; ((tot-runs 0) : number) ((last-data-update 0) : number) ;; last time the data in allruns was updated ((last-runs-update 0) : number) ;; last time we pulled the runs info to update the tree (runs-mutex (make-mutex)) ;; use to prevent parallel access to draw objects ((run-update-times (make-hash-table)) : hash-table) ;; update times indexed by run-id ((last-test-dat (make-hash-table)) : hash-table) ;; cache last tests dat by run-id ((run-db-paths (make-hash-table)) : hash-table) ;; cache the paths to the run db files ;; Runs view ((buttondat (make-hash-table)) : hash-table) ;; ((item-test-names '()) : list) ;; list of itemized tests ((run-keys (make-hash-table)) : hash-table) (runs-matrix #f) ;; used in newdashboard ((start-run-offset 0) : number) ;; left-right slider value ((start-test-offset 0) : number) ;; up-down slider value ((runs-btn-height (or (configf:lookup *configdat* "dashboard" "btn-height") "x16")) : string) ;; was 12 ((runs-btn-fontsz (or (configf:lookup *configdat* "dashboard" "btn-fontsz") "10")) : string) ;; was 8 ((runs-cell-width (or (configf:lookup *configdat* "dashboard" "cell-width") "50")) : string) ;; was 50 ((all-test-names '()) : list) ;; Canvas and drawing data (cnv #f) (cnv-obj #f) (drawing #f) ((run-start-row 0) : number) |
︙ | ︙ | |||
311 312 313 314 315 316 317 318 319 320 321 322 323 324 | (cons dboard:tabdat? (lambda (tabdat-item) (filter (lambda (alist-entry) (member (car alist-entry) '(allruns-by-id allruns))) ;; FIELDS OF INTEREST (dboard:tabdat->alist tabdat-item))))) (define (dboard:tabdat-target-string vec) (let ((targ (dboard:tabdat-target vec))) (if (list? targ)(string-intersperse targ "/") "no-target-specified"))) (define (dboard:tabdat-test-patts-use vec) (let ((val (dboard:tabdat-test-patts vec)))(if val val ""))) ;;RADT => What is the if for? | > > | 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 | (cons dboard:tabdat? (lambda (tabdat-item) (filter (lambda (alist-entry) (member (car alist-entry) '(allruns-by-id allruns))) ;; FIELDS OF INTEREST (dboard:tabdat->alist tabdat-item))))) (define (dboard:tabdat-target-string vec) (let ((targ (dboard:tabdat-target vec))) (if (list? targ)(string-intersperse targ "/") "no-target-specified"))) (define (dboard:tabdat-test-patts-use vec) (let ((val (dboard:tabdat-test-patts vec)))(if val val ""))) ;;RADT => What is the if for? |
︙ | ︙ | |||
337 338 339 340 341 342 343 | (dboard:tabdat-dbdir-set! tabdat (db:dbfile-path)) ;; (conc (configf:lookup *configdat* "setup" "linktree") "/.db")) (dboard:tabdat-dbfpath-set! tabdat (db:dbfile-path)) (dboard:tabdat-monitor-db-path-set! tabdat (conc (dboard:tabdat-dbdir tabdat) "/monitor.db")) ;; HACK ALERT: this is a hack, please fix. (dboard:tabdat-ro-set! tabdat (not (file-read-access? (dboard:tabdat-dbfpath tabdat)))) | | | 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 | (dboard:tabdat-dbdir-set! tabdat (db:dbfile-path)) ;; (conc (configf:lookup *configdat* "setup" "linktree") "/.db")) (dboard:tabdat-dbfpath-set! tabdat (db:dbfile-path)) (dboard:tabdat-monitor-db-path-set! tabdat (conc (dboard:tabdat-dbdir tabdat) "/monitor.db")) ;; HACK ALERT: this is a hack, please fix. (dboard:tabdat-ro-set! tabdat (not (file-read-access? (dboard:tabdat-dbfpath tabdat)))) (dboard:tabdat-keys-set! tabdat (rmt:get-keys)) (dboard:tabdat-dbkeys-set! tabdat (append (dboard:tabdat-keys tabdat) (list "runname"))) (dboard:tabdat-tot-runs-set! tabdat (rmt:get-num-runs "%")) ) ;; RADT => Matrix defstruct addition (defstruct dboard:graph-dat ((id #f) : string) |
︙ | ︙ | |||
565 566 567 568 569 570 571 | db-pth))) (db-mod-time (common:lazy-sqlite-db-modification-time db-path)) (db-modified (>= db-mod-time last-db-time)) (multi-get (> (dboard:rundat-run-data-offset run-dat) 0)) ;; multi-get in progress (tmptests (if (or do-not-use-db-file-timestamps (dboard:tabdat-filters-changed tabdat) db-modified) | < | | 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 | db-pth))) (db-mod-time (common:lazy-sqlite-db-modification-time db-path)) (db-modified (>= db-mod-time last-db-time)) (multi-get (> (dboard:rundat-run-data-offset run-dat) 0)) ;; multi-get in progress (tmptests (if (or do-not-use-db-file-timestamps (dboard:tabdat-filters-changed tabdat) db-modified) (rmt:get-tests-for-run run-id testnamepatt states statuses ;; run-id testpatt states statuses (dboard:rundat-run-data-offset run-dat) ;; query offset num-to-get (dboard:tabdat-hide-not-hide tabdat) ;; no-in sort-by ;; sort-by sort-order ;; sort-order #f ;; 'shortlist ;; qrytype last-update ;; last-update |
︙ | ︙ | |||
640 641 642 643 644 645 646 | ;; this calls dboard:get-tests-for-run-duplicate for each run ;; ;; create a virtual table of all the tests ;; keypatts: ( (KEY1 "abc%def")(KEY2 "%") ) ;; (define (update-rundat tabdat runnamepatt numruns testnamepatt keypatts) (let* ((access-mode (dboard:tabdat-access-mode tabdat)) | | < | < | | 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 | ;; this calls dboard:get-tests-for-run-duplicate for each run ;; ;; create a virtual table of all the tests ;; keypatts: ( (KEY1 "abc%def")(KEY2 "%") ) ;; (define (update-rundat tabdat runnamepatt numruns testnamepatt keypatts) (let* ((access-mode (dboard:tabdat-access-mode tabdat)) (keys (rmt:get-keys)) (last-runs-update (- (dboard:tabdat-last-runs-update tabdat) 2)) (allruns (rmt:get-runs runnamepatt numruns (dboard:tabdat-start-run-offset tabdat) keypatts)) ;;(allruns-tree (rmt:get-runs-by-patt (dboard:tabdat-keys tabdat) "%" #f #f #f #f)) (allruns-tree (rmt:get-runs-by-patt keys "%" #f #f #f #f last-runs-update)) ;;'("id" "runname") (header (db:get-header allruns)) (runs (db:get-rows allruns)) ;; RA => Filtered as per runpatt selected (runs-tree (db:get-rows allruns-tree)) ;; RA => Returns complete list of runs (start-time (current-seconds)) (runs-hash (let ((ht (make-hash-table))) (for-each (lambda (run) (hash-table-set! ht (db:get-value-by-header run header "id") run)) |
︙ | ︙ | |||
723 724 725 726 727 728 729 | ;; create a virtual table of all the tests ;; keypatts: ( (KEY1 "abc%def")(KEY2 "%") ) ;; (define (dboard:update-rundat tabdat runnamepatt numruns testnamepatt keypatts) (let* ((access-mode (dboard:tabdat-access-mode tabdat)) (keys (dboard:tabdat-keys tabdat)) ;; (db:dispatch-query access-mode rmt:get-keys db:get-keys))) (last-runs-update (- (dboard:tabdat-last-runs-update tabdat) 2)) | < | < | | 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 | ;; create a virtual table of all the tests ;; keypatts: ( (KEY1 "abc%def")(KEY2 "%") ) ;; (define (dboard:update-rundat tabdat runnamepatt numruns testnamepatt keypatts) (let* ((access-mode (dboard:tabdat-access-mode tabdat)) (keys (dboard:tabdat-keys tabdat)) ;; (db:dispatch-query access-mode rmt:get-keys db:get-keys))) (last-runs-update (- (dboard:tabdat-last-runs-update tabdat) 2)) (allruns (rmt:get-runs runnamepatt numruns (dboard:tabdat-start-run-offset tabdat) keypatts)) ;;(allruns-tree (rmt:get-runs-by-patt (dboard:tabdat-keys tabdat) "%" #f #f #f #f)) (allruns-tree (rmt:get-runs-by-patt keys "%" #f #f #f #f 0)) ;; last-runs-update));;'("id" "runname") (header (db:get-header allruns)) (runs (db:get-rows allruns)) ;; RA => Filtered as per runpatt selected (runs-tree (db:get-rows allruns-tree)) ;; RA => Returns complete list of runs (start-time (current-seconds)) (runs-hash (let ((ht (make-hash-table))) (for-each (lambda (run) (hash-table-set! ht (db:get-value-by-header run header "id") run)) |
︙ | ︙ | |||
790 791 792 793 794 795 796 | (elapsed-time (- (current-seconds) start-time))) (if (null? all-test-ids) (hash-table-delete! (dboard:tabdat-allruns-by-id tabdat) run-id) (hash-table-set! (dboard:tabdat-allruns-by-id tabdat) run-id run-struct)) (if (or (null? tal) (> elapsed-time 2)) ;; stop loading data after 5 seconds, on the next call more data *should* be loaded since get-tests-for-run uses last update (begin | > | > > > > > > > > | | 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 | (elapsed-time (- (current-seconds) start-time))) (if (null? all-test-ids) (hash-table-delete! (dboard:tabdat-allruns-by-id tabdat) run-id) (hash-table-set! (dboard:tabdat-allruns-by-id tabdat) run-id run-struct)) (if (or (null? tal) (> elapsed-time 2)) ;; stop loading data after 5 seconds, on the next call more data *should* be loaded since get-tests-for-run uses last update (begin (when (> elapsed-time 2) (debug:print 0 *default-log-port* "NOTE: updates are taking a long time, " elapsed-time "s elapsed.") (let* ((old-val (iup:attribute *tim* "TIME")) (new-val (number->string (inexact->exact (floor (* 2 (string->number old-val))))))) (if (< (string->number new-val) 5000) ((debug:print 0 *default-log-port* "NOTE: increasing poll interval from "old-val" to "new-val) (iup:attribute-set! *tim* "TIME" new-val)))) ) (dboard:tabdat-allruns-set! tabdat new-res) maxtests) (if (> (dboard:rundat-run-data-offset run-struct) 0) (loop run tal new-res newmaxtests) ;; not done getting data for this run (loop (car tal)(cdr tal) new-res newmaxtests))))))) (dboard:tabdat-filters-changed-set! tabdat #f) (dboard:update-tree tabdat runs-hash header tb))) (define *collapsed* (make-hash-table)) (define (toggle-hide lnum uidat) ; fulltestname) (let* ((btn (vector-ref (dboard:uidat-get-lftcol uidat) lnum)) (fulltestname (iup:attribute btn "TITLE")) (parts (string-split fulltestname "(")) (basetestname (if (null? parts) "" (car parts)))) ;(print "Toggling " basetestname " currently " (hash-table-ref/default *collapsed* basetestname #f)) (if (hash-table-ref/default *collapsed* basetestname #f) (begin ;(iup:attribute-set! btn "FGCOLOR" "0 0 0")s (hash-table-delete! *collapsed* basetestname)) (begin ;(iup:attribute-set! btn "FGCOLOR" "0 192 192") (hash-table-set! *collapsed* basetestname #t))))) (define blank-line-rx (regexp "^\\s*$")) |
︙ | ︙ | |||
999 1000 1001 1002 1003 1004 1005 | key-vals: (map (lambda (x) "")(dboard:tabdat-keys tabdat))))) (let* ((run (dboard:rundat-run rundat)) (testsdat-by-name (dboard:rundat-tests-by-name rundat)) (key-val-dat (dboard:rundat-key-vals rundat)) (run-id (db:get-value-by-header run (dboard:tabdat-header tabdat) "id")) (key-vals (append key-val-dat (list (let ((x (db:get-value-by-header run (dboard:tabdat-header tabdat) "runname"))) | | | 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 | key-vals: (map (lambda (x) "")(dboard:tabdat-keys tabdat))))) (let* ((run (dboard:rundat-run rundat)) (testsdat-by-name (dboard:rundat-tests-by-name rundat)) (key-val-dat (dboard:rundat-key-vals rundat)) (run-id (db:get-value-by-header run (dboard:tabdat-header tabdat) "id")) (key-vals (append key-val-dat (list (let ((x (db:get-value-by-header run (dboard:tabdat-header tabdat) "runname"))) (if (string? x) x ""))))) (run-key (string-intersperse key-vals "\n"))) ;; fill in the run header key values ;; (let ((rown 0) (headercol (vector-ref tableheader coln))) (for-each (lambda (kval) |
︙ | ︙ | |||
1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 | "190 190 190" )) (dboard:tabdat-filters-changed-set! tabdat #t))) (define (update-search commondat tabdat x val) (hash-table-set! (dboard:tabdat-searchpatts tabdat) x val) (dboard:tabdat-filters-changed-set! tabdat #t) (set-bg-on-filter commondat tabdat)) ;; force ALL updates to zero (effectively) ;; (define (mark-for-update tabdat) (dboard:tabdat-last-db-update-set! tabdat (make-hash-table))) | > | 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 | "190 190 190" )) (dboard:tabdat-filters-changed-set! tabdat #t))) (define (update-search commondat tabdat x val) (hash-table-set! (dboard:tabdat-searchpatts tabdat) x val) (dboard:tabdat-filters-changed-set! tabdat #t) (mark-for-update tabdat) (set-bg-on-filter commondat tabdat)) ;; force ALL updates to zero (effectively) ;; (define (mark-for-update tabdat) (dboard:tabdat-last-db-update-set! tabdat (make-hash-table))) |
︙ | ︙ | |||
1371 1372 1373 1374 1375 1376 1377 | #:value 200 ;; ;; (iup:split ;; #:value 300 ;; Target, testpatt, state and status input boxes ;; | > > | | | | > | | > > > > | > > | | | 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 | #:value 200 ;; ;; (iup:split ;; #:value 300 ;; Target, testpatt, state and status input boxes ;; (iup:split #:orientation "HORIZONTAL" (iup:vbox ;; Command to run, placed over the top of the canvas (dcommon:command-action-selector commondat tabdat tab-num: tab-num) (dboard:runs-tree-browser commondat tabdat)) (iup:vbox (dcommon:command-runname-selector commondat tabdat tab-num: tab-num) (dcommon:command-testname-selector commondat tabdat update-keyvals))) ;; key-listboxes)) (dcommon:command-tests-tasks-canvas tabdat test-records sorted-testnames tests-draw-state)))) (tb (dboard:tabdat-runs-tree tabdat))) (dboard:commondat-add-updater commondat (lambda () (if (dashboard:database-changed? commondat tabdat context-key: 'run-control) (dashboard:update-tree-selector tabdat))) tab-num: tab-num) result))) ;;(iup:frame ;; #:title "Logs" ;; To be replaced with tabs ;; (let ((logs-tb (iup:textbox #:expand "YES" ;; #:multiline "YES"))) ;; (dboard:tabdat-logs-textbox-set! tabdat logs-tb) ;; logs-tb)) ;; browse runs as a tree. Used in both "Runs" tab and ;; in the runs control panel. ;; (define (dboard:runs-tree-browser commondat tabdat) (let* ( (txtbox (iup:textbox #:action (lambda (val a b) (debug:catch-and-dump (lambda () ;; for the Runs view we put the list of keyvals into tabdat target ;; for the Run Controls we put then update the run-command (if b (dboard:tabdat-target-set! tabdat (string-split b "/"))) (dashboard:update-run-command tabdat)) "command-testname-selector tb action")) #:value (dboard:test-patt->lines (dboard:tabdat-test-patts-use tabdat)) #:expand "HORIZONTAL" ;; #:size "10x30" )) (tb (iup:treebox #:value 0 #:title "Runs" ;; was #:name -- iup 3.19 changed this... "Changed: [DEPRECATED REMOVED] removed the old attribute NAMEid from IupTree to avoid conflict with the common attribute NAME. Use the TITLEid attribute." #:expand "YES" #:addexpanded "YES" #:size "10x" #:selection-cb (lambda (obj id state) (debug:catch-and-dump (lambda () (let* ((run-path (tree:node->path obj id)) (run-id (tree-path->run-id tabdat (cdr run-path)))) |
︙ | ︙ | |||
1438 1439 1440 1441 1442 1443 1444 | (dboard:tabdat-curr-run-id-set! tabdat run-id) (dboard:tabdat-view-changed-set! tabdat #t)) (debug:print-error 5 *default-log-port* "tree-path->run-id returned non-number " run-id)))) "treebox")) ;; (print "path: " (tree:node->path obj id) " run-id: " run-id) ))) (dboard:tabdat-runs-tree-set! tabdat tb) | > | > > | 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 | (dboard:tabdat-curr-run-id-set! tabdat run-id) (dboard:tabdat-view-changed-set! tabdat #t)) (debug:print-error 5 *default-log-port* "tree-path->run-id returned non-number " run-id)))) "treebox")) ;; (print "path: " (tree:node->path obj id) " run-id: " run-id) ))) (dboard:tabdat-runs-tree-set! tabdat tb) (iup:detachbox (iup:vbox tb txtbox)))) ;;====================================================================== ;; R U N C O N T R O L S ;;====================================================================== ;; ;; A gui for launching tests ;; |
︙ | ︙ | |||
1507 1508 1509 1510 1511 1512 1513 | (dcommon:command-runname-selector commondat tabdat tab-num: tab-num) (dcommon:command-testname-selector commondat tabdat update-keyvals)) (iup:vbox (iup:split #:orientation "HORIZONTAL" #:value 800 (let* ((cnv-obj (iup:canvas | | | 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 | (dcommon:command-runname-selector commondat tabdat tab-num: tab-num) (dcommon:command-testname-selector commondat tabdat update-keyvals)) (iup:vbox (iup:split #:orientation "HORIZONTAL" #:value 800 (let* ((cnv-obj (iup:canvas ;; #:size "250x250" ;; "500x400" #:expand "YES" #:scrollbar "YES" #:posx "0.5" #:posy "0.5" #:action (make-canvas-action (lambda (c xadj yadj) (debug:catch-and-dump |
︙ | ︙ | |||
1552 1553 1554 1555 1556 1557 1558 | ))) cnv-obj) (let* ((hb1 (iup:hbox)) (graph-cell-table (dboard:tabdat-graph-cell-table tabdat)) (changed #f) (graph-matrix (iup:matrix #:alignment1 "ALEFT" | | | | 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 | ))) cnv-obj) (let* ((hb1 (iup:hbox)) (graph-cell-table (dboard:tabdat-graph-cell-table tabdat)) (changed #f) (graph-matrix (iup:matrix #:alignment1 "ALEFT" ;; #:expand "YES" ;; "HORIZONTAL" #:scrollbar "YES" #:numcol 10 #:numlin 20 #:numcol-visible 5 ;; (min 8) #:numlin-visible 1 #:click-cb (lambda (obj row col status) (let* ((graph-cell (conc row ":" col)) (graph-dat (hash-table-ref/default graph-cell-table graph-cell #f)) (graph-flag (dboard:graph-dat-flag graph-dat))) |
︙ | ︙ | |||
1609 1610 1611 1612 1613 1614 1615 | ;; display and manage a single run at a time (define (tree-path->run-id tabdat path) (if (not (null? path)) (hash-table-ref/default (dboard:tabdat-path-run-ids tabdat) path #f) #f)) | | | | | | | | | | | | | < > | | | | | | | | | | | | < | | > > | 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 | ;; display and manage a single run at a time (define (tree-path->run-id tabdat path) (if (not (null? path)) (hash-table-ref/default (dboard:tabdat-path-run-ids tabdat) path #f) #f)) ;; (define (dboard:get-tests-dat tabdat run-id last-update) ;; (let* ((access-mode (dboard:tabdat-access-mode tabdat)) ;; (tdat (if run-id (db:dispatch-query access-mode rmt:get-tests-for-run db:get-tests-for-run ;; run-id ;; (hash-table-ref/default (dboard:tabdat-searchpatts tabdat) "test-name" "%/%") ;; (hash-table-keys (dboard:tabdat-state-ignore-hash tabdat)) ;; '() ;; (hash-table-keys (dboard:tabdat-status-ignore-hash tabdat)) ;; '() ;; #f #f ;; offset limit ;; (dboard:tabdat-hide-not-hide tabdat) ;; not-in ;; #f #f ;; sort-by sort-order ;; #f ;; get all? "id,testname,item_path,state,status,event_time,run_duration" ;; qryval ;; (if (dboard:tabdat-filters-changed tabdat) ;; 0 ;; last-update) ;; *dashboard-mode*) ;; '()))) ;; get 'em all ;; ;; (debug:print 0 *default-log-port* "dboard:get-tests-dat: got " (length tdat) " test records for run " run-id) ;; (sort tdat (lambda (a b) ;; (let* ((aval (vector-ref a 2)) ;; (bval (vector-ref b 2)) ;; (anum (string->number aval)) ;; (bnum (string->number bval))) ;; (if (and anum bnum) ;; (< anum bnum) ;; (string<= aval bval))))))) (define (dashboard:safe-cadr-assoc name lst) (let ((res (assoc name lst))) (if (and res (> (length res) 1)) (cadr res) #f))) (define (dboard:update-tree tabdat runs-hash runs-header tb) (let* ((access-mode (dboard:tabdat-access-mode tabdat)) (run-ids (sort (filter number? (hash-table-keys runs-hash)) (lambda (a b) (let* ((record-a (hash-table-ref runs-hash a)) (record-b (hash-table-ref runs-hash b)) (time-a (db:get-value-by-header record-a runs-header "event_time")) (time-b (db:get-value-by-header record-b runs-header "event_time"))) (< time-a time-b))))) (changed #f) (last-runs-update (dboard:tabdat-last-runs-update tabdat)) (runs-dat (rmt:get-runs-by-patt (dboard:tabdat-keys tabdat) "%" #f #f #f #f last-runs-update))) (dboard:tabdat-last-runs-update-set! tabdat (- (current-seconds) 2)) (for-each (lambda (run-id) (let* ((run-record (hash-table-ref/default runs-hash run-id #f)) (key-vals (map (lambda (key) (let ((val (db:get-value-by-header run-record runs-header key))) (if (string? val) val ""))) (dboard:tabdat-keys tabdat))) (run-name (db:get-value-by-header run-record runs-header "runname")) (col-name (conc (string-intersperse key-vals "\n") "\n" run-name)) (run-path (append key-vals (list run-name)))) (if (not (hash-table-ref/default (dboard:tabdat-path-run-ids tabdat) run-path #f)) ;; (let ((existing (tree:find-node tb run-path))) ;; (if (not existing) |
︙ | ︙ | |||
1687 1688 1689 1690 1691 1692 1693 | (reverse (sort (hash-table-values tests-ht) (lambda (a b) (let ((a-test-name (db:test-get-testname a)) (a-item-path (db:test-get-item-path a)) (b-test-name (db:test-get-testname b)) | | > > > > | | | | | | 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 | (reverse (sort (hash-table-values tests-ht) (lambda (a b) (let ((a-test-name (db:test-get-testname a)) (a-item-path (db:test-get-item-path a)) (b-test-name (db:test-get-testname b)) (b-item-path (db:test-get-item-path b)) (a-event-time (db:test-get-event_time a)) (b-event-time (db:test-get-event_time b))) (if (not (equal? a-test-name b-test-name)) (> a-event-time b-event-time) (cond ((< 0 (string-compare3 a-test-name b-test-name)) #t) ((> 0 (string-compare3 a-test-name b-test-name)) #f) ((< 0 (string-compare3 a-item-path b-item-path)) #t) (else #f)))))))) (define (dashboard:run-id->tests-mindat run-id tabdat runs-hash) (let* ((run (hash-table-ref/default runs-hash run-id #f)) (key-vals (rmt:get-key-vals run-id)) (testnamepatt (or (dboard:tabdat-test-patts tabdat) "%/%")) (tests-ht (dboard:get-tests-for-run-duplicate tabdat run-id run testnamepatt key-vals)) |
︙ | ︙ | |||
1725 1726 1727 1728 1729 1730 1731 | hide-clean: hide-clean) #f))) (define (dashboard:get-runs-hash tabdat) (let* ((access-mode (dboard:tabdat-access-mode tabdat)) (last-runs-update 0);;(dboard:tabdat-last-runs-update tabdat)) | < | < < | | 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 | hide-clean: hide-clean) #f))) (define (dashboard:get-runs-hash tabdat) (let* ((access-mode (dboard:tabdat-access-mode tabdat)) (last-runs-update 0);;(dboard:tabdat-last-runs-update tabdat)) (runs-dat (rmt:get-runs-by-patt (dboard:tabdat-keys tabdat) "%" #f #f #f #f last-runs-update)) (runs-header (vector-ref runs-dat 0)) ;; 0 is header, 1 is list of records (runs (vector-ref runs-dat 1)) (run-id (dboard:tabdat-curr-run-id tabdat)) (runs-hash (let ((ht (make-hash-table))) (for-each (lambda (run) (hash-table-set! ht (db:get-value-by-header run runs-header "id") run)) runs) ht))) runs-hash)) (define (dashboard:runs-summary-updater commondat tabdat tb cell-lookup run-matrix) ;; (if (dashboard:database-changed? commondat tabdat context-key: 'runs-summary-rundat) (dashboard:do-update-rundat tabdat) ;; ) (dboard:runs-summary-control-panel-updater tabdat) (let* ((last-runs-update (dboard:tabdat-last-runs-update tabdat)) (runs-dat (rmt:get-runs-by-patt (dboard:tabdat-keys tabdat) "%" #f #f #f #f last-runs-update)) (runs-header (vector-ref runs-dat 0)) ;; 0 is header, 1 is list of records (runs (vector-ref runs-dat 1)) (run-id (dboard:tabdat-curr-run-id tabdat)) (runs-hash (dashboard:get-runs-hash tabdat)) ;; (runs-hash (let ((ht (make-hash-table))) ;; (for-each (lambda (run) ;; (hash-table-set! ht (db:get-value-by-header run runs-header "id") run)) |
︙ | ︙ | |||
1863 1864 1865 1866 1867 1868 1869 | ;; ;; General info about the run(s) and megatest area (define (dashboard:summary commondat tabdat #!key (tab-num #f)) (let* ((rawconfig (read-config (conc *toppath* "/megatest.config") #f #f)) ;; changed to #f since I want #{} to be expanded by [system ...] to NOT be expanded. WAS: 'return-string))) (changed #f)) (iup:vbox (iup:split | | | 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 | ;; ;; General info about the run(s) and megatest area (define (dashboard:summary commondat tabdat #!key (tab-num #f)) (let* ((rawconfig (read-config (conc *toppath* "/megatest.config") #f #f)) ;; changed to #f since I want #{} to be expanded by [system ...] to NOT be expanded. WAS: 'return-string))) (changed #f)) (iup:vbox (iup:split #:value 300 (iup:frame #:title "General Info" (iup:vbox (iup:hbox (iup:label "Area Path") (iup:textbox #:value *toppath* #:expand "HORIZONTAL")) (iup:hbox |
︙ | ︙ | |||
1900 1901 1902 1903 1904 1905 1906 | (define (dboard:add-external-tab commondat view-name views-cfgdat tabs tab-num) (let* ((success #t) ;; at any stage of the process set this flag to #f to skip downstream steps. Intention here is to recover gracefully if user provided tabs fail to load. (source (configf:lookup views-cfgdat view-name "source")) (viewgen (configf:lookup views-cfgdat view-name "viewgen")) (updater (configf:lookup views-cfgdat view-name "updater")) (result-child #f)) | | | 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 | (define (dboard:add-external-tab commondat view-name views-cfgdat tabs tab-num) (let* ((success #t) ;; at any stage of the process set this flag to #f to skip downstream steps. Intention here is to recover gracefully if user provided tabs fail to load. (source (configf:lookup views-cfgdat view-name "source")) (viewgen (configf:lookup views-cfgdat view-name "viewgen")) (updater (configf:lookup views-cfgdat view-name "updater")) (result-child #f)) (if (and (common:file-exists? source) (file-read-access? source)) (handle-exceptions exn (begin (print-call-chain) (debug:print 0 *default-log-port* " message: " ((condition-property-accessor 'exn 'message) exn)) (debug:print 0 *default-log-port* "ERROR: failed to load " source ", try loading in the repl: megatest -repl") |
︙ | ︙ | |||
2044 2045 2046 2047 2048 2049 2050 | ;; This is the Run Summary tab ;; (define (dashboard:runs-summary commondat tabdat #!key (tab-num #f)) (let* ((update-mutex (dboard:commondat-update-mutex commondat)) (tb (iup:treebox #:value 0 | | > | | 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 | ;; This is the Run Summary tab ;; (define (dashboard:runs-summary commondat tabdat #!key (tab-num #f)) (let* ((update-mutex (dboard:commondat-update-mutex commondat)) (tb (iup:treebox #:value 0 ;;#:name "Runs" #:title "Runs" ;; was #:name -- iup 3.19 changed this... "Changed: [DEPRECATED REMOVED] removed the old attribute NAMEid from IupTree to avoid conflict with the common attribute NAME. Use the TITLEid attribute." #:expand "YES" #:addexpanded "YES" #:selection-cb (lambda (obj id state) (debug:catch-and-dump (lambda () ;; (print "obj: " obj ", id: " id ", state: " state) (let* ((run-path (tree:node->path obj id)) (run-id (tree-path->run-id tabdat (cdr run-path)))) |
︙ | ︙ | |||
2106 2107 2108 2109 2110 2111 2112 | tpatt)) "%"))) (item-path (db:test-get-item-path (rmt:get-test-info-by-id run-id test-id))) (item-test-path (conc test-name "/" (if (equal? item-path "") "%" item-path))) (status-chars (char-set->list (string->char-set status))) | | | | | | 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 | tpatt)) "%"))) (item-path (db:test-get-item-path (rmt:get-test-info-by-id run-id test-id))) (item-test-path (conc test-name "/" (if (equal? item-path "") "%" item-path))) (status-chars (char-set->list (string->char-set status))) (run-id (dboard:tabdat-curr-run-id tabdat))) (debug:print-info 13 *default-log-port* "status-chars=["status-chars"] status=["status"]") (cond ((member #\1 status-chars) ;; 1 is left mouse button (dboard:launch-testpanel run-id test-id)) ((member #\2 status-chars) ;; 2 is middle mouse button (debug:print-info 13 *default-log-port* "mmb- test-name="test-name" testpatt="testpatt) (iup:show (dashboard:context-menu run-id test-id target runname test-name testpatt item-test-path test-info) ;; popup-menu #:x 'mouse #:y 'mouse #:modal? "NO") ) (else (debug:print-info 13 *default-log-port* "unhandled status in run-summary-click-cb. Doing right click action. (status is corrupted on Brandon's ubuntu host - bad/buggy iup install??" ) (iup:show (dashboard:context-menu run-id test-id target runname test-name testpatt item-test-path test-info) ;; popup-menu #:x 'mouse #:y 'mouse #:modal? "NO") ) ) )) "runs-summary-click-callback")))) |
︙ | ︙ | |||
2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 | run-matrix) (dboard:make-controls commondat tabdat extra-widget: runs-summary-control-panel)))) ;;====================================================================== ;; R U N S ;;====================================================================== (define (dboard:make-controls commondat tabdat #!key (extra-widget #f) ) (let ((btn-fontsz (dboard:tabdat-runs-btn-fontsz tabdat))) (iup:hbox (iup:vbox (iup:frame #:title "filter test and items" (iup:vbox | > > > > > > > > > > > > > > > > > > | 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 | run-matrix) (dboard:make-controls commondat tabdat extra-widget: runs-summary-control-panel)))) ;;====================================================================== ;; R U N S ;;====================================================================== (define (dboard:squarify toggles size) (let loop ((hed (car toggles)) (tal (cdr toggles)) (cur '()) (res '())) (let* ((ovrflo (>= (length cur) size)) (newcur (if ovrflo (list hed) (cons hed cur))) (newres (if ovrflo (cons cur res) res))) (if (null? tal) (if ovrflo newres (cons newcur res)) (loop (car tal)(cdr tal) newcur newres))))) (define (dboard:make-controls commondat tabdat #!key (extra-widget #f) ) (let ((btn-fontsz (dboard:tabdat-runs-btn-fontsz tabdat))) (iup:hbox (iup:vbox (iup:frame #:title "filter test and items" (iup:vbox |
︙ | ︙ | |||
2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 | (update-search commondat tabdat "test-name" val)) "make-controls"))) (iup:hbox (iup:button "Quit" #:action (lambda (obj) (exit)) #:expand "NO" #:size "40x15") (iup:button "Refresh" #:action (lambda (obj) (mark-for-update tabdat)) #:expand "NO" #:size "40x15") (iup:button "Collapse" #:action (lambda (obj) (debug:catch-and-dump (lambda () (let ((myname (iup:attribute obj "TITLE"))) (if (equal? myname "Collapse") | > > > > > > > > > > | 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 | (update-search commondat tabdat "test-name" val)) "make-controls"))) (iup:hbox (iup:button "Quit" #:action (lambda (obj) (exit)) #:expand "NO" #:size "40x15") (iup:button "Refresh" #:action (lambda (obj) (dboard:tabdat-last-data-update-set! tabdat 0) (dboard:tabdat-last-runs-update-set! tabdat 0) (dboard:tabdat-run-update-times-set! tabdat (make-hash-table)) (dboard:tabdat-last-test-dat-set! tabdat (make-hash-table)) (dboard:tabdat-allruns-set! tabdat '()) (dboard:tabdat-allruns-by-id-set! tabdat (make-hash-table)) (dboard:tabdat-done-runs-set! tabdat '()) (dboard:tabdat-not-done-runs-set! tabdat '()) (dboard:tabdat-view-changed-set! tabdat #t) (dboard:commondat-please-update-set! commondat #t) (mark-for-update tabdat)) #:expand "NO" #:size "40x15") (iup:button "Collapse" #:action (lambda (obj) (debug:catch-and-dump (lambda () (let ((myname (iup:attribute obj "TITLE"))) (if (equal? myname "Collapse") |
︙ | ︙ | |||
2221 2222 2223 2224 2225 2226 2227 | #:action (lambda (obj val index lbstate) (set! *tests-sort-reverse* index) (mark-for-update tabdat)))) (default-cmd (car (list-ref *tests-sort-type-index* *tests-sort-reverse*)))) (iuplistbox-fill-list sort-lb cmds-list selected-item: default-cmd) | | | | | | | | | 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 | #:action (lambda (obj val index lbstate) (set! *tests-sort-reverse* index) (mark-for-update tabdat)))) (default-cmd (car (list-ref *tests-sort-type-index* *tests-sort-reverse*)))) (iuplistbox-fill-list sort-lb cmds-list selected-item: default-cmd) ;; (set! hide-empty (iup:button "HideEmpty" ;; ;; #:expand HORIZONTAL" ;; #:expand "NO" #:size "80x15" ;; #:action (lambda (obj) ;; (dboard:tabdat-hide-empty-runs-set! tabdat (not (dboard:tabdat-hide-empty-runs tabdat))) ;; (iup:attribute-set! obj "TITLE" (if (dboard:tabdat-hide-empty-runs tabdat) "+HideE" "-HideE")) ;; (mark-for-update tabdat)))) (set! hide (iup:button "Hide" #:expand "NO" #:size "40x15" ;; #:expand "HORIZONTAL" #:action (lambda (obj) (dboard:tabdat-hide-not-hide-set! tabdat #t) ;; (not (dboard:tabdat-hide-not-hide tabdat))) ;; (iup:attribute-set! obj "TITLE" (if (dboard:tabdat-hide-not-hide tabdat) "HideTests" "NotHide")) (iup:attribute-set! hide "BGCOLOR" sel-color) (iup:attribute-set! show "BGCOLOR" nonsel-color) |
︙ | ︙ | |||
2261 2262 2263 2264 2265 2266 2267 | (iup:hbox)) ;; empty widget ))) | < < < < < | | | | | | | | | | | < < | | | | | | | | | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | | | | | | | | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 | (iup:hbox)) ;; empty widget ))) (let* ((status-toggles (map (lambda (status) (iup:toggle (conc status) #:fontsize 8 ;; btn-fontsz ;; "10" ;; #:expand "HORIZONTAL" #:action (lambda (obj val) (mark-for-update tabdat) (if (eq? val 1) (hash-table-set! (dboard:tabdat-status-ignore-hash tabdat) status #t) (hash-table-delete! (dboard:tabdat-status-ignore-hash tabdat) status)) (set-bg-on-filter commondat tabdat)))) (map cadr *common:std-statuses*))) ;; '("PASS" "FAIL" "WARN" "CHECK" "WAIVED" "STUCK/DEAD" "n/a" "SKIP"))) (state-toggles (map (lambda (state) (iup:toggle (conc state) #:fontsize 8 ;; btn-fontsz ;; #:expand "HORIZONTAL" #:action (lambda (obj val) (mark-for-update tabdat) (if (eq? val 1) (hash-table-set! (dboard:tabdat-state-ignore-hash tabdat) state #t) (hash-table-delete! (dboard:tabdat-state-ignore-hash tabdat) state)) (set-bg-on-filter commondat tabdat)))) (map cadr *common:std-states*))) ;; '("RUNNING" "COMPLETED" "INCOMPLETE" "LAUNCHED" "NOT_STARTED" "KILLED" "DELETED"))) (num-toggle-cols (inexact->exact (round (/ (max (length status-toggles)(length state-toggles)) 3))))) (iup:vbox (iup:hbox (iup:frame #:title "states" (apply iup:hbox (map (lambda (colgrp) (apply iup:vbox colgrp)) (dboard:squarify state-toggles 3)))) (iup:frame #:title "statuses" (apply iup:hbox (map (lambda (colgrp) (apply iup:vbox colgrp)) (dboard:squarify status-toggles 3))))) ;; ;; (iup:frame ;; #:title "state/status filter" ;; (iup:vbox ;; (apply ;; iup:hbox ;; (map ;; (lambda (status-toggle state-toggle) ;; (iup:vbox ;; status-toggle ;; state-toggle)) ;; status-toggles state-toggles)) ;; horizontal slider was here ))))) (define (dashboard:runs-horizontal-slider tabdat ) (iup:valuator #:valuechanged_cb (lambda (obj) (let ((val (inexact->exact (round (/ (string->number (iup:attribute obj "VALUE")) 10)))) (oldmax (string->number (iup:attribute obj "MAX"))) (maxruns (dboard:tabdat-tot-runs tabdat))) (dboard:tabdat-start-run-offset-set! tabdat val) (mark-for-update tabdat) (debug:print 6 *default-log-port* "(dboard:tabdat-start-run-offset tabdat) " (dboard:tabdat-start-run-offset tabdat) " maxruns: " maxruns ", val: " val " oldmax: " oldmax) (iup:attribute-set! obj "MAX" (* maxruns 10)))) #:expand "HORIZONTAL" #:max (* 10 (max (hash-table-size (dboard:tabdat-allruns-by-id tabdat)) 10)) #:min 0 #:step 0.01)) (define (make-dashboard-buttons commondat) ;; runs-sum-dat new-view-dat) (let* ((stats-dat (dboard:tabdat-make-data)) (runs-dat (dboard:tabdat-make-data)) (onerun-dat (dboard:tabdat-make-data)) ;; name for run-summary structure (runcontrols-dat (dboard:tabdat-make-data)) (runtimes-dat (dboard:tabdat-make-data)) |
︙ | ︙ | |||
2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 | (iup:label) ;; (iup:valuator) (apply iup:vbox (map (lambda (x) (let ((res (iup:hbox #:expand "HORIZONTAL" (iup:label x #:size (conc 40 btn-height) #:fontsize btn-fontsz #:expand "NO") ;; "HORIZONTAL") (iup:textbox #:size (conc 35 btn-height) #:fontsize btn-fontsz #:value "%" #:expand "NO" ;; "HORIZONTAL" #:action (lambda (obj unk val) (mark-for-update runs-dat) (update-search commondat runs-dat x val)))))) (set! i (+ i 1)) res)) keynames))))) (let loop ((testnum 0) (res '())) | > > > | 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 | (iup:label) ;; (iup:valuator) (apply iup:vbox (map (lambda (x) (let ((res (iup:hbox #:expand "HORIZONTAL" (iup:label x #:size (conc 40 btn-height) #:fontsize btn-fontsz #:expand "NO") ;; "HORIZONTAL") (iup:textbox #:size (conc 35 btn-height) #:fontsize btn-fontsz #:value "%" #:expand "NO" ;; "HORIZONTAL" #:action (lambda (obj unk val) ;; each field (field name is "x" var) live updates ;; the search filter as it is typed (dboard:tabdat-target-set! runs-dat #f) ;; ensure the fields text boxes are used and not the info from the tree (mark-for-update runs-dat) (update-search commondat runs-dat x val)))))) (set! i (+ i 1)) res)) keynames))))) (let loop ((testnum 0) (res '())) |
︙ | ︙ | |||
2603 2604 2605 2606 2607 2608 2609 | "%" tpatt)) "%"))) (item-path (db:test-get-item-path (rmt:get-test-info-by-id run-id test-id))) (item-test-path (conc test-name "/" (if (equal? item-path "") "%" item-path)))) | | | < < | | > > | > | 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 | "%" tpatt)) "%"))) (item-path (db:test-get-item-path (rmt:get-test-info-by-id run-id test-id))) (item-test-path (conc test-name "/" (if (equal? item-path "") "%" item-path)))) (iup:show (dashboard:context-menu run-id test-id target runname test-name testpatt item-test-path test-info) ;; popup-menu #:x 'mouse #:y 'mouse #:modal? "NO") ;; (print "got here") )) (if (eq? pressed 0) (let* ((toolpath (car (argv))) (buttndat (hash-table-ref (dboard:tabdat-buttondat runs-dat) button-key)) (test-id (db:test-get-id (vector-ref buttndat 3))) (run-id (db:test-get-run_id (vector-ref buttndat 3)))) (dboard:launch-testpanel run-id test-id)))))))) (hash-table-set! (dboard:tabdat-buttondat runs-dat) button-key (vector 0 "100 100 100" button-key #f #f)) (vector-set! testvec testnum butn) (loop runnum (+ testnum 1) testvec (cons butn res)))))) ;; now assemble the hdrlst and bdylst and kick off the dialog (iup:show (iup:dialog #:title (conc "Megatest dashboard " (current-user-name) ":" *toppath*) #:menu (dcommon:main-menu) (let* ((runs-view (iup:vbox (iup:split #:orientation "VERTICAL" ;; "HORIZONTAL" #:value 100 (dboard:runs-tree-browser commondat runs-dat) (iup:split #:value 100 ;; left most block, including row names (apply iup:vbox lftlst) ;; right hand block, including cells (iup:vbox #:expand "YES" ;; the header (apply iup:hbox (reverse hdrlst)) (apply iup:hbox (reverse bdylst)) (dashboard:runs-horizontal-slider runs-dat)))) controls )) (views-cfgdat (common:load-views-config)) (additional-tabnames '()) (tab-start-num 5) ;; DON'T FORGET TO UPDATE THIS WHEN CHANGING THE STANDARD TABS BELOW ;; (data (dboard:tabdat-init (make-d:data))) (additional-views ;; process views-dat |
︙ | ︙ | |||
2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 | result)) (tabs (apply iup:tabs #:tabchangepos-cb (lambda (obj curr prev) (debug:catch-and-dump (lambda () (let* ((tab-num (dboard:commondat-curr-tab-num commondat)) (tabdat (dboard:common-get-tabdat commondat tab-num: tab-num))) (dboard:tabdat-layout-update-ok-set! tabdat #f)) (dboard:commondat-curr-tab-num-set! commondat curr) (let* ((tab-num (dboard:commondat-curr-tab-num commondat)) (tabdat (dboard:common-get-tabdat commondat tab-num: tab-num))) (dboard:commondat-please-update-set! commondat #t) (dboard:tabdat-layout-update-ok-set! tabdat #t))) "tabchangepos")) (dashboard:summary commondat stats-dat tab-num: 0) runs-view (dashboard:runs-summary commondat onerun-dat tab-num: 2) ;; (dashboard:new-view db data new-view-dat tab-num: 3) (dashboard:run-controls commondat runcontrols-dat tab-num: 3) (dashboard:run-times commondat runtimes-dat tab-num: 4) additional-views))) ;; (set! (iup:callback tabs tabchange-cb:) (lambda (a b c)(print "SWITCHED TO TAB: " a " " b " " c))) (iup:attribute-set! tabs "TABTITLE0" "Summary") (iup:attribute-set! tabs "TABTITLE1" "Runs") (iup:attribute-set! tabs "TABTITLE2" "Run Summary") (iup:attribute-set! tabs "TABTITLE3" "Run Control") (iup:attribute-set! tabs "TABTITLE4" "Run Times") | > > > | 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 | result)) (tabs (apply iup:tabs #:tabchangepos-cb (lambda (obj curr prev) (debug:catch-and-dump (lambda () (let* ((tab-num (dboard:commondat-curr-tab-num commondat)) (tabdat (dboard:common-get-tabdat commondat tab-num: tab-num))) (dboard:tabdat-layout-update-ok-set! tabdat #f)) (dboard:commondat-curr-tab-num-set! commondat curr) (let* ((tab-num (dboard:commondat-curr-tab-num commondat)) (tabdat (dboard:common-get-tabdat commondat tab-num: tab-num))) (dboard:commondat-please-update-set! commondat #t) (dboard:tabdat-layout-update-ok-set! tabdat #t))) "tabchangepos")) (dashboard:summary commondat stats-dat tab-num: 0) runs-view (dashboard:runs-summary commondat onerun-dat tab-num: 2) ;; (dashboard:new-view db data new-view-dat tab-num: 3) (dashboard:run-controls commondat runcontrols-dat tab-num: 3) (dashboard:run-times commondat runtimes-dat tab-num: 4) ;; (dashboard:runs-summary commondat onerun-dat tab-num: 4) additional-views))) ;; (set! (iup:callback tabs tabchange-cb:) (lambda (a b c)(print "SWITCHED TO TAB: " a " " b " " c))) (iup:attribute-set! tabs "TABTITLE0" "Summary") (iup:attribute-set! tabs "TABTITLE1" "Runs") (iup:attribute-set! tabs "TABTITLE2" "Run Summary") (iup:attribute-set! tabs "TABTITLE3" "Run Control") (iup:attribute-set! tabs "TABTITLE4" "Run Times") |
︙ | ︙ | |||
2756 2757 2758 2759 2760 2761 2762 | (common:max (map (lambda (filen) (file-modification-time filen)) (glob (conc dbdir "/*.db*")))))) (define (dashboard:monitor-changed? commondat tabdat) (let* ((run-update-time (current-seconds)) (monitor-db-path (dboard:tabdat-monitor-db-path tabdat)) | | | 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 | (common:max (map (lambda (filen) (file-modification-time filen)) (glob (conc dbdir "/*.db*")))))) (define (dashboard:monitor-changed? commondat tabdat) (let* ((run-update-time (current-seconds)) (monitor-db-path (dboard:tabdat-monitor-db-path tabdat)) (monitor-modtime (if (and monitor-db-path (common:file-exists? monitor-db-path)) (file-modification-time monitor-db-path) -1))) (if (and (eq? (dboard:commondat-curr-tab-num commondat) 0) (or (> monitor-modtime *last-monitor-update-time*) (> (- run-update-time *last-monitor-update-time*) 5))) ;; update every 1/2 minute just in case (begin (set! *last-monitor-update-time* run-update-time) ;; monitor-modtime) |
︙ | ︙ | |||
2885 2886 2887 2888 2889 2890 2891 | (db:test-get-event_time (hash-table-ref testsdat (car b)))))))))) ;; run times tab data updater ;; (define (dashboard:run-times-tab-run-data-updater commondat tabdat tab-num) (let* ((access-mode (dboard:tabdat-access-mode tabdat)) (last-runs-update (dboard:tabdat-last-runs-update tabdat)) | < < | | 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 | (db:test-get-event_time (hash-table-ref testsdat (car b)))))))))) ;; run times tab data updater ;; (define (dashboard:run-times-tab-run-data-updater commondat tabdat tab-num) (let* ((access-mode (dboard:tabdat-access-mode tabdat)) (last-runs-update (dboard:tabdat-last-runs-update tabdat)) (runs-dat (rmt:get-runs-by-patt (dboard:tabdat-keys tabdat) "%" #f #f #f #f last-runs-update)) (runs-header (vector-ref runs-dat 0)) ;; 0 is header, 1 is list of records (runs-hash (let ((ht (make-hash-table))) (for-each (lambda (run) (hash-table-set! ht (db:get-value-by-header run runs-header "id") run)) (vector-ref runs-dat 1)) ht)) (run-ids (sort (filter number? (hash-table-keys runs-hash)) |
︙ | ︙ | |||
3473 3474 3475 3476 3477 3478 3479 | ;;====================================================================== ;; The heavy lifting starts here ;;====================================================================== (define (main) (let ((mtdb-path (conc *toppath* "/megatest.db"))) ;; | | | | 3436 3437 3438 3439 3440 3441 3442 3443 3444 3445 3446 3447 3448 3449 3450 3451 3452 3453 3454 3455 3456 3457 3458 | ;;====================================================================== ;; The heavy lifting starts here ;;====================================================================== (define (main) (let ((mtdb-path (conc *toppath* "/megatest.db"))) ;; (if (and (common:file-exists? mtdb-path) (file-write-access? mtdb-path)) (if (not (args:get-arg "-skip-version-check")) (common:exit-on-version-changed))) (let* ((commondat (dboard:commondat-make))) ;; Move this stuff to db.scm? I'm not sure that is the right thing to do... (cond ((args:get-arg "-test") ;; run-id,test-id (let* ((dat (let ((d (map string->number (string-split (args:get-arg "-test") ",")))) (if (> (length d) 1) d (list #f #f)))) (run-id (car dat)) (test-id (cadr dat))) (if (and (number? run-id) (number? test-id) |
︙ | ︙ | |||
3508 3509 3510 3511 3512 3513 3514 | (lambda () (dashboard:runs-tab-updater commondat 1)) tab-num: 1) (iup:callback-set! *tim* "ACTION_CB" (lambda (time-obj) (let ((update-is-running #f)) | | | | | | | | | | | | | | 3471 3472 3473 3474 3475 3476 3477 3478 3479 3480 3481 3482 3483 3484 3485 3486 3487 3488 3489 3490 3491 3492 3493 3494 3495 3496 3497 3498 3499 3500 3501 3502 3503 3504 3505 3506 3507 3508 | (lambda () (dashboard:runs-tab-updater commondat 1)) tab-num: 1) (iup:callback-set! *tim* "ACTION_CB" (lambda (time-obj) (let ((update-is-running #f)) (mutex-lock! (dboard:commondat-update-mutex commondat)) (set! update-is-running (dboard:commondat-updating commondat)) (if (not update-is-running) (dboard:commondat-updating-set! commondat #t)) (mutex-unlock! (dboard:commondat-update-mutex commondat)) (if (not update-is-running) ;; we know that the update was not running and we now have a lock on doing an update (begin (dboard:common-run-curr-updaters commondat) ;; (dashboard:run-update commondat) (mutex-lock! (dboard:commondat-update-mutex commondat)) (dboard:commondat-updating-set! commondat #f) (mutex-unlock! (dboard:commondat-update-mutex commondat))) )) 1)))) (let ((th1 (make-thread (lambda () (thread-sleep! 1) (dboard:common-run-curr-updaters commondat 0) ;; force update of summary tab ) "update buttons once")) (th2 (make-thread iup:main-loop "Main loop"))) (thread-start! th2) (thread-join! th2))))) ;; ease debugging by loading ~/.dashboardrc (let ((debugcontrolf (conc (get-environment-variable "HOME") "/.dashboardrc"))) (if (common:file-exists? debugcontrolf) (load debugcontrolf))) (if (args:get-arg "-repl") (repl) (main)) |
Modified datashare-testing/.sd.config from [567a2bce44] to [06bbdb5a60].
1 2 3 4 5 6 7 | # Read in the users vars first (so the offical data cannot be overridden [include ~/.datashare.config] # Read in local overrides [include datashare.config] # Replace [storage] with settings entry - more secure | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. # # Read in the users vars first (so the offical data cannot be overridden [include ~/.datashare.config] # Read in local overrides [include datashare.config] # Replace [storage] with settings entry - more secure |
︙ | ︙ |
Modified datashare-testing/.spublish.config from [c513dac9c0] to [5e8382b591].
1 2 3 4 5 6 7 | [settings] target-dir #{scheme (create-directory "/tmp/#{getenv USER}/target" #t)} allowed-users matt mrwellan pjhatwal allowed-chars [0-9a-zA-Z\-\.]+ admins matt [database] | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. # [settings] target-dir #{scheme (create-directory "/tmp/#{getenv USER}/target" #t)} allowed-users matt mrwellan pjhatwal allowed-chars [0-9a-zA-Z\-\.]+ admins matt [database] |
︙ | ︙ |
Modified datashare-testing/.sretrieve.config from [71cb2ce9dc] to [d1c10dc80c].
1 2 | [settings] base-dir /tmp/delme_data | > > > > > > > > > > > > > > > > > | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. # [settings] base-dir /tmp/delme_data allowed-users matt allowed-chars [0-9a-zA-Z\-\.]+ allowed-sub-paths [0-9a-zA-Z\-\.]+ [database] location #{scheme (create-directory "/tmp/#{getenv USER}" #t)} |
Modified datashare-testing/NOTES from [1e24a4d112] to [089c332d65].
1 2 3 | To test sretrieve first publish megatest as v1.60 at least twice to get iterations 0 and 1 | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. To test sretrieve first publish megatest as v1.60 at least twice to get iterations 0 and 1 |
Modified datashare-testing/megatest.config from [85f1bdc170] to [690e33142f].
1 2 3 4 | [v1.60] status released iteration 1 | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. # [v1.60] status released iteration 1 |
Modified datashare-testing/packages.config from [85f1bdc170] to [690e33142f].
1 2 3 4 | [v1.60] status released iteration 1 | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. # [v1.60] status released iteration 1 |
Modified datashare.scm from [aff106f1a7] to [2c1663032f].
1 2 3 | ;; Copyright 2006-2013, Matthew Welland. ;; | | | > > > > > | | > | > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | ;; Copyright 2006-2013, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. (use ssax) (use sxml-serializer) (use sxml-modifications) (use regex) (use srfi-69) (use regex-case) |
︙ | ︙ | |||
224 225 226 227 228 229 230 | (define (datashare:open-db configdat) (let ((path (configf:lookup configdat "database" "location"))) (if (and path (directory? path) (file-read-access? path)) (let* ((dbpath (conc path "/datashare.db")) (writeable (file-write-access? dbpath)) | | | 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 | (define (datashare:open-db configdat) (let ((path (configf:lookup configdat "database" "location"))) (if (and path (directory? path) (file-read-access? path)) (let* ((dbpath (conc path "/datashare.db")) (writeable (file-write-access? dbpath)) (dbexists (common:file-exists? dbpath)) (handler (make-busy-timeout 136000))) (handle-exceptions exn (begin (debug:print 2 *default-log-port* "ERROR: problem accessing db " dbpath ((condition-property-accessor 'exn 'message) exn)) (exit)) |
︙ | ︙ | |||
411 412 413 414 415 416 417 | res))) (cons 0 #f) paths)) ;; remove existing link and if possible ... ;; create path to next of tip of target, create link back to source (define (datashare:build-dir-make-link source target) | | | 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 | res))) (cons 0 #f) paths)) ;; remove existing link and if possible ... ;; create path to next of tip of target, create link back to source (define (datashare:build-dir-make-link source target) (if (common:file-exists? target)(datashare:backup-move target)) (create-directory (pathname-directory target) #t) (create-symbolic-link source target)) (define (datashare:backup-move path) (let* ((trashdir (conc (pathname-directory path) "/.trash")) (trashfile (conc trashdir "/" (current-seconds) "-" (pathname-file path)))) (create-directory trashdir #t) |
︙ | ︙ | |||
516 517 518 519 520 521 522 | (conc "/" (string-intersperse (map conc pathlst) "/"))) (define (datashare:path->lst path) (string-split path "/")) (define (datashare:pathdat-apply-heuristics configdat path) (cond | | | 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 | (conc "/" (string-intersperse (map conc pathlst) "/"))) (define (datashare:path->lst path) (string-split path "/")) (define (datashare:pathdat-apply-heuristics configdat path) (cond ((common:file-exists? path) "found") (else (conc path " not installed")))) (define (datashare:get-view configdat) (iup:vbox (iup:hbox (let* ((label-size "60x") ;; filter elements |
︙ | ︙ | |||
690 691 692 693 694 695 696 | (set! (current-effective-user-id) eid)))) (define (datashare:find name paths) (if (null? paths) #f (let loop ((hed (car paths)) (tal (cdr paths))) | | | | 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 | (set! (current-effective-user-id) eid)))) (define (datashare:find name paths) (if (null? paths) #f (let loop ((hed (car paths)) (tal (cdr paths))) (if (common:file-exists? (conc hed "/" name)) hed (if (null? tal) #f (loop (car tal)(cdr tal))))))) ;;====================================================================== ;; MAIN ;;====================================================================== (define (datashare:load-config exe-dir exe-name) (let* ((fname (conc exe-dir "/." exe-name ".config"))) (ini:property-separator-patt " * *") (ini:property-separator #\space) (if (common:file-exists? fname) ;; (ini:read-ini fname) (read-config fname #f #t) (make-hash-table)))) (define (datashare:process-action configdat action . args) (case (string->symbol action) ((get) |
︙ | ︙ | |||
783 784 785 786 787 788 789 | (conc "\"" (vector-ref x 4) "\"")) (print (vector-ref x 0)))) versions) (sqlite3:finalize! db))))) ;; ease debugging by loading ~/.dashboardrc - REMOVE FROM PRODUCTION! (let ((debugcontrolf (conc (get-environment-variable "HOME") "/.datasharerc"))) | | | 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 | (conc "\"" (vector-ref x 4) "\"")) (print (vector-ref x 0)))) versions) (sqlite3:finalize! db))))) ;; ease debugging by loading ~/.dashboardrc - REMOVE FROM PRODUCTION! (let ((debugcontrolf (conc (get-environment-variable "HOME") "/.datasharerc"))) (if (common:file-exists? debugcontrolf) (load debugcontrolf))) (define (main) (let* ((args (argv)) (prog (car args)) (rema (cdr args)) (exe-name (pathname-file (car (argv)))) |
︙ | ︙ |
Modified db.scm from [76ec962e7c] to [62e275181d].
1 2 3 | ;;====================================================================== ;; Copyright 2006-2016, Matthew Welland. ;; | | | > > > > > | | > | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | ;;====================================================================== ;; Copyright 2006-2016, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. ;; ;;====================================================================== ;;====================================================================== ;; Database access ;;====================================================================== ;; dbstruct vector containing all the relevant dbs like main.db, megatest.db, run.db etc |
︙ | ︙ | |||
186 187 188 189 190 191 192 | ;; (filedb:get-path db id))) ;; NB// #f => return dbdir only ;; (was planned to be; zeroth db with name=main.db) ;; ;; If run-id is #f return to create and retrieve the path where the db will live. ;; | < | < < < < < < < | | | | | | > > > > | > > > > > > > | | | > | > > | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | > | | | | | > > | | > > > | > > > > > | | | | > | > > > > > > > > > > > > > > > > | < | > > > | | 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 | ;; (filedb:get-path db id))) ;; NB// #f => return dbdir only ;; (was planned to be; zeroth db with name=main.db) ;; ;; If run-id is #f return to create and retrieve the path where the db will live. ;; (define db:dbfile-path common:get-db-tmp-area) (define (db:set-sync db) (let ((syncprag (configf:lookup *configdat* "setup" "sychronous"))) (sqlite3:execute db (conc "PRAGMA synchronous = " (or syncprag 0) ";")))) ;; open an sql database inside a file lock ;; returns: db existed-prior-to-opening ;; RA => Returns a db handler; sets the lock if opened in writable mode ;; ;; (define *db-open-mutex* (make-mutex)) (define (db:lock-create-open fname initproc) (let* ((parent-dir (or (pathname-directory fname)(current-directory))) ;; no parent? go local (raw-fname (pathname-file fname)) (dir-writable (file-write-access? parent-dir)) (file-exists (common:file-exists? fname)) (file-write (if file-exists (file-write-access? fname) dir-writable ))) ;; (mutex-lock! *db-open-mutex*) ;; tried this mutex, not clear it helped. (if file-write ;; dir-writable (condition-case (let* ((lockfname (conc fname ".lock")) (readyfname (conc parent-dir "/.ready-" raw-fname)) (readyexists (common:file-exists? readyfname))) (if (not readyexists) (common:simple-file-lock-and-wait lockfname)) (let ((db (sqlite3:open-database fname))) (sqlite3:set-busy-handler! db (sqlite3:make-busy-timeout 136000)) (sqlite3:execute db "PRAGMA synchronous = 0;") (if (and (configf:lookup *configdat* "setup" "tmp_mode") (string-match "^/tmp/.*" fname)) (begin ;;(print "DEBUG: Setting tmp_mode for " fname) (sqlite3:execute db (configf:lookup *configdat* "setup" "tmp_mode")) ) ) (if (and (configf:lookup *configdat* "setup" "nfs_mode") (not (string-match "^/tmp/.*" fname))) (begin ;;(print "DEBUG: Setting nfs_mode for " fname) (sqlite3:execute db (configf:lookup *configdat* "setup" "nfs_mode")) ) ) (if (and (not (or (configf:lookup *configdat* "setup" "tmp_mode") (configf:lookup *configdat* "setup" "nfs_mode"))) (configf:lookup *configdat* "setup" "use-wal") (string-match "^/tmp/.*" fname)) ;; this is a file in /tmp (sqlite3:execute db "PRAGMA journal_mode=WAL;") (debug:print 2 *default-log-port* "Creating " fname " in NON-WAL mode.")) (if (not file-exists) (initproc db)) (if (not readyexists) (begin (common:simple-file-release-lock lockfname) (with-output-to-file readyfname (lambda () (print "Ready at " (seconds->year-work-week/day-time (current-seconds))))))) db)) (exn (io-error) (debug:print 0 *default-log-port* "ERROR: i/o error with " fname ". Check permissions, disk space etc. and try again.")) (exn (corrupt) (debug:print 0 *default-log-port* "ERROR: database " fname " is corrupt. Repair it to proceed.")) (exn (busy) (debug:print 0 *default-log-port* "ERROR: database " fname " is locked. Try copying to another location, remove original and copy back.")) (exn (permission)(debug:print 0 *default-log-port* "ERROR: database " fname " has some permissions problem.")) (exn () (debug:print 0 *default-log-port* "ERROR: Unknown error with database " fname " message: " ((condition-property-accessor 'exn 'message) exn)))) (condition-case (begin (debug:print 2 *default-log-port* "WARNING: opening db in non-writable dir " fname) (let ((db (sqlite3:open-database fname))) (sqlite3:set-busy-handler! db (sqlite3:make-busy-timeout 136000)) (sqlite3:execute db "PRAGMA synchronous = 0;") ;; (mutex-unlock! *db-open-mutex*) db)) (exn (io-error) (debug:print 0 *default-log-port* "ERROR: i/o error with " fname ". Check permissions, disk space etc. and try again.")) (exn (corrupt) (debug:print 0 *default-log-port* "ERROR: database " fname " is corrupt. Repair it to proceed.")) (exn (busy) (debug:print 0 *default-log-port* "ERROR: database " fname " is locked. Try copying to another location, remove original and copy back.")) (exn (permission)(debug:print 0 *default-log-port* "ERROR: database " fname " has some permissions problem.")) (exn () (debug:print 0 *default-log-port* "ERROR: Unknown error with database " fname " message: " ((condition-property-accessor 'exn 'message) exn)))) ))) ;; This routine creates the db if not already present. It is only called if the db is not already opened ;; (define (db:open-db dbstruct #!key (areapath #f)(do-sync #t)) ;; TODO: actually use areapath (let ((tmpdb-stack (dbr:dbstruct-dbstack dbstruct))) ;; RA => Returns the first reference in dbstruct (if (stack? tmpdb-stack) (db:get-db tmpdb-stack) ;; get previously opened db (will create new db handle if all in the stack are already used (let* ((max-stale-tmp (configf:lookup-number *configdat* "server" "filling-db-max-stale-seconds" default: 10)) (dbpath (db:dbfile-path )) ;; path to tmp db area (dbexists (common:file-exists? dbpath)) (tmpdbfname (conc dbpath "/megatest.db")) (dbfexists (common:file-exists? tmpdbfname)) ;; (conc dbpath "/megatest.db"))) (mtdbexists (common:file-exists? (conc *toppath* "/megatest.db"))) (mtdbmodtime (if mtdbexists (common:lazy-sqlite-db-modification-time (conc *toppath* "/megatest.db")) #f)) (tmpdbmodtime (if dbfexists (common:lazy-sqlite-db-modification-time tmpdbfname) #f)) (mtdb (db:open-megatest-db)) (mtdbpath (db:dbdat-get-path mtdb)) (tmpdb (db:open-megatest-db path: dbpath)) ;; lock-create-open dbpath db:initialize-main-db)) (refndb (db:open-megatest-db path: dbpath name: "megatest_ref.db")) (write-access (file-write-access? mtdbpath)) ;(mtdbmodtime (if mtdbexists (common:lazy-sqlite-db-modification-time mtdbpath) #f)) ; moving this before db:open-megatest-db is called. if wal mode is on -WAL and -shm file get created with causing the tmpdbmodtime timestamp always greater than mtdbmodtime ;(tmpdbmodtime (if dbfexists (common:lazy-sqlite-db-modification-time tmpdbfname) #f)) ;if wal mode is on -WAL and -shm file get created when db:open-megatest-db is called. modtimedelta will always be < 10 so db in tmp not get synced ;(tmpdbmodtime (if dbfexists (db:get-last-update-time (car tmpdb)) #f)) ;(fmt (file-modification-time tmpdbfname)) (modtimedelta (and mtdbmodtime tmpdbmodtime (- mtdbmodtime tmpdbmodtime)))) (when write-access (sqlite3:execute (car mtdb) "drop trigger if exists update_tests_trigger") (sqlite3:execute (car mtdb) "drop trigger if exists update_runs_trigger")) ;(print "mtdbmodtime " mtdbmodtime " tmpdbmodtime " tmpdbmodtime " mtdbpath " mtdbpath " " (conc *toppath* "/megatest.db")) ;;(debug:print-info 13 *default-log-port* "db:open-db>> mtdbpath="mtdbpath" mtdbexists="mtdbexists" and write-access="write-access) (if (and dbexists (not write-access)) (begin (set! *db-write-access* #f) (dbr:dbstruct-read-only-set! dbstruct #t))) (dbr:dbstruct-mtdb-set! dbstruct mtdb) (dbr:dbstruct-tmpdb-set! dbstruct tmpdb) (dbr:dbstruct-dbstack-set! dbstruct (make-stack)) ;; BB: why a stack? Why would the number of db's be indeterminate? Is this a legacy of 1.db 2.db .. ? (stack-push! (dbr:dbstruct-dbstack dbstruct) tmpdb) ;; olddb is already a (cons db path) (dbr:dbstruct-refndb-set! dbstruct refndb) ;; (mutex-unlock! *rundb-mutex*) (if (and (or (not dbfexists) (and modtimedelta (> modtimedelta max-stale-tmp))) ;; if db in tmp is over ten seconds older than the file in MTRA then do a sync back do-sync) (begin (debug:print 1 *default-log-port* "filling db " (db:dbdat-get-path tmpdb) " with data \n from " (db:dbdat-get-path mtdb) " mod time delta: " modtimedelta) (db:sync-tables (db:sync-all-tables-list dbstruct) #f mtdb refndb tmpdb) ;touch tmp db to avoid wal mode wierdness (set! (file-modification-time tmpdbfname) (current-seconds)) (debug:print-info 13 *default-log-port* "db:sync-all-tables-list done.") ) (debug:print 4 *default-log-port* " db, " (db:dbdat-get-path tmpdb) " already exists or fresh enough, not propogating data from\n " (db:dbdat-get-path mtdb) " mod time delta: " modtimedelta) ) ;; (db:multi-db-sync dbstruct 'old2new)) ;; migrate data from megatest.db automatically tmpdb)))) (define (db:get-last-update-time db) ; (db:with-db ; dbstruct #f #f ; (lambda (db) (let ((last-update-time #f)) (sqlite3:for-each-row (lambda (lup) (set! last-update-time lup)) db "select max(lup) from ( select max(last_update) as lup from tests union select max(last_update) as lup from runs);") last-update-time)) ;)) ;; Make the dbstruct, setup up auxillary db's and call for main db at least once ;; ;; called in http-transport and replicated in rmt.scm for *local* access. ;; (define (db:setup do-sync #!key (areapath #f)) ;; (cond (*dbstruct-db* *dbstruct-db*);; TODO: when multiple areas are supported, this optimization will be a hazard (else ;;(common:on-homehost?) (debug:print-info 13 *default-log-port* "db:setup entered (first time, not cached.)") (let* ((dbstruct (make-dbr:dbstruct))) (when (not *toppath*) (debug:print-info 13 *default-log-port* "in db:setup, *toppath* not set; calling launch:setup") (launch:setup areapath: areapath)) (debug:print-info 13 *default-log-port* "Begin db:open-db") (db:open-db dbstruct areapath: areapath do-sync: do-sync) (debug:print-info 13 *default-log-port* "Done db:open-db") (set! *dbstruct-db* dbstruct) ;;(debug:print-info 13 *default-log-port* "new dbstruct = "(dbr:dbstruct->alist dbstruct)) dbstruct)))) ;; (else ;; (debug:print 0 *default-log-port* "ERROR: attempt to open database when not on homehost. Exiting. Homehost: " (common:get-homehost)) ;; (exit 1)))) ;; Open the classic megatest.db file (defaults to open in toppath) ;; ;; NOTE: returns a dbdat not a dbstruct! ;; ;;(define (db:reopen-megatest-db (define (db:open-megatest-db #!key (path #f)(name #f)) (let* ((dbdir (or path *toppath*)) (dbpath (conc dbdir "/" (or name "megatest.db"))) (dbexists (common:file-exists? dbpath)) (db (db:lock-create-open dbpath (lambda (db) (db:initialize-main-db db) ;;(db:initialize-run-id-db db) ))) (write-access (file-write-access? dbpath))) (debug:print-info 13 *default-log-port* "db:open-megatest-db "dbpath) |
︙ | ︙ | |||
408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 | (mutex-unlock! *db-multi-sync-mutex*) (db:sync-tables (db:sync-all-tables-list dbstruct) update_info tmpdb refndb mtdb)) (mutex-lock! *db-multi-sync-mutex*) (set! *db-last-sync* start-t) (set! *db-last-access* start-t) (mutex-unlock! *db-multi-sync-mutex*) (stack-push! (dbr:dbstruct-dbstack dbstruct) tmpdb))) ;; close all opened run-id dbs (define (db:close-all dbstruct) (if (dbr:dbstruct? dbstruct) (handle-exceptions exn (begin (debug:print 0 *default-log-port* "WARNING: Finalizing failed, " ((condition-property-accessor 'exn 'message) exn)) (print-call-chain *default-log-port*)) ;; (db:sync-touched dbstruct 0 force-sync: #t) ;; NO. Do not do this here. Instead we rely on a server to be started when there are writes, even if the server itself is not going to be used as a server. (let ((tdbs (map db:dbdat-get-db (stack->list (dbr:dbstruct-dbstack dbstruct)))) (mdb (db:dbdat-get-db (dbr:dbstruct-mtdb dbstruct))) (rdb (db:dbdat-get-db (dbr:dbstruct-refndb dbstruct)))) (map (lambda (db) | > > > > > > > > > > > > > > > > | | | | | 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 | (mutex-unlock! *db-multi-sync-mutex*) (db:sync-tables (db:sync-all-tables-list dbstruct) update_info tmpdb refndb mtdb)) (mutex-lock! *db-multi-sync-mutex*) (set! *db-last-sync* start-t) (set! *db-last-access* start-t) (mutex-unlock! *db-multi-sync-mutex*) (stack-push! (dbr:dbstruct-dbstack dbstruct) tmpdb))) (define (db:safely-close-sqlite3-db db #!key (try-num 3)) (if (<= try-num 0) #f (handle-exceptions exn (begin (thread-sleep! 3) (sqlite3:interrupt! db) (db:safely-close-sqlite3-db db try-num: (- try-num 1))) (if (sqlite3:database? db) (begin (sqlite3:finalize! db) #t) #f)))) ;; close all opened run-id dbs (define (db:close-all dbstruct) (if (dbr:dbstruct? dbstruct) (handle-exceptions exn (begin (debug:print 0 *default-log-port* "WARNING: Finalizing failed, " ((condition-property-accessor 'exn 'message) exn)) (print-call-chain *default-log-port*)) ;; (db:sync-touched dbstruct 0 force-sync: #t) ;; NO. Do not do this here. Instead we rely on a server to be started when there are writes, even if the server itself is not going to be used as a server. (let ((tdbs (map db:dbdat-get-db (stack->list (dbr:dbstruct-dbstack dbstruct)))) (mdb (db:dbdat-get-db (dbr:dbstruct-mtdb dbstruct))) (rdb (db:dbdat-get-db (dbr:dbstruct-refndb dbstruct)))) (map (lambda (db) (db:safely-close-sqlite3-db db)) ;; (if (sqlite3:database? db) ;; (sqlite3:finalize! db))) tdbs) (db:safely-close-sqlite3-db mdb) ;; (if (sqlite3:database? mdb) (sqlite3:finalize! mdb)) (db:safely-close-sqlite3-db rdb))))) ;; (if (sqlite3:database? rdb) (sqlite3:finalize! rdb)))))) ;; (let ((locdbs (dbr:dbstruct-locdbs dbstruct))) ;; (if (hash-table? locdbs) ;; (for-each (lambda (run-id) ;; (db:close-run-db dbstruct run-id)) ;; (hash-table-keys locdbs))))) |
︙ | ︙ | |||
469 470 471 472 473 474 475 | '("final_logf" #f) '("logdat" #f) '("run_duration" #f) '("comment" #f) '("event_time" #f) '("fail_count" #f) '("pass_count" #f) | | > | > | > | | 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 | '("final_logf" #f) '("logdat" #f) '("run_duration" #f) '("comment" #f) '("event_time" #f) '("fail_count" #f) '("pass_count" #f) '("archived" #f) '("last_update" #f)) (list "test_steps" '("id" #f) '("test_id" #f) '("stepname" #f) '("state" #f) '("status" #f) '("event_time" #f) '("comment" #f) '("logfile" #f) '("last_update" #f)) (list "test_data" '("id" #f) '("test_id" #f) '("category" #f) '("variable" #f) '("value" #f) '("expected" #f) '("tol" #f) '("units" #f) '("comment" #f) '("status" #f) '("type" #f) '("last_update" #f)))) ;; needs db to get keys, this is for syncing all tables ;; (define (db:sync-main-list dbstruct) (let ((keys (db:get-keys dbstruct))) (list (list "keys" '("id" #f) '("fieldname" #f) '("fieldtype" #f)) (list "metadat" '("var" #f) '("val" #f)) (append (list "runs" '("id" #f)) (map (lambda (k)(list k #f)) (append keys (list "runname" "state" "status" "owner" "event_time" "comment" "fail_count" "pass_count" "contour" "last_update")))) (list "test_meta" '("id" #f) '("testname" #f) '("owner" #f) '("description" #f) '("reviewed" #f) '("iterated" #f) |
︙ | ︙ | |||
535 536 537 538 539 540 541 | (fname (pathname-strip-directory dbpath)) (fnamejnl (conc fname "-journal")) (tmpname (conc fname "." (current-process-id))) (tmpjnl (conc fnamejnl "." (current-process-id)))) (debug:print-error 0 *default-log-port* "" fname " appears corrupted. Making backup \"old/" fname "\"") (system (conc "cd " dbdir ";mkdir -p old;cat " fname " > old/" tmpname)) (system (conc "rm -f " dbpath)) | | | 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 | (fname (pathname-strip-directory dbpath)) (fnamejnl (conc fname "-journal")) (tmpname (conc fname "." (current-process-id))) (tmpjnl (conc fnamejnl "." (current-process-id)))) (debug:print-error 0 *default-log-port* "" fname " appears corrupted. Making backup \"old/" fname "\"") (system (conc "cd " dbdir ";mkdir -p old;cat " fname " > old/" tmpname)) (system (conc "rm -f " dbpath)) (if (common:file-exists? fnamejnl) (begin (debug:print-error 0 *default-log-port* "" fnamejnl " found, moving it to old dir as " tmpjnl) (system (conc "cd " dbdir ";mkdir -p old;cat " fnamejnl " > old/" tmpjnl)) (system (conc "rm -f " dbdir "/" fnamejnl)))) ;; attempt to recreate database (system (conc "cd " dbdir ";sqlite3 old/" tmpname " .dump | sqlite3 " fname)))) |
︙ | ︙ | |||
582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 | "megatest -cleanup-db" "megatest -import-megatest.db;megatest -cleanup-db") "\"\n") (exit) ;; we can not safely continue when a db was corrupted - even if fixed. ) ;; test read/write access to the database (let ((db (sqlite3:open-database dbpath))) (cond ((equal? fname "megatest.db") (sqlite3:execute db "DELETE FROM tests WHERE state='DELETED';")) ((equal? fname "main.db") (sqlite3:execute db "DELETE FROM runs WHERE state='deleted';")) ((string-match "\\d.db" fname) (sqlite3:execute db "UPDATE tests SET state='DELETED' WHERE state='DELETED';")) ((equal? fname "monitor.db") (sqlite3:execute "DELETE FROM servers WHERE state LIKE 'defunct%';")) (else (sqlite3:execute db "vacuum;"))) | > > | | | 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 | "megatest -cleanup-db" "megatest -import-megatest.db;megatest -cleanup-db") "\"\n") (exit) ;; we can not safely continue when a db was corrupted - even if fixed. ) ;; test read/write access to the database (let ((db (sqlite3:open-database dbpath))) (sqlite3:set-busy-handler! db (sqlite3:make-busy-timeout 136000)) (sqlite3:execute db "PRAGMA synchronous = 0;") (cond ((equal? fname "megatest.db") (sqlite3:execute db "DELETE FROM tests WHERE state='DELETED';")) ((equal? fname "main.db") (sqlite3:execute db "DELETE FROM runs WHERE state='deleted';")) ((string-match "\\d.db" fname) (sqlite3:execute db "UPDATE tests SET state='DELETED' WHERE state='DELETED';")) ((equal? fname "monitor.db") (sqlite3:execute "DELETE FROM servers WHERE state LIKE 'defunct%';")) (else (sqlite3:execute db "vacuum;"))) (sqlite3:finalize! db) #t)))))) ;; tbls is ( ("tablename" ( "field1" [#f|proc1] ) ( "field2" [#f|proc2] ) .... ) ) ;; db's are dbdat's ;; ;; if last-update specified ("field-name" . time-in-seconds) ;; then sync only records where field-name >= time-in-seconds ;; IFF field-name exists ;; (define (db:sync-tables tbls last-update fromdb todb . slave-dbs) (handle-exceptions exn (begin (debug:print 0 *default-log-port* "EXCEPTION: database probably overloaded or unreadable in db:sync-tables.") (print-call-chain (current-error-port)) (debug:print 0 *default-log-port* " message: " ((condition-property-accessor 'exn 'message) exn)) (debug:print 5 *default-log-port* "exn=" (condition->list exn)) (debug:print 0 *default-log-port* " status: " ((condition-property-accessor 'sqlite3 'status) exn)) (debug:print 0 *default-log-port* " src db: " (db:dbdat-get-path fromdb)) (for-each (lambda (dbdat) (let ((dbpath (db:dbdat-get-path dbdat))) (debug:print 0 *default-log-port* " dbpath: " dbpath) (if (not (db:repair-db dbdat)) (begin |
︙ | ︙ | |||
659 660 661 662 663 664 665 | (let ((stmts (make-hash-table)) ;; table-field => stmt (all-stmts '()) ;; ( ( stmt1 value1 ) ( stml2 value2 )) (numrecs (make-hash-table)) (start-time (current-milliseconds)) (tot-count 0)) (for-each ;; table (lambda (tabledat) | | | > | > > > > | | | | | > > > > > > > | > > > > | | | | > > > | 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 | (let ((stmts (make-hash-table)) ;; table-field => stmt (all-stmts '()) ;; ( ( stmt1 value1 ) ( stml2 value2 )) (numrecs (make-hash-table)) (start-time (current-milliseconds)) (tot-count 0)) (for-each ;; table (lambda (tabledat) (let* ((tablename (car tabledat)) (fields (cdr tabledat)) (has-last-update (member "last_update" fields)) (use-last-update (cond ((and has-last-update (member "last_update" fields)) #t) ;; if given a number, just use it for all fields ((number? last-update) #f) ;; if not matched first entry then ignore last-update for this table ((and (pair? last-update) (member (car last-update) ;; last-update field name (map car fields))) #t) (last-update (debug:print 0 *default-log-port* "ERROR: parameter last-update for db:sync-tables must be a pair or a number, received: " last-update) ;; found in fields #f) (else #f))) (last-update-value (if use-last-update ;; no need to check for has-last-update - it is already accounted for (if (number? last-update) last-update (cdr last-update)) #f)) (last-update-field (if use-last-update (if (number? last-update) "last_update" (car last-update)) #f)) (num-fields (length fields)) (field->num (make-hash-table)) (num->field (apply vector (map car fields))) ;; BBHERE (full-sel (conc "SELECT " (string-intersperse (map car fields) ",") " FROM " tablename (if use-last-update ;; apply last-update criteria (conc " WHERE " last-update-field " >= " last-update-value) "") ";")) (full-ins (conc "INSERT OR REPLACE INTO " tablename " ( " (string-intersperse (map car fields) ",") " ) " " VALUES ( " (string-intersperse (make-list num-fields "?") ",") " );")) (fromdat '()) (fromdats '()) (totrecords 0) (batch-len (string->number (or (configf:lookup *configdat* "sync" "batchsize") "100"))) (todat (make-hash-table)) (count 0) (delay-handicap (string->number (or (configf:lookup *configdat* "sync" "delay-handicap") "0"))) ) ;; set up the field->num table (for-each (lambda (field) (hash-table-set! field->num field count) (set! count (+ count 1))) fields) |
︙ | ︙ | |||
712 713 714 715 716 717 718 | ;; tack on remaining records in fromdat (if (not (null? fromdat)) (set! fromdats (cons fromdat fromdats))) (if (common:low-noise-print 120 "sync-records") (debug:print-info 4 *default-log-port* "found " totrecords " records to sync")) | | > > > > > > | 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 | ;; tack on remaining records in fromdat (if (not (null? fromdat)) (set! fromdats (cons fromdat fromdats))) (if (common:low-noise-print 120 "sync-records") (debug:print-info 4 *default-log-port* "found " totrecords " records to sync")) ;; read the target table; BBHERE (sqlite3:for-each-row (lambda (a . b) (hash-table-set! todat a (apply vector a b))) (db:dbdat-get-db todb) full-sel) (when (and delay-handicap (> delay-handicap 0)) (debug:print-info 0 *default-log-port* "imposing synthetic sync delay of "delay-handicap" seconds since sync/delay-handicap is configured") (thread-sleep! delay-handicap) (debug:print-info 0 *default-log-port* "synthetic sync delay of "delay-handicap" seconds completed") ) ;; first pass implementation, just insert all changed rows (for-each (lambda (targdb) (let* ((db (db:dbdat-get-db targdb)) (stmth (sqlite3:prepare db full-ins))) (db:delay-if-busy targdb) ;; NO WAITING (for-each |
︙ | ︙ | |||
832 833 834 835 836 837 838 | count INTEGER, last_update INTEGER DEFAULT (strftime('%s','now')))") (sqlite3:execute maindb "CREATE TRIGGER IF NOT EXISTS update_run_stats_trigger AFTER UPDATE ON run_stats FOR EACH ROW BEGIN UPDATE run_stats SET last_update=(strftime('%s','now')) WHERE id=old.id; | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 | count INTEGER, last_update INTEGER DEFAULT (strftime('%s','now')))") (sqlite3:execute maindb "CREATE TRIGGER IF NOT EXISTS update_run_stats_trigger AFTER UPDATE ON run_stats FOR EACH ROW BEGIN UPDATE run_stats SET last_update=(strftime('%s','now')) WHERE id=old.id; END;") (sqlite3:execute maindb "CREATE TABLE IF NOT EXISTS test_rundat ( id INTEGER PRIMARY KEY, test_id INTEGER, update_time TIMESTAMP, cpuload INTEGER DEFAULT -1, diskfree INTEGER DEFAULT -1, diskusage INTGER DEFAULT -1, run_duration INTEGER DEFAULT 0);")) (define (db:adj-target db) (let ((fields (configf:get-section *configdat* "fields")) (field-num 0)) ;; because we will be refreshing the keys table it is best to clear it here (sqlite3:execute db "DELETE FROM keys;") (for-each (lambda (field) (let ((column (car field)) (spec (cadr field))) (handle-exceptions exn (if (string-match ".*duplicate.*" ((condition-property-accessor 'exn 'message) exn)) (debug:print 0 *default-log-port* "Target field " column " already exists in the runs table") (db:general-sqlite-error-dump exn "alter table runs ..." #f "none")) ;; Add the column if needed (sqlite3:execute db (conc "ALTER TABLE runs ADD COLUMN " column " " spec))) ;; correct the entry in the keys column (sqlite3:execute db "INSERT INTO keys (id,fieldname,fieldtype) VALUES (?,?,?);" field-num column spec) ;; fill in blanks (not allowed as it would be part of the path (sqlite3:execute db (conc "UPDATE runs SET " column "='x' WHERE " column "='';")) (set! field-num (+ field-num 1)))) fields))) (define *global-db-store* (make-hash-table)) (define (db:get-access-mode) (if (args:get-arg "-use-db-cache") 'cached 'rmt)) ;; Add db direct ;; |
︙ | ︙ | |||
855 856 857 858 859 860 861 | ;; return the target db handle so it can be used ;; (define (db:cache-for-read-only source target #!key (use-last-update #f)) (if (and (hash-table-ref/default *global-db-store* target #f) (>= (file-modification-time target)(file-modification-time source))) (hash-table-ref *global-db-store* target) (let* ((toppath (launch:setup)) | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | > > > > | | | | | | | | > > > > | | | < | | | | < < < < < < < | | | < | | | < < < < < < < < < < | | | | | | | | | > > > | | < | | | | | | | | < < < < | < < | | > | < < < | < < < < | | > > | < | | | | | | < > | < | > > > < < < < < < < < < < < < < < < | < < | < | > > | > | > | | < > | < < | < < > > > > | > > > | | | | | | > > > > > | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 | ;; return the target db handle so it can be used ;; (define (db:cache-for-read-only source target #!key (use-last-update #f)) (if (and (hash-table-ref/default *global-db-store* target #f) (>= (file-modification-time target)(file-modification-time source))) (hash-table-ref *global-db-store* target) (let* ((toppath (launch:setup)) (targ-db-last-mod (if (common:file-exists? target) (file-modification-time target) 0)) (cache-db (or (hash-table-ref/default *global-db-store* target #f) (db:open-megatest-db path: target))) (source-db (db:open-megatest-db path: source)) (curr-time (current-seconds)) (res '()) (last-update (if use-last-update (cons "last_update" targ-db-last-mod) #f))) (db:sync-tables (db:sync-main-list source-db) last-update source-db cache-db) (db:sync-tables db:sync-tests-only last-update source-db cache-db) (hash-table-set! *global-db-store* target cache-db) cache-db))) ;; ;; call a proc with a cached db ;; ;; ;; (define (db:call-with-cached-db proc . params) ;; ;; first cache the db in /tmp ;; (let* ((cname-part (conc "megatest_cache/" (common:get-testsuite-name))) ;; (fname (conc (common:get-area-path-signature) ".db")) ;; (cache-dir (common:get-create-writeable-dir ;; (list (conc "/tmp/" (current-user-name) "/" cname-part) ;; (conc "/tmp/" (current-user-name) "-" cname-part) ;; (conc "/tmp/" (current-user-name) "_" cname-part)))) ;; (megatest-db (conc *toppath* "/megatest.db"))) ;; ;; (debug:print-info 0 *default-log-port* "Using cache dir " cache-dir) ;; (if (not cache-dir) ;; (begin ;; (debug:print 0 *default-log-port* "ERROR: Failed to find an area to write the cache db") ;; (exit 1)) ;; (let* ((th1 (make-thread ;; (lambda () ;; (if (and (common:file-exists? megatest-db) ;; (file-write-access? megatest-db)) ;; (begin ;; (db:sync-to-megatest.db dbstruct 'timestamps) ;; internally mutexes on *db-local-sync* ;; (debug:print-info 2 *default-log-port* "Done syncing to megatest.db")))) ;; "call-with-cached-db sync-to-megatest.db")) ;; (cache-db (db:cache-for-read-only ;; megatest-db ;; (conc cache-dir "/" fname) ;; use-last-update: #t))) ;; (thread-start! th1) ;; (apply proc cache-db params) ;; )))) ;; options: ;; ;; 'killservers - kills all servers ;; 'dejunk - removes junk records ;; 'adj-testids - move test-ids into correct ranges ;; 'old2new - sync megatest.db to /tmp/.../megatest.db and /tmp/.../megatest_ref.db ;; 'new2old - sync /tmp/.../megatest.db to megatest.db and /tmp/.../megatest_ref.db (and update data_synced) ;; 'closeall - close all opened dbs ;; 'schema - attempt to apply schema changes ;; run-ids: '(1 2 3 ...) or #f (for all) ;; (define (db:multi-db-sync dbstruct . options) ;; (if (not (launch:setup)) ;; (debug:print 0 *default-log-port* "ERROR: not able to setup up for megatest.") (let* ((mtdb (dbr:dbstruct-mtdb dbstruct)) (tmpdb (db:get-db dbstruct)) (refndb (dbr:dbstruct-refndb dbstruct)) (allow-cleanup #t) ;; (if run-ids #f #t)) (servers (server:get-list *toppath*)) ;; (tasks:get-all-servers (db:delay-if-busy tdbdat))) (data-synced 0)) ;; count of changed records (I hope) (for-each (lambda (option) (case option ;; kill servers ((killservers) (for-each (lambda (server) (match-let (((mod-time host port start-time pid) server)) (if (and host pid) (tasks:kill-server host pid)))) servers) ;; /tmp/bjbarcla/megatest_localdb/fullrun/.nfs.pdx.disks.icf_env_disk001.bjbarcla.gwa.issues.mtdev.matt-bisect.megatest.ext-tests.runs.all.v1.65.1.6524.dev.bb-24-justrollup-f8.rollup.fullrun/megatest.db.lock (delete-file* (common:get-sync-lock-filepath)) ) ;; clear out junk records ;; ((dejunk) (db:delay-if-busy mtdb) ;; ok to delay on mtdb (when (file-write-access? (db:dbdat-get-path mtdb)) (db:clean-up mtdb)) (db:clean-up tmpdb) (db:clean-up refndb)) ;; sync runs, test_meta etc. ;; ((old2new) (set! data-synced (+ (db:sync-tables (db:sync-all-tables-list dbstruct) #f mtdb tmpdb refndb) data-synced))) ;; now ensure all newdb data are synced to megatest.db ;; do not use the run-ids list passed in to the function ;; ((new2old) (set! data-synced (+ (db:sync-tables (db:sync-all-tables-list dbstruct) #f tmpdb refndb mtdb) data-synced))) ((adj-target) (db:adj-target (db:dbdat-get-db mtdb)) (db:adj-target (db:dbdat-get-db tmpdb)) (db:adj-target (db:dbdat-get-db refndb))) ((schema) (db:patch-schema-maindb (db:dbdat-get-db mtdb)) (db:patch-schema-maindb (db:dbdat-get-db tmpdb)) (db:patch-schema-maindb (db:dbdat-get-db refndb)) (db:patch-schema-rundb (db:dbdat-get-db mtdb)) (db:patch-schema-rundb (db:dbdat-get-db tmpdb)) (db:patch-schema-rundb (db:dbdat-get-db refndb)))) (stack-push! (dbr:dbstruct-dbstack dbstruct) tmpdb)) options) data-synced)) (define (db:tmp->megatest.db-sync dbstruct last-update) (let* ((mtdb (dbr:dbstruct-mtdb dbstruct)) (tmpdb (db:get-db dbstruct)) (refndb (dbr:dbstruct-refndb dbstruct)) (res (db:sync-tables (db:sync-all-tables-list dbstruct) last-update tmpdb refndb mtdb))) (stack-push! (dbr:dbstruct-dbstack dbstruct) tmpdb) res)) ;;;; run-ids ;; if #f use *db-local-sync* : or 'local-sync-flags ;; if #t use timestamps : or 'timestamps ;; ;; NB// no-sync-db is the db handle, not a flag! ;; (define (db:sync-to-megatest.db dbstruct #!key (no-sync-db #f)) (let* ((start-time (current-seconds)) (last-full-update (if no-sync-db (db:no-sync-get/default no-sync-db "LAST_FULL_UPDATE" 0) 0)) (full-sync-needed (> (- start-time last-full-update) 3600)) ;; every hour do a full sync (last-update (if full-sync-needed 0 (if no-sync-db (db:no-sync-get/default no-sync-db "LAST_UPDATE" 0) 0))) ;; (or (db:get-var dbstruct "LAST_UPDATE") 0)) (sync-needed (> (- start-time last-update) 6)) (res (if (or sync-needed ;; don't sync if a sync already occurred in the past 6 seconds full-sync-needed) (begin (if no-sync-db (begin (if full-sync-needed (db:no-sync-set no-sync-db "LAST_FULL_UPDATE" start-time)) (db:no-sync-set no-sync-db "LAST_UPDATE" start-time))) (db:tmp->megatest.db-sync dbstruct last-update)) 0)) (sync-time (- (current-seconds) start-time))) (debug:print-info 3 *default-log-port* "Sync of newdb to olddb completed in " sync-time " seconds pid="(current-process-id)) (if (common:low-noise-print 30 "sync new to old") (if sync-needed (debug:print-info 0 *default-log-port* "Sync of " res " records from newdb to olddb completed in " sync-time " seconds pid="(current-process-id)) (debug:print-info 0 *default-log-port* "No sync needed, last updated " (- start-time last-update) " seconds ago"))) res)) ;; keeping it around for debugging purposes only #;(define (open-run-close-no-exception-handling proc idb . params) (debug:print-info 11 *default-log-port* "open-run-close-no-exception-handling START given a db=" (if idb "yes " "no ") ", params=" params) (print "I don't work anymore. open-run-close-no-exception-handling needs fixing or removing...") (exit) (if (or *db-write-access* (not #t)) ;; was: (member proc * db:all-write-procs *))) (let* ((db (cond ((pair? idb) (db:dbdat-get-db idb)) ((sqlite3:database? idb) idb) ((not idb) (debug:print-error 0 *default-log-port* "cannot open-run-close with #f anymore")) ((procedure? idb) (idb)) (else (debug:print-error 0 *default-log-port* "cannot open-run-close with #f anymore")))) (res #f)) (set! res (apply proc db params)) (if (not idb)(sqlite3:finalize! dbstruct)) (debug:print-info 11 *default-log-port* "open-run-close-no-exception-handling END" ) res) #f)) #;(define (open-run-close-exception-handling proc idb . params) (handle-exceptions exn (let ((sleep-time (random 30)) (err-status ((condition-property-accessor 'sqlite3 'status #f) exn))) (case err-status ((busy) (thread-sleep! sleep-time)) (else (debug:print 0 *default-log-port* "EXCEPTION: database probably overloaded or unreadable.") (debug:print 0 *default-log-port* " message: " ((condition-property-accessor 'exn 'message) exn)) (debug:print 5 *default-log-port* "exn=" (condition->list exn)) (debug:print 0 *default-log-port* " status: " ((condition-property-accessor 'sqlite3 'status) exn)) (print-call-chain (current-error-port)) (thread-sleep! sleep-time) (debug:print-info 0 *default-log-port* "trying db call one more time....this may never recover, if necessary kill process " (current-process-id) " on host " (get-host-name) " to clean up"))) (apply open-run-close-exception-handling proc idb params)) (apply open-run-close-no-exception-handling proc idb params))) ;; (define open-run-close #;(define open-run-close open-run-close-exception-handling) ;; open-run-close-no-exception-handling ;; open-run-close-exception-handling) ;;) (define (db:initialize-main-db dbdat) (when (not *configinfo*) (launch:setup)) ;; added because Elena was getting stack dump because *configinfo* below was #f. (let* ((configdat (car *configinfo*)) ;; tut tut, global warning... (keys (keys:config-get-fields configdat)) (havekeys (> (length keys) 0)) (keystr (keys->keystr keys)) (fieldstr (keys:make-key/field-string configdat)) (db (db:dbdat-get-db dbdat))) (for-each (lambda (key) (let ((keyn key)) (if (member (string-downcase keyn) (list "runname" "state" "status" "owner" "event_time" "comment" "fail_count" "pass_count" "contour")) (begin (print "ERROR: your key cannot be named " keyn " as this conflicts with the same named field in the runs table, you must remove your megatest.db and <linktree>/.db before trying again.") (exit 1))))) keys) (sqlite3:with-transaction db (lambda () ;; handle-exceptions ;; exn ;; (begin ;; (debug:print 0 "ERROR: Failed to create tables. Look at your [fields] section, should be: fieldname TEXT DEFAULT 'yourdefault'") ;; (exit)) (sqlite3:execute db "CREATE TABLE IF NOT EXISTS keys (id INTEGER PRIMARY KEY, fieldname TEXT, fieldtype TEXT, CONSTRAINT keyconstraint UNIQUE (fieldname));") (for-each (lambda (key) (sqlite3:execute db "INSERT OR REPLACE INTO keys (fieldname,fieldtype) VALUES (?,?);" key "TEXT")) keys) (sqlite3:execute db (conc "CREATE TABLE IF NOT EXISTS runs (id INTEGER PRIMARY KEY, \n " fieldstr (if havekeys "," "") " runname TEXT DEFAULT 'norun', contour TEXT DEFAULT '', state TEXT DEFAULT '', status TEXT DEFAULT '', owner TEXT DEFAULT '', event_time TIMESTAMP DEFAULT (strftime('%s','now')), comment TEXT DEFAULT '', fail_count INTEGER DEFAULT 0, pass_count INTEGER DEFAULT 0, last_update INTEGER DEFAULT (strftime('%s','now')), CONSTRAINT runsconstraint UNIQUE (runname" (if havekeys "," "") keystr "));")) (sqlite3:execute db "CREATE TRIGGER IF NOT EXISTS update_runs_trigger AFTER UPDATE ON runs FOR EACH ROW BEGIN UPDATE runs SET last_update=(strftime('%s','now')) WHERE id=old.id; END;") (sqlite3:execute db "CREATE TABLE IF NOT EXISTS run_stats ( id INTEGER PRIMARY KEY, run_id INTEGER, state TEXT, status TEXT, count INTEGER, last_update INTEGER DEFAULT (strftime('%s','now')))") (sqlite3:execute db "CREATE TRIGGER IF NOT EXISTS update_run_stats_trigger AFTER UPDATE ON run_stats FOR EACH ROW BEGIN UPDATE run_stats SET last_update=(strftime('%s','now')) WHERE id=old.id; END;") (sqlite3:execute db "CREATE TABLE IF NOT EXISTS test_meta ( id INTEGER PRIMARY KEY, testname TEXT DEFAULT '', author TEXT DEFAULT '', owner TEXT DEFAULT '', description TEXT DEFAULT '', reviewed TIMESTAMP, iterated TEXT DEFAULT '', avg_runtime REAL, avg_disk REAL, tags TEXT DEFAULT '', jobgroup TEXT DEFAULT 'default', CONSTRAINT test_meta_constraint UNIQUE (testname));") (sqlite3:execute db "CREATE TABLE IF NOT EXISTS tasks_queue (id INTEGER PRIMARY KEY, action TEXT DEFAULT '', owner TEXT, state TEXT DEFAULT 'new', target TEXT DEFAULT '', name TEXT DEFAULT '', testpatt TEXT DEFAULT '', keylock TEXT, params TEXT, creation_time TIMESTAMP DEFAULT (strftime('%s','now')), execution_time TIMESTAMP);") ;; archive disk areas, cached info from [archive-disks] (sqlite3:execute db "CREATE TABLE IF NOT EXISTS archive_disks ( id INTEGER PRIMARY KEY, archive_area_name TEXT, disk_path TEXT, last_df INTEGER DEFAULT -1, last_df_time TIMESTAMP DEFAULT (strftime('%s','now')), creation_time TIMESTAMP DEFAULT (strftime('%','now')));") ;; individual bup (or tar) data chunks (sqlite3:execute db "CREATE TABLE IF NOT EXISTS archive_blocks ( id INTEGER PRIMARY KEY, archive_disk_id INTEGER, disk_path TEXT, last_du INTEGER DEFAULT -1, last_du_time TIMESTAMP DEFAULT (strftime('%s','now')), creation_time TIMESTAMP DEFAULT (strftime('%','now')));") ;; tests allocated to what chunks. reusing a chunk for a test/item_path is very efficient ;; NB// the per run/test recording of where the archive is stored is done in the test ;; record. (sqlite3:execute db "CREATE TABLE IF NOT EXISTS archive_allocations ( id INTEGER PRIMARY KEY, archive_block_id INTEGER, testname TEXT, item_path TEXT, creation_time TIMESTAMP DEFAULT (strftime('%','now')));") ;; move this clean up call somewhere else (sqlite3:execute db "DELETE FROM tasks_queue WHERE state='done' AND creation_time < ?;" (- (current-seconds)(* 24 60 60))) ;; remove older than 24 hrs (sqlite3:execute db (conc "CREATE INDEX IF NOT EXISTS runs_index ON runs (runname" (if havekeys "," "") keystr ");")) ;; (sqlite3:execute db "CREATE VIEW runs_tests AS SELECT * FROM runs INNER JOIN tests ON runs.id=tests.run_id;") (sqlite3:execute db "CREATE TABLE IF NOT EXISTS extradat (id INTEGER PRIMARY KEY, run_id INTEGER, key TEXT, val TEXT);") (sqlite3:execute db "CREATE TABLE IF NOT EXISTS metadat (id INTEGER PRIMARY KEY, var TEXT, val TEXT, CONSTRAINT metadat_constraint UNIQUE (var));") (sqlite3:execute db "CREATE TABLE IF NOT EXISTS access_log (id INTEGER PRIMARY KEY, user TEXT, accessed TIMESTAMP, args TEXT);") ;; Must do this *after* running patch db !! No more. ;; cannot use db:set-var since it will deadlock, hardwire the code here (sqlite3:execute db "INSERT OR REPLACE INTO metadat (var,val) VALUES (?,?);" "MEGATEST_VERSION" (common:version-signature)) (debug:print-info 11 *default-log-port* "db:initialize END") ;; )))) ;;====================================================================== ;; R U N S P E C I F I C D B ;;====================================================================== ;; (define (db:initialize-run-id-db db) ;; (sqlite3:with-transaction ;; db ;; (lambda () (sqlite3:execute db "CREATE TABLE IF NOT EXISTS tests (id INTEGER PRIMARY KEY, run_id INTEGER DEFAULT -1, testname TEXT DEFAULT 'noname', host TEXT DEFAULT 'n/a', cpuload REAL DEFAULT -1, diskfree INTEGER DEFAULT -1, uname TEXT DEFAULT 'n/a', |
︙ | ︙ | |||
1248 1249 1250 1251 1252 1253 1254 | comment TEXT DEFAULT '', event_time TIMESTAMP DEFAULT (strftime('%s','now')), fail_count INTEGER DEFAULT 0, pass_count INTEGER DEFAULT 0, archived INTEGER DEFAULT 0, -- 0=no, > 1=archive block id where test data can be found last_update INTEGER DEFAULT (strftime('%s','now')), CONSTRAINT testsconstraint UNIQUE (run_id, testname, item_path));") | | > > > > > | | | | | | | | | | | 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 | comment TEXT DEFAULT '', event_time TIMESTAMP DEFAULT (strftime('%s','now')), fail_count INTEGER DEFAULT 0, pass_count INTEGER DEFAULT 0, archived INTEGER DEFAULT 0, -- 0=no, > 1=archive block id where test data can be found last_update INTEGER DEFAULT (strftime('%s','now')), CONSTRAINT testsconstraint UNIQUE (run_id, testname, item_path));") ;; deprecated -- (sqlite3:execute db "CREATE INDEX IF NOT EXISTS tests_index ON tests (run_id, testname, item_path, uname);") (sqlite3:execute db "CREATE INDEX IF NOT EXISTS tests_run_id_index ON tests (run_id);") ;; new (sqlite3:execute db "CREATE INDEX IF NOT EXISTS tests_testname_index ON tests (testname,item_path);") ;; new (sqlite3:execute db "CREATE INDEX IF NOT EXISTS tests_state_status_index ON tests (state, status); ") ;; new (sqlite3:execute db "CREATE TRIGGER IF NOT EXISTS update_tests_trigger AFTER UPDATE ON tests FOR EACH ROW BEGIN UPDATE tests SET last_update=(strftime('%s','now')) WHERE id=old.id; END;") (sqlite3:execute db "CREATE TABLE IF NOT EXISTS test_steps (id INTEGER PRIMARY KEY, test_id INTEGER, stepname TEXT, state TEXT DEFAULT 'NOT_STARTED', status TEXT DEFAULT 'n/a', event_time TIMESTAMP, comment TEXT DEFAULT '', logfile TEXT DEFAULT '', last_update INTEGER DEFAULT (strftime('%s','now')), CONSTRAINT test_steps_constraint UNIQUE (test_id,stepname,state));") (sqlite3:execute db "CREATE INDEX IF NOT EXISTS teststeps_index ON tests (run_id, testname, item_path);") (sqlite3:execute db "CREATE TRIGGER IF NOT EXISTS update_teststeps_trigger AFTER UPDATE ON test_steps FOR EACH ROW BEGIN UPDATE test_steps SET last_update=(strftime('%s','now')) WHERE id=old.id; END;") (sqlite3:execute db "CREATE TABLE IF NOT EXISTS test_data (id INTEGER PRIMARY KEY, test_id INTEGER, category TEXT DEFAULT '', variable TEXT, value REAL, expected REAL, tol REAL, units TEXT, comment TEXT DEFAULT '', status TEXT DEFAULT 'n/a', type TEXT DEFAULT '', last_update INTEGER DEFAULT (strftime('%s','now')), CONSTRAINT test_data_constraint UNIQUE (test_id,category,variable));") (sqlite3:execute db "CREATE INDEX IF NOT EXISTS test_data_index ON test_data (test_id);") (sqlite3:execute db "CREATE TRIGGER IF NOT EXISTS update_test_data_trigger AFTER UPDATE ON test_data FOR EACH ROW BEGIN UPDATE test_data SET last_update=(strftime('%s','now')) WHERE id=old.id; END;") (sqlite3:execute db "CREATE TABLE IF NOT EXISTS test_rundat ( id INTEGER PRIMARY KEY, test_id INTEGER, update_time TIMESTAMP, cpuload INTEGER DEFAULT -1, diskfree INTEGER DEFAULT -1, diskusage INTGER DEFAULT -1, run_duration INTEGER DEFAULT 0);") (sqlite3:execute db "CREATE TABLE IF NOT EXISTS archives ( id INTEGER PRIMARY KEY, test_id INTEGER, state TEXT DEFAULT 'new', status TEXT DEFAULT 'n/a', archive_type TEXT DEFAULT 'bup', du INTEGER, archive_path TEXT);"))) db)) ;; ) ;;====================================================================== ;; A R C H I V E S ;;====================================================================== ;; dneeded is minimum space needed, scan for existing archives that ;; are on disks with adequate space and already have this test/itempath |
︙ | ︙ | |||
1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 | db (conc "SELECT d.id,d.archive_area_name,disk_path,last_df,last_df_time FROM archive_disks AS d INNER JOIN archive_blocks AS b ON d.id=b.archive_disk_id WHERE b.id IN (" (string-intersperse (map conc res) ",") ") AND last_df > ?;") dneeded)) blocks)) ;; returns id of the record, register a disk allocated to archiving and record it's last known ;; available space ;; (define (db:archive-register-disk dbstruct bdisk-name bdisk-path df) (let* ((dbdat (db:get-db dbstruct)) ;; archive tables are in main.db | > | 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 | db (conc "SELECT d.id,d.archive_area_name,disk_path,last_df,last_df_time FROM archive_disks AS d INNER JOIN archive_blocks AS b ON d.id=b.archive_disk_id WHERE b.id IN (" (string-intersperse (map conc res) ",") ") AND last_df > ?;") dneeded)) (stack-push! (dbr:dbstruct-dbstack dbstruct) dbdat) blocks)) ;; returns id of the record, register a disk allocated to archiving and record it's last known ;; available space ;; (define (db:archive-register-disk dbstruct bdisk-name bdisk-path df) (let* ((dbdat (db:get-db dbstruct)) ;; archive tables are in main.db |
︙ | ︙ | |||
1392 1393 1394 1395 1396 1397 1398 | (sqlite3:for-each-row (lambda (id) (set! res id)) db "SELECT id FROM archive_blocks WHERE archive_disk_id=? AND disk_path=?;" bdisk-id archive-path) (if res ;; record exists, update du if applicable and return res | < | | < | > > | 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 | (sqlite3:for-each-row (lambda (id) (set! res id)) db "SELECT id FROM archive_blocks WHERE archive_disk_id=? AND disk_path=?;" bdisk-id archive-path) (if res ;; record exists, update du if applicable and return res (if du (sqlite3:execute db "UPDATE archive_blocks SET last_du=?,last_du_time=(strftime('%s','now')) WHERE archive_disk_id=? AND disk_path=?;" bdisk-id archive-path du)) (begin (sqlite3:execute db "INSERT OR REPLACE INTO archive_blocks (archive_disk_id,disk_path,last_du) VALUES (?,?,?);" bdisk-id archive-path (or du 0)) (set! res (db:archive-register-block-name dbstruct bdisk-id archive-path du: du)))) (stack-push! (dbr:dbstruct-dbstack dbstruct) dbdat) res)) ;; The "archived" field in tests is overloaded; 0 = not archived, > 0 archived in block with given id ;; (define (db:test-set-archive-block-id dbstruct run-id test-id archive-block-id) (db:with-db dbstruct |
︙ | ︙ | |||
1446 1447 1448 1449 1450 1451 1452 | ;;====================================================================== ;; L O G G I N G D B ;;====================================================================== (define (open-logging-db) (let* ((dbpath (conc (if *toppath* (conc *toppath* "/") "") "logging.db")) ;; fname) | | | | 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 | ;;====================================================================== ;; L O G G I N G D B ;;====================================================================== (define (open-logging-db) (let* ((dbpath (conc (if *toppath* (conc *toppath* "/") "") "logging.db")) ;; fname) (dbexists (common:file-exists? dbpath)) (db (sqlite3:open-database dbpath)) (handler (sqlite3:make-busy-timeout (if (args:get-arg "-override-timeout") (string->number (args:get-arg "-override-timeout")) 136000)))) ;; 136000))) (sqlite3:set-busy-handler! db handler) (if (not dbexists) (begin (sqlite3:execute db "CREATE TABLE IF NOT EXISTS log (id INTEGER PRIMARY KEY,event_time TIMESTAMP DEFAULT (strftime('%s','now')),logline TEXT,pwd TEXT,cmdline TEXT,pid INTEGER);") (db:set-sync db) ;; (sqlite3:execute db (conc "PRAGMA synchronous = 0;")) |
︙ | ︙ | |||
1489 1490 1491 1492 1493 1494 1495 | (let* ((incompleted '()) (oldlaunched '()) (toplevels '()) (deadtime-str (configf:lookup *configdat* "setup" "deadtime")) (deadtime (if (and deadtime-str (string->number deadtime-str)) (string->number deadtime-str) | | | 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 | (let* ((incompleted '()) (oldlaunched '()) (toplevels '()) (deadtime-str (configf:lookup *configdat* "setup" "deadtime")) (deadtime (if (and deadtime-str (string->number deadtime-str)) (string->number deadtime-str) 72000))) ;; twenty hours (db:with-db dbstruct #f #f (lambda (db) (if (number? ovr-deadtime)(set! deadtime ovr-deadtime)) ;; in RUNNING or REMOTEHOSTSTART for more than 10 minutes ;; |
︙ | ︙ | |||
1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 | #f #t))))) ;; given a launch delay (minimum time from last launch) return amount of time to wait ;; ;; (define (db:launch-delay-left dbstruct run-id launch-delay) ;; select end_time-now from ;; (select testname,item_path,event_time+run_duration as ;; end_time,strftime('%s','now') as now from tests where state in | > > > > > > > > > > > > > > > > > > > > | > > | > > > > > | | | > > > > | < < | > > > > > > > > > > > > > > > > > > > | | | > > | | > | | > > > > > > > > > | > > > > > > > > | > > > > | 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 | #f #t))))) ;; given a launch delay (minimum time from last launch) return amount of time to wait ;; ;; (define (db:launch-delay-left dbstruct run-id launch-delay) (define (db:get-status-from-final-status-file run-dir) (let ( (infile (conc run-dir "/.final-status"))) ;; first verify we are able to write the output file (if (not (file-read-access? infile)) (begin (debug:print 0 *default-log-port* "ERROR: cannot read " infile) (debug:print 0 *default-log-port* "ERROR: run-dir is " run-dir) #f ) (with-input-from-file infile read-lines) ) ) ) ;; select end_time-now from ;; (select testname,item_path,event_time+run_duration as ;; end_time,strftime('%s','now') as now from tests where state in ;; ('RUNNING','REMOTEHOSTSTART','LAUNCHED')); (define (db:find-and-mark-incomplete dbstruct run-id ovr-deadtime) (let* ((incompleted '()) (oldlaunched '()) (toplevels '()) ;; The default running-deadtime is 720 seconds = 12 minutes. ;; "(running-deadtime-default (+ server-start-allowance (* 2 launch-monitor-period)))" = 200 + (2 * (200 + 30 + 30)) (deadtime-trim (or ovr-deadtime (configf:lookup-number *configdat* "setup" "deadtime"))) (server-start-allowance 200) (server-overloaded-budget 200) (launch-monitor-off-time (or (configf:lookup-number *configdat* "setup" "test-stats-update-period") 30)) (launch-monitor-on-time-budget 30) (launch-monitor-period (+ launch-monitor-off-time launch-monitor-on-time-budget server-overloaded-budget)) (remotehoststart-deadtime-default (+ server-start-allowance server-overloaded-budget 30)) (remotehoststart-deadtime (or deadtime-trim remotehoststart-deadtime-default)) (running-deadtime-default (+ server-start-allowance (* 2 launch-monitor-period))) (running-deadtime (or deadtime-trim running-deadtime-default)) ;; two minutes (30 seconds between updates, this leaves 3x grace period) ) (debug:print-info 4 *default-log-port* "running-deadtime = " running-deadtime) (debug:print-info 4 *default-log-port* "deadtime-trim = " deadtime-trim) (db:with-db dbstruct #f #f (lambda (db) ;; in RUNNING or REMOTEHOSTSTART for more than 10 minutes ;; ;; HOWEVER: this code in run:test seems to work fine ;; (> (- (current-seconds)(+ (db:test-get-event_time testdat) ;; (db:test-get-run_duration testdat))) ;; 600) ;; (db:delay-if-busy dbdat) (sqlite3:for-each-row (lambda (test-id run-dir uname testname item-path event-time run-duration) (if (and (equal? uname "n/a") (equal? item-path "")) ;; this is a toplevel test ;; what to do with toplevel? call rollup? (begin (set! toplevels (cons (list test-id run-dir uname testname item-path run-id) toplevels)) (debug:print-info 0 *default-log-port* "Found old toplevel test in RUNNING state, test-id=" test-id)) (begin (set! incompleted (cons (list test-id run-dir uname testname item-path run-id) incompleted)) (debug:print-info 0 *default-log-port* "Found old test in RUNNING state, test-id=" test-id" exceeded running-deadtime "running-deadtime" now="(current-seconds)" event-time="event-time" run-duration="run-duration)))) db "SELECT id,rundir,uname,testname,item_path,event_time,run_duration FROM tests WHERE run_id=? AND (strftime('%s','now') - event_time) > (run_duration + ?) AND state IN ('RUNNING');" run-id running-deadtime) ;; default time 720 seconds (sqlite3:for-each-row (lambda (test-id run-dir uname testname item-path event-time run-duration) (if (and (equal? uname "n/a") (equal? item-path "")) ;; this is a toplevel test ;; what to do with toplevel? call rollup? (begin (set! toplevels (cons (list test-id run-dir uname testname item-path run-id) toplevels)) (debug:print-info 0 *default-log-port* "Found old toplevel test in RUNNING state, test-id=" test-id)) (begin (debug:print-info 0 *default-log-port* "Found old test in REMOTEHOSTSTART state, test-id=" test-id" exceeded running-deadtime "running-deadtime" now="(current-seconds)" event-time="event-time" run-duration="run-duration) (set! incompleted (cons (list test-id run-dir uname testname item-path run-id) incompleted))))) db "SELECT id,rundir,uname,testname,item_path,event_time,run_duration FROM tests WHERE run_id=? AND (strftime('%s','now') - event_time) > (run_duration + ?) AND state IN ('REMOTEHOSTSTART');" run-id remotehoststart-deadtime) ;; default time 230 seconds ;; in LAUNCHED for more than one day. Could be long due to job queues TODO/BUG: Need override for this in config ;; ;; (db:delay-if-busy dbdat) (sqlite3:for-each-row (lambda (test-id run-dir uname testname item-path) (if (and (equal? uname "n/a") (equal? item-path "")) ;; this is a toplevel test ;; what to do with toplevel? call rollup? (set! toplevels (cons (list test-id run-dir uname testname item-path run-id) toplevels)) (begin (debug:print-info 0 *default-log-port* "Found old test in LAUNCHED state, test-id=" test-id" 1 day since event_time marked") (set! oldlaunched (cons (list test-id run-dir uname testname item-path run-id) oldlaunched))))) db "SELECT id,rundir,uname,testname,item_path FROM tests WHERE run_id=? AND (strftime('%s','now') - event_time) > 86400 AND state IN ('LAUNCHED');" run-id) (debug:print-info 18 *default-log-port* "Found " (length oldlaunched) " old LAUNCHED items, " (length toplevels) " old LAUNCHED toplevel tests and " (length incompleted) " tests marked RUNNING but apparently dead.") ;; These are defunct tests, do not do all the overhead of set-state-status. Force them to INCOMPLETE. ;; ;; (db:delay-if-busy dbdat) (let* (;; (min-incompleted (filter (lambda (x) ;; (let* ((testpath (cadr x)) ;; (tdatpath (conc testpath "/testdat.db")) ;; (dbexists (common:file-exists? tdatpath))) ;; (or (not dbexists) ;; if no file then something wrong - mark as incomplete ;; (> (- (current-seconds)(file-modification-time tdatpath)) 600)))) ;; no change in 10 minutes to testdat.db - she's dead Jim ;; incompleted)) (min-incompleted-ids (map car incompleted)) ;; do 'em all (all-ids (append min-incompleted-ids (map car oldlaunched)))) (if (> (length all-ids) 0) (begin ;; (launch:is-test-alive "localhost" 435) (debug:print 0 *default-log-port* "WARNING: Marking test(s); " (string-intersperse (map conc all-ids) ", ") " as DEAD") (for-each (lambda (test-id) (let* (;; (run-dir (db:test-get-rundir-from-test-id dbstruct run-id test-id)) (tinfo (db:get-test-info-by-id dbstruct run-id test-id)) (run-dir (db:test-get-rundir tinfo)) (host (db:test-get-host tinfo)) (pid (db:test-get-process_id tinfo)) (result (db:get-status-from-final-status-file run-dir))) (if (and (list? result) (> (length result) 1) (equal? "PASS" (cadr result)) (equal? "COMPLETED" (car result))) (begin (debug:print 0 *default-log-port* "INFO: test " test-id " actually passed, so marking PASS not DEAD") (db:set-state-status-and-roll-up-items dbstruct run-id test-id 'foo "COMPLETED" "PASS" "Test stopped responding but it has PASSED; marking it PASS in the DB.")) (let ((is-alive (launch:is-test-alive host pid))) (if is-alive (debug:print 0 *default-log-port* "INFO: test " test-id " on host " host " has a process on pid " pid ", NOT setting to DEAD.") (begin (debug:print 0 *default-log-port* "INFO: test " test-id " final state/status is not COMPLETED/PASS. It is " result) (db:set-state-status-and-roll-up-items dbstruct run-id test-id 'foo "COMPLETED" "DEAD" "Test stopped responding while in RUNNING or REMOTEHOSTSTART; presumed dead."))))))) all-ids) ;;call end of eud of run detection for posthook (launch:end-of-run-check run-id) ))))))) ;; ALL REPLACED BY THE BLOCK ABOVE ;; ;; (sqlite3:execute ;; db ;; (conc "UPDATE tests SET state='INCOMPLETE' WHERE run_id=? AND id IN (" ;; (string-intersperse (map conc all-ids) ",") |
︙ | ︙ | |||
1653 1654 1655 1656 1657 1658 1659 | ;; b. If test dir gone, delete the test record ;; 2. Look at run records ;; a. If have tests that are not deleted, set state='unknown' ;; b. .... ;; (define (db:clean-up dbdat) ;; (debug:print 0 *default-log-port* "WARNING: db clean up not fully ported to v1.60, cleanup action will be on megatest.db") | > | | | | | | > > > > > > > > | 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 | ;; b. If test dir gone, delete the test record ;; 2. Look at run records ;; a. If have tests that are not deleted, set state='unknown' ;; b. .... ;; (define (db:clean-up dbdat) ;; (debug:print 0 *default-log-port* "WARNING: db clean up not fully ported to v1.60, cleanup action will be on megatest.db") (let* ((keep-record-age ( - (current-seconds) (common:hms-string->seconds (or (configf:lookup *configdat* "setup" "delete-record-age") "30d")))) (db (db:dbdat-get-db dbdat)) (count-stmt (sqlite3:prepare db "SELECT (SELECT count(id) FROM tests)+(SELECT count(id) FROM runs);")) (statements (map (lambda (stmt) (sqlite3:prepare db stmt)) (list ;; delete all tests that belong to runs that are 'deleted' (conc "DELETE FROM tests WHERE run_id in (SELECT id FROM runs WHERE state='deleted') and last_update < " keep-record-age ";") ;; delete all tests that are 'DELETED' (conc "DELETE FROM tests WHERE state='DELETED' and last_update < " keep-record-age " ;") ;; delete all tests that have no run (conc "DELETE FROM tests WHERE run_id NOT IN (SELECT DISTINCT id FROM runs) and last_update < " keep-record-age "; ") ;; delete all runs that are state='deleted' (conc "DELETE FROM runs WHERE state='deleted' and last_update < " keep-record-age ";") ;; delete empty runs (conc "DELETE FROM runs WHERE id NOT IN (SELECT DISTINCT r.id FROM runs AS r INNER JOIN tests AS t ON t.run_id=r.id) and last_update < " keep-record-age ";") ;; remove orphaned test_rundat entries (conc "DELETE FROM test_rundat where test_id NOT IN (SELECT id FROM tests);") ;; remove orphaned test_steps entries (conc "DELETE FROM test_steps WHERE test_id NOT IN (SELECT id FROM tests);") ;; remove orphaned test_dat entries (conc "DELETE FROM test_data WHERE test_id NOT IN (SELECT id FROM tests);") )))) ;; (db:delay-if-busy dbdat) ;(debug:print-info 0 *default-log-port* statements) (sqlite3:with-transaction db (lambda () (sqlite3:for-each-row (lambda (tot) (debug:print-info 0 *default-log-port* "Records count before clean: " tot)) count-stmt) (map sqlite3:execute statements) |
︙ | ︙ | |||
1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 | (lambda (db) (sqlite3:execute db "INSERT OR REPLACE INTO metadat (var,val) VALUES (?,?);" var val)))) (define (db:del-var dbstruct var) (db:with-db dbstruct #f #t (lambda (db) (sqlite3:execute db "DELETE FROM metadat WHERE var=?;" var)))) ;; use a global for some primitive caching, it is just silly to ;; re-read the db over and over again for the keys since they never ;; change ;; why get the keys from the db? why not get from the *configdat* ;; using keys:config-get-fields? | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 | (lambda (db) (sqlite3:execute db "INSERT OR REPLACE INTO metadat (var,val) VALUES (?,?);" var val)))) (define (db:del-var dbstruct var) (db:with-db dbstruct #f #t (lambda (db) (sqlite3:execute db "DELETE FROM metadat WHERE var=?;" var)))) ;;====================================================================== ;; no-sync.db - small bits of data to be shared between servers ;;====================================================================== (define (db:open-no-sync-db) (let* ((dbpath (db:dbfile-path)) (dbname (conc dbpath "/no-sync.db")) (db-exists (common:file-exists? dbname)) (db (sqlite3:open-database dbname))) (sqlite3:set-busy-handler! db (sqlite3:make-busy-timeout 136000)) (if (not db-exists) (begin (sqlite3:execute db "PRAGMA synchronous = 0;") (sqlite3:execute db "CREATE TABLE IF NOT EXISTS no_sync_metadat (var TEXT,val TEXT, CONSTRAINT no_sync_metadat_constraint UNIQUE (var));") (sqlite3:execute db "PRAGMA journal_mode=WAL;"))) db)) ;; if we are not a server create a db handle. this is not finalized ;; so watch for problems. I'm still not clear if it is needed to manually ;; finalize sqlite3 dbs with the sqlite3 egg. ;; (define (db:no-sync-db db-in) (mutex-lock! *db-access-mutex*) (let ((res (if db-in db-in (let ((db (db:open-no-sync-db))) (set! *no-sync-db* db) db)))) (mutex-unlock! *db-access-mutex*) res)) (define (db:no-sync-set db var val) (sqlite3:execute (db:no-sync-db db) "INSERT OR REPLACE INTO no_sync_metadat (var,val) VALUES (?,?);" var val)) (define (db:no-sync-del! db var) (sqlite3:execute (db:no-sync-db db) "DELETE FROM no_sync_metadat WHERE var=?;" var)) (define (db:no-sync-get/default db var default) (let ((res default)) (sqlite3:for-each-row (lambda (val) (set! res val)) (db:no-sync-db db) "SELECT val FROM no_sync_metadat WHERE var=?;" var) (if res (let ((newres (if (string? res) (string->number res) #f))) (if newres newres res)) res))) (define (db:no-sync-close-db db) (db:safely-close-sqlite3-db db)) ;; transaction protected lock aquisition ;; either: ;; fails returns (#f . lock-creation-time) ;; succeeds (returns (#t . lock-creation-time) ;; use (db:no-sync-del! db keyname) to release the lock ;; (define (db:no-sync-get-lock db-in keyname) (let ((db (db:no-sync-db db-in))) (sqlite3:with-transaction db (lambda () (handle-exceptions exn (let ((lock-time (current-seconds))) (sqlite3:execute db "INSERT INTO no_sync_metadat (var,val) VALUES(?,?);" keyname lock-time) `(#t . ,lock-time)) `(#f . ,(sqlite3:first-result db "SELECT val FROM no_sync_metadat WHERE var=?;" keyname))))))) ;; use a global for some primitive caching, it is just silly to ;; re-read the db over and over again for the keys since they never ;; change ;; why get the keys from the db? why not get from the *configdat* ;; using keys:config-get-fields? |
︙ | ︙ | |||
1846 1847 1848 1849 1850 1851 1852 | res))) ;; look up values in a header/data structure (define (db:get-value-by-header row header field) (if (or (null? header) (not row)) #f (let loop ((hed (car header)) | | | | > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > | 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 | res))) ;; look up values in a header/data structure (define (db:get-value-by-header row header field) (if (or (null? header) (not row)) #f (let loop ((hed (car header)) (tal (cdr header)) (n 0)) (if (equal? hed field) (handle-exceptions exn (begin (debug:print 0 *default-log-port* "WARNING: attempt to read non-existant field, row=" row " header=" header " field=" field) #f) (vector-ref row n)) (if (null? tal) #f (loop (car tal)(cdr tal)(+ n 1))))))) ;; Accessors for the header/data structure ;; get rows and header from (define (db:get-header vec)(vector-ref vec 0)) (define (db:get-rows vec)(vector-ref vec 1)) ;;====================================================================== ;; R U N S ;;====================================================================== (define (db:get-run-times dbstruct run-patt target-patt) (let ((res `()) (qry (conc "select runname, (max(end_time)-min(event_time))/60 as runtime, target from (select runname, run_id,tests.event_time,tests.event_time+run_duration AS end_time, " (string-join (db:get-keys dbstruct) " || '/' || ") " as target from tests inner join runs on tests.run_id = runs.id where runs.runname like ? and target like ?) group by run_id ;"))) ;(print qry) (db:with-db dbstruct #f ;; this is for the main runs db #f ;; does not modify db (lambda (db) (sqlite3:for-each-row (lambda (runname runtime target ) (set! res (cons (vector runname runtime target) res))) db qry run-patt target-patt) res)))) (define (db:get-run-name-from-id dbstruct run-id) (db:with-db dbstruct #f ;; this is for the main runs db #f ;; does not modify db (lambda (db) |
︙ | ︙ | |||
1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 | (set! res (cons (apply vector a x) res))) db qrystr ))) (debug:print-info 11 *default-log-port* "db:get-runs END qrystr: " qrystr " keypatts: " keypatts " offset: " offset " limit: " count) (vector header res))) ;; TODO: Switch this to use max(update_time) from each run db? Then if using a server there is no disk traffic (using inmem db) ;; (define (db:get-changed-run-ids since-time) (let* ((dbdir (db:dbfile-path)) ;; (configf:lookup *configdat* "setup" "dbdir")) (alldbs (glob (conc dbdir "/[0-9]*.db"))) (changed (filter (lambda (dbfile) (> (file-modification-time dbfile) since-time)) | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 | (set! res (cons (apply vector a x) res))) db qrystr ))) (debug:print-info 11 *default-log-port* "db:get-runs END qrystr: " qrystr " keypatts: " keypatts " offset: " offset " limit: " count) (vector header res))) (define-record simple-run target id runname state status owner event_time) (define-record-printer (simple-run x out) (fprintf out "#,(simple-run ~S ~S ~S ~S)" (simple-run-target x) (simple-run-id x) (simple-run-runname x) (time->string (seconds->local-time (simple-run-event_time x) )))) ;; simple get-runs ;; (define (db:simple-get-runs dbstruct runpatt count offset target) (let* ((res '()) (keys (db:get-keys dbstruct)) (runpattstr (db:patt->like "runname" runpatt)) (remfields (list "id" "runname" "state" "status" "owner" "event_time")) (targstr (string-intersperse keys "||'/'||")) (keystr (conc targstr " AS target," (string-intersperse remfields ","))) (qrystr (conc "SELECT " keystr " FROM runs WHERE (" runpattstr ") " ;; runname LIKE ? " ;; Generate: " AND x LIKE 'keypatt' ..." " AND target LIKE '" target "'" " AND state != 'deleted' ORDER BY event_time DESC " (if (number? count) (conc " LIMIT " count) "") (if (number? offset) (conc " OFFSET " offset) "")))) (debug:print-info 11 *default-log-port* "db:get-runs START qrystr: " qrystr " target: " target " offset: " offset " limit: " count) (db:with-db dbstruct #f #f (lambda (db) (sqlite3:for-each-row (lambda (target id runname state status owner event_time) (set! res (cons (make-simple-run target id runname state status owner event_time) res))) db qrystr ))) (debug:print-info 11 *default-log-port* "db:get-runs END qrystr: " qrystr " target: " target " offset: " offset " limit: " count) res)) ;; TODO: Switch this to use max(update_time) from each run db? Then if using a server there is no disk traffic (using inmem db) ;; (define (db:get-changed-run-ids since-time) (let* ((dbdir (db:dbfile-path)) ;; (configf:lookup *configdat* "setup" "dbdir")) (alldbs (glob (conc dbdir "/[0-9]*.db"))) (changed (filter (lambda (dbfile) (> (file-modification-time dbfile) since-time)) |
︙ | ︙ | |||
2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 | (sqlite3:for-each-row (lambda (count) (set! numruns count)) db "SELECT COUNT(id) FROM runs WHERE runname LIKE ? AND state != 'deleted';" runpatt) (debug:print-info 11 *default-log-port* "db:get-num-runs END " runpatt) numruns)))) ;; (sqlite3#fold-row proc3670 init3671 db-or-stmt3672 . params3673)> ;; (define (db:get-raw-run-stats dbstruct run-id) (db:with-db dbstruct run-id | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 | (sqlite3:for-each-row (lambda (count) (set! numruns count)) db "SELECT COUNT(id) FROM runs WHERE runname LIKE ? AND state != 'deleted';" runpatt) (debug:print-info 11 *default-log-port* "db:get-num-runs END " runpatt) numruns)))) ;; just get count of runs (define (db:get-runs-cnt-by-patt dbstruct runpatt targetpatt keys) (db:with-db dbstruct #f #f (lambda (db) (let ((numruns 0) (qry-str #f) (key-patt "") (keyvals (if targetpatt (keys:target->keyval keys targetpatt) '()))) (for-each (lambda (keyval) (let* ((key (car keyval)) (patt (cadr keyval)) (fulkey (conc ":" key)) (wildtype (if (substring-index "%" patt) "like" "glob"))) (if patt (set! key-patt (conc key-patt " AND " key " " wildtype " '" patt "'")) (begin (debug:print-error 0 *default-log-port* "searching for runs with no pattern set for " fulkey) (exit 6))))) keyvals) ;(print runpatt " -- " key-patt) (set! qry-str (conc "SELECT COUNT(id) FROM runs WHERE state != 'deleted' AND runname like '" runpatt "'" key-patt)) ;(print qry-str ) (sqlite3:for-each-row (lambda (count) (set! numruns count)) db qry-str) (debug:print-info 11 *default-log-port* "db:get-num-runs END " runpatt) numruns)))) ;; (sqlite3#fold-row proc3670 init3671 db-or-stmt3672 . params3673)> ;; (define (db:get-raw-run-stats dbstruct run-id) (db:with-db dbstruct run-id |
︙ | ︙ | |||
2203 2204 2205 2206 2207 2208 2209 | ;; db:get-runs-by-patt ;; get runs by list of criteria ;; register a test run with the db ;; ;; Use: (db:get-value-by-header (db:get-header runinfo)(db:get-rows runinfo)) ;; to extract info from the structure returned ;; | | | 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 | ;; db:get-runs-by-patt ;; get runs by list of criteria ;; register a test run with the db ;; ;; Use: (db:get-value-by-header (db:get-header runinfo)(db:get-rows runinfo)) ;; to extract info from the structure returned ;; (define (db:get-runs-by-patt dbstruct keys runnamepatt targpatt offset limit fields last-update sort-order ) ;; test-name) (let* ((tmp (runs:get-std-run-fields keys (or fields '("id" "runname" "state" "status" "owner" "event_time")))) (keystr (car tmp)) (header (cadr tmp)) (key-patt "") (runwildtype (if (substring-index "%" runnamepatt) "like" "glob")) (qry-str #f) (keyvals (if targpatt (keys:target->keyval keys targpatt) '()))) |
︙ | ︙ | |||
2226 2227 2228 2229 2230 2231 2232 | (debug:print-error 0 *default-log-port* "searching for runs with no pattern set for " fulkey) (exit 6))))) keyvals) (set! qry-str (conc "SELECT " keystr " FROM runs WHERE state != 'deleted' AND runname " runwildtype " ? " key-patt (if last-update (conc " AND last_update >= " last-update " ") " ") | | > > | 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 | (debug:print-error 0 *default-log-port* "searching for runs with no pattern set for " fulkey) (exit 6))))) keyvals) (set! qry-str (conc "SELECT " keystr " FROM runs WHERE state != 'deleted' AND runname " runwildtype " ? " key-patt (if last-update (conc " AND last_update >= " last-update " ") " ") " ORDER BY event_time " sort-order " " (if limit (conc " LIMIT " limit) "") (if offset (conc " OFFSET " offset) "") ";")) (debug:print-info 4 *default-log-port* "runs:get-runs-by-patt qry=" qry-str " " runnamepatt) ;(print "runs:get-runs-by-patt qry=" qry-str " " runnamepatt) (vector header (reverse (db:with-db dbstruct #f #f ;; reads db, does not write to it. (lambda (db) (sqlite3:fold-row (lambda (res . r) (cons (list->vector r) res)) |
︙ | ︙ | |||
2252 2253 2254 2255 2256 2257 2258 | ;; this is inconsistent with get-runs but it makes some sense. ;; (define (db:get-run-info dbstruct run-id) ;;(if (hash-table-ref/default *run-info-cache* run-id #f) ;; (hash-table-ref *run-info-cache* run-id) (let* ((res (vector #f #f #f #f)) (keys (db:get-keys dbstruct)) | | > | | 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 | ;; this is inconsistent with get-runs but it makes some sense. ;; (define (db:get-run-info dbstruct run-id) ;;(if (hash-table-ref/default *run-info-cache* run-id #f) ;; (hash-table-ref *run-info-cache* run-id) (let* ((res (vector #f #f #f #f)) (keys (db:get-keys dbstruct)) (remfields (list "id" "runname" "state" "status" "owner" "event_time" "comment" "fail_count" "pass_count" "contour" "last_update")) ;; "area_id")) (header (append keys remfields)) (keystr (conc (keys->keystr keys) "," (string-intersperse remfields ",")))) (debug:print-info 11 *default-log-port* "db:get-run-info run-id: " run-id " header: " header " keystr: " keystr) (db:with-db dbstruct #f #f (lambda (db) (sqlite3:for-each-row (lambda (a . x) (set! res (apply vector a x))) db (conc "SELECT " keystr " FROM runs WHERE id=?;") run-id))) (debug:print-info 11 *default-log-port* "db:get-run-info run-id: " run-id " header: " header " keystr: " keystr) (let ((finalres (vector header res))) ;; (hash-table-set! *run-info-cache* run-id finalres) finalres))) (define (db:set-comment-for-run dbstruct run-id comment) |
︙ | ︙ | |||
2315 2316 2317 2318 2319 2320 2321 | user (conc newlockval " " run-id)) (debug:print-info 1 *default-log-port* "" newlockval " run number " run-id))))) (define (db:set-run-status dbstruct run-id status msg) (db:with-db dbstruct #f #f (lambda (db) | | > > > > > > > > > > > > > > > > > > > > > > | | | | 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 | user (conc newlockval " " run-id)) (debug:print-info 1 *default-log-port* "" newlockval " run number " run-id))))) (define (db:set-run-status dbstruct run-id status msg) (db:with-db dbstruct #f #f (lambda (db) (if msg (sqlite3:execute db "UPDATE runs SET status=?,comment=? WHERE id=?;" status msg run-id) (sqlite3:execute db "UPDATE runs SET status=? WHERE id=?;" status run-id))))) (define (db:set-run-state-status dbstruct run-id state status ) (db:with-db dbstruct #f #f (lambda (db) (sqlite3:execute db "UPDATE runs SET status=?,state=? WHERE id=?;" status state run-id)))) (define (db:get-run-status dbstruct run-id) (let ((res "n/a")) (db:with-db dbstruct #f #f (lambda (db) (sqlite3:for-each-row (lambda (status) (set! res status)) db "SELECT status FROM runs WHERE id=?;" run-id) res)))) (define (db:get-run-state dbstruct run-id) (let ((res "n/a")) (db:with-db dbstruct #f #f (lambda (db) (sqlite3:for-each-row (lambda (status) (set! res status)) db "SELECT state FROM runs WHERE id=?;" run-id) res)))) ;;====================================================================== ;; K E Y S ;;====================================================================== ;; get key val pairs for a given run-id ;; ( (FIELDNAME1 keyval1) (FIELDNAME2 keyval2) ... ) (define (db:get-key-val-pairs dbstruct run-id) (let* ((keys (db:get-keys dbstruct)) (res '())) (db:with-db dbstruct #f #f (lambda (db) (for-each (lambda (key) (let ((qry (conc "SELECT " key " FROM runs WHERE id=?;"))) (sqlite3:for-each-row (lambda (key-val) (set! res (cons (list key (if (string? key-val) key-val "")) res))) ;; replace non-string bad values with empty string to prevent crashes. This scenario can happen when Megatest is killed on updating the db db qry run-id))) keys))) (reverse res))) ;; get key vals for a given run-id (define (db:get-key-vals dbstruct run-id) (let* ((keys (db:get-keys dbstruct)) (res '())) (db:with-db dbstruct #f #f (lambda (db) (for-each (lambda (key) (let ((qry (conc "SELECT " key " FROM runs WHERE id=?;"))) ;; (db:delay-if-busy dbdat) (sqlite3:for-each-row (lambda (key-val) (set! res (cons (if (string? key-val) key-val "") res))) ;; check that the key-val is a string for cases where a crash injected bad data in the megatest.db db qry run-id))) keys))) (let ((final-res (reverse res))) (hash-table-set! *keyvals* run-id final-res) final-res))) ;; The target is keyval1/keyval2..., cached in *target* as it is used often (define (db:get-target dbstruct run-id) (let* ((keyvals (db:get-key-vals dbstruct run-id)) (thekey (string-intersperse (map (lambda (x)(if x x "-na-")) keyvals) "/"))) thekey)) ;; Get run-ids for runs with same target but different runnames and NOT run-id ;; (define (db:get-prev-run-ids dbstruct run-id) (let* ((keyvals (db:get-key-val-pairs dbstruct run-id)) (kvalues (map cadr keyvals)) (keys (rmt:get-keys)) (qrystr (string-intersperse (map (lambda (x)(conc x "=?")) keys) " AND "))) (let ((prev-run-ids '())) (if (null? keyvals) '() (begin |
︙ | ︙ | |||
2678 2679 2680 2681 2682 2683 2684 | run-id #f (lambda (db) (sqlite3:first-result db ;; WARNING BUG EDIT ME - merged from v1.55 - not sure what is right here ... ;; "SELECT count(id) FROM tests WHERE state in ('RUNNING','LAUNCHED','REMOTEHOSTSTART') AND run_id NOT IN (SELECT id FROM runs WHERE state='deleted') AND NOT (uname = 'n/a' AND item_path = '');") | | | > > > > > > > > > > > > | 3035 3036 3037 3038 3039 3040 3041 3042 3043 3044 3045 3046 3047 3048 3049 3050 3051 3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066 3067 3068 3069 3070 3071 3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 | run-id #f (lambda (db) (sqlite3:first-result db ;; WARNING BUG EDIT ME - merged from v1.55 - not sure what is right here ... ;; "SELECT count(id) FROM tests WHERE state in ('RUNNING','LAUNCHED','REMOTEHOSTSTART') AND run_id NOT IN (SELECT id FROM runs WHERE state='deleted') AND NOT (uname = 'n/a' AND item_path = '');") "SELECT count(id) FROM tests WHERE state in ('RUNNING','REMOTEHOSTSTART','LAUNCHED') AND run_id=?;" run-id)))) ;; NOT IN (SELECT id FROM runs WHERE state='deleted');") ;; NEW BEHAVIOR: Look only at single run with run-id ;; ;; (define (db:get-running-stats dbstruct run-id) (define (db:get-count-tests-running-for-run-id dbstruct run-id) (db:with-db dbstruct run-id #f (lambda (db) (sqlite3:first-result db "SELECT count(id) FROM tests WHERE state in ('RUNNING','LAUNCHED','REMOTEHOSTSTART') AND run_id=?;" run-id)))) ;; For a given testname how many items are running? Used to determine ;; probability for regenerating html ;; (define (db:get-count-tests-running-for-testname dbstruct run-id testname) (db:with-db dbstruct run-id #f (lambda (db) (sqlite3:first-result db "SELECT count(id) FROM tests WHERE state in ('RUNNING','LAUNCHED','REMOTEHOSTSTART') AND run_id=? AND NOT (uname = 'n/a' AND item_path = '') AND testname=?;" run-id testname)))) (define (db:get-not-completed-cnt dbstruct run-id) (db:with-db dbstruct run-id #f (lambda (db) ;(print "SELECT count(id) FROM tests WHERE state not in ('COMPLETED', 'DELETED') AND run_id=" run-id) (sqlite3:first-result db "SELECT count(id) FROM tests WHERE state not in ('COMPLETED', 'DELETED') AND run_id=?;" run-id)))) (define (db:get-count-tests-running-in-jobgroup dbstruct run-id jobgroup) (if (not jobgroup) 0 ;; (let ((testnames '())) ;; get the testnames (db:with-db dbstruct #f #f |
︙ | ︙ | |||
2791 2792 2793 2794 2795 2796 2797 | db "SELECT attemptnum FROM tests WHERE id=?;" #f test-id)))) (define db:test-record-fields '("id" "run_id" "testname" "state" "status" "event_time" "host" "cpuload" "diskfree" "uname" "rundir" "item_path" | | | 3160 3161 3162 3163 3164 3165 3166 3167 3168 3169 3170 3171 3172 3173 3174 | db "SELECT attemptnum FROM tests WHERE id=?;" #f test-id)))) (define db:test-record-fields '("id" "run_id" "testname" "state" "status" "event_time" "host" "cpuload" "diskfree" "uname" "rundir" "item_path" "run_duration" "final_logf" "comment" "shortdir" "attemptnum" "archived" "last_update")) ;; fields *must* be a non-empty list ;; (define (db:field->number fieldname fields) (if (null? fields) #f (let loop ((hed (car fields)) |
︙ | ︙ | |||
2896 2897 2898 2899 2900 2901 2902 | (db:with-db dbstruct #f ;; run-id #f (lambda (db) (let ((res #f)) (sqlite3:for-each-row ;; attemptnum added to hold pid of top process (not Megatest) controlling a test | | | | 3265 3266 3267 3268 3269 3270 3271 3272 3273 3274 3275 3276 3277 3278 3279 3280 3281 | (db:with-db dbstruct #f ;; run-id #f (lambda (db) (let ((res #f)) (sqlite3:for-each-row ;; attemptnum added to hold pid of top process (not Megatest) controlling a test (lambda (id run-id testname state status event-time host cpuload diskfree uname rundir-id item-path run_duration final-logf-id comment short-dir-id attemptnum archived last-update) ;; 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 (set! res (vector id run-id testname state status event-time host cpuload diskfree uname rundir-id item-path run_duration final-logf-id comment short-dir-id attemptnum archived last-update))) db (conc "SELECT " db:test-record-qry-selector " FROM tests WHERE id=?;") test-id) res)))) ;; Use db:test-get* to access ;; Get test data using test_ids. NB// Only works within a single run!! |
︙ | ︙ | |||
2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 | #f (lambda (db) (db:first-result-default db "SELECT rundir FROM tests WHERE id=?;" #f ;; default result test-id)))) ;;====================================================================== ;; S T E P S ;;====================================================================== (define (db:teststep-set-status! dbstruct run-id test-id teststep-name state-in status-in comment logfile) (db:with-db dbstruct run-id #t (lambda (db) (sqlite3:execute db "INSERT OR REPLACE into test_steps (test_id,stepname,state,status,event_time,comment,logfile) VALUES(?,?,?,?,?,?,?);" test-id teststep-name state-in status-in (current-seconds) (if comment comment "") (if logfile logfile ""))))) | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 3318 3319 3320 3321 3322 3323 3324 3325 3326 3327 3328 3329 3330 3331 3332 3333 3334 3335 3336 3337 3338 3339 3340 3341 3342 3343 3344 3345 3346 3347 3348 3349 3350 3351 3352 3353 3354 3355 3356 3357 3358 3359 3360 3361 3362 3363 3364 3365 3366 3367 3368 3369 3370 3371 3372 3373 3374 3375 3376 3377 3378 3379 3380 3381 3382 3383 3384 3385 3386 3387 3388 3389 3390 3391 3392 3393 3394 3395 3396 3397 3398 3399 3400 3401 3402 3403 3404 3405 3406 3407 3408 3409 3410 3411 3412 3413 3414 3415 3416 3417 3418 3419 3420 3421 3422 3423 3424 3425 3426 3427 3428 3429 3430 3431 3432 3433 3434 3435 3436 3437 3438 3439 3440 3441 3442 3443 3444 3445 3446 3447 3448 3449 3450 3451 3452 3453 3454 3455 3456 3457 3458 3459 3460 3461 3462 3463 | #f (lambda (db) (db:first-result-default db "SELECT rundir FROM tests WHERE id=?;" #f ;; default result test-id)))) (define (db:get-test-times dbstruct run-name target) (let ((res `()) (qry (conc "select testname, item_path, run_duration, " (string-join (db:get-keys dbstruct) " || '/' || ") " as target from tests inner join runs on tests.run_id = runs.id where runs.runname = ? and target = ? ;"))) (db:with-db dbstruct #f ;; this is for the main runs db #f ;; does not modify db (lambda (db) (sqlite3:for-each-row (lambda (test-name item-path test-time target ) (set! res (cons (vector test-name item-path test-time) res))) db qry run-name target) res)))) (define (db:get-test-times dbstruct run-name target) (let ((res `()) (qry (conc "select testname, item_path, run_duration, " (string-join (db:get-keys dbstruct) " || '/' || ") " as target from tests inner join runs on tests.run_id = runs.id where runs.runname = ? and target = ? ;"))) (db:with-db dbstruct #f ;; this is for the main runs db #f ;; does not modify db (lambda (db) (sqlite3:for-each-row (lambda (test-name item-path test-time target ) (set! res (cons (vector test-name item-path test-time) res))) db qry run-name target) res)))) ;;====================================================================== ;; S T E P S ;;====================================================================== (define (db:teststep-set-status! dbstruct run-id test-id teststep-name state-in status-in comment logfile) (db:with-db dbstruct run-id #t (lambda (db) (sqlite3:execute db "INSERT OR REPLACE into test_steps (test_id,stepname,state,status,event_time,comment,logfile) VALUES(?,?,?,?,?,?,?);" test-id teststep-name state-in status-in (current-seconds) (if comment comment "") (if logfile logfile ""))))) (define (db:delete-steps-for-test! dbstruct run-id test-id) ;; TODO: figure out why status is the key field rather than state (note: CONSTRAINT test_steps_constraint UNIQUE (test_id,stepname,state) ) (db:with-db dbstruct run-id #t (lambda (db) (sqlite3:execute db "UPDATE test_steps set status='DELETED' where test_id=?" ;; and run_id=? !! - run_id not in table (bummer) TODO: get run_id into schema for test_steps test-id)))) ;; db-get-test-steps-for-run (define (db:get-steps-for-test dbstruct run-id test-id) (db:with-db dbstruct run-id #f (lambda (db) (let* ((res '())) (sqlite3:for-each-row (lambda (id test-id stepname state status event-time logfile comment) (set! res (cons (vector id test-id stepname state status event-time (if (string? logfile) logfile "") comment) res))) db "SELECT id,test_id,stepname,state,status,event_time,logfile,comment FROM test_steps WHERE status != 'DELETED' AND test_id=? ORDER BY id ASC;" ;; event_time DESC,id ASC; test-id) (reverse res))))) (define (db:get-steps-info-by-id dbstruct test-step-id) (db:with-db dbstruct #f #f (lambda (db) (let* ((res (vector #f #f #f #f #f #f #f #f #f))) (sqlite3:for-each-row (lambda (id test-id stepname state status event-time logfile comment last-update) (set! res (vector id test-id stepname state status event-time (if (string? logfile) logfile "") comment last-update))) db "SELECT id,test_id,stepname,state,status,event_time,logfile,comment,last_update FROM test_steps WHERE id=? ORDER BY id ASC;" ;; event_time DESC,id ASC; test-step-id) res)))) (define (db:get-steps-data dbstruct run-id test-id) (db:with-db dbstruct run-id #f (lambda (db) (let ((res '())) (sqlite3:for-each-row (lambda (id test-id stepname state status event-time logfile) (set! res (cons (vector id test-id stepname state status event-time (if (string? logfile) logfile "")) res))) db "SELECT id,test_id,stepname,state,status,event_time,logfile FROM test_steps WHERE status != 'DELETED' AND test_id=? ORDER BY id ASC;" ;; event_time DESC,id ASC; test-id) (reverse res))))) ;;====================================================================== ;; T E S T D A T A ;;====================================================================== (define (db:get-data-info-by-id dbstruct test-data-id) (db:with-db dbstruct #f #f (lambda (db) (let* ((res (vector #f #f #f #f #f #f #f #f #f #f #f #f))) (sqlite3:for-each-row (lambda (id test-id category variable value expected tol units comment status type last-update) (set! res (vector id test-id category variable value expected tol units comment status type last-update))) db "SELECT id,test_id, category, variable, value, expected, tol, units, comment, status, type, last_update FROM test_data WHERE id=? ORDER BY id ASC;" ;; event_time DESC,id ASC; test-data-id) res)))) ;; WARNING: Do NOT call this for the parent test on an iterated test ;; Roll up test_data pass/fail results ;; look at the test_data status field, ;; if all are pass (any case) and the test status is PASS or NULL or '' then set test status to PASS. ;; if one or more are fail (any case) then set test status to PASS, non "pass" or "fail" are ignored (define (db:test-data-rollup dbstruct run-id test-id status) |
︙ | ︙ | |||
3075 3076 3077 3078 3079 3080 3081 | 0 ;; 2 ;; Tolerance "n/a" ;; 3 ;; Units (configf:lookup dat entry-name "message") ;; 4 ;; Comment (configf:lookup dat entry-name "exit-status") ;; 5 ;; Status "logpro" ;; 6 ;; Type )))) (let* ((value (or (configf:lookup dat entry-name "measured") "n/a")) | | | | 3524 3525 3526 3527 3528 3529 3530 3531 3532 3533 3534 3535 3536 3537 3538 3539 | 0 ;; 2 ;; Tolerance "n/a" ;; 3 ;; Units (configf:lookup dat entry-name "message") ;; 4 ;; Comment (configf:lookup dat entry-name "exit-status") ;; 5 ;; Status "logpro" ;; 6 ;; Type )))) (let* ((value (or (configf:lookup dat entry-name "measured") "n/a")) (expected (or (configf:lookup dat entry-name "expected") 0.0)) (tolerance (or (configf:lookup dat entry-name "tolerance") 0.0)) (comment (or (configf:lookup dat entry-name "comment") (configf:lookup dat entry-name "desc") "n/a")) (status (or (configf:lookup dat entry-name "status") "n/a")) (type (or (configf:lookup dat entry-name "expected") "n/a"))) (set! res (append res (list (list stepname |
︙ | ︙ | |||
3181 3182 3183 3184 3185 3186 3187 3188 3189 3190 3191 3192 3193 3194 | (lambda (db) (sqlite3:for-each-row (lambda (id test_id category variable value expected tol units comment status type) (set! res (cons (vector id test_id category variable value expected tol units comment status type) res))) db "SELECT id,test_id,category,variable,value,expected,tol,units,comment,status,type FROM test_data WHERE test_id=? AND category LIKE ? ORDER BY category,variable;" test-id categorypatt) (reverse res))))) ;;====================================================================== ;; Misc. test related queries ;;====================================================================== (define (db:get-run-ids-matching-target dbstruct keynames target res runname testpatt statepatt statuspatt) (db:with-db | > > > > > > > > > > > > > > > | 3630 3631 3632 3633 3634 3635 3636 3637 3638 3639 3640 3641 3642 3643 3644 3645 3646 3647 3648 3649 3650 3651 3652 3653 3654 3655 3656 3657 3658 | (lambda (db) (sqlite3:for-each-row (lambda (id test_id category variable value expected tol units comment status type) (set! res (cons (vector id test_id category variable value expected tol units comment status type) res))) db "SELECT id,test_id,category,variable,value,expected,tol,units,comment,status,type FROM test_data WHERE test_id=? AND category LIKE ? ORDER BY category,variable;" test-id categorypatt) (reverse res))))) ;; This routine moved from tdb.scm, :read-test-data ;; (define (db:read-test-data* dbstruct run-id test-id categorypatt varpatt) (let* ((res '())) (db:with-db dbstruct #f #f (lambda (db) (sqlite3:for-each-row (lambda (id test_id category variable value expected tol units comment status type) (set! res (cons (vector id test_id category variable value expected tol units comment status type) res))) db "SELECT id,test_id,category,variable,value,expected,tol,units,comment,status,type FROM test_data WHERE test_id=? AND category LIKE ? AND variable LIKE ? ORDER BY category,variable;" test-id categorypatt varpatt) (reverse res))))) ;;====================================================================== ;; Misc. test related queries ;;====================================================================== (define (db:get-run-ids-matching-target dbstruct keynames target res runname testpatt statepatt statuspatt) (db:with-db |
︙ | ︙ | |||
3300 3301 3302 3303 3304 3305 3306 3307 3308 3309 3310 3311 3312 3313 3314 3315 | ;; state is the priority rollup of all states ;; status is the priority rollup of all completed statesfu ;; ;; if test-name is an integer work off that instead of test-name test-path ;; (define (db:set-state-status-and-roll-up-items dbstruct run-id test-name item-path state status comment) ;; establish info on incoming test followed by info on top level test (let* ((testdat (if (number? test-name) (db:get-test-info-by-id dbstruct run-id test-name) ;; test-name is actually a test-id (db:get-test-info dbstruct run-id test-name item-path))) (test-id (db:test-get-id testdat)) (test-name (if (number? test-name) (db:test-get-testname testdat) test-name)) (item-path (db:test-get-item-path testdat)) (tl-testdat (db:get-test-info dbstruct run-id test-name "")) | > > | > | | < | | > > > | < > | < | | < < < < < < < < < < < < < < < < < < | < < < < < < < < < < | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > | | | | | | | > | | > > > > > > > > > > > > > > > > > > > > > | 3764 3765 3766 3767 3768 3769 3770 3771 3772 3773 3774 3775 3776 3777 3778 3779 3780 3781 3782 3783 3784 3785 3786 3787 3788 3789 3790 3791 3792 3793 3794 3795 3796 3797 3798 3799 3800 3801 3802 3803 3804 3805 3806 3807 3808 3809 3810 3811 3812 3813 3814 3815 3816 3817 3818 3819 3820 3821 3822 3823 3824 3825 3826 3827 3828 3829 3830 3831 3832 3833 3834 3835 3836 3837 3838 3839 3840 3841 3842 3843 3844 3845 3846 3847 3848 3849 3850 3851 3852 3853 3854 3855 3856 3857 3858 3859 3860 3861 3862 3863 3864 3865 3866 3867 3868 3869 3870 3871 3872 3873 3874 3875 3876 3877 3878 3879 3880 3881 3882 3883 3884 3885 3886 3887 3888 3889 3890 3891 3892 3893 3894 3895 3896 3897 3898 3899 3900 3901 3902 3903 3904 3905 3906 3907 3908 3909 3910 3911 3912 3913 3914 3915 3916 3917 3918 3919 3920 3921 3922 3923 3924 3925 3926 3927 3928 3929 3930 3931 3932 3933 3934 3935 3936 3937 3938 3939 3940 3941 3942 3943 3944 3945 3946 | ;; state is the priority rollup of all states ;; status is the priority rollup of all completed statesfu ;; ;; if test-name is an integer work off that instead of test-name test-path ;; (define (db:set-state-status-and-roll-up-items dbstruct run-id test-name item-path state status comment) ;; establish info on incoming test followed by info on top level test ;; BBnote - for mode itemwait, linkage between upstream test & matching item status is propagated to run queue in db:prereqs-not-met (let* ((testdat (if (number? test-name) (db:get-test-info-by-id dbstruct run-id test-name) ;; test-name is actually a test-id (db:get-test-info dbstruct run-id test-name item-path))) (test-id (db:test-get-id testdat)) (test-name (if (number? test-name) (db:test-get-testname testdat) test-name)) (item-path (db:test-get-item-path testdat)) (tl-testdat (db:get-test-info dbstruct run-id test-name "")) (tl-test-id (if tl-testdat (db:test-get-id tl-testdat) #f))) (if (member state '("LAUNCHED" "REMOTEHOSTSTART")) (db:general-call dbstruct 'set-test-start-time (list test-id))) (mutex-lock! *db-transaction-mutex*) (db:with-db dbstruct #f #f (lambda (db) (let ((tr-res (sqlite3:with-transaction db (lambda () ;; NB// Pass the db so it is part fo the transaction (db:test-set-state-status db run-id test-id state status comment) ;; this call sets the item state/status (if (not (equal? item-path "")) ;; only roll up IF incoming test is an item (let* ((state-status-counts (db:get-all-state-status-counts-for-test dbstruct run-id test-name item-path state status)) ;; item-path is used to exclude current state/status of THIS test (state-stauses (db:roll-up-rules state-status-counts state status)) (newstate (car state-stauses)) (newstatus (cadr state-stauses))) (debug:print 4 *default-log-port* "BB> tl-test-id="tl-test-id" ; "test-name":"item-path" newstate="newstate" newstatus="newstatus" len(sscs)="(length state-status-counts) " state-status-counts: " (apply conc (map (lambda (x) (conc (with-output-to-string (lambda () (pp (dbr:counts->alist x)))) " | ")) state-status-counts))); end debug:print (if tl-test-id (db:test-set-state-status db run-id tl-test-id newstate newstatus #f)) ;; we are still in the transaction - must access the db and not the dbstruct )))))) (mutex-unlock! *db-transaction-mutex*) (if (and test-id state status (equal? status "AUTO")) (db:test-data-rollup dbstruct run-id test-id status)) tr-res))))) (define (db:roll-up-rules state-status-counts state status) (let* ((running (length (filter (lambda (x) (member (dbr:counts-state x) *common:running-states*)) state-status-counts))) (bad-not-started (length (filter (lambda (x) (and (equal? (dbr:counts-state x) "NOT_STARTED") (not (member (dbr:counts-status x) *common:not-started-ok-statuses*)))) state-status-counts))) (all-curr-states (common:special-sort ;; worst -> best (sort of) (delete-duplicates (if (and state (not (member state *common:dont-roll-up-states*))) (cons state (map dbr:counts-state state-status-counts)) (map dbr:counts-state state-status-counts))) *common:std-states* >)) (all-curr-statuses (common:special-sort ;; worst -> best (delete-duplicates (if (and state status (not (member state *common:dont-roll-up-states*))) (cons status (map dbr:counts-status state-status-counts)) (map dbr:counts-status state-status-counts))) *common:std-statuses* >)) (non-completes (filter (lambda (x) (not (member x (cons "COMPLETED" *common:dont-roll-up-states*)))) all-curr-states)) (preq-fails (filter (lambda (x) (equal? x "PREQ_FAIL")) all-curr-statuses)) (num-non-completes (length non-completes)) (newstate (cond ((> running 0) "RUNNING") ;; anything running, call the situation running ((> (length preq-fails) 0) "NOT_STARTED") ((> bad-not-started 0) "COMPLETED") ;; we have an ugly situation, it is completed in the sense we cannot do more. ((> num-non-completes 0) (car non-completes)) ;; (remove (lambda (x)(equal? "COMPLETED" x)) all-curr-states))) ;; only rollup DELETED if all DELETED (else (car all-curr-states)))) (newstatus (cond ((> (length preq-fails) 0) "PREQ_FAIL") ((or (> bad-not-started 0) (and (equal? newstate "NOT_STARTED") (> num-non-completes 0))) "STARTED") (else (car all-curr-statuses))))) (debug:print-info 2 *default-log-port* "\n--> probe db:set-state-status-and-roll-up-items: " "\n--> state-status-counts: "(map dbr:counts->alist state-status-counts) "\n--> running: "running "\n--> bad-not-started: "bad-not-started "\n--> non-non-completes: "num-non-completes "\n--> non-completes: "non-completes "\n--> all-curr-states: "all-curr-states "\n--> all-curr-statuses: "all-curr-statuses "\n--> newstate "newstate "\n--> newstatus "newstatus "\n\n") ;; NB// Pass the db so it is part of the transaction (list newstate newstatus))) (define (db:set-state-status-and-roll-up-run dbstruct run-id curr-state curr-status) (mutex-lock! *db-transaction-mutex*) (db:with-db dbstruct #f #f (lambda (db) (let ((tr-res (sqlite3:with-transaction db (lambda () (let* ((state-status-counts (db:get-all-state-status-counts-for-run dbstruct run-id)) (state-stauses (db:roll-up-rules state-status-counts #f #f )) (newstate (car state-stauses)) (newstatus (cadr state-stauses))) (if (or (not (eq? newstate curr-state)) (not (eq? newstatus curr-status))) (db:set-run-state-status dbstruct run-id newstate newstatus ))))))) (mutex-unlock! *db-transaction-mutex*) tr-res)))) (define (db:get-all-state-status-counts-for-run dbstruct run-id) (let* ((test-count-recs (db:with-db dbstruct #f #f (lambda (db) (sqlite3:map-row (lambda (state status count) (make-dbr:counts state: state status: status count: count)) db "SELECT state,status,count(id) FROM tests WHERE run_id=? GROUP BY state,status;" run-id ))))) test-count-recs)) ;; BBnote: db:get-all-state-status-counts-for-test returns dbr:counts object aggregating state and status of items of a given test, *not including rollup state/status* (define (db:get-all-state-status-counts-for-test dbstruct run-id test-name item-path item-state-in item-status-in) (let* ((test-info (db:get-test-info dbstruct run-id test-name item-path)) (item-state (or item-state-in (db:test-get-state test-info))) (item-status (or item-status-in (db:test-get-status test-info))) (other-items-count-recs (db:with-db dbstruct #f #f (lambda (db) (sqlite3:map-row (lambda (state status count) (make-dbr:counts state: state status: status count: count)) db ;; ignore current item because we have changed its value in the current transation so this select will see the old value. "SELECT state,status,count(id) FROM tests WHERE run_id=? AND testname=? AND item_path != '' AND item_path !=? GROUP BY state,status;" run-id test-name item-path)))) ;; add current item to tally outside of sql query (match-countrec-lambda (lambda (countrec) (and (equal? (dbr:counts-state countrec) item-state) (equal? (dbr:counts-status countrec) item-status)))) (already-have-count-rec-list (filter match-countrec-lambda other-items-count-recs)) ;; will have either 0 or 1 count recs depending if another item shares this item's state/status (updated-count-rec (if (null? already-have-count-rec-list) (make-dbr:counts state: item-state status: item-status count: 1) (let* ((our-count-rec (car already-have-count-rec-list)) (new-count (add1 (dbr:counts-count our-count-rec)))) (make-dbr:counts state: item-state status: item-status count: new-count)))) (nonmatch-countrec-lambda (lambda (countrec) (not (match-countrec-lambda countrec)))) (unrelated-rec-list (filter nonmatch-countrec-lambda other-items-count-recs))) (cons updated-count-rec unrelated-rec-list))) ;; (define (db:get-all-item-states db run-id test-name) ;; (sqlite3:map-row ;; (lambda (a) a) ;; db ;; "SELECT DISTINCT state FROM tests WHERE item_path != '' AND state != 'DELETED' AND run_id=? AND testname=?" ;; run-id test-name)) |
︙ | ︙ | |||
3426 3427 3428 3429 3430 3431 3432 | (list '(update-run-duration "UPDATE tests SET run_duration=? WHERE id=?;") ;; TESTS '(register-test "INSERT OR IGNORE INTO tests (run_id,testname,event_time,item_path,state,status) VALUES (?,?,strftime('%s','now'),?,'NOT_STARTED','n/a');") ;; Test state and status '(set-test-state "UPDATE tests SET state=? WHERE id=?;") '(set-test-status "UPDATE tests SET state=? WHERE id=?;") | | | 3981 3982 3983 3984 3985 3986 3987 3988 3989 3990 3991 3992 3993 3994 3995 | (list '(update-run-duration "UPDATE tests SET run_duration=? WHERE id=?;") ;; TESTS '(register-test "INSERT OR IGNORE INTO tests (run_id,testname,event_time,item_path,state,status) VALUES (?,?,strftime('%s','now'),?,'NOT_STARTED','n/a');") ;; Test state and status '(set-test-state "UPDATE tests SET state=? WHERE id=?;") '(set-test-status "UPDATE tests SET state=? WHERE id=?;") '(state-status "UPDATE tests SET state=?,status=? WHERE id=?;") ;; D/ONE '(state-status-msg "UPDATE tests SET state=?,status=?,comment=? WHERE id=?;") ;; DONE ;; Test comment '(set-test-comment "UPDATE tests SET comment=? WHERE id=?;") '(set-test-start-time "UPDATE tests SET event_time=strftime('%s','now') WHERE id=?;") ;; DONE '(pass-fail-counts "UPDATE tests SET pass_count=?,fail_count=? WHERE id=?;") ;; test_data-pf-rollup is used to set a tests PASS/FAIL based on the pass/fail info from the steps '(test_data-pf-rollup "UPDATE tests |
︙ | ︙ | |||
3578 3579 3580 3581 3582 3583 3584 | (define (db:login dbstruct calling-path calling-version client-signature) (cond ((not (equal? calling-path *toppath*)) (list #f "Login failed due to mismatch paths: " calling-path ", " *toppath*)) ;; ((not (equal? *run-id* run-id)) ;; (list #f "Login failed due to mismatch run-id: " run-id ", " *run-id*)) ((not (equal? megatest-version calling-version)) | | | 4133 4134 4135 4136 4137 4138 4139 4140 4141 4142 4143 4144 4145 4146 4147 | (define (db:login dbstruct calling-path calling-version client-signature) (cond ((not (equal? calling-path *toppath*)) (list #f "Login failed due to mismatch paths: " calling-path ", " *toppath*)) ;; ((not (equal? *run-id* run-id)) ;; (list #f "Login failed due to mismatch run-id: " run-id ", " *run-id*)) ((not (equal? megatest-version calling-version)) (list #t (conc "Login warning due to mismatch megatest version: " calling-version ", " megatest-version))) (else (hash-table-set! *logged-in-clients* client-signature (current-seconds)) '(#t "successful login")))) (define (db:general-call dbstruct stmtname params) (let ((query (let ((q (alist-ref (if (string? stmtname) (string->symbol stmtname) |
︙ | ︙ | |||
3601 3602 3603 3604 3605 3606 3607 | ;; get a summary of state and status counts to calculate a rollup ;; (define (db:get-state-status-summary dbstruct run-id testname) (let ((res '())) (db:with-db dbstruct #f #f | > | | | | | | | | 4156 4157 4158 4159 4160 4161 4162 4163 4164 4165 4166 4167 4168 4169 4170 4171 4172 4173 4174 4175 4176 4177 | ;; get a summary of state and status counts to calculate a rollup ;; (define (db:get-state-status-summary dbstruct run-id testname) (let ((res '())) (db:with-db dbstruct #f #f (lambda (db) (sqlite3:for-each-row (lambda (state status count) (set! res (cons (vector state status count) res))) db "SELECT state,status,count(state) FROM tests WHERE run_id=? AND testname=? AND item_path='' GROUP BY state,status;" run-id testname) res)))) (define (db:get-latest-host-load dbstruct raw-hostname) (let* ((hostname (string-substitute "\\..*$" "" raw-hostname)) (res (cons -1 0))) (db:with-db dbstruct #f #f (lambda (db) |
︙ | ︙ | |||
3717 3718 3719 3720 3721 3722 3723 | (dbfj (conc dbpath "-journal"))) (if (handle-exceptions exn (begin (debug:print-info 0 *default-log-port* "WARNING: failed to test for existance of " dbfj) (thread-sleep! 1) (db:delay-if-busy count (- count 1))) | | | 4273 4274 4275 4276 4277 4278 4279 4280 4281 4282 4283 4284 4285 4286 4287 | (dbfj (conc dbpath "-journal"))) (if (handle-exceptions exn (begin (debug:print-info 0 *default-log-port* "WARNING: failed to test for existance of " dbfj) (thread-sleep! 1) (db:delay-if-busy count (- count 1))) (common:file-exists? dbfj)) (case count ((6) (thread-sleep! 0.2) (db:delay-if-busy count: 5)) ((5) (thread-sleep! 0.4) (db:delay-if-busy count: 4)) |
︙ | ︙ | |||
3781 3782 3783 3784 3785 3786 3787 | (lambda (tag) (hash-table-set! res tag (delete-duplicates (cons testname (hash-table-ref/default res tag '()))))) tags))) db "SELECT testname,tags FROM test_meta") | | | 4337 4338 4339 4340 4341 4342 4343 4344 4345 4346 4347 4348 4349 4350 4351 | (lambda (tag) (hash-table-set! res tag (delete-duplicates (cons testname (hash-table-ref/default res tag '()))))) tags))) db "SELECT testname,tags FROM test_meta") (hash-table->alist res))))) ;; read the record given a testname (define (db:testmeta-get-record dbstruct testname) (let ((res #f)) (db:with-db dbstruct #f |
︙ | ︙ | |||
3870 3871 3872 3873 3874 3875 3876 3877 3878 | (if (null? all-patts) item-path (let loop ((hed (car all-patts)) (tal (cdr all-patts)) (res item-path)) (let* ((parts (string-split hed)) (patt (car parts)) (repl (if (> (length parts) 1)(cadr parts) "")) (newr (if (and patt repl) | > > > > > > > > > | > > > > | > > > > > > > > | 4426 4427 4428 4429 4430 4431 4432 4433 4434 4435 4436 4437 4438 4439 4440 4441 4442 4443 4444 4445 4446 4447 4448 4449 4450 4451 4452 4453 4454 4455 4456 4457 4458 4459 4460 4461 4462 4463 4464 4465 4466 4467 4468 4469 4470 4471 4472 4473 4474 4475 4476 4477 4478 4479 4480 4481 4482 | (if (null? all-patts) item-path (let loop ((hed (car all-patts)) (tal (cdr all-patts)) (res item-path)) (let* ((parts (string-split hed)) (patt (car parts)) (repl (if (> (length parts) 1)(cadr parts) "")) (newr (if (and patt repl) (begin (handle-exceptions exn (begin (debug:print 0 *default-log-port* "WARNING: itemmap has problem \"" itemmap "\", patt: " patt ", repl: " repl) res) (string-substitute patt repl res)) ) (begin (debug:print 0 *default-log-port* "WARNING: itemmap has problem \"" itemmap "\", patt: " patt ", repl: " repl) res)))) (if (null? tal) newr (loop (car tal)(cdr tal) newr))))))) ;; the new prereqs calculation, looks also at itempath if specified ;; all prereqs must be met ;; if prereq test with itempath='' is COMPLETED and PASS, WARN, CHECK, or WAIVED then prereq is met ;; if prereq test with itempath=ref-item-path and COMPLETED with PASS, WARN, CHECK, or WAIVED then prereq is met ;; ;; Note: mode 'normal means that tests must be COMPLETED and ok (i.e. PASS, WARN, CHECK, SKIP or WAIVED) ;; mode 'toplevel means that tests must be COMPLETED only ;; mode 'itemmatch or 'itemwait means that tests items must be COMPLETED and (PASS|WARN|WAIVED|CHECK) [[ NB// NOT IMPLEMENTED YET ]] ;; mode 'exclusive means this test/item cannot run if the same test/item is LAUNCHED,REMOTEHOSTSTART or RUNNING ;; ;; IDEA for consideration: ;; 1. collect all tests "upstream" ;; 2. any NOT completed and good? if yes => return those as prereqs not met, if no => return null list ;; ;; (define (db:get-prereqs-not-met dbstruct run-id waitons ref-item-path mode) (define (db:get-prereqs-not-met dbstruct run-id waitons ref-test-name ref-item-path mode itemmaps) ;; #!key (mode '(normal))(itemmap #f)) ;; BBnote - rollup of an itemized test's overall state/status done in db:set-state-status-and-roll-up-items (append (if (member 'exclusive mode) (let ((running-tests (db:get-tests-for-run dbstruct #f ;; run-id of #f means for all runs. (if (string=? ref-item-path "") ;; testpatt ref-test-name (conc ref-test-name "/" ref-item-path)) |
︙ | ︙ | |||
3918 3919 3920 3921 3922 3923 3924 3925 3926 3927 | ;; (if (equal? (db:test-get-item-path testdat) "") ;; (db:test-get-testname testdat) ;; (conc (db:test-get-testname testdat) ;; "/" ;; (db:test-get-item-path testdat)))) running-tests) ;; calling functions want the entire data '()) (if (or (not waitons) (null? waitons)) '() | > > > > > > > > > > > > > > | | > > | > > > | | > > | | < | | | > > > | | | | | | > > > > | > > > > | | | > | | | > < < | > | | > | | | | | > > | > > > > > > > > > | > > > > > > > > > > > > > > | | | | > > > > > > > > > > > > > > > > > > > > > > > > | | | | | | 4495 4496 4497 4498 4499 4500 4501 4502 4503 4504 4505 4506 4507 4508 4509 4510 4511 4512 4513 4514 4515 4516 4517 4518 4519 4520 4521 4522 4523 4524 4525 4526 4527 4528 4529 4530 4531 4532 4533 4534 4535 4536 4537 4538 4539 4540 4541 4542 4543 4544 4545 4546 4547 4548 4549 4550 4551 4552 4553 4554 4555 4556 4557 4558 4559 4560 4561 4562 4563 4564 4565 4566 4567 4568 4569 4570 4571 4572 4573 4574 4575 4576 4577 4578 4579 4580 4581 4582 4583 4584 4585 4586 4587 4588 4589 4590 4591 4592 4593 4594 4595 4596 4597 4598 4599 4600 4601 4602 4603 4604 4605 4606 4607 4608 4609 4610 4611 4612 4613 4614 4615 4616 4617 4618 4619 4620 4621 4622 4623 4624 4625 4626 4627 4628 4629 4630 4631 4632 4633 4634 4635 4636 4637 4638 4639 4640 4641 4642 4643 4644 4645 4646 4647 4648 4649 4650 4651 4652 4653 4654 4655 4656 4657 4658 4659 4660 4661 4662 4663 4664 4665 4666 4667 4668 4669 4670 4671 4672 4673 4674 | ;; (if (equal? (db:test-get-item-path testdat) "") ;; (db:test-get-testname testdat) ;; (conc (db:test-get-testname testdat) ;; "/" ;; (db:test-get-item-path testdat)))) running-tests) ;; calling functions want the entire data '()) ;; collection of: for each waiton - ;; if this ref-test-name is an item in an itemized test and mode is itemwait/itemmatch: ;; if waiton is not itemized - if waiton is not both completed and in ok status, add as unmet prerequisite ;; if waiton is itemized: ;; and waiton's items are not expanded, add as unmet prerequisite ;; else if matching waiton item is not both completed and in an ok status, add as unmet prerequisite ;; else ;; if waiton toplevel is not in both completed and ok status, add as unmet prerequisite (if (or (not waitons) (null? waitons)) '() (let* ((ref-test-itemized-mode (not (null? (lset-intersection eq? mode '(itemmatch itemwait))))) ;; how is this different from using member? (ref-test-toplevel-mode (not (null? (lset-intersection eq? mode '(toplevel))))) (ref-test-is-toplevel (equal? ref-item-path "")) (ref-test-is-item (not ref-test-is-toplevel)) (unmet-pre-reqs '()) (result '()) (unmet-prereq-items '()) ) (for-each ; waitons (lambda (waitontest-name) ;; by getting the tests with matching name we are looking only at the matching test ;; and related sub items ;; next should be using mt:get-tests-for-run? (let (;(waiton-is-itemized ...) ;(waiton-items-are-expanded ...) (waiton-tests (db:get-tests-for-run-state-status dbstruct run-id waitontest-name)) (ever-seen #f) (parent-waiton-met #f) (item-waiton-met #f) ) (for-each ; test expanded from waiton (lambda (waiton-test) (let* ((waiton-state (db:test-get-state waiton-test)) (waiton-status (db:test-get-status waiton-test)) (waiton-item-path (db:test-get-item-path waiton-test)) ;; BB- this is the upstream itempath (waiton-test-name (db:test-get-testname waiton-test)) (waiton-is-toplevel (equal? waiton-item-path "")) (waiton-is-item (not waiton-is-toplevel)) (waiton-is-completed (member waiton-state *common:ended-states*)) (waiton-is-running (member waiton-state *common:running-states*)) (waiton-is-killed (member waiton-state *common:badly-ended-states*)) (waiton-is-ok (member waiton-status *common:well-ended-states*)) ;; testname-b path-a path-b (same-itempath (db:compare-itempaths ref-test-name waiton-item-path ref-item-path itemmaps)) ;; (equal? ref-item-path waiton-item-path))) (real-ref-test-name (car (string-split ref-test-name "/"))) ;; I THINK ref-test-name SHOULD NEVER HAVE THE ITEM_PATH! (test-and-ref-are-same (equal? real-ref-test-name waiton-test-name))) (debug:print 4 *default-log-port* "waiton-test-name " waiton-test-name " ref-test-name: " ref-test-name " test-and-ref-are-same: " test-and-ref-are-same) (set! ever-seen #t) ;;(BB> "***consider waiton "waiton-test"/"waiton-item-path"***") (cond ;; case 0 - toplevel of an itemized test, at least one item in prereq has completed ((and waiton-is-item ref-test-is-toplevel ref-test-itemized-mode waiton-is-completed) (set! parent-waiton-met #t)) ;; case 1, non-item (parent test) is ((and waiton-is-toplevel ;; this is the parent test of the waiton being examined waiton-is-completed ;;(BB> "cond1") (or waiton-is-ok ref-test-toplevel-mode)) ;; itemmatch itemwait)))))) (set! parent-waiton-met #t)) ;; Special case for toplevel and KILLED ((and waiton-is-toplevel ;; this is the parent test waiton-is-killed (member 'toplevel mode)) ;;(BB> "cond2") (set! parent-waiton-met #t)) ;; For itemwait mode IFF the previous matching item is good the set parent-waiton-met ((and ref-test-itemized-mode ref-test-is-item same-itempath) ;;(BB> "cond3") (if (and waiton-is-completed (or waiton-is-ok ref-test-toplevel-mode)) (set! item-waiton-met #t) (set! unmet-prereq-items (cons waiton-test unmet-prereq-items))) (if (and waiton-is-toplevel ;; if upstream rollup test is completed, parent-waiton-met is set (or waiton-is-completed waiton-is-running)) (set! parent-waiton-met #t))) ;; normal checking of parent items, any parent or parent item not ok blocks running ((and waiton-is-completed (or waiton-is-ok (member 'toplevel mode)) ;; toplevel does not block on FAIL (and waiton-is-ok (member 'itemmatch mode) ;; itemmatch blocks on not ok ;; TODO: THIS IS PROBABLY A BUG. ITEMMATCH AND ITEMWAIT ARE SYNONYMS!! WHAT HAPPENED OT ITEMWAIT??? )) ;;(BB> "cond4") (set! item-waiton-met #t)) ((and waiton-is-completed waiton-is-ok same-itempath) ;;(BB> "cond5") (set! item-waiton-met #t)) ((and waiton-is-completed waiton-is-ok test-and-ref-are-same) ;; probably from [waitons] table (set! item-waiton-met #t)) (else #t ;;(BB> "condelse") )))) waiton-tests) ;; both requirements, parent and item-waiton must be met to NOT add item to ;; prereq's not met list ;; (BB> ;; "\n* waiton-tests "waiton-tests ;; "\n* parent-waiton-met "parent-waiton-met ;; "\n* item-waiton-met "item-waiton-met ;; "\n* ever-seen "ever-seen ;; "\n* ref-test-itemized-mode "ref-test-itemized-mode ;; "\n* unmet-prereq-items "unmet-prereq-items ;; "\n* result (pre) "result ;; "\n* ever-seen "ever-seen ;; "\n") (cond ((and ref-test-itemized-mode ref-test-is-item (not (null? unmet-prereq-items))) (set! result (append unmet-prereq-items result))) ((not (or parent-waiton-met item-waiton-met)) (set! result (append (if (null? waiton-tests) (list waitontest-name) waiton-tests) result))) ;; appends the string if the full record is not available ;; if the test is not found then clearly the waiton is not met... ;; (if (not ever-seen)(set! result (cons waitontest-name result))))) ((not ever-seen) (set! result (append (if (null? waiton-tests)(list waitontest-name) waiton-tests) result)))))) waitons) (delete-duplicates result))))) ;;====================================================================== ;; To sync individual run ;;====================================================================== (define (db:get-run-record-ids dbstruct target run keynames test-patt) (let ((backcons (lambda (lst item)(cons item lst)))) (db:with-db dbstruct #f #f (lambda (db) (let* ((keystr (string-intersperse (map (lambda (key val) (conc key " like '" val "'")) keynames (string-split target "/")) " AND ")) (run-qry (conc "SELECT id FROM runs WHERE " keystr " and runname='" run"'")) (test-qry (conc "SELECT id FROM tests WHERE run_id in (" run-qry ") and testname like '" test-patt "'"))) (print run-qry) (print test-qry) `((runs . ,(sqlite3:fold-row backcons '() db run-qry)) (tests . ,(sqlite3:fold-row backcons '() db test-qry)) (test_steps . ,(sqlite3:fold-row backcons '() db (conc "SELECT id FROM test_steps WHERE test_id in (" test-qry ")"))) (test_data . ,(sqlite3:fold-row backcons '() db (conc "SELECT id FROM test_data WHERE test_id in (" test-qry ")" ))) )))))) ;;====================================================================== ;; Just for sync, procedures to make sync easy ;;====================================================================== ;; get an alist of record ids changed since time since-time ;; '((runs . (1 2 3 ...))(steps . (5 6 7 ...) ...)) ;; (define (db:get-changed-record-ids dbstruct since-time) ;; no transaction, allow the db to be accessed between the big queries (let ((backcons (lambda (lst item)(cons item lst)))) (db:with-db dbstruct #f #f (lambda (db) `((runs . ,(sqlite3:fold-row backcons '() db "SELECT id FROM runs WHERE last_update>=?" since-time)) (tests . ,(sqlite3:fold-row backcons '() db "SELECT id FROM tests WHERE last_update>=?" since-time)) (test_steps . ,(sqlite3:fold-row backcons '() db "SELECT id FROM test_steps WHERE last_update>=?" since-time)) (test_data . ,(sqlite3:fold-row backcons '() db "SELECT id FROM test_data WHERE last_update>=?" since-time)) ;; (test_meta . ,(fold-row backcons '() db "SELECT id FROM test_meta WHERE last_update>?" since-time)) (run_stats . ,(sqlite3:fold-row backcons '() db "SELECT id FROM run_stats WHERE last_update>=?" since-time)) ))))) ;;====================================================================== ;; Extract ods file from the db ;;====================================================================== ;; NOT REWRITTEN YET!!!!! |
︙ | ︙ | |||
4081 4082 4083 4084 4085 4086 4087 | (append res (list (vector-ref vb (+ i 2)))))))) (runname (vector-ref vb 1)) (testname (vector-ref vb (+ 2 numkeys))) (item-path (vector-ref vb (+ 3 numkeys))) (final-log (vector-ref vb (+ 7 numkeys))) (run-dir (vector-ref vb (+ 18 numkeys))) (log-fpath (conc run-dir "/" final-log))) ;; (string-intersperse keyvals "/") "/" testname "/" item-path "/" | | | | 4740 4741 4742 4743 4744 4745 4746 4747 4748 4749 4750 4751 4752 4753 4754 4755 | (append res (list (vector-ref vb (+ i 2)))))))) (runname (vector-ref vb 1)) (testname (vector-ref vb (+ 2 numkeys))) (item-path (vector-ref vb (+ 3 numkeys))) (final-log (vector-ref vb (+ 7 numkeys))) (run-dir (vector-ref vb (+ 18 numkeys))) (log-fpath (conc run-dir "/" final-log))) ;; (string-intersperse keyvals "/") "/" testname "/" item-path "/" (debug:print 4 *default-log-port* "log: " log-fpath " exists: " (common:file-exists? log-fpath)) (vector-set! vb (+ 7 numkeys) (if (common:file-exists? log-fpath) (let ((newpath (conc pathmod "/" (string-intersperse keyvals "/") "/" runname "/" testname "/" (if (string=? item-path "") "" (conc "/" item-path)) final-log))) ;; for now throw away newpath and use the log-fpath conc'd with pathmod (set! newpath (conc pathmod log-fpath)) |
︙ | ︙ | |||
4129 4130 4131 4132 4133 4134 4135 4136 4137 4138 4139 4140 | (if (string-match (regexp "^[/~]+.*") outputfile) ;; full path? outputfile (begin (debug:print 0 *default-log-port* "WARNING: path given, " outputfile " is relative, prefixing with current directory") (conc (current-directory) "/" outputfile))) results) ;; brutal clean up (system "rm -rf tempdir"))) ;; (db:extract-ods-file db "outputfile.ods" '(("sysname" "%")("fsname" "%")("datapath" "%")) "%") | > | 4788 4789 4790 4791 4792 4793 4794 4795 4796 4797 4798 4799 4800 | (if (string-match (regexp "^[/~]+.*") outputfile) ;; full path? outputfile (begin (debug:print 0 *default-log-port* "WARNING: path given, " outputfile " is relative, prefixing with current directory") (conc (current-directory) "/" outputfile))) results) ;; brutal clean up (stack-push! (dbr:dbstruct-dbstack dbstruct) dbdat) (system "rm -rf tempdir"))) ;; (db:extract-ods-file db "outputfile.ods" '(("sysname" "%")("fsname" "%")("datapath" "%")) "%") |
Modified db_records.scm from [ebae0b2ffd] to [37c233f08b].
1 2 3 4 5 6 7 | ;;====================================================================== ;; dbstruct ;;====================================================================== ;; ;; -path-|-megatest.db ;; |-db-|-main.db | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | ;; Copyright 2006-2017, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. ;;====================================================================== ;; dbstruct ;;====================================================================== ;; ;; -path-|-megatest.db ;; |-db-|-main.db |
︙ | ︙ | |||
83 84 85 86 87 88 89 90 91 92 93 94 95 96 | (define-inline (db:test-get-rundir vec) (vector-ref vec 10)) (define-inline (db:test-get-item-path vec) (vector-ref vec 11)) (define-inline (db:test-get-run_duration vec) (vector-ref vec 12)) (define-inline (db:test-get-final_logf vec) (vector-ref vec 13)) (define-inline (db:test-get-comment vec) (vector-ref vec 14)) (define-inline (db:test-get-process_id vec) (vector-ref vec 16)) (define-inline (db:test-get-archived vec) (vector-ref vec 17)) ;; (define-inline (db:test-get-pass_count vec) (vector-ref vec 15)) ;; (define-inline (db:test-get-fail_count vec) (vector-ref vec 16)) (define-inline (db:test-get-fullname vec) (conc (db:test-get-testname vec) "/" (db:test-get-item-path vec))) ;; replace runs:make-full-test-name with this routine | > | 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 | (define-inline (db:test-get-rundir vec) (vector-ref vec 10)) (define-inline (db:test-get-item-path vec) (vector-ref vec 11)) (define-inline (db:test-get-run_duration vec) (vector-ref vec 12)) (define-inline (db:test-get-final_logf vec) (vector-ref vec 13)) (define-inline (db:test-get-comment vec) (vector-ref vec 14)) (define-inline (db:test-get-process_id vec) (vector-ref vec 16)) (define-inline (db:test-get-archived vec) (vector-ref vec 17)) (define-inline (db:test-get-last_update vec) (vector-ref vec 18)) ;; (define-inline (db:test-get-pass_count vec) (vector-ref vec 15)) ;; (define-inline (db:test-get-fail_count vec) (vector-ref vec 16)) (define-inline (db:test-get-fullname vec) (conc (db:test-get-testname vec) "/" (db:test-get-item-path vec))) ;; replace runs:make-full-test-name with this routine |
︙ | ︙ | |||
145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 | (define-inline (db:testmeta-set-author! vec val)(vector-set! vec 2 val)) (define-inline (db:testmeta-set-owner! vec val)(vector-set! vec 3 val)) (define-inline (db:testmeta-set-description! vec val)(vector-set! vec 4 val)) (define-inline (db:testmeta-set-reviewed! vec val)(vector-set! vec 5 val)) (define-inline (db:testmeta-set-iterated! vec val)(vector-set! vec 6 val)) (define-inline (db:testmeta-set-avg_runtime! vec val)(vector-set! vec 7 val)) (define-inline (db:testmeta-set-avg_disk! vec val)(vector-set! vec 8 val)) ;;====================================================================== ;; T E S T D A T A ;;====================================================================== (define (make-db:test-data)(make-vector 10)) (define-inline (db:test-data-get-id vec) (vector-ref vec 0)) (define-inline (db:test-data-get-test_id vec) (vector-ref vec 1)) (define-inline (db:test-data-get-category vec) (vector-ref vec 2)) (define-inline (db:test-data-get-variable vec) (vector-ref vec 3)) (define-inline (db:test-data-get-value vec) (vector-ref vec 4)) (define-inline (db:test-data-get-expected vec) (vector-ref vec 5)) (define-inline (db:test-data-get-tol vec) (vector-ref vec 6)) (define-inline (db:test-data-get-units vec) (vector-ref vec 7)) (define-inline (db:test-data-get-comment vec) (vector-ref vec 8)) (define-inline (db:test-data-get-status vec) (vector-ref vec 9)) (define-inline (db:test-data-get-type vec) (vector-ref vec 10)) (define-inline (db:test-data-set-id! vec val)(vector-set! vec 0 val)) (define-inline (db:test-data-set-test_id! vec val)(vector-set! vec 1 val)) (define-inline (db:test-data-set-category! vec val)(vector-set! vec 2 val)) (define-inline (db:test-data-set-variable! vec val)(vector-set! vec 3 val)) (define-inline (db:test-data-set-value! vec val)(vector-set! vec 4 val)) (define-inline (db:test-data-set-expected! vec val)(vector-set! vec 5 val)) (define-inline (db:test-data-set-tol! vec val)(vector-set! vec 6 val)) (define-inline (db:test-data-set-units! vec val)(vector-set! vec 7 val)) (define-inline (db:test-data-set-comment! vec val)(vector-set! vec 8 val)) (define-inline (db:test-data-set-status! vec val)(vector-set! vec 9 val)) (define-inline (db:test-data-set-type! vec val)(vector-set! vec 10 val)) ;;====================================================================== ;; S T E P S ;;====================================================================== ;; Run steps ;; make-vector-record "Run steps" db step id test_id stepname step_complete step_pass event_time | > > > > > > > | > | | 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 | (define-inline (db:testmeta-set-author! vec val)(vector-set! vec 2 val)) (define-inline (db:testmeta-set-owner! vec val)(vector-set! vec 3 val)) (define-inline (db:testmeta-set-description! vec val)(vector-set! vec 4 val)) (define-inline (db:testmeta-set-reviewed! vec val)(vector-set! vec 5 val)) (define-inline (db:testmeta-set-iterated! vec val)(vector-set! vec 6 val)) (define-inline (db:testmeta-set-avg_runtime! vec val)(vector-set! vec 7 val)) (define-inline (db:testmeta-set-avg_disk! vec val)(vector-set! vec 8 val)) ;;====================================================================== ;; S I M P L E R U N ;;====================================================================== ;; (defstruct id "runname" "state" "status" "owner" "event_time" ;;====================================================================== ;; T E S T D A T A ;;====================================================================== (define (make-db:test-data)(make-vector 10)) (define-inline (db:test-data-get-id vec) (vector-ref vec 0)) (define-inline (db:test-data-get-test_id vec) (vector-ref vec 1)) (define-inline (db:test-data-get-category vec) (vector-ref vec 2)) (define-inline (db:test-data-get-variable vec) (vector-ref vec 3)) (define-inline (db:test-data-get-value vec) (vector-ref vec 4)) (define-inline (db:test-data-get-expected vec) (vector-ref vec 5)) (define-inline (db:test-data-get-tol vec) (vector-ref vec 6)) (define-inline (db:test-data-get-units vec) (vector-ref vec 7)) (define-inline (db:test-data-get-comment vec) (vector-ref vec 8)) (define-inline (db:test-data-get-status vec) (vector-ref vec 9)) (define-inline (db:test-data-get-type vec) (vector-ref vec 10)) (define-inline (db:test-data-get-last_update vec) (vector-ref vec 11)) (define-inline (db:test-data-set-id! vec val)(vector-set! vec 0 val)) (define-inline (db:test-data-set-test_id! vec val)(vector-set! vec 1 val)) (define-inline (db:test-data-set-category! vec val)(vector-set! vec 2 val)) (define-inline (db:test-data-set-variable! vec val)(vector-set! vec 3 val)) (define-inline (db:test-data-set-value! vec val)(vector-set! vec 4 val)) (define-inline (db:test-data-set-expected! vec val)(vector-set! vec 5 val)) (define-inline (db:test-data-set-tol! vec val)(vector-set! vec 6 val)) (define-inline (db:test-data-set-units! vec val)(vector-set! vec 7 val)) (define-inline (db:test-data-set-comment! vec val)(vector-set! vec 8 val)) (define-inline (db:test-data-set-status! vec val)(vector-set! vec 9 val)) (define-inline (db:test-data-set-type! vec val)(vector-set! vec 10 val)) ;;====================================================================== ;; S T E P S ;;====================================================================== ;; Run steps ;; make-vector-record "Run steps" db step id test_id stepname step_complete step_pass event_time (define (make-db:step)(make-vector 9)) (define-inline (tdb:step-get-id vec) (vector-ref vec 0)) (define-inline (tdb:step-get-test_id vec) (vector-ref vec 1)) (define-inline (tdb:step-get-stepname vec) (vector-ref vec 2)) (define-inline (tdb:step-get-state vec) (vector-ref vec 3)) (define-inline (tdb:step-get-status vec) (vector-ref vec 4)) (define-inline (tdb:step-get-event_time vec) (vector-ref vec 5)) (define-inline (tdb:step-get-logfile vec) (vector-ref vec 6)) (define-inline (tdb:step-get-comment vec) (vector-ref vec 7)) (define-inline (tdb:step-get-last_update vec) (vector-ref vec 8)) (define-inline (tdb:step-set-id! vec val)(vector-set! vec 0 val)) (define-inline (tdb:step-set-test_id! vec val)(vector-set! vec 1 val)) (define-inline (tdb:step-set-stepname! vec val)(vector-set! vec 2 val)) (define-inline (tdb:step-set-state! vec val)(vector-set! vec 3 val)) (define-inline (tdb:step-set-status! vec val)(vector-set! vec 4 val)) (define-inline (tdb:step-set-event_time! vec val)(vector-set! vec 5 val)) (define-inline (tdb:step-set-logfile! vec val)(vector-set! vec 6 val)) (define-inline (tdb:step-set-comment! vec val)(vector-set! vec 7 val)) ;; The steps table (define (make-db:steps-table)(make-vector 5)) (define-inline (tdb:steps-table-get-stepname vec) (vector-ref vec 0)) (define-inline (tdb:steps-table-get-start vec) (vector-ref vec 1)) (define-inline (tdb:steps-table-get-end vec) (vector-ref vec 2)) |
︙ | ︙ |
Deleted dbwars/NOTES version [8f8ee6c6d0].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted dbwars/sql-de-lite-test.scm version [004f7cb8d7].
|
| < < < < < < < < < < < < < < < < < < < |
Deleted dbwars/sqlite3-test.scm version [338a298923].
|
| < < < < < < < < < < < < < < < < < < < < |
Deleted dbwars/test-common.scm version [02dcd9f2da].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Modified dcommon.scm from [71cb131d2d] to [ada970eba5].
1 2 3 | ;;====================================================================== ;; Copyright 2006-2013, Matthew Welland. ;; | | | > > > > > | | > | > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 | ;;====================================================================== ;; Copyright 2006-2013, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. ;; ;;====================================================================== (use format) (require-library iup) (import (prefix iup iup:)) (use canvas-draw) (import canvas-draw-iup) (use regex typed-records matchable) (declare (unit dcommon)) (declare (uses megatest-version)) (declare (uses gutils)) (declare (uses db)) ;; (declare (uses synchash)) (include "common_records.scm") (include "db_records.scm") (include "key_records.scm") (include "run_records.scm") ;; yes, this is non-ideal (define dashboard:update-summary-tab #f) (define dashboard:update-servers-table #f) ;;====================================================================== ;; C O M M O N D A T A S T R U C T U R E ;;====================================================================== ;; ;; data common to all tabs goes here ;; (defstruct dboard:commondat ((curr-tab-num 0) : number) please-update tabdats update-mutex updaters updating uidat ;; needs to move to tabdat at some time hide-not-hide-tabs ) (define (dboard:commondat-make) (make-dboard:commondat curr-tab-num: 0 tabdats: (make-hash-table) please-update: #t update-mutex: (make-mutex) updaters: (make-hash-table) updating: #f hide-not-hide-tabs: #f )) ;; RADT => Matrix defstruct addition (defstruct dboard:graph-dat ((id #f) : string) ((color #f) : vector) ((flag #t) : boolean) ((cell #f) : number) ) ;; data for runs, tests etc. was used in run summary? ;; (defstruct dboard:runsdat ;; new system runs-index ;; target/runname => colnum tests-index ;; testname/itempath => rownum matrix-dat ;; vector of vectors rows/cols ) (define (dboard:runsdat-make-init) (make-dboard:runsdat runs-index: (make-hash-table) tests-index: (make-hash-table) matrix-dat: (make-sparse-array))) ;; used to keep the rundata from rmt:get-tests-for-run ;; in sync. ;; (defstruct dboard:rundat run tests-drawn ;; list of id's already drawn on screen tests-notdrawn ;; list of id's NOT already drawn rowsused ;; hash of lists covering what areas used - replace with quadtree hierdat ;; put hierarchial sorted list here tests ;; hash of id => testdat ((tests-by-name (make-hash-table)) : hash-table) ;; hash of testfullname => testdat key-vals ((last-update 0) : number) ;; last query to db got records from before last-update ((last-db-time 0) : number) ;; last timestamp on megatest.db ((data-changed #f) : boolean) ((run-data-offset 0) : number) ;; get only 100 items per call, set back to zero when received less than 100 items (db-path #f)) ;;====================================================================== ;; D O T F I L E ;;====================================================================== (define (dcommon:write-dotfile fname dat) (with-output-to-file fname |
︙ | ︙ | |||
70 71 72 73 74 75 76 | ;; modify a cell if the data is changed, return #t or-ed with previous if modified, #f elsewise ;; (define (dcommon:modifiy-if-different mtrx cell-name new-val prev-changed) (let ((curr-val (iup:attribute mtrx cell-name))) (if (not (equal? curr-val new-val)) (begin | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | < > | | | | < > | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 | ;; modify a cell if the data is changed, return #t or-ed with previous if modified, #f elsewise ;; (define (dcommon:modifiy-if-different mtrx cell-name new-val prev-changed) (let ((curr-val (iup:attribute mtrx cell-name))) (if (not (equal? curr-val new-val)) (begin (iup:attribute-set! mtrx cell-name new-val) ;; was col-name #t) ;; need a re-draw prev-changed))) ;; TO-DO ;; 1. Make "data" hash-table hierarchial store of all displayed data ;; 2. Update synchash to understand "get-runs", "get-tests" etc. ;; 3. Add extraction of filters to synchash calls ;; ;; NOTE: Used in newdashboard ;; ;; Mode is 'full or 'incremental for full refresh or incremental refresh ;; (define (dcommon:run-update keys data runname keypatts testpatt states statuses mode window-id) ;; (let* (;; count and offset => #f so not used ;; ;; the synchash calls modify the "data" hash ;; (changed #f) ;; (get-runs-sig (conc (client:get-signature) " get-runs")) ;; (get-tests-sig (conc (client:get-signature) " get-tests")) ;; (get-details-sig (conc (client:get-signature) " get-test-details")) ;; ;; ;; test-ids to get and display are indexed on window-id in curr-test-ids hash ;; (test-ids (hash-table-values (dboard:tabdat-curr-test-ids data))) ;; ;; run-id is #f in next line to send the query to server 0 ;; (run-changes (synchash:client-get 'db:get-runs get-runs-sig (length keypatts) data #f runname #f #f keypatts)) ;; (tests-detail-changes (if (not (null? test-ids)) ;; (synchash:client-get 'db:get-test-info-by-ids get-details-sig 0 data #f test-ids) ;; '())) ;; ;; ;; Now can calculate the run-ids ;; (run-hash (hash-table-ref/default data get-runs-sig #f)) ;; (run-ids (if run-hash (filter number? (hash-table-keys run-hash)) '())) ;; ;; (all-test-changes (let ((res (make-hash-table))) ;; (for-each (lambda (run-id) ;; (if (> run-id 0) ;; (hash-table-set! res run-id (synchash:client-get 'db:get-tests-for-run-mindata get-tests-sig 0 data run-id 1 testpatt states statuses #f)))) ;; run-ids) ;; res)) ;; (runs-hash (hash-table-ref/default data get-runs-sig #f)) ;; (header (hash-table-ref/default runs-hash "header" #f)) ;; (run-ids (sort (filter number? (hash-table-keys runs-hash)) ;; (lambda (a b) ;; (let* ((record-a (hash-table-ref runs-hash a)) ;; (record-b (hash-table-ref runs-hash b)) ;; (time-a (db:get-value-by-header record-a header "event_time")) ;; (time-b (db:get-value-by-header record-b header "event_time"))) ;; (> time-a time-b))) ;; )) ;; (runid-to-col (hash-table-ref *cachedata* "runid-to-col")) ;; (testname-to-row (hash-table-ref *cachedata* "testname-to-row")) ;; (colnum 1) ;; (rownum 0) ;; (cellname (conc rownum ":" colnum))) ;; rownum = 0 is the header ;; ;; (debug:print 0 *default-log-port* "test-ids " test-ids ", tests-detail-changes " tests-detail-changes) ;; ;; ;; tests related stuff ;; ;; (all-testnames (delete-duplicates (map db:test-get-testname test-changes)))) ;; ;; ;; Given a run-id and testname/item_path calculate a cell R:C ;; ;; ;; NOTE: Also build the test tree browser and look up table ;; ;; ;; ;; Each run is unique on its keys and runname or run-id, store in hash on colnum ;; (for-each (lambda (run-id) ;; (let* ((run-record (hash-table-ref/default runs-hash run-id #f)) ;; (key-vals (map (lambda (key)(db:get-value-by-header run-record header key)) ;; keys)) ;; (run-name (db:get-value-by-header run-record header "runname")) ;; (col-name (conc (string-intersperse key-vals "\n") "\n" run-name)) ;; (run-path (append key-vals (list run-name)))) ;; (hash-table-set! (dboard:tabdat-run-keys data) run-id run-path) ;; ;; modify cell - but only if changed ;; (set! changed (dcommon:modifiy-if-different (dboard:tabdat-runs-matrix data) cellname col-name changed)) ;; (hash-table-set! runid-to-col run-id (list colnum run-record)) ;; ;; Here we update the tests treebox and tree keys ;; (tree:add-node (dboard:tabdat-tests-tree data) "Runs" (append key-vals (list run-name)) ;; userdata: (conc "run-id: " run-id)) ;; (set! colnum (+ colnum 1)))) ;; run-ids) ;; ;; ;; Scan all tests to be displayed and organise all the test names, respecting what is in the hash table ;; ;; Do this analysis in the order of the run-ids, the most recent run wins ;; (for-each (lambda (run-id) ;; (let* ((run-path (hash-table-ref (dboard:tabdat-run-keys data) run-id)) ;; (test-changes (hash-table-ref all-test-changes run-id)) ;; (new-test-dat (car test-changes)) ;; (removed-tests (cadr test-changes)) ;; (tests (sort (map cadr (filter (lambda (testrec) ;; (eq? run-id (db:mintest-get-run_id (cadr testrec)))) ;; new-test-dat)) ;; (lambda (a b) ;; (let ((time-a (db:mintest-get-event_time a)) ;; (time-b (db:mintest-get-event_time b))) ;; (> time-a time-b))))) ;; ;; test-changes is a list of (( id record ) ... ) ;; ;; Get list of test names sorted by time, remove tests ;; (test-names (delete-duplicates (map (lambda (t) ;; (let ((i (db:mintest-get-item_path t)) ;; (n (db:mintest-get-testname t))) ;; (if (string=? i "") ;; (conc " " i) ;; n))) ;; tests))) ;; (colnum (car (hash-table-ref runid-to-col run-id)))) ;; ;; for each test name get the slot if it exists and fill in the cell ;; ;; or take the next slot and fill in the cell, deal with items in the ;; ;; run view panel? The run view panel can have a tree selector for ;; ;; browsing the tests/items ;; ;; ;; SWITCH THIS TO USING CHANGED TESTS ONLY ;; (for-each (lambda (test) ;; (let* ((test-id (db:mintest-get-id test)) ;; (state (db:mintest-get-state test)) ;; (status (db:mintest-get-status test)) ;; (testname (db:mintest-get-testname test)) ;; (itempath (db:mintest-get-item_path test)) ;; (fullname (conc testname "/" itempath)) ;; (dispname (if (string=? itempath "") testname (conc " " itempath))) ;; (rownum (hash-table-ref/default testname-to-row fullname #f)) ;; (test-path (append run-path (if (equal? itempath "") ;; (list testname) ;; (list testname itempath)))) ;; (tb (dboard:tabdat-tests-tree data))) ;; (print "INFONOTE: run-path: " run-path) ;; (tree:add-node (dboard:tabdat-tests-tree data) "Runs" ;; test-path ;; userdata: (conc "test-id: " test-id)) ;; (let ((node-num (tree:find-node tb (cons "Runs" test-path))) ;; (color (car (gutils:get-color-for-state-status state status)))) ;; (debug:print 0 *default-log-port* "node-num: " node-num ", color: " color) ;; ;; (set! changed (dcommon:modifiy-if-different ;; tb ;; (conc "COLOR" node-num) ;; color changed)) ;; ;; ;; (iup:attribute-set! tb (conc "COLOR" node-num) color) ;; ) ;; (hash-table-set! (dboard:tabdat-path-test-ids data) test-path test-id) ;; (if (not rownum) ;; (let ((rownums (hash-table-values testname-to-row))) ;; (set! rownum (if (null? rownums) ;; 1 ;; (+ 1 (common:max rownums)))) ;; (hash-table-set! testname-to-row fullname rownum) ;; ;; create the label ;; (set! changed (dcommon:modifiy-if-different ;; (dboard:tabdat-runs-matrix data) ;; (conc rownum ":" 0) ;; dispname ;; changed)) ;; ;; (iup:attribute-set! (dboard:tabdat-runs-matrix data) ;; ;; (conc rownum ":" 0) dispname) ;; )) ;; ;; set the cell text and color ;; ;; (debug:print 2 *default-log-port* "rownum:colnum=" rownum ":" colnum ", state=" status) ;; (set! changed (dcommon:modifiy-if-different ;; (dboard:tabdat-runs-matrix data) ;; (conc rownum ":" colnum) ;; (if (member state '("ARCHIVED" "COMPLETED")) ;; status ;; state) ;; changed)) ;; ;; (iup:attribute-set! (dboard:tabdat-runs-matrix data) ;; ;; (conc rownum ":" colnum) ;; ;; (if (member state '("ARCHIVED" "COMPLETED")) ;; ;; status ;; ;; state)) ;; (set! changed (dcommon:modifiy-if-different ;; (dboard:tabdat-runs-matrix data) ;; (conc "BGCOLOR" rownum ":" colnum) ;; (car (gutils:get-color-for-state-status state status)) ;; changed)) ;; ;; (iup:attribute-set! (dboard:tabdat-runs-matrix data) ;; ;; (conc "BGCOLOR" rownum ":" colnum) ;; ;; (car (gutils:get-color-for-state-status state status))) ;; )) ;; tests))) ;; run-ids) ;; ;; (let ((updater (hash-table-ref/default (dboard:commondat-updaters commondat) window-id #f))) ;; (if updater (updater (hash-table-ref/default data get-details-sig #f)))) ;; ;; (if changed (iup:attribute-set! (dboard:tabdat-runs-matrix data) "REDRAW" "ALL")) ;; ;; (debug:print 2 *default-log-port* "run-changes: " run-changes) ;; ;; (debug:print 2 *default-log-port* "test-changes: " test-changes) ;; (list run-changes all-test-changes))) #;(define (dcommon:runsdat-get-col-num dat target runname force-set) (let* ((runs-index (dboard:runsdat-runs-index dat)) (col-name (conc target "/" runname)) (res (hash-table-ref/default runs-index col-name #f))) (if res res (if force-set (let ((max-col-num (+ 1 (common:max (cons-1 (hash-table-values runs-index)))))) (hash-table-set! runs-index col-name max-col-num) max-col-num))))) #;(define (dcommon:runsdat-get-row-num dat testname itempath force-set) (let* ((tests-index (dboard:runsdat-runs-index dat)) (row-name (conc testname "/" itempath)) (res (hash-table-ref/default runs-index row-name #f))) (if res res (if force-set (let ((max-row-num (+ 1 (common:max (cons -1 (hash-table-values tests-index)))))) |
︙ | ︙ | |||
311 312 313 314 315 316 317 | (tal (cdr tests-dat)) (res '())) (let* ((test-id (db:test-get-id hed)) ;; look at the tests-dat spec for locations (test-name (db:test-get-testname hed)) (item-path (db:test-get-item-path hed)) (state (db:test-get-state hed)) (status (db:test-get-status hed)) | > | | > > > | 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 | (tal (cdr tests-dat)) (res '())) (let* ((test-id (db:test-get-id hed)) ;; look at the tests-dat spec for locations (test-name (db:test-get-testname hed)) (item-path (db:test-get-item-path hed)) (state (db:test-get-state hed)) (status (db:test-get-status hed)) (event-time (db:test-get-event_time hed)) (newitem (list test-name item-path (list test-id state status event-time)))) (if (null? tal) (reverse (cons newitem res)) (loop (car tal)(cdr tal)(cons newitem res))))))) (define (dcommon:tests-mindat->hash tests-mindat) (let* ((res (make-hash-table))) (for-each (lambda (item) (let* ((test-name+item-path (cons (list-ref item 0) (list-ref item 1))) (value (list-ref item 2))) (hash-table-set! res test-name+item-path value))) tests-mindat) res)) ;; return 1 if status1 is better ;; return 0 if status1 and 2 are equally good ;; return -1 if status2 is better (define (dcommon:status-compare3 status1 status2) (let* ((status-goodness-ranking (cdr ;; cdr to drop first item -- "n/a" (append (map cadr *common:std-statuses*) '(#f)) ;; algorithm requres last item to be #f ) ) (mem1 (member status1 status-goodness-ranking)) (mem2 (member status2 status-goodness-ranking)) ) (cond ((and (not mem1) (not mem2)) 0) ((not mem1) -1) ((not mem2) 1) |
︙ | ︙ | |||
433 434 435 436 437 438 439 | (if (not testdat) (begin (debug:print 2 "ERROR: No test data found for test " test-id ", exiting") (exit 1)) (let* ((rundir (if testdat (db:test-get-rundir testdat) | | | 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 | (if (not testdat) (begin (debug:print 2 "ERROR: No test data found for test " test-id ", exiting") (exit 1)) (let* ((rundir (if testdat (db:test-get-rundir testdat) (current-directory))) ;; logfile)) (testfullname (if testdat (db:test-get-fullname testdat) "Gathering data ...")) (xterm (lambda () (if (directory-exists? rundir) (let* ((shell (if (get-environment-variable "SHELL") (conc "-e " (get-environment-variable "SHELL")) "")) (command (conc "cd " rundir |
︙ | ︙ | |||
489 490 491 492 493 494 495 | ;; Section to table (define (dcommon:section-matrix rawconfig sectionname varcolname valcolname #!key (title #f)) (let* ((curr-row-num 1) (key-vals (configf:section-vars rawconfig sectionname)) (section-matrix (iup:matrix #:alignment1 "ALEFT" | | | 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 | ;; Section to table (define (dcommon:section-matrix rawconfig sectionname varcolname valcolname #!key (title #f)) (let* ((curr-row-num 1) (key-vals (configf:section-vars rawconfig sectionname)) (section-matrix (iup:matrix #:alignment1 "ALEFT" ;; #:expand "YES" ;; "HORIZONTAL" #:numcol 1 #:numlin (length key-vals) #:numcol-visible 1 #:numlin-visible (min 10 (length key-vals)) #:scrollbar "YES"))) (iup:attribute-set! section-matrix "0:0" varcolname) (iup:attribute-set! section-matrix "0:1" valcolname) |
︙ | ︙ | |||
707 708 709 710 711 712 713 | (define (dcommon:main-menu) (iup:menu ;; a menu is a special attribute to a dialog (think Gnome putting the menu at screen top) (iup:menu-item "Files" (iup:menu ;; Note that you can use either #:action or action: for options (iup:menu-item "Open" action: (lambda (obj) (let* ((area-name (iup:textbox #:expand "HORIZONTAL")) (fd (iup:file-dialog #:dialogtype "DIR")) (top (iup:show fd #:modal? "YES"))) | | | 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 | (define (dcommon:main-menu) (iup:menu ;; a menu is a special attribute to a dialog (think Gnome putting the menu at screen top) (iup:menu-item "Files" (iup:menu ;; Note that you can use either #:action or action: for options (iup:menu-item "Open" action: (lambda (obj) (let* ((area-name (iup:textbox #:expand "HORIZONTAL")) (fd (iup:file-dialog #:dialogtype "DIR")) (top (iup:show fd #:modal? "YES"))) (iup:attribute-set! area-name "VALUE" ;; was source-tb, no idea what is correct (iup:attribute fd "VALUE")) (iup:destroy! fd)))) ;; (lambda (obj) ;; (iup:show (iup:file-dialog)) ;; (print "File->open " obj))) (iup:menu-item "Save" #:action (lambda (obj)(print "File->save " obj))) (iup:menu-item "Exit" #:action (lambda (obj)(exit))))) |
︙ | ︙ | |||
931 932 933 934 935 936 937 | (let ((il (cddddr inlst))) (take il (- (length il) 2)))) (lambda (x y) (list (+ x 0) ;; xtorig) (+ y 0))) ;; ytorig))) #f #f)) ;; process polyline edges)))) | | | > > | | > > | 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 | (let ((il (cddddr inlst))) (take il (- (length il) 2)))) (lambda (x y) (list (+ x 0) ;; xtorig) (+ y 0))) ;; ytorig))) #f #f)) ;; process polyline edges)))) (cx (if no-dot ;; this is the centerpoint! curr-x (string->number (list-ref nodedat 2)))) (cy (if no-dot curr-y (string->number (list-ref nodedat 3)))) (boxw (if no-dot boxw (string->number (list-ref nodedat 4)))) (boxh (if no-dot boxh (string->number (list-ref nodedat 5)))) (boxw/2 (/ boxw 2)) (boxh/2 (/ boxh 2)) (urx (+ cx boxw/2)) (ury (+ cy boxh/2)) (llx (- cx boxw/2)) (lly (- cy boxh/2))) ;; if we are in no-dot mode then increment curr-x and curr-y as needed (if no-dot (begin (cond ((< curr-x (- scaled-sizex boxw boxw margin)) (set! curr-x (+ curr-x boxw margin))) |
︙ | ︙ | |||
1135 1136 1137 1138 1139 1140 1141 | ;; #:title "Target" ;; ;; Target selectors ;; (apply iup:hbox ;; (let* ((dat (dashboard:update-target-selector tabdat action-proc: update-keyvals)) ;; (key-lb (car dat)) ;; (combos (cadr dat))) ;; combos))) | | | | | | | | | | | | | | | | | | | > | 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 | ;; #:title "Target" ;; ;; Target selectors ;; (apply iup:hbox ;; (let* ((dat (dashboard:update-target-selector tabdat action-proc: update-keyvals)) ;; (key-lb (car dat)) ;; (combos (cadr dat))) ;; combos))) ;; (iup:hbox ;; ;; Text box for STATES ;; (iup:frame ;; #:title "States" ;; (dashboard:text-list-toggle-box ;; ;; Move these definitions to common and find the other useages and replace! ;; (map cadr *common:std-states*) ;; '("COMPLETED" "RUNNING" "STUCK" "INCOMPLETE" "LAUNCHED" "REMOTEHOSTSTART" "KILLED") ;; (lambda (all) ;; (dboard:tabdat-states-set! tabdat all) ;; (dashboard:update-run-command tabdat)))) ;; ;; Text box for STATES ;; (iup:frame ;; #:title "Statuses" ;; (dashboard:text-list-toggle-box ;; (map cadr *common:std-statuses*) ;; '("PASS" "FAIL" "n/a" "CHECK" "WAIVED" "SKIP" "DELETED" "STUCK/DEAD") ;; (lambda (all) ;; (dboard:tabdat-statuses-set! tabdat all) ;; (dashboard:update-run-command tabdat))))) )) (define (dcommon:command-tests-tasks-canvas tabdat test-records sorted-testnames tests-draw-state) (iup:frame #:title "Tests and Tasks" (let* ((updater #f) (last-xadj 0) (last-yadj 0) |
︙ | ︙ | |||
1183 1184 1185 1186 1187 1188 1189 | (hash-table-set! tests-draw-state 'scalef (+ scalef (if (> step 0) (* scalef 0.01) (* scalef -0.01)))) (if the-cnv (dashboard:draw-tests the-cnv last-xadj last-yadj tests-draw-state sorted-testnames test-records)) )) | | | 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 | (hash-table-set! tests-draw-state 'scalef (+ scalef (if (> step 0) (* scalef 0.01) (* scalef -0.01)))) (if the-cnv (dashboard:draw-tests the-cnv last-xadj last-yadj tests-draw-state sorted-testnames test-records)) )) ;; #:size "250x250" #:expand "YES" #:scrollbar "YES" #:posx "0.5" #:posy "0.5" #:button-cb (lambda (obj btn pressed x y status) ;; (print "obj: " obj ", pressed " pressed ", status " status) ; (print "canvas-origin: " (canvas-origin the-cnv)) |
︙ | ︙ | |||
1240 1241 1242 1243 1244 1245 1246 | (hash-table-keys tests-info))))))) canvas-obj))) ;;====================================================================== ;; S T E P S ;;====================================================================== | | | | > > > > > > > > > > | > | > > > > > > > > | > > > | | 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 | (hash-table-keys tests-info))))))) canvas-obj))) ;;====================================================================== ;; S T E P S ;;====================================================================== (define (dcommon:populate-steps teststeps steps-matrix run-id test-id) (let* ((max-row 0) (max-col 9) (white "255 255 255") (testinfo (rmt:get-testinfo-state-status run-id test-id)) (state (db:test-get-state testinfo)) (status (db:test-get-status testinfo)) (test-status-color (car (gutils:get-color-for-state-status state status))) (running-color (car (gutils:get-color-for-state-status "RUNNING" "STARTED"))) (failcolor (car (gutils:get-color-for-state-status "COMPLETED" "FAIL")))) (if (null? teststeps) (begin (iup:attribute-set! steps-matrix "CLEARATTRIB" "CONTENTS") (iup:attribute-set! steps-matrix "CLEARVALUE" "CONTENTS")) (let loop ((hed (car teststeps)) (tal (cdr teststeps)) (rownum 1) (colnum 1)) (if (> rownum max-row)(set! max-row rownum)) (let* ((status (vector-ref hed 3)) (val (vector-ref hed (- colnum 1))) (bgcolor (cond ((member (conc status) '("" "-" "#<unspecified>")) running-color) ((member (conc status) '("0" 0)) white) (else test-status-color))) ; (else failcolor))) (mtrx-rc (conc rownum ":" colnum))) ;;(print "BB> status=>"status"< bgcolor="bgcolor) (iup:attribute-set! steps-matrix mtrx-rc (if val (conc val) "")) (if (< colnum 5) (iup:attribute-set! steps-matrix (conc "BGCOLOR" mtrx-rc) bgcolor)) (if (< colnum max-col) (loop hed tal rownum (+ colnum 1)) (if (not (null? tal)) (loop (car tal) (cdr tal) (+ rownum 1) 1)))))) (if (> max-row 0) (begin ;; we are going to speculatively clear rows until we find a row that is already cleared (let loop ((rownum (+ max-row 1)) (colnum 0) (deleted #f)) ;; (debug:print-info 0 *default-log-port* "cleaning " rownum ":" colnum) |
︙ | ︙ | |||
1288 1289 1290 1291 1292 1293 1294 1295 | ;;====================================================================== (define (dcommon:run-html-viewer lfilename) (let ((htmlviewercmd (configf:lookup *configdat* "setup" "htmlviewercmd"))) (if htmlviewercmd (system (conc "(" htmlviewercmd " " lfilename " ) &")) (iup:send-url lfilename)))) | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 | ;;====================================================================== (define (dcommon:run-html-viewer lfilename) (let ((htmlviewercmd (configf:lookup *configdat* "setup" "htmlviewercmd"))) (if htmlviewercmd (system (conc "(" htmlviewercmd " " lfilename " ) &")) (iup:send-url lfilename)))) (define (dashboard:monitor-changed? commondat tabdat) (let* ((run-update-time (current-seconds)) (monitor-db-path (dboard:tabdat-monitor-db-path tabdat)) (monitor-modtime (if (and monitor-db-path (common:file-exists? monitor-db-path)) (file-modification-time monitor-db-path) -1))) (if (and (eq? (dboard:commondat-curr-tab-num commondat) 0) (or (> monitor-modtime *last-monitor-update-time*) (> (- run-update-time *last-monitor-update-time*) 5))) ;; update every 1/2 minute just in case (begin (set! *last-monitor-update-time* run-update-time) ;; monitor-modtime) #t) #f))) ;; DOES NOT WORK RELIABLY WITH /tmp WAL mode files. Timestamps only change when the db ;; is closed (I think). If db dir starts with /tmp always return true ;; (define (dashboard:database-changed? commondat tabdat #!key (context-key 'default)) (let* ((run-update-time (current-seconds)) (dbdir (dboard:tabdat-dbdir tabdat)) (modtime (dashboard:get-youngest-run-db-mod-time dbdir)) (recalc (dashboard:recalc modtime (dboard:commondat-please-update commondat) (dboard:get-last-db-update tabdat context-key)))) ;; (dboard:tabdat-last-db-update tabdat)))) (if recalc (dboard:set-last-db-update! tabdat context-key run-update-time)) (dboard:commondat-please-update-set! commondat #f) recalc)) (define (dashboard:get-youngest-run-db-mod-time dbdir) (handle-exceptions exn (begin (debug:print 2 *default-log-port* "WARNING: error in accessing databases in get-youngest-run-db-mod-time: " ((condition-property-accessor 'exn 'message) exn) " db-dir="dbdir) (current-seconds)) ;; something went wrong - just print an error and return current-seconds (common:max (map (lambda (filen) (file-modification-time filen)) (glob (conc dbdir "/*.db*")))))) (define (dboard:get-last-db-update tabdat context) (hash-table-ref/default (dboard:tabdat-last-db-update tabdat) context 0)) (define (dboard:set-last-db-update! tabdat context newtime) (hash-table-set! (dboard:tabdat-last-db-update tabdat) context newtime)) ;; point inside line ;; (define-inline (dashboard:px-between px lx1 lx2) (and (< lx1 px)(> lx2 px))) (define (dashboard:recalc modtime please-update-buttons last-db-update-time) (or please-update-buttons (and ;; (> (current-milliseconds)(+ *last-recalc-ended-time* 150)) ;; can't use this - it needs to be tab specific (> modtime (- last-db-update-time 3)) ;; add three seconds of margin (> (current-seconds)(+ last-db-update-time 1))))) |
Deleted defunct/multi-dboard.scm version [de11d53f46].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted defunct/nmsg-transport.scm version [b30844cb1a].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Modified diff-report.scm from [44fb509d7c] to [722e4fdcd5].
1 2 3 4 5 6 7 | (declare (unit diff-report)) (declare (uses common)) (declare (uses rmt)) (include "common_records.scm") (use matchable) | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | ;; Copyright 2006-2017, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. ;; (declare (unit diff-report)) (declare (uses common)) (declare (uses rmt)) (include "common_records.scm") (use matchable) |
︙ | ︙ |
Modified docs/Makefile from [ef7610ee8e] to [c01320f2b0].
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | ASCPATH = $(shell which asciidoc) EXEPATH = $(shell readlink -f $(ASCPATH)) BINPATH = $(shell dirname $(EXEPATH)) DISPATH = $(shell dirname $(BINPATH)) api.html : api.txt asciidoc -b html5 -a icons -a iconsdir=$(DISPATH)/images/icons -a toc2 api.txt # all : html/megatest.html megatest.pdf html/megatest.html : megatest.lyx elyxer megatest.lyx html/megatest.html fossil add html/* megatest.pdf : megatest.lyx lyx -e pdf2 megatest.lyx | > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. # ASCPATH = $(shell which asciidoc) EXEPATH = $(shell readlink -f $(ASCPATH)) BINPATH = $(shell dirname $(EXEPATH)) DISPATH = $(shell dirname $(BINPATH)) api.html : api.txt asciidoc -b html5 -a icons -a iconsdir=$(DISPATH)/images/icons -a toc2 api.txt # all : html/megatest.html megatest.pdf html/megatest.html : megatest.lyx elyxer megatest.lyx html/megatest.html fossil add html/* megatest.pdf : megatest.lyx lyx -e pdf2 megatest.lyx pkts.pdf : pkts.dot dot -Tpdf pkts.dot -o pkts.pdf |
Deleted docs/api.html version [145585f8de].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Modified docs/api.txt from [22dea6c059] to [15375fdc79].
︙ | ︙ | |||
13 14 15 16 17 18 19 20 21 22 23 24 25 26 | [abstract] Example Abstract ---------------- The Megatest Web App aims to make as much of the power of the dashboard available to the web based user. :numbered: Common ------ This is an example endpoint. You will need to use your own cgi server to serve out your megatest runs. Endpoint: http://kiatoa.com/cgi-bin/megatest | > > > > > > > > > > > > > > > > > > > | 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | [abstract] Example Abstract ---------------- The Megatest Web App aims to make as much of the power of the dashboard available to the web based user. :numbered: // Copyright 2006-2017, Matthew Welland. // // This file is part of Megatest. // // Megatest is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Megatest is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Megatest. If not, see <http://www.gnu.org/licenses/>. Common ------ This is an example endpoint. You will need to use your own cgi server to serve out your megatest runs. Endpoint: http://kiatoa.com/cgi-bin/megatest |
︙ | ︙ |
Added docs/architecture-brainstorming.fig version [f1561db291].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 | #FIG 3.2 Produced by xfig version 3.2.5-alpha5 Landscape Center Inches Letter 100.00 Single -2 # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. 1200 2 6 1425 2475 2925 4050 1 2 0 1 0 7 50 -1 -1 0.000 1 0.0000 2175 2812 750 263 1425 3075 2925 2550 1 2 0 1 0 7 50 -1 -1 0.000 1 0.0000 2175 3713 750 263 1425 3976 2925 3451 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2 1425 2850 1425 3750 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2 2925 2850 2925 3750 -6 6 8775 2625 10275 4200 1 2 0 1 0 7 50 -1 -1 0.000 1 0.0000 9525 2962 750 263 8775 3225 10275 2700 1 2 0 1 0 7 50 -1 -1 0.000 1 0.0000 9525 3863 750 263 8775 4126 10275 3601 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2 8775 3000 8775 3900 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2 10275 3000 10275 3900 -6 6 450 750 1950 2325 1 2 0 1 0 7 50 -1 -1 0.000 1 0.0000 1200 1087 750 263 450 1350 1950 825 1 2 0 1 0 7 50 -1 -1 0.000 1 0.0000 1200 1988 750 263 450 2251 1950 1726 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2 450 1125 450 2025 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2 1950 1125 1950 2025 -6 6 11775 5100 13275 6675 1 2 0 1 0 7 50 -1 -1 0.000 1 0.0000 12525 5437 750 263 11775 5700 13275 5175 1 2 0 1 0 7 50 -1 -1 0.000 1 0.0000 12525 6338 750 263 11775 6601 13275 6076 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2 11775 5475 11775 6375 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2 13275 5475 13275 6375 -6 6 225 4950 11250 9225 6 4125 6300 5625 7875 1 2 0 1 0 7 50 -1 -1 0.000 1 0.0000 4875 6637 750 263 4125 6900 5625 6375 1 2 0 1 0 7 50 -1 -1 0.000 1 0.0000 4875 7538 750 263 4125 7801 5625 7276 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2 4125 6675 4125 7575 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2 5625 6675 5625 7575 -6 6 9000 5700 10500 7275 1 2 0 1 0 7 50 -1 -1 0.000 1 0.0000 9750 6037 750 263 9000 6300 10500 5775 1 2 0 1 0 7 50 -1 -1 0.000 1 0.0000 9750 6938 750 263 9000 7201 10500 6676 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2 9000 6075 9000 6975 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2 10500 6075 10500 6975 -6 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 1 2 0 0 1.00 60.00 120.00 0 0 1.00 60.00 120.00 5850 7050 8775 6375 2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5 225 4950 11250 4950 11250 9225 225 9225 225 4950 4 0 0 50 -1 0 12 0.0000 4 150 780 9300 5325 IDEA #1\001 4 0 0 50 -1 0 12 0.0000 4 195 2160 3975 8100 megatest.db in main area\001 4 0 0 50 -1 0 12 0.0000 4 195 2400 8625 7350 megatest.db in satellite area\001 4 0 0 50 -1 0 12 0.0000 4 195 1740 8850 7650 (compatible targets)\001 4 0 0 50 -1 0 12 0.0000 4 150 765 3900 8775 NEEDS:\001 4 0 0 50 -1 0 12 0.0000 4 195 5565 3900 9030 enhancements to dashboard to make viewing mulitple areas easy\001 -6 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2 0 0 1.00 60.00 120.00 2925 3225 8700 3300 2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5 14700 4950 16500 4950 16500 6900 14700 6900 14700 4950 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2 0 0 1.00 60.00 120.00 13275 5925 14700 5925 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2 0 0 1.00 60.00 120.00 16500 6000 17625 6000 2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5 17625 4050 20250 4050 20250 7875 17625 7875 17625 4050 2 4 0 1 0 7 50 -1 -1 0.000 0 0 7 0 0 5 14325 5850 14325 4950 13575 4950 13575 5850 14325 5850 2 4 0 1 0 7 50 -1 -1 0.000 0 0 7 0 0 5 17550 5925 17550 5025 16575 5025 16575 5925 17550 5925 2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5 225 300 11250 300 11250 4725 225 4725 225 300 4 0 0 50 -1 0 12 0.0000 4 195 1440 1275 4425 tmp megatest.db\001 4 0 0 50 -1 0 12 0.0000 4 195 1065 8775 4500 megatest.db\001 4 0 0 50 -1 0 12 0.0000 4 150 1065 750 2475 ref database\001 4 0 0 50 -1 0 12 0.0000 4 150 510 9300 825 NOW\001 4 0 0 50 -1 0 12 0.0000 4 150 210 12300 7050 db\001 4 0 0 50 -1 0 12 0.0000 4 150 525 15150 7125 cache\001 4 0 0 50 -1 0 12 0.0000 4 195 600 18225 8100 display\001 4 0 0 50 -1 0 12 0.0000 4 150 390 13650 5250 filter\001 4 0 0 50 -1 0 12 0.0000 4 150 255 13650 5505 via\001 4 0 0 50 -1 0 12 0.0000 4 195 240 13650 5760 sql\001 4 0 0 50 -1 0 12 0.0000 4 150 315 16725 5325 2nd\001 4 0 0 50 -1 0 12 0.0000 4 150 390 16725 5580 filter\001 |
Deleted docs/html/dashboard-test.png version [c539143ccf].
cannot compute difference between binary files
Deleted docs/html/dashboard.png version [12ba87e86e].
cannot compute difference between binary files
Deleted docs/html/megatest.html version [d407d07366].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted docs/html/monitor-state-diagram.png version [83e4cb1ce3].
cannot compute difference between binary files
Modified docs/inprogress/graph-draw-arch.fig from [c5d001fa40] to [a0a2272d3b].
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | #FIG 3.2 Produced by xfig version 3.2.5-alpha5 Landscape Center Inches Letter 100.00 Single -2 1200 2 6 5700 3075 8400 3675 2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5 5700 3075 8400 3075 8400 3675 5700 3675 5700 3075 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 9 5700 3525 5925 3525 5925 3225 6750 3225 6750 3450 7350 3450 7350 3600 8325 3600 8250 3525 -6 | > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | #FIG 3.2 Produced by xfig version 3.2.5-alpha5 Landscape Center Inches Letter 100.00 Single -2 1200 2 # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. 6 5700 3075 8400 3675 2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5 5700 3075 8400 3075 8400 3675 5700 3675 5700 3075 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 9 5700 3525 5925 3525 5925 3225 6750 3225 6750 3450 7350 3450 7350 3600 8325 3600 8250 3525 -6 |
︙ | ︙ |
Modified docs/inprogress/megatest-architecture-2.fig from [a394cb2a13] to [fd464801e4].
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | #FIG 3.2 Produced by xfig version 3.2.5-alpha5 Landscape Center Inches Letter 100.00 Single -2 1200 2 2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5 750 975 5850 975 5850 7425 750 7425 750 975 2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5 6000 975 9975 975 9975 7425 6000 7425 6000 975 2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5 900 1500 5250 1500 5250 2475 900 2475 900 1500 2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5 | > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | #FIG 3.2 Produced by xfig version 3.2.5-alpha5 Landscape Center Inches Letter 100.00 Single -2 1200 2 # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. 2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5 750 975 5850 975 5850 7425 750 7425 750 975 2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5 6000 975 9975 975 9975 7425 6000 7425 6000 975 2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5 900 1500 5250 1500 5250 2475 900 2475 900 1500 2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5 |
︙ | ︙ |
Modified docs/inprogress/megatest-architecture-proposed-2.fig from [677a65230c] to [c8840a4e86].
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | #FIG 3.2 Produced by xfig version 3.2.5-alpha5 Landscape Center Inches Letter 100.00 Single -2 1200 2 6 600 1350 1575 2400 1 1 0 1 0 7 50 -1 -1 0.000 1 0.0000 1125 1500 450 150 1125 1500 1575 1650 1 1 0 1 0 7 50 -1 -1 0.000 1 0.0000 1124 2177 450 150 1124 2177 1574 2327 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2 675 1575 675 2175 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2 1575 1500 1575 2175 | > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | #FIG 3.2 Produced by xfig version 3.2.5-alpha5 Landscape Center Inches Letter 100.00 Single -2 1200 2 # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. 6 600 1350 1575 2400 1 1 0 1 0 7 50 -1 -1 0.000 1 0.0000 1125 1500 450 150 1125 1500 1575 1650 1 1 0 1 0 7 50 -1 -1 0.000 1 0.0000 1124 2177 450 150 1124 2177 1574 2327 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2 675 1575 675 2175 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2 1575 1500 1575 2175 |
︙ | ︙ |
Modified docs/inprogress/megatest-architecture-proposed.fig from [9938b93bd4] to [cfa9d9869b].
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | #FIG 3.2 Produced by xfig version 3.2.5-alpha5 Landscape Center Inches Letter 100.00 Single -2 1200 2 6 600 1350 1575 2400 1 1 0 1 0 7 50 -1 -1 0.000 1 0.0000 1125 1500 450 150 1125 1500 1575 1650 1 1 0 1 0 7 50 -1 -1 0.000 1 0.0000 1124 2177 450 150 1124 2177 1574 2327 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2 675 1575 675 2175 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2 1575 1500 1575 2175 | > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | #FIG 3.2 Produced by xfig version 3.2.5-alpha5 Landscape Center Inches Letter 100.00 Single -2 1200 2 # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. 6 600 1350 1575 2400 1 1 0 1 0 7 50 -1 -1 0.000 1 0.0000 1125 1500 450 150 1125 1500 1575 1650 1 1 0 1 0 7 50 -1 -1 0.000 1 0.0000 1124 2177 450 150 1124 2177 1574 2327 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2 675 1575 675 2175 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2 1575 1500 1575 2175 |
︙ | ︙ |
Modified docs/inprogress/megatest-architecture.fig from [e8481e20cc] to [d962310bf3].
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | #FIG 3.2 Produced by xfig version 3.2.5-alpha5 Landscape Center Inches Letter 100.00 Single -2 1200 2 6 600 1350 1575 2400 1 1 0 1 0 7 50 -1 -1 0.000 1 0.0000 1125 1500 450 150 1125 1500 1575 1650 1 1 0 1 0 7 50 -1 -1 0.000 1 0.0000 1124 2177 450 150 1124 2177 1574 2327 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2 675 1575 675 2175 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2 1575 1500 1575 2175 | > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | #FIG 3.2 Produced by xfig version 3.2.5-alpha5 Landscape Center Inches Letter 100.00 Single -2 1200 2 # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. 6 600 1350 1575 2400 1 1 0 1 0 7 50 -1 -1 0.000 1 0.0000 1125 1500 450 150 1125 1500 1575 1650 1 1 0 1 0 7 50 -1 -1 0.000 1 0.0000 1124 2177 450 150 1124 2177 1574 2327 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2 675 1575 675 2175 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2 1575 1500 1575 2175 |
︙ | ︙ |
Modified docs/inprogress/megatest-query-view.fig from [b760721f42] to [03a6b9aff3].
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | #FIG 3.2 Produced by xfig version 3.2.5-alpha5 Landscape Center Inches Letter 100.00 Single -2 1200 2 2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5 900 675 4350 675 4350 1650 900 1650 900 675 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2 0 0 1.00 60.00 120.00 4350 1200 6975 1725 2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5 6975 1350 10725 1350 10725 3075 6975 3075 6975 1350 | > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | #FIG 3.2 Produced by xfig version 3.2.5-alpha5 Landscape Center Inches Letter 100.00 Single -2 1200 2 # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. 2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5 900 675 4350 675 4350 1650 900 1650 900 675 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2 0 0 1.00 60.00 120.00 4350 1200 6975 1725 2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5 6975 1350 10725 1350 10725 3075 6975 3075 6975 1350 |
︙ | ︙ |
Modified docs/inprogress/megatest_qa.fig from [b36c055ff1] to [da89516b7b].
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | #FIG 3.2 Produced by xfig version 3.2.5-alpha5 Landscape Center Inches Letter 100.00 Single -2 1200 2 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2 6000 300 6000 9675 2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5 525 675 4500 675 4500 2550 525 2550 525 675 2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5 900 1125 2325 1125 2325 1575 900 1575 900 1125 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2 | > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | #FIG 3.2 Produced by xfig version 3.2.5-alpha5 Landscape Center Inches Letter 100.00 Single -2 1200 2 # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2 6000 300 6000 9675 2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5 525 675 4500 675 4500 2550 525 2550 525 675 2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5 900 1125 2325 1125 2325 1575 900 1575 900 1125 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2 |
︙ | ︙ |
Modified docs/manual/Makefile from [bf9f3b126b] to [ec9633c3d9].
|
| > | > > > > > > > > > > > > > > > > | | | > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 | # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # ASCPATH = $(shell which asciidoc) EXEPATH = $(shell readlink -f $(ASCPATH)) BINPATH = $(shell dirname $(EXEPATH)) DISPATH = $(shell dirname $(BINPATH)) SRCFSL = $(shell fossil info | grep repository: | awk '{print $$2}') INPAGES = plan.in howto.in reference.in getting_started.in # broad_goals.csv needed_features.csv : tables/*.dat # ./refdb2csv tables # in a makefile recipe, $< denotes the first dependency; $@ the target # design_spec.html : $(SRCFILES) $(CSVFILES) # asciidoc -b html5 -a icons -a iconsdir=$(DISPATH)/images/icons -a toc2 design_spec.txt # all : server.ps megatest_manual.html client.ps complex-itemmap.png megatest_manual.pdf megatest_manual.html : megatest_manual.txt *.txt installation.txt *png asciidoc -b html5 -a icons -a iconsdir=$(DISPATH)/images/icons -a toc2 megatest_manual.txt # dos2unix megatest_manual.html megatest_manual.pdf : megatest_manual.txt *.txt *png a2x -a toc -f pdf megatest_manual.txt server.ps : server.dot dot -Tps server.dot > server.ps client.ps : client.dot dot -Tps client.dot > client.ps complex-itemmap.png : complex-itemmap.dot dot -Tpng complex-itemmap.dot -o complex-itemmap.png dot -Tpdf complex-itemmap.dot -o complex-itemmap.pdf %.in : $(SRCFSL) fossil wiki export $* $*.in # %.txt : %.in # cp $*.in $*.txt clean: rm -f megatest_manual.html |
Modified docs/manual/client.dot from [23d472e170] to [b320e4ba8c].
1 2 3 4 5 6 7 | digraph G { // put client after server so server_start node is visible // subgraph cluster_2 { node [style=filled,shape=box]; | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | // Copyright 2006-2017, Matthew Welland. // // This file is part of Megatest. // // Megatest is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Megatest is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Megatest. If not, see <http://www.gnu.org/licenses/>. digraph G { // put client after server so server_start node is visible // subgraph cluster_2 { node [style=filled,shape=box]; |
︙ | ︙ |
Modified docs/manual/complex-itemmap.dot from [1ce1e37196] to [3864d8bfd9].
1 2 3 4 5 6 7 | digraph G { // put client after server so server_start node is visible // subgraph cluster_1 { node [style=filled,shape=box]; | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | // Copyright 2006-2017, Matthew Welland. // // This file is part of Megatest. // // Megatest is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Megatest is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Megatest. If not, see <http://www.gnu.org/licenses/>. digraph G { // put client after server so server_start node is visible // subgraph cluster_1 { node [style=filled,shape=box]; |
︙ | ︙ | |||
36 37 38 39 40 41 42 | subgraph cluster_6 { node [style=filled]; label = "Test E"; "C/1/bb" -> "E/1/res"; "C/2/bb" -> "E/2/res"; } | | | 53 54 55 56 57 58 59 60 61 62 63 64 | subgraph cluster_6 { node [style=filled]; label = "Test E"; "C/1/bb" -> "E/1/res"; "C/2/bb" -> "E/2/res"; } label = "Complex Itemmapping (arrows indicate order of execution)"; color=green; } } |
Modified docs/manual/complex-itemmap.png from [d2bdff7bfb] to [69224f5aa7].
cannot compute difference between binary files
Added docs/manual/devnotes.txt version [e6b6b73f5f].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | Developer Notes --------------- Collected here are some topics that may interest the megatest developer. telemetry ~~~~~~~~~ A new feature introduced in v1.6525 allows a centralized debug messaging system. Debugging client-server issues is greatly aided by a centralized, time coherent log of events across test execution, server, and runner. This is provided by the telemetry feature source code call example [source,ini] [telemetry] host <IP where telemetry daemon will run> port <UDP port to listen -- we recommend 5929> want-events <comma separated list of telemetry-log keywords [source,ini] [telemetry] host 10.38.32.91 port 5929 want-events ALL [source,scheme] (common:telemetry-log <keyword string> Usage: 1. Add telemetry section to megatest.config 2. Start telemetry daemon telemetry-daemon -a start -l /tmp/my-telemetry.log 3. Run megatest 4. examine / parse telemetry log |
Modified docs/manual/getting_started.txt from [de12299551] to [5c6821a0c5].
1 2 3 4 | Getting Started --------------- | > > > > > > > > > > > > > > > > | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | // This file is part of Megatest. // // Megatest is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Megatest is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Megatest. If not, see <http://www.gnu.org/licenses/>. // // Copyright 2006-2012, Matthew Welland. Getting Started --------------- // [partintro] .Getting started with Megatest ------------------- Creating a testsuite or flow and your first test or task. ------------------- After installing Megatest you can create a flow or testsuite and add some tests using the helpers. Here is a quickstart sequence to get you up and running your first automated testsuite. Creating a Megatest Area ~~~~~~~~~~~~~~~~~~~~~~~~ |
︙ | ︙ |
Modified docs/manual/howto.txt from [b7c69b99ac] to [5266978039].
1 2 3 4 5 6 7 | How To Do Things ---------------- Process Runs ~~~~~~~~~~~~ | > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | // This file is part of Megatest. // // Megatest is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Megatest is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Megatest. If not, see <http://www.gnu.org/licenses/>. // // Copyright 2006-2012, Matthew Welland. How To Do Things ---------------- Process Runs ~~~~~~~~~~~~ |
︙ | ︙ | |||
50 51 52 53 54 55 56 57 58 59 60 61 62 63 | ---------------- Hint: You can browse the archive using bup commands directly. ---------------- bup -d /path/to/bup/archive ftp ---------------- Submit jobs to Host Types based on Test Name ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .In megatest.config ------------------------ [host-types] | > > > > > > > > > > > > > > > > > | 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 | ---------------- Hint: You can browse the archive using bup commands directly. ---------------- bup -d /path/to/bup/archive ftp ---------------- Pass Data from Test to Test ~~~~~~~~~~~~~~~~~~~~~~~~~~~ .To save the data call archive save within your test: ---------------- megatest -archive save ---------------- .To retrieve the data call archive get using patterns as needed ---------------- # Put the retrieved data into /tmp DESTPATH=/tmp/$USER/$MT_TARGET/$MT_RUN_NAME/$MT_TESTNAME/$MT_ITEMPATH/my_data mkdir -p $DESTPATH megatest -archive get -runname % -dest $DESTPATH ---------------- Submit jobs to Host Types based on Test Name ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .In megatest.config ------------------------ [host-types] |
︙ | ︙ |
Modified docs/manual/installation.txt from [6d6c5f2d2a] to [73f4fcba67].
1 2 3 4 5 6 7 8 9 10 | Installation ------------ Dependencies ~~~~~~~~~~~~ Chicken scheme and a number of "eggs" are required for building Megatest. See the script installall.sh in the utils directory of the source distribution for an automated way to install everything needed for building Megatest on Linux. | > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | // Copyright 2006-2017, Matthew Welland. // // This file is part of Megatest. // // Megatest is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Megatest is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Megatest. If not, see <http://www.gnu.org/licenses/>. Installation ------------ Dependencies ~~~~~~~~~~~~ Chicken scheme and a number of "eggs" are required for building Megatest. See the script installall.sh in the utils directory of the source distribution for an automated way to install everything needed for building Megatest on Linux. |
Modified docs/manual/itemmap.fig from [3b4d1aa45b] to [04bee1e78d].
|
| | | 1 2 3 4 5 6 7 8 | #FIG 3.2 Produced by xfig version 3.2.5-alpha5 Landscape Center Metric A4 100.00 Single -2 |
︙ | ︙ | |||
36 37 38 39 40 41 42 43 44 45 46 47 48 49 | 0 58 #515151 0 59 #e7e3e7 0 60 #000049 0 61 #797979 0 62 #303430 0 63 #414141 0 64 #c7b696 6 3600 2700 4455 3555 2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5 3600 2700 4050 2700 4050 3150 3600 3150 3600 2700 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5 3690 3150 3690 3285 4185 3285 4185 2790 4050 2790 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5 3825 3285 3825 3420 4320 3420 4320 2925 4185 2925 | > > > > > > > > > > > > > > > > | 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 | 0 58 #515151 0 59 #e7e3e7 0 60 #000049 0 61 #797979 0 62 #303430 0 63 #414141 0 64 #c7b696 # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. 6 3600 2700 4455 3555 2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5 3600 2700 4050 2700 4050 3150 3600 3150 3600 2700 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5 3690 3150 3690 3285 4185 3285 4185 2790 4050 2790 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5 3825 3285 3825 3420 4320 3420 4320 2925 4185 2925 |
︙ | ︙ | |||
87 88 89 90 91 92 93 | 5490 4950 5490 5085 5985 5085 5985 4590 5850 4590 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5 5625 5085 5625 5220 6120 5220 6120 4725 5985 4725 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5 5760 5220 5760 5355 6255 5355 6255 4860 6120 4860 -6 6 6840 2790 8910 3420 | | | | | | | | | | | 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 | 5490 4950 5490 5085 5985 5085 5985 4590 5850 4590 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5 5625 5085 5625 5220 6120 5220 6120 4725 5985 4725 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5 5760 5220 5760 5355 6255 5355 6255 4860 6120 4860 -6 6 6840 2790 8910 3420 4 0 0 50 -1 0 12 0.0000 4 195 1290 6840 2970 [requirements]\001 4 0 0 50 -1 0 12 0.0000 4 150 1050 6840 3165 waiton TstE\001 4 0 0 50 -1 0 12 0.0000 4 195 1950 6840 3360 itemap foo/(\\d+) \\1/bar\001 -6 6 6840 6345 8910 6975 4 0 0 50 -1 0 12 0.0000 4 195 1290 6840 6525 [requirements]\001 4 0 0 50 -1 0 12 0.0000 4 150 1050 6840 6720 waiton TstE\001 4 0 0 50 -1 0 12 0.0000 4 195 1980 6840 6915 itemap baz/(\\d+) \\1/bar\001 -6 6 3600 6570 4860 7200 4 0 0 50 -1 0 12 0.0000 4 195 900 3600 6750 [itemmap]\001 4 0 0 50 -1 0 12 0.0000 4 180 1140 3600 6945 TstA .*/ foo/\001 4 0 0 50 -1 0 12 0.0000 4 195 1050 3600 7140 TstB ab/ xy/\001 -6 2 1 0 2 0 7 50 -1 -1 0.000 0 0 -1 1 0 2 0 0 1.00 60.00 120.00 5355 4455 4500 3600 2 1 0 2 0 7 50 -1 -1 0.000 0 0 -1 1 0 2 0 0 1.00 60.00 120.00 5400 1800 4500 2700 |
︙ | ︙ | |||
130 131 132 133 134 135 136 | 0 0 1.00 60.00 120.00 7065 2700 7065 2160 6390 1575 2 1 0 2 23 7 50 -1 -1 0.000 0 0 -1 1 0 3 0 0 1.00 60.00 120.00 7065 6255 7065 5715 6390 5130 2 2 0 2 7 7 50 -1 -1 0.000 0 0 -1 0 0 5 900 0 9000 0 9000 7425 900 7425 900 0 | | | | | | | | | | | | | | | 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 | 0 0 1.00 60.00 120.00 7065 2700 7065 2160 6390 1575 2 1 0 2 23 7 50 -1 -1 0.000 0 0 -1 1 0 3 0 0 1.00 60.00 120.00 7065 6255 7065 5715 6390 5130 2 2 0 2 7 7 50 -1 -1 0.000 0 0 -1 0 0 5 900 0 9000 0 9000 7425 900 7425 900 0 4 0 0 50 -1 0 12 0.0000 4 150 420 1935 4725 TstB\001 4 0 0 50 -1 0 12 0.0000 4 150 435 5445 1170 TstC\001 4 0 0 50 -1 0 12 0.0000 4 150 435 5445 4770 TstD\001 4 0 0 50 -1 0 12 0.0000 4 150 420 3600 2970 TstE\001 4 0 0 50 -1 0 12 0.0000 4 150 450 1845 1170 TstA\001 4 0 0 50 -1 0 12 0.0000 4 150 675 5085 450 runthird\001 4 0 0 50 -1 0 12 0.0000 4 150 900 3330 405 runsecond\001 4 0 0 50 -1 0 12 0.0000 4 150 615 1575 405 runfirst\001 4 0 0 50 -1 0 12 0.0000 4 150 1155 6750 1005 2. TstE starts\001 4 0 0 50 -1 0 12 0.0000 4 150 1770 6750 1215 3. TstC & TstD start\001 4 0 0 50 -1 0 12 0.0000 4 150 1770 6750 810 1. TstA & TstB start\001 4 0 0 50 -1 0 12 0.0000 4 195 1290 3600 6165 [requirements]\001 4 0 0 50 -1 0 12 0.0000 4 150 1545 3600 6360 waiton TstA TstB\001 |
Added docs/manual/megatest-stand-alone-area.png version [b4666b70f8].
cannot compute difference between binary files
Added docs/manual/megatest-system-architecture.png version [d1d2f4a2b8].
cannot compute difference between binary files
Added docs/manual/megatest-system-architecture.svg version [1f9c743227].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985 2986 2987 2988 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005 3006 3007 3008 3009 3010 3011 3012 3013 3014 3015 3016 3017 3018 3019 3020 3021 3022 3023 3024 3025 3026 3027 3028 3029 3030 3031 3032 3033 3034 3035 3036 3037 3038 3039 3040 3041 3042 3043 3044 3045 3046 3047 3048 3049 3050 3051 3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066 3067 3068 3069 3070 3071 3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090 3091 3092 3093 3094 3095 3096 3097 3098 3099 3100 3101 3102 3103 3104 3105 3106 3107 3108 3109 3110 3111 3112 3113 3114 3115 3116 3117 3118 3119 3120 3121 3122 3123 3124 3125 3126 3127 3128 3129 3130 3131 3132 3133 3134 3135 3136 3137 3138 3139 3140 3141 3142 3143 3144 3145 3146 3147 3148 3149 3150 3151 3152 3153 3154 3155 3156 3157 3158 3159 3160 3161 3162 3163 3164 3165 3166 3167 3168 3169 3170 3171 3172 3173 3174 3175 3176 3177 3178 3179 3180 3181 3182 3183 3184 3185 3186 3187 3188 3189 3190 3191 3192 3193 3194 3195 3196 3197 3198 3199 3200 3201 3202 3203 3204 3205 3206 3207 3208 3209 3210 3211 3212 3213 3214 3215 3216 3217 3218 3219 3220 3221 3222 3223 3224 3225 3226 3227 3228 3229 3230 3231 3232 3233 3234 3235 3236 3237 3238 3239 3240 3241 3242 3243 3244 3245 3246 3247 3248 3249 3250 3251 3252 3253 3254 3255 3256 3257 3258 3259 3260 3261 3262 3263 3264 3265 3266 3267 3268 3269 3270 3271 3272 3273 3274 3275 3276 3277 3278 3279 3280 3281 3282 3283 3284 3285 3286 3287 3288 3289 3290 3291 3292 3293 3294 3295 3296 3297 3298 3299 3300 3301 3302 3303 3304 3305 3306 3307 3308 3309 3310 3311 3312 3313 3314 3315 3316 3317 3318 3319 3320 3321 3322 3323 3324 3325 3326 3327 3328 3329 3330 3331 3332 3333 3334 3335 3336 3337 3338 3339 3340 3341 3342 3343 3344 3345 3346 3347 3348 3349 3350 3351 3352 3353 3354 3355 3356 3357 3358 3359 3360 3361 3362 3363 3364 3365 3366 3367 3368 3369 3370 3371 3372 3373 3374 3375 3376 3377 3378 3379 3380 3381 3382 3383 3384 3385 3386 3387 3388 3389 3390 3391 3392 3393 3394 3395 3396 3397 3398 3399 3400 3401 3402 3403 3404 3405 3406 3407 3408 3409 3410 3411 3412 3413 3414 3415 3416 3417 3418 3419 3420 3421 3422 3423 3424 3425 3426 3427 3428 3429 3430 3431 3432 3433 3434 3435 3436 3437 3438 3439 3440 3441 3442 3443 3444 3445 3446 3447 3448 3449 3450 3451 3452 3453 3454 3455 3456 3457 3458 3459 3460 3461 3462 3463 3464 3465 3466 3467 3468 3469 3470 3471 3472 3473 3474 3475 3476 3477 3478 3479 3480 3481 3482 3483 3484 3485 3486 3487 3488 3489 3490 3491 3492 3493 3494 3495 3496 3497 3498 3499 3500 3501 3502 3503 3504 3505 3506 3507 3508 3509 3510 3511 3512 3513 3514 3515 3516 3517 3518 3519 3520 3521 3522 3523 3524 3525 3526 3527 3528 3529 3530 3531 3532 3533 3534 3535 3536 3537 3538 3539 3540 3541 3542 3543 3544 3545 3546 3547 3548 3549 3550 3551 3552 3553 3554 3555 3556 3557 3558 3559 3560 3561 3562 3563 3564 3565 3566 3567 3568 3569 3570 3571 3572 3573 3574 3575 3576 3577 3578 3579 3580 3581 3582 3583 3584 3585 3586 3587 3588 3589 3590 3591 3592 3593 3594 3595 3596 3597 3598 3599 3600 3601 3602 3603 3604 3605 3606 3607 3608 3609 3610 3611 3612 3613 3614 3615 3616 3617 3618 3619 3620 3621 3622 3623 3624 3625 3626 3627 3628 3629 3630 3631 3632 3633 3634 3635 3636 3637 3638 3639 3640 3641 3642 3643 3644 3645 3646 3647 3648 3649 3650 3651 3652 3653 3654 3655 3656 3657 3658 3659 3660 3661 3662 3663 3664 3665 3666 3667 3668 3669 3670 3671 3672 3673 3674 3675 3676 3677 3678 3679 3680 3681 3682 3683 3684 3685 3686 3687 3688 3689 3690 3691 3692 3693 3694 3695 3696 3697 3698 3699 3700 3701 3702 3703 3704 3705 3706 3707 3708 3709 3710 3711 3712 3713 3714 3715 3716 3717 3718 3719 3720 3721 3722 3723 3724 3725 3726 3727 3728 3729 3730 3731 3732 3733 3734 3735 3736 3737 3738 3739 3740 3741 3742 3743 3744 3745 3746 3747 3748 3749 3750 3751 3752 3753 3754 3755 3756 3757 3758 3759 3760 3761 3762 3763 3764 3765 3766 3767 3768 3769 3770 3771 3772 3773 3774 3775 3776 3777 3778 3779 3780 3781 3782 3783 3784 3785 3786 3787 3788 3789 3790 3791 3792 3793 3794 3795 3796 3797 3798 3799 3800 3801 3802 3803 3804 3805 3806 3807 3808 3809 3810 3811 3812 3813 3814 3815 3816 3817 3818 3819 3820 3821 3822 3823 3824 3825 3826 3827 3828 3829 3830 3831 3832 3833 3834 3835 3836 3837 3838 3839 3840 3841 3842 3843 3844 3845 3846 3847 3848 3849 3850 3851 3852 3853 3854 3855 3856 3857 3858 3859 3860 3861 3862 3863 3864 3865 3866 3867 3868 3869 3870 3871 3872 3873 3874 3875 3876 3877 3878 3879 3880 3881 3882 3883 3884 3885 3886 3887 3888 3889 3890 3891 3892 3893 3894 3895 3896 3897 3898 3899 3900 3901 3902 3903 3904 3905 3906 3907 3908 3909 3910 3911 3912 3913 3914 3915 3916 3917 3918 3919 3920 3921 3922 3923 3924 3925 3926 3927 3928 3929 3930 3931 3932 3933 3934 3935 3936 3937 3938 3939 3940 3941 3942 3943 3944 3945 3946 3947 3948 3949 3950 3951 3952 3953 3954 3955 3956 3957 3958 3959 3960 3961 3962 3963 3964 3965 3966 3967 3968 3969 3970 3971 3972 3973 3974 3975 3976 3977 3978 3979 3980 3981 3982 3983 3984 3985 3986 3987 3988 3989 3990 3991 3992 3993 3994 3995 3996 3997 3998 3999 4000 4001 4002 4003 4004 4005 4006 4007 4008 4009 4010 4011 4012 4013 4014 4015 4016 4017 4018 4019 4020 4021 4022 4023 4024 4025 4026 4027 4028 4029 4030 4031 4032 4033 4034 4035 4036 4037 4038 4039 4040 4041 4042 4043 4044 4045 4046 4047 4048 4049 4050 4051 4052 4053 4054 4055 4056 4057 4058 4059 4060 4061 4062 4063 4064 4065 4066 4067 4068 4069 4070 4071 4072 4073 4074 4075 4076 4077 4078 4079 4080 4081 4082 4083 4084 4085 4086 4087 4088 4089 4090 4091 4092 4093 4094 4095 4096 4097 4098 4099 4100 4101 4102 4103 4104 4105 4106 4107 4108 4109 4110 4111 4112 4113 4114 4115 4116 4117 4118 4119 4120 4121 4122 4123 4124 4125 4126 4127 4128 4129 4130 4131 4132 4133 4134 4135 4136 4137 4138 4139 4140 4141 4142 4143 4144 4145 4146 4147 4148 4149 4150 4151 4152 4153 4154 4155 4156 4157 4158 4159 4160 4161 4162 4163 4164 4165 4166 4167 4168 4169 4170 4171 4172 4173 4174 4175 4176 4177 4178 4179 4180 4181 4182 4183 4184 4185 4186 4187 4188 4189 4190 4191 4192 4193 4194 4195 4196 4197 4198 4199 4200 4201 4202 4203 4204 4205 4206 4207 4208 4209 4210 4211 4212 4213 4214 4215 4216 4217 4218 4219 4220 4221 4222 4223 4224 4225 4226 4227 4228 4229 4230 4231 4232 4233 4234 4235 4236 4237 4238 4239 4240 4241 4242 4243 4244 4245 4246 4247 4248 4249 4250 4251 4252 4253 4254 4255 4256 4257 4258 4259 4260 4261 4262 4263 4264 4265 4266 4267 4268 4269 4270 4271 4272 4273 4274 4275 4276 4277 4278 4279 4280 4281 4282 4283 4284 4285 4286 4287 4288 4289 4290 4291 4292 4293 4294 4295 4296 4297 4298 4299 4300 4301 4302 4303 4304 4305 4306 4307 4308 4309 4310 4311 4312 4313 4314 4315 4316 4317 4318 4319 4320 4321 4322 4323 4324 4325 4326 4327 4328 4329 4330 4331 4332 4333 4334 4335 4336 4337 4338 4339 4340 4341 4342 4343 4344 4345 4346 4347 4348 4349 4350 4351 4352 4353 4354 4355 4356 4357 4358 4359 4360 4361 4362 4363 4364 4365 4366 4367 4368 4369 4370 4371 4372 4373 4374 4375 4376 4377 4378 4379 4380 4381 4382 4383 4384 4385 4386 4387 4388 4389 4390 4391 4392 4393 4394 4395 4396 4397 4398 4399 4400 4401 4402 4403 4404 4405 4406 4407 4408 4409 4410 4411 4412 4413 4414 4415 4416 4417 4418 4419 4420 4421 4422 4423 4424 4425 4426 4427 4428 4429 4430 4431 4432 4433 4434 4435 4436 4437 4438 4439 4440 4441 4442 4443 4444 4445 4446 4447 4448 4449 4450 4451 4452 4453 4454 4455 4456 4457 4458 4459 4460 4461 4462 4463 4464 4465 4466 4467 4468 4469 4470 4471 4472 4473 4474 4475 4476 4477 4478 4479 4480 4481 4482 4483 4484 4485 4486 4487 4488 4489 4490 4491 4492 4493 4494 4495 4496 4497 4498 4499 4500 4501 4502 4503 4504 4505 4506 4507 4508 4509 4510 4511 4512 4513 4514 4515 4516 4517 4518 4519 4520 4521 4522 4523 4524 4525 4526 4527 4528 4529 4530 4531 4532 4533 4534 4535 4536 4537 4538 4539 4540 4541 4542 4543 4544 4545 4546 4547 4548 4549 4550 4551 4552 4553 4554 4555 4556 4557 4558 4559 4560 4561 4562 4563 4564 4565 4566 4567 4568 4569 4570 4571 4572 4573 4574 4575 4576 4577 4578 4579 4580 4581 4582 4583 4584 4585 4586 4587 4588 4589 4590 4591 4592 4593 4594 4595 4596 4597 4598 4599 4600 4601 4602 4603 4604 4605 4606 4607 4608 4609 4610 4611 4612 4613 4614 4615 4616 4617 4618 4619 4620 4621 4622 4623 4624 4625 4626 4627 4628 4629 4630 4631 4632 4633 4634 4635 4636 4637 4638 4639 4640 4641 4642 4643 4644 4645 4646 4647 4648 4649 4650 4651 4652 4653 4654 4655 4656 4657 4658 4659 4660 4661 4662 4663 4664 4665 4666 4667 4668 4669 4670 4671 4672 4673 4674 4675 4676 4677 4678 4679 4680 4681 4682 4683 4684 4685 4686 4687 4688 4689 4690 4691 4692 4693 4694 4695 4696 4697 4698 4699 4700 4701 4702 4703 4704 4705 4706 4707 4708 4709 4710 4711 4712 4713 4714 4715 4716 4717 4718 4719 4720 4721 4722 4723 4724 4725 4726 4727 4728 4729 4730 4731 4732 4733 4734 4735 4736 4737 4738 4739 4740 4741 4742 4743 4744 4745 4746 4747 4748 4749 4750 4751 4752 4753 4754 4755 4756 4757 4758 4759 4760 4761 4762 4763 4764 4765 4766 4767 4768 4769 4770 4771 4772 4773 4774 4775 4776 4777 4778 4779 4780 4781 4782 4783 4784 4785 4786 4787 4788 4789 4790 4791 4792 4793 4794 4795 4796 4797 4798 4799 4800 4801 4802 4803 4804 4805 4806 4807 4808 4809 4810 4811 4812 4813 4814 4815 4816 4817 4818 4819 4820 4821 4822 4823 4824 4825 4826 4827 4828 4829 4830 4831 4832 4833 4834 4835 4836 4837 4838 4839 4840 4841 4842 4843 4844 4845 4846 4847 4848 4849 4850 4851 4852 4853 4854 4855 4856 4857 4858 4859 4860 4861 4862 4863 4864 4865 4866 4867 4868 4869 4870 4871 4872 4873 4874 4875 4876 4877 4878 4879 4880 4881 4882 4883 4884 4885 4886 4887 4888 4889 4890 4891 4892 4893 4894 4895 4896 4897 4898 4899 4900 4901 4902 4903 4904 4905 4906 4907 4908 4909 4910 4911 4912 4913 4914 4915 4916 4917 4918 4919 4920 4921 4922 4923 4924 4925 4926 4927 4928 4929 4930 4931 4932 4933 4934 4935 4936 4937 4938 4939 4940 4941 4942 4943 4944 4945 4946 4947 4948 4949 4950 4951 4952 4953 4954 4955 4956 4957 4958 4959 4960 4961 4962 4963 4964 4965 4966 4967 4968 4969 4970 4971 4972 4973 4974 4975 4976 4977 4978 4979 4980 4981 4982 4983 4984 4985 4986 4987 4988 4989 4990 4991 4992 4993 4994 4995 4996 4997 4998 4999 5000 5001 5002 5003 5004 5005 5006 5007 5008 5009 5010 5011 5012 5013 5014 5015 5016 5017 5018 5019 5020 5021 5022 5023 5024 5025 5026 5027 5028 5029 5030 5031 5032 5033 5034 5035 5036 5037 5038 5039 5040 5041 5042 5043 5044 5045 5046 5047 5048 5049 5050 5051 5052 5053 5054 5055 5056 5057 5058 5059 5060 5061 5062 5063 5064 5065 5066 5067 5068 5069 5070 5071 5072 5073 5074 5075 5076 5077 5078 5079 5080 5081 5082 5083 5084 5085 5086 5087 5088 5089 5090 5091 5092 5093 5094 5095 5096 5097 5098 5099 5100 5101 5102 5103 5104 5105 5106 5107 5108 5109 5110 5111 5112 5113 5114 5115 5116 5117 5118 5119 5120 5121 5122 5123 5124 5125 5126 5127 5128 5129 5130 5131 5132 5133 5134 5135 5136 5137 5138 5139 5140 5141 5142 5143 5144 5145 5146 5147 5148 5149 5150 5151 5152 5153 5154 5155 5156 5157 5158 5159 5160 5161 5162 5163 5164 5165 5166 5167 5168 5169 5170 5171 5172 5173 5174 5175 5176 5177 5178 5179 5180 5181 5182 5183 5184 5185 5186 5187 5188 5189 5190 5191 5192 5193 5194 5195 5196 5197 5198 5199 5200 5201 5202 5203 5204 5205 5206 5207 5208 5209 5210 5211 5212 5213 5214 5215 5216 5217 5218 5219 5220 5221 5222 5223 5224 5225 5226 5227 5228 5229 5230 5231 5232 5233 5234 5235 5236 5237 5238 5239 5240 5241 5242 5243 5244 5245 5246 5247 5248 5249 5250 5251 5252 5253 5254 5255 5256 5257 5258 5259 5260 5261 5262 5263 5264 5265 5266 5267 5268 5269 5270 5271 5272 5273 5274 5275 5276 5277 5278 5279 5280 5281 5282 5283 5284 5285 5286 5287 5288 5289 5290 5291 5292 5293 5294 5295 5296 5297 5298 5299 5300 5301 5302 5303 5304 5305 5306 5307 5308 5309 5310 5311 5312 5313 5314 5315 5316 5317 5318 5319 5320 5321 5322 5323 5324 5325 5326 5327 5328 5329 5330 5331 5332 5333 5334 5335 5336 5337 5338 5339 5340 5341 5342 5343 5344 5345 5346 5347 5348 5349 5350 5351 5352 5353 5354 5355 5356 5357 5358 5359 5360 5361 5362 5363 5364 5365 5366 5367 5368 5369 5370 5371 5372 5373 5374 5375 5376 5377 5378 5379 5380 5381 5382 5383 5384 5385 5386 5387 5388 5389 5390 5391 5392 5393 5394 5395 5396 5397 5398 5399 5400 5401 5402 5403 5404 5405 5406 5407 5408 5409 5410 5411 5412 5413 5414 5415 5416 5417 5418 5419 5420 5421 5422 5423 5424 5425 5426 5427 5428 5429 5430 5431 5432 5433 5434 5435 5436 5437 5438 5439 5440 5441 5442 5443 5444 5445 5446 5447 5448 5449 5450 5451 5452 5453 5454 5455 5456 5457 5458 5459 5460 5461 5462 5463 5464 5465 5466 5467 5468 5469 5470 5471 5472 5473 5474 5475 5476 5477 5478 5479 5480 5481 5482 5483 5484 5485 5486 5487 5488 5489 5490 5491 5492 5493 5494 5495 5496 5497 5498 5499 5500 5501 5502 5503 5504 5505 5506 5507 5508 5509 5510 5511 5512 5513 5514 5515 5516 5517 5518 5519 5520 5521 5522 5523 5524 5525 5526 5527 5528 5529 5530 5531 5532 5533 5534 5535 5536 5537 5538 5539 5540 5541 5542 5543 5544 5545 5546 5547 5548 5549 5550 5551 5552 5553 5554 5555 5556 5557 5558 5559 5560 5561 5562 5563 5564 5565 5566 5567 5568 5569 5570 5571 5572 5573 5574 5575 5576 5577 5578 5579 5580 5581 5582 5583 5584 5585 5586 5587 5588 5589 5590 5591 5592 5593 5594 5595 5596 5597 5598 5599 5600 5601 5602 5603 5604 5605 5606 5607 5608 5609 5610 5611 5612 5613 5614 5615 5616 5617 5618 5619 5620 5621 5622 5623 5624 5625 5626 5627 5628 5629 5630 5631 5632 5633 5634 5635 5636 5637 5638 5639 5640 5641 5642 5643 5644 5645 5646 5647 5648 5649 5650 5651 5652 5653 5654 5655 5656 5657 5658 5659 5660 5661 5662 | <?xml version="1.0" encoding="UTF-8" standalone="no"?> <!-- Created with Inkscape (http://www.inkscape.org/) --> <svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" width="210mm" height="297mm" viewBox="0 0 744.09448819 1052.3622047" id="svg2" version="1.1" inkscape:version="0.91 r13725" sodipodi:docname="megatest-system-architecture.svg" inkscape:export-filename="Z:\src\megatest\docs\manual\megatest-system-architecture.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90"> <defs id="defs4"> <marker inkscape:stockid="Arrow1Lstart" orient="auto" refY="0.0" refX="0.0" id="marker16686" style="overflow:visible" inkscape:isstock="true"> <path id="path16688" d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z " style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1" transform="scale(0.8) translate(12.5,0)" /> </marker> <marker inkscape:isstock="true" style="overflow:visible" id="marker16520" refX="0.0" refY="0.0" orient="auto" inkscape:stockid="Arrow1Lstart" inkscape:collect="always"> <path transform="scale(0.8) translate(12.5,0)" style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1" d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z " id="path16522" /> </marker> <marker inkscape:stockid="Arrow2Lstart" orient="auto" refY="0.0" refX="0.0" id="Arrow2Lstart" style="overflow:visible" inkscape:isstock="true"> <path id="path4946" style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1" d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z " transform="scale(1.1) translate(1,0)" /> </marker> <marker inkscape:stockid="Arrow1Lstart" orient="auto" refY="0.0" refX="0.0" id="Arrow1Lstart" style="overflow:visible" inkscape:isstock="true" inkscape:collect="always"> <path id="path4928" d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z " style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1" transform="scale(0.8) translate(12.5,0)" /> </marker> <marker inkscape:stockid="Arrow2Lend" orient="auto" refY="0.0" refX="0.0" id="marker5302" style="overflow:visible;" inkscape:isstock="true"> <path id="path5304" style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1" d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z " transform="scale(1.1) rotate(180) translate(1,0)" /> </marker> <marker inkscape:stockid="Arrow2Lend" orient="auto" refY="0.0" refX="0.0" id="marker5274" style="overflow:visible;" inkscape:isstock="true"> <path id="path5276" style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1" d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z " transform="scale(1.1) rotate(180) translate(1,0)" /> </marker> <marker inkscape:stockid="Arrow2Lend" orient="auto" refY="0.0" refX="0.0" id="Arrow2Lend" style="overflow:visible;" inkscape:isstock="true"> <path id="path4949" style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1" d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z " transform="scale(1.1) rotate(180) translate(1,0)" /> </marker> <inkscape:path-effect effect="vonkoch" id="path-effect4210" is_visible="true" ref_path="m 427.02546,366.74247 311.64896,0" generator="m 427.02546,561.12273 103.88298,0 m 103.88299,0 103.88299,0" similar_only="false" nbgenerations="1" drawall="true" maxComplexity="1000" /> <inkscape:path-effect effect="spiro" id="path-effect4208" is_visible="true" /> <inkscape:path-effect effect="knot" id="path-effect4206" is_visible="true" interruption_width="3" prop_to_stroke_width="true" add_stroke_width="true" add_other_stroke_width="true" switcher_size="15" crossing_points_vector="" /> <inkscape:path-effect effect="interpolate" id="path-effect4204" is_visible="true" trajectory="M 0,0 0,0" equidistant_spacing="true" steps="5" /> <inkscape:path-effect effect="gears" id="path-effect4202" is_visible="true" teeth="10" phi="5" /> <marker inkscape:stockid="Arrow2Lend" orient="auto" refY="0" refX="0" id="marker5302-0" style="overflow:visible" inkscape:isstock="true"> <path inkscape:connector-curvature="0" id="path5304-2" style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1" d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> </marker> <marker inkscape:stockid="Arrow2Lend" orient="auto" refY="0" refX="0" id="marker5302-0-9" style="overflow:visible" inkscape:isstock="true"> <path inkscape:connector-curvature="0" id="path5304-2-2" style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1" d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> </marker> <marker inkscape:stockid="Arrow2Lend" orient="auto" refY="0" refX="0" id="marker5302-0-9-7" style="overflow:visible" inkscape:isstock="true"> <path inkscape:connector-curvature="0" id="path5304-2-2-6" style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1" d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> </marker> <marker inkscape:stockid="Arrow2Lend" orient="auto" refY="0" refX="0" id="marker5302-0-9-7-7" style="overflow:visible" inkscape:isstock="true"> <path inkscape:connector-curvature="0" id="path5304-2-2-6-7" style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1" d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> </marker> <marker inkscape:stockid="Arrow2Lend" orient="auto" refY="0" refX="0" id="marker5302-0-9-7-7-1" style="overflow:visible" inkscape:isstock="true"> <path inkscape:connector-curvature="0" id="path5304-2-2-6-7-7" style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1" d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> </marker> <marker inkscape:stockid="Arrow2Lend" orient="auto" refY="0" refX="0" id="marker5274-8" style="overflow:visible" inkscape:isstock="true"> <path inkscape:connector-curvature="0" id="path5276-0" style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1" d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> </marker> <marker inkscape:stockid="Arrow2Lend" orient="auto" refY="0" refX="0" id="marker5274-8-6" style="overflow:visible" inkscape:isstock="true"> <path inkscape:connector-curvature="0" id="path5276-0-2" style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1" d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> </marker> <marker inkscape:stockid="Arrow2Lend" orient="auto" refY="0" refX="0" id="marker5274-8-6-7" style="overflow:visible" inkscape:isstock="true"> <path inkscape:connector-curvature="0" id="path5276-0-2-5" style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1" d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> </marker> <marker inkscape:stockid="Arrow2Lend" orient="auto" refY="0" refX="0" id="marker5274-8-6-7-5" style="overflow:visible" inkscape:isstock="true"> <path inkscape:connector-curvature="0" id="path5276-0-2-5-3" style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1" d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> </marker> <marker inkscape:stockid="Arrow2Lend" orient="auto" refY="0" refX="0" id="marker5302-0-9-7-7-6" style="overflow:visible" inkscape:isstock="true"> <path inkscape:connector-curvature="0" id="path5304-2-2-6-7-1" style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1" d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> </marker> <marker inkscape:stockid="Arrow2Lend" orient="auto" refY="0" refX="0" id="marker5302-0-9-7-7-6-8" style="overflow:visible" inkscape:isstock="true"> <path inkscape:connector-curvature="0" id="path5304-2-2-6-7-1-6" style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1" d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z" transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> </marker> </defs> <sodipodi:namedview id="base" pagecolor="#ffffff" bordercolor="#666666" borderopacity="1.0" inkscape:pageopacity="0.0" inkscape:pageshadow="2" inkscape:zoom="0.88269231" inkscape:cx="330.10992" inkscape:cy="527.65204" inkscape:document-units="px" inkscape:current-layer="layer1" showgrid="false" inkscape:window-width="1876" inkscape:window-height="1085" inkscape:window-x="3865" inkscape:window-y="33" inkscape:window-maximized="0" showguides="false"> <inkscape:grid type="xygrid" id="grid4462" /> </sodipodi:namedview> <metadata id="metadata7"> <rdf:RDF> <cc:Work rdf:about=""> <dc:format>image/svg+xml</dc:format> <dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> <dc:title></dc:title> </cc:Work> </rdf:RDF> </metadata> <g inkscape:label="Layer 1" inkscape:groupmode="layer" id="layer1"> <image y="187.43408" x="132.13397" id="image18538" xlink:href="data:image/png;base64,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 " style="image-rendering:optimizeSpeed" preserveAspectRatio="none" height="176.65359" width="322.573" /> <g transform="translate(12.122621,500.63961)" id="g4654-9"> <rect y="199.68129" x="68.74765" height="262.25259" width="282.35532" id="rect4359-0" style="fill:#fff6d5;fill-opacity:1;stroke:#ffe680;stroke-width:2.35244703;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> <g transform="translate(32.85403,-1.1328976)" id="g4558-5"> <rect style="fill:#ffb380;fill-opacity:1;stroke:#aa4400;stroke-width:1.75937951;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" id="rect4388-0" width="134.52634" height="57.383476" x="164.16541" y="270.81332" /> <flowRoot transform="translate(-350.93614,69.363122)" xml:space="preserve" id="flowRoot4230-6-5-8" style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"><flowRegion id="flowRegion4232-8-3-0"><rect id="rect4234-36-7-2" width="188.57143" height="34.285721" x="521.42859" y="205.21935" /></flowRegion><flowPara id="flowPara4236-0-5-3" style="font-size:22.5px">run control</flowPara></flowRoot> </g> <g transform="translate(32.85403,-1.1328976)" id="g4550-8"> <rect style="fill:#ddff55;fill-opacity:1;stroke:#88aa00;stroke-width:2.12757635;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" id="rect4414-12" width="134.15814" height="59.872425" x="164.34949" y="330.99744" /> <flowRoot transform="translate(-352.92371,125.9618)" xml:space="preserve" id="flowRoot4230-6-5-4-2" style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"><flowRegion id="flowRegion4232-8-3-5-9"><rect id="rect4234-36-7-3-4" width="168.57141" height="78.571434" x="521.42859" y="205.21935" /></flowRegion><flowPara id="flowPara4236-0-5-6-8" style="font-size:22.5px">storage</flowPara><flowPara style="font-size:22.5px" id="flowPara4456-57">allocation</flowPara></flowRoot> </g> <g style="fill:#ffcc00" transform="matrix(0.69892424,0,0,0.60590041,-67.539165,-184.64324)" id="g4510-3"> <g transform="translate(21.07191,-13.088427)" id="g4565-33"> <rect y="817.35736" x="220.84483" height="45.00967" width="84.160019" id="rect4494-61" style="fill:#ffcc00;fill-opacity:1;stroke:#88aa00;stroke-width:1.99030769;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> <path sodipodi:open="true" d="m 221.21854,816.24251 a 41.834236,18.546101 0 0 1 40.18978,-19.00419 41.834236,18.546101 0 0 1 43.40743,17.55829 41.834236,18.546101 0 0 1 -39.01506,19.47937 41.834236,18.546101 0 0 1 -44.46328,-17.03113" sodipodi:end="3.0620028" sodipodi:start="3.1161299" sodipodi:ry="18.546101" sodipodi:rx="41.834236" sodipodi:cy="815.77032" sodipodi:cx="263.03922" sodipodi:type="arc" id="path4458-0" style="fill:#ffcc00;fill-opacity:1;stroke:#88aa00;stroke-width:2.02593803;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> <path transform="scale(1,-1)" d="m 221.40372,-862.64317 a 41.834236,18.546101 0 0 1 20.45608,-16.4174 41.834236,18.546101 0 0 1 42.30602,-0.10995 41.834236,18.546101 0 0 1 20.88886,16.30994 l -41.83028,-0.25478 z" sodipodi:end="0.013738116" sodipodi:start="3.1161299" sodipodi:ry="18.546101" sodipodi:rx="41.834236" sodipodi:cy="-863.11536" sodipodi:cx="263.2244" sodipodi:type="arc" id="path4458-4-6" style="fill:#ffcc00;fill-opacity:1;stroke:#88aa00;stroke-width:2.02593803;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> <rect y="853.41882" x="222.65796" height="11.132897" width="81.339867" id="rect4496-8" style="fill:#ffcc00;fill-opacity:1;stroke:none;stroke-width:2;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> </g> </g> <flowRoot style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" id="flowRoot4230-6-7-3" xml:space="preserve" transform="translate(-444.3006,0.67342019)"><flowRegion id="flowRegion4232-8-9-7"><rect y="205.21935" x="521.42859" height="34.285721" width="188.57143" id="rect4234-36-4-96" /></flowRegion><flowPara style="font-size:22.5px" id="flowPara4236-0-4-93">area/testsuite</flowPara></flowRoot> <flowRoot transform="translate(-104.22658,-299.08497)" style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" id="flowRoot4540-7" xml:space="preserve"><flowRegion id="flowRegion4542-3"><rect y="649.05066" x="168.80174" height="39.651405" width="130.28322" id="rect4544-3" /></flowRegion><flowPara style="font-size:15px;text-align:center;text-anchor:middle" id="flowPara4546-2">state/status database</flowPara><flowPara id="flowPara4548-7" /></flowRoot> <rect y="399.81317" x="70.239655" height="61.176472" width="279.82571" id="rect4598-3" style="fill:#d3bc5f;fill-opacity:1;stroke:none;stroke-width:2;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> <flowRoot style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" id="flowRoot4230-6-7-1-0" xml:space="preserve" transform="translate(-440.9019,200.0634)"><flowRegion id="flowRegion4232-8-9-2-6"><rect y="205.21935" x="521.42859" height="52.412083" width="264.47556" id="rect4234-36-4-9-3" /></flowRegion><flowPara style="font-size:17.5px;text-align:center;text-anchor:middle" id="flowPara4236-0-4-9-0">configs and custom automation</flowPara></flowRoot> </g> <g transform="translate(-7.1366364,513.10148)" id="g4654-4"> <rect y="199.68129" x="68.74765" height="262.25259" width="282.35532" id="rect4359-8" style="fill:#fff6d5;fill-opacity:1;stroke:#ffe680;stroke-width:2.35244703;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> <g transform="translate(32.85403,-1.1328976)" id="g4558-9"> <rect style="fill:#ffb380;fill-opacity:1;stroke:#aa4400;stroke-width:1.75937951;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" id="rect4388-5" width="134.52634" height="57.383476" x="164.16541" y="270.81332" /> <flowRoot transform="translate(-350.93614,69.363122)" xml:space="preserve" id="flowRoot4230-6-5-0" style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"><flowRegion id="flowRegion4232-8-3-6"><rect id="rect4234-36-7-4" width="188.57143" height="34.285721" x="521.42859" y="205.21935" /></flowRegion><flowPara id="flowPara4236-0-5-66" style="font-size:22.5px">run control</flowPara></flowRoot> </g> <g transform="translate(32.85403,-1.1328976)" id="g4550-9"> <rect style="fill:#ddff55;fill-opacity:1;stroke:#88aa00;stroke-width:2.12757635;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" id="rect4414-1" width="134.15814" height="59.872425" x="164.34949" y="330.99744" /> <flowRoot transform="translate(-352.92371,125.9618)" xml:space="preserve" id="flowRoot4230-6-5-4-1" style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"><flowRegion id="flowRegion4232-8-3-5-2"><rect id="rect4234-36-7-3-6" width="168.57141" height="78.571434" x="521.42859" y="205.21935" /></flowRegion><flowPara id="flowPara4236-0-5-6-1" style="font-size:22.5px">storage</flowPara><flowPara style="font-size:22.5px" id="flowPara4456-5">allocation</flowPara></flowRoot> </g> <g style="fill:#ffcc00" transform="matrix(0.69892424,0,0,0.60590041,-67.539165,-184.64324)" id="g4510-57"> <g transform="translate(21.07191,-13.088427)" id="g4565-3"> <rect y="817.35736" x="220.84483" height="45.00967" width="84.160019" id="rect4494-6" style="fill:#ffcc00;fill-opacity:1;stroke:#88aa00;stroke-width:1.99030769;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> <path sodipodi:open="true" d="m 221.21854,816.24251 a 41.834236,18.546101 0 0 1 40.18978,-19.00419 41.834236,18.546101 0 0 1 43.40743,17.55829 41.834236,18.546101 0 0 1 -39.01506,19.47937 41.834236,18.546101 0 0 1 -44.46328,-17.03113" sodipodi:end="3.0620028" sodipodi:start="3.1161299" sodipodi:ry="18.546101" sodipodi:rx="41.834236" sodipodi:cy="815.77032" sodipodi:cx="263.03922" sodipodi:type="arc" id="path4458-46" style="fill:#ffcc00;fill-opacity:1;stroke:#88aa00;stroke-width:2.02593803;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> <path transform="scale(1,-1)" d="m 221.40372,-862.64317 a 41.834236,18.546101 0 0 1 20.45608,-16.4174 41.834236,18.546101 0 0 1 42.30602,-0.10995 41.834236,18.546101 0 0 1 20.88886,16.30994 l -41.83028,-0.25478 z" sodipodi:end="0.013738116" sodipodi:start="3.1161299" sodipodi:ry="18.546101" sodipodi:rx="41.834236" sodipodi:cy="-863.11536" sodipodi:cx="263.2244" sodipodi:type="arc" id="path4458-4-4" style="fill:#ffcc00;fill-opacity:1;stroke:#88aa00;stroke-width:2.02593803;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> <rect y="853.41882" x="222.65796" height="11.132897" width="81.339867" id="rect4496-9" style="fill:#ffcc00;fill-opacity:1;stroke:none;stroke-width:2;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> </g> </g> <flowRoot style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" id="flowRoot4230-6-7-2" xml:space="preserve" transform="translate(-444.3006,0.67342019)"><flowRegion id="flowRegion4232-8-9-0"><rect y="205.21935" x="521.42859" height="34.285721" width="188.57143" id="rect4234-36-4-5" /></flowRegion><flowPara style="font-size:22.5px" id="flowPara4236-0-4-8">area/testsuite</flowPara></flowRoot> <flowRoot transform="translate(-104.22658,-299.08497)" style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" id="flowRoot4540-2" xml:space="preserve"><flowRegion id="flowRegion4542-6"><rect y="649.05066" x="168.80174" height="39.651405" width="130.28322" id="rect4544-7" /></flowRegion><flowPara style="font-size:15px;text-align:center;text-anchor:middle" id="flowPara4546-0">state/status database</flowPara><flowPara id="flowPara4548-6" /></flowRoot> <rect y="399.81317" x="70.239655" height="61.176472" width="279.82571" id="rect4598-5" style="fill:#d3bc5f;fill-opacity:1;stroke:none;stroke-width:2;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> <flowRoot style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" id="flowRoot4230-6-7-1-2" xml:space="preserve" transform="translate(-440.9019,200.0634)"><flowRegion id="flowRegion4232-8-9-2-2"><rect y="205.21935" x="521.42859" height="52.412083" width="264.47556" id="rect4234-36-4-9-8" /></flowRegion><flowPara style="font-size:17.5px;text-align:center;text-anchor:middle" id="flowPara4236-0-4-9-3">configs and custom automation</flowPara></flowRoot> </g> <g id="g4190" transform="matrix(-0.84371534,0.01979065,-0.02351016,-1.0022856,1092.315,1172.4738)"> <path sodipodi:open="true" d="m 512.15263,288.64133 a 63.57143,12.857143 0 0 1 60.44617,-12.99805 63.57143,12.857143 0 0 1 66.45678,11.73666 63.57143,12.857143 0 0 1 -55.53716,13.86501 63.57143,12.857143 0 0 1 -70.55918,-10.71249" sodipodi:end="2.9816588" sodipodi:start="3.1294277" sodipodi:ry="12.857143" sodipodi:rx="63.57143" sodipodi:cy="288.48492" sodipodi:cx="575.71936" sodipodi:type="arc" id="path4136-0" style="fill:#99ff99;fill-opacity:1;stroke:#07ff00;stroke-width:2;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> <path style="fill:#99ff99;fill-opacity:1;stroke:#07ff00;stroke-width:2;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" id="path4178" sodipodi:type="arc" sodipodi:cx="575.71936" sodipodi:cy="294.60724" sodipodi:rx="63.57143" sodipodi:ry="12.857143" sodipodi:start="3.1294277" sodipodi:end="2.9816588" d="m 512.15263,294.76364 a 63.57143,12.857143 0 0 1 60.44617,-12.99805 63.57143,12.857143 0 0 1 66.45678,11.73666 63.57143,12.857143 0 0 1 -55.53716,13.86501 63.57143,12.857143 0 0 1 -70.55918,-10.71248" sodipodi:open="true" /> <path sodipodi:open="true" d="m 512.15263,300.88596 a 63.57143,12.857143 0 0 1 60.44617,-12.99805 63.57143,12.857143 0 0 1 66.45678,11.73666 63.57143,12.857143 0 0 1 -55.53716,13.865 63.57143,12.857143 0 0 1 -70.55918,-10.71248" sodipodi:end="2.9816588" sodipodi:start="3.1294277" sodipodi:ry="12.857143" sodipodi:rx="63.57143" sodipodi:cy="300.72955" sodipodi:cx="575.71936" sodipodi:type="arc" id="path4180" style="fill:#99ff99;fill-opacity:1;stroke:#07ff00;stroke-width:2;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> <path style="fill:#99ff99;fill-opacity:1;stroke:#07ff00;stroke-width:2;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" id="path4182" sodipodi:type="arc" sodipodi:cx="575.71936" sodipodi:cy="306.85187" sodipodi:rx="63.57143" sodipodi:ry="12.857143" sodipodi:start="3.1294277" sodipodi:end="2.9816588" d="m 512.15263,307.00827 a 63.57143,12.857143 0 0 1 60.44617,-12.99805 63.57143,12.857143 0 0 1 66.45678,11.73666 63.57143,12.857143 0 0 1 -55.53716,13.86501 63.57143,12.857143 0 0 1 -70.55918,-10.71248" sodipodi:open="true" /> <path sodipodi:open="true" d="m 512.15263,313.13058 a 63.57143,12.857143 0 0 1 60.44617,-12.99804 63.57143,12.857143 0 0 1 66.45678,11.73666 63.57143,12.857143 0 0 1 -55.53716,13.865 63.57143,12.857143 0 0 1 -70.55918,-10.71248" sodipodi:end="2.9816588" sodipodi:start="3.1294277" sodipodi:ry="12.857143" sodipodi:rx="63.57143" sodipodi:cy="312.97418" sodipodi:cx="575.71936" sodipodi:type="arc" id="path4184" style="fill:#99ff99;fill-opacity:1;stroke:#07ff00;stroke-width:2;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> <path style="fill:#99ff99;fill-opacity:1;stroke:#07ff00;stroke-width:2;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" id="path4186" sodipodi:type="arc" sodipodi:cx="575.71936" sodipodi:cy="319.0965" sodipodi:rx="63.57143" sodipodi:ry="12.857143" sodipodi:start="3.1294277" sodipodi:end="2.9816588" d="m 512.15263,319.2529 a 63.57143,12.857143 0 0 1 60.44617,-12.99805 63.57143,12.857143 0 0 1 66.45678,11.73666 63.57143,12.857143 0 0 1 -55.53716,13.86501 63.57143,12.857143 0 0 1 -70.55918,-10.71249" sodipodi:open="true" /> <path sodipodi:open="true" d="m 512.15263,325.37521 a 63.57143,12.857143 0 0 1 60.44617,-12.99804 63.57143,12.857143 0 0 1 66.45678,11.73666 63.57143,12.857143 0 0 1 -55.53716,13.865 63.57143,12.857143 0 0 1 -70.55918,-10.71248" sodipodi:end="2.9816588" sodipodi:start="3.1294277" sodipodi:ry="12.857143" sodipodi:rx="63.57143" sodipodi:cy="325.21881" sodipodi:cx="575.71936" sodipodi:type="arc" id="path4188" style="fill:#99ff99;fill-opacity:1;stroke:#07ff00;stroke-width:2;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> </g> <path style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" d="m 480.79052,694.68093 c -20.48995,16.02845 -49.92126,-2.22239 -61.48209,35.56138 -14.07962,50.51945 13.82501,65.4894 9.14417,107.80549 0.30581,43.82264 -8.10403,35.30357 13.87255,75.62963 11.76423,19.14732 41.85079,38.54184 50.91809,59.14205 25.79328,31.08882 46.46188,-3.14626 83.61295,-0.31378 32.17165,2.32694 31.03441,7.29979 63.48515,9.94718 26.05422,-13.75252 60.87578,-31.62469 63.68671,-61.1889 9.53867,-46.64667 -26.39163,-67.56952 -17.75811,-114.34909 3.31882,-37.73498 28.49078,-79.48402 2.32824,-109.58076 -24.95714,-19.25618 -45.71429,-7.14286 -62.21189,-38.53298 -30.06032,-27.22255 -65.38383,-15.84869 -72.95381,5.65785 -24.07053,43.07907 -44.28571,-11.42857 -72.64196,30.22193 z" id="path4199" inkscape:connector-curvature="0" sodipodi:nodetypes="ccccccccccccc" /> <flowRoot xml:space="preserve" id="flowRoot4230" style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" transform="translate(-24.923748,483.7473)"><flowRegion id="flowRegion4232"><rect id="rect4234" width="188.57143" height="34.285721" x="521.42859" y="205.21935" /></flowRegion><flowPara id="flowPara4236" style="font-size:22.5px"><flowSpan style="font-size:22.5px;line-height:124.00000095%" id="flowSpan4238">compute</flowSpan> cloud</flowPara></flowRoot> <flowRoot transform="translate(-6.809158,713.2426)" xml:space="preserve" id="flowRoot4230-5" style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"><flowRegion id="flowRegion4232-6"><rect id="rect4234-3" width="162.85713" height="72.857147" x="521.42859" y="205.21935" /></flowRegion><flowPara id="flowPara4236-7" style="font-size:22.5px">storage (NFS, moosefs etc.)</flowPara></flowRoot> <g id="g4306" transform="translate(-24.923748,483.7473)"> <rect y="237.82025" x="481.17233" height="43.369614" width="56.226757" id="rect4277" style="fill:#e9afaf;fill-opacity:1;stroke:#a02c2c;stroke-width:1.48752904;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> <flowRoot style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" id="flowRoot4230-2" xml:space="preserve" transform="translate(-33.313982,40.923874)"><flowRegion id="flowRegion4232-3"><rect y="205.21935" x="521.42859" height="32.857151" width="61.428555" id="rect4234-2" /></flowRegion><flowPara style="font-size:22.5px" id="flowPara4236-9">job</flowPara></flowRoot> </g> <g transform="translate(95.790536,522.31872)" id="g4306-3"> <rect y="237.82025" x="481.17233" height="43.369614" width="56.226757" id="rect4277-9" style="fill:#e9afaf;fill-opacity:1;stroke:#a02c2c;stroke-width:1.48752904;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> <flowRoot style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" id="flowRoot4230-2-2" xml:space="preserve" transform="translate(-33.313982,40.923874)"><flowRegion id="flowRegion4232-3-7"><rect y="205.21935" x="521.42859" height="32.857151" width="61.428555" id="rect4234-2-0" /></flowRegion><flowPara style="font-size:22.5px" id="flowPara4236-9-5">job</flowPara></flowRoot> </g> <g transform="translate(-25.638031,588.03302)" id="g4306-6"> <rect y="237.82025" x="481.17233" height="43.369614" width="56.226757" id="rect4277-6" style="fill:#e9afaf;fill-opacity:1;stroke:#a02c2c;stroke-width:1.48752904;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> <flowRoot style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" id="flowRoot4230-2-27" xml:space="preserve" transform="translate(-33.313982,40.923874)"><flowRegion id="flowRegion4232-3-2"><rect y="205.21935" x="521.42859" height="32.857151" width="61.428555" id="rect4234-2-09" /></flowRegion><flowPara style="font-size:22.5px" id="flowPara4236-9-4">job</flowPara></flowRoot> </g> <flowRoot transform="translate(-433.36378,162.68235)" xml:space="preserve" id="flowRoot4230-6" style="font-style:normal;font-weight:normal;font-size:15px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;"><flowRegion id="flowRegion4232-8"><rect id="rect4234-36" width="188.57143" height="34.285721" x="521.42859" y="205.21935" style="font-size:15px;" /></flowRegion><flowPara id="flowPara4236-0" style="font-size:15px;" /></flowRoot> <g id="g4654" transform="translate(-23.79085,525.66451)"> <rect y="199.68129" x="68.74765" height="262.25259" width="282.35532" id="rect4359" style="fill:#fff6d5;fill-opacity:1;stroke:#ffe680;stroke-width:2.35244703;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> <g transform="translate(32.85403,-1.1328976)" id="g4558"> <rect style="fill:#ffb380;fill-opacity:1;stroke:#aa4400;stroke-width:1.75937951;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" id="rect4388" width="134.52634" height="57.383476" x="164.16541" y="270.81332" /> <flowRoot transform="translate(-350.93614,69.363122)" xml:space="preserve" id="flowRoot4230-6-5" style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"><flowRegion id="flowRegion4232-8-3"><rect id="rect4234-36-7" width="188.57143" height="34.285721" x="521.42859" y="205.21935" /></flowRegion><flowPara id="flowPara4236-0-5" style="font-size:22.5px">run control</flowPara></flowRoot> </g> <g transform="translate(32.85403,-1.1328976)" id="g4550"> <rect style="fill:#ddff55;fill-opacity:1;stroke:#88aa00;stroke-width:2.12757635;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" id="rect4414" width="134.15814" height="59.872425" x="164.34949" y="330.99744" /> <flowRoot transform="translate(-352.92371,125.9618)" xml:space="preserve" id="flowRoot4230-6-5-4" style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"><flowRegion id="flowRegion4232-8-3-5"><rect id="rect4234-36-7-3" width="168.57141" height="78.571434" x="521.42859" y="205.21935" /></flowRegion><flowPara id="flowPara4236-0-5-6" style="font-size:22.5px">storage</flowPara><flowPara style="font-size:22.5px" id="flowPara4456">allocation</flowPara></flowRoot> </g> <g style="fill:#ffcc00" transform="matrix(0.69892424,0,0,0.60590041,-67.539165,-184.64324)" id="g4510"> <g transform="translate(21.07191,-13.088427)" id="g4565"> <rect y="817.35736" x="220.84483" height="45.00967" width="84.160019" id="rect4494" style="fill:#ffcc00;fill-opacity:1;stroke:#88aa00;stroke-width:1.99030769;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> <path sodipodi:open="true" d="m 221.21854,816.24251 a 41.834236,18.546101 0 0 1 40.18978,-19.00419 41.834236,18.546101 0 0 1 43.40743,17.55829 41.834236,18.546101 0 0 1 -39.01506,19.47937 41.834236,18.546101 0 0 1 -44.46328,-17.03113" sodipodi:end="3.0620028" sodipodi:start="3.1161299" sodipodi:ry="18.546101" sodipodi:rx="41.834236" sodipodi:cy="815.77032" sodipodi:cx="263.03922" sodipodi:type="arc" id="path4458" style="fill:#ffcc00;fill-opacity:1;stroke:#88aa00;stroke-width:2.02593803;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> <path transform="scale(1,-1)" d="m 221.40372,-862.64317 a 41.834236,18.546101 0 0 1 20.45608,-16.4174 41.834236,18.546101 0 0 1 42.30602,-0.10995 41.834236,18.546101 0 0 1 20.88886,16.30994 l -41.83028,-0.25478 z" sodipodi:end="0.013738116" sodipodi:start="3.1161299" sodipodi:ry="18.546101" sodipodi:rx="41.834236" sodipodi:cy="-863.11536" sodipodi:cx="263.2244" sodipodi:type="arc" id="path4458-4" style="fill:#ffcc00;fill-opacity:1;stroke:#88aa00;stroke-width:2.02593803;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> <rect y="853.41882" x="222.65796" height="11.132897" width="81.339867" id="rect4496" style="fill:#ffcc00;fill-opacity:1;stroke:none;stroke-width:2;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> </g> </g> <flowRoot style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" id="flowRoot4230-6-7" xml:space="preserve" transform="translate(-444.3006,0.67342019)"><flowRegion id="flowRegion4232-8-9"><rect y="205.21935" x="521.42859" height="34.285721" width="188.57143" id="rect4234-36-4" /></flowRegion><flowPara style="font-size:22.5px" id="flowPara4236-0-4">area/testsuite</flowPara></flowRoot> <flowRoot transform="translate(-104.22658,-299.08497)" style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" id="flowRoot4540" xml:space="preserve"><flowRegion id="flowRegion4542"><rect y="649.05066" x="168.80174" height="39.651405" width="130.28322" id="rect4544" /></flowRegion><flowPara style="font-size:15px;text-align:center;text-anchor:middle" id="flowPara4546">state/status database</flowPara><flowPara id="flowPara4548" /></flowRoot> <rect y="399.81317" x="70.239655" height="61.176472" width="279.82571" id="rect4598" style="fill:#d3bc5f;fill-opacity:1;stroke:none;stroke-width:2;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> <flowRoot style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" id="flowRoot4230-6-7-1" xml:space="preserve" transform="translate(-440.9019,200.0634)"><flowRegion id="flowRegion4232-8-9-2"><rect y="205.21935" x="521.42859" height="52.412083" width="264.47556" id="rect4234-36-4-9" /></flowRegion><flowPara style="font-size:17.5px;text-align:center;text-anchor:middle" id="flowPara4236-0-4-9">configs and custom automation</flowPara></flowRoot> </g> <g id="g4510-5" transform="matrix(0.9875096,0,0,0.89462735,317.68506,-291.88682)" style="fill:#ffcc00"> <g id="g4565-7" transform="translate(21.07191,-13.088427)"> <rect style="fill:#ffcc00;fill-opacity:1;stroke:#88aa00;stroke-width:1.99030769;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" id="rect4494-4" width="84.160019" height="45.00967" x="220.84483" y="817.35736" /> <path style="fill:#ffcc00;fill-opacity:1;stroke:#88aa00;stroke-width:2.02593803;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" id="path4458-8" sodipodi:type="arc" sodipodi:cx="263.03922" sodipodi:cy="815.77032" sodipodi:rx="41.834236" sodipodi:ry="18.546101" sodipodi:start="3.1161299" sodipodi:end="3.0620028" d="m 221.21854,816.24251 a 41.834236,18.546101 0 0 1 40.18978,-19.00419 41.834236,18.546101 0 0 1 43.40743,17.55829 41.834236,18.546101 0 0 1 -39.01506,19.47937 41.834236,18.546101 0 0 1 -44.46328,-17.03113" sodipodi:open="true" /> <path style="fill:#ffcc00;fill-opacity:1;stroke:#88aa00;stroke-width:2.02593803;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" id="path4458-4-7" sodipodi:type="arc" sodipodi:cx="263.2244" sodipodi:cy="-863.11536" sodipodi:rx="41.834236" sodipodi:ry="18.546101" sodipodi:start="3.1161299" sodipodi:end="0.013738116" d="m 221.40372,-862.64317 a 41.834236,18.546101 0 0 1 20.45608,-16.4174 41.834236,18.546101 0 0 1 42.30602,-0.10995 41.834236,18.546101 0 0 1 20.88886,16.30994 l -41.83028,-0.25478 z" transform="scale(1,-1)" /> <rect style="fill:#ffcc00;fill-opacity:1;stroke:none;stroke-width:2;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" id="rect4496-5" width="81.339867" height="11.132897" x="222.65796" y="853.41882" /> </g> </g> <path style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend)" d="m 274.16122,593.53868 26.05664,95.1634" id="path4922" inkscape:connector-type="polyline" inkscape:connector-curvature="0" /> <path style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#marker5302)" d="m 261.69935,595.80447 -2.2658,89.49892" id="path5270" inkscape:connector-type="polyline" inkscape:connector-curvature="0" /> <path style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#marker5274)" d="m 252.63617,598.07027 -49.80483,90.64802" id="path5272" inkscape:connector-type="polyline" inkscape:connector-curvature="0" /> <path style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#marker5302-0)" d="M 313.96906,821.51733 442.96295,751.01146" id="path5270-0" inkscape:connector-type="polyline" inkscape:connector-curvature="0" /> <path style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#marker5302-0-9)" d="M 313.81263,825.7827 570.98038,787.26418" id="path5270-0-9" inkscape:connector-type="polyline" inkscape:connector-curvature="0" /> <path style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#marker5302-0-9-7)" d="m 310.41394,830.31429 135.94771,18.12636" id="path5270-0-9-2" inkscape:connector-type="polyline" inkscape:connector-curvature="0" /> <path style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#marker5302-0-9-7-7)" d="M 334.20479,679.63889 561.91721,483.64761" id="path5270-0-9-2-0" inkscape:connector-type="polyline" inkscape:connector-curvature="0" /> <path style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#marker5302-0-9-7-7-1)" d="M 373.85621,692.10077 572.11329,491.57789" id="path5270-0-9-2-0-5" inkscape:connector-type="polyline" inkscape:connector-curvature="0" /> <flowRoot transform="translate(65.932827,283.73434)" xml:space="preserve" id="flowRoot4230-7" style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"><flowRegion id="flowRegion4232-4"><rect id="rect4234-68" width="151.18582" height="55.810787" x="521.42859" y="205.21935" /></flowRegion><flowPara id="flowPara4236-39" style="font-size:22.5px;text-align:center;text-anchor:middle">postgresql database</flowPara></flowRoot> <flowRoot transform="matrix(0.75559123,-0.65504344,0.65504344,0.75559123,-79.970125,770.0914)" xml:space="preserve" id="flowRoot4230-8" style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" inkscape:transform-center-y="-2.2099189" inkscape:transform-center-x="3.4352659"><flowRegion id="flowRegion4232-46"><rect id="rect4234-30" width="70.750061" height="33.152824" x="521.42859" y="205.21935" /></flowRegion><flowPara id="flowPara4236-6" style="font-size:15px">sync</flowPara></flowRoot> <path style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" d="m 467.3997,628.12966 0,0" id="path9031" inkscape:connector-type="polyline" inkscape:connector-curvature="0" /> <path style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#marker16686);marker-end:url(#marker5274-8)" d="M 125.75163,641.12037 113.28976,360.16178" id="path5272-7" inkscape:connector-type="polyline" inkscape:connector-curvature="0" /> <path style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#marker16520);marker-end:url(#marker5274-8-6)" d="M 87.233115,651.31645 100.82788,357.89598" id="path5272-7-4" inkscape:connector-type="polyline" inkscape:connector-curvature="0" /> <path style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#Arrow1Lstart);marker-end:url(#marker5274-8-6-7)" d="M 49.847495,676.2402 84.96732,356.76309" id="path5272-7-4-2" inkscape:connector-type="polyline" inkscape:connector-curvature="0" /> <g id="g12830" transform="translate(-133.68192,-662.74509)"> <image width="334.8475" height="196.18736" preserveAspectRatio="none" style="image-rendering:optimizeSpeed" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAyUAAAH+CAIAAAANkDYNAAAAA3NCSVQICAjb4U/gAAAgAElEQVR4 nOzdd3wcx50g+l9Vp8nAJOQZ5MhMgjmTEiVGBSpYsmzL66Rdh/Oe7+369u36rXf99j5v79761uuw sixbkm3JiqQYxEyKOQMgEhNyjpOAid1ddX80MARBMMkkAYj1/eAjTajqro78TXX1r9G0+asBAAAQ 5njJgBAwDMMwDPN5hwFG/5Of606aOa1I0ulvUc3hdJpNRqpGu1trtp3afbW/iwJQCgCAEABCGAPG gAAQQgBAKSWUUgoIAGGEMaKYUApAAWOMEXA8CCLo9IgXCMdTDMAhhDmOEiwrNBJWI2GiqkhVAQAR oJRQhAEhjDECoBSBSihGwPMIYUopRQghBISCNhdCASilAIAAYwQAGAPPA8cDz1O9AUkSCALwGHgM GAFQRAmlFDCHeB6rhKgqVVVOVVBMVqMxoihIViEapao6tESACAWgBBAGXsC8ABwHVOdV9J2qArKC KEFo2vzVCCG9NcWSnO3Kn4oQvj/blWEYhmEY5s+nRXe3h+L/GY+6A9HGLt+RsP64zPkpBR4hbE5y FS3aYLZngKC746kxDMMwDMM8UIpKQqEQUeTbF0XAizqDTqf1aT34ukaa40yaV9+Q06P+URW8vGiy Fsxfa3JmKxSorNx+QgzDMAzDMA+coqoDAwOBrgYU9WN8m8txKqHY5ExIcpuMRozxuNTlJIvNuTbU 0ue3vsebnS5dQrJKKSGsZ4thGIZhmImIUhoKhQLdTQaTOW1qqSTwty4fDEear1T6elr5tGydJI1X XUlvNhpnBMOHeYszA0smRSHXLxW52YQ0bJgXw0wyNzmoCVEH+1o50WC0pvx500SA4Mbht7efBiXB /jZKweTIGHliudnn95YSDQ32t+ssDp3Jep9mwTDMvaLIURry2POnEwrh2G2uyCHMW5zuvvrzarKb 0uvqhiK3vCyI0C3qhmMKJRQQGnV/ISUUEKAb6oqipNfnCh25PABQSumIYVuyLNdWXqI3H8ilKErR lAKT2XQHK4dhmPGnKjE60BWLDt74lSIr331u6ZXWvv3V3cbEpM88TYR5LJo4g40XpbuKugZ6W19a lQ8AfzxUZ3K4bvv5PURU2aj2f++lxduP1db5BkQ9O6cxzISGACGMeA7f4RU5juO0qIhSGq+rqqS7 qVbE6pjnKUVVsS7BnpYzZl1CaCwSjHhagdeZne74T0FVjkW8bYqimJKyOV4YWXf4zkg01C1G4VrT VUKA0mnTCqJjBY+CwNVfbVIUZWQVhmEmsoG+1h88Oy/XNTqcUhT13/+wpzA7zRMIKkr3XR3UI6dJ CR0IRarr2o9Vt/VF9Fgyjf7pd3NKLJyVagcAOVo5sgE3+/weIoQgNVqcnXbgTK1K2DmNYSY8LYgB ejcDoBAgRIGOqEtFpPzFk0vNRsONpZvbuz/8tJYMdTmNrqsSEuprfnnjwtbOvhOXuzmTE2NOVWJo sGvziqmhcGTLsSvWtNyRdbXUFwjBGP1bGGhRGj8jy9TW3j38MxXBcCINp92YoBr6Cb1FBxjDMBOK IBmr6jp6PH4AmJbvSnUkHi27HI7GVJWEIlGtTCw0MNDfiRAS9CZBMiIElBI5EoqFBxHCktHCCbqR QRRRFZNeQgCnq+oppQlmw/xpOfnupLd2l3dGMCfolFhEjoaIIiOOE/VmXtQjBKoix8IDaiwKCPGi TtSZ4ucRORYZ8HQCBUEyiAbzdZ/3dyKMJUMCL0iAgFJQ5Ug0NEBVhRNE0WDheAFAm/igKkcBKC/q JYMFYRwZ9CmxsM5ojUUGiKrqLXbMcdpyEVUx6VQAAAqUAjunMcxERikMdxrd0dE6MkwhhF6rqwVr FGquNo/qJ+N5nGg2UaBkxBfX1aVU0Jm7+vxzp+cjhI5Ud2K9VZC96xYVutOcR87VcqJ+ZF1KhyMs qsVbACNnKXJ0QZGwaVlGn0eMR1pxFlPCufP9Oy5DhI2vZ5hJQrI4D9T2qXJPJOj7xgYwGXSvf3xC EW2AgIuEAcBqMS4qduakO2OKWt3kaQkovM4E0UCuFRVPT4vJpLyhvzcs87oRV9woAEBXn//Vrad0 liSTDs3KbH/mkdnLprveP9aoqnKaUcnLTbSZdcGIXNXk6QjKnKiTFO/c3IRUW5KiktbegctdfqIo AGDQiaX5SQWZqRijq+2+i10e7VSp1wmz85zF2WnhmFJe7+mPKLxkUKKDdiEyY5otwSj1+MMVjd6Q akEImWhgRqYxzW7nMGrqDlS39UcJNztDzE51najtmDrFZtCJ+8vbYiDkOoSS6WlRWfEFBtHwqZTd M8QwE95dHq10uGuK0mt1KaUA/b6BbYcrdQkje/0pGezd/Oi8oXhurLqUAm9O2l/eoihK6bQ8gefP XmpbOS8vKz157/ELFS2DxsSUkXXJcOcUhbH6t4bywA6lbtV+zyKEr4VcN1ZhGGaC05ntANcumGFO MNpSAUDuGwCAqbkZmSl2nSRKIj8lp/+tPRUdgf6SVPGLa2abDDoAKHD3vbW3MiALHC9qU4hffeMl g8GaIivy2Yb+zJrGmYXubUdrqBJ5ftXCFEcChzHH4ZKcvt/vqezy9G1eXTJ/WjZGiFIIRaK7Tl7c 3nQVAFIciS9tWGSQREkU5gSC7+wrP9k1AACpjsSX1i8yGSSR5/Ndnb/fV+0PKcm66EtrprtTbFoD 8jPa3zl0yR+MbVqeN29KliQKGKOorHx0qHLfmSuFi+asnjfFkWgsyExp6/Hh83U5DvHldaVmgxRT VJUQjsMwdN5j5zSGmQRGdRLdoti118NHNwUg6tCNPrxkMNvTrpUhJBj1a4XVEdO/ri6hgDBnSjpS 00UpKZ2an+pMtCWaD56uvtAWkixJoy7+XQuWKOUBgBCqqCPuM9LuOUIII4wQolr/1rVOLkwBVEKU 293DyDDMREPI0GFLAVSVwHC+5F7vwDt7znb2Dy6dkfnkqjlOI25u71y+dqmsqH/afSrVkbB8bvEU t/XQJb9kGopy4ucUSqmiEkBcjEotnf2r5hZzQAZV7mxNk39gcDAcnVOctWpeSZK5ur3DNzUvvavP /9GBs8FQNCPF0R8kmBcBYCAU3nqwvLa5tyTT8dUnluanJR45HQKAQDDy/r5zDZ3eVbPzVs0vnpqZ uPv01c3r5qQ6Et7efaamoWv13ILlcwqn1nd+Wtle1+bp6vN29/udiebNj86dU5i+89OzACCJvE4S //fbB9u9UVWRX5idB0B/+cHhPn94/aLiZFsCaOc0lZ3TGGYSUFUSjd1B3lEAQimKn6OG68ZkRbuk SMj106E0/nksJo9ZN15exabTNa05rpTUJFvN1ebKJg/hrbHhJKYj6w7HW2P1b8XH0iOMEUJAKRqO vQDBtSH3bGwpw0w2I450Skb8ZLrc1FnREhSNtvOXWp95ZC7PISqHs9OdqY6EV55dBQAIoWSbUZF7 xfhPvWsvhs4hGIgk8jFFAcxFFbGj1/fI/OKcDGei2SCJgihgEExna5uWzy74ysalF660nL/Y0tCv cqIeAHo9A0eqOySbq+xq65dUVSfyWlaaPu/AmSu9YmLagfN1q+cXp9hMsZA/K9XmHwidvtSt6pwH zl5dNbco3WmmiGvo9D5amv3YomlOq9mgk/r9QUJUABgMR7d+Wtk8IHEmO/iacjOclxo7qtvDVDDt OVWzfE4hsD57hpkMtBiEUhr/6XgbFAAQAjR0j+FQ35WqBTCjpkMpue7zsepq5YkSM9DAuiVTrAnm K41tRbmuwVB0X1mLqrcjzI2a79CJBcXHb42Mt0AbSz90PZEiiq4bwTX8+EkWbzHMZHPdca69GRpb QCnCgDlZUQEADWd0qGvp3n+6JhqTEUKdPlnQm8gNQQmllBBVjYVtfGR20dTmzv6ois1c7Lk1SwSe +/TsRZ0kbFg2CwEigvnjoxcvNXbmZzhmFLpnFmb+aX/50bKu4RYhhHlFIdoPPg1CQ1f6OIy1znzt rAdo6ESG8FDWLznofezRRctm5Z2raTx4pnbDslnxwf2yojZ3ebE1lwIgBLx2AZEQBCieepBSuHHR GIaZOEYk+KOEkJCnHZGxe7kopVgy6SzO+DmPDg+oGgqrhj8kqnqtVrzw0KWAMeoSQihRjMS/cXFR dnrynuMVFfW9j8wJlU7L43lu99kmItm02EyrED+rYKTlg6DxU+/QLFVVJYSajQkjlnPo0Y0Ycaqq AkXA4i2GmXSuH1gAIzNl0RHfIgBBX9/Wm5VqCwyGrjR35bqSeY6nZOS5ggKAwHNGLooDTVnJiY8v mJaZ5vjgQFlA5p26WEay7dDZ2jPVDUtmF2pREY0GSqdleDzeQ2dqe7yBL21Ykptm/fRUeESL6Kg0 EvZE8/yCpIaOnpXzCiilnf2DgiGhob1v6az8JVPTy6+0r5pbQAjt6BsESlxJiYOh6MEztQ6rGeMR J+eRy8tJLV2ePFfyDHdLe69nyYw8zGHta/b0WIaZyCgAHurxAUIIpwSff2zumDkdOnr6tx+/TKgD w9DPR0rotbqUUkp5DksQVT0NI6ZPDQIAGhpTP3ZdQkigc8OaWZnpSQdOVZ2t94Pk2F/eSiiZOzU/ Jis7TjWICSnxuvGAazgfxHV3TQIFaOoJvvb21pstc1SWVXCxvneGmXRG/oAbdQgPnQeGU8CoguXA ubovry395rOrKIFwNLb9aNXlHp92+Q+Gx2/lupL+/W9e1CpFZeXg2UunrnqpYIwStbG9b+XcknlT c2VFpYSKPCeAPLfYleeaw3MYAA2EIo1dfk7QxSd441kl0Wx4ce08vSTyPK6u67jQ5JES045Xtxdm pjy/pvS5R0sBaFVde0WjVzI76tp68zOT/9vL64LhqFEvefyDghBPMQiUUoQQEcyHyupfeqz028+u iMRkWRnKeTjqNMgwzEQUz6FFCMaIu/mjDAmhlBCAoZ9w8ZPbUK4HSinA04/Ov3H6A4PhW9fFGKuE HjhVdabOR0ULAhTjE/acbeIwB1TrALu+LgAF4DDwQ9MYMTsZhEZUBGG4BQroVl8zDDMhcYL+YnPf YCiqcnrtGMaS5dDZS42dXk7QU4QGFW738apOv4wl06Ue5dfbTs/IcepEvrN/8EJLgJOM8XMFpzOf qGxoaO8BAEohGInVd/hq2wYVMQHxfEA2vnvgwszcpGBEbu0NlGQ6egZkqrd9dOTilMweu0UXialX 2701HWFdYuqJygaOw1gy0hHtkSxJJyobKq60tfUGctOsgWD0bF2vXzVgUdcRDL22/VxpQbLZIHZ7 Bs/X9w9Qo2A2H6joiMQUo8TXd/qSEg0YIZ3FMWp5KW+oaAnEdpwudttDUbmlJzAjN7nTLyMssGiL YSY4LUOV9vMoQnVvfnL+ZsEIEg2EUjz8Lb2h7lufrS6AItne2nUeiwbeYIV4RKWzfXT0MkIgmJNG 1dUKcBjQE9/7qS1/fjgcvSfrgmGYCU4ODxAlKprsw2MxSWygHws6QW8GAKIqsUGPoDdr/VhqLKJE g0AJ4kVeMmLuuge1xoJeosgAQ/fXcIKOk4zxzPJqLKxEgwhhLEhqNMRJBk40ECWmxkJElRHCnKjj JCMCFAt6gVLRZBvVnljQSwnhBEmNRRDH8ToT5gRt4kSJyZFBSlTMC4LOhDCvNV4JByhROVFPlBgF EI2JSiQ4cnkBAIAq0ZAaCwPCnCApkWB8eRmGmbgQEjnaX19myy0NRWJ3UoMqkUjXZWfB/Kisjk/d mAIAkUDvgOcX6Inv/dSWNz+eY5phGIZhGGYCEgUu6u8e9PXx5hTM87curMpRdaAnwZnGG+0xWRmv ugAQDfQGfb8YY/wWwzAMwzDMRBOTVSkhharKYN/V2z+kFaGEtEJOnxCTZUrHra5maPwWe3AYwzAM wzATHKU0Jit6u8vgcN1JeUJoNCYPDbEap7oajgPezvX4u+sVRb1FTYZhGIZhmIkgMtnqSsSfnBDl V0+3z1i8hBLlz2gDwzAMwzAMMxolaldT+fHLKm+1GIuzU4l6R0PuGYZhGIZhmDtEiSKGjCeuwE1z hTEMwzAMwzD3BIu3GIZhGIZh7iPK4i2GYRiGYZj7ilK4VdqultbW3p4+ALDZbdlZmc3NLenpaf5A QFXVJKfzQTWSYRiGYRhmEkNwy3jr57941efz2Wy2+fPmul0ZV+vqk5KTdu3aixD64ovPP7BWMgzD MAzDTGK37t/CGH/15S/PmTOLwxwANDU1l86ZTSgBCqqqnj1XdujQ4Zkzp69auVySpAfVZIZhGIZh mMmEArrV+C1FUf7/f/v3r3/jr373xlsqUY8cPR6LDaWNGBwc/PCjrXq9/uix461tbQ+ktQzDMAzD MJMPpehW/Vs8z7/yra9PnzZVFMVRX0VjsVOnz9ptVoPBwHLTMwzDMAzD3Awht7yeCADWxMSkJCcA xGR55OeSKK1etSIxMSEjPS01Jfk+tpFhGIZhGGYyI7fu33r6qSdc7gztNYfxN772cmJiwsL58wDA ZDJ++UsvnjtXJooSe9Y1wzAMwzDMzcgyuVW8NW/unPhrjuOWLl0MAPn5edonOdlZOdlZ97F1DMMw DMMwk19MpizfKcMwDMMwzH0kyyy/PMMwDMMwzP2ksHiLYRiGYRjmvqIj88tTSsNROSYr4z78HWOk l0RR4Ma5HQzDMAzDMH++kfnluz0D24/Wll/tjsnjmk8LgcUoLSpJf3RBYYJJP54tYRiGYRiG+bNd e151NKbsO3P1fHNEn1xs4AVA49gokGPhT2u7TIamNQuKMB7HpjAMwzAMw/z5hvNvRWJyU3vfFx9b KEmjU8k/eJTSgC/hzNlTJXYvJdH7MQuEsM6QmODMlvSW+zF9hmEYhmGYIfH+LR6UkoSupSWOCdKd 5PdG+2raJSlb1Nnvx/QppZGQr7etKjlzpiAa78csGIZhGIZhAACADsVbCFGLGEGAAIZHy4/LsHk0 FO5hRBN1is5g5PjbPHHoM+O4RH9va9DXlZiUe59mwTAMwzAMc238FgLACF8btkUJIcoDbw/CHA9D MR/FCAEllNyvwfsYIYSRHAvfp+kzDMMwDMNorvUeYYyBAoVxzAahPYlRawDFCFFKKSHj1x6GYRiG YZh7YDjeQnDjnYA+n99g0IuiCACqqnq9PrvdhhAaVSYhwRL/0Of36/V6VVEMBoP2SSgU5nkuFA4n JiTcQXsoDHeyITzU0QUACPP3alwZpZRSNf76Hk2VYRiGYRhmbAiNyC+PEB6Ob4ainJ/9/Jdv/f7t SCQCAJcvX/2bH/59X1//qEn8xy/+s6q6JhQKNze3KIpy8ODhs2fOvfHmHweDQQCIxeRt23fu3Xfg wIFPBwcH76xVNH49kVJCKaWUIgSA0L35Gwq5KKUUxrMzj2EYhmGYhwICjIdfoRv7twKBgeMnTnV1 dYdCoeMnTtbV11NKr16tu3q1LhaLHT16XFXVYDAYHAy++trrP/ibv2toaDQY9G63SyVqdXUtAHR0 dLS1dxQU5BuNBoRwKBQ6euzElq3b29rbL1260tTUrCjKlSt1hJCKC5WdnV0kfvWQUowRUDr0BzAw GDxXXj0wGNS+7+v3nj5XGY3GRja4vqGlvqHldktNr02WhVsMwzAMw9xnFOi1/i08FHtd6/XBGBcU 5O/Zt7+s/EI4EjGZTABw8vSZk6fP+Hz+115/QyUEAGRFiUSiRFVlRXn7nfdEUczPy62pqfX7/Zcu X7GYTRkZ6W+/814wGKy4ULlr997aixd37Nx95uy5o8dPnDhx6tVfv15Te3Hb9p2tbW1a95P2hxCm QCklFCgh9PS5ypNnKvo9vnfe3xEOR7btPNjS2oEQUhRFVhRCKACcOV915nwVACiKIsuKFr1RShVF lZWh5xRRAErJ0B8LuBiGYRiGuc8IoSPHb2GAeKxFAQBjPHVKybYdO8srKpcvW2KzWgEAIaQqajAY jE/FaDCseWSV3+/Pz8vTas2cMb2yqrqs/MK5c2XPPvs0P5zToaWl7djxk9bEBIfD8ewzT50/X15V VVNQkP/Ht98VBMGaaEWA4iEQxggIpZgigMbmtp/98i2E0PnymgtVlz49cqaq9uqs6UVpqUlbt+83 m4xFhTlPrF+tVQwGQ7/9/YdX6pqmlhS88Mz6zq7eN/64xWIxLZo/a8nCOQjotWFbbPwWwzAMwzD3 38jxW2MMSbcmJpQUFXo83qklJVpA5rDbe3p69x84FA5fy6QgSZIoil6vV3ubnJyU6XZ/+NFWo8mY nZUZL2a321auWPryV770yje/5na5amovujLSH3/s0VgsFgqFLBbzcEGtfwtRrTeK0uzMjHWPLd+4 btXf/vXXS2dN/X/+7juLF8x69um1Br3OHxhYvHD28ZNlwWBIq2ww6B9/dNm6NcvPllW1tHWGwpGe 3v6li0o/PXo6MDAYn/7InjyGYRiGYZj75Pr8W0Pjt66FIPPnzU1LT9uQkuxyZeTkZK95dLXRaFiy eGEgEOA5ftXKFRzm5s+ba7PbkpyOBfPn9vb1aWUQQsuXLfH5/atWLhcEQVVV7fN5c0v7+vouXKgk hKxeveKJjetLS+e4XOnPbn46MBBISLCMyLYK2vgtSikCQAglWMwA4LBbOYzt9kSDQa99YjGbstzp KlHj7Q6Fwh9+vDcUCnd198myAgAZaclz50z9/TsfK4oCI/q3WPcWwzAMwzAPQDz/FtK6r0ZGIE89 uVF7kZ+XCwAvffEL2tvnn3vmxjLr1j4GAFOnlGhvU1KSv/WNvxiaB8/H677whefidZ9/fmg6CxfO 016MmPvQ/YlAhpLOcxwmhEqSmJvjPldWzfOcVq65teONP24pyMs26HVaGUKooijRWAwjFIlEdTqJ 4ziMsMBzoEVb13J6sYCLYRiGYZj7C12XfwvFx8uPo/jcKcYYKAEEABiArlq2AHPYZDS8/NJTAODK SHXarZeuNLoyUl96fpPDYdXrdVoZo1H/za8+19HViwBys90ch52OzTzP/dfvftVhtxJVBhiKt1j+ LYZhGIZh7js0Kr/8+KaXh+tG6w+N36JUC48cDqv2ndNhixc36HVTivIKC7K1t/EySU57kvPag64z 0lMAICfbpU18RJjF4i2GYRiGYe6zW4/fGg8j+7cQUKoNslKV2Jilc7NTM11rFTly5zMgqgLs/kSG YRiGYR6ga+O30A35TsfP8P2JWucWBTlyq9z08md9svZ49+YxDMMwDPP5hwCNup44USDEIYQUJTZm lop7haiqIkfkaOj+zYJhGIZhmIcLAow5zAkIxZ/iE7+eiJDAc5TI49e6kZAgmY0Wx+CA7/7Oh6IB T0cw0Ht/58IwDMMwzEMDISSIhkRnltmarn1CEb3Wv4Uwh7AwQUIuQTIVlj493q1gGIZhGIa5O6oS 9fc1+PqaBNGgMybCdfkgJhw6QSI/hmEYhmGYO4cxMiemRQb6Q4N9WryFMUygMVsMwzAMwzCTH8Kc AECIOnRDH8exeIthGIZhGObeuv5mP57/rPFWLBY7evS4qqp3W5FSum//wfizpRmGYRiGYT7fOB5z X3x+Q17hTFWO+Pua7amFqqL856uvBUMhk8m0Zev23bv3mc3mK1frPB5PgsVy5uz51JSUPXv3vfra b3/xq18nJSf19/W/8eYfampqnQ6HxWLR6uoNhg8+2HLufNm582UzZkzr7Oz649vvnj9flp6etmff gX/65/+hqIosywcOHEpKcm7bvrOkpGjrx9uNJqPH6/v9H94pK6vQ6w0Oh11LBhEMBl/99es1tRe9 Xp/b7erp7f3N62/u3X+AUkhLTzt79vwnu/YcO3HS4/F8evhoX1+/25URjcYOHPz0vfc/kiQpOTlp QqW6YBiGYRjm841SEvR1YF4ymB3e3pbyq0dGByIqUY8ePylJUln5hbr6Bqs1cduOnS0treXlF/bs 3f/Ou++fOHnqzJlzhQX5+Xm5s2ZMd7tdixYtkGX542074nUrKi40NjXxPH/w0GFC6c5de3p6ez1e 7559+2dMn5aWmjJzxvTGpqbu7h5ZlvfuO0AIPXP2fG9Pn6ffc/TYcZvNtn37zr7+/p6e3lgsFgyG 9uzdr5Okc+fLW1rbLGbL/HmlxUVF73/wUcAfuFJXV1lVbbfZ3n3vA4NBf/ToiYbGpta2tl2795rM po+37xgYuFWuVIZhGIZhmPsKjTleXuD5rCx3f39/SnLSvLlzWlrbUlKS6xsajx47sWzJ4q0fb4/F YjNnTDcajS5XxuUrV3bt3nfs+Mn2js54XY/Hm5aaOmf2LF7gAaCpqfno0eOVldWRSDQz051oTSwq LACAtLRUvUGPMQ4E/KHhK4zZWVnr1z1+5WrdpYuXf/h3Pzp9+iwA2Gy2jRvWez1er9fr9/v37j+w e8++igtVhBAAmD1r5soVyyiFTRs3yIocDAZDwdCJk6ePHDnW19d/XzOmMgzDMAzD3AalY+eD4DDn dmds37Grta29ID8/IyO9pbnl0UdXr1yxrLq6NhqL2Oy25OSky5evtLd36vW6woL8cCSiKopWNz09 7XxZucfjjYQjADBr5gy9Tud2u2bOmI4AFRUWXLp8magEc1gSJbfb9d77W1rb2rRZY4xFSVRVtaio 8D9/9TMO4/5+DwBIOokCpYQGQyGv11dSXNjR0RmTY0CBF3hBELQyCCGgYHPYHl/zSEpKcmamW6eT HtDaZBiGYRiGuQEFGD1+C6ia5HTk5eUkOZNMRoPdblv7+JrkJKfLlTFvbqnT6XC7MoqKCnOys3Jy sjHCM2dOBwCTybRo4QJXRnpyUlJeXo7dbpckcWBgoKe398lNG1yuDISQLMdSU1OSk5PcblcsJufn 5bky0lNTU3JysjiOK50zu6Aw32azJjudGelpWhtEUcQYAyCbzZqfl5uQkJCZ6UpOSnI4HNFobN7c 0qlTShITE1wZ6Xa7fWSZJKfTmeQIBoMWiyUnJ5uN32IYhmEY5oEZNaX6I/sAACAASURBVH7r3JUj 6JMPf/XYppejIV/zpcP5szbdkyyjlZXVr//urYGBgUUL5//FV7/Mwh2GYRiGYR4ehMjdjed4yexI K2qoPfarj39yX/LLl5QU/ejv/5ZSMBqNLNhiGIZhGOZhRsj9eZ4Pz/N2u/1+TJlhGIZhGGZyIeQu O58IoapK7tG8CaX0nkyKYRiGYRhmwlIUenfx1qXLl1/99W8AgFLq8/lvUdLn8986nKqqrjl3vuy2 02EYhmEYhpnUFHmsfBDhcLipuSUSibhdLrvd1t/vae/osNlsqSnJ4VC4pbUNAI4eO/HmW3/84d/+ wJWR3tTUAgCZmS5AqLmpORKJ8gL/69d+u2Txwief2CSKwpjzTklOjsaiY05Hr9dfvHhZkkRFVY0G g8/nd7tdkiS1t7d7vT6rzZqV6WZZtRiGYRiGmRRk5YbxW4SQj7ZsO33mbILFsnnzk3qD/vd/eOfy lavJyUmvfPNrWhlFUcorLlRWVV+orKqvbzh06AildO3aNcFg8KOPPk5OTrbZrRUXqkRRXL/u8ZvF W/v2H1RV1ef33zidxYsX/uM//0tRYYHf7zcZjTzPFxUV5uXmvPb6GyajcdGiBZluF4u3GIZhGIaZ FIh6Q355VVUPHzn24gvP//gf/37mjOmhYKi6pvavv/+dYDDY1d2tleF5/oXnny0uLty0Yf3Jk6fr 6uubW1uPHjthMZszM92Zma4XX3h+0cL5X3j+WaPReNN5U4IwGnM6AMBhvGH940VFhVab9QvPP7P/ wCFRFDMzXQ6no6S4iAVbDMMwDMNMFnTM+xOdDntbW3tmpsthtyOEBEGoq6tHCPMcryqqVgYhpJOk UChotVqnTCmeWzqnsLDA4bBLknT02Ik9e/aZTCafz0cpvXVsNOZ0AIDn+Uy3++KlywaD3mazxWIx lztjw/q1p06f3bFzV15ejpZQnmEYhmEYZoKj9Ib+LZ7nn3pq08mTp//xx/9vefkFs9m0auXy7ds/ mTql2OXO0Bv0mZluADCbTStXLD9fVrFu7RpKYdfufY2NzcePn3rzrT+GI+FFCxesW7umtbUtGArd bN52my3J6RxzOgBQXFQoioJWBiGUl5d7+fKV37z+Rt3VukWLFvD8fUljwTAMwzAMc89RCmPkl6eU KqoKlGLMcRwmhKqqgjHmOA4AFEXRwh0toQPGWFVV7QVCSFVVANAKqITwHHfzeVNCCMdxN06H4zht LvEysizzPK8oijZxdj2RYRiGYZgJa1R++R+/ekN+eUoJUMpjBIAAKCUqAuA5DACUqADAYaS9QAAI AVDCDRUGAKqVBEoAgENDVW4GI9CmP2o6lKjxuWhleA4DJfGJ31XeLoS54UWjlI6dPAwBQiNSkRFC 7m4eDMMwDMN8fiGEOIwpIRTGDA+Q5ubVbxi/1d1U3t7R8rmJNSw6nD3tUUE0EKL2dDZ3tNYHB3zX ryyKETYn2Nw5U632ZO2j6pqLR4+dZFctHxhFURVV0UnSeDdkPAUGBswm88PcdRuJRnmOe5iPO0oh FA4ZDIaHeC+AYDBkMBge5gOBnQ9hQp4Pk5Kcq5bN72ir8/R2qKoy6ltJ0iWn5WRkFvCCeLMpjD61 hYKBjy6aeiI3va9wEsGIbs5tyaYAAP09ba1NF905MxPtKQghAAqUEFWmVJWjod6ult6uJkFnjkai VmtCIDBQMmXarFkzKbk3yfSZW2tqbrp48fKG9etv3IkfEoqqvPvu+5ueeFKvl8b+7fQQOHX6tE6n f5iPu0AgsGv37uef/wLcpCf+YfDxtu3z589PTUl+aB9Aws6HE/N8GIsGm+sv6AzWWQvW8YIIQAGA qDFKVKLKwYCnubGG43BGVvHNerluuJ4IEFb5oHLTAG0SwYiodGix25ouOpxpyek5HMcDJdr4MVUO EaIIvDElzRWNhmsvXuno6F77+GoAkERRVcKxaGRcl+BhocgRnucAlEj4IX3YgKqqlKp6nRQJBWDi nGAeLKJGJTHhYT7uYtEgJVQUcMDvHe+2jBtKZJ1OikYHyUMbbbDz4YQ8Hw74egYDnoKpS4xmGwAF SgGoKmNCZEqwIDii4dSW+sr0zEKExh65PlbX/c3HOd2MiW/PMu7AoCpUXzf4VIwkfoaFuQ+uXTlU CU2wuzhegPhvphE/nkRJJ+lNWciSkpKm05uu1X5Yf2A9aMPr+aFd4ZTG91X6EK8E7X8P924AQB/i AwFg5HHwsK4Edj6ckOdDQqioTzCabdc+GtE2hFCCLUVtqL9ZdTRmvHW3+7mJb1uZV7ZmwdcxFiPR wa1H9p5tX0iGnxSkUr1C9XcxuXtn1EKMHBGvxMLhwV5Jbxka6A8IEEpy2hHCQGIPsI0MwzAMw0wC CDAgpIVZlCihgR6MOV4YHmmHbvNA6rHirbsJqzFSZjk/3LDs+zZbH4AKoHtmZWn6udco1QMAIbEL TY4LvU9LJqskcG6nCSFQVNLjjwyG5TtfyM/mJjcRgBIL9bSUDfq7EhxZCXY3wkMx12AwpI3fut8N YxiGYRhmkqJE9fc19rVVCTqTPbVIkAy3r3Pj/YnalIL97f72y6PGbCKOs2ZOl0y2kWPBKKUCCur1 ToAWAAIQTkvDT234PkAOAASDndX/8yedl05nlT6e6TR97bGiq+1+hKCtL7inrO1+51wYM96So8G+ tipAnC2lKDTQ7e9rttgztCUaOX6L+Tzp7/e0trXNnDH9tmVmTJ927NiJOaWzDfqbdsqWlVU0NjVp r2fPmpWdnRkOhysrq5OSnNnZWfekwbIsl5VfKJ0zm+Nu84PpFm2bNXNGY1Ozz+cDAITQqpXLExMn yIX+e+D+bdPP93oDgMbGprLyCu11dlbW7NkzCSE1tRcVRZk1c8b4tu3BkGV53/6D4XAYAARBfOSR lQa9vquru6qqZvGShbfYTz5PKKUHDx0e3s/xksULz50vG14nwiOPrPrcrIf+fs+Ro8cJUQHAbrdn ZKRfuFCpfaXt/3c7QUpJoK8p4GlNTM6Xo4PenvpEZ9adhFw3xluUEkqUmKfh/BSXZc2jj+h0Op/P 9/G2HX3gsLqnjrqemq4/JKGW8+f/leM6hycw9B+HY2pysgsAKFEpJRRofaf/zQOXp2balk5J3Vve uqQ4+XK7DyOUl5pw4mLXxvmZoagqK+qJi92pNsOComQeo2O1Xc09A3e7Oq4tyw0hlypHJH2C2e7m eVFvsoYG+uhw9rCsTNd147eYyYNSqqoqANICFFVVKQWOwwghRVFb29p27do7c8Z0rRilwPMcQogQ QgjBGGOM2zs6du3aO6Wk+MMtHxeXFOl1OlVVEUIUgOc4VVUJIQjheAAUCoUrK6utiYlZWe6m5pZ/ /9kvN29+Ijs7654sjj8QePud96ZPmypJIsbxJaIcxyGEtKW4bdtMRtNHWz6eP39eQoIZIayqk+yW t/HaphNqvY3c7qpKAKiWIzq+jDeUGVoonue07NOEEEEQCCGqShACbjgHtaqo1bUXfT7/7Nkze3v7 Xn/9TbvDPgHjrfjeHk+4rb2I7xsjjwiO4yiliqJqS6plzAYAbeUoiqLtQrKiaNmzOzo6m1taly9b EuO4/fsPfvjRx7Nmz5hQcQalVEsDDgDaMsa3Y3zBta2PMVYUJZ4z3O8P7Nt/cNPGdYIgKIqKMMII jSwDMLQzeL2+6ura1NSU9977aO3aNTzP8TwvTLC0LPFthzEePjMAxhzGo48LANCSpQ+XwRyHKSWU Ql1dfW3tpYKC/MrKqs8QZsVRoqpqzJ5aYrAkydGBgKeZqCq64Wk9o4yRf0v72OhwZS56drDjXEJC 4tKlS7Zs26Ek5rnyl4om+6g+KZt0Zcn871utPoBMAAAVoA9Ags6u9n/5lwPf+MZCLTqjFCilU9y2 Hzw1XeS5I9UdikoKMxK7vCEEqMiVePJS94xs+9mrvUZJKnYllritJr149kpPnz/ymXvBxqwnGRJE vQVjTCkRdRbtyislCgCw8VuTV119w86du2VFfmbzk3JM3rJ1u8/nX71qeVp62ie79oaCQe0oraqu 2fXJXo/X+/TTm+bMnnXo0yOffnqkpKT4ySc3jppgZ2fX1o93yLIciUT+619/98TJ03v37rdYLBs2 rJ09e+bs2TPr6hsGBwanTCkJBoPl5RUpKcn3don6+vp/9epvEhMSnn3mKQDYu+9AWXnF8mVLVq5Y 1tvbd0dtm1q8e8++JUsWOh0Og0EvTbZ0PuO2TSfMehsYGNizZ39ZecWSJYsffWTl8ROnKiurnnvu mZrq2kOHj0ydUrJp03pVUeJl5s8r3X/g4NmzZTnZWZs2rT985FhXV3d/v+cHP/heT3fvu+99gBBa uXL5ksULs7OzPB5vb2/f0qWLZVk5dvyEw2FHtxt98uBRSs+cPb93736bzfbcs0+Lkvizn/1y3drH LAmW+L6RlZkZL/PsM081NDZ98skeALr56ScGBoPHjp1QVbJgwdwFC+b98Q9/qqtvKCkp2vz0E5s2 rldVdcuWbQX5+QaD/sqVq6Fw2GC4g6tCDxCl9OrV+vLyC08//YTH49m770BJcdH2HZ/Et2NrW/uO 7Z+0tLYtXDhv44Z1W7duP3e+PD097YknNnz44dYtW7fLsjxjxrRdu/YCgM1m/fKXXoyX2fz0EyuW L6WUnjh5Wq/TpaYkm82mFcuXSpJoNJoEYQLFW8FQaOS26+rq+f0f3jYaTQUFeevXPXbi5OnKyqrn nt18vqyiqqp6cDD4lS9/0Ww2vfX7t71e39y5c9ave/zpp56IRqNvvPGH6dOndnR05ufnrVi+TJRE 42fa4pjjE5y5HMcDAMcJFpuLqspt76NEMHZERgEhgz0D0kpf/dOuH/34J+/trzDlLRFNNm1w18i/ sJqiUCkKWU5nTlJSTlJqTlJqTpIlx+7MUuXQ5cstkUhguDBcbPX8dt+lmhaPZzCKERBCRR6bDTwC AKBRmZy72hOKyg6L7nht10AoNsVttRiFG2d6N383LDPm8XDGeYS07PNDxQaDob6+/oc25cmkdujQ EVVVKaGHDx+7UFkNAI899sisWTOOHjme5Xbl5+VqD4zatm3ntGlTfvCD702fPm1wcPDEiVOPPrK6 vr6xo71z1ASrqmswQsXFha2tbQAwbeqUjRvX6fX6Awc/BYBYLFZTXet2uxwOR1V1bTAYmjXrHncM 6HW6ObNnNre0dHZ2dXR0nDtXlul2Hzp0OBgM3mHbkpzO1NSU13/75r/+r59+8MFWvz9wb1t4v43X Np04662jo/NqXf2aNY8cP35ycDDY399vNBoRwIGDhzLdrvLyis6OzpFlmpqbL12+Om9u6eOPrxkY GGhqap43t7Snp5dSmpnpevLJjTk52bt27dV6RMrKK0xmU3ZWZlNTc09P78KF8zGeSMklAQBAVdV9 ew+Uls6mlF6orJJluau7x+XKGLlvjCxTVl5RcaHS4bBv3Lg+M9N98OCnM6ZPkyTR5/MZ9PpHHln5 6KOrysovtLV3AEB7e0e/x1NUVBCNRi9UVhcU5Nnttts26UFCCJktJp/fd/Vq3YmTpw0GQ35B3sjt uG/fAavN+r3v/uXqVSs5jlu0aMG6tWt6e/uqqmqeeGLDrJnT1zy6+uiR45luV1paamdn18gyFRWV AODz+evq6guLCi0Ws06v+7ef/se//fTnO3buikSi473014zaduFIOBAYWLBg7unTZ4PB4eMCoTNn zi5aOD8YCoYjYYfDvnHDuoUL5x08dHgwOAgAFy9e5niupKTY6XRUXKj81//509de+11NzcXP1CLE 8SLE77ZDGGF8s/Hi1+qM2b9FtbwSgAy2dEoWVTZfcBYulsw2AHRjV1NdYN22Q/9LNn/t715AfJhC CEAGkCE1krp5nfv/+/nh3FwZ6Aqtj0tWSJcndKiyY+mUlMGI3NAVmJ5tl3gOIW2EPo3JKqEUI2TS Cf5gLM1usBrF9r7gZ1ojQG86Yn5sbPzW5BUIBOrqGzLS05KTnIsXLzxx8vSpU2eA0lA4nG+zEUoa m1sohXA4nJGR7rDbMcahUGhgYNCd6cLHkSyP7tSMRWN6gz4lOVm7rfXY8ZM1NbX9/R6rNREAOju7 6hsavvTSi5SSPXv2G40Gr7cZY7R61Yp7NdZHksRMt0vgeVmREUB9Q6MgCOlpaaIo3WHbBEFYt+6x JKfT5/O9/ts358yZlZBguSdtezDGa5tOnPWmqqqqErcrIybHtFEcCQkJPM83t7QRQu12uyRJ0Wg0 XsblynjqyU2HjxzdvWdfaeksSmlGRpokiQBw8dLlXbv2UUo8Hg8A+Hz+ysrqTZvWC4Lw6adHenp6 I5FofX1DY2NTdnbWuCzsmCiFYCiUkZHe3d0zPLSIt1oTR+4bI8vIMfnJJzYePnz04KHDoiCEw2GX K6O9owMAQqHwtu2fhMLhnu4eWZZlWa6qrklNTUlJSW5ubjl9+uyUKcX9/Z4zZ849tubRux03ef84 HY7UlJTjJ0729fd/+aUXr16p27X72nYMBkPp6enOJKcoCKpKtu/4pK+vv7OrKxIJJ1jMGGOz2XTt eGlqHlkmHAlTSpuam2OxWFFhgV6ve/krL6WmpNTVNbzzp/dWLF+i002UHvFR2w4AzGaz25WhElWL SbTjIhgMutwuo8EIAJ1dXVu2bgOEuru6KaXhcPjc+bIZM6aZzaaiosLvfucvEyyWnZ/sPnz02LRp Ux7MUlA65vVEuJZ/y+BwGezpgLAWD91YVAWuaWBlMjp57PSCZVky8AAygAcAqMuVn59/5uxZIhVQ SkmHJ3i0ppNQ0hcIHa3pMEjC6ctd+WmJ4aiCMSKE7DjTNBCO1TR7MEJmgxCJyScvdl1p991tMrBr i4GuNZgQqC47rDOY40l+KKWUKJRSAEIpTU51Z2W62fitSWr+/LmyokiSaLVaL126Ul1dqxJCKJ0x feqhT49gjHU6CWO8eNHCj7Zu27vvwOOPP5qdlZmbk/2b199w2O12u723tw9zHAAIvAAA2dlZZeUX Ojo6o5EIAIiCEA6FtZFD0Wj01KkzRYWFdruNUlixYml/f39FRdXwCJt7AAEMDAy+/8EWURRtNhvP cUuXLAwMDNrsNkrpHbaNENrY2Lx3z/5QOJyWlpo42W68Ha9tOnHWm8Ph0Ot1v/7N74oKCwwGPcYc pUSn061YvrSnt9dqTdTpdKIoxstEI9EzZ856Pd709LSkpCSe599970OP1wcAHOYURYlGo4qixmKx 82XlmW6XKyMdAObMmWVrsra1dXATbMgOAGCMSktnv//BFkkU58+biwB4jofr942RZeaWzikvq2hq bqGEYIxnzZyxZeu2nt6+FcuXEEoURYlFowihaCTa09Pb2dm1csVySZKSkpzLly9RFFUlJBqNTqh+ Pp7np0wpPn7i1PTpU51OR29v38jtOH9e6b79B6uqqueWzlm2bLHBYFCUbqA0FpN5ns/OziqvuKAd LwghURIB6MgywWCwqqpmxvRpJpMxFAqfO1vW3dMTiUSmT5+qn0iD2EZtO1EUW1vb3n7nvbzcHL1e N3xcSG63++23321paQUAnuMJobFYlBf4aCTa2dHF83x2VhbG2Ov17d23f2BgEAAWLVpwVy3p6mw6 dXjrtVSBAIQoQMlQPCHHotGb9gvetH/r+lK3ivQpxd5YYY7yp7Izh9quqMABhIcCsxAdtNnCdXUw pQAAIBCK1bZ4AIAQ2uMLA4QBoLy+Nz6pysZ+AGjrG9Te1jR7brvwtzFiQRqDDr8iGjgjoUAoJYTK CiGUkKEVBVOstlVs/NakNbd0dlpqSiQSSU5OJoQYjUadTpeRka6qitvt4nleEEWOw8uXL83NzVEU OSMjw2AwPP/85q7uHrvd5nQ4LBbLS1/8As/z3/6rb9ptNovZ/OUvv+j3+d948w8AsHTp4uycrGg0 arNaeV5YtmxJYmKiNuZ0xfKlALBi+TKOw/eqc8tisfz3H/5AkiSDweB0OhBCzz77dH9fv8FoNBj0 BQV5d9I2SmHpkkX5+blEJUlJTpvNek/a9sCM1zadOOvNbre/+MJzPr8/JSVZp9MtW7qY47DBoH9m 85MdnZ2iIJjNZp7n42UMev3SJYsIIampqWaz6UsvvRAMhrSLp8XFRZYES3AwKOkkvV4/Y/o0SZK0 oWna2LVwOOLxetPTUsdrYcfEcdyjj6wqKS4ymYypqSmU0le+9XVBEEbuGyPLJKckWyxmlys9MTEx OTnZ7c6YPn3aseMnAMBoMHzly1/s7u4GgKysLEEQNqxf63DYASAxMfHpp56glM6bOycz032LRw6P C7fb9ZevfN1qtYqiOGo7zpo1Iyk5KRQMOZ0OjuM2bljX3t6uEpKelmYymV584TlAYNDr3W5XY2Pz ufNlo8pIkm7limXJyUkAoNNJ69Y91tfXhzFOSUnR6XTjvdzXjNp2DY2N6Rlpzz272W636fV67bjQ 6/UvvvCc1+t96/dvA0BSkvPll1/yerw8zycnJ5nMprS0VK0nOyvLvWnj+sHBoMFouKsdfkDRVQ5k u+1ZhFBCKaFUUYmiUkqpFkioioIj3pV07JjpJvHWXWZ0jaiJhy6/fOXwH4k6ai5WAKs5BURj4rik iKUj7k8ME0mRnGHeJKtUpVSlJAqqSohKCFEpRqDyJpZ/a/LS6XS5uTnxt0lJzuGXYl5ebvxzo9FQ WJgff2uz2Wy2oREber0uXZ8KAFlZmQAgimJ2Vma/x5OVlYkwNhoNhQXXKqampoxqwL0d+SEIQnFx 0chPUpKTU5KHhuTfYdsQgsTEhMTEybo/j9c2nTjrjeNwampKvGHxfcxqTdT+5dCMLFNYWBD/PD09 TZbl4uIiQRAkSczJzop/5XQ6Rs0rvq4mGovFbLEUxt/m5eXADfvGyDIuV4bLlaG9TkhISEhIaO/o 0G7fczodIxd81D0uCCFtP5loBEGIN2zUdpQkaeTbUfutFk0CQF5eLqXQ1d19Y5n4urpx/Uwco9qm 1+mLCgvy84dOAvHjwuGwOxz2/Pw8vU7PcVxGelpGepr2VYLl2pAASZIyM92foRkqxWFsjYkpUVlV KVVVGgNVploUQQihIkeoEr75Uoydf+uGLq7bEewzip8oudm3COFxycg/avQWHc4PoSXQJ1qOCgrx NGBs/BYzit1m+/ZffZPnxn4Y1viayG2byB6q9SYIwiuvfP0hWdibWbVyOSET5Zkw4yU/Pzc7eyJG k5/BrZflpS9+4X73UA5HDtofjb++tbHjLXr3z08E0G70u6nPPAbrzzFy/NadYPm3mBsJgjDeTbip idy2ieyhWm8PebAFAAghjptYlwjHBT/xxud9ZrdYFownyr0Oo3DcWPFWokkMoetuTBgcDAqiIIni g2rYvcEhelcHGcu/9ZCglEZjsWAwaLNaEUKyLAeDIUJUSdIZDHqP1xu//G232bQ0iQMDg4mJCeM1 sENV1cFg0KDXa4krw+FwNBrFmDOZjDFZDoVCWjGDXq8oSkweelJWgsXyuQksKKXhcERRZIvFAgDR aDQUClNKtfxYHo9X68xGgMxm88BAQNt+giCMvI4w2cmyPDgY1PZDVVWDwZAsy6IoGAzGYHBw1HYn hAwODur1+s/NPgAAlNJgMIgx1hJlhcPhcDiCEDKZjAAQCAxtd1EQtP0kHA7L8tA+8/lw5+cum9Xm 9V47Lmw260Qbl/aZTdLzIebQ6HiL5/D3n5yms6SN/HDnzp16HV61evkDbNs9QInaUXMXg+7Z+K2H RL/Hc+jQkYOHDv/kn35kt9sqK6v37jvg9frc7ozHH1+zY8eupuZmWVYCgcA//P0P8/NyL168/PNf vvr9//Lt4qLC20/9XiOEnDx1ZsfOXcuWLl639jGfz/fhR9vq6uoNBsPSpYswxls/3g4U/P7AokXz /f5AXV29Tq8DgBe+8Nz8eaUPvsH3Q1NT86FPj165evWff/wPHMcd+vTIyZNnwpFwcVHR8mVL3njr D4FAIBKJAqUvvvj8L3/1a21oTl5u7ufmalowFDp69Pi27Z989zuvFBcVtra2bdm6vau722a1Prbm kYuXLp8+c5aoxOv1vfyVl1avXtHZ2fW/f/aLlSuWrVv72Hi3/Z4pr7hw8OBhSZK++51XotHo9h27 yisuIECzZs0oLip8480/KKoSHAympqb86B/+OwV4/4MttbUX//mffvS5CTrv/Nz1V3/5zV/952vW xESEkc1m+/73vm2xmMe7+ffA5D0fojGvJ5r1osl0Xf/W7GlFhBCraaJk47hDlKg9d5NGhY3f+hxr bGxqbmmNxWJTSop7+/oikUgoFNJ+/PE8//RTm2w227vvfXD1at13vvMKJeTixcunTp9JsFgGBgar q2vieV8eDFmWjx49wfFcYkJCRkZ6XV29JEla/iGEUElJ0eanN126dGXX7n0/+ocfLl60IByJfPTR x9nZWSdOnPrWN782dWoJAOBbXuKf+MrKK8LhiCzL06dNra9v5DgcCAwAAAVITEj42te+jAC99pvf LVww9x/+778FgMOHj3V1d+skafq0qf/Xf/u+NpFJHWz193vKKy4ghDIz3TpJ6urqBkq1/ZACrFi+ 1O12HT589PiJk3/5yjee2fxkd3fPjp2709JSFUWpqb3Y2dGp7TOTF6X008NHeZ7nOW7KlOKGhiad ThcIBACAEJKcnPTX/+Xb/f3e13/75iOrV/yPf/kxIeSjLdtEUcAYX71a39LS2tf/Z9/nPt4+27nL YjbbbNZ/+cmPtUzxkzri/HycDxG6oX9rTNqzuv7MmVFKuruPNza+BwAmU1ZJyXc4bnwCOKrlgRhK BXFtjBcbv/U5VlZecfr0OZcro7m55asvf2lKSfH5snLtqxkzphFCmppbACA9LY3nuHAsVl/fkJWV abNZa2ouBkOh4uIH2rPlDwR+9+bvlyxe1N3T89WvvPTyV176CgXlkAAAIABJREFU8KOt2ldWq3Xx ogXBYKi5uSW/IFd7jFpba7vP5589a+b58+UffLT18JFjxUWFixcv1K6zTFK7du0VBEElxOv1PfXk xr7+/vKKCwDAYbxgwTxFUSorqx0Oh8ViEQTB7/c3NDQuWrQAIaira/jZf/zK7rCvXL7U7XZN3sso 7R0df/rT+3PmzD59+ux3vv2tl7/yUmdnl/ZVdlYmzXT3ezz+QCAvL1d7tFFLS6tep8vJyW5v77h0 6crChXeXW2gCUhTlT+9+MH36VK/Hhznumc1PVlZV79y5GwD0ev3yZUtisVhFRVVhYb4k6QRB6Ojo 7Orqfv65zZFI5NTpM7Nmzejp6b3tXCa4z3bucjodXq/vl7/6tclkWrpkUVFRATdpf3t8Ts6H9HZP WNR0d3c3Njb+mbPq7T3T2bk3N/fp3NynTaaUixd/Hg53xf9U9cGNmmpvaag8d7y2/NSlilO+vq74 50lOe6YrhY3f+rwqLi5c8+iquvqGUdlJZFm+ePHynj37ZsyYXlRUCAAdnV1d3d3Tp02NxWLHjp/M zs7S6XQej/dBpjVJsFg2bHic5zh/4LrnyRBC+vr6t+/4hFBYv/YxjHEsFjt2/ERp6WyTybhp47rn nnm6dM7squqac+fLHlhr7weM8bx5pUsWLWhoGH3yiUQi586VHTtxctXK5cnJSZTS2tpLBqPenenK ysr89re/tXLlckkUt2zdrj2zdvJKS0vbtGm91+uT5eueM6aqamtr29at221W65LFiwDAHwhUXKic P38uz3P7DxxKTk4ymYx+/8C45OK5hyRJWrVyeVaWu6uza9RXgcDAwf/D3nuGx3FcidrV3ZNzxkQA g5wTARKJAEiCOUgUJVKJWkmWbNOWZFvS2usNd/3sZ3vlsOu712Ety7KsRFKUKFFiTgBBAEQkcs5h kAaYnKfT96PJ4RCgSIgBAEm8D37M9DS6q06dqq4+deqc0osDQ0MbNxRzOGwcJ6qqa+PiYhQKeUdH l81mk0qlOI673fe3kQ/c1tglFotee2Vf8bo1Go3qs8NfULbh+5elNh4SBOH3efw+D+rzYnNSWdwQ nCDnZd+Ki4vzer13UjiPx9jT87cVK55js0cAAACI+/omKiufB4ANAMAwB5u9NTPz21zuN5h+kiTZ 09MTHR39TW1vKm2YRKHyoThBkMHRXJf9tx5sRkYNCEKTy2QwDFNp5CnqLzd++unn6empHDbb4XDw Bfz29g6tVqNQyK1Wa3//QFd3z9DQsMPhzEhPWzAfCKfLVVfXQBDErEDPZrPlL++8B8NQbm622WyR SCTd3b0AQMlJCRAEjRrGfF4fh8NBUXTJ7tOZJyRJdvf0IjBMxWMMPn7y1JmKiqqCgjwURf1+1Ofz 9vb1x8fF8nm8iYnJ/v4BnU6L+lEURe9f4xbFjMlUXV0rFotmrQcNDg2/8857YeGhIcoQs9nM4bCb mlo4bE5ERDhBEFNTxobGJqvFhhPE2jUFSzOs1DyhDJlTxunQUF3wcZ/ff+jTw4ODQ0VFBRarTaVS Tk5OzUzPbNy4nkajORyO9vbO3r6B1raOs+dKHt/16GKV/65wG2OX2+3pHxjUaNQ4hsMwvHQyFN0e S208dDntPR2tGI6TJMnmCtThsYF0il8Hjs9vvjU4OAjDcGRkZPBBv9/f2tra1tY262SRSFRQUCAW zwrKTHq900ymkAorD4AnMlISEfEmACEAgJmZlh/96Ddsdt7KlSvnUx6Kqampf/u3f/voo48Y33Dj pN1qsdusKE6QJMkTShmsK5O8Zf+tBxscw3Ac27ZtM7X4UrA6j8NmAwAsFqtEIh4dNRgMY5s3b4iO imIymCtWpMMwLJFIfv2rnwMAzp4tiU+IW1CHUxJYrbZVq7JUSiUAQB8eTh32+/0wDGE4XllZpdGo IyMjvF5vfl4On88HAERE6C9erJiZnklLTUlLS1m40t4DSJL0+/wCAX9NUQEAgEGnr1qZhSAIjuMO h1MkErV3dPX09MnlMhaLpdNq4+JiIQgSiUQiobCmulYkEj7++M77ftJJEHabvbh4DZfLAQCkp6eK RSIAgMPuEAj4FrO1tLQsPT1VrVbBMLx2bSGdTocg6Mc/fp0kiMbGZgiGby+049IBx3GXyxUWqktO SgQASKXStNQUAIDP63U6XWw2u76+QSAQREdFer3e9PRUlSoEAFBUVJCfn2u3O86cPb9j+5ZFrsMd cxtjF5PJ0Gk19ZcbaAjt0Ue2c3n3uZ/MEhsP+QJRyopcP4ajOJX/HdzSkIxjN86fOJtZc2oKCIJs NtuBAwfCw8MzMzNpNNr4+PiJEye2b99eWHjdTkaSxDs6/mA2N1VX/xKCjABcy7QDwYhanclmcwmC oG5RXl7e0tKyc+fOI0eODAwMZGVlbdu2bWJi4vDhw3Q6fd26dcnJyTMzM59//rnFYjGZTJWVlWw2 e9WqVX19fW1tbdu3b59XlBEIQNDssK7L/lsPMDCMpKWlPLbzEeorjUYLfN6yecOWzRuCT964sTjw mbIrbNmyoJu8IABkMukzT+8OWDUyMtKoD2q16p9+8kbwySuDNt2Eher2PvvUgpXznsJgMAoL81OS k6ivAoHgqSefAADAMPzc3qdnnbxmTQH1gcNhb9iwbsOGB+GtCYbgcH34Cy/sDRzZtHE99SE9PTU9 PTX4ZCqvFAUNQQCCrHwgdqcK+PwdO7bKpFdCpWvUKioHi0Ag+OEPvh98ZnR0VOAzBEF0Ol0qlVA6 c19ze2MXnU7PyVmVk7NqIYt6j1iC46Hb5Rzo7cJwnCBIJour0OrnYd+an798SEgIi8UyGo1CoRBF UR6PBwCg0+n5+fl0Ov3YsWNRUVFhYWEHDx7cu3fv7t27Z2WRI0ncZGrMzv53FqsfgAgAAPABYAMA JjuGe37x3ul9+66ZtTo7OycmJjgcTkZGhlwuP336dFxcnMfjKSkpeeaZZz777LPQ0NDa2tq+vr7I yEgGg+H3+9va2sLDwysqKhAEmY9LIE8gZHK4fhTHCRKCaYFZ13L8rQcYKsfWYpdivggEAipP3GIX ZDF56sknpFefsg8nkZERzz7z5GKXYjEJ5L5c7IIsJvfX2HUvWILjIZPJUmnDUIzAcAJAMATBt7Zv EfOzb3V1dSEI0tHRkZWV1d/f//zzz1PHGQxGTk4OQRCffvophmGZmZk7d+6cs5IIAABSaRqLpZDL uRBkBwAAAgA6IGFSZPZMG2v6+gwoes2lUafT0en0kpKStra2pqaml19+GQAQGRm5c+fOF154wefz TU9Pa7Xa7OzsU6dOpaWlNTQ01NbWtra2vv766/Nx1xgfHZoxTuIECUgyRBvBE13JyrTsv/UAc3fz G95r6HQ6lSfuYUar1Sx2ERaZJZvTcMFYsjkNF5L7a+y6FyzV8TB4snHrXSnkPP3l9Xo9QRDFxcU0 Gi07+7o9xjQaLTc3F4bh7u7uXbt23XCyBcOMuLh9NTWvFxX9CwTVAysAKAAkgGxQLCssP5v3zjun SPKaXQqCIK/XOzw8HB8fPz4+7vV6GQwGgiBMJpPabRQWFvbpp5+aTCa32y0WiyMjIz/77LOsrCyV al5jU2hEtDo00odiOEFScSGo48v+W8sss8wyyyyzzM3x+bwThiEcJ3CCYLA4yvm5IX2D+FuUX9Rc mx61sJiXl3cT11QGQxQSkjcwUB4h1gF0EpAAOABwAhimpaTEX6rrqa+/8r8FBQUAAKFQ+Morr9TV 1e3du1ev17PZ7D179iAI8sorr0gkkqysLAzD/H5/ZmYmDMMREREAgI0bN84zvggEQTAMQzAMkSQE EYGZ6bL/1kMFhmGXG5rq6i4DAPLyshPi4yYmJs+XlG3atJ5yEFksCIJ47+8fUnGDYAR59pknF7c8 i0JDQ9Op02cpc3Vaasrm651UHgaWrH4uJKOjYxfLK4zG6ejoyMKCfIIgq6prCILc8tDow+ioYf+B Q5Rzs1areerJJx6kNIjzYWmOhxwuLy55hR/DUQwnCBLHidn+4HOAwPz8t6amprxeb0JCwtdeCIJu vpBHp/OUytWnTz9b7YEA3QvAlX2KJCCdhA1BiImJK2fGxcVRH5KTk5OTkwNXkMvlAIB169YBABgM xoYNV/pbVVXV22+/vWXLFmrWdScs+289VPh8/qGh4eTkRIfDceTIUQhAx46f7OjsysrKWNz+jON4 Q2PzE7selUglMARLbmQzfuAZHBpic9jr1hYBAB5OL64lq58LycDAII/H1em0tbX1LBZrYGCwf2CQ z+c/PPMti9U6PT3z3HNPAwDYLPbDNtkCD9B4CEHzs2/defwtAIBUms5gvPHO+38FYFb20BAMA9nZ jG8UfCvAihUrfvOb3/D5/DtXxGX/rYcKLpezdcsmj8dTUVlFp9P1+vDvf+87v//D/y52uQAAgMlg MJhMOo0uk0uZzPssT/xdAYIgBp0BwzCPx5M9lP4rS1k/F4zsnJUQAB6Pp7Ozm0ajPbnnifaOjgsX yhe7XAsHBCAqPRGTyVTPz2HmwePBGA/nO9+6Yfyt27jdrl0v7tix9+t+vr0JE4PBoExfd86y/9bD Bo/H7entramtk8lkCIIIhYucQJ4CguDMzIyqqhqf3y/g8/fs3iWXyxa7UAtNZGTEwODQiROnAQC5 Oavy83MXu0SLwNLUz4WEyWBYrbbSC2VcLic5OVEg4N/ea/n9i0wulclkJ06eIQkiPi5269ZN929a ntvjwRkPofnl87lh/K3buR0EMb6eRY9MGB6my8hIX/bfekjw+/1VVTU6rXb3E49NTkyi88vJsAAg CBweHrZ792OPP/aowTA2M2Na7BItAkKhsHjd2hee36tSKhubWxa7OIvAktXPhcQwNnbwk89cLndx 8Zr7dyHpTmAyGLm52d964bnUlOSa2rr7PTvTbfDAjIfQPP3lqfhbtzzNYrGIRKL7N4HGsv/WQwVB ECOjhuMnTmE4npeXQ0WVEwgEi67AJEm6Xe6///0ju90eGxtDxct+2CBJsry8cnRkVCgSbt26abGL swgsWf1cSC5cKD9z5pxCIa+/3LBr5yOrV+fR6XQOh7PY5VpAIKijo/OLL75i0OmFhasfNuMWeIDG QxLMLx5EV1cXi8XSaG4RDufQoUNFRUWxsbF3o2yLwLL/1kMFi8V65JFtG9avBQBwOBxqpeaF5/fS 6YvskQrDcEFB/orMdJIgWCzWrHxhDwlhoboXnn/W7/fDCMK/31OR3BZLVj8Xksd27ti06UpIfWqa FRcb8/BsFwAASMTiJ/c84fV6IRjicbkP1Wyb4sEZD8n52beo+Fu3PC0uLu6G8beWCBAANBoEcIDA MAYRJAnjMEkQAIchKiTEsv/WwwaLyWQxmcFHOJwl0ZkZDDqDIbr1eQ8ulKf8YpdikVmy+rlgcDic WdYsCIIEAsHXnf9AwuGwH7Z2n8UDMx5+g/hb8znzzleXSRIfGDhkNFYAAHp7cZ1u95o1a+/wmgAA CBDDQ4MMBpMEgCRJkgQESVA5JkkSkCSwChWpccvxt5ZZZplllllmmRtAkiQMkUwahJMAgUkYgmgQ TJAEjsMkQV4Lnn7D/53nfOuW8bcoBgcHpVJpSMjtL68ShH94+IjV2qXTZcKwzeMpOXjwVR7vf5KS ruSsZbNDbpkV8oakhThixX42lwXBN17/lkroy/5byyyzzDLLLLPMXBCIdNume9rc1KQqYLsBgAQk IAEgCULG/fr5yTzXE+cZfyszM/OWPl43x2RqHBj4q1ab7fdPAECGhqbu3Omfnv55ZSUDAAzDvFzu q6tW7WIwvnEEDhELk/NpXAELRm5cZTqLvuy/df9isVgnp6aYTKZGrWIymb29/R6vB4ZhqUSiUMj9 frS/fwAAwBfwNWoVjUYbG5+QiMUsFtPhcLjcbrlcTpvjiIrj+NjYuNPpEotFISEKysRrtVpHRg3U CWKRSKfTAgBIkvR4POPjExqNhs2+9c6SW0KSZFd3D4qiCIIoQ0LEYpHdbh8ZNVA1ogrT1zcQFqaj 0WjUhh2pVDLXCI2i6Oiowefzh4QoxOIre1nGxidMpit7fDRqNZWdze/3T00Z7XY7h8NRqZTz2R9z r6HKCUGQgM9XqZR0Or2ruwfDMA6Ho9VomEyG1WrFcUIqlXg8HrPZIpVKWSzmrIsQBDE9PTMzY+Lx uGq1mnJ+8ni8/f0DBEkAANhsdlRkBCUZs9lsNM6QgFQplULhkvBMd7nc4+PjBEFqtWoul7vwMvH7 /ROTUzwud7Gy+BEEMT4+4XA4pFKpTCb1+fxUOel0ukatEggElEzodLpCLpdIxACA4eGRsLBQkiQn JiY5XI5IKJzblC6Xe2xsnCAJnVbD4XCoE6hxgzohOiqK6ssEQZgtFrvNrteHL4pKBMYcDpujVqs4 HHZvb7/X62UymSqVks/neTxek8mk1WowDJuaMgqFgrlr8SRJ2my2iYkpGo2m02moDh4YZwAAEATF xcZQboIOh2Ny0oiiqEwmlcmkix46YImMh3Ku/5kMl0ylRGj0G9p9MMxnMRoQ6GuNXHcz/lZnZyeH w7kTFy6SJDkcaUzMWgB81JGIiNwr+Xa8zoGButd+/Ju//W2NUqm87VvchGX/rfsUk8l84uTpiYlJ iUSyOj83IiL8N7/9nVIZQsUZeW7v08bp6bfe+q+09FSRUJCXlxMfF/fRxwe3bFovEosuXaoRi0V5 udm0OXF92js6T58+53a7JWLxzp07qPTJg4PDp06fJUly1DCWkpK07zsvBQpw7lzpj//xR0lJtzAD z6tGZvPPf/6r+IQ4QJICgeDFF54rKS07dfpcbEy0XC4rLMhXq1V/fvuv//jmDy0Wa3395ejoKLFY NGt8IUmyoqKq8lIVhuHh4aE7H90hFAoAAC3NrU3NLX4/Ojwy8uSexzesXxeol8frxTE8Py+nsDD/ zmtxh7z//kc2m10g4EMQtH3bFpVa+fOf/yoxMV4g4KelpqxcmVVSWgZBcGFBXlVVrdfnKypcPXdu MTY+8eWXx+x2OwzD27ZuplrHbLEcP3mawHGjcZrNYf/Hz/6VRqN5vd4TJ88YDGMYhslk0r3PPrXo oZ5cLnfphbLWtnaxSLxiRfqKjLQFlonf7z92/FRJSdm6dUU7H92+8BIgSbKtrf3c+QsEQURFRaxd WzQ0NPzWW/+VnJxIEERkZMQTj+98//2PbHa7Qi4PDw8tLFgNIPDHP/3l3//PP3d0dPb29qWlpYqE s1+hURQtKS1rbGwiCCIlJXnL5o0sFhPDsOqaWoNhzO32jI4afvpPb8bGRgMA6i83VlZW9fb1/8/v fr0o8c+ovq8PD8MwLCdnVWFB/m9++zulSikRi+PjYlavzuvrHzh9+ty+fS9fulRtnJouKMibO9+y 2WxfHT0xPDxCkuTaNYW5udkwDDscjjNnzrvdbqvNZrXafvWf/yESiQiCOHf+Qk9PL4qiXC73maf3 KBR3J8LlbbN0xkMug+CzERqNBm4088ZQ3EfHb1KRec235h9/665MhCHIBsDMlc8AABMAbADsAIYR DLtSmY8//hhBkKysrE8++cRmsxUXFxcWFtbU1DQ2Nnq93j179oSGhg4NDbldrvnfdzl/4n1Ke3sH hmEvfet5BoPhcrkAABwuZ9++lwmc+PPb75otFgBAcnLim6+/1tvbf+r02diYaBzDW1raXW5XSkpy eloK83qv5NFRw7nzpUPDIwWr81ZkpH92+IvOrm5qvpWenpqenup0Og8e/CxjRRp1Po1G02rUCoWc Mg/cFWQy6es/fGV4ZPTdd9/3+/0kSW5cv27Hjq1VVbUXyyuf3PO41+errq6dMk6vzs+Njo6cFS64 oaGps7O7sbn5maf2qNWqd9/7YMpopMaXzZs3bN68YXTUcOLk6ZiYaOp8sVj0yI6tcrnswoXy1rb2 pTDfgiBo9+7HIvThH+8/NDI6qlIr5QrZm2/80GQyffDh/qSkRJIkBwcHjVPGsLDQjRuKebzrpkdu t/uTQ4ftDodIKHz66d2VldVV1TXU3EKjVv3kH3+EYdhHHx/UqFXUHnsYhtNSUx55ZNu0cfov77zn 9/sXfb41OTXV09P33LNPSyTimRkTDMMLLBMcxwV8fmRkOEHc7Cly7yAI4uy50lWrslZmrTCbLXQa DQCQmBj/+o9eratvOHHi9OO7HoUg6Jmn9kRHRx07frKtvSMpKcFqtZ49e97pdBUVrdZqNbOMUidO nLY7HM3NLd/9zksYhr339w/XFBWwWEwajbb32acAAJcbmtpa2wJBNZlMRmJC/MDg4MJXn4IkyXVr i7Zt3Xz6zLmOjq7CgnwOl/PaK/toNNrH+z+Jio4CAExOTR05cpTP423evGGWJZIgiI8+OkgCcmJi 8rvffWl4ePTMmXPZ2SthGBYIBD947XskSZ44eRpF0cDWhMSE+MLCfAzF3v7LuyazedHnW+DBGA/n GV9+nvG3IiIipFKpxWKh0+kMBsNqtQqFQhRFURQVCoU2m406/g1WA6mHFx0AGwC0gM0LAAAuXbqU m5srl8vz8/NHRkY++uij1NTUzs7OxsbGwsLCw4cPv/rqq19++WWoyBq/Yr53W/bfuk+xWKxcHlck EsIwzONxURS12x1vvfVfMAxHRkaEhCjGxsYBADAMSyTi8fEJkiRJkujt66PR6DKpdK5CWqzWzs5u Gp0mkYgFAr5IJHQ6r03cSZLs6OjCcCwh/kquT5FIuHZtUU1t/V2s1PDI6D//y89gBF6RkX7lqQkB Op0uEgnr6owAAL/P39nZzeGwJVLx3NwMg0NDxulpj9ujVqtkMikCwz7ftf6DYVh3T69IKNRprzgA KBRyHMeHh0dGDYbMFel3sSK3DY7jf/nL3zhcjkIuD4gagoBEIjabzTiOAwBGRkalUumKFelzN3C5 PZ6amrqEhDgOhyMSirQadVdXd/AJg4NDbpc7PT2Veh4zGIzExHiHw9nU1JKSnLgUgjx5PB4/iiqV IQiCUCvXCywTNptdXLzGZrctRG1vBEGQU1PGiIhwBoOhVF7xDK6vb/jJT/+NyWDm5+deiUcFARaL SUMQq9UKAHC53J1d3TqdViS+QTzIpuYWnVbr9fpCQhQkSXp9vmBrgsPh7Ovr1+vDRaIrVrHUlOQZ jenEqdP3vrpfy1dfHa+qrhEKhNsCseggIBAIPB6Px+0BAMzMmAYGBjNXZPD4s+0FOI7X1tVnZa0A AEglEhzDLRZr8M42o3F6bGy8qHA1NRLCMBwTE+XxeGpa6uVymVy2JIK5Pwjj4Tz9t+YZf6u+vt7t dtfV1UVGRjKZzI6OjqysrP7+fp/Pl5CQQB3n8XhUzul54QTADwAGAAIAAUDQlA+GYb1e73A4jh07 NjQ01N7eTvWZrKysdevWvfHGG6+88sqowSBjfAN727L/1n0Km812ezx+vx+CYL/fx2KxBHz+vn0v y6RSFovJ5nCo+RZJknaHQywSQRAEw/CmTetpCK26plYoFMxNECEWi/h8vs1md7s9brcn+AS321NT W1dQkD/LKnZ3CQsL/aefvMFg0NlsTmBGSBCE1+cTiUQAAA6HvXv3Y719/dXVtcXr1sw1xiiVITab 3WqzsVhMkiTpQWPQ9MxMe0fnzke2B8Inoija0dldWXkpJSU5IyPt3tVr/iAIsvfZp+LjY+l0OpfL tVit1HGXyy0SiaiSr1qVtXJl5sWLFVKpRK8Pn3UFFpsVqtO53G6fz2u12Tjca1MoDMOqqmuTkhOD /R+MxumzZ0todNqGDcX3tHHnCZ1OZ9DpTpeLy+G6XE6BQLDwMllcIAiIxSKH3YErFC6Xm5pBpqen fu9734YhmMe7Fo8KxTCSJPlcPgBAoZB/61v/UHrhYl3d5fy8nFkvVBAEabXqru5um82OEziLxQpe lhkZGbXZbOuL1y6601Iwmzat37x5AwIjfD7vylSJBD6fl8VkMhgMr88bHRX50reeP33mXFdXd3JS 4qzC0+g0fXjY1JTR6XRNz8ywOeyA3AiCaGltk0gkWu2157vNZi8vr5ycmtqyeRPlErfoPAjj4Tzt W/OMv/XSSy9BELRq1So6nU4QRHFxMY1Gy87OpszggePfoHwMACizAg4ACoDzuh9hGHY6nWazOTk5 2WAw+P1+AACNRqPT6ZQDYHJSkpA+Nv+7Lftv3afExcWcL7nw2eEjAoEgQh8WGxsDICCVSoLt6oND w4c//9Lv969efeWdmMPhxMXGWG22ysqq9evXcbmz7Rnp6am1NXWDg0Nms2XVykwMw3p6+uLiYpqa W0QiUXRUJARBJEk2t7TGx8Xe9cczBAGpVBLsL3K5oYnACZwgsrOzAAAAAgKhIC8v59TJMzU1dfn5 ubOeKwiCZK5IP336LJPJ5PP5EonEZrMbp6cjI/S1tfWqkBCNRg0AoOrl9Xr/8Me3w8J0Y2PjbWz2 EplyCYQCqVQa+GoymY8cOYpi2KqVmZT9iclk6MPDHA5HRWUVj8ebO2+Oioo8d7704/2fWCzWnOyV gfYaHh7x+/xRUZGUMvT09AlFgnf/9v7g0HBebvalS9XF69dyFjuyYohCoVSGfPHFUYGAF6JQ5OSs AgsrE8odewFrPBsYhvPzc8suVra1d7LZ7NyclQAAOp0uC5IASZLnz1/o7u4FAMTFxQAAAAQkYnHx 2jUnTp7u6upJSkqYNf9gs9lRUZGHP/8SRdG42Gg2mzU+MQEAkIjFbe3tUZERYrEIAED1l+ioO0wc fBfgcNiBKqMoivrRk6fO0On0sLBQhUI2MmpAECQkRFFYkH/u/AUBn6/Xh8+6gkIh53G5nxz6zGq1 paWmwDBMta/H6xkdNazMuqI84xMTBE4cP3GqvPxSfn5uXX29QFBETWgWlwdgPIQggDyzZ1tUbBqO em0zw1JVrHV6gCdSM9jXBZSbmpqCYfiWaaGpeRWCIJSUvt0kAAAgAElEQVT9gFJxBEFmHb/JFVwu g9lcreUlAtINpgGgdorQAPADYAEW3Hy8pG/nzr08Hk8kEkVERCiVypCQEK/Xm5ubm5qaKpFIwsLC ZDKZVCqNi4vTabUwOi1VRiE0um16CEEgBpMLfU0BEBqLzRXLFSEymXxkeAiCaTKpGMexbyLPZW4T h8NptTmioiL8/ltvg52LQCAQCPget0ckEsbHx9HpDKlUog8PC7ysMJkMBEEQBInQ6zMy0hAE4fN5 Wo2Gz+fJ5XIGg87hsBEEIa7CYbNlUmlKShKDwSBIMjMzPSYmGsfxKaNRqQzx+f0x0VESiZiab1ks VrlcBsMwdc3bi0xIkmRXd19KSgqG+QAAAIJEQmF4eFjgNZTNYkEQYLKYcXEx8fFxEARTdWSzWAqF AkEQoVBIkiRVfhIALoejUavi4mIJHGez2bl52SqlEsMwh8MpkYgJnEhNTaammCiKThmNQpGQz+cp FHIYhsUikUp1T7ak3JyJySk2mxvod7PlCUFsFgsASK1SZmSkczhsNoulUiklEolUIuFyuAwGg8lk BhoRQRCRUJialiIQ8HEMj4+LXbEiHYZhqr0wDNdo1BqNihqRzBYLg85AMSxCH8ZkMphMZvTVacdC 4vejg4MjqakpPq8bAMBkMhVyudvj5nA4KclJHA57gWXC4XBYLCZ1TWoKsgD09Q/q9RF0GkySBARB CrkckKTfj8ZER4aEKNhslkwqDdZPLpdLkiSHw05PS9HptNDVvsPhsOUyGY5jQpEoIAEIggQCfnh4 aEx0tM/rk8mleXk5QoHA6XQCADgcDo4TKSnJTCYDAICiqMPhlEolc/vjPWXWeDhH/hCPz8MxTCwR Z67IkEolTCaDkgmPx6NKy+Nyg6sslUrj4mKVSqXX59WHh63Oz2UymVT7MhkMDpcTEx1FrcE5nE6S JGEYDgvTcbkcGEZCdbqFj7a6NMdDHPXgnhmuQAbDyA395QkCdzssUlUsBMEAAJIkXNZxmMbk8GWW 6ZHKpovQicP/u3HH8z63dbirLDp9x1D72ZCwFTzxdUuH58+f93q9W7duvcdCBiZTw6VLr0v5iQDB gO+qNz9yxXPLhbp//d/NH354Zp77E0kC767/LCyukM7kDHeU0ukwVyD/+ngQQhYvhBJTecUlGGHG xuh9Ps9dqtkyN2NsbGJweGzTxmKnw7rwd8dw/M9//mtffz/1VSAQ/PC17y+wFR3H8SNfnnz22We9 HtttBA222x3/9//90Ww2U1/Dw8K+/71vL8peqjuhobFFIlHcdr/7/IsvL5ZXUp9pCO2733kpKiri rhbwnuN0us6XVOx97hm7deauXPB+lMmpMyVr1qzjsJC78ro7NDT8xz/9BcVQ6uuqlVlPPfnEnV/2 nnKH42FNbf2Bg4cCX6m8k3evdAvB0hwP/W6Tz9yp0MbRaIyv2Z/omx7vj07fToX5JAh0arCexuTL 1HEDHRW/fv+XdzP+1p0jlab7/c//8rcffN0JQmHUbQTfmifL/lsPJzQE2bv3KWoNGgAAAWjBXuXv Fnw+7/v7vk2CKwMTBEH33WTrztm0cX1BwZVtRBAAD1vWlxuyLJOwsNCf/OT1wFfGQ9AvMtJTIyP1 ga9LYefHArM0x0MInl++6nnG37obQI899g/btz99kzPu3Xxr2X/roUV4nz+HIAharHCUS4e5ufaW WZYJBEHBzl4PA7P82x5CluZ4CM3TX37+8bfuHAiC7t2M6uYsx996AMBxAoahm7tZBM7BcHxuWPmb ELCBAQCoFyaCIHAcp9PpJEniOE65PlAOizhOkID8Rte/PTAMo9FoJElSd7/Xt1tcqLbDMIySP4Zh geUGGo2GYddWoAL7ZgJfb3hBgiCp4FKUgyl18Ib/eLWJAQzDCPKAy3mZ+xRqTKPGhMUuy93nvq4X PE/71jzjb93vLMffegAor6jEcXzd2qJbnpOZmfHhhwe+8+0X52lqDvgEYCjGYDL+9Z9/LBaLLzc0 Hjt28rXXvufz+U6ePNPXN6BQyLZv3yoSCmpq6js6u374g+/fa1P2gYOfZq9aCQCoqq55bu/NbMMP AOUVlX6fv6Oza+/ep6QSyVdHj18sryQJ0uvzPbFr56WqGrPZDCBAQ2hPPbX7wMFD1Azs63zyCIJo aWk7euwkiqLbt2/JSE9FEATD8bf/8re+/n4cJzAUff3116gdat3dvWfPlYyNj0dFRj76yDaZ7KE2 ISyzBLHZ7dSYdvCTz7JXrYyOXvydlXcXaqy7T+uFINDdjL91v7Psv3VfQCU+Y7KYapXS7/cbDOME gWs0agiCJycne3p6KUuy3e4Yn5jAcTwyIoLBoE9Pz5jMZir3FpUtC0VRykfe4/GOGgx0Gp1Gp+m0 GoNhzGazcXk8lVJJbVOiCPgENDQ09fX1M5lMu91eU1Pf1NxKkqTVaouMjCgqKigrKy8tLROLxaOj Bipp421AkmRfXz9CozEZDKUyBIIgi8U6NTUFwXBUVCQEwMTEpNPl0mk1PB7PYBjzpHoAAFSYsQeG sfEJDEVRFFWrVRwOx+FwUu0rEAiGhocxFJuZMRUU5BcU5JvNlpMnz/AFPLPZvG/fy1KpBALAj6Io iv30J2/Q6LQb+uSNjU/YbfZz50vXrS10ezznS0pjY6IEAkHAn29oaPjixUr21VfNmRlTVlbGBvG6 Y8dONjY1ry9ee68lQBDEzIzJZDIpVUqRUIjjeHC7j41PkARBRRUK6Ab9vn37/zqC+zudTrdYrVOT UyKRSKGQ+3x+w9iYRq2CYdhgGPP6fBq1+r5zvrwlVqvVZDKjGKZShlAhxA1j4y6XSyIWq9WqYPkE xrTAmPDAYDKZzWZzV1dPamoylQA0MJ67XK7R0TEAgFqtFM7J3bR0gOc535pn/K37nWX/raUPQRBH j53o7Ozi8/nbtm6qq2+43NAYHha2ZfPG6pra/v4Bm92+Oj/X5/N99dXxnt4+mUwqEYshCNp/4JDZ bNZqtVTKjmAqKi9VVdVCEGAwGG++8YPW1rbWtg6SIDduKk5LTQmcRvkEeDyekeHRVSuzGAxGXX2D RCKm4hvFx8XGxkSfOXPeaJyOjY1+ZMe26emZ//zVb2+vmiaz+ee/+HVCQjxJEi88vxeG4U8OfWYy WXQ6TXhY2NDQ8JdHj2MYlpaavHnThtsW5hLngw8+9vtRDMeKClevKSr44shXVPtmr1pJ4ERnZ7fF as3JWamQK0aGR7kcTlxsDACgoaFJKBDExETx+XyHw1FVVcPhcpKTEkmSnLXK/MEH+9lspsEwlpqa TJLk6dPnUPTKcqRQIEBRdHJiKiY6KpDMJDc3GwByenqGy+UsTFSq6emZAwc/tVqtoaG6J/c8Pjw8 GtzuH3ywX6NRrV1TdOTLrwK68YDNt4L7+47tW0JDdV98cXRoaEgRonhy9+PjExPvvPPem2/8oKGx ubGxmc/nbdmy8cGbb5WUlpVXVEkl4uioqMcff7Su7vL5kgs0Gi0ne6VSGRIsH8nSc1q6K3g8nkOf HjabLWNjYwAAo3E6eDyfmJg8d77U6/Wq1aon9zy+8GFc5gkMQ/PyQiAI4s79QkiSmJwsr6p6tarq 1dbW/8Jx363/Z2EJD9NlZKQv+28tZQiCuFRVY7Ha2js6e3v75XKZVqsNC9PJZJL29s4nHt+ZnJQI AHC53E3NLS+99Pyrr+5TqZQms9nj8XzrxX/o6+/3+mbvtG1ray9YnZubm03puUajEQqFnd3dAwND cwvQ1d1Do9PCw8NMJnNPT29cXAyPy8UxnHKfotFoGI4DAGAYRmh31O25PO4TT+xEMWzGZJqenpmZ Mb/26r4XX3iOzWb19fe3t3cYp4wlJWUE8Y03S98vkCTIy81eU1jQ3NJKEERw+3q83pLSMgRBlCEh bre7sak5LS2Fz+fv3LmDzWJNT898dviI3e7Y9dgjJACjo4b9Bw4FZ2QK3CE+Lo5GpwEAkSSA4evm Y1NTxrHxicTE+CB3UnJiYvLkqTNqtZoqxr1mxmSqqq612ewVFVVer3dOu5Px8XE2my1YNxagVAvJ df29r9/t9pwvKXU4ndXVtdPT0wAAhUKuCFHUVNfufHT7G2/8IDEhfrGLfPchSTIhPvaRR7Y1NjUT BFFbd3nlyqx/fPOHRUUFs+Sz2CW9V3g83oGBoWee3qPT6QAAs8ZzkUikVqtsNvuFCxeXsmGIJIl5 vQxNTU15vd6EhIQ7udf0dO3ExJnIyMcAAC7XeGfnHyIjnwn8zGBIEGRx3OQDLPtv3Rco5DKFQhET E5WUGE8QJJ/Pr62rFza3CgX8UcOYyWQWiYQQDDGZjJGRUS6HI5GIGXQ6juODQ8M8Lg+Z8+bA5/HG xiegqw7RZ86el0olMdFRVDa6YJxOZ29vX3h4mFgs6uvrLy+/1Nzc2trWsf/AoQ3r101OTkVEhE9M ThqNdyF4kt/nM4waYBimIQiC0EiSGBkdJQEpEYvZbHZ4WFhOzkqNWkWnP1D2jOshjdPTdDqNx+UC AALty+VyWUxmZmb6+Ni4xWLt6+/3+fyJifEAAJ/Pp4/QkwTR1z/gdDoBCZISE6ampk6ePju3NQEA XC5XLpPVX24gCEKukNPpdJ/PR70fd/f0CgT80FAdAADDMAzDBwYHv/jiq8hIfVpqysLs6WHQGVqN evXqPJVKKb5Ru1OhWYN1YwFKtcAE9fcECIJUKtWKjDSdThseHtbb10+j0eg0mkQiGZ+Y1GjUYrFo Kez8v+tYrbaREQOXy6GiuU5OTk5OTlHx1oPls9jFvFdAEESjIcPDIw6nAwAwazxva+vo6upOTkqw 2+23EaxrwcDx+e1PvPP4Wx6PsafnbytWPMdmjwAAABD39U1UVj4PABsAgGEONntrZua35+Y8WkiW /beWPgiCbNq0/vjx0+Pj41KppL2to6m5NTY2OiE+jkFnXCyvIAhCKpXyebzi4rUnTpw+e/b8yy+9 oFar9Prwc+dK164tpJITUJvRwsPCIBjOz8/98qvjKIpS+Q+yMlecOn3WbrdnZKThOB5snbbZ7HQ6 g0pPFh0d9bvf/QpDsQMHP3300e1MBuNieeW586VhYbqNG9cDAALXv72aut2emtr6CH24SqVkMBip qSkff/xJSIjiO99+MS01pb9/oOxiRdaKjKSkRI1GzWaxAQDBGdAeAAiC7O8f4HC5W7dshGG4oGD1 1faVxMbGZGWuqCMvGwxj42MTq/NzWSwWSZJcDufo0eMejyc7e2VoqM5gGPvww/0IjbZxQ/HcFUCN Ri2TS9cUFRw7fgpBkO3bNnO53JbWNgadodVqLGZLbk421fqTk1ODQ8PDwyMDA0MTE5PVNXVPPbl7 1crMey0BjUaVlbXi0qXqqMiIpKSEG7a7VqsO1g0e74Eyzwf39xCFIioqYn3xmgsXykdHDVGREWwW W6vVIAiyafP6I18eKy+vfHLP42lpKbe+7v3G+PgEjhPr1q1BEGTtuqLPDh/5/R/+XFS4etOm9cHy UYTIqTEnMCY8GHC5nFUrsy5V1/K4PDaLrVYr9UHjeVRUZH3d5arqWrFYjKLYYsU3uCUYCuYVX76i ogKG4dzc3OCDfr+/tbW1ra1t1kVFIlFBQcGsjKcez2Rl5b61a/8DhmupIyQJkWQoACEAgJmZlh/9 6Dc/+MFfVq5cOZ9yd3V1AQAiIiLKy8uLioq+br32m8aXb+maoPy36urql+PLLyTfKJ5yYFs+gsBU xgYIurI/H8NwGIYAgKifqNNoNASCICqxAxWsgSRJgiARBEZRNBDKobWt/dSpsz/9pzdJksQwHAAS gqCyixXWqymB6XR6cfFaJoMBX7/yFAgqgeM4QZAQdC2yAHX9+UhgVjzlGZPp57/41Vu//A86nU6p N1V+AAC1HRrHcSpTB41Goz5AEHRfb5YGc+LL/+dbv928eUNiQgLVglS7UO1LBdqgBEJFwaAEHhSy AQokaAIAUClrLpZXUqEfAAD68PC0tBTqv/CrS8CUblAXxDAcQa41NI7jEAQFjGQwjNyLkBBz48sT BIHjBATdrN1n6cb9zqz48sH9nWogqhWoXhYIhkJFY6HSxy12De6UWePh4c+PEAS589HtgSx5lBrA MIwgyCz5UGNOQDcWuyq3ydz48rPitgSP5+CqQMDXh325K9xhfPlfvf/z24+/BUGQzWY7cOBAeHh4 ZmYmjUYbHx8/ceLE9u3bCwsLg88kSbyj4w9mc1N19S8hyAgAuBr3FUAwolZnstncwJBRXl7e0NDg 8Xji4uJGRkb0ev2GDRtMJtPf//53m81WXFys0+lee+01HMdDQ0PPnTv31ltvPfPMM+BusBx/676A etgEvgbPtoMX12adFuiZ1E8IAoGrnZM6Ux8etumqXYq6Do4TwRenVi7mTu4DEbYQZPaPt935ORzO rp2PMJnMwIgZXP6r90ICPwVKeHu3W5ps3rxBp9UG2jTQLgHmPllv0ugIApPkdYPYDeUWeErRrne/ o6S98M/y+bT7rHMeMGa16ayv1OdZBx8wMtLTwPVaGqwGs+pOjTkPnj7AMATDN+7a4HqBLFnmu55I xd8yGo3UZlTKZE2n0/Pz8+l0+rFjx6KiosLCwg4ePLh3797du3fPSidOkrjJ1Jid/e8sVj8AEQAA 4APABgBMdgz3/OK90/v2XTNrdXZ2NjY25ufnv//++9u2bSspKYmIiNDr9fn5+SMjIx999NHPfvaz zMxMHMcLCwsNBkNWVtbdEsey/9bDjEgkSk+/Tm8RBC4qXL0oheGw2fddyrO7TvDm0DtHJBI9tvOR u3jBZZZZGPT68EUuwTJ3A5Kc33yrq6sLQZCOjo6srKz+/v7nn3+eOs5gMHJycgiC+PTTTzEMy8zM 3Llzp/hGPptSaRqLpZDLuRBkBwAAAgA6IGFSZPZMG2v6+gwoem3lbuXKlRs3bjx27NgTTzzR2Njo dDotFsuxY8eGhoba29vZbLZerydJMiMjg8fjhYWF3bkgKJb9t5ZZZplllllmmbvOfPP5UPG3iouL aTRadnZ28E80Gi03NxeG4e7u7l27dt1wsgXDjLi4fTU1rxcV/QsE1QMrACgAJIBsUCwrLD+b9847 p0jy+oUbOh2CIBaLRfltOJ1Os9mcnJxsMBj8fr9arW5paXG5XGq1uqOjIz09/Q4FQbEcf2tpQhBE Z2f38MiIUhmSmBAPw/DZcyUej4fJZMbHx3HYbLPFkpgQ73S6Wlvb0tNTGQxmWVk5jMD5eTk4jl+q qklLTREKBe3tnUplCIfDaW1tUyjken24w+FsaWk1WyyRERExMVGUI0hJaRnlswVB0No1hcHGWpIk TWZzS0tbRnoqdZwEYHBgcGJyKnvVylkOPU6n63JDo9PpSkyI0+m0JpO5qbmFJMmMjDSZVHpL1wqH w9HU3Op0OFNSklQq5fDwSENjEwQgqVSSkBA/PjEZHqbj8/l9fQMkIKOjIi0Wa0VlVUpKUnhY6OTk 1Pj4BBVWqrW1PTExwWKxtLa25+XnsFmskZHRzs5uGp2WnJQYEqIAAJhM5oBvk1QqXZ2fdxPnJBRF W1rbxscnVcqQ5OREJpN5k1o0Njbr9WGUrExmc1tru83u0GhUCfFxFou1o7PL6/VGR0Xq9frxiYnO zq68PMUSbPdZkCQ5V4Zfh8lkHjUYKFudz+fr6ekbGhpms1nJKUlcDqejs3tyYlIqlSQnJ5EkWVd3 OXhnEkmS0zMzLS1tJEmmp6dKJZLGxubBoSEYRtRqVWxMdFdXd2pqMp3OaGxqDtVpFQr50PBIc3NL YcFqoVAQ0A2rzTZmGI+PjxsZGaF0FYJAV1fP4NCwQMBPSUmi8ocODg41NDZRt9aHh2dkpN2kXnNl eBNxVVRcWpGZwWGzAQBj4+MdHV0+ry8yKiIyQj86aujp7QMkSEpOlMtkg4ODBsNY8L+jKNrc0jo1 ZYyKioyMjLBZbRfLKwmC4HI5SYmJfr+PRqPrdJqAzhMEUVJaFqJQpKenBnSDyWTW1tYnJMThONHY 1JyeliIUCmdmTC2tbV6vLyEhLjwsFIIgFEUpHQNX/TWpMt8QgiDmyvDrGBwcAlctVU6nq72jY3LS KJVKkpMScRxva2u32ewajTo+Ic5hdzQ2NfMF1yJpkSQ5PDzS2dktEPBTU5O5XC6lqzQaLSJCr9Nq BweHUlKSgnW+qallbHx87ZoiBuOaboyOjmEYFhqq7ezqxjAsPS31hn25oaFpcGiIunVGehpV5q9r 2bky/LqTURRtaGzOXJGBIDBBEAMDQz29vRCAEhPj5XJZf//g4NAwm8WiKtjW3m53OIL/fcmOh/OH BN8k/hbVo+a6pFALiy+++OINJ1sUDIYoJCRvYKCcMMkIL0ZgGOHACAcGw7SUlHg+n+jpueLSVVBQ UFBQwOPxXnrpJTqd/tRTT+n1+vDw8BdeeEGlUn3/+98XiUT5+fmFhYV8Pv973/veXVy2X46/tTTp 6Ogsu1hhsVjHxiampow2u/3Qoc9RFDMapw8cODQ8PFJSUma32y83NP757XcHB4eNRuOxEyePfHl0 ZsbUPzD4wQf7W1rb7Hb7hbJyo9E4PDz8P//vTw2NTX6/v6qqprdvwOVy19Zd9vn8AAAMww4dOmyz OQAAEATj+HUeP2PjEx98sP+dv/59ZNRAHXG7XJ8cOvzuu38POGJTEARx9lxJc3OLYdRw7Pip8YnJ c+dL+/oGenr6jh07SQ3oN8HvRysrq1tb27w+b0dnl9+PNjQ2XW5ownD8ckNTSWnZ5csNLa3tVpvt q6PHjxw5arc7urq69x/4pLq61uVyV1Rc+uDD/cbpmf7+gbPnSnw+37lzJX/637+43W6DYayioop6 AHd0dl2t1/jJU2eozzhO+aRfB0mSGIahKEYQRFV1bUtLm9vlbm5ptVis1L8E8hhSZwa+njp9dnBo mPra0tI2MDhktVrPnj3f1NxSeal6dNQwM2P67PCR/oGBw4ePTExMLs12B1e9tlEUxXF8rgypWge8 6QmCwDCMckgdGx8/ceI0hmEEQVos1praOofT2d3Td/Toif6BwabmFpfbXV1TV1Jadu58aUtrGwmu bWi32WylpWVDQ8Nut6e/f4AkyZOnzoyNTXg8ntLSssbG5vKKSwbDmHF6ev/+T86XXHA4HLU1dQcO ftbS2nadbnT21NbWu93XdLW9vbOu7rLdbu/t7R8duaLMDY1NDQ1NN1FLql4Yhs2V4ax2v/oVpz4c /uJLh92B4ziO41VVNWNj4zMm0+effzk4OHypqmZmxmQYG/94/yc9vb1fHDlqt9mDxV5VXVtdU+d2 ufv7B50OB6WrJEEMDY0cPXq8q7u3umaWzg8e/OSzs+dLg3VjaspYeuGiy+Vuamr+3e9+PzJqsFpt F8srJyYm7TZ7U1ML1ViUjmEYDq76a35NR0CpgHCzZBjc7rP6RUNjU119A4piJEkOj4y0trS73e6a mrrSC2XNLa19/QMWq/XM2fNNTS2HPv28o6MzeOIyNjZ+vuTCjMk0PWMaGh65qqt2m81+5MjR/v6B k6fOzJiu0/lzJRc+/+Irw9j1ulFb19fXPz098+677x87foqS7ay+DACgdOwmakB1BAzD5sowuN1n 9Qub3b7/wCG/308QhNfrq66pNZsshrGx/QcOjY4aqqprHQ5HT0/vV0ePNzY1l5SUud3uwB2X2nh4 m5Dzy594y/hbt9wKQafzlMrVp08/W+2BAN0LAAAeAAAgAekkbAhCTFxt37i4OOrD1q1bAQCBTZF5 eXl5edc8WqjjCsXN3iy/Kcv+W0uT6pr6uNjo1avz/H4UQRCny8nlcQsL8g1jYwMDQ1KZlMNh9/cP trS0abXq9o5OoUCQkpxEbTm0Wm1hYbq2tnYej8vhsNlsTlV1tVIZAgBwuz1V1bV79uySiMUYhnE4 V15kORxOfn6OXCbjcNizjDcyqWT79i2WqzsWCYKoq28QCgSMOTYegiAaG5uefnqPUhny57f/ahg1 dHR2vfbKPgzH/vDHt71eH4fDuUmV3R53/eWG5557Wq1Su1xOFosJAIiKjMzPyymvuGQ2WzIyUltb 2yVisd3uIAhiYmKit7dv+7bNdrt9fHyir3+Qx+MNDg6NjIwmJMQPD4+4PR7qjt3dvX6/f0PROgRB Au9OEIBUSmVRYQGNhvB4vFl9mSTJ1rb2kyfOmC2WHTu2VpRfWreuSK8PR1FUIpE4HM4zZ883NDYV FuSvKSowmy3Hjp8aGxvbunVTRnoaQRAnT509c6Zkx44tqSnJmSsyjEbj0WMnHQ5nYUE+n8+z2x3v f/Cx1Wozm82RkdelRVs67Q4AMJstp06daW3riIjQ63SaYBmSJFlX33D27HmpVPLE4zuFQmFZWUVp 2cWkxIQdO7YCAPoHBv/rv38fExO1vnjtIzu2kSRZW1ff3NwaqtOF6nRsNqukpGzUYGAwGEwGM9gL 2GicMRjGXnj+OT6f53S6KB/h5OREvT7cZDJ7PJ7k5MSm5ha1Ws3j8/r6BsbHJ2x2+47tm3t7+2RS aUA3enp64hNiGxqbA7paU1On1WrS01NxHBcKA4YZKDo6qqiwgMFkcOfoJ47j1dV1p8+cI0ji8cce nSVDo3E6uN37+geOHz+FYujjux7VajRej/fAwU8BALt37yooyGcxWcPDw8MjoziOrVu3RioRj4wY 9h845PP6vF6vXK4IvmlFxaXNmzemJCe6XG6qsZQhioKC/KbmlqqqmjVrCsouVszS+TVFBX6/f5Zu RESEu93ugcEhqUwKAJienu7rG3hyz+NMJoMgru2M4fN5RYWrmUwGl8ubG9xuZNRw7OiJkVFDTs7K mWlTsAwxDAtudxzDg/sFAKCu/nJ//8Dq/LyUlCTN42qHw3GhrHx6emb16rzMFRkkSR4+fMRsMrtc LrlcHnzTru4eBoPx2M4dNDod9fsBAGw2Oy83h/yHg9gAACAASURBVCTJwaFhCIbCw8NaW6/TebFI uHZNYfP1umG2WBIT4y9VVctkUgiCcRyf1Zep2yEIkpqSnJycyGKx5kbQdbncZWXl5RWXhCLB2qLC WTLs7esPtHt4WFhwvwAAzMyY/vftv4qEwsd27li3tojFYnV0dJ45e14kEj3yyFaRUNjY2Hz2fKlO q4UgODiexZIaD2+fea4n3nn8LQCAVJrOYLzxzvt/BWCW3TUEw0B2NmNxg2+BZf+tpYrVahWJU6lV ZgCA0+UcHh75z7d+63S5tm3dpNNqJBJJW3uHyWQqWJ3X1t4JAFlUWIATxKVL1SiK5uZkV1Ream1t l0qlhrExl8udnp4KAMBxvKen9+Ann3k9npTkpJ07H2GzWQBAKpXy3b+9D8NwUkLCtm2bg55GgMVi RUdFBpYYZmZMXV096RmpPb19s8pMkqTb4xGLRHw+H5DA5/d7PV6BgE+SwO/z3zIoH47hNrtdJpPR aEggI9iJE6eamltoNOTFF54L1enOnSvt7e1TKGQ4hnd0dhnGxr/z7W99cuhwW3s7ivqTkxP7+vqH hkee2LWzqaklJiaqra0DAOBwOmvrL/cNDHDY7I0bi6lck1wux2q1/urX/y0SCfPzc/PzcoKf+jiO f/XV8Yz0tMysDDaL9dFHB06cOuN2u6OjIp94fKfROF1f36DXh5eWlq3MWtHc0jo2Ni6WiM+eLUlN SYYgKCxUBwAoL7/07ZdfMJst7773AQSAVrNWoZDbbLby8kqdThsVGREaqmtr71i7dv0SbHcAQGNj 84zJ9O2XXxSLRRfKyoNlKBQKTp85JxGLJiYmW1rb09NSzpeU6vXhjY1NWZkZAAA+j5ednXXy5Jmi wny5XLb/wKFLVdV5uTlCoQDH8aamlqHhkcLCfIfDcfjzr3iCa+uYfr8fxwmBUEBDECpNDYphH350 gMViqZQh1NrZe+9/5HK5U1OS2ts7u7p6MAzbsL74L+/8bZZu5OXlni+5ENDVGZOpt6+/9MJFpVLx 6CPb9XouAEAuk5ZXVHZ2doeEKNYXr01Ovi6GvsPhPHP23ObNG2Kio1AUnSXDWe1eWnoRx3GSIMvK Kp55eg8Mw7Gx0b29/W1tHRvWr+3r63/7nffUapVMJpPLZUbj9MXyiqysFWFhoSwWa3BoOLgfWW02 pVKBIIhAwKcO1tc3/uKXv3a73c88vUevDz93/sIsnX9u79NNTS2zdKNgdX5Pb79QKIjQhwMAfH5/ W1v7uy4XACA/L0epDIFhGIFhFpv137/7PZPJTE9P3bxpA/VoD3D27HmxRPzoo9sFAsEf//R2sAzF YlFwu2MYFtwvAAAymTQlOfnCxfLs7CySJN/7+4cjo6Pbt22RSiRer/fSpRoMx1JSk70+b0VldURk TOCmTqeTzWaz2WwYhpkMBoqiZovlf37/JwxFMzLSIvThBE5UVFYF67xCIU9OSvrw4wOzdAPHCaNx OidnVW1tPUmSowZDcF9mMMQAAI1GffTYiROnTkfo9Vs2b9DptMESMIyN1dU3PPvMkyqVcmxsfJYM g9td94w2uF8kJyeyWawVGWklpWVG43RMTNTF8sr9+z9JTIzn83kMBmNwaLihsbmwIE+tVpeWXQTQ NRejJTUe3gnzusrg4ODU1NQd3wvatevFo0fL5v6dPFl29uzZxMSFSJFxEzo6e8ora1Fs6SYEeDhR KOTT0zNer9dkMlttNgBAVFTEL37+syf3PI6imB9F9fqwpuYWkUgUGRlhsVhtNodSGaLVqGdMJpfL FRam43K5bW0dGo3q/PkLVquts7O7sbHZbreHhmp3bN/yzNNP1l9upNb4aDRky5aNb/zotRf+4dmW 1tZZK1yzaG5pHRgYaGxsNhjGmppbg3+CIEgiFk9OTk1PT5OAZLNYbDZrcso4NjbG5XFvuXUZQRCR UDg1ZfT70ZGRUQzDAAC7d+/613/+cXJSotvtZrGYWq224lJVVFRkbGzMhQvlKpVSIhFHRUVcuFCu 02ljoqNaWtr4PJ7P56uprevp6TOZzLW19Ww2Ky42+rvf+VZ0VGRVVW1Awt/9zks//emb6Wmpp8+c mxX8hSSBx+PRajUyqZTNZms06oL83O999+WhoZHJKSOO4/0DgwbDmEatZjCYPq+vt6/PYraGhCio sFjKkBCVSulyuYaHRzAMe/X73xVLxMMjo+PjE8dPnEYxbMP6dTQaMjAwlJKSvGTb3ev1cjlcpTJE LBbxeNxgGZIkmJqc6u0bYDKZIqEQJ4jhEUN//6BUKqXsZHw+P1SnxQnc4XD29Q1s37blke3b2js6 HU7nxYuVDU3NBQX58XGxDQ3NsbHR7CCHITabTafTzWaz1+sbH58gSZJOo73yve+8+foPNBq1y+UW ioQsJrOzsysiQh8eHlZecSk8PFwiEc/VjYGBwWBdlUolqanJr77yXQiCO7u6qdvFxcW++sq+f3zz h1KppKy8YpYECAJ3Ol0ajVoiETOZzFkynNXudru9t6/f7/eHKOQAADqdrtNqBQKB1+vt6uqRSqU/ +sH3HXaHyWTq7ev/6uhxtVpVsDrPbLZ4PF5qPhToRyqlcmrK6Pf7xycmvV4fACA/P+fn/9+/b960 AcNxAEFzdV4hl8/VDQ6Xc+bMuckp48iIoby8ksCJiIjw5/Y+tXZtYdnFckrnBQLB8//w7E9+/Pq2 rZsvXqzweNyzhOByucVisVwh5/N5s2Q4q91n9QsAgEwq1WhUDofDOD0zMTn1wvPPZq7I6Ozstlis x4+f6h8Y2LihWBmiaG5uTU9LDX7Ai4RCj8fjcrntDseU0QgAkEjE//rPP/72yy9yOByf369SK2fp fGioTi6XztWNS1U1xv+fvfcMj+s4777vmTlly1lsBXYBLHohCYAFJAiAICl2qlCNokpE2ZYiK3Li WE6cOHmc13mS633iOH7fOFFsp1iWo9iWLFFUsSirkaJEsTdI7B299+3l1Hk+LAmCAEEuCIgAifP7 gGt3MDtnzpyZ2Xtn7vnfPb3Hj5+sr29oamoeNpYTl1tcs+g733nuuT/9E7/ff/LU6WEtoCoqACRm G97AD2vDoc992LgAAJ7ncrKzWIaJx+Pnz9eVz5vz7B893djUEgyGjh49vm3bJ/Pmzamuqkyszrpc zqk5H46HG9ffugEQQlNW+xV0/a2pytIli7d9/MnJk6fT090rli/jOJYhjMHAL11Ss3PX3n37Diys mC+YzTNnFns8bq83gxDidDoQQnm5ObKieDyestKS/QcPFeTnL1++tL+//+jREwghjudrFlV/9NHH iqrOmjXTaDReqKtXFKWxsXnb1u3RWCwjI912tcXOQZfBwoL8YDAYjcZMZhPVhms7LV2y+PfvfaAo anZ2Vk5Odvm8ub/5zW9lWalYUG4yX2szEQBMJuPimkVvvvk7lmXnzC5LT/dgTBBCqamutWtW7fhs l9lsrlgw73Dt56Wls6gGv3/vg8rKCozx3Dmz33v/w3nz5uZkZxmNhjmzS7Ozs5YtW6Ioqqppoigu rFjQ0tL261+/ijGqqlqoadrOnbvz8nITyq6SJM2ZXTrsxxzGeHHNorffeXfbx5/cuXbVqlUrdu/e e+DgYZfLabNZGcIsXbIoGAo7nA5KaVFR4dy5sxVZ8bjTEsKhe/ftB4QW11S3tXccPHhYkiRCSHZW 1suvvLZ33/45s8taWtvWP3hfTm52S0vrlH3uM2YWnz5z9l+f/+nMmTMqFy5obGwebEOM0Zo1q06f OSuYzYJgNvCG5cuW9vT22u02g8GAEW7v6Hj1tc2FBfmA0PZPdvj9fkVR5s4uO3ni1H+98Eu3O62/ r7+1pXXWrBl79u7n+cvL/B6Pu6Ag/3/+52VBMM8vn5ee7mEYhmGZ3NzsqvjCQ4drly9bWj5vzs5d e3JzczDCtbVfzJs3G2NcUVE+rG+YzeZwJDzYVxfXLNr28Scvv7IJEORkZ8fj4uHaz50Oxyef7giF wnAxOPcVGAzGsrKS//7vXzsc9gcfuHdYGw577lVVC2VF4Xku4dSrquoHH26Ni+L8+XPr6uo/+PCj WCyekZHOctwLL/x3c0tLyaxZ58/X3XPPnXaHrfvSF3+i761ateLTTz/79NOd+fl5K1fcgREmDGOx CCtWLNu6bXtt7eezy0qH9XmDgc/Pyx3WN9I9nuXLl8qyjAnmed7rzZwxo/j1zW+pqlpSMgtjfOjw 5x53Wu3hL7p7euLx+Jw5ZcYRzvJVlRUfb//0xImTCysWDGvDYc+d5/mh4wJjcurUmZaWttmzywKB wPbtO0KhMMaoZlHV1m0fv775rcLCgr6+/jWrV86ZO/v8+brsnPzBi5aWlrR3dP7nf/0iNTW1ZlGl w25nGZbjuXnz5kiS9OmnO1evWpGbk62o6mCfz8/LNRgM5eVzd+7cPbRveNxpjU32trYOwjCJth06 lnt6e5uaWmRZPnjwsCiKGOPcnOxhLeB2pzmc9p/9+39lpKffs+6uYW049LkPGxcIIBQKv/Hm7ziO EwTz7j37Emb03DllAz7fz/7j5whQf39/XV39nDllR4+dSPTDKTgfjoek9OXr6+sNBkNm5nWihfh8 PpvNNnU0bceqL28Q3AhhANi9Z5+uL38zuba+vKZpXV3dPr/fbrO53WmapjU3txYW5gNAJBL1+/3p 6Z6Ozk67zWYymfr6+hmGJGb5vv5+jLDdbotEosFgMD3dk+ic/f0DhGCr1RqLxVpb2zWqpXvcNpst EAhijFRV6+ru1lQtLS3Vbrf5/YFBF2aWZa0pKW1t7U6nc9CzQZblRH2CwaAkyxcrTcFsNrW1tSuK 6vG4rdaUaDTW1t6OEcrMzBi5dT5ST1kUxdbWdlVV0tPTU1IsiTrbbDZN0wYGfDzPcRzf1taWl5er aVpbe0eWN5MQkvDmzszMwBh3dHQ6HPaEm0LiiFNOTjaltKend2DAxxt4b2YGx3Fd3d2pLldPT6/f 7+c4PjMznQIMdVZNsaTIstzW1q4ostfrNRj41tZ2URJTXa7Eb9Ce3t7+vn6T2Zybk60oSmdnVygU slqtXm9ma1u7IsuKomRleRVV7e7qjsdFh8PucjmbmlsSa0sY4fz8XFGUDh6qnTmzbHDcTannbjaZ urq6/YGA2WTOycka2oY8z4dC4bb2dqCQlZVpNpv9/kBHZyfHstnZ2Zqmtba2IoSdTkdKSkpPT4/f 7+d5PiMjIxqNtnd0JC7hdDodDntTY/O5C41f+9pXBvXlg8FQZ2cXIdjrzTQYDIN9T1GUvr5+m82q aZrP50/PSJdEqb29PT8/DyEkSVJr6/C+MbSvKorS0dEZDIVsVqvb40YAXV3dqamurq7ucDhiMpsy M9Lj8fjl/gzgsNtDoXBHRwcAysvL0TRtaBvKsjz0ucfj8fb2jng87na7nU5HQ0Nj4ldKenp6NBrt 6u6mmpaWliYI5vMX6hIdnmXZ4qLCvr7+nbv3P/DAg4P68rKstLe3R2Mxd1qq3W4XRWnA58vMSKeU hkIhSZLsdvvIPk8pbe/oGNk3ACDRhgYD7/f7u7p6CEMyMzLMZlNPb69FsITD4b6+Poyxx+MxmYzB YHBw799kNBJC2js6o5FoaqrL6XQMbUOGkKHPnWWZoeNiYMDn9/s1jaanu1mW7erqDkciZrM5Iz29 u7t70CU0y+tlGObEyVMaJYPzIaW0v3+gt6/PYDB4MzMYhkmMZYSQKIr9/QMej3vA5xvZ56PR6Mi+ AQCxWDzRholJZnAsy7ISDAWNRmN3V3c8Hrfb7WlpqYEhQQkRILvd1tff39vbx7FcQUFeIBAY2oZD n7vL5Rw6Lnier6ur53neZDI5nU6/39/X14cJSfd4WJYZDLZtNBhzc7M7Ojr37Dv8zNe/PrXmQznI K+03rC//jy/9ICl76/333zcYDKtWXUco4YUXXli+fPmMGTOune2mMVZ7S0GWhP/Wvv2HdHvrZjKm eD43k4EB37/99D+CwYsHpgoLCv74j59hRtkNfG3TGwcPHU68Zhn2T7/5bG5usuJwI+2tSWT37r1v /W7L4NubEysQRsTzmUTG9NwnkJHxfCaR8fTn8TAsns8kUlfX8PMXfqlcqsYdSxffHMncqTMfyrL8 H//5i6bmix51Dofjz7/9p4OOdF8eU3M+zE63Pf3o4vSc0huzt374P/84Bv2t62abOXPmNSQhpj66 /pbOMBwO+//+/v8amnKNL93HHt3w8IYHL+e8ZQOMLFlSU119OeQDxlM9UMaEM6bnfrty2/TnG6aw MP+ffvj/Dr6dOls3Nw2WZb/1rT8e6izxpQYonJoMzodStF8LDT8alTzJ6ssn9LeSK3G8piilakPD 5p6ePQBw4YKalfXoihUrx1lmkgz131K1hFiMet1P6YwfTdM0jU7NBh/W869dw6GZx+TymBB8UlQ1 EXZ3jHWceK68a3pznguldOqMuzE994lC1VRKqapMiRaAcfTncXGxBW5Sm1+bSekGU2o+RADoytPK N+GiU3M+JISMawwkaW9dV38rQWNjo9PpdLvdN1wfTZOam9/x+89mZVVgHIjFPt206TlB+ElZWVki g9HoBviyfmQM1d/at2//sWPH6E2bYqY3sXisLzxQ13dhmGro9IFSGmgJvfnmW4o8feXf+gcGjICO 7eWn7bhTVLU9EHz11U2KIl8/921Ke0dHOBxDGGDyv2cnh1g8Fg5H+/v7tClgb00KFGhzc+tUmw8F g1ZVOmrYietCITm90yT1tyoqKq7rU39t+vuPNDT80uutlqROAJqdPXf9eqm39wd793IAiqLEzebn qqo2fEmHHIfqb1VWVpaXz5u28/5Npqm56aen/uPsvRcmuyKThwoFr+U9+OCDKdeMCnJ7s3//frJ9 e+X027UZJKhpW9LTN37lK9dVDLmNefvttysqKrKzh5+Mmz40NjYeP378gQemb3h1VVVffvnlqTYf Rvwd/rb9N/xxlKQeRGNjI8Z4mPrzSM6cOWMymcbjwkUpNZmcxcUrAcRESn5+zcWfOfFwQ8Phb//1 P7/00gqPx3ONEj744INly5YJwphlHYb6b/EcpyoxSRyvyqtOMihynBKqpkzTH3MAgFQEDKSkpAyq +U1DTCYTIGSdxqYGACCAlJSUaegsNQjP82azeToPhEQHmM4toCgKwzBTbT4kWng85xcQnmj9rQlR qkAoAHDxeA4CgH4AI0AQMCaJyFYA0Nra+sYbbwDAI488UldXZ7FYiouLjxw5snXr1s2bNz/zzDN/ +Zd/yYwxxuRw/S06Ae5oOkmht7OOjo6Ozm1MkvF83G63wTA8jtJI8vPznU6nz+djWZbjOL/fb7Va ZVmWZdlqtQYCgUT6GHYDEzYeCxAAYAbXvAAAfve733V1dXEc9957761Zs+btt9+ura0VRXHdunX7 9u2bM2dOf3+/zTY201iPn6ijo6Ojo6Mz4SS7n3j27Nlk9E5ra2uj0ejhw4cLCgp4nj99+vTChQvr 6+tFUSwpKUmkC4JwXR2vy4QBJAAFgABoAENMvvr6+r1796ampjqdztzc3LS0tB07djz55JMLFixw OBwsyz733HPf+Maz3rFs/urxE3V0dHR0dHQmHJzk+laS+lvPPPMMQqiqqoplWU3TVq9ezTBMdXV1 IozaYPoYKsgBRAAAQAWQAS7r+8PChQuNRmNeXt78+fO/+OILn8/34IMPHjt2LCMjo6SkBCH08ssv E4Lrj/wu+auNX39LovScrJyXFDvBC3jWes3dVYXCGVku5dgrTt4DbI3GBzSNBVTEMiUcw13pPlwn KwBQOCJw/SBBTasV5ZBG5/NsJkMaZOWQKHGAijimlGPJ9cq/YXpVrUVRF/BTVJ0lci7s2+MDBHwa b622cS4OKETrIrGWmG2RnZiIJmrhU6HwmTDr4GyLbKyNlQdk/wGf4lfMswRLmQWx09eP+5aAUvrO 2bO90ShLSGlq6jyPxxeLvX/hgqppFp6v9npzrNY9LS1n+i76KtyRkzPT5QrE4/vb2rrD4Vy7vSoz 03Cl49RgmYP5ZU072tWlUTo/PZ3F+GxfHwDk2+27W1qW5+SQiQv9oaOjc1uBkotXnaT+FiEEY8xx HEKIEJJw+WRZdlj6tQuhlFKfRqOUdlA6QCmllFCqUOq7wpnqnnvuWbJkCc/zLMuaTKb169evW7du 7dq1BoPh6aefNplMPM+PVaIwNydr/vzykfETKYBMqUIvbm8qFGRKr+ra3aaovw1F+zStV9U+F2WZ 0ncisQZZSZQgU6oBUID9cWlfXFKAxjSKAOilMjUAhdKXQ9GASv2a9no41q5o9NK2qkwpABwSpUOi BAAaXPzI4GuFgkTpZzHxqCjFKT0hyRKlh0TpUFyWAb4Q5ZOiPLL8YbegJozbi5UBbUi6TCkdUn8Y Uu3EvW+JTF05ft8en2/PAKjUt9fXs6UbANSI2rW5s+PXbeFTIQCINcfaftkqdUtSl+g/4Kcq7X6r c2BHv+yXQ0cD0frIZN+BznWQNe0/a2t98bg/Hn/p6NHmQKDR73/1xAkN4Hx//6+PHVMoffXkySb/ ZZ9XUVU/bWqqGxiQNe1kd/f+tjbtSlfCwTIHUzpDod8cO/bSkSOdoRAA7Gpu3tXcPBCL/fuhQ6ru hqijozMKGKGJ1N8aP4Rw/f1d+49tB6KAeGm3k1z03IrI0UGby+Fw3HvvvcM+XlpamniRn58PY3fC Hs1/66Qkb4nEAcBJ8LMp5tcj0QNxKZthHheMXuYKk04BiFJazDLFLIMADonyj3zh+Tz7J1bz25HY gEprDNxsjv2BL8Qj+J7NsisulfNsm6K+HYk3KsodBn692WDCaJmRpwD1cjRCtXMy3RUTn7aY/8Uf fiblYtw9mcInsfi2qDiXZx80G3bHpI9icQfGDwvGA3H5WavJS5gQ1QwIAUClgX1UMO6LSXviYinH DCsf4Ipb+DQq7ouLCCCbZbpVNYOQhwWjTOH9aPxQXFpl4gtZJlH/v7Wn7ImL5yVlNs8+LlwnAPNU QCi1uO5M7f2wV+yIA4XIhYgSUhwrXMEvgpbZKVShakQVSgVhlgAIEEFKSCUm4ljmYCwMY5+i63Y6 QzGz7F2FhQBwprc3JIoAkGW13ltcvK+1dVt9PVDKYFzl9VZlZgKAw2gMieInjY3/+447Uk2m8/39 L3z++ZKsLHzl77REmW6z2WE0qpp2tq8vzWwmGB/t6sqwfOmBTXR0dG4Pkj2fmKT+1vhxOssl6akf /vg3o2WwWgu/JPEtGN1/69OomMcQmdJ6RSUAywy8h5CPovFaUfIyVwSQz2PIerPx05i4Py4tN/IL eHaxkbvPZJjJMhvMxrOS8n40vtLI32s2sACZDDknywDwfjTuIPhRwZLYf+xXtf/PH5IprTRwXoY0 ymqbompA6xVl0IAMUe3DqFjIksOiNINlaiW5lGMXGzgnxgGqpRLCILCjy0uSBMCMkV+jI8sfdrO9 mioBLDfyr4SiT1lM22Nio6wCwIG4VMiSbdH4IntKov5lHGPBqJBV3grHFhu+rIcygXS+1hE47Dfl mdIfz9Akrff9HiaFwUbsP+hzLHOYCk3pGzN6P+wd+GzAdaeLzzSkb8zoeaer5d+bzTMF93o3Y5m+ R/RvFXqj0b/Zvt3C8ytyc/NstnP9/Tubmr75/vthSfp2VRWDsaSqz+/fbzcaAeBblZVlqal9kUgK z2OELBzXFQ6P/I2WKJNnmG9VVs51u7fV1+fZ7QCwrb5+kdd7029RR0fnlgTh5PROk9TfmgjQQw89 ed99G6+R48uzt0bz34pS6mKIRmm9oqoAb0di3arWrqjREQtoIoVMhvyFTdgRk96MxBbyrICQBaMO VXs9HAOATlUFABtGlAJ7yXEqotEsBrsJ4RDIlDoJ/nt7SpuinpDkOKUIQANoVtT4kKtpFJoUhQJN xdhN8FcE49ao+F4kvt5ssGPcqajZDGlX1EFzSgEIa1oGwQAwrHw6QrC/hGPmcuxmBDUGbkdMFCkl CM7LCosgiyEGjBL1lyi8FY5FKO1SNflW2EjJ+kZ25lNehAAxOHQiGGuIYh6LPZISUAKHAqyTM2Qb C/+uqO/D3o6X2+2L7WpETb3P7Vyb2vLTJv8BvyfbeP1r6EwqaWbzT+66yyMIGKGEK9XdRUU/XLny jdOnFU0TVZUj5AcrV1ZmZgIAQcgvit6UlL5IJMNi6Y5ECux2PMKdcWiZ2xsbG/3+qCwjhHojkRM9 PRqlIz+io6OjM4xk/eWT198aPwihL8+iujbD9bcuMZ9nt0XiCIDHiAKYEFJowqkL1Ct341SgR0S5 TlaCmjabYwlC5Tx3VFKWGLBGQQTKAIpTWsAy++NSr6oxgABgsZF7PyIeFeVFBm6FkWMB8Qgt4DmR wkdRscbAWTH6fSQe1ygAEEAUwIjQGqOhS1UdBDMI7Y6JHaoqIGREeJmBfzUc4wDKeTaTIQTQlkjs gqxmErzaZACAYeWvNxuG+vUnykcADCAMwCAEAG5CVhj5oKa5CKEUEvXvVlWZgkgpAohRakRoKrsK I4IAAeYwAFCFDuwccD+S7lrjQgyKNcZaf96cstAaOOiLnI0oASVlvhUIUkJK/+/6xA4RAEwFt8CG qQ5LCEcId2lDECPEYGw1GB6YOfP1kyc/a2qiAD85eNAjCADwWGlpZWbmPUVF/3P0aFc4nJmS8tCs WSMd3gfLjMryzqamv6qpqfJ6KaVHurp+d+aMWxCMDAMALYHAd7ZuZTD+TnV1ru3Gg37o6OjcluAk 9xOT1N+61RnNf2uJgc9lmDpFORiXCMAGwdgiqxqAlyED6mUzFAE4CF5l5Es5hkXISwgGWG3kfZqW Tsg3rOYBVWMQeAhJJTidEDvGf24TWIQW8pyHkLBG3QQzCH3XJrgIRgBVBrZAJR5CvmIxyRTuNRtc BK808gSBCaONgrFNVTlADoyrDNxcnvUQ5x/9JgAAIABJREFU4iLYw+BslqiUZjKEQ2ilkS9mGQaB i2APIQAwtPx8lcQpSJfugkWQKN+CUKJuT1lMqQTzCH1VMPZomoCQGaM5HJtOiIvgZ63mTkUFgIKL lzDfrGc1ZlLvTgVycR0CYZT2gJtzcohBAGDINni/kW3IMnBOzjI3jjlkzDEijIQSgRGIElBYJ2fI vP37/60Og/E/rFjhNl/uhKVpad+prgYAl9G4cfZsUVULHY6+aDTx30KHgyNkcXZ2usXyyvHjMUXx CEJEksLS5RnAZjAMlskR8sz8+bk2GwJACJWlpQkcZ+E4jpAUnv/PdesopRihVPPUHQU6OjqTBSYT qr91qzOa/5YZoxkcQxF0KioCsGNs5zEAyJT+iz9cryiJbC5MvmcXXAS7hujaCxgJmABANkOyL+3u sYCyGAIAMzADADxCQ/Ud8i+9NiCU2BBMH+LAm3qpcAfBjkuvE+UkIAjNGFJaKsGpV+rsDy3fhNA/ +UOBS4uXM1j2z60CgxKvmUS1E/9KZ0j6pbU8A7pYfyNB7iGFZ43wBps6cG7+8hsMxiGbg4ggU74J ALg0jku7vLaKOWwq1L87bxkwQjOczqEpZpY122wAgBByGC8+8UKHY2genpBZLtcz8+e/UFv72+PH i12uXx09Ovjfb1VWrsrLS7xmMC4YEqyMJ2To5apu9+lRR0dnPBCS3PnEJPW3bnWurb81k2UKr9Tm YRH6rs1Ch0SxZ281Tw4nwf/kuEITlrnF7kBHZwLItdl+sHIlpZTB+O7CwsF0cquNaB0dnakJSXJ9 K0n9rWtDqdbdvbexcTMACEJuScm3COGv+6mbyWj+W4OMtEUYBCPczW8xbjkbUUdnwkEAzKUpjpve AbN1dHS+DJLdT5wI/S3a23uos3NbQcFDABCJdJw58+8FBU8M/pvjHIRMsqbAUP+tSDQaDodF8Wao YOjE4nEkIhKcvt9zSAWgNBgMTnZFJhNRFFVNC6hX1RKeFgQ1TVHVYDB4XV3o2xhFUYLBYCAQmOyK TBqRSEQUxencAqqq0qk3H8Yj41K9RgjfJP2tWKzn/PmXFiz4mtHYAgAA9rq6zr17nwIwAoCihIzG dRUVz5rN5r6+PlVV3W73eC53Ywz13zp48GBdXd2YJVN1bghRFF1tMKNzKh9w/NLp6om8/fbbDDN9 Vb78fr/M8/XCqAvMtz0UoLGz89VXX0XTeNW5vb29u7vbZJq+J4JFUezq6nrllVcmuyKTSV1d3VSb D60mmFtw45tylCa3vnVV/S1Jkk6cOHHy5MlhmW022x133GEf4liauFY83svzVoBEyJdYQYEjP/+7 AG4A6Os7/p3v/LPRuLiysvKdd97BGD/99NM3fFc3zFD/reXLly+YP0/Vpu9P7ZtJc3Pzyfc+fqz4 0GRXZNJQKX4RHtj41a+mpIwlxPrtxe7duzHGixcvnuyKTBrBYPC111575plnpvP61qZNm6qqqvIu HVOYhjQ0NNTW1j766KOTXZFJQ1XVF198cePGjVNqPgz72jvOf3LDH5dl7cb1txBCgUDgtddey83N raioYBimo6Pjgw8+uO+++5YtWzY0J6Xq6dP/PjBw9MCBHyLUAwCDLuYIk4yMCqPRrGla4hKJF+Fw +Gc/+5nBYPB4PPfffz8AfPLJJwcPHrznnnuqqqoGBgbefvttVVUVRfnmN7+5a9eurVu3pqWlPfjg g4VDfF3HylD/LYxQNBIUxakbEPB2IhoOIqAMvv3PZIyKBgjoYNTR6UnCyNBbYJp3A4zxNG+BxL1P 5xYAgKFRmKcI46yMJNOkdnDcbndeXl5PT48oiuFwOJHIsuySJUu+//3vW63WwsLCZcuWIYS++tWv Pvvss7Yr5f4oVfv7j1RX/31hYWFBQXVBQXVBVnVBSnWBrSruS/nHf9za3t427IrhcPiDDz4wm82f ffZZU1NTc3PzO++8k5KSsnnz5kAgcOjQobq6OkLIRx99RCnNy8tbtmyZJEmbN28eT3OkpTpzsjwj 9bd0dHR0dHR0dG4YRU5af4sQcvr06YULF9bX1z/11FOJdI7jFi1apGnaG2+8oShKRUXF+vXrR+wk AgA4nfMMhrTUVDNCQQAADYAFiqltINbbc7Curk2Wh68k2Wy2tWvXfvHFF9FoFAB27drV2trqcrkw xr29vV6vt6qq6sMPPwSA06dPv/vuu42NjeNZ3ILR9bd0dHR0dHR0dG4YTU3O3krob61evZphmOrq 6qH/YhimpqYGY3zu3LkNGzZc1djCmJs5808OHvyL5cu/j1At+AFkAAoogGYYcpZUCy+++BGlIwIn 9/a+8sorhBCbzcYwzP3335+enp6fn28wGHJyct54443+/v6EKdba2moymUpLS6PRqKIoN7zod239 LR0dHR0dHR2dG0BL0l8+ob+VsGNYlh3238TG4uLFi6+h0cVxNrd7cUPD7nx7FshdQAFCAGHAmJkz Z9a+w+dray9+9o477ki8EAShtLR09erV2dnZGOMnnnjixIkTRqORYZiFCxcqijIwMHD06FEAeOih h/bs2TMwMDDO9a3r6m9dl2ZFPS7K95n12C9TiL4g3XpMeWQRG5fpf38ib6hmvE78bq1Skom9TrTt mCqrcF8FY2Bh9xl1016ZYJSTitZXMjmp+KcfSItnkooC8vpeeVExyU2b1icodXR0dHRuDAoTpL+F ELr2AWaWFTyepVu3fuVADAEbB7h4TpECDWsBQrTOzos5Z86cmbhidnb2unXrBmNXL1iwYMGCBZdK Y9euXdvd3b1t2zYAcLvdGzZsSOZGrs1o8RNlSoMaZRAwCJkRCmiaTIFHyIyHR2geULXDonSf2TCY x4RRUNNsGCOAoEYFjERKoxo1YWRESKY0QqkFY5+qcQgBUAxIpNRKMAMQ1miMUhaBgDED0KdqLAIE SMBIoTSkUQCwYqwrwl8bjUJtnVpZSLr8dMthJd2O75iFPq9X89Nw+wD9+JgiqzAnB8/IwGfaNIFH 91Ywe8+qb+5X/vxebssh5UKnNisT7zun5qXh3LTJvhkdHR0dnVsQlKS9NX79LQBwOss57i9f/PUv AYad8HQrClRXc+YhcV7T0tJ+9KMfDRpbVyWZPGNiNP+tQ6K8JRIjgBwEfcdqeScSPyxK6YRsEIwz 2as0oEJhMM9dJsNnMfERwegk+Deh6GIDd1ySD8SluTz7B4KxSVZ/Hox8xyr8JBD2ECwDWDEOadod Rn6Fkd8dF7dGRQGjO02Gap7924Ggi2ACsFEwnZbl9yJxO8FPWUxl3PAVR52hWIyoNJvsO6cOhGlF AfmiQbWbwWZGqSlo3zl1lhfLKhxp1HJTMQAQAhoFVaMshxJvjRzacUqdBuGsdHR0dHS+NNA49Ldu 4GobNjx9//1fHe3fQ/2uEEJpaddZTEgmz5gYzX9rb0xcYuAVSo9IMoNgqYETMNoWFU+I8lXtraF5 LsjKTJapFaVMQggCI0Yfx8RChuyNiXcYOApgxSiDIRFKlxr505ISptr9ZuPLoegdBq6cZ1WAA3Hp 02i8mmfjlK4x8sck+bgkhygt5JhqnsubSsdlpyYGFmZn41d2yRTgnnLm9b3KgfNqcQZWNXjrgJzl wkDhwDl56SwCAPvPqT0B6o/Q//MHPAAIBrRyNjlwXuv06cq3Ojo6Ojo3CErS3rqq/tYNXQ9N4HLU hDOa/xZCoFxSmlcBNoVjPEIcQjJc/Tt4aB4V6Hye+0Uw0k20HJY4MAYAM8Z3mwxphLQqKo+QAQGH oIxjO1XVDiSbIRGqAcDWqNihqCxCMqUAgAEIQgQQg9ADRv6wKO2OSzxCNYap26RTAYTA68QRETCC PDf22NHRJm3dAmbfOdVlQXlpGCGQVThcp6oaPL6EfWwx8/pe5VSrlu1CGMGsTNzSS3+7S1/g0tHR 0dG5QRDAGPS3rpvN5/PRWzkAzmj6W0sM/IG4tDsuJb5yi1mmSVFaFUWjoFx5uywCM0ZD81AKFozT GFKvKHM4NgWju418i6KclZWEb1YivwsTBGBGmAOEAKwYA0AeQ/pU7YKkYACJQpzSbdF4h6qWcMxH sfh70TgApBPdg/v6pKagykJSloWznGjpLJKTirNd+HSb9uwa7o/Xss+uZp9dwx5p0ggGnoUUI3qg kglE6cELmisFmXi0ZBaZl4encYQVHR0dHZ3xkeT61tmzZw0GQ2Zm5rWzbd68efny5TNmzJiIqk0C o/lvLeS5WRxzXJS3x0QCcL/ZsNzIUwATQnWyErtkYiKAEo7JSjEPy9OqqAzAQp5LZwgBeEQw3mUy IIAUjL0MyWIIi9D37EIKxnebeAXAiNDf2CwsQjUGfjbPKhRYdNGSe8pichBswTiTkLVGA4dAGP1M qM4gHAN/uIKVVWo2oLvLmcUziNWMvnMvazEiAEAIZmTgb9/Nmg1IUSlC4LaiJ5ayADA/D9sElJaC XvqmwcTrBpeOjo6Ozg0yBv2t62abOXPmVfW3bhVG899iENgQzmOZBRoFAA4hF0EAoFDYExdblIsx Fq0YF3FMYmnqch6A45LMIbTWxCcUxjiEnOTyN3ci/+CnEluDToIT17VfOgGpUFhlNLgZYkYIAASM BNC//scAzwLPIgAgGOwCAgCr6XIDIgROCwIAYC8mGrnEXwQACIPNrLe2jo6Ojs6NgtAY9LeSyTn+ /URK1YaGzT09ewDgwgU1K+vRFStWjrPMJLm2/lYWQ7KYK0RZGQTPpJivmvlyHoBHBeP468Yg+IOJ KEdHR0dHR0fn5jMx+lsJGhsbnU6n2+2+4dpomtTc/I7ffzYrqwLjQCz26aZNzwnCT8rKyhIZjEY3 fGnrOqPpb+no6Ojo6Ojo3DCU0onU36qoqLiuj9e16e8/0tDwS6+3WpI6AWh29tz166Xe3h/s3csB KIoSN5ufq6rawHFcU1NTamrqUMmu8TPUf6uvv9/UxsmSOIHl64xGT09vSOQa/M7JrsikoVAsqqSl pWViu/StRW9vL8a4oaFhsisyaQSDwWg02tjYSMjw+GbTh2Aw2N7ePtm1mEza29tDodB0HgiKooii ONXmQynSO54dPJpkPJ8k9bfOnDljMpnG48JFKTWZnMXFKwEuGjr5+TWQkF2IhxsaDn/7r//5pZdW eDye559//oknnqisrLzha41kqP9WQ0NDPB6HURQfdCaWQCBYi9x7WMtkV2TyoGCOEHttLc/zk12V SaOzs5NSGosND10/fVAUpcHX+H/2/0NyB8dvT9hOdh/dT5un79yLgzinJ/vAgQOTXZHJpKurq3aK zYcGIhZnjOPzSdpbyetvJenmdW0QCgD0XXwNAP0ARoAgYEyUS87pmqZpmlZXV7dp0yaWZefPn79s 2bJwOLxly5aWlpaHH364pKSkqakpGokkf92h/luVlZXz5pYqijL+29G5Li0trXtP7ut9LDjZFZk0 kIpsobSHHnrIah1+PHb6sGvXLhgSQXUaEggEDgdrex/pp2T6Whv2zbbowqiYN339OvhGbtXnKzdu 3DjZFZk0FEXx+XxTbT4M+9pbTm+94Y8nq3fqdrsNhuvHYM7Pz3c6nT6fj2VZjuP8fr/VapVlWZZl q9UaCAQS6WOQPE3YeCxAAIAZXPO6TF9f3969e9evX79p06by8vJDhw4dPnw4MzPzrbfeKi4u3rJl S7bNP2tBsle7wn+L0lg0IorT96f2zSQWDU92FXR0dHR0dL5EJlJ/q7a2NhqNHj58uKCggOf506dP L1y4sL6+XhTFkpKSRLogCKtWDRdcGJUwgASgABAADeBqJl9mZuaaNWs+/vhjVVW7u7t37NiRk5NT VFSEEGpta3NxY1hvG01/S0dHR0dHR0dnPEyw/taMGTOqqqpYltU0bfXq1QzDVFdXY4wRQoPpY6gd B5DYD1QBZICrLYLU19f/6le/ysvLMxqNBQUF69at83q9ZWVlGOPZZWVWdgx+l6Ppb+no6Ojo6Ojo 3DDJ7ieOSX8rsV04eL6GZdnEi2Hp1yiB+jTgKfgvJTEAEoAPhp4MePzxx/Py8hIKFPPmzSsuLhYE oaKiQtO0pqYmlmURQvfee2/7mQ+TqXaC0fS3FEVhRoSFVlUVY6woyuAN6kxlqEqpSgEAYYQISoiK UJUCBcSgoXkuZ6BAFQpAgSCEdb1TndsCDTRFAwCEEGIuDoREVx98S1UKGgW4lIECVSnVKCIIkdth IGiJ2Gzo0mwAw1tg5Ngf3iY6OmMkWXvrpulvEcL193ftP7YdiALipdU3ctFzKyJHB09j1tTUAEB7 e3tRUdH69esTiSaTafny5YOlOZ3OviTczgYZTX/rV79+ZcmSmpkziocmfrpjpyiKJ0+efubrT7lc 1xIy6O/vdzgcSA+/N6n0fdjb+osWbMAGrzHzyUzL3BSq0N4PewIH/DnfzuXcvOyTu9/q8u0dMGYZ 0zdmmGcIoePBrjc6xU7RvtTh3uBhLEkNFh2dqUz4dOj8989hDrMO1v1wunOVEyHkP+jvfrPT+0fZ 5hlmTdJ6f9/T91EvMRP3o+m2KpvYHu98vTNyOizMtqRvzOA9U+jI2A1AFXr2z09LPRJika3alvmH WUwKI/VKrS80m4uFtPVuzOFhYx/zeFib3B52p87NBCFgkjEDbpr+ltNZLklP/fDHvxktg9VaONTd vry8PJlA2kkymv9WS0trS3MLwTg3N4dl2WAw1NHRcebMWavVWt/QIMtyT28vQ0hvX78Yj6elpdls tpaWFgqQnZXV2dX14x//25NPPlFYUKBRzeV0NjY25eXltrV3yJIsy7LXmzGlJEZuV8Ru0bnK6V7v 6Xm3u+e9HsvcFLlf8u0a0CQt8EXAdWdqrCnm2zvgfToLG0m0KWoqNve8200sTO5jGbG2mNgeZ2Ze PfCAjs4thBpVDZmGgv9d5N/n6/ldl2O5gypa3wc9VKMDO/pMBSYloHRv6fI8kmHKM0brI5qo+Q/4 xc549nM5SliJ1kdveXtLo1KPVPB3RaDRpp82OZqilrKU4OcBJaD49gzYlzl4Dz9s7LNOblibENP0 FUjTuTEQBiYZK/2m6W8BoIceevK++651DnaovYUQmsCIjaP5b6ma9tnO3fsPHLrvvnvmzZ3z+uY3 z5+/4A8Eliyu0VTt5MnTA76BSDhyuPaL1NTUO+9cFY3Gdu3ao1HtzjWrB3y+L44cLS4uqqtrYBhm 5YplP/7Xn/zk+X9+8cWXRFFSVGXNqpV33bVmom5B5xoEjwYxT+IdoqnABBoEDge4VC6l3Bo6EbRV 2TkXZ8gwBA75hRKLtcKGMBLKLMEvgoFav2VuijHXNNnV19GZGKKN0d73euJtMS6VQxgFT4YwjzPu z+z9oCfWHONcnLnQHD4ZorJmrbRhAzbmGkPHgv69Psu8FMvs20EkT5O0gR19QIERCDES2SdFzkdc d6aGToRCR4PcWtewsa+J2rA2mew70Ln1wDg5Wb2bqb+FEOKuyTjLvwa5OVnz55eP9N/CCC1ZUrNq 5fJPPtmhqurxYyee2PgH5XPnAkA0Ftu6bTshTPGM4qxsb3a2Nz8v9+DBw/UNjW2t7fv2H1h3z12z Z5c9sfExjJCqKIqqyJIMAJTS5cuWrF296osjR7+8O9IZBuKQrdrmftCtBOWuNzv9B/wdr3b0vNsT Ph3iPbz3j7KNuabgkUDXpg6qUNfa1LT70zSRdr3RFfw8MNl119GZODAIsy3eZ7OpTHvf7/bt87W+ 2DLwWb9vzwAxkaw/zrbMscQaoq0/b1GDimVeSvrGDMbB9n/c1/dh72RXfQKgsqbJlLGzGV/zGrKM kfORnne7O15t9+0Z6HilXQkqw8Y+k8IMa5PJvgOdWw+EJ1p/y+VyjbtWk8Zo/lsIoXSPBwBCoTAA WG3WlpbW3r4+s2A2GAzV1QvbWtvml89bs2rlvv0HPt6+w263zZo5Y8GC8uKiQgBIsVhCoZDFYmlo bNy372Ds0s5sV3cPy7KCoG8m3iTsSxzep7MAACj0fthjniXYqmzERMKnw4GDfs7Nh0+GhFJBCSmB A36gNHg0QFWwVduidZF4x/X303V0bgmEGYL361mJ18EjQcTg7G/lck423hoPnw1HG6Ph0yFzkQAA XW90ajIVG6KxlljKPKvUIUYujEFBespCBCbjq5m8mwcANawGPw94HktPmZeixTXfPp9/v49JYYaO fTWm+vb5hrbJZN+Bzq0HIROtvyUIwowZMyaibpPAaP5bXq/XaDICQHZ2FiFk9aoV2z/9TFO1VJer tGTWouqq/fTgm2++3dHZ5fG4775rIcJ406Y3Pv74E57j8vPz7rnnzmPHTyyuWdTY1DwwMFBUWIAQ 0jTt/IU6wWx+8MH7JuNepx2ck7t8DlGhYqfoWpuaMi8FEJhnCG0vtRIDBgRN/9pIBJK+MQMx2JRn 6vhtR+RMWJhtsdVM2La1js4kQkzEmHdxc5yqVOyMWxdYnWtciEGWeZrUJ2lRlXWwrb9o1uKa+yEP a2Mxj317fd1vdhm8Bs+j6ZNb/wlBKBXwJWlGOSBrMvV+NYOxMkABG0n4ZEgotXS93jk49jGHOSc3 tE0mt/46tyIMM9H6WxPoTXXzGc1/65mvP4kQQggVFuRjjJctW7p48aJEytq1qxiGeeihBzRNo5QC IIYhAPA33/supRRjjDFeuWKZqqoMw3zzT/4IADRNYxiGELL+/nVz58weqTSh82WQ9oCbahd/lSIW ZT7lRejiuW7GyuQ8l4sIMmQa09a5ASChB8FnGHL/Iu+yQoSOzq2PUGYxz7joMoEISr07LSH0AACY w95nshACQMi+yDGohsCwTOZT3syvZV5UQ7jFwRwu+NuiwRsxZBpyvpWLWAQAgMC60JpSnoIIumLs I7Avcdiq7bo6jM4Ng5PcTxyT/tb4qgSUqg0Nm3t69gDAhQtqVtajK1asHGeZSTKa/tbgvSdsI4TQ MM2thF01NGWoFYUQSrxNaI8l/j5w/73ZOVm6dtfNA8FQm2mY/XRx8kUwbCa9bQSHdHQGuWhbXHxz 9XGBWARwZfptNBCGWY1XNMil/w4f+2h4m+jojAmM0NTS39I0qbn5Hb//bFZWBcaBWOzTTZueE4Sf lJWVJTIYje4vr8eP5r/1ZbBgQflNuIqOjo6Ojo7O5JOkvXXT9Lf6+480NPzS662WpE4Amp09d/16 qbf3B3v3cgCKosTN5ueqqjZwHNfU1JSamjqxylV6/EQdHR0dHR2dCYfS5PYTb5r+FqXUZHIWF6+8 qCgPkJ9fA0ABAOLhhobD3/7rf37ppRUej+f5559/4oknKisrb/haIxnqv3X+woVg0Kco8gSWrzMa fn+A9BJh7/Q9qolU0PzaoUOHeP7WFpMcDxcuXJjsKkwy0WhU6ZXN+0zJCfXcnrBdjPGYke2Yvr4W TD/p6ujatWvXZFdk0lBV1e/3T7X5EKshGzOWANBXomnAJONvdTP1twAAoQBA38XXANAPYAQIAsZE UdREuqZpmqbV1dVt2rSJZdn58+cvW7YsHA5v2bKlpaXl4YcfLikpaWpqikbGcHp5qP8WQigl5Rb2 /b+1UFQ053xo4bGGya7IpEEB7ejl1I8+gokYQbcqkgQAcPbsZNdj0iCUeo2uR/Gj140zextzCA4V sAVOcq0gabc3vai3qWUndP9+sisyaWCAoBz8hXhcG4d9M+FkKKY/Yhff8McVhTLJOLgnr7/ldDp9 Ph/LshzH+f1+q9Uqy7Isy1arNRAIJNLHoFmaaGoWIADADK55Xaavr2/v3r3r16/ftGlTeXn5oUOH Dh8+nJmZ+dZbbxUXF2/ZsiXb5p+1INmrDfXfKioqKistlqWb4culYzJx0rngHVn1k12RSUPR8MnO /EWcyTqNv2gT3DGNw1sFVPW8ICxdunQ6H1tua2ubO3dufn7+ZFdk0mhoaBD37ZvOA0GhdLcUilRH 1RR1sutymagfwTiW4BWFTrD+VjQaPXz4cEFBAc/zp0+fXrhwYX19vSiKJSUliXRBEFatGi64MCph AAlAASAAGsDVTL7MzMw1a9Z8/PHHqqp2d3fv2LEjJyenqKgIIdTa1ubixrBacIX/FqWyJIliLPmP 69wwsjTClNbR0dHR0bldUJSJ1t+aMWNGVVUVy7Kapq1evZphmOrqaowxQmgwfQwV5AAS+4EqgAwQ vkqW+vr6X/3qV3l5eUajsaCgYN26dV6vt6ysDGM8u6zMyrYnf7XR9Ld0dHR0dHR0dG4YNUl7a0z6 W4ntwkH/g0GJqWHp1yiB+jTgKfgvJTEAEoAPhm59Pv7443l5eQkFinnz5hUXFwuCUFFRoWlaU1MT y7IIoXvvvbf9zIfJVDvBaPpbOjo6Ojo6OjrjYWrpbxHC9fd37T+2HYgC4qXakYueWxE5OqinWlNT AwDt7e1FRUXr169PJJpMpuXLlw+W5nQ6+5JwOxtkPPpbAU1LwViloAA1IF0TbwqhahCOU6sJaRT6 gtRpQQSDP0otBoQRhGKUEDDzCADCcRqOAwBwDKQYEUOgJ0CtZsQz4AtTmxlN5QcrqepALAYABGMr z3OE+GIxUVURgJFlBY5DCPWEw4nxgwDSBAEBRGU5LEkYIQvH8SN8hgbLHMyvaNpALGY3GlmMAaAn Ekk1myOSxBHCTQHPs+5IhFKKEBJY1sxxo7VJIrPDaOQIUTQtKIqyphkZxsLzI59woszB/JTSkCQR jM0sCwBhSeIIYQnxx+P2scw2OjpfHqONfYxQCs8bGCYsSeFL3skCxwkcRwEC8bikqhwhVp4fOdkN jp1EfgCIyrKsaRaOwwhJqiqpqsBxiTlhCs+Ul6Ag9YgUAGHEWBhswABAFSoPyKydTUjgaqKmhBQA YCwM5sd7kgklGT/xpulvOZ3lkvTUD3/8m9EyWK2FQ93ty8vL8/LyxnPFoYxHf+vnwcg6kyEF43pZ WWHkz8lKPkPYqfz9PD2gAG392s961vFoAAAgAElEQVS3yX/zEOePwF/9Jv7dB7g5OeQ/P5LXzCEF Hvz8exLB6M/uYe0CeuuA8vNtcoYDpaagRxexS2aRP3tJvHMe+coy9v/fIj1Sw8zPm3yTYjSOdHV9 8/33s61Wm8FwZ0HBI6WlP9i9+0R3t4Xn82y2PywvdxmND23e7DKZMEJpZvOPVq9mMX7n7NnPmpoQ QncWFNxZUGC58vT1YJmJ/HaD4Xh3978dPPhIScm6oiJF0763ffs/rVr1UX09i/HG2bMn694TSKr6 9S1bNAATw8x2u/+koqLR7x9sk7X5+Y+WlSXaxMxxAPCtysqVublHuro2nTzZFQ6XpaU9Wlqab7ej EWVSAI6Qb1VWrsrL84viv+7fTxD6s+pqu8Hw1pkzLMar8vL+7rPPfnb33VPB6NTRuTz27fan581z Xhr7JpZdmJHxjQUL3jpz5ue1tR5BAIB1RUXPzJ9/vq9v06lT5/r6cqzWDSUl8zwe5spNrcGxk8gv qepvT5w40tn5V4sX59lsR7q63j9//m/vuCMxJ7iFqb5NJPWIRx89wrpYYiTWSpv361nETEInQi0/ a3Jv8LjuTkUAXW909m/vwxx23Znquit1nFfEODm905umvwWAHnroyfvu23iNHEPtLYTQBEZsHM1/ 64yknJRkG8blPOskeEdMrDZwHYoKAPksc0FWGmWlUVZlCkaEzAjti0s/9oe+ZjHdZzbqs+/kggCs JsQxcKJF6/LRcBz2n9NMHJIVahdQQ7cWjoOi0gtdWkUBEWV4cjm7cSmzaY/8yQllySzSPqB9cgKW l5JwnEpTW4uNUlrt9f7L2rU7mppePXFiw6xZkqr+3bJlRU7nvx04cLSra1VeXprZ/PL69QmbgCNk e0NDVJZ/uGoVBXj7zJnDHR0rr/z1kijz+TvvTOSXVPWTxsaytLSdTU135OQYGcYXj1MAUVGmyHkH lpCf3HWXSunf79jRFgwm6v/jtWt3NDa+dvLkwyUliTapzMwEAIJQUJI+uHDhD8vLc63Wo11db50+ /ReLFg37mkmU6REEghCltH5gICxJiqZd6O+vyMhI3DsF6BmL9IyOzpdKop/PcLme37//yKWx/5v1 68/39/9w9+6vzJkjKsqTc+c+XV4OAAghRdPeOH16RW7ud2tqGny+zadOFTgcw9ZrB8dOYumrOxI5 3t1tMxhq29uzU1Iopb54HAASc8LUhwJwadzs/5kbuRBp+FFd+uMZiEUDO/qFUmFg14B9qYMY8cCn /c6VLucaV/RCRI2pyS1PjUqy8RNvpv4WQmgMghETymj+WxpQBehRSepS1T8QjK+Fo7M59pAoAYCb kDfCMTMCv6YBQJuivheN320yhDUq0umsWTiFMPNofj7Zc1qNSfSucnKyRXVZwJWCrCa07ZhaVYQR gr1n1FmZGADe2Ccfa1ZlBe4uZwDAbEDz8vC7tYqsTPZtJMH+trbvbtsWU5RyjwdjrGraTw4edBqN FKDI4QCABp/vf23fjhESOO6va2ragkGMUKrJBAAsxi2BwFXL/Mtt2wSO+6uamrZgMCrL9xYXv3f+ /MG2tuW5uTf5Bq9LWJJ+sGsXRshlMjlNps5QKNEmQVGcn54+2CaJn/WPlZYWO51n+/oKbDYjy+bZ 7f9VW6uNEMhJlMkzzGOlpfPT0w+1t1dlZiKE9ra2zkod709eHZ0vg0Q/TzWbgdLBsf+97dsjkjTX 7U6s775x+vSp3l4AqMnK2jBr1qne3j+cN8/MsoV2e93AgKQOF2IYHDs1WVmPlpbuaGzMt9vnp6fv bm7uiUZv/j2On1hj9Pz3z2oitcxJISYSPRdRo2rqPWm9H/QEDvkdK5xpD7oDh/yxpqhztYu1sjC+ n1QkyfWt5PW3XC7XuGo0qYzmvxWntFFWj0lyAUsBAAOSKJUocAhESjsU9f+xW7rUy4cnK3g2lyUr jVfxBdG5+bAMFKXjLYcVBsPquczxJm33GXXdAqbTRzfvk1kCGgVRgtVzGABYUEDuKCFbjyilWZgC 8AwsmUk+OqqeaJlCsnujUWC3f2XOHCPD5NntBCGE0Jr8fCPLnuzpybZaAcBtNj9WWprwtbIZDAk3 Do1SDYDB2HA1zacCu/2J2bM5Qowse6Ct7YMLFw61t/dHo33RaEVGxk2/xevAEbKuuDhDENItlnRB 6AyFCuz2h0tK3jlzZkF6OgJACK0tKJidlgYAhQ4HpdTEspKmGQDiimLhuJFjNlGm22wucDjqfb7N p06xhGiUioqyehprROlMZRL9fI7b7TQas63WgVjMbTZvmDVre0NDocORcL6syMhYP3MmAHgEAQFY eV7SNAoQV1WbwYBHOMMMjh2PIPREIu+dP98TjW6tq+uJROZ5PHajcRLuc3xwabznkXRiIoYsIyLI f9Df91Fv4LBfHpDlfslWbbctspuLzZGzkc5XO1gHCx7LeC6HUHLrW8nrbwmCMGPGjPHUaRIZzX/r c1E2IlRl4PpVTQPIZ8neuHhclCsMLEYgYLQzLnaqV3wfpxPSpaougnWTayqQbkMCDwihnFRclI4P XlCL0vF7nyvfWMMuK2WAwq7TymenVIRooQffOY/hGfjkhHofjwAgy4VnZdKXd94Ca+QeQaj2egff YoTmuN3zPB6M0PaGhiqvN5EIALKmyZpWlpZ2oL19Z3OzomkapbOvdtJlsMy6gYHuSORnd9+dbbX2 RaO/P3/+SFfX4PmVJr//QFubmeNKU1NHztQ3DY6QqsxMzxDfEY8gLMvJcRiNH9fXJ75XBlE1zcxx i7KydjU32wyGtmBwdX4+GbFCP1imrKq/OXbsGwsWLMvNBYBdzc2fNTYihBL7sxFJOtTezmA82+02 s9M3Fo3OVAAjNDstrWrIV7aZ45ZkZxc7na+fOnW0q0ujlFwap4qmYYTWFhR83tHREQp1hkJLsrOF EbtMiTKrvV5K6asnT64pKFiTn29gmCOdnQfb26u83sRcQCn9orPTYTTm2WxT3IuLmIm10oY5DADR uqjUI858vsSQbZD75N73uwOf+5WAgo2EalSLq3QihFcnWH9rAr2pbj6j+W+tMRrei8Z6VW0uxyKA DWbjrri40MAWsIwFoftMhuOSUsGzDoIxwAKeIwg9JBg7VK00EY9IZ7KxmtH6Klaj4LGhdQsYrxOn 21GGHd85jzgEBACr5jDvf65kOrCBQyyBpSUMxkpvULtnAZNihGWl5Lm7WVfKlH6YiXX+oSlLsrJc JpOBYe4tLv6sqSkmy2Vu9+unTgGA3WAoTU0tSU0NSdJ758/vaWn5TnX1rBGL04NlJg79zU5Lm5+e zmDsNpsDoqho2t1FRQLHzXK5jnR1/fbEiVybrWTyttgQQuuKioZ+TyTqjxEqTU1VVLUtGKzMzDzY 3n68uxsAHi8rq8nKureo6K0zZ/7twIGFmZnfW7x4mLE4tExZ0zIsljsLChxGIwCsys9///z5zJQU AyE8IbPd7tdPnWIwTjOb82/laVDnNiAx9gff8oSszMsjGGdaLPcVF5/q7S12Oo91d//2xIlE5kKH Y3V+/rvnzv3r/v1mlv2HFSuMI1a7B8tUKTWzbGVmZo7NhgCW5+X54nG32Vzj9SKEarKyPrhwASH0 eFnZVLa3MIcdK5yIIAAACoBAKLOklKcgBvFpvBKQAcAyN6Xn3W6pW3Q/nG7MM8L4ws1oVEMfvPVf d97/lBj1N5/dWVR+f9Opj905CwT7FUtZJ0+exBhfVw9i586dM2fOHI8eBABQqjY0bO7p2QMAFy6o WVmPrlix8gaL0tRztW/mzFzG8qbm0ztYFptTUjG5uonJGqzBGBMX1Zyc7N27PsOEn1Gcp+vL3xza 2zsbP/vHjTMPTnZFJg1Fwy/Urv4KN+vmx/OJSNKL/5e99w6P67ju/s+ZuWUbdhdYNBKFBEAALGAB K0iRIiWSahRFUdWUrJJEcRI7tuPYyeskz2v/3jyOncTJqzivU/yz41cukWApksWoWaJkSqLABkoU G9gAEJXofdstM/P+sQAEkgC1JCAuiZ3Pw4fPxd25M+fe3b177pkz3/PRR2d6eh5fvLiqubmhf1j4 LpbjdS2nCd4PhSBB9XzebWh4oaZmUWbmvIyMF2pqRvc/vGDB2vz8a2bGAGO/9Hj+4OtfT+Z6Ps8+ +2xFRUWS1/PZ/y//8kjKpGavro6TXV3/cfiwW9O2lZb+4uhReyTOsiYvb0dZ2TUzwxbib82OvV9v va7q+eT2e756dtOMnAWKosF4UXzbMrrO1xWXb0VCAYBzq+PcIUVPSZ85t77mg6df/M71pb/FudnY +HJ//6m8vOWEDEQiv62s/LLH84OykXfa6cz67GJGk9HfkkhuUFyq+sTixQ0DA3ler1vTQiOqPLEc r8Tads2oyM3N8ngQINXheHSMsMWctLQEWiWRXGOKA4EvrlgRtqzZfv/DCxaM7s++jiNVNwpcXGf6 Wz09h+vrf5KbW2GabQAiP3/x9u1mV9d3qqo0ANu2o273l1etul/TtIaGhoyMDPeUPgpPRn9LIrlB QcRUpzMWxxo7B5FUOBRldDr1ep4EkUg+UxRCRmfDxyaDSiZPvP7WNdPfEkK4XIGSkluHFeUBCgvX AAgAgGiwvr76K3/+/Z/+9Jbs7Oynn3760UcfXbly5VWPdSmyfqJEIpFIJJIpR8Tpb11L/S0AQBwA 6B7eBoAeACfAIBBCbXt4Npdzzjmvra2trKxUVXXp0qXr168PBoM7d+5samp64IEH5s+f39DQEL4S EcKx+lvVhw6drT3NLtEgkXwWhEPh/p60Z2uWJtqQhMEFtoZdO+1w8qbtAJw3TURsuaKS9tMLQ4jG cPj5559PtCGJ5MyZM4ODg16vN9GGJIyhoaE2w3g20WYkEA7Qa/HAq2mgXEcLw/2KAyajgROnvxW/ /lYgEOjr61NVVdO0/v5+n89nWZZlWT6fb2BgILb/CuRMYzdeFWAAQBmNeX1Cd3d3VVXV9u3bKysr y8vLDx48WF1dnZOT8+KLL5aUlOzcuTPf3z9vWbyjjc3fmj179qJFi4ZDa5LPmPOt50/2v1cxszHR hiQMJrDNmrXo/seS+WfmyJEjnPPy8vJEG5IwQqFQ365dy5cvT+Z8+aGhofnz508yNeWGprW1VQhR cdttiTYkYTDG2l5++fElm6+r+6EZ6uKDJ67++Dj9rfj1t8LhcHV1dVFRka7rNTU1K1asqKurMwxj /vz5sf0ej2fjxrgn7IIAJoANQAE4wHguX05OzubNm3ft2sUY6+jo2L1796xZs4qLixGxuaUlXbuC eNvY/K2MjHS/12ma10mdkmmOw0G9WqTQ35NoQxKGzYlLg4KCAp8vedMHW1paACCZF6YNDAzoul5Y WJjM/lZKSkpOTk4yfwwAoLm5OZmvgG3bLpfrersfBvv0pppJ+FtTrr9VWlq6atUqVVU555s2bVIU paKighCCiKP7r8A6DYYV9BmABRAcp0ldXd0zzzxTUFDgdDqLioq2bNmSm5tbVlZGCFlYVuZTW+Mf 7YL8LQGcc8ZuhDIuNz5czttKJBKJZPoSb/1EznmciVlCiNh0IR2REVJHpJYv2n+ZHkQfB11A/8gu BcAE6IOxlc127NhRUFAQU6BYsmRJSUmJx+NZvnw557yhoUFVVUS8++67W0++EY/ZMSaqnyiRSCQS iURy1cRbz+ea6W9RqvX0tO878jZQG4yR6BsdztwKWeHR+iFr1qwBgNbW1uLi4u3bt8d2ulyuDRs2 jPYWCAS6r0RASOpvSSQSiUQimXLi9beumf5WIFBumk9+9x9+PlEDn2/O2HT78vLygoKCyYw4lon0 t5ptlk6J80I92V7OmYBezgsVql5VwTgBcMK0LAEUYQalgUsrt11Ik81mUqqMlB84Z9kFqtJis+6R 0o25Cs2gpJfzNpsRwDyFugn2cd5oMQKQTskMhU7B8tEbDYtBUxcvyCJCQE0LL8xCt47NPdzvQpeO 7X3C5iI3QCiB7kFR284Rwe3A2RnoceDxJj4jFdNSsLGTZ/jQLUuQSyQSieTKoXHOJ14z/S0AvO++ J7ZufeQyLcb6W4g4hRUbJ9Lf+o/B0L1u5xL9ghq0b4UNW4iqqPnXad4MejU/w92M/2XP4EJdFQA+ JF/0uVMmLm/NAOosO5MSBTB27D/0B3+Q7vvRYKif8zRCAGCb2+km+LOhcIfN0imZp6qbXPpbYeOV UGSepmZRstGpF6pJl4fb3if+6TXz2w/pPUPi6z+L/tX9+rJC8uNd1t3Llfx08r9fNW0Of3mfluXD lw/alVXWvFxq2WLTIuWeFcqf/8K4dSH96hbt6VetR29WVs651sV2JBKJRDINULXrT38LEa9AMGJK mSh/iwF8EDWOmOZ2tzOFkBOm9X7EqLPYIl21QQxwftayZyt0pvLJj3FIiJ8Phdc5tDqLLdVVDnDU sLa4HT8ZDHkIOhC3uBwAkEnJX/pT6m37XwdCphBnLLYzFFUANrr0hZq6MxQZ4MIQ4g6nI1eljTZb KkSIizfC0QHOBzkHAALwuMdVrqsAoCD2MX7StB7yuJZoag/jCiIHscXteMDt2hMxfhsxktDf8rsh J418VM86+oXfjftOM7cOuoqZXqxt55oCqoCaZp6eQrmA+1apn1+vPF9lf3SO3bNCCRviWCM/2cKZ EEksCyWRSCSSSaFrEJd7lJWVFc+0XWFhYfpITYwbkcyMwKy87EvztwSAKYAD7ooYTMBLwYiGqCIA gClgd8ToYCz1wpm6MBdVEcOD5EPD7Ga8l/Fqw2RC7ImYloBOxj8yLAA4Z7Ov9vR/r29oqa56CKYR stqhZVDyYjBiC3HIsHoZD3HxViTKhKiKGqaAj02r0WY+QigiANgAPxgIfrG7/4vd/bsjhofggx7n 3qjxfwaC3ZyPyodpCKmUtLNkdBmcOi4tJHtOslOt/M5ypbaNHz7HAyno0vG9E6wsnyyeTfacZIMR AQDPvGt9/gfRNz62Ny2iAOBx4Lr59NVDdlQm9UkkEonkatE0OsX6Wx6Pp7S0dCpsSwAT5W8RgJsc GkF4I2zc4xLdnD/gdMWEIqJC1NtMR1QvqaLtJDhDIRTAECI0kufvIHCrU38/YjTZbI6qFKj0f6Z6 3w5H/YQwgA7G3gxHOxnvH4ldLdJVAXBgzK99L+MzFFquq7sjBgAoAE953WWaCgBugipimaYu1LQj hlUZDM/Tht9fDhAVInUq1P9vOBQCBZnk2T22QuHeleTgWfbBSfb4BvVsG991xHbpSAiYlrh9CRUC PneTcksZfWm/7XUiF6AqsLyIvv6R/VE9B1nnSSKRSCRXBVXi87fi19+awmyqa89l6idqsWCSEAhY oiqvhiKNFlvp0LwE73M7qiJmg23PuWSqjgAs0NQ9USMqPtGycCAiAgMBAAgwk5L7Pc5XQ0a1YdoC uIAiVTlsmBYAB6iKmhRgbM85Cn0tFO1lPCoEAAiA/VGzjTEAWKlrMxW6N2qaQnQwnk2pBggAB6MW F2EGsNaZmInahJPtx2w/CoD8DLJoFn33hF2YhT971/6L+7QNCxQBUHXK3nWUeZ3gceCiWRQAfnuM OTUUArJ8uKyQ/Of7stKARCKRSK4SRDL1+luTMwmEYPX1z3d2fgAAZ8+yvLyHbrnl1kn2GScT5W9t cztzFUoRtrodFGGb23nEsJZo2myVzlGVBZqagkRDtMacu5vgDo9LQbzN5fjYMN2EcBAE8ckUt4/g Sl0b28aHeIdLb7TtOZpCAdoYL9NcsTdmlkKzKV2hq6PHLtJUWwgLYJGmKohb3Y5a6xNRVgfiWod+ yDDdSBbpqntkLB2wWFNiYbAkxOPAxzeoQkB6Cm5boSycRbL9uGkRXVZIYqsgVs6hAJjpRVUBSmBh PtUUdKjw5bu0QAquLqH/+IRekJmM0UGJRCKRTAFx+lvXTH+Lc7Ox8eX+/lN5ecsJGYhEfltZ+WWP 5wdlZWWxBk5nFlwyczdVTKS/tWxkZWKargFAnkLzRlLjS1QAgLmaUhmMvBMZlsxQAP/E77nVqQOA l+DNTn20q5scGoyJV9068lI6JelUA4ANYxqnErJYU0fXRcaO1RDGdrhS12Ie1ShZlMSS8WPMUZVL A2/JBiLMzx32lmam4cw0CgBr536yviHFiRsXfvKnQmFBHgGAomwAAE3BO8qT/RpKJBKJ5Krh/DrT 3+rpOVxf/5Pc3ArTbAMQ+fmLt283u7q+U1WlAdi2HXW7v7xq1f2apjU0NGRkZLjd7skMdxET5W/F w1a3Y+MYN8g/sbJD/Pyhz52k838SiUQikUwjLFtcX/pbQgiXK1BScuuwojxAYeEaiK2yiwbr66u/ 8uff/+lPb8nOzn766acfffTRlStXXvVYl3KZ/K1PxY3ovioVrsv3ObUdSiQSiUQiufYYhn3d6W8B AOIAQPfwNgD0ADgBBoEQatvDhY0555zz2trayspKVVWXLl26fv36YDC4c+fOpqamBx54YP78+Q0N DeFQKP5xx+ZvMc5iTP50JJ8K55wLtHnyJkgxQQCAMWbbyVsiXQjBOU/mK8AYE0LI245t20n+MZBf BLj+7oeT/GLG629lZWU54ihEWFhYGAgE+vr6VFXVNK2/v9/n81mWZVmWz+cbGBiI7b8COdOYj6cC DAAoozGvT+ju7q6qqtq+fXtlZWV5efnBgwerq6tzcnJefPHFkpKSnTt35vv75y2Ld7Sx+Vt79+47 cuSI1Li8NkSike6+zIZT6xNtSMIQAru71GeffRaTOKjZ1dWlqmpNTU2iDUkYtm2fO3fuJz/5SaIN SSSNjY3t7e26rn9602lKOBzu6+v70Y9+lGhDEoYQora29nq7H3p0Vl7svOrD7TjnE+PX3wqHw9XV 1UVFRbqu19TUrFixoq6uzjCM+fPnx/Z7PJ6NG+OesAsCmAA2AAXgAOO5fDk5OZs3b961axdjrKOj Y/fu3bNmzSouLkbE5paWdO0KQiZj87dWrlxZXr5E+lvXhobGhn8+cebU3Ul8tRkUPefctm2b1+tN tCkJY9++fZTSqU0SuLEYHBzcuXPnjh07KE3eylEvvfTS8uXL8/PzE21Iwjh37tzRo0e3bduWaEMS BmPsF7/4xfV2Pwz1n+9v2XfVh8ebLx+//lZpaemqVatUVeWcb9q0SVGUiooKQggiju6/AgM1gNh8 IAOwAILjNKmrq3vmmWcKCgqcTmdRUdGWLVtyc3PLysoIIQvLynxqa/yjjc3f0jWN2RHT+PRVApLJ Y1tRQQXzJu80CjIEBbxer893Ncs1pgculwsAkvkKAAAier1eRUne9bC6rrvd7mT+GMQ+AMl8BWzb VhTlersfUh7sn1wPU6+/FZsuHH0+U9VhOYOL9l+mB9HHQRcwemYKgAnQB2O1vXbs2FFQUBBToFiy ZElJSYnH41m+fDnnvKGhQVVVRLz77rtbT74Rj9kxLtbfElMgJyaJC3mdJRKJRDJ9QYzP37pm+luU aj097fuOvA3UBmPEG6TDmVshKzzqAK1ZswYAWltbi4uLt2/fHtvpcrk2bNgw2lsgEOiOI+1slIn0 tyQSiUQikUgmw/WlvxUIlJvmk9/9h59P1MDnmzM23b68vDyeQtpxMhn9LYlEIpFIJJKJuL70twDw vvue2Lr1kcu0GOtvIeIUVmycSH+r2jCLVCXtwhnVWssWAM02q3BoritfQ2EJOGCY5boaE9mKCnHM tBZrmnblqzFMId4IGyHBAUADvMvtEABHDavVZnkKXayrOuKb4WgfFz6CS3U1i061UNiNQOh0sO+D PkDQM3VfhV9L10BAuDYUaYr4V6dSF+UGD54YCp4Mqmmaf7Vf9atWr9W/v8/ut93zPCllKagm4WWT SCQSyRSAiITE8eN7LfW3EFG7LJPs/zLMnpW3dGn5pfUTXwlF6y3bHkkx4jFvKWrujZrPBcNBLviw JOsFWAIEQOwoMSJtYQnBABgAB3HYsI6ZVuzYasP6IGpyELYAa2TS1BbAAOos++VQRAyPK9jISwJA ADCAAS5+MRSODaQiKgAfGeYr4eiQ4PW2fcy0bCF+MRTu57yL8d0Rsz8pF132fdDX90EvMNFX1de5 swMAWIi1P992/mctwRNDABBpjLT8pNnsMM12o39/v2Ci48W23t09Vr819PFAuO4KhNwkEolEIrkI RfBPT1WOX38rPT19KqxKDBPlb3GAN8PGbyPGEymuTErfjxi/jRhtNlvr1AGgg7EPDXOuphSMWVLU z/nf9QXvdTuOmVas2fsR43dT3H/TN+SnRAV4PMW93qm9GY4u0lQBsDdqbHY6ehl/MRRpttm9bmeF Q/vpUCjCxUemdc6yUwhxIr4WjqZT8pDHeTBq5StkBqUHDDNPoW6Cm5y6iogAKmKUAwAs1NSZCtUB AcBF8AG304X4r4PBdltNvRKZjGmDZ0FK+u0ZXW90GeejICB0NmQP2Wm3pA9+NJiy0CtswULMs8Dj mecBBKRoDzHqomnr05QURUlN0lLfEolEIpkS4vrdPXXq1KlTpz612aFDh1pbr0B/4XojGAp3d/cw No6gbRYlRaryRthgAn4Tji7T1XyFAkCEw5thwxKQe+G6S0tAG2OzVNpkswgXYS5abCZA1NusUFE0 xGrDnKVQF+LHhnXYMFMJKVaVw4bFAdY69DfDUSZEs83macojHucah75cV18NR1MJOW+z44a1RFPf j5jPBSOphGRT2mDZ3+od/MvegX/sDw5yvtqhrdTVl0LR54ORjjGSuC6CES7MZF0M2Pbc+VN/djJy Lpx5TxY3eddrnYpXIU4yeHgg0hB2zXHNeGRm1xtdTf/WFK4LCy5mPDJTn6E3/bCx49cddp+VaPMl EolEcqOCAArEkXsUv/7WFGZTXXsmyt8iAOW6hgA7QxEBIiLEbFVpthkAcBBRITrZOFdHRUgjREUc 4ryPD/s4OsIqh/ZOJNrBuMFy1rsAACAASURBVIeQZbr2btQAAbe6dDfBCAgnYq5CdkU4ACBAOqUI oCE4Edts1oU8i5I0SjIocSA22yyDEg2xRFP+Kd2vDY+LXYwv0dWbHPoLocgbYaPYpwCAAOjn3EuI aypqad+I5P1Bfs6TuYiAChk6NhipDxOdGJ2mPWAPHBxQA5oj3znnW8Xdb3Sd/0Vr6k2pLMQytmYF bsto+ueG/v392flXrywskUgkkmRGACjxSB9dkf7WZG0SrL7++c7ODwDg7FmWl/fQLbfcOsk+4+Ri /a0RFEQCgAAIQBCX61rlUKSbsXVO3U/IdrfjvYh52rIXaRdMOcU82bUObXfEELFCkAAqIAGggAKA AhSrylvhKAAUKAoBKFWVymjkhGkt1zWKqCAiQDolHkLOWuwul+OYacUmFndFogFKFuvqwai5zKGd t/nf9g0hgJvgH3rdUSHejZgNlm0B3OzQAMAS8HR/0Edwka7OVJJRuhopAgLRCAAIW/S+15v14Iz0 zemoYORcpPnfG70rfAMH+kKnQvaA7V3qA4r2kN3z627jvAEAriJXos9AIpFIJDcsQijxOEjXTH+L c7Ox8eX+/lN5ecsJGYhEfltZ+WWP5wdlZWWxBk5n1ojrMvVMlL/1ZIorgxIA+D3qpgBb3Y6lOlMQ 0wlZ69DyVSWdUkuILvZJkMtH8E/8HhVxtUPLU6gTkQMoiN/we9IpudWpx1YppFLye143AQhQAgCl qvJ7XpchIF+hZGRcFfHzKc4UJHkKnacpAJCn0FRC0ihRAGYrNIWQv0nzxt5GFcFLiIfAZqfeq6tO xDyFKojfTE2JcBH70309VaS6ZmTcmQEjS0OQYOa2LC2goYIA4Mh35P5BviPPoQW0lMVRoqFzlhMJ euZ7FA+1B2w1oDlyrkDITSKRSCSSsSC5zvS3enoO19f/JDe3wjTbAER+/uLt282uru9UVWkAtm1H 3e4vr1p1v6ZpDQ0NGRkZbrd7MsNdxET6W/kjAaE8hQKAnxD/SL55zE/KouSZoXBVdLietgr4Db+n VFUAwIE4R/3kIheqCgDEvDcAIAA5Y6JNGmLhmMaj484cSQ4rGwmh+UaijbFg1RL9gtAaBchRaA58 0vNcNXnLg8TQssaUvyXgHDM5iBRdhS4A0DI1LfOTBbBEI645U/kBk0gkEklygteb/pYQwuUKlJTc OqwoD1BYuGZYbCEarK+v/sqff/+nP70lOzv76aeffvTRR6e2tO1E+Vvx8HiK61HPJz/hSlLGkCQS iUQikVyKiNPfupb6WwCAOADQPbwNAD0AToBBIITa9vBqO84557y2trayslJV1aVLl65fvz4YDO7c ubOpqemBBx6YP39+Q0NDOHQFskkT5W/FAwEg0seSSCQSiURyCfHWT4xffysQCPT19amqqmlaf3+/ z+ezLMuyLJ/PNzAwENt/BZqlMR9PBRgAUEZjXp/Q3d1dVVW1ffv2ysrK8vLygwcPVldX5+TkvPji iyUlJTt37sz3989bFu9oY/O3QuFwMBg0jE+fRZVMnkg0igbSwWRM5I+BDECIwcHBRBuSSAzDYIwN DAwk2pCEMTg4aNv24OAgpcn7XYhdgWT+GIRCIcMwkvkKMMbE9Xc/jF5J+GZc4vK3Tp065XA4PjU3 69ChQ+FwuLq6uqioSNf1mpqaFStW1NXVGYYxf/782H6Px7NxY9wTdkEAE8AGoAAcYDyXLycnZ/Pm zbt27WKMdXR07N69e9asWcXFxYjY3NKSfiXCnmPztw4cOFBbWxvP4k3J5DEMI70FStuSUYV1lPbO 0EsvvaQoyZtp19/fb3V11b33XqINSRgC4Fww+Oyzz2ISB8tbW1s7OjpcruRdEWwYRnt7+y9/+ctE G5JIamtrr7f7oc8Fi4v0T283AULE52/Fqb/11FNPIeKqVatUVeWcb9q0SVGUiooKQsjY/VdgoAYQ cygZgAUQHKdJXV3dM888U1BQ4HQ6i4qKtmzZkpubW1ZWRghZWFbmU69Af3Vs/taGDRuWLV3COPvU oySTp7Gx8firux4uOZhoQxIGE+THsO2Rxx7zer2JtiVh7Nmzh7z++k2fZc2u65xBzp/LzX3q938/ meNblZWVq1atKigoSLQhCaO+vv7QoUMPPfRQog1JGIyxH//4x4888sh1dT8M9rWeP/POVR8er78V p/5W7B4Rmy4cvV+o6vDSuYv2T2yTEH0cdAH9I7sUABOg74Jg044dOwoKCmIKFEuWLCkpKfF4PMuX L+ecNzQ0qKqKiHfffXfryTfiOcEYY/O3CGI4NGgYkfgPl1w14eAgglBIMhZ2HIYDgqCUXlfPc9eY 2M0hmdeaxG6OSf4xIIQk+RWInXsyXwEAQMTr7WMwSWPizd+KU39r8lCq9fS07zvyNlAbjJHZTjqc uRWywqN6qmvWrAGA1tbW4uLi7du3x3a6XK4NGzaM9hYIBLrjSDsbZSL9LYlEIpFIJJKrhsTpb8Wp vzV5AoFy03zyu//w84ka+Hxzxqbbl5eXT2HYeSL9LYlEIpFIJJKrhtAp1d+aCvC++57YuvWRy7QY 628h4hRWbJyM/pZEIpFIJBLJuJA49eXj19+aPIh4BYIRU8pk9LdihIWoipofRs1sSu5wO7IoZQKU S9JRGAABMITYFzVvdupjM9o4wL8NhDoY0xCX6uotTt15YTrLQcMEgJX6+JcoJMQroej9bocB8F7E YAI0xM0uPba+82PD4gBLdTWp1gF2D4o3j9gPrlajlviPd6z7K5TcAPnvQ/b8HJIbwLeOMIvB1uWK Q4U9J1lllUUJzsrA7SuVWRnkn183b5pLlxfRX1VZq0vo7MykunI3GEyIv6+qOj80pFG6Ojf3ruLi 80ND/3zwoBAi4HTeU1q6JDv72WPHDrQOr6F5eMGCtfn5bUNDvz51qqG/f2FW1rbSUq+uj9vnaPuo bf+mttbifGtJiUNR9jQ2AkD5jBmVx48/sWSJOhUChBKJZPpBCcR1d8jKykqG1SKZGYFZedmX5m9Z QvQwPsB5SAgAGOC8m/EhLi71QJtt9looslBXC1TlmGEFufj/B0NVUdMSopfxHsajQphCvBKKPB+M EIB0SigAA+jjvJvxsBBMiGrDXOvQVju09yNmo8UsIWLj9jAuAGotu9ayASAiRA/jESFi292M93Ee 4mJXONrG+M5Q1BSQo9DTltVoMQDoZfxDw2Igki0bmQs4VMsau/iRBr6z2t57mrf3iQ/rWNSC1l6x 64i964jd2MUB4GQL9+j44GrFsuG/9tmMw86D9jO7rVBU7D3N2vulOMh1DeP8g6amTYWFGwsK3qqr q+vr6w6H24aGdpSV5Xi9vzx61OZ8X0vLoqysRxcufHThwrnp6WHLeqOuLtPt3jZ3rkrIW3V17MIH y9E+Y+0BoHlwcFd9/a66usaBAQA42d19srs7aJqvnT0rpHyMRCKZgHjjW3Hqb93oTJS/ddCwdoYi FDCN4td8KS+HotWGOYPS+z3Oi+oSqgAuQmwhMhQlg5Jqw6wMho+bqo+4nw9GBriYrykrde3nQ2FD wGyFvhyK/nWactK0K4ORfs5vdznucukKgorIAAQIRDhh2u9EjK/43N/rH/qmPyU2kCnEC8HIvqi5 WFfvcztfCUXei5qFKt3udvZy/rOhcJGibHLpDoSzlnXMtPIUWm/bUcEXqGqy+VspTlyQT/eeZr1B sbyIflTPUt3gd2OGF/eeZvNyicXg8Dk+O4MAAKXABTAuVA1jfzo13H2CXavwrmRSqISohHAhuBh+ rqCEAIBh20wIgji2CATjPGSa+5qb/37zZr/Dcc7j+buqqm2lpXS8PmPtbc6PdnTMS0+3OD/c1jbb 77925yaRSG5k4s3filN/60Znovytqoix1qHbQhw2LQVhnUPzEHwrbBwzrIv8rVmq8ojH+V7EqLHs MlW90+VY59TvdTvmqMoWt+Njw3o7bNzvdt7rdhKA2arSzRkAvBWJluvqnW6HA1EIMcjFK6HoAOfL dHUmpbXcHuBcAMT+jzHExVsRY45CqyLGEk3t5qJcV9c59HRCKOAshQ4K3s95rkIXa+quiNFo2x8b 1mJd9ZBkc7fAocLCfPLL9y0BcFe58qsqe/8ZVjKTMA4v7rfy0gkI2H/aWjePAsC+06xzQPSHxF9/ TgcAjwNvXUj3n+FtfTJ0cQPQF42+UFOT5nBsKSmZ7fcf7+w83d398yNHant7/+rmmymixdjb9fVH OzoAYEdZWVFaWtA0HZQigEZp0DQvfZtjfXo0bUdZGQd4saYmz+cDgP0tLetmzbrmpyiRSG5I4vW3 4tTfujxC8I6OqnPnngcAj2f2/Pl/TOnVS7V+FkyUv4UI9oj4FwOoDEZ0RA3RgotvzgOMh7h42OP6 IGq+EzHucOk6ABfQYrOXgpECVYn1oyOa4pN5PQpoAwgBBIEB+Ah+MzWln/N3I0Y7Y7GdR01riF88 nJuQO12OQlWZpdKqqPlKKLLV7Uil+JDHedAw3wxHH/A4i1RlT9R8LRwdYHyHJxklmxEhN0BCBhCE giySnYofN/Aty5S9p1l6ChZkEkSwGFTXMsZhx1r14ZuUX1XZJ5p5fjoShHk5pKlL/Of70/95YxqQ 5nR+b+PGbM8nX+G1+fn/cNttb9bW1vf1LZ85U6X0SytWVOTmAoBKyIBhlAQC5/r7Z/n9Df39i7Oy 6CXqX6N9ciH+6+TJdJerwO9HRIux6tZWJkTsEC6EyRgAaEksVSqRSCZCIUSh9NMDHlOhvyW6ug62 tb1VVHQfAIRC50+e/GFR0aOjL2taGqWfYZo844IbpmJECRnfxUTFnZmRNa7+1lqH/utQxBTgJggA JaryXtRottkqodoXpsPrBDs4f6F/iAHc6tQVxJud+nHL3kC1VEIORk0BEBGiTFPfjxqtNvMRAgAb Xfp/BSNVUWO9Q7/X7UgnlAAUqUqEi71Rc51Dy1fo7ojhIYgAbiSWEG6Cdzr1/YY5xMlSxt+KRGtM e56mpBDiI4QCrNC1QSYORq2NLn21rv10KHynS0/C4FaMDC+unEOjpsgL4Lp51LAgP528+qH1hc1a WT4RAk6f589V2TmpqKvgdeK2lcorh+wDZ3m6F106rp1Hdx2V5chvADLd7rHvkkapR9N0SjfMnv3q mTNv1dW5VPU777/v1jQAeGrp0juKiu4pLf3l0aMftrWVZ2c/tXQpveTBcrTPiG3XdHZ+YdmyssxM AXC6u/u548dzUlJ0RUGA7nD4sV//WiHk2+vXl2VmXqszlkgkNwa5WKQQ8ulPY5PX34pEOs+c+emy ZY87nU0AAJBaW9tWVfUkgBMAbHvI6dyyfPkX3G73RQc2NDRkZGQAQEdHR2Fh4VUb0DsQ6e/rUrWe 0duxAAAhAASAAAEz80tmqKnj5m+t0LV5mnLUsN6OGBTgHrdjg1MXAC7EWsuOjCTJIsB8Tbndqa/V NUDwICLAWoe+TAgPwS/7PGEhACBACQDMUqiO+Bf+FBWxTFNn+6khQEdUEb+Z6vESggALdbVIVdwE H1eoJYCB8BNyp0u3ARyID3qcd7gcCJBCyOOKyxbgQHSR4T5VgNtcuimAAszX1W+rKe4kLsmmKfA7 t6gWE24H3lmu3FRKfW782t1qihMBABFKZ5Kv3Km6HWgzgQhZPnx0nQoASwuI34OZXvzpFx0uPWmv 342BRunfbtrkHyNxXJ6dXeD3A4BX1x+YP9+w7duKikLm8AOVR9MoIUuzs4tSU39+5EhnKBQ0zc5Q qL6vb7SH2X7/aJ8uVf1aRUWKrgMAApQGAl9ZudKtaTbnbk176aGHYjeCNKfz2p2zRCK5QSicfdPV 62+Zpnns2LHjx49f1Njv9998882XyGKJaLRL130AsQo5kaKitMLCbwBkAUB399Gvfe37TudNK1eu vKi3p59++tFHH+Wc/+pXv3r66aev5OwuBEn56rvTM/NGHCwhBOfMEJwJwQTnSOhHR06Nm7+lIPiR FKjKMi4AQENMpwgAtoAPokaTPVxj0UdIsaa4EfUxIUMFIQURANwE3fDJ/lioKeZ7EQDvmKdq38g2 GWnmRIw5BrHRY2FADTEwMpAfPzk81udwSwQAoAD+pF+mrqugqwgAlECqBwHA5/rk7UCEQAoCAIws J3Bqsf8RAJCA3y2drRuA1AvrSSBi6oj3o1Eam+lLuVBuBhH9DseOsrLna2oOtLbOS09/oaZm9NUd ZWVr8vKGWwL4xvSPiIExNZWzPFevIyORSKY9CPzq9bcQcWBg4Lnnnps9e/by5csVRTl//vzrr7++ devW9evXj20pBKup+WFv78f7938XsRMARhOfkNCZM5c7nW7OeWyI48ePV1ZWUkq3bt26dOnS0f22 bU/ybAkhhFIQAgQHFEKAYEIAB8FAMPg0/a08heYpF8QCFYSnvBcH5CQSyQ1Hhtv9pRUrYts3yyx4 iUQy9Yi4/K2srCyHw9HZ2enz+SzL8ng8AKCq6tq1a1VVffXVV+fMmTNr1qzKysrHHnvsoYce8l+4 TFoI1tNzuKLi2w5HHUAhAIABMABARE3jmb/5v2/+0R99EtbKzMxcv359XV3dz3/+80WLFk3lyQIA gM1sFIJSAgBCCMu0lJEMLFk/USKRSCQSyZQjRNz6W5TSmpqaFStW1NXVPfnkk7H9mqatXr2ac/7C Cy/Ytr18+fLt27ePW2AnEFjicGRmZLgRBwEAOIAKggh/b6Sr80BtbYtlxeYZobW19eWXX25ra+sb k0UxhTQ1NjU1Ni5dVu5xu7q6ug9//PGy8oV+XwpcqL/V3dPjatEs0/gsbJBcRGdn15Ch1fcHEm1I wrAFMRhtamq6NIUxeejq6iKM1ZvJ+8AzyHnYMM6dO0eTeJHj4OBg60gNgOSktbV1aGiovr4+0YYk DNu2DcO43u6HZqhrcprG8cW37rrrLs75pk2bFEWpqKgY+5KiKGvWrCGEnD59+v777x/X2SJEmzv3 jw4c+NMNG/4K8RD0A1gAAnAASx2z1lZ4fvzj3wgxfH/p6OjgnM+dO3f//v2WZU3i3MZHCLHr7bdP 1JyYN7d0794qVaHlixfEXhqrv1VfXx+NRuESxQfJZ8HAwGBHyLv/fDLP42B7h1H9re84GEu0JQmj zeXgjEXCk1qac0NjE9JXlH/gwIHJ6+/cuLS3tyNic3Nzog1JGIODg+1V+/e/tivRhiQMAdic5fm+ 74jQr6Of4GzqfCx32dUfL+LztxBx9HlLVdWLXo1NLN50002XuUdomj8r66b6+j2FqXlgtYMAGAII AiHKokXz9lafOXRo+Ng1a9YIIVpaWpYtW6Yoyo4dOwoKCiilDz/88FWd4sUUFRU+8fjj//bv//76 62+sWFH+xGMPBwJpgl+cv7Vy5colixdMPmlMEg9NTc01vS89MvejRBuSMGxO+ro8953s9JpT/4xx o7AnJx0A1rV2J9qQhDGoqUPLF3/uc59TlLjuzNOSZ599tqKiYjKr0W906uvr97/+9ueOJ3F8i+C5 zDmnt4WZ9zp6/tT6PXD26g8XEN984qeCiJdXG1BVT3b2ujff/Pz+CIIaBRhepyhABPkApbytbbil 1+u98847Rw9cs2ZNbGPt2rVTYioAFhfP+eMvffFg9cH16yrSA37Bh52qC/K3hIiEQ4YRmaJBJZcj Eg4m2gSJRCKRSD474otvTQmBQLmmff3HP/sJgPfCV7JsGyoqtM96pnZ05hURi4oKZ87MVinnw86W ADFh/USJRCKRSCSSqyfO+cQpAu+//3fvueexiV7+TEPoBHGory2QkTOq7+pwOJgVjm3blmXb4ZN1 nePqb0kkEolEIpFcPeP6W5yzWD7TZ4GqXGbdjZjacfmY3rJmzmptPONLm+lPy0JEACE454xxzjhj vT0d4VBw9qziy+hvSW5QBABjEPvcmTaoCiCAzYDS4Q2CEMs8ZBwYBwAgCJQAIpg2qBRiBRbV6bJi zBqJ9FIECggADIQAUAABgAMIEBTQFEKbpiUJOIA9Eu2OnaMAsIRQR7IiYufOQBCYppdAIgEAAPOS L4IthDLyRYh9KUbvCYkz8zOBmxwAEAEoYqzYnQBucaKS2LkKLoAJAESKMOkVLEKwi/0tqmgtp98n ysVJ8TckQlhGKHbhsnKKbMZrTx6MRkJC8Ni6QyEYACCi0+3NK5j3GelvCSEGB4d8Pu+nN5V8BrT1 il/usb58pzYUFd97yXxqo1o6k/zf3dayQlKUTZ77wA4Z4g82qx4Hvvah/e9vWU4NctPJkxvUhfnk f/zS2FhG71qq/PB1c9NiZWH+dFg19k+DnXujIQS41Znyx94MW4jXI4P7oqE/8WVmUeWEGdkVGfqK N+PbfW2xPYm2d+o5YUb+ove8hphKle+lzsykSq1l/PtQ9z0u3zqHhwsRO/cDRogJsd3t//QeJZIb kF7O/qi7yRJCQfyWf0aZ5uhi9r8NdpVqjvtcfg3xh4Ndm5wpALArMvSnvmlVFdTqs2q+dFxYgjhp +ub07IdmEJ2E60LNP2rK3JqVujYNEHp393S90skiLGNrVvpt6ZMf9OKb6YzCFdyeRiukEFTNBQCK ouXNnpudUzhuCI0QqqjaRPlb0ajR1NQkAPLz8pxOx+nTZ3RdB8TcnJmNjU15ebmqqra1tVNKe3p6 GOd5ebmqojQ1tzh0PTc35+DBQ//57K++/qdf0XQ9PZAGAF1d3fn5eadPn4lNoebm5ur6Z1irO8nR VegdEqfP8/Y+fqyR7T9LnBo0d/N182hTlzjRzE1b1HeIhfnY3i82LaL3VSgvH7BfOWQvyNMO1bHB sFhZTOs7eSh6Ha1MngzNtvWFlPRy3akjAYAebr8bGTIBPjTCd7i8YcEbbJMDnLaiYprqoYQFz1HU /5U6AwEzqMJA7IoMqoDvRIZW6C4FMHbuHWwa3QklkkswBTeF+EEgV0NMIwoHOGSEBjjfEw1ucHiy qXrONsOCA0CDPd1U8bjJhcnn/u/5kYZI04+a0u/IUNPUnre7iUp6ftvtXe4jKrY/3+Zf5fdVpIZO B60+C/RJjSgunU+kVKV0WgS3LoEQquuXKyU7Vn9rLHs+qHr//Q+44Ldv3rR69arvfu/7paUlqqps ueuOV155fcuWO2fOnPFc5Qutra1DQ8GiosJt2+6urv7w2LHjXq/33m13Hzl67PiJmmPHT3x85Oi9 27YKLl559fW/+OY3/ua7f19YWBCJRnd87sEli6deSV8Sw+PAxbNJ1Sl7MAwbypQj53iaBwMpmOrB XUfsZYVEABw8y4pnEAA4fI7rKjvfJ2J/OjXIDeBvDtvs4nJWNzAcxHvRYAsz56qOmxyeA0Y4k6pL dedRM1rBXZ9+/LTgnG2+Eh7Qkdzn8ndyq4ez7W7fK+GB42Z0iSYLTkuShU5mvx4eVBDvdfkQ4bRl 3OHyHjUjHxmRO1zT0xMYxeg0u37TZfVajlwH0Um0MWL2WJn3ZnW92hk8MeQt93mX+aItUfLxoHe5 TwtoMNll9EK5SNJTCNHf29F8rsacQFpdcHE+6u+zJpvkJIQoDYRyUq5ewJ0L0TsQFRNMKhOE9My8 mfklihpv6Gii+okHDlTX1Z9TFWXvvv2rV68ilN5x++aak6dOnjq9ek3Fb3e/u2DBfK83JTNzSWNj U8HsWRnp6e+9twcQGhqaysrmP/jAfYc/Prrlrjs++uhjzjjnPCbrpSjK1q13HTr0UW1tnfS3Pjs0 Bebl0n/9jUkJPLhG/fm71t5TrKKEBqPiF+9ZPjeCgN6guHXhcH5W2BBtfeL3N1EAcGl4S5nyzjFW 1z59Ij0CYLSi+iBnL4T6hzg7aUXrbWOV7lKSKWFJBUSEqmjot5GhestoZRYTME+d3GOsRHLjQBEE AAGwQNRb5svhgcNmZICzD43wasd1pO3+WYAUgYMjz5F1bxZxkP59fb27eyLnwkZrVHCRstCb/eCM oY8Hh44Ntf5Hc94XZ4EvZZIjKhfNGAz2d587e9ShO2cWl9HxFgw2n6vp6oqaKQWT+f1BgM7OLj8J zk67+lubaVr9fV2LV911ae0LIUSwv729tU4A5BXMG12TeHkmyt9KTfXPm1u6bFl5SfEcAFAUmpeX e+r0GcMw580rfeONN7u7ezduXF9SUnzmTO3evfv9Hx3Oys7Kzs6aN7d08aKFiKBrWjgcDgQCZ86e 7evrj1Xg5kKcP98eDodzc3Ku+iJIPhVEmJmKhAAXMCsDCzLJR+fY4xvU3cfYpkXKTXMpAFTXsj0n mc1h3Tz6+fXKGx+x3x5jD65BRCjMIs3d/GfvTp8AFwW8x+VbpbsFwOvhgfmaXqG7XUhOmNEDRmix NhziEgAdzAaANKJMv8T5uarj91PSAaDZNpts8w+86QWK1sfZQSN0wvpE4L6Ps3ZmaUjS4ruHSCQ3 FulE+b2UgIYY5PxDI/yIJ3WJ5owK8UE0uC8aGv2VD3LWziwEzKTKtLkXaOlazu/mEo0AQLQ5GmmK 5n0h3znbafVZA9X9Q8eHzC5Dy9R9y3wtRwbtPgsmKRV16Xzi+ebajOyCmbPmappj3KU5fd1tTucQ OFM4v3qPixB0OIZ0R4rbe/VnoBhRRe3OyMon49UaS8/M9QVyzhzfm51TqDvimiWZKH/rtts2VVa+ sGvXO7qmzZqVX1pSoqpqWloqpdTv81VUrDx3rnHe3LlvvPHmoY8OL5g/b9HCMp/P9+uX/7uluXVG dtacOXPWr197+PCRrXff+euX/9vtcuXn5wGAYRiHD3/s9XqXLJHBrc+WQAqun0cRMSeNbCijbgfM SMWhqHj4JiU/nQDAzDT8r312th+9TnRpuHkxfaXarmnm83OJxwFr59Gty6nbMU3uM7MVzYUEAGwh zjP7dqe3XHMhwFzV8R9DPQhQoGgAkEXV/6+vDQH+2Jtxq3OyD3bXFS4ksXMUAH2cZVP1XpfPgYQD RAXvYvY8zaEhSSfKEQbX/gAAIABJREFUf4X690dDZZrzW/7spIr8SZIBBCxVHbFFQAOCWUI84Unz ESoAXEiOmZFcRY3dK5qZ9cXu5kyqfi9tZuq0ePZABHeJe3RZotVn6Vla5j1ZxEEEFzzKrR7Tkets /9V547yRtj7NWeCaZDrrOPry4dBgVk6xpjkAAIQAAGYbZmRQc/kojU3MCS6EzflkMlooCC4ACSGT WP1EiDJ8qYTgnDc2NgohCgsLABAAEInPnxmNRISI19CJ8rfmFBX+xTe/IYQghFBK/+SrX1IU5fbb NnHOKaX3bN3CGKOUfv7zOx555OFY7aPs7Kxly8pBCEopIeT+++6NHf7Vr3yJEMI5F0J4PO4v/P7v pqcHkrk27bWBEvjcWpULoARunk/XlFKVwpfv1EbFSWZnkK9u0SiJfeTB68Qd61QQUFFCFQppHvzB 7zimTUW7r/oyEBAAVMTfTUnDkecqH6Ff8WVQwPUOj4r4w0Bu7JtDp52bsVBzzlUdAIAAizTnfNUR 86UIwDaXn4O40+lVEO91+7e4hp++pLMlmX5kUeV/pc6IfbZzqPoVb4aKCAAIsEJ3lWtOREBAAvBa VlHskGkT6tYy9aJvF2PMiUBIWZTime+J/YkEM+/JElwgQc+8EsEFUkSK0D+5IS+NbwnBERGEiOV1 cWb1tZ+2rWhG7iIgPNZCCGBcsEviW23Njf60dCHEQH9vdk5eU/3ZmXmzVW3c9CmcXJ3tC0wGwTmz z52rf/vtd5544vHSkpLhMYblhOJlovwtRByrxRrbHq0pOfoqpXSs56SOOWS0smSsJSGEMfbkE4+l paUlc6G0awnisN+AMKykdZES3LC81sjNhCDAGMmVy8nG3WiM1dG5SFNHGfHDYLp7GOqYsxt7phi7 JiMflWnz6yKRjMvYT7h64ad97PdiWn4RYjOJo+DYmVIEpBjbiVMmPCbGfWYXAByAc2b2tB4PDbb7 M+cQqsR2xuJbjI3zr6e7KxwJR6KRnq4O2+bdne2WbY/bkjHBp8rfEgKAU0qWL1uan5/3L//yr3V1 dUJwAA4jOltxkpkRmJWXPeX6W+NCKb1pTYWmTfMFIBKJRCKRSDizlUsldgS3mW0AiGiod7C3yekJ KKrG2fBCQs5txrhh2fYl8S3GuWVzAGBcGJbNuDAtJoh96cAKQcanIAFZCMGZGZswdDnVkuLCF196 qbp6/8wZ6Zqmcc7ElcS3ZP1EiUQikUgkU044NKAgXhziEoILbgMITff4M4uG+lrCg+1OT3pM4l9w xoVgXDB2iaMmRMyLEkIwLkAIxgW5pBkAIMBUuFvDQ4EQQoiOzq69+/atW7t67U0VCiWC24IxuJIo 2tj8rTNnzw4O9tnTSfr1Oqa/f6B7yPN+c1GiDUkYTGC/7TiYnaazz6qU1vXPWf+0ysq/CsKK0hUM VlVV4XScvomTtra2w4cPt7S0JNqQhNHT09Pq1PbkTIGg+Q0KQwwS1VXtFI7rSIjHyZ0wCWHy1MzC cZKHYv5WLO7l8WeD4KHBTlX30FiRH8GFEIzxS9cnBrJyVc2JiGmZOZyLrNxCJAofz7FiU5e/JTgT wG3bPn78OCX4xOd3ZGakCWELcUH9xHgYm7+FiF5v6pRYKPlUbIY9GWth6dcSbUjCIEJYXW/yZQZO m7T8KwdNExYtwuLiRBuSMBTDUA8ejC3ESbQtCSO2tCjRViQSzjlZuQxXrEi0IQmDCuHYvfsprHDR 60mBmQ9Q7Lz6wxEv9rcIobYZ4fyTuI7bl+XkNiFEcBti3pgAzvml8S1XyrCD4vamcS48/nQhgI23 jhGnyt8SsfgWQxCLFs5bvHB+Wpo/ZicAMNsmhELcyW5j9beKi4vLFpRY5nQrYnB94nJppmncfPPN iTYkYdi2fXz//tXBoC+Jf2gBAIqLk/ljMDAwcObMmXXr1iXzMpqWlpbFixcXFhYm2pCEUV9fbxhJ fz88fnz16tU+33WU3hPsa22qeXMyPVz8rfb60wf6u10uh8OZMhrTJoSOOjFCcMEFUiCTCHgjwNTF tzgIhgBpfi8AjJRHFLZt9XZ3eLyp8T8pXpC/JYRlmoYRmRIjJZfHmqCYgUQikUgk04OL/a2ZeXPO 1lSfOrovJTWLXJLaBQBdneeDQ66w0j3JgUNDg5HgUH/31VckMg0zHBqoP3MExMXzhgIgGhqIRKNF c5fHX89nIv0tiUQikUgkkslwsb/lcnvnzFvW0XqOcR6Lb3HOEXF0OytnzvpMT9DWL9p/5dueHK/p cFpX3Y/mEnPmZcAEbVJS3Xlpmf5AthAAIC7fZ4yJ9LckEolEIpFIJsM4ESxVczV3GiakzJm7NL+w rK3Hvmh7xaLSm8pmKpHOLJd1y9LZV71dWlzqyyw51RjuCuoZuWVXup2aXXr+EttGt6PCE8jMZYzv qTpYc+osAJimOe72KJfX37KECAkBAAOXXVoZFiIyMlXKAfonU/YIQHzacGPHNadMQlZy42Ey1h4M tgeDXeGwyRgA9EUi7cFgRzA4aBhcCAHQEQzG2nQEg7HPStiyOkOh7nDYsMfRbRntc7S9zXlnKGSN fCY7QyEBEDRNM4mXVUokEkk8jJOVybngQlDFgUTl3Jj222JkccDl9bdOmPY7EeOrPs/7EfMWp+6Z IH/t9VD0jGV/yef2EdLJ+N/1DT3ldS24Wl3THsb/sT/412kp6qetD389FFURt7kdVzeQ5EbncHv7 F197Ld/n8zsctxcVPbhgwXf27DnW0ZGi6wV+/++Ul6c7nfc9/3y6y0UQM93uv920SSXk5VOn3m1o QMTbi4puLypK0fVx+4y1T3U4jnZ0/NOBAw/On7+luNjm/Jtvv/29jRt/U1enEvLIwoWJOneJRCK5 /hnH33I49PXrVlOqA9jJsD164hPlb/UyftAw2xnv45wiOBBtEEdM+7RpBygpVZVjpoUAhYpSpCom iIOGeZvlKNPwqGEeNy1TQD/ne6NmhIuFulqoKg2Wfc5iphCLdDVXubg8XS/j1YY5yMUKh+ZGbLLt PVFzpkJKVNUW4pRl11v2El3NUxRbiGOmVW+xLIVEhTBBNNqMCVGgTp8S7pI4EUJU5Ob+42237W5o ePbYsfvnzTMZ+9b69cWBwD/t3/9xe/vGgoJMt/sX27drlAKARunb9fVhy/ruxo0C4KWTJ6vPn7+1 oODSPp++/fZYe5Oxd86dK8vMfK+h4eZZs5yK0heNCgDDtuV6B4lEIrk84686JgiCG9d6WwhhG4Yx MCpSOnaG47PbRkKIolOqTZS/9VYkWmexWAEiW4jnQ2E/dT8bjGRSGqDkPGM/Gwqv0rWqqPkNvwcA ilVlT8RQEc5YdhYlAEAALQF9nD8zGP6zVM9Bw6yKmrMVWm/bf+T1jHWOGMCvgpFezgvV4bcmLMRp 0z5mCr+HRAW8FIq6EM5Y9h963Wcs+5VQNF9VMgQgwlmLWcJYpssaQUnKvpaWb7z1VsS2y7OzCSGM 8x8cOBBwOgVAcVoaANT39f2Pt98miB5N+/M1a1oGBwlihssFACohTQMD4/b59bfe8mjan61Z0zI4 GLasu0tKXj1z5kBLy4bZs6/xCUokEsmNy/Wj8iKMyEBz/YmWxlOR8NDUVbP+FBCJO8U/e87i3MKF Y/W3xlJnsQqHhgDvRoZ9xAAhFbp21LSCnHuQ5ir0QY/zu/1DpgAAKFWVRps9OxTOpjRfUQDAEqKH s48Mq8a0bQEAUKap6x3avw2GBYixCmFciBrT+j2fe7GmIkAX46mEPOhx/utgqINxBNgTMdIpQQBT QKPFMin9vMelIzwbDJ82LUuIe9wOGdxKTopSUz+/aJFTUQpSUykiIm4uLHSq6vHOznyfDwCy3O6H FyzQKNUo9TscDkUJmiYXggMohDjG03wqSk19dOFCjVKnqu5vaXn97NmDra094XB3OLx85sxrfooS iURyozLOHfbkqdNFhYXxl1IWQtTVnyssKGhpbUkPpLtczquwg9lmy7majvaWogU3666Ua+YxCMEH ezvON9W6UtKdKenRSOTS/K1sSo4aFsAntRg1xHmaYoM4bFgbnKSL8fejZhohGgIAOBBX6NrPhkJ3 u527wlEA6GS81mQ3O/VuzhkIAGi0WBWYmZRcVHscAQtU5bBhcQGzFQoAFMFH0BaCC0ghuNqhLdXV LEp9BNMpOWHZ+6JGrkKFgA1O3RCixrRXO7SklmdOVrI9norc3NE/CeKirKwl2dkE8e36+lW5ubGd AGBxbnFelpm5v7X1vcZGm3MuxMKsrMv0Wdvb2xEK/Z8778z3+brD4VfOnPl/7N15eFvHeSj8d2bO hh0gCXDfV5ESJVGURK22VmuxLMuWLdtxbDdOk9ze5ja96dck90l727RP4/uladL0a5vcJG1T20rq NfJuWV60WLu1ixT3naK4E8R2cM6Z+f6AREEU5U0iABnz+0MPCMwZzIEOD1/Mec+8J/v7J78XdYyN He7psUhSlduNk7gWDcdx3I1MjbfCmvajv//pU3/3A4/H/Sm7GBwceur//P2//PM//uIXv77//ntr 5s/7HOMw9FB3R0PJ7DvySubFuHZYenaJpJi6O+oNKbunu+f6/K11JuWtYEgAVCgSBGiNSdEB9gbV AGNbLCYGjAKMU7rJrFgxLhEFACgUyCg1zZfEMYOmEOwmeKEinla1GkkUAQGADkwHuM+iTMneIgi2 WZXX/KE3A6F7LEqeQJYpMkFooSylEJxB8B2KfEQN+wS2QBYXyNIIpQdC4UKBFIsCAkghuE3jd4ol owyrdWlubvQzy3Nz08xmRRDuLiv7oKMjqGmz09P/6/x5AHApSpXbXel2T4TDrzU1Hejq+tO6ullp U+u1TfbJGEMIzfF4ajIzBYzTLZZxVdUp3VhaapWkWWlpJ/v7nz17tsDprHR/2vMGx3FcUplmfisQ CDz/4stmk+meLZsVRX75968+tGP7K6++XltbYxj01dfeEAVhxYrllbPKR0ZGX3v9zfHx8bFxLwAY lDLKAoHgvv0HTpw4tXbNqpqaec3NrZTRqspZnzAQxoKBCclknbImVgwQIpitzt6O86WluR63+/r8 rTyRfE20TP74kNUEAN90XG52StWKBfLf7JcbLJIvL6/6uM0MAFuu3DC4zWLaZrk880cA1cpSpJ+P VG2X/+oq9lssykJZmuwcAJ64tp91Znmd+cpNZCjS7TWjLRUT5xoxFzsFTmeB0xn9zI7ZsyMPHLK8 tbwcAP5h/fopWy3Jyan2eH554sTu1tYMq/XD7u6OsbHIS5Ecr4dnzwYAhFCxy1XsulywCyG0LDcX AO7IzweAFfn5K/LzZ3DfOI7jbn/TrgdBRVFs7+g8dvyjmvnzdr/z7oMP3H/02Ef5eXkAsP/Ah9vv 2/bqq6/nZGedOHmqvaOjsKBAiKqZ093T8+Zbu4uLi3a9+lppaUlGZjr5dMVHGWPxug4Rqefocacx qt9o/a0bKZeEJ4nlk9tFWW2SJ6e18gQyGYcBQL6Y3OXzuJgzi+Ljc+d2jI/n2u0WSfJfqRkayfGK 79g4juO+MKZdD0JZWrd47/4DY2PjAIAx9nrHA/5A5NXCgoLNmzZ880++HQ6Hh4dHsjIzF9TM3/Pe +5ObB/yBg4eO9Pb2paamIISczs9Tb3J8fHxkZCQtLU0QhIsXL+bl5cWggKvP7w/6fTdaf+tGTAjl Cp8tSHITHP04+keOizGEkMtkcplMAJBmNsd7OBzHcV9M0wQxoVDojTffHhkdnVs9R5KkvLzc555/ ubunJ/IqxliSJcMwACAnJ/uVV0+NjIyGgqHJzVNSUzasX5uRkZ6fn6cocmTD3Kg03k9kGMavf/3r kZGRuXPnmkymrq6uJ554IgbxVn1Dc093N6+fyHEcx3HcrTU1iCEYf+0Pv4IxxhjNm1dtNpm+8gdf bmvrKC0tzs3LIYRs27qFYPyHTz7hdDrmz6vWdV3TtHnzqkVBuG/b1ty8HJfTtX37toaGC4qifL4g yTCMU6dOLV269NVXXy0rK9uwYYMSk+saBfk5HndaJH/r2PHjzS2NBq9SEhMBf2BsfGLnzp3xHkjc UEp7Bwd36XoyJ9/16To6dqznyle7JKSqamdn53PPPRfvgcRTU1OT1+u12+3xHkjcTExMXLx4MdnP h729u3btisE8y6dnEsIlGTcVElwXbxGyds2q6GcK8vMLopJhUxenAMCKFcsAQJKkVXeunHxp0cIF kQdzq+fMrb5c3OMzzWxNjmHz5s2NjY2KovT29n7wwQcjIyNr167Fny4P7HOLzt8qKCiorq4G4BUJ Y6Gvt6/hwoW6urp4DyRuDMO42NZWHQjYZ/ggT2SnQyFaUDB//vx4DyRu/H7/6OhobW1tQv2ZibGJ iYnKysrs7Ox4DyRuent7GWPJfj68eLG6ujqhwu6wf5B6z3/uzamuCYx9qnLIsUQI2bZt24kTJ3bv 3l1fXy/L8ksvvbRq1aqZjrei87fc7jSn3RQO8zolsaAoxG63FRUVxXsgcaPrulmWCzXNQZL3hoke TQO3O5kPg/HxcVmWi4qKkjnestls2dnZyXwYAEB3d3cyfwK6rpvN5sLCQofj8+R/zxDfqNxV//nj Le9It4BQIn6fZow1NDQUFxd7PJ7+/v60tLQYLBJxTf4WA0qpYeiftBF3C1B+3ZbjOI774rI5MwSI VeWcz4QxVlZWVllZqWlac3Nzbm5uDL7wRedvcRzHcRzH3RKUagk6a60oyrJlyyKPPR5PbN70862/ xXEcx3Ec93FYAtWrBohf2TUGgBD6NOtvDRjUgZEcNVQ/Y2MGzRIur2A6SqnBIJXgyRYMoF3TC0Vh 8NptGzW9SCDidHutMjZGWTpfl4v71Pyadn5ggDImEVLgdLpMps6xsX6fDyPkVJQ8h0Mm5GR/f9gw AAAhND8jQyJkKBDo9noBINtm81imLts72edke9UwLgwN5TsckaVQzw0MlKWmelXVoDTdyieGOY7j boQlTLyFkCybtXDok1veaowxLRwUJaW+oWna+onRWjW9SBTSrywPzwA6NOOdYOhxm9mFcYCxNwKq B+M1ZnkyjBoy6N+P+f4xzRG9rcbYT8d8P0ixu68toHhMDReLgs6gTdPTiTQT+8t9IZ29dOmbb75Z l5NjMFbldn99wYIfHTw4HAymKApC6MvV1QVO5zdee21BVpaAcaR+4mgo9FpTU/PwMGWs0u3eVFo6 JeSa7DPSXiLkYHf3z48fv6e8/KHZsw1K/3rv3n/auPG1piaM0FeS+L5CjuO4T5Qo8RYmYnZ+eW/7 WYcr3WpPidlcF2N0bKivt/18Zm6pZPVMqZ9IAT5SNQRQI4tdutEY1v2M5gjkkkFf8AUnKF1mkisl wYbRaVW7wyT36sYl3bjTKr3qD50LawUC2WBWAEADBgADBs0RmJ+y94Nqj24MGAYANGn6Ln9IAFhj llXGvj/snSOLX7aZhwzKABrD+u5gyE3IJrMsIPSfEwErQnkCWW6Sk/c2Nu4GarOyfrRu3QcdHc+e OfO1mhqM0B/V1lakpf3syJHW0dECpzPTZvvRunUSIQAgEfJBRwdl7PsrVwLAs2fPHu3tvbus7Po+ f7x+faS9Pxw+2N29vrj4WG/v+qIih6LolAIAZYwmZBoox3FcgmCJM79FBCW/dH570+mPDryohoIs VqdvhJBismTmlmfmlmGMEELR+VsIwGDsZFjLFvCxUFhAcFLVCgWhQhJqZbHPMF72BStctgpRqA/r VZJ4PqxlCyRDIBWMKQiOq9phNTxZwfojNZwnkCBjH4bUGlmMRJQpGC9RpA5Nf9EX/LrdUiIKdbJk MDimhjealRf8wXSCO3T9IxXPkcQ9AXWH1XQyrBWIQv5nLCLEfeHt7eh4+MUXFUI2lpYSjDXD+Jt9 +yRCPBbLl6qrAaB5ePjLL78MAC5FeWrt2sFAAAAskgSMEYQG/f5p+9zxwgsuRfnh2rWtIyO+cLg8 NbVnfPz9jo6tFRUx3kGO47jbVeLkbyGETWZ7RfVyTVvIaEyXBEMYi6KEMfL5/WpIjc7fQgBVkrg/ pB4KhS9o+tfs5pOqBgDjlL4bVHt0o0nTAWC2JB4JaUfU8Lmw/oTNjACOhsInw1qLphddV386SJmA 0BJFfiOgAsAlw3g7EBow6BilboLTCC4ShUgoxoANGPQ+i+lASB0xKACkELTJrPxobGLUoDze4qZY npf3g1WrMEIOWcYICRh/q65OEYRD3d0SIQygLDX1HzdskAhBAG6LxS7L46FQJKMLI+Q0mW7UJwKw iuKhnp79XV3nBwYCmjYaCi3Ly4v5LnIcx92mEmZ+CwAMXR0b6h0a6AqrgZit644QUsw2d2aRw5VZ 39DU13dpSv6WDaM5kvicL7jaJKddWYsyQNk4pRWSeNEwwoy5CZktCS/6g3WylCkQymDQoFmEhBgL M5gSPDoJ1hl7wRccoxQAhgxKGRSLwkk1rAEUikKjphcIBAAQoFmisMsfDDFWbRYjm8sIGF/2npuO LAgZUUnrCKFUk2lBVpZO6VstLXfk51/y+99obsYIyYJw/6xZCzIz321v//eTJxmAIgg1GRkf0+f5 wcGJcPjpbduybbbxUOiZs2c/6uubvIy4v6sLADKs1s2lpSSJl8jnOI67kUSJtxjVRwa6muuPC7KV CGIsAwr/4NDo8FDVgjWFBXkZGVnXr79Vp0gSQnMlkQBstZhyBOLA6AGrqUUzHreZHRgDwGJFEhCa I4kEgCHYbjUdC4WzBFwjSRaEHraaBYQmt91uNY0YrEISHBjVyBIDuGjQ2ZJZANhsVrp0I1cgWywK QbDVohxXtVSCq2URAKL7id0HxN0OSlJSdlRVRT/z8OzZhU6niPHK/PxUk8kmSd+orVV1HQBEjCVC 8p3Olfn5B7q6nj9//hu1tbkOR/jahWcn+2QAaWbzppKSfIcDI5RmsWwuLdUp/eaiRSkm08or9b4M SnH87jLmOI5LXCxh5rd0LdTedColvaikso4IEsTspM2YGvK3Nx7rbj9fUb0cGL1+/S0nxqtNcuTx AvnyPFOtLNXKV9s4otoggDyB5FmvXp2JvDS57QL56o2HEoI7TVc7chPkJhgAPEQCgCyB3BMVWk3p h+MmpZnNy6+9wLc0NzfywCQItVlZAPC40zllq9KUlFy7XcT4hfp6mZAD3d3nBgYiL0VyvCJ9IoB0 iyX9yt2LCKAsNRUAKt1uAKhIS6tIS5vBfeM4jrvNsWnntzo6u0ZHR202W25OtiRJFy40pad7zGZT R0cXAOTn55pMpiltevsuZmdl3kzJHUb10eH+/Iqlsskag9I90URJSfXktTce9weCn7j+Fsd9wSiC sGP27LtKSsyiuDA7e3KKK5LjFd+xcRzHfVFcN79lGMZHH508cfIUo/Tee+8pyM/7X9//q+9999sj I6Pvv7+PMbZx4/qVK5ZFt6mcVX727LmszIybjJMMQ8c4PpfJCBENQ7+mfiLHJQ0RY7fZDAAWkU+d chzHzYip8RbGOD8/t6Oj8/29+yorZxXk51ks5spZFT/6+5+2tLYKorj/wME771gR3WbRwgUbN6y/ tcOilFJKCSEAYBhGDIonwrX1Ew1qRMTgfTlKKaVM15O3OnjkSDMA9CReyIoBUMNI8sOAMcZPO7qu J/lhQClN8k8g8m9CfQg3+4vJmKBduz+GYex65XWPO61qVkWkd4yxJMsul6uqatbC2gXl5WVT2jDG /H6/9dZV82CM7dmzp6GhYcWKFbIsHzly5L777nNel3pyy0XXTzx48NDp06djvDJF0gqGgj5f4Be/ +EW8BxI3jLGWnp6dELvExQQ0aBjiwYP19fXxHkjc6Lre3t7+q1/9Kt4DiafOzs7+/n5Zlj+56RdU IBAYHR1N9vNhS8vOnTtjnFz08ayyMb90mkVzPj1BvHbqCGO8fNmSl3//6tjYWF3dYkppSUkxRmjT xvVPP/u7N996R5LkkuKi6DYjI6N79x3Yes9mQm7N1UBd15977rnKysrnn38+JSVl3rx5NpvtlvT8 8aLrJy5atGj+/Hk83oqNjs6OhobGrVu3xnsgcWMYxtM///lWv9+exIspHAoEyKJFixYtivdA4sbr 9e7atevhhx++VefS29FLL71UW1ubl8Sru7W3t585cybZz4dPP71161a73R7vsVzlH+sb6zn0uTef Jl8eY7x+3ZrVq+5gAARjQsj3vvNtQRBKS0v+9198jzGGMb6+zT1bNt3aE0R+fn44HG5vb8cYj42N 9fT05OXlzXSoG52/JUuSoQfDahzqOSYhXQsJAnE4kvdOBV3XBULsGDuS+A+tGWOQ5WQ+DAAAIWS3 22OTQZGYZFm2WCzJfBhEDoBk/gR0XRcEwW63J9SHQKhv7Ga2n3Y9CISQGJU2G3mMEIo+BUxpc2vP DoIgPPbYY0ePHvV6vW1tbTab7cKFC9/97nfFGU7mjc7fAgBgELOyQsmOf84cx3HcF1oifotCCOXk 5DQ2NrpcLkqpJEmtra0xeN/o/C2O4ziO47hbJGHWO51iYmKip6dn06ZNqqru379/+/btMZhgj87f 4jiO4ziOuzUYCCwha/E5nc7HHnsskhNWXV2NMY7BfQq3ZP2tXt0AgOzPXm9n0KBdulEjiydUrUoS NAaNml4qkgGDUoByMUEjYy5BXPL5Xm9uNii1yfKS3Nw8h+NAZ2fD0JCAcb7TuSg7Wybkhfp6XzgM AJH6iRZJahkePn7xIgaoycwsSU1F0/WpUxppb5Ukr6q+296+MCsr224Hxt5oabkjP7/H6wUAvsQ8 x3HcjWjhIEYoQe+HEgQBIRTJG8MxuWmrID+npmb+lPqJDEBnoDFmRD1m175EAVTG/mMiMGxQ40ox aQqXX4LrNpyCAWiMder6Ln+QASAADHBEDR8KhYcM+ltfMMjTm7hP0j42tvPsWQbQNDLym1OndEp3 njvXMTbm07RC2UkyAAAgAElEQVTfX7hwuLt7JBj81+PHdUrhSv3EttHR9zs6JlR1JBR6v6OjY2xq Mmikz8n2APB+R8cL9fW7GhsNSjVKf3XihC8c3tfZua+zM/a7zHEcd7uQzK4EmjUhRKA0Pgv9UWpg QqbN37qoG8/5gy2avlCW1pjkV/yhLl3fZjUtkqUOTX/JH2rX9ZWKrAP7yZivTzfmySIGSCf4naC6 O6BWy+IOi6nbMP7D63dgvESRVpjkKXNf58LaLn/ITylGiDLYHQjpTP7pmA8jOK6GT6tarkDmSXzh b+4T5Docd5eVHezpeau5GRgTMF6ckzMrLe2SzzccDAKAXZbvLiuTCEEAIiGn+vsRQo9VVwPA02fO fNTXV3jdKne5Dsc95eWR9iPB4JlLl+6tqDjU3d03MZFx65bc4ziO+2JTLC4hQVZYRJikuLNHB3vc GQWSfFNLin1GLBTwjQx2O1MyfD5fMOCfkr/VrOuXDLrKpCyUxVNhrUs3Ugl+wx+qkcTXA6EUgh+0 2hwYU2BvB9RtFtPJcBgAJhjbG1Q3W5T3Amq3YgQpGzDo3RbTnkBoriy6rp2uey+gFgpEY7hVNxiw Vl3/imjZbFFEgKWK/A9jE3eblRh+INztam9Hx39/4w2PxbKjqkrAOGwYPzl0yCSKeQ7H4pwcAGga Hv7mm29ihDwWy1Nr146HQghAIgQQAoDIpcbr+/xvr7/usVh+uGbNsb6+oUAAI8QA3mpp+fLcubHe Q47juNsTQiRR5reIqBSW1zSfP15/4l1RVmIXBTIW9I/rulo1f9W5+gu9vRen5G8tkiVg8GEoHKaU IHRB0ypALBAIQchPWa6A0wmREGgMFASp5PKwKQMvZYUCwQBhxgAgWyALZfE/JwL6ddcGA4ylCYQy 1qpfLRXswAgA3AQjBE6cEDExl+A2lpb+5K67AEDAGCEkEfI3q1enmc2vNDZOqKpMyGyP5+lt2yJX BiVC0q3WixMTAV1njGGE0qebr5rs069pp/v7B/z+99vb/ZpWPzjYNzER4x3kOI67fSVKvIWxmOrJ kxT78ECPFg7FbOErhFCKJ8ednme22PLzstPTM6bkb3XrxlE1PE6ZCrBAEmplSWMsUyAMYJlJet2v nlK1JYq02iQvkuWjqgYAGJCCUKko/H/jfjfBboIv6ZQA4Bt83DWyuNsfIghkhABABAQABFDkIxAS YwKSS3AYIeFKllWEgLGIcVlq6prCwnfb25fn5XWOj39nzx6MkFWS/nzp0oVZWW+3tv71Bx+ohlGT mbkwK+tGfTKArqGhgK7/08aNaWZzQNOePnPmeF8fwTjyRjvPnj07MFDkcv3xokViEi+Rz3EcdyOJ Em9FKLLo9ngopRCruyYRIEwEQUCMGh53KkJ4Sv6Wh+ANZkUAlCcQCYHNZh6n1IUxAVgoSxmE+ChL J5gguM+q+ChTECIIzBg9ZjNfNAw3wW5CnBg/SSwCQn/mtDowGjSulgkyY7RckQsEQUAgIRRpk0bw apNMENgQ+pbTKiZSDSkuMVV5PH9aVxf9zDcXLUq3WglCc9PTPRaLQ5b/dfPmyDcZiRCnoiCE7iou znc4fnnihFkU7bJ8ye+f/KqDAKrc7kifCKDY5Xpy3rxUsxkAzKK4raICAOamp6dbLJtLSyvdbgCw SBIPtjiO46aVMPEWo4GJodaGjy71d4XVYMwWHEcYmy327LzywvJaNayHQuqU/C0nxk7p6p+QAoEA XJ5CkBEqiVqmwYWxK+pvTRrBaeTyzyaEcgUCAEWi0KjpPx3z6VcCyjUm5SGrqVy62k+RKACA+8q2 fCUI7tOwiKLl2mz3Ipcr8kAkJM/hAIDF2dlTtvJYLC6TyauqL1+4kGYyvd3a2jg8PPnSU2vXFlzp 0ypJVkmK3nDy33SrddprkRzHcdykRPlbbuhqZ8vZYFCtWXafbLLGrCo4o3RibKCr9ZSlv6t3MNjb 03eT6299onJR+Fna1ZAO8cuFXFyJGG8uLb2ruBhjvCI/n0Z91ZGSuJgjx3HcrTU13lJV9elnfnvv 1i0pKS7DMODKOli6riOEMCaGYQAwxpgoiowxwzAYY4IgUEpf3vXq/LnVRUWFkbLWn2kchhHu626u rN3oySqKWbAV4XB5GKN9XQ2Fs1ake9Kn5G/NBH59kEsoCCExElrxI5PjOG5mTI23/uu5F//fv/9J b2/f5s0bn3n2twihTRvvWrP6zl/88t9kSdqwYf0bb7zV3dM7NDT0g7/6C03Xnn/+5a6u7u3b7w2H tb/526dqF9R884+/cfFi/8YN6z/bQBgLh4OiKN+yPfvUEMaSYtHCoej1t/yBgM/nU9VQ7MeThIKh kBpSx8fH4z2QuDEMgwF4Kf3kpl9cKmNGIJDMh4HX69V13ev1kiSeWYx8Asl8GPj9flVN+vMhY16v N94DuUbI77/JHqbGW1u2bHrjzbcf2L4tLy/vkYcfPHHi1Esv77rzjhVdXd133rFieHi4pbVt3drV //yv/5cxdvz4ic6u7rS0lFdefeP7/+s7K1csu3frlrnVc0qKiz7PWOK3iDoCYIxF1088cuRIS0tL zNLIkpyqqgODg88880y8BxJPLX19L1GaKBf442GMUu3w4dgUp09MjLH29vadO3fGeI4/ofT29l66 dMlsNsd7IHGjqmp/f3+ynw9bWl566aUY1E3+9BxmmFt8U1NCU3fGarEoipKSmnL23LmXXn6FUjo4 OMQAEEJudxpjjFKan5+nyDIABIOhhoaGWbMqCgsLFEWxWa12uw0hZL3p5Nnu7u6urq7S0lJRFOvr 6xcsWKAoM77mZ3T9xDvvvHNBzTwjTuvdJ5vOzs5z5xp27NgR74HEjWEYv/zJTx7x++1JfH/f/kAA r1q1bNmyeA8kbrxe729/+9uvfvWryTy/9bvf/W7x4sWFhYXxHkjctLW1HT9+/MEHH4z3QOLGMIxf /vKXjzzyiN1uj/dYrvKN9vY1vXszPUyNtxBCdXWLjhw55nG7NU0LhVRN11VVFQQBAXK73YIg/Prf fjM8PAIAlZUVCxfWapqWlZkJwBYsmP/RRyddTmd//6Xly5d+7jHpuv7zn/9cFMWzZ8/abDZN02pr a29mJz+lgvwcjzstkr+FEQr4vaoajMH7cgGfFyFIqK8ysYcQIgBCEk9sEABAKJkPg0iYRQhJ5g8B Y5zkn0Bk35P5E4DI+TDBDoObH8zU7QkhDz5wn2/C50n3pKalTkxMKIpiNpn+8Mkn3G43xvjBB+5v aWnt7+9HGJWXlz3x+KPj4+Mul4sQsn7d2tHRUY/HbbPZbmZMlNKhoaHZs2d/8MEHlZWV69evj83s +rT1EzmO4ziO427SNPNbKS5XissFAGWlJZPP5+fnAUBnV/dzz784OjK6bu0au80miWJRYcFkG5vN arNZAeAmr/0JgnD//fefPn3a6XT29fXt3r27s7Nz+/btMz3HHp2/xXEcx3Ecd6t8tvmx/Lzcv/3B X0aWe5i56AdjvHbt2pSUFFVVGxsbPR7P66+/ft999810vBWdv8VxHMdxHHerfObrkbG5nhoKhY4e PTpv3rzy8vLTp0/Pmzfvsy7o9TlE5299Sn7GXvWHtltMAgIA6NSNM6q2xTLjqf0cN0XLyMjPjh5l jKWYTPdWVMxLT3/27Nkjvb0CQpUez7aKCkUQ/m7//olwGAAi9RPtsnysr+/tlhYAWF9cvDgnB197 4X6yz0h7l8nU7/M9c+bMhpKSKrebAvzLsWOPzplzbmAAAFbk58dlxzmO424LCZSMFk2SpA0bNmRm Zuq6XltbG8kPm+k3vVH+lsaYlzIBgYCQBaEwYxOUSQhZMApQ9m4wdL9F0Rh4KevRjWNqmMdbXOwN BQIXJyb+55Il9YODz5w5U7VmzaGennkZGYVO59utrfs7O5fk5h7v6/v+ypUSIZH6iWcHBk5furQ0 Lw8BnL50ySrLczye6/v89pIlkfaUsXfa2ppHRrSmprLUVAB4r739gcrKhqEh4PEWx3Hcx0rQeEsQ hKKiy4t43WT2/ad3o/yto6q2yx9EAGkE/5nT9kYg9E5QzSLkEZvZemU+4Kiq/d4fRAxEnLz3l3Hx RTBmjKm6rhsGRmhyskqnVLjydSXypEapRum5gQER4zsLCjBA29jY+YGBKfFWpM/J9iPBYMvIyPbK yndaW1tGRkpSUmK4cxzHcbe3BIq3EELxWl2UAUMI3Sh/68OgulyRNcZOhTWdsb3B8MNW8yk1fEbV lirSZJsVV9rEfPgcBwDQODT023Pn3GbzV2pqCMaaYbzT1kYQcirKgsxMABgIBJ49e1bA2KUoVW53 OFKMCyEAIAipxjSrzTUODT179qxLUSrS0j7s7m4YGlIE4eLExCuNjd9cvDjWe8hxHHfbSph4CyGz xaEGvMBYjIu4UcMIBSYUkzU3b/r8LYSQHvVjZAILAbCoFfERAj2OC+RzHMDyvLx/2rhx8keRkD+t qytwOp8/f75peLg0NTXf4fjRunWRKtQSIflOZ8vIyFAwCAAIIN8xzZ25k31e8vubhoer3O5Uk2lu RsZgINA2MjLZTKc0bBgYISGJ12vlOI77GIkSbxFBziue3dN2xmSx2xzumJWzYIyODPb0dpwrqljo TnMBsOvzt5Yq0u/9wSBlDoIJQmtM8vO+oAOjTRYTAnBgDADLFfllfxCu/MhxMSYRYpWk6GdcioIR yrBYNpaU7G5rIxgP+v1ffvnlyEtPrV1bm5U1Egx+7913B/z+ByorF2Zn36hPxthFnw8Avr1kiVWS wobxQn39ucHBVJMJAVgl6V+PH3+nra08NfUHq1ZJSbw2Osdx3I0kULyVU1hNgTScfC8U9LNYFS7E GNscqXnF1WnpuT7fRCikXp+/VSSSu8zKSVWTEGCAdSZ5sSwRBDaMMcD3nDYRoYWyNEsSMCDGZ7m4 eJifkVHodEY/8+fLlkmEIIRKUlIybTaJkJd37IgcnQjAbbEggLtLS+d4PP987FjYMALhcNvoqD98 +fsGQmheenrh0qWRx3M8ngKHwyJJACARsr2yUjOMDcXFTpNpe2Xl6sLCSDMebHEcx00rUeItACRK clHZ/ILS6thHLBgTBOx8Q1Nf36Xr87daNeNYKGzHeL1ZBgARoVRydfotlWAAEBA4UWRmi+fLc3GA EHKZTNHPTE53IYQij9OvK2wqC0Kxy/XY3LmvNDa2jI4e7ulpGx2NvBTJ8ZrsM5IHNrlh5CZHy5XH GTddMpXjOO6LLXHiLdDC/ks9LX3djaGAL2bzWwhji9WZWzTHnVlUkJ+bkZF1ff7WckVarkjTbs5x tzuC8YLMzEhC/ZKcnHgPh+M47ospUeItaoQv9bR0tJxLTS9KzYzld2UWmBhtvXBSMTvTIzfD8/qJ HMdxHMfdUokSbxl6qLPlbHbhvMLyWhzbFBBdU9svHOtqO180yx4M+CP5W0PDw+YeSQursRxJ0hoY GJyYmGhra4v3QOJG13U1HO7SNMt0izIkiUFdx8PDyXwYeL3eQCDQ3t4eg+WdE5bX6+3t7Y33KOKp t7eXnw9VVe3q6rJYLPEey1Vh/+BNXnmbGm8xxt7evSc3J1sQRYxQfn7ekSPHli6tO3b8I13XVTW8 dEmdyXQ5jaO5uaWruycQCCxfttTlcp6vbzh79pzT4ViwoCYtLfXt3XsURTEMw+V09l3sX1hb4/G4 x8e9hw4fJRgtWrzQYbcfP35izpwqRVEYpV7vcKk9lQhizG5OjJBksz0lY7C/vf5Cy+T6W21tbaFQ CHjye0yMj3svXbp0+PDheA8knvrHxo7ruhzbgz+hXNR11toaDAbjPZC40XV9dHT0yJEjMShflrD6 +/sRQt3d3fEeSNx4vd7+/v5kPx/29x8/flyW5XgP5CqFqGVZN9XD1HhL0/V//80zT/7BYxcv9iOM HA7HL3/9H4vrFr300iuSLFotVsOgq1etZIyJonjoyNH9+w/OmV0ZCAS3338vpVTTtBMnT1/sv/Sl Lz30q1//ZvGi2oHBQYRQTnZ2Z2fX17/2lbfefufChUYG4A8Ett5ztyRJhFweA6M0xpHWJIwwpTS6 fuKiRYvmza3Sdf0Tt+VuXldXd31D0yOPPBLvgcSNruuj3d33+XyOJJ7Y2Of3w6JFK1eujPdA4mZ8 fHxiYuKhhx6KTZnaxLRz5866urrJ+iJJqK2t7fDhw8l+Phwdve+++xzTLQoYL77R3q76t2+mh2l+ q2VJqqqcdWlgwNANv98feRJjtHrVHSbF9PbuPQMDA0ePHf/L738PAObPq968acMP/8+Pt227JxQM tbV3njhxqrS0GAAURd6yZdOHHx5SVXXTpg0/+JsfUsbOna8/euy4LEmSJG279565c+dMO6xQKBQO h81mM2PM7/c7r73RfYZcUz+RsWDAr6rJ+1U7loIBH59K5DiO477Apv8WJYpiWmrq2bPn97z7/uXp fYQcdgcAhFR1271b7lq/NjU1BQCsNqvJZAoEAgBw9PhHJpOydMnioeFhSinGOMXlEiVRlESzyRSZ KyrIz3PYbVVVlYWFBQDQ2dmVnZ015cscpfS5557r6upasmSJoignT558/PHHY1BF8Ub1EzmO4ziO 427G1CwBjND6dWssFvPyZUvy83NTXK7Vq+4kmCxetDAlNcXtSVu0cIHFYnG70xBCZSUlZSUlkiSt XLGMYLJxw3pBEEbHxubPm8sojfQzpc2mTXfZbLZjxz4aGhwyDKOpuUXTpl6z03X9nXfeSUlJeeGF F/bu3VtTUxObpLn6hub9Hx7VdBqD9+I4juM4LnlMnd8SBOHRLz0Uebzjwe2Tz2+7d0vkQV5u7uST dXWLIg+++uQTAFBUWPA/v/XNyVcj/Uxpk5WZ+Y2vf3Wyzbq1q68fE8Z4yZIlQ0NDfr9/eHj49OnT ZrO5urp6pnNIo/O3olEAykC4klqmMSYgxK7EqgxAv3LPgogQBUAACECP2uSz+pTbGgCYr6/KAQAA ZUynFAAQgIAxQkijNHI3DUGIYAwA4aibHyMLwRuMGZQiAIIxvi57crLPyfYMQDMMEeNIqmXYMCRC DEoxQvFKvuQ4jrstJGJWJiHkoYceOnXqlGEYjY2NWVlZzzzzzA9/+MOZjreuyd+KclrVGjT9brNi x0hn8OMx33KTXB/Wvma3AECjpj81OiEicGD8PaetzzDCDIpF8itv4E8cFvGz/xEao/RTbvteQDWA bTArH9+MSwbnBwe/s2ePTEiKyfRgVdW6oqKfHDp0sLtbwHiW2/2HNTVWSfrGa69plMKV+ol2Wf6g o2NXY6NB6Zby8g0lJeK1v2KTfUbaeyyWlpGRfz12bGtFxYq8PMrYX77//p8uWXKkp8egdNusWXHa dY7juNtAIsZbCCG73T48PJyVlSVJkqZpmqbF4H2nzd8aofQZX2C2JIoIenVjjNIGTa+RxR7d8FHm Z8xHaQYh33ZaEUAKwQaAypjGoFHTACDEWJduMIA8gSCATt1QGfMQnHHtbWhBxrp0I8RYrkAMBufC WrtuODDyEEIBBg1j0KDZAnFhbDDoN4xhg1owGjAMhGCUUsoghWA+vZDM/OFwjs32V3fe+WF394v1 9asLCrrGx7+2YEGRy/WrEycO9/SszM8PG8bPNm6UCInUTzzU3d05Pv6tujrdMPZ1dX3U11d37fry kT5/sGpVpL1B6e7WVpGQPW1tC7OyBIwbh4cZY/0+X7z2muM47naRiPEWAIRCIYzxpk2bNE07evTo hg0bYnCDdH1D8+T6W5NaNf2cqskIdevGsxMBAjBiUAAYp+y9oGrDyIxRl66/EwxJgDZZlPeCKgJY bbq8asj+UHhfUKUAd5llP2Wv+ENugu8yK9HxFgV4xR86pobtGN9rUTIJGaX0RV/QSfBDVlOIsd9M BEYMWiCSx22Wbs34nS+gA1RIAgBc0unugFogkkWEVxxKdm2jo682NXWPj3ssFowQA9jb2dk6Oqoa RqrZDACX/P43mpsxQrIg3D9rVsvIiIBxaUoKABzq6WkeGam7rp5P2+joK42NkfYDfv9QILBt1qxX GxvPDgzMz8iIw05yHMfdnhI03rJarffff3/kccwWYpk2f2uhLC1WpG0WU4gxHeAJm7lVnwCAZk23 YvQ1uyUSfgGAiJAAQK9d1+BIKNyq6SJCB4PhFSY5VyAeQoqEaya3DMYOBNXH7JYFsogBBg3qxPhh m/mZiUCvblCAfcFwjkA+CKgPWsz1YS2VkK/YzRaEdvoCR9VwFRM3mhU+ucUBAEaoOj19aW4uwZgy hhHq9/kwQnM8HsqYcOVJEWOJEIRQJMGLAVyfvBUtkrB1oKvr/fb29tHR3okJg9JZaWmx2i2O47jb XoLGWzEWCZFulL8VIQHSGGvVDZUxACgVhVyBXAjrKQSViMIjVvO0W7kwniWJC2SxTBRSCZYQHAyF 3wmqj9muaZ9GcK9u5AokFSMAkBBkExxmTGNgwihPIKtNcrZAUgm2YuTVaI9uZBICAAtlyQBo1/Rq WeQhV5KL5GlN/ihgvLW8vCIt7eWGhn2dnYtzcmyyfHdZWeR6okhIWWrqmUuXGoeHI8FWeWrqtH1+ bcECAOj2eru83q/X1hY6naOh0NGenvODg5PNRkOhfp9PIiTFZJr5HeU4jrv9JFC8JUqyrsciT+s6 zNDDgijdaP2tHIGYMMompFAQDgXDuQJxYDxHEu40yUdDWhoR8qLmq1IwJoAQQLEgIEDrzfLvfMF3 AqpsQc2a/nZAzRDwRuWaa38CQlsspud9wfeCocdslgKBRLaNvG8uIUsVaW9ILReFeZJYq0gtmvGz Md8cScwVSaqEUwhu1Y3Zspi8C5NzABZJKnK5op8pcDotkuRUlI2lpa80NvZ6vQjgT956CwA8FstT a9fWZGYO+v0/PniwdXT0vy9cOPe664OTfTLGRoLBDItlW0WFIgiUsZCuDwYCs9LSJELcZvPz9fWH e3pmezz/+447hCSuRcNxHHcjiRJvYSKmZxYO9janeXJNFlvMVjlgjPnGhwZ6m9PS887XN/b29E7J 3wKAr9otkSUevu6wUAYMmIjQAlkiCApFgQDMlcTJxneZFQpAAL7ttAoISkThe04bAxa5gX6tSQaA Dt3Y6QtMbrJIlubLYrUkMmAEIXxl28n3fdRmfthqQoAEBBZAX3dYKGMAICBEATDAfAl4sJXk5ng8 Fdde4PtWXV3ktyjDan2ypgYDvLxjx+SrkfUdNpWW1uXk/OzIkYahobnp6ecGBgYDl4/MSM7WHy9a BAAIobnp6VVudySWwgjdW15OATaVlAgY31tRsbmsLLIVD7Y4juOmlSjxFhGUwvIFTeePHT/wEqMs ltVdEIDVkZpbWGUdm0j3eK5ffwtHPcAossXl9bEiUU70WlnoypOR1RzQ5Vcvt8Ao6odrxxDdLLLt te97dSMCQK78eP0AuKQ1ZTUHEn3MIARXYqxoGKEUk+nJmppD3d2UMRLVQyTHK7rP6FgKIUQAIHI8 I3R9zxzHcVy0RIm3ECZWh7tqwZqAf5xGrcoYA4IoW20OQRQ97hSE8I3yt26hElEoERPlk+eSHEYo 3+HIdzgAoJynwHMcx82MRPqrzwxD9WrBYV3TYji/hagkaxIWiNMXCKohlddP5DiO4zju1kqUeItR wzt6sen8Mb/PZ9DYzW8hhAghKanp5dUrGi409/b2R/K3mpqbvd7ROOXvJ52xsfGh4bF9+/bFeyBx YxjGmM93NBiUk7gqTnM4DM3N8R5FPAUCgcHBwQ8//DCZiyNdvHjx5MmTPT098R5I3AwPD/f19SX7 +XBs7OjRo7Isx3ssV2FjwincVHnlaeItTdNEUbz++QjDMPCV6mm3kKGH2ppOibJ9Ye0mSY7dLeWM saBvrP3C0d6u5oKCgvT0zEj+FkLIbnd94ubcLaEbaHhkPN6jiCeMsWYYBmOQxH9oOUKIKIqUUpLE +XCMsZku3ZbgKKXJHHBD5HyoaUZsM4s+0c3/v0yNt4aGhv/5X37xyCM7igoLJiZ8uqE7HQ6E0MTE RFjTBCK8/8HeUEh9+KEHAoGA1To1tfxzo4Y22N9Vvfgeu9Md40PNZLYFA96u1lPFFbWT62+VlpbO rirTwjOey8UBgNkshcPqypUr4z2QuNF1/dzhw0t8PkcS/6EFACgtTebDYHx8vKmpacWKFTEop5Gw enp65s6dG7NlrhNQW1ubqib9+fDcuSVLljgcCZTe4xvt7ap/+2Z6mPpb/ftdrz772/8CgIcfeuA3 T++cmJi4e/PGgvy8f/n5r8bGxjIy0k+ePK0benl5WXd39z1bNt/C72G6FibCDefVZg5CSBBlXdOu WX+LMS0cVtVg7MeThLSwGu8hcBzHcdwMmhpvPfqlh/buO/DVJ584dPhoV3ePx5328u9f+dIjD5lN ypzZS9etXf3Ou+8RTGrmz5s3d84XZtIbAQCwaesnchzHcRzH3aSp8RYhRJYlAEAIAWPFRYW5uTkL auZbLZYP9u3f9crrdoeNGhQhmLmrfoyx06dPX7hwYdGiRaIoHj169K677rJarZqmPf3005s2bcqY mUK509ZP5DiO4ziOu0lT4y2M8fp1aw98eHD+/HkXGhtPnjotSXJDw4X/fHpnSA3dtX5tSXHx+3v3 NTRcuNDYfM+WTTORZ6Dr+r/9279lZWW1tra63W6Xy6UoCgA0NjZeuHBhy5Ytt/wdI25UP3GcUjvG SZ2+yCW8sGGMBIMAQDB2yLJEyGgwqBoGAjCJolWSEEIDPl9knRUE4LFaEUBA03zhMEbIJknydb/L k31OttcpHQkGXSZTZB3UAb/fbbH4w2GJEL7kKcdx3MeYZn7r3q13B4NBm83+P/74j0KhkCiKVqvl L77/HQZgt9kFgRQW5suykpWVNUNJnYwxSZJEUTx16lR5eXlJSYnX63W5XB9++GF1dbXdbp+JNwWA G9VP/Cy5Q9YAACAASURBVLnXv9mszJbikFvGcZ/Syf7+P3r99TyHw6kodxUXP1BV9bf795+9dMkm y4VO5x/Mn59mMt333HNpZjNGKFI/UcT49xcufNDRgRC6q7j4ruJi27V3X0/2GWnvUpQzly799MiR ByorN5eW6pR+d8+eH65Z81Zrq4jxI3PmxGvfOY7jEt80AZMkSZIkAYDNZrXZLl9cS01NnWwQuS3R 6ZypGwcEQXj00UcPHTqUlZXV0dFBCLlw4cIDDzzQ0dGxffv2yNhmwo3yt/yUaQzGKD0YCgcpmy2L NoyGDDpHElXGzqhamSTWh7Uhgy5SxHRCjqlhBDBPEsUrl1xHKe3WjDJJ8FPWZxj5Ajkb1ocNulAR M6Zrz3GfFWOsLifnx+vXv9/RsfPs2ftnzQobxl/ecUdpaupPDx8+1d+/prDQY7E8vW1bZCJKImRP W1tA0/5uzRoG8FJDw7G+vtWFhdf3+ZO77oq0DxvGu+3tsz2evR0dK/PzTYIwGgoxAFXX+f0OHMdx Hy8R7zrGGFdXVwcCgdHR0UAgkJaWdujQoVmzZjkcjuzs7JnLG/v4/C0MSGMwSul/eAP3WpTDajiL kAuafjgUDjJ4PxgyYzRMjS/bLK/4QxWiMO/a+bAzYb1dNwYNWigSL6XvBFQFo4uG8eQN2nPcZ3Wo p+fPdu8O6vr8jAyMsUHpPx45kmoyMYDSlBQAaBsd/c6ePRghqyT9+dKlPV4vRshtNgOAiHHX+DRL oB3q6fn27t1WSfp/li7t8XoDmnZ3WdlrTU1HenruLCiI8Q5yHMfdvhIx3gIAv99/4sSJO+64IxQK HTp0aNWqVQMDA9nZ2WkzWd/tRvlbERpjw9Q4oWr1Yf3rdosb4xOqdjKsrTJJnZpxSA07ME7D+FEr wwBlkhA9WeXEuFYR/9MbyBXJUkV63R/KFoSlivgLr5/BNO057nModrkera42CUKhy0UQQgitKyoy ieK5gYE8hwMA0i2WHVVVkVwrp6IoguALhyljFEDAWJkuPaDY5frSnDkSISZRPNzT80Zz89He3uFA YCgQqM3KivkuchzH3a4SNN6y2WyPPvqoxWJBCC1cuFCSJISQruszugzgjfK3IgYM2hI2VprkIUoV DHki2RNQrRiXi4KPshWKPFcSswQiIAQAIlwTPAUYO69qZaLgZ6xV0+0YNWn6/hBLJwRN157jPocM q7UuJ2fyR4xQdXr6vIwMjNCetrbFOTmRJwFAo1SjdLbHc7i3d29np04pZWxOevrH9NkyMnLJ7/+n jRvzHI6hQODVpqaT/f2MXa5z2jE2drinxyJJVW435t8cOI7jrpOg8RYAOJ3OyIPJBPmZLqV0o/yt hbKUQrCb4IWKeFrVaiRRBFQoCOMstEIWrRjXyuKQQc+ENQowXxYj7aN7mKDUSfBaszhs0BZNr5Gl IYMOUbrdaiJX+p/RXeO+8DKs1qW5udHPLM/NTTObFUG4u6zsg46OoKbNTk//r/PnAcClKFVud6Xb PREOv9bUdKCr60/r6mZdN3k82SdjDCE0x+OpycwUME63WMZVVad0Y2mpVZJmpaWd7O9/9uzZAqez 0u2O2S5zHMfdRhIo3sIYT35djjHGGEL4RvlbWyxK5ME2i2mbxQQAfbrxzESgVBDmSiIBsGP8oNUU 3d7P2I/HfOP0cm3LPIE8YbMICBwYF4kCADxiM1/fP8d9bgVOZ8GVrygRO2bPjjxwyPLW8nIA+If1 66dstSQnp9rj+eWJE7tbWzOs1g+7uzvGxiIvRXK8Hp49GwAQQsUuV7HrckVRhNCy3FwAuCM/HwBW 5OevyM+fwX3jOI67/SVKvIUQtjvdvvFBml1MSExHpYVDPu+Q1e5yp6UCM26UvxUtheAtFsVDSOoN 5qUkgDUmeTJ4NGEk8GssXEIyi+Ljc+d2jI/n2u0WSfJfqRkayfGK79g4juO+MBIl3iKikl9S3dna IIiy2epAscpnooyODfWODvaUz13h802EgsEb5W9FUxCq/NjbCUWE5sn8fkPuNoAQcplMLpMJANLM 5k9sz3Ecx30OiRJvYSJl5FYQydrXeUEN+WN2YRFhbLWllM5Z5nC5jx470dd3iddP5DiO4zju1kqU eAsACBEys4szc0tjNrkVwRgDZjBGC/JzMzKyIvlbx44fb25pNAwjliNJWgF/YGx8YufOnfEeSNxQ SnsHB3fpegL9QsZcn66jY8d6enriPZC4UVW1s7Pzueeei/dA4qmpqcnr9c5cHZHENzExcfHixWQ/ H/b27tq1a0ZXJPisTEK4JOOmQoIE2hkAYMwAw4hPzjyAx52KEI7kbxUUFFRXVwPEayzJpa+3r+HC hbq6ungPJG4Mw7jY1lYdCNhx8t6pejoUogUF8+fPj/dA4sbv94+OjtbW1ibUn5kYm5iYqKyszM7O jvdA4qa3t5cxluznw4sXZ7R83+cQ9g9S7/mb6SF5f6uv5/MH1JAayd9yu9OcdlM4zOuUxIKiELvd VlRUFO+BxI2u62ZZLtQ0RxJXfe7RNHC7k/kwGB8fl2W5qKgomeMtm82WnZ2dzIcBAHR3dyfzJ6Dr utlsLiwsdDhmqmzg5+Ablbvqebx1i9Q3NF3N32JAKTUMPd6DSgqUX7flOI7jvtB4vHVVdP4Wx3Ec x3HcrcLjraui87c4juM4juNuFR5vXRWdvxVjDOCibmQK5HPcmdmo6UUCCTKgwJwYDxnUALBiNGjQ HEL4OqtJwq9p5wcGKGMSIQVOp8tk6hwb6/f5MEJORclzOGRCTvb3hw0DABBC8zMyJEKGAoFurxcA sm02j8Vyoz4n26uGcWFoKN/hiCyFem5goCw11auqBqXpVj4xzHEcd0M83rrqmvytWGnRdADIIOR8 WM/47PGWxthPx3w/SLEPGxQhEAE94wvUytKAYQQYbLcoAq+EnRzOXrr0zTffrMvJMRircru/vmDB jw4eHA4GUxQFIfTl6uoCp/Mbr722ICtLwDhSP3E0FHqtqal5eJgyVul2byotnRJyTfYZaS8RcrC7 ++fHj99TXv7Q7NkGpX+9d+8/bdz4WlMTRugrSXxfIcdx3Cfi8dZV1+dv6YwdUzUzRqWicFrVFsrS e0FVZaxJ0ynAZrN8IBQWAQkINpuV6JrTBsDxUPi9oGrF6AGrqVs39gbValm8Q5EB4GgofCAUtmC0 2iQ/NToBAH+RYh+mlDK4aBivB0IAcLdFySDkV16/FSMFoc1mRUbXRE5+yt4Pqj26MWAYAOBl1KDw ZiD0nC84ZNDjarhKEu82ywri8VayqM3K+tG6dR90dDx75szXamowQn9UW1uRlvazI0daR0cLnM5M m+1H69ZJhACARMgHHR2Use+vXAkAz549e7S39+6ysuv7/PH69ZH2/nD4YHf3+uLiY72964uKHIqi UwoAlDEap8qnHMdxtwseb111ff4WQahPN/yMdWrG3pBqABxWw5Hrd2tNioeQ/aHwapPcqRsfqdo6 szy5oY/SVwIhJ8ZLFBkDetkfyib4w2C4WBAYwJsBdalJKhaFfIFUyyIFMCH0bjB0v0V5OxDSGDMA dgfUL1lN+4PhtWbZS+kJVVuiSNGj7TWMD0NqjSxG4qkWTWcMlsjSsVD4HrMyatAlsuRI4sWcktDe jo6HX3xRIWRjaSnBWDOMv9m3TyLEY7F8qboaAJqHh7/88ssA4FKUp9auHQwEAMAiScAYQWjQ75+2 zx0vvOBSlB+uXds6MuILh8tTU3vGx9/v6NhaURHjHeQ4jrt98XjrquvztxBAhkD2BNUQ1ZYp0qv+ oILQo1ZTfVg/rKoZBCsIFsviAcbGGY3uyorx3WblnWDoSEi1m5XjargVYzNCBkCQMgSwXJGdGAFA rkAYgOnKLNRFgy5RJMrYUVUDAAXDapO8L6h26caSa0cbpExAaIkivxG4vEgYQlAkCmaM5sviawFc LPLcreSyPC/vB6tWYYQcsowREjD+Vl2dIgiHurslQhhAWWrqP27YIBGCANwWi12Wx0OhSEYXRshp Mt2oTwRgFcVDPT37u7rODwwENG00FFqWlxfzXeQ4jrtd8XjrqmnztzIJ7tb01WZlhSKfV3UVGAVI Jbhd0weoEWLwdlAdMeica8tXMwYhxtIJ6dONEGN3KrID4ywBpxM8gZiI4NmJQJ5A1prldEIawrqX Xg7XykVhX1AVEKqQLv/XKAghBMZ1K907CdYZe8EXHKMUOA5AFoSMqKR1hFCqybQgK0un9K2Wljvy 8y/5/W80N2OEZEG4f9asBZmZ77a3//vJkwxAEYSajIyP6fP84OBEOPz0tm3ZNtt4KPTM2bMf9fVN Xkbc39UFABlW6+bSUsJnVTmO467D462rpl1/K1Mgf2i3FIlCGsGP2Ew+xnyU+SnbYFaqJAEDFAnC AglVS6IWlcISYkABUjBeZpVKROERm/mEGpYRYgAZAtlhNdeHNQGBALBQlhwYmzB62GoWEFpjlh0Y M2CLFQkj9ITN4sBokSwBgHZtikwmwdutphGDVUjCZBvLlX62Wkw5QvKuVJ6ESlJSdlRVRT/z8OzZ hU6niPHK/PxUk8kmSd+orVV1HQBEjCVC8p3Olfn5B7q6nj9//hu1tbkOR/jahWcn+2QAaWbzppKS fIcDI5RmsWwuLdUp/eaiRSkm08r8/Eh7g1LM8wU5juOmw+Otq6Zdf8uE0OIriVPF4jUfl8ZYFiHL FCmNYJ3BT8d9jZoWecmB8fecttQrGfQFAikQrl6smSUJs65MX4kIFsgiAGSZCAC4MI7OA1umSABQ IgrT9r9AvprRVXJlbKtNMsDlPrnkkWY2L7/2At/S3NzIA5Mg1GZlAcDjTueUrUpTUnLtdhHjF+rr ZUIOdHefGxiIvBTJ8Yr0iQDSLZb0K3cvIoCy1FQAqHS7AaAiLa0iLW0G943jOO72x+Otqz7r+lsi Qt91WSMFhgUEX7WbtSszUAgg+nbFmzfT/XNJSxGEHbNn31VSYhbFhdnZk1NckRyv+I6N4zjuC4PH W1d9jvW3om8AdM5w2spM988lLRFjt9kMABaRT4tyHMfNCB5vXRWdv2VQI+L/Z++849s4rsT/Zhs6 QIIAO1jFIolNVLWq1btlxY5cz7HjJJfmlEtycZxfnMTJxUnuEueSS+I4dhI3uava6r1SEklRpEiR Yu8UAJIgOrBlfn8sDVEA1WWREuf70UcfYrGYeTPz3uzb2bdvRlqoMYEkSZKEBWHs7g4ua5oIIIzh RFYYQBLFMa4GGGMy7QiCMMbVQJKkMd4D8v+jqhNu3jCJv3WRofFbx44dP3PmDCav/t0WfH6f2+39 29/+NtKCjBgY44aOjvUwpncDsIkie+xYTU3NSAsyYgiC0Nzc/Oqrr460ICNJa2trT0+PQqG4+ql3 KV6vt7+/f6zPhw0N69evR6Pp/RutQpyUNUzSnGuH+FsXGRq/NW3atEmTioi/dXtoaW05d65uzZo1 Iy3IiCGK4psvv7zG49GP4afGx71eetq0adOmjbQgI4bT6dy8efMjjzxC02P35eINGzZMmTIlZQxn d2tubq6srBzr8+Gbb65Zs0av14+0LBfxOLocHcdvpgTib11kaPyWguNEwRcM+EdaqDGBwPsZhjYY RmCn8FGCIAgMTespyjCGL7RqigKFYiyrAQAghPR6PcOM3ZlZoVBoNJqxrAayAozlHhAEgWEYvV4/ qjqBltyOmyth7Fp1JOH5tzDgMRxMc1sh/UwgEAiEUQwGwBhjSZIkCYZ70Cld7YEY8bcuMmz+LQKB QCAQCGOcIC82t1m7bF4YElY2dFEGSxJNU+MuH4ZL/K2LXG/+LQKBQCAQCGMBScIx8eMKpy+Vl7rk xzKSGMSSCFjEWPJ5XdUVx65QAvG3LnID+beGEsT4VICfoeRogCDGR/zBAo6Noan9vsAMJae+/vcs TgWCmSxjvFoA9dB6CWOWC273J/X1oiTpFIp7LJYUg+FIa+s5u52hqNSoqGlJSQqa/rCmxh0MAoC8 f6KG4xp6e0u7uymA4oSEcTExaLgyBUmSz9dynDMQ2NvcPDUxMUmvB4y3NTTMS03tcDoBgKSYJxAI dzcUzajUWsAhfwuLPCVJPJYESRIE9ioX4bH7MlQkaamW4uJJYfsnAoCA5cRIg//Lq4cSAI8x/+lH AUOfJP3L5RExFgEGJPxiv2unzx/E+B231yNhDCBg4DHGACLAJo+viQ/PLBI6R87ysdXjb+IF4dPV SrnGUAKQTwXAAxIO1UsYszQ7HOurqjDA+b6+1ysqBElaf/Zsi8Ph5vlNtbUl7e19Pt9fS0sFSYJP 909s6u/f39LiCgT6/P79LS0tjvBgULnM0PkAsL+l5cOams11daIk8ZL0anm5Oxg81Np6qLX19jeZ QCAQRgQsSTB48QeM8TWGepP1rYtcLn7rHy6PU8IeScpkmWZBLFawS1TKOp5/w+VFgJaqFfeqFP9w eQYkyS3hJl5sFoR0lmEQdAhiIz/oBfWI0ka3r00Q1mpVPIZf97uLFewvjPqYIdvy9IrSFo/vdJDP Ztmv6jUSwE5vYJ8v8AWdOpamS/zBT7x+E009rlVHU9RRf+Bjr18EWKdRSRjkeqcpuBiyz89YxWIw rMrOPtbRsaO+HjBmKGp6cvJ4k+mC293r8wGAXqFYlZ3N0TQCYGm6oqcHIfREQQEAvFlZWdbVlR6x waLFYLgvJ0c+v8/nq7xw4f7c3OPt7V0uV7w2/M6EQCAQ7nqCPF9VeSYtLdUYHS2KYlNzi8AHx2Wm XvWH5Np8EbfHa7f3imL4slObIOopNI5jjvmD81WK3d6AU5LSGWadVpXN0ps9PhHjdkFMpGmXhLf7 /EaKiqJQAk1bGLo0EAxgAIDyQLBNEGNoapvHX6xgZ6m4dVpV2B6IpwJBqyh9y6B9TKdiEQBAHE1l ssx2b0DE8LHXH01RXYJ4OhB0Yeljr3+1RvWjKF0KQ9skabBe4myNYQ62tHxj27bdjY0PTZzIUFRQ FF86fvzbO3bYvd7pyckAcL6395nt27/2ySfPHzjg8PsH/H4EwNE0xzAAID9qjCxTPr/f5zvV1WX3 eimEMMCOhgaRvFVKIBDGHoFA4MiRo//857/q6uoOHTn2t1f+2d194Vp+SNa3LnK5+C0KYLKCQwC1 QWGqgn3d5ZUAzgb5LV6/BGAXJQBAACaaYhF4JNwrSSlA0wjuUXDvun3dgggAfoxreT4X2DSGViKk RUhHhYd0+SSspahEhtYgJNc7ScEhgM0eHwbcLYg2JMXRVDRNiRjcEk5haBNN2UWJhsF6b09HEUYn y7OyXlq6FAAYikIIcTT9iwULTGr1lro6VyCgoOm82Ng3166VnwxyNB2n1Xa7XF5BwBhTCMUNt14V KtPD82d6eqwez/7mZg/P19hsXS7XbW4ggUAgjDg6rfbhhx/6+99ffe7HP+EU7INrV8+8Z+q1/JD4 WxcJz7/1KQxCFAACoAEoAHlHXxohHuMABgEggIFBCAGKp+nVauURfzCZoRlASQydx7ElgSAA5LLM FAXHY5zA0BhgkoKrCAo5LKulLjpdExRsldv7X/2uPJZZp1WH6kUAFEIr1MqqIK+jKB1FqShUqGD/ POA2UdRyjTJUr1UUE8ZwwsyxDIUQ82mUlQxDUSxFZcfELExP39vcPDslpXVg4Id79lAIaTnuP2fO nJqYuLOx8ecHDgREsTghYWpi4uXKxABtdrtXEP60fLlJrfby/JuVlaVdXTRFyRWtr6qqslozoqO/ OW0aO4ZT5BMIhLFAXFzcl57+4gcGfUa6Zf68WQyNJOnqWz0Sf+sil4vfelKnNtMUADxNaxiEvh+l NdGUnkJReo1LwkqEVBR6Uqc2UCiVpdMZ2kRTBor6TpSWQ2i+SpHDMSaaiqLQ4zr1gCRFUxQNsEil 6JckH8Y+cfChDItgHMM8pdP0i5KWQgy6pF4aYKlaOZ5jACCJptUIPaxVtQsiAkhhmO9EaeV6r/oy I+FuZWJs7HdnzBh65Jlp0+K0Whqhwri4WI3GoFD8deVKOa6To+kopRIhtDQzM9Vg+Ht5uZpl9QrF BY8nFPiJACaazXKZCCAzOvrpoqIYtRoA1Cy7NjcXAArj4uI0mpVZWRPMZgDQcBxxtggEwt3LxSCK +Pi4p578AktjisJYdrauFmJB/K2LXC7/VgozuGZgYWgAyGAZAFAgNI5lws4xUBQAJDE0AORQDABo KZRNMQDAIpTG0ACDRWkpFMDoRYdr4NOHgDks+x2DNoWhQ9WF1aunUB7HhmqMoqgobvDapqeYUL2E sYmGZTWXRrtnREfLf7A0nWIwAMD0pKSwX8VqNNEqlTMQ2Fhba1KpdjY21vX2hr769aJFaZ+WqeU4 LccN/WHo/zitdthnkQQCgXDXgBCIvJ8P+FhOKR/QarUi75MkXj4h4HMDXCmqh/hbF7nJ/FvXSwxN vWi8ZDNOZhRthU4YK7AUtTIra2lmJkVRc1JTpSG3aBx5Nk0gEAgAAKBQqCQx0NNxPjF1QtiO8hhD MODvaKs3RJvQ5XNtEn/rIqH4LYqiAIEkiVfeDglfNmv/tRL26OW6XvhCAAjdNS+ISQAYS2M3gxjG Ik0hTCE8Ij43QgwlTx9o6Cxym9ULUQhjaWyrgUQhwFjE0ti996IQYEkcy2oAWEJkPry9swGGK853 CBCi1NqotKzi7s7G7s6m0G+wJGIsAWCEkFJlyMguROiyMRXE37pIKH5r4oRcp8PeWH3E43EPe6Yo it0eZas/4TZLOASsY7wLMpz0XTEtMzxv0QVqT7wz0oKMGBjjnHTchdXdIy3JCMJKHBWsrT3RMdKC jBiCIGTFuhtKPxhpQUaSRI3N1Xm41nZipAUZMQLBYLLOOdbnw3hvV83H3de/L8uN4Q8KvY4AzSqG FQdhMSk1NyVjojneotVFBQI+jMPWYhDNMGq1TqFUX6EW4m9dJBS/RSPR3tNkMicVTJ3IcKrIM+0X 2npPViRb8q8xq+wth+d5W0tVbEIqQ90VDhcBINo0gu77qCA81+qYxBSXPNIijDBRMfEjLcLIEzfW J4PbPR86HP1qUV00fVnkV1gSe3sauzuaFApVgmWcVh+thegbq4X4WxcJxW/12bs1emPG+Oksy8Fw /rVKpQUKYcTw4kj4WwhoBhCiFCod8bcIBAKBQLgZOD9Pe70q9fDv/agyitQ6c31NSXxyBkI3HtVK /K2LhOK3+GCAYRQsyw7ZA5x393cptUZOqQMAAIwxiBIWrzPFqIQlClEYY0AIAWCMrxBbd1kQAGBA CFE0Iv4WgUAgEAg3AUIUIDmhA/Z6vWVl5XFxsdnZ2Z9+C2qN3u8bPr7o2iHJci4Sa45JtcSDFMQg 7/4NgDFgLPKB3q4aV387RTHyEcCD/pZwPf94Uao9e8br83V3dXZ3tPkCgbqaSl4Qr6sQQcKiiCUJ 3+5gZgKBQCAQ7lbkmHmMGZrutdtfe+0ftbW1GEuDF3241k2prwDxty5yyf6JGGMsYixKYrCvu8bj 6DIm5NIMKx/EWMQYC6J0ff8E0e1yCqLk83l9fj/PCwMOx3UXIkqCKIlDNicnEAgEAoFwc2DAEsYi y9KLFs3X63V//vNf2tva5Cs+hAfI3wjkeeJFhubfwliSxABgzPM+n9sOgCmKkoSAfKYk8hLGQUEM 8NcxBhhLoiQFeVEQJQAI8qKEpYAgXm9aB4QAUxLxtggEAoFAuCVgLIliACQJADgWxRijTp482dnR mhhvQgiJYuCq6eOvCvG3LjJ0/0Q58wfGEk2zxoSc/p76AVuzwZxOUTQAyOtboihdOUFXGJIkIUSJ 0uCqpChhACSK0g3sgIKvmMSWQCAQCATC9YDlxG+SJJWVV1RXVz/15GNFhXkYixjDLckERvyti1yy fyKWsCTIOTY4hSY6NsPt6BF4H8sqAQBLIsZYkrAoXp/fk5QxnmZYQ0wcQoii6aT0XIzhegtBCCRE 4rcIBAKBQLhFYNnfEjweT1NT0/x7Zy+cP4emQN4bEV/DdtRXhfhblyA7WBRF8wGvKAZDLw+yCrXB nErRLMYiAGAsAgZJkqTrfKynUGokCdMMBwAYg1Ktu94SZKS7J7M8gUAgEAgjDIbBoG2NSrFqxWKK ojiWlq/4AMAHgzRzs/4S8beGQW8wdrbZ7D0t0aYEmh7sIoQAf7otJZZEDJhCiB2Z/O4Iw4gk/iIQ CAQC4W4EyxtJCQCgVDDw6ZoWxtjrHujqbDOaEq6wV8+1QPytYYiOiXe7HI11Z9jmejRcdFUg4PO4 gnZny20XbRBJlDSS29peS5MXTAkEAoFAuAk8Xp/dOlB+Ym/ke4gYcNDn0kcnZk0ovJF8mUMg/tYw 0AybnJoTZYwVBf5yy0iZ+axXZG+rWJfCUtkxKn4EBSAQCAQC4S4AY5yUddmIeApRaq1BqdLcZC3E 3xoehuWijHEjLQWBQCAQCITPHN1nXwV5HEUgEAgEAoHw2XKV9S1RFE+eKj148IhSpVy5YllmRvrJ k6UAMGPGtGspHWNcVnbaHwhU19Q89PkHo6IMGzZunjKlmGO5hsam2bPukU8rKTl57WUSCAQCgUAg 3FlcZX3L6XS98+4HFkvy5OKis2ervV7v+YaGyqqzdnuvnOqTF4Te3j6Hw8HzwoDTiTEWBDEQCABA X3+/wzFQfrqiv99x9OjxYDAIACdPldmsdo1GnZiQAACBQKC3r6/qbM35hgYA8Pl8dnuvz+f7zNtN IBAIBAKBcLu4yvoWBqxUqgRR0Ol02VlZGo0GAI6XnGhuab1/zaqpUyaXlpa/996HFE3ft3rFyVNl K5Yv4YN8zbnaFSuW/v6lP82dM6u3r2/B/Hsxhsqqs9FRUTabDQDq6xt37dn7n9//7oaNW44eO+4c cC5avCAYDL7z7gdHj5VMmlT42KMPRUdF3Y4OIBAIBAKBQPiMGcbf4gMer8sm8n4A0BlTvvbVL+3e H/38LQAAIABJREFUvXfjxi2JiQmPP/YwAKSnp61YtvTDDZuKJxXt239g3rzZgiAcLzmhVCrPnq2u b2jyer0Mw7jdbsfAgEqpSkpKHHA6N2/5WKPRtLS0AQDG2OEYEEXx8JGjD6178PjxEwDgdLm27diV nTXu4KEj986bI/tbnoGegNdxO3uEQCAQCATCaAQhVqFRaU0MqxxpUa6bcH+LD3h6u89RNMsqtBTF CBLV1dW95r5Vdefr//GP1x/43P0AkJaWmpJi6erqxgAIUTwv0DSFJZyZkf7hR5smTMhdtHD+m2+t j4uLO19XP2/eHJqhowyGn/z42dhY87PPPT+0OpqmAbAkbyiIAQC0Ws3qlcvjYmPlExDFUsyd160E AoFAIBBuMRj73H0B70B0fBZNcyMtzfUR7m85+9o5pSE6LouiGQAcDAZ9Pt/vX/pTX3//vHlz9Hqd Rq3heR4hFBVlQAAL7p373gcfSZL0yMPrDAa9Qa+/b9VKiyX5+PETKpWqt7evID8PAMxmk5woLCrK gBBiWEaj0VAUNf/eeRs2bnG73BnpaRqNZvXK5ceOlTidrnnz5sjyaPRmjSH2NncKgUAgEAiE0QbG mA+4HRcafO4+rSEB7qiNhNHuLa8uWP5YwOtorT2YNem+zvrD0fG5al1MaDdsQRCcTpckSRqNRqVS BoNBnhfUalVvb5/JFCOKotPlkkTJYNAjhFxut0GvRwh5PF4ACAT8RqMRAByOAfkEj8fDshzLMgMD zqgoQzDIO51OhmFYltVo1MFg0Ol0IYQMBj1z03sVEQgEAoFAuLvAvV21NKuKjs3AEengRw+SxF9o LmUUOlNiblPNkfbOCxE+DZYoih7aBoZhjMbo0EeO4ziOAwCTKQYAaJoeGtgeZTDIf2g06tD/ABAV FTquGXqE41i5nFDhQz8SCAQCgUAgDAEN7quD0B21vBWRDwIDAIzIHswEAoFAIBAIdyckv/wggiD4 /P6RloJAIBAIBMJdyDXFSGEJsIhBwoAAUQjR6PYsgd3OetvauyqraubNnRUdFb6Nks/na2/v8Pn9 JlNMfFwcTdOflRAEAoFAIBDuRq7ub0kBydvvsve0e5x9iEIaQ7QpwaI26BD72a6N3eZ6tVpNcnKy QqUFhABf8kx41559hw8fVSgU4zLTFy1aEBcbe+LEqZkzZwx1vDDGe/bun3nPjFDIGoFAIBAIBILM 1fZP9Iv21o7mpnJWq1BHRQOAfaC9p6d+XPZUoyUJUeHLTZIkiaIIgBiGRghJEsYY0/R1e0jXWy/P 8yzLAoAgCAzDYIwxxhQ1WK8oihRFDUbYXYZYc0xcXCwAhSU+7Ku6uvNxsbGPPrIuEAgwNPO/f/rL W2+/+5P/92yc2bxv/0GTKWbF8qVlpyt+89vfP/7Yw48+vG73nn2dnV33rV5hMpm279h1/nx9YWHB /WtWkYUxAoFAIBDGJlfyt7CI3Rf6W1pOm9LSTEnZgogoCjEUtnc3NDaXqWOjVSrNJedjfOjw0R07 d/v9/mVLFy+Yf29DY+OBA4e+/rWvXJdMoXrNaekpWYUKlRYA/F5XR0v1sPUKgvDib373tX//ktls +vtr/5o3d7Zer6+qql6+bLF8wu49+0RRXLli2RUqFQSBF/wqpVJuiCTyckYMimbW3Ldq1+69v3vp j0WFBatXLZ81854TJ05NKixgGGbmzBnV1TWbt3y8cuXyxIT4osKCM5VVpysqExPitny8rXhS0cFD h+fOmZ2fNx6LQUG8rm4gEAgEAuEOBlE0RTMIkUhxgCv7W6JP7Oqs05pizMnjN2zcvGHDBofD8cgj jzz6yMN+n6unoyE9q2hotjFBEDZt3jp5cvG0KcX1DY0Oh8Pn9dXV1dfWnU9MSNDptIIgdHR0utzu FEsyLwgURRmjo202u9ls6u7uiTZGy+5OqN6MCdNZTiEXrtZGZeRM9XudkfVKGDc0NGKMAaC1tc3n 9aWmpFgsSQDgdDo7Oruqa86ZzSYA6O3r6+rsNsZEJ8THh1a/ZIbEb2n9nj6HtZEPuDHG+pgUk8n0 +QfWWm229evfi4kxTp0yWaPRWCzJBw4e2rFzb1tbW3p6WmpqSlR0VG5O9r79B48ePWaxJKenpxUV Fly4YD1TWaVWAMe3X3mBjUAgEAiEuwZEUaxCrYtO1hjiicsFV/G3AqLV1pQ/Z/mp0vL9+/fr9fqD Bw/29PTk5ORMLsw9W7Y7LatoqAeBECosLOjq6qqs4iYVFRqN0e3tHU0tLe+88356etpD6x44X9+w fv37gUBg0qRCAFCrVbk5ORs3b33yicfeXv/e6tUr8iZOGFovy12SrZ9h2MSUYeoFgCDPf7Rhs0ar rq9vAIDa2rqNm7e+8LP/99b69+rqzjv6HQsXzff5fG+//V5DY2NCQvwXn3oitGWQTCh+Swj6nb2t akO8PiaVolkAKDl+vK6uLhAIYAx6vZ5hmLi42Lq6852d3SqVMic7y+f3S6KYm5NdW1dnsSQvXrwg MSFhfG6Ox+OhKEqn1bZ02Nc++DjNkOeJBAKBQBgTYEnwDPS4+toZTq1UR139B3c7V4zfwjgY9KrU ut7e3pKSEoRQIBCw2Wx2u51TFnndAwBo6DoTwzBr16yqOltdXVP75lvvfOnpJwHAkpz09NNPvvjr /1m5cllt7fmUVMs9M6b9/dV/rli2tL6h4UxllVqteefdD3x+P0MzYfWGZwJDiFOqI+sFAIHneeGS uCtBEERRrKio/OpXnj585BgAeDzej7dtT0iIP1/fsGL50jB/KxS/5XX2SqJoMKUhQFgMAkB+3nie D3Z2dt1//+rCwnyOZb/41BNYwqtWLi85cdLhGEhPT6MZ5tFH1lmttokTxiOA9o4OhmURQgzDFBTk TZ8+lUIiFskDRQKBQCCMFdQ6k99tD3gHlBojjOJc8LeHK/lbiEEardHj7EtJSdHr9VVVVRRFZWZm WizJroFefZQp7HxJkk6VlptNpklFhWerqvsdDgDQ6/Xx8XEejwdLWK1WOxqbGhubNRpNYlLihxs2 ZY3LXHv/6j//5RWapvR6XVi9Wr3pkmdwGA9bLwCo1eqH1z0YG2uuqakdejwqytDS2mq12aKNUQgh S3LyPTOmpaelZY3LDCshFL+FJQkAKIqRxGCo8Nmz7hl6cm5OtvzH6lUrQgdTU1JSU1IAYNaQky2W 5Cv0MIFAIBAIdysIUQhRGGME6I5KBf+ZcCV/i1bSCYnZnU3VBYVzf/SjH33wwQcURa1bty5/4viG s4eS0vPQpctMskPzwUcbe3p6Zs2amZaa0tHZlZqaAgDjc3M4jp0yeVLV2eqSEyfX3r86NSU5L2/C ogXzs7PGLVpwr9PlMhj0YfVGxSQq1RezYfn9nq6Wmsh6Q+UDQIolWaVWAUBqagpN00sXL9q1e48o SbFms06nW71qxY6du5pbWnNzs9XqSxI3hOK3FOQpM4FAIBAIt5CIq/YYJHy/6o7zB01JBQq1DjAG jL29rpqqwwq9xpJRqDGYMcYep62tsYKiqPGFcxmaDutCjLEoinIuBjn9gZygQf4fAERRlCSJpmmK okRRRIiiKIQxlg+GSgnVmzpukt4YBwDOvgvN9eUUhYatd0j5EkKIolAoMYQgCAghhBBN0/JHAGAY Jix63WrrbWvvnjBxIgTtA7aWpKxZofUtAoFAIBAIN0Bfdy3FKKPjMuVX/kdtmbeca9iveigIqaK1 EybNaW2rqj97WBQFAERRlD46LnVcAcPQYXlBAUCOWBp6RP4YOkjTdMivCv0hO0PD1ltXefBa6h1S PjX0CEJIzssVqmjox6GE4rc8gUgn/HJu+ah93/AK9xGjVuZr565p3R2nV6OTu0YfboDR3PY7Wr1H p/CjebgJV+cq+U4RTamjDFna6T6vKxjwAyBOqVKrdTQ9jNNzC7n99Q7NvxUCY4n3uwJ+lxzUFS4j y6m0JooaVW8dYiHg8fuckihEfkfRjEprpBll5Fd3CpIYDPicfMA3zNSDkEKpVaijR0Ku6+MO1KtR yt2hDzfGqG07loSg3xnwe4abqxGrUCo1MaM2O8CotU2R9wd8AwIfiPwKUbRCbeAU2tsvFeG6uJb9 EzHDMDq9ceiR2/Ik9rbWO2z8FsairaeltuqEIAjh70oCUmv1xbPWqjWaz9T1vC4wxs4BW2XpgYDf FymwQqmeULwwNj4V49G7BntlRMFfU3Gk19YVeYVhWc6ckJ4/dSlE7BAw2rjj9GrUcnfow40xatsu SUJLQ1V7S50YcddHIVoXFTNlzgOjNjfOqLXNgN9VcWq/a6AXLo2EQYAYlkvPmZyRMzVycxTCqOKa 9qsGgJELdbtN9V7cPzHoH3q8396VlF4wvmh+mJZjSTq6+w2f16XWXJLsvr6+4fiJkwihWLN5cvGk mBhjaF/FEydOjcvKFEXxbFXN1KmTFQpO3ofxVGm5XqfLzh7X3NwCAKmpKcMez8oaN+B0lpWdtlqt RqNx2tTJUVHDZDTxeRycUnvv6q+F30FiXF2+19HbE5uQOrRTMcYXLlhPlZZjwDOmTTWbTRjjqrPV 9fUNKpVqyuTiuLhYq8127lzdtKmTVSqVIAg1NbUqtSo1xbL14+0er0epUBQVFWZmpDc1NctyyiWX lJw839Ag/z1j2tT6hsbevr5QvbFmc1pq6snSUvlj9rhx06dP3bZ9Z19/f5TBMGVycXx8XGSGWCxJ vdaO2cue1uhjwr5yO3uP712ff+k8GLmvJc/zZ6trJEkqyM9nWUZO2JaVNc5qs7W0tE2dUrxr996c nOzUFMvJk6XjsjKN0dFh/SMfjzEa5d+mpqbI/QAAHMutXrWiq6vr+ImTHMvl5GTl500Me8Iuc/N6 tW37Trk/KUQtX75EFMXIMcoal+l0Ok+Vltvs9hSLpbi4qL2t/fiJk6FiKUQtXDj/2LGSMPmH9sm0 qZN5ni8tO93W1m4yxUyfNkWr1Xo8noozVR0dHRaLZVJR4ZkzlaGxlstZumRRW1t73fn66OioaVMn X7DaSi6td/nyJXqdLmwshraxoaExrMzVq1aE7U96A/oQOb5Wq620rNzj8ebmZE+cOP7UqbIr13vV tq9etYKmqZITp5KTk9LTUmmalm2BpmiLJXlSUcGhw0dH0BaUSsW52jqaog0GfUdn19QpxUNtJBgM Dt0f1mqz7d69T5REWc7FixacOlVW39Co0ajz8yaOG5c5XBpnbO1uLpi2Ii45O+wLgQ/s2/JXURQY +pK4DnlujI6Kamtv7+9zjBuXUVFROXPmjNLSctnWIMKWg8HgsHZ3BRuJHOth91i7Xtu8qj7MmD7V arNPmzo51LcIoTOVZxubmpKTEosKCyiKko/LOYxiY82pqSmXdiwWgn6Pa2DR2m8xrCKst7vb6lrO l2XmTgu7WEbOdUP7x2SKCQaDp0rLu7q7J+Tm5uRk9fX3y/YekrO0tDwpKbGzs6u4eBLLMgBgs9nb Ozp9Pl9jU5Ncyz3Tp8lzoM/ni401z5g+LZRqgBDGKF3Uvf3EmmOmTinUqDiImKQQRdMMS9PM0H8M y8mvuYaVc/zEyZKSk6IgHi85uW37Tl4Q3nzrHY/HAwAbN29taW5tb+t4/ue/LCsr7+93/P21f4mS 9NGGTb976Y8Ox8DxkpPHT5x0OAaGPR4IBvfuO3D6dEUgGOzv76+sOisNs+I96KAyDBcmMM2wNMNK ERlQ+vv7P9m+s6Gh0evx1tbVYYwrzlTu3LXH3ttX39D48SfbHY6B9raOX7343+fO1QGA1Wr73z/9 paTkpMMx8M9/vSnwQs8F66uv/svpch0/cXLotfyjjZvb2zrkvyUJy1NbScnJkpKTACCK4omTp+S/ ZXhB+Oe/3uzvd1ittj179zscjmFHSpIkhlWEt45mWFYhRWQ4G9r/Mlar7b33P1r/zvtWq1UeL1nm 9raODRs384Lw8t9ee/Otd4LBoDxekf0jHw/9NtQPAMCyLMsysg7wPH+qtKyy6uywrbh5vfrnv950 OAYAACEkiuKwYxQMBvfuO1Badtrr8R46fKSk5KSsMx6396233hV4ASHU29sbKf/QPsEY7z946OCh wy63u/x0xfYdu/x+f2lZ+cZNW51OV2NjU2VVlSxkc3Prpk1b5XK6e3pef/Ntq81mtdpOnSqLrFcU xcixGNrGyDLlGf8m9SFsfPv6+z/ZvuN8fYPT5dq5e8/Z6pqr1nvVtrMsU1t3/sOPNq5/5z2P1wsA H23c3NbW4fV6t23fefJU2Qjagt1uP3zk2JGjx4N8sKOzU9b5oTYSmn/kj7IOyH/LG9F+tHFzW1v7 wIDz0JFjLS2twwqGJYmmw3WbphmGVQy7MLRx89b6+obKyrPbtu/yeDx9n86NIVuDCFu+nN1dwUb6 +vsPHDp8wWoNBgOl5eXV1eeGF/46bfPqttDdI/dhqG8rzlTu2rWnr7evra29q7tHPt7f7/jkkx3n 6upEURzWi5WwONxwsyyrkIYLG7+yfWGMDxw6fOjQEY/bU1t33ul0hsY6JOfGzVura87t3LWnoaER AHieP15ysrKyasOGi3N7aCx4nm9tbdu1e4/P5xu2YwnXvr51lzNs/NaNkZubs3DBvbv37LtwwTrs CSzLnKmsMpvNg58xZhim5MRJURQvyUF/6XGP23PsWMm3nvmaVqNxuz3+QCBsS6Ibo7vnQmtr27e+ +TW9Xu9yuSiKOnToSEF+3oL585xO1//95WV5tSPI81Vnq9PT06pranv7+jBgANDptEuWLGxr66ir qxcj5neapidPnlQ8qQgAoqIMubkXb3afePxRAHjjrfW5uTnLliwGAPmeVc6jptao//ePf+nq7omO vsUBKKIo1jc0mkwxDE2fPVsdFxcbeQ4G7HA4yssrZM81sn8AwGa3W602j9ur0arlfli6ZBHLsqEX MmbMmPbIw58/eqzk4MEjcg/cPGF6pVarF86fJ2uR2WRqb+uIHCO3x3PsWMk3v/HVxMSEs9U1H360 6WfPP5eTk2212o6XnHj88Uc4lrVabZHyOxwDVqtNTqEniuLePfs///kHigrzOzq7/vinvyyYP8/r 9QPgwsL8pKREhUJhiomZMWNaWdlpn88nD25t3XmPxzs+NzsnOxshlJSUmHtpvaIoHj5yLGwshrbx iX97NKzMW0LY+Pb0XGhtbf/WM1/TqNV79u4/cODQt7/1jSvXe9W2+3y+mppz06ZOaWpubmlpzc+b SNP05OJJWVmZVpvd6XStvX91qLTbaQvBYHDrJ9tcLs/jjz6UlJR4+vSZa/lVYmKiLBjHsfK7TUuX Li7In/je+x/J+nbzgmFJOnjoiM/nf/CB+3Nzsvv6+q/lV5F6e2UbqTlX29jQ9O1vfUOh4I4ePb7/ wMGCgrybF/6q+lBWdjrsJ4cOHcnLm7h40fxgMEjTjMvl6nc43lr/rkqleuBza0wx4QuWN8Cwc93Q /pHt+nOfu39ycZHb7dFoNADg8XitVpvNZguVY9Drp06dvP/AwezscXZ7b/npiie/8Hht3fmhc7vD MWA0Rj/26ENOp+vXv/3d/HvnqlSqm2/C3Qfxtwa5hfm3Pvxo48mTpSzDfuuZrwEAQghjjDEOrZwV 5OfJtzhycgqapufPn1taWs4puOTkpFA5YccFURgYcJrN5rfffvfgoSMcx/31L//LXeZ1y2snEAiI ghAVZWAYJibGCAB9/Y7o6GiWZaOjo3heCASDAJA1LrO9o3Pf/gOnK84UFebLv21sav7Rcz/VarXL li4y6PVhJfM8/9eX/24wGADgy08/OWfOrGH7qrS0HACWLF64bt0D8kGNWu33+YKBW5+PY2DAuX// oZRUCwLYf+DQ5CnFACDfsEpYku8otVrNzHtmHDteInsbkf0TaldPz4XHH39Y7odnn3seIWQ2m37y 42fluhiG0ajVl1uZuAHC9Mpu7/3Ff/2G4ziOY5/94fdhuDESBMEx4DSbzSzLms1mm80+bMmR8svj 4vV609JSMcb9DkdCQjzDMLFmk8vlliQ8e/Y9Xq/3/Q82xMXGLl+2OPIKkZmR/vkHP7d7z94jR44v WDAvISF8x9JhxgKHt/GzYJjxFcUog4GmabPJdKq07KolXLXtbe0dlVXVUyZP0ul0O3bszs7O4nn+ 5b/9XaVSJSUmTi4e3v++DbYQDAYd/QNKldIfCFz7dq7Hjpd8/z+fA4DxuTk/+P53AAAByF6Ox+O9 JYJJGPf3OzQajdfru/bbyGH19go2EggEfH6/SqWkKEqtUff13xrbvKo+AABgkNMeIYQQQG9f/4yY aJZlOY4DAJfLFfAHvF6vUqGQJAljfPOb7V7VvjDGff2OpMQEhmGiogzyr+Sxxhg7nU75CMuyEyeM P3euru58fXX1ueTkpKSkxLC5PUdOAI6QVqd1DjgliQSeDg/xtwa5XPzWDfDUk08sW7Low482uj0e SRS1Wk1rW7skSf5AgGEZgRdUKtWSRQtffuXVwbVxhCxJSRRCr/3jjccee+hiQZceZxjGbIrp6e55 4t8enXnPjBd/8z+35A1gjVrNKRR2e6/BYLDZ7ZbkpBRLcntHx8QJuf39DrVKpVGrXS630RidkpL8 +pvrCwvyUywW+be5Odl//fMfOI6jKDqUiSMEy7LPPfuDScVFAEBfZg794pNPPProQwBAISRhDJ8u P+j1erX6Ft8hyY9KW9vavD4vRVG9vb3nztUpOEVHZ6fD4Whv75DDMihEFeTnWa3Wqqqzw/ZPqF1v vfXO0H6Qt/sMecA8L7jc7sTEhFsl/1C9EkXRZIp58b9+bo41AwBDM6dPV0SOEcuwsWZTS2trZkZ6 Q0OjJTlp2Hk8Un55XMrKTm/e8jFCKD09rbW1LcYY3dTckpSYwHGsz+srnlQ4Z87Md9/98ONPduTl TQwr0+8PWJITf/iD7+3Zu++99z6aMX3a0OvosGMhYRzWxmHDa26SsPHVaXVKhaKru8dojO65cCE5 KemqJVy57XLQTE/PhVOl5aIoer2+xsZmlmV/9MPvG43GHTt3u9xuSZIivYrbYAtarfbJJx9vamrZ f+CQMTr6Gq+KixbO/8ULz8t/y8GIGMDr9WGM5TuQm4em6bX3rzbo9bv37I8xRmt11/SqXaTeXtlG GhsbDQb9wIBTq9V4Pb6UW7T5x1VtgWVZfyBgtdrqGxqVSiUAJCbE9/Rc8Pl8bo+HZRgAiI+P++Y3 vrp7z75du/etXbM6LE7xerk2+5KSkxK7unvMZrPVZpPdRHmsrVbbcz/+aai0hIT4pKSE/fsPdnR0 funpJ1mGCZvbe3v75FptVltSUuLlki4RiL81yBXzb10HNEVTiIqPj1tz36rtO3ZpNOrFixasf+c9 jHFiQkJCfHxHZydNUTk5WTnZ2XZ7LwAwDKNQKu6ZMX3T5o8pRMGQpGVDj2s1moUL57/z7gcerxcB hAJab5KkpKTcnOw//t9fdTrdPTOmWZKTFi9asHnrJ7/575ckSZo6ZXJSUmLd+XqaoubMnrVt287F i+a3ffrknmEYluNC1kVT9IaNm2tqalNTU7789JMURb3y6j/kxfy1a1ZPnz5VPicUAEFT9ObNH9fW nQeAaVMnr1q1guf53/73SwaDflJRYVJS4s23DgB4nv/1b3/HcdyyJYuOHSt55htfLS4uAoDKqrOf bNu5YtmS6uqan73wK4TQ59beBwAcx+oNuilTJm/Zum3Y/mEYhmEYjmUVCoXcls7Orhd++WuEkEaj eeYbX5X7oa6uPjk5ceniRbekFWF6pVIqg8Hg7176I8dxNEX9+78/jSgUOUZarWbx4oXvf7AhEAho NZrVq1eEdGZoFH+k/BSiOJZVKDiaomiaXr1yxZaPP/lk23aaphcvWqjVagcGuvbuO9Dc3BLkhfn3 zpHLkWWQ/xYlsbTsdH19w4DTVViYH1av3++PHItYs0mpVIbaqNfrCvLzhpZ5S4gY38T8/ImvvPKa IApms/mBtWsi2xKG3++/Qtv7+x3VZ2t+9vxzaWmpPM/v3Xfg8JGjCBDLsuPGZcz1zTp85GiUwZCY mHD7bYHjWI7lpk2d0tfXt2fv/qSkRFnmkI2sXbM6PT2ts7PrJ8+/wNC0rFflpyue/+kvACBk1399 +RWLJTkzM2NSUeEtEYxhGIZmxo3LtNt7Dx46MvOe6bKeUBT1l5dfMZvNoT4JkzNSb69gI0lJiRPG j//Ly6/09zuys8YtXbL4lgh/ZX0AgMTEhMSEuF/9+r8FUVy44F6aphctWrB5y8enKyqTkhJXLFvC cRzDMEqlcvHC+Zs2bz1x8tS8ubNvZnoXRbGk5OSV7Uur1axcsWz7jl2fbNuRk521YvlSRCGGpjmW 5Vh2aOJMlmUnFRX+4Y9/njhxgqyKYXN7enpaZ2fX8z/7pV6vW7DgXq2WZKYYnivmlx9LCILAC4JK qfQ6rQP2Vjm/vCTx1aW7ObVp4uRhrpqHtv8jO3+2KTZhaF9ZbTaapmOMRkmSbHa7UqFgGKaltU0Q hMTEhBij0e8P2HvtluTkvv5+q9U2PjentbXNbDZzCq6jvUOn1+m0usampsjjMUZjIBBoa2t3ezwq pcpiSdJc+poMAGAsdTWfaW1pmLv86UiBq8v3AEBu/j1hOXkHBgbaOzppmk5LTVGpVBjj7p4eq9Wm VCgslmR5kd/ea09KTGxpaU1JsfQ7HDRNh+Qc2nY5iFKlVk0Yn9vc0trXO/gSVlp6qvySUah/hp4P AOZYU3JScm1dnc/nU6tUFkvysEYb9Dn2bXtjwX3fVGvD3830uPsPbXtt8f1fB3zxLXRJwrV1dT6v DwAslmSv12uxWOSluEAw2N7WnpJi6em50Nffr9VqU1MsNM00NTdnZqQHAsG29vbkpCS1WhXWP/K4 qNUquS06re7s2Wr5wslybH7eRJvd3t7WwTC0OdacEB8fuaR083ql4Liu7h65XYhCuTk5ABA+nN+q AAAgAElEQVQ5RjFGYzAYbG1t83i9RmO0JTlZFiYY5ENjFwzykfLLv5XHPcViEQSho6PT4RjQ6bQW SzLHcaIodnf39Pb2qdUqi8WiVCoAIHQ+AGCM7b293d09LMumWJJlXQ3VK4pie3tH2FhodVqWZYfY jtJg0A8t85boQ+T4ulzujo4OnhdiY81xcbFyF4XqxRjb7b0hx4jjWJ1Od4W2BwKB9o7OzIz0T8vx 9vU7eJ6Pi41Vq1U8z1utNmOMUaVU3n5bkNuOEHK53G6322DQ23t7B+vy+gAgLT01pM8hvTp3bnBT 2ot23dfHsmxSUqIsfBii4Du6+50JU1bER7yfKIr8ro/+d+7ypxTcJUsgIZvy+/19ff16g769vWN8 bk5oDrnYJxFyQoTeXs5G1GqVy+VqaW17/Y23c3OyH1r3oC5iIe0GbPOqtiDL09NzQaFQpKWmKJVK SZI6O7t6+/pijMaEhHhJwrJdYIwdDoffH0hIiL+0ZuzsbT9+6ONln/8+TYevkvR01J+vOjJ78SOh PVEwxq1t7Zbk5Cvbl0qlamtr83i9CQnxppgY+dqUYrGE7DQ0LjzPt7a1G6OjjcZoAAib2+WxAACd XpdiSVYoLnmDkuSXD+WXJ/7WIE3NbZ/Gb/mG+lvnKw/5AqIlvSDsqilhqbbiQN6UxdEx5tHTVxhL PW3VjeercwrnUZfmg8AYtzVWRJuSMnKKRrOOXpmgz3H8wKbMibNVqkteOcYAHld/y/nSeSueGv35 lu44vRq13AZ9sNt7X/jli/JrbvBpDNOwOT5uM6PWFkTBV3pkS3RsptFsCbvV4PlAbcWBWYsfY9kR S8CFMa44U/XOu+/PmDb1c59bE/btaLVN7OzrOHV0Z97UZWGpNDDgPluH22GfMue+0bkHHfG3rm0/ n7HEsPFbCFEJqRNbG2rOVx8NMzCEUGxihlZvHGV7cKIoU1LMgKuh+hiOEFirj4lLyhxlAl8fFKPI nDCjq6VGEMJnFpZVZufNROgO2IX+DtSrUcpt0AeTKeZ3//3i0EJGg7MFo9gWEGIycqe3NZ2z97SG JVCkKDotu5jllIBH7KYIIVRUmJ83ccKwIemj1TaRUh2Vll3cXHsqIvUDUqo06TmTcUSuH8JoY1RM HKOBYeO3EKINxsSiGSmX+RHGkjSqcrUjhFTamImT5l1uOy2MpdF8Q3BVGFZlSc9LySgY9luMMZaG 2chotHHH6dWo5fbow+iM/x21tkDRbGxiZlxS+MPET8FYEkf2bgIhNGwuNxjFtskpdeMmTM+aMGPY b+/0iX2MQPytQS6bfwtLo3OR9rJgLImj/YHazYAl4W5Y+rnj9Gq0cpfoww0xatuOJRHDHXv5H622 iUV+dA434Roh+eUHaWvv2rnrQL/DJX/E5HEOgUAgEAiEWwTxtwYJxW8higGE7u4lIgKBQCAQPmuw JGJJpCLeqRybkF4YJBS/xSMVRdFOW7M2OpGiGLjpPL8EAoFAIIwtMGAsel22YNCri0kjT4yA+Fsh QvFbDKs0mFKcvW0Dva1YvAOCrwkEAoFAGHUgxCo1BlOGQm0gLwAB8bdChPZPjI7SKTVGThUFgACR 560EAoFAIFw3CAAQRVEUxhLJJgjE3wpxMf8WQoCBokYsHR+BQCAQCHcFEpZIYrBBiL81SCh+C0dk ZMYYC4IIgGmavva96wkEAoFAIBBkiL81yGXzbwGcra7ZvPnjngvWmfdMv2/1Co1GMzDgjIoyhJ1m t/fGxBgjN8sjEAgEAoEwxiGrNYOE5d8ayvbtuzQazde/+mWz2dTV3XP4yLHv/eBH9Q2NVqvtdMWZ c7V1bre7sbHphz/6SUnJSbu912qzYYwbGpsCgUBzc0t5eUVzSysmT68JBAKBQBirkPWtQS6N37rE Nxo/IbfyTFV5RUV+3sTEhITtO3ZVVp09U1llNpkOHDjk9/unT58qiGJpWXlubvb5+gaGYRYvWvDr 3/zPV770xdf++YZWo5k5c0ZqioUsfREIBAKBMDYh/tYgQ+O3BN7v6u/wu+wSljT6uIXz5yUlJFRU Vm3atHXZ0sWPPPT5svLT961a2drWao41nzhx6vjxE7/4xU+3bv3kC//22M5de0RRFAQhGOSVSmVq qgUhalx6YnfTCSAZSAgEAoFAuH4QIJpVaKMS1Lq4kZblBiH+1iCh+C1RDA7Ym4Wg32DOpFklw6nL yisFITB1cnFTY3N3d09GRrpSofB6PXv3Hujv7y/Iz7PabICxXq93ulw6na6xsenI0WM+n8+Skrxq 5fKSE6d27D78ja8+NTp3vSUQCAQCYdSD+aDH2deOEHWHbrhH/K1BQvm3VKzA+z0mSyHLqTCWAHCK JfH9DzbUnT8/YcL4adOn6nTa+ffOKyuvmD596ptvvWOz24sKCyRJWr16xenTZ+bOmdXc3Nzb25eT nVVXd379O+8rFYo1a1Zr9NHkeSKBQCAQCDcGp9QiAGdvO6tQj7QsNwLxtwYJxW9JwV6MMcupsSTI TwDj4+O+8fWvSJKEEKJpGiH00LoHMMYUReXnTZQwphBiGGbxwgWiKDIM861nvg4AkiQxDDO5eBIA MAyDAEjCNwKBQCAQbgyEEKfUBXwOllONtCw3AvG3BgnFb3kCEgAghIauWNI0TdMXM6CGsnAxzMUO RAjJH+Uz5f/JM0QCgUAgEG4JCFF37sv+JB/EIIIgeL2eyGSnBAKBQCAQCDcJ8bcGuUL+LQKBQCAQ CISbgTxPHORi/q2g/+JRjCWJv/zG5oiiOXQb9rTGkiTyGC63CxWiaMVnEow/UvUOK4vIS1i43LcU xSLqFigzxiIW+cu9/IIQRdGKm6/lsrXfljbeDCPbP5dllNjpZ8mo0I27qZ/vprZ8ZoxSe79jIf7W IEPity7qFsbiQG9n0/kKj6s//AcIRcck5BQt4FjFZ51YSxJ5a1djS0NlMOANl4Ki4pIyx02c/Vl4 PSNV7zBgyeOyN9ef6bd3RX6p0UXnFMzTGkyAb3ZjVJH3d7ac62g9JwrhT5Zphk3JLLBkFsNl5+ib 43a18WYYyf65PKPETj9DRodu3E39fDe15bNjdNr7nQvxtwYZdv9EDPhCVzNQygmTl4fd60hYqqs8 5HE5uRjzUJP0eLwejwcAOI7VanUMQwOAz+fjeUGn0yKEJEnyer0+v59lWL1eR1EUz/Mul1uSJLVG rVIqI1eMMEitjVXGuExjrAXBJd8KIl9dtjst+x6Ou2QoHY6BYDAIABqNWqPRhMkQDPI8H9RoNFfe 8/F66/X6fCzDsCwbCAR4npfrdblcOp1OkqS+/v6oqCiWYQDAZrNjjBGFNGq1Wq0OBnmfzyfLNuze lBjANWDv7+sdP3kZhehLvsK4vbnS2tOhizJfOYxywOnUajRD33uIRBL5xrrTmRNna3TGsE7x+Vwt daWWzCkAl8wvgWDQ7XIDgE6n5Tgu1LeSJLndHpVK5fF4DAY9zwsOhwMAaJrW63WRL1Jcbxsxxi6X W6/XSZLU19cXbTTSFOV0OjUaDUVRbrebpmm1Wg0AHo+XYWiPxxsdHSWPNcbY5XJRFO31DnrSsp7Y bHYMmGUYnU439F2Qm+kfjLHT6eJ5XqvVKJXKUP9gjOWxDukqAERFGTiOEwRBtgi5ozweL8syHMcF eT4YCKjV6rBt42/ATkVRdLvdclJijVbjHHCGZAAAhJDBoJd1OCQnALhc7kAgoFQqNRo1AMjHMcZO p1OpVCkUnKxjfX19AMBynEGvRwiF5gS4vD06HA6EkEKp0Gm1w80A163/kWVG9jPGOExPPB4PopBa rdaoh3nf/pbMh5G2L9uFfE5UVBQAuNxuv9/P0IxOp43Uw6FlyufzPO92u/V6PU3TQ/XKYNBffnIb RW0Z2ufynCxJ0lD9pBAKsyMAkCRpYGBAo9FwHAefzvkIIaVSodFoEEJ2ey8AvoIefhb2DsPpNgDQ NKXT6WRRw/pkyDm0TqfjeT4kp4zZbLo7sikRf2uQUP4txaVLyHzQrzWY4i05kT+pP3tUFMNX+Ld+ vO31N96Oi4s1mWLuX7Nq9qyZPM9/8NHGqqrqZ77x1ZQUS29v32v/fL2hoSkjPW3lymUF+XknTpza sGmL3++/Z8b05csWm0ymyLoCfo8xNiU+OSvsuCgKZ0q2Ra73/v4Pfzx3rk6lUi1ZvPDxxx4Ok+Hs 2epde/Z+77vfeuGXL/7kx8+azcPUeAP17t9/UBTE5cuX7N6778iR48/+5/ecLufrr7/9nW9/s7m5 5W9/f+2+1SsXL1ogiuK3v/sDjLFKpcrNzXnqycfb2zr+9OeXf/iD/zDGRP/mt79/8VcvcBHuiCQK DMslWHIjhey1tvF84HJNkAkGg6+99vr8+XOLCguubLrBoC/Bkq3WRocd97od507vC7vflSRp0+at Bw4cVnDcggXzFi2cX1t7fteevd/99jNl5eWnKyoXLZz//gcb1ty3UuCFH/zwx8nJSXq9bsH8efet Xhnp+V1XG/v6+v/2yqvPfPNrTqfrZy/819e/9u8TJ+T+459vzJs3Jy019eVXXqMp9JUvPx0VZdj6 8bZgMNjd0/PA2jWZmRkIobrz9Vu2fmKKifngw43y6C9ZvPChdQ98+7s/QAglJiYsX7Zk1sx7FAru JvsHAOobGte/877Vaps3Z9bKlcvOn2/YtWfvs//5Pbu999e//d2Lv3ohpKsA8OWnn5w9e2ZFReW7 738oCOKyJYsWLJi39eNtLMsuW7ro6LGStrb2lSuXJ8SHJ5i+XjttbGr+1+tv9fX1TZwwftWqFXv3 7j90+KjP57PabKkpKWazaeWKZSdPlQ6V09HveHv9e+fr6wsL8tfefx9FUb/+7e9++cLzra3tBw4e mjSpqLAg77XXXs/Lm/DSH/4vLi42NdWyetWKosICeU4I9fOw9viDH/44IyMtJzv7/vtXZ2akR6ro 9ep/ZJlh/TxnzqwBp/OvL786VE9ef+Pt9PTUSZOKVq9aHh83TBbvm5wPp0+bGmn7P/jhj5OSEgFg fG7OD77/nf7+/o2btlacqTQY9CuWL50+bap8kQ4r02w2yefTNL13/4EtWz758peemlRUGBqvP/35 5TX3rSzIz4sUdbS1JdTnMUajPCf3OxxD9TM9LTXMjrRabVd39+9f+lNBft7DDz2oVCrl8dVqtSmW 5EceWRdjNH7hi1+JNZsvp4efkb0Pq9vJyUk6nXbe3NmfW7umr69v/bsf1NSc0+l0K5YvnT3rnrNn az6dG/Xz752jVqvXv/M+xripqTkjI12h4J794ffHZWZcbhzvIIi/Ncjw8VuDXIdnHeSDD6174MEH 7t+waevBg0dmz5pps9nOnas1GPSnK84kJSV29/Q0NDR+4+v/boyO7ujsxBgOHTlmSU5e9/nPXbBa 3W7PsP7W9QkBEAzy3/+Pb08qLqIQAoAwGTDGDscABnA4Bq76bu211xtjNJ4qK+vuuVBRUdnR0dnY 1NTZ1R0dHcUw9OEjR3Nzc44dK5l5z3SFUskwzK9++TNBEH77P3/o7urBGFdWnT1x8tS98+bYbPbr aagsIoo0e6vNVlZ2GgAKCwsS4uOamltEUdTrdHv3HbDZ7FlZmQX5eWFz3yD4so2O7CpRFA8eOjJ3 7qwF985tbGr2+fwY47a29u07dtlstuVLF6elpXo8Hj7IA8CUKcU//9n/O3Lk2IYNm1etXH7llbar tpFlGZphztXWWa02t8dbWlqmVql4XogyGNra2jwejyAITc3NRYUFQT4oSVJBfv7+A4dS01IRwN69 +3Nzcvr6+x5a98Cjjz4EABRCEsbyuGCM333/w7TUlIyM9Jvvn02btxYW5M+/d25nZ5coSrLuAQDG WB7rkK4CAE1RLpd7x67da+5blZ83sb29HSEU5IPtHR0ffLhRziocazZfro+uvTurqqoFQfz+974j CoJzwPnUk0888cRjZWWnN23e+osXngeAysqzYXLu3LUnJsb4wmM/cTqdkiQihNrbO44ePX6utm7O 7FkTJ05obGoSRTE6OspsNv3fH3/X3tH54Ycbx2VmynNCqJ9hOHucMqX4Z88/V1l5duvWbc9886vD LjZcluH0P7LMsH7GGLe2tIbpyUPrHvjc2jUHDh7avXvfvz3+yM33c9h8OG3a1EjbnzKlWO5zAGAY ZueuPSmpKY88/Pl+h+OjjzYlJyenp6VGlin3J8Mwbrf72LGSjIz0o0ePT5wwPjReIbu7ct+NhraE +vyhhx6U5+Qw/Yy0I1EUT58+ExtrrjpbvXjRgsTExGCQ/95/fDszI/1vr7x29mzN3DmzTDExV9DD z8Le4TK6/fOf/vjQ4aNbtn5y/5rVO3buNhqjf/nCT7t7ejZt3pqenhY65/CRYxs3bvnDS79dsOBe q9X23I9/+tc//4HlOIa+SxyVu6QZN8+w8Vs3xpatn9Scq5Ukad7c2aIkHTl6PCUlpbAgr6TkpN3e m5SYWFw8acPGLWmpKUuXLEII5s+fe/Dg4X+98dbUKZNzc4a52boBJFF85dV/mM3maVMnr1mzOkyG W1JFJNnZ4/buO9BQ32i12gry887X1VfXnFt7/31NzS1er2/JkoW7du8tK6uYOXOGx+v9/R/+JEmS MTrKaIy+cME6ccL4ru7u+obGW5Vbpb2t429//8eC+fPq6xu/8MRjdXX1MTExRqPx/PkGl8v13nsf RkVF3fw9E0VRq1YsLysvb2trnz9vrl6vB4CWltZdu/esWrXCYkke+uSrtLT8pz/7ZcAfyM/Puz5n azhUKlVBfl5JySm/379w/rza2jqjMdpojNbpdAcOHi4uLqIQOnmyNDsrS5azeFJhyYmTbW3tkiT1 9TsefHDtzp17Nm3ZWlt3HgCmTZ28atUKAOA4zmSKcTldA07nTUoIAJIkNTQ0PrTuwagoQ+gx8alT Zc8+97zH43EMDMAQXQWAtWtWZ2Smt7a2FxUW6HTa0E8qKir1ev1XvvzFWLP5ljxZKCjIa2trf+PN twvy8xYuuJemKZqmOJZFCP3/9s4suI0jPcDdPTMYnMQNECCEgxTF+5YUibpPW77kM9n1ro/Y3kry lkrlqH3ZrSSV4yGVl7xtUrsbe71Vca3t9SHJOmhJpkRSFE+dJMVDpEiKICCAh0Bc09N5GImCAFBl CwQJUf09sQBw+v//+f+ef7r/7pbGVhPbkBocHBp+9uB+k8kojRBMT/uCweDXR7+pqqzYsGE9wyDJ x6R0UMbzHrf71vhEPB4HAHz51ZFFO6eNRwihQqFwuZy//u1HyxUCSddMsnN1dWVXd2+ynzBIo9HY bbbOrp5lkQE83B8CAFJjv6Oj6xe//GcAgMvl/Nn7794YHC4pKdFoNEqlKhicmZmZAcCVes2+/gGX y/nBe+92dHQbDYb9+/d+feTYjRtDjxitz01d0to8yT9T42hqyjs0PLJje2Nf/8CFCxcPH35BxPhX //1rg0FPRFJ0P3N6hB9mI95Tn3fgfr93Jxjc2FDPMMzg0Mhzhw6aTEa9XvfJJ59KM4kdHV2//Md/ mZ+fr66uZFkWISSFISeTpc51PLnQfOseaeu3Ho+amuoXnn9WpVS5XOv8Pv/xk013/HfOnPnO5/dX Vlbu2rntlZdf8nq9HR1dH370+7/727+uKCuzWa3DIzfPnP0OQnhg/97MZYAQ7t61s7ys1Gwxpcqg 0+Vl3kQqer3earV8c/yE0Wioqa46cbIJImi3206e+vZU0+mu7p5gcCYQCNbUVsk4bt/e3WNj44SI Or3O653Oz7fW1lQ3N58PLSTX5j82bpfzp2/+2T/8/BdTU1MTk5PlpSVKpWJ2bvbS5Sttbe0/+tEb mTfBMMzmzQ3riwpvDA5+8ofPpK7Q4/H85V+8f/r02UK3u6TkwVSs2+3809df5eW8y+lMqkB6DDiO K/R4jn1zgmXZXbu2X712vbWt/eCBfdM+3x+//JpjWZGQaCS6c+d2QACAQK/X1dVWnzr1LcMwtTVV RoMBQFBTU/3Cc88CAMyWB0+peDzO8zyDMs0IJZRKZSwWE0UxFovxvBwA4HY733jtleDMzP9++DFI 8FUAgNvjIiLhOC4WjxFCwuGIUqkAADQ01G1r3HLufIvNlp9vtWQulaOg4PXXX5mcvN3cfP7Tz774 4P13k34AERQEIRqNzc7OMgwLAVDI5eFIRBRFjLGULptMpg/ee6elrb2js7usrETyMWnCDhASjUbV ahVCEICH7LxUPBJCIpGopO9ykXjNh+zsdo3cHE3rJwAQLOJl6QklEvtDAEBq7Ev+AABQKBUsy6pV qngsJoqiIMQVCkXaNxPJngqlIhqNnPmuuaOj68LFTu+U16A3PHfo4HJJvjK6AABSbZ7kn++8/ZPE OOJksv6BgaPHTrS2XgiHI1pt3vbtjRDC3bt2yOX89b4BaU4TgEf54WJbyxjvaX3b7Xa+9urLl65c nZycxBirVapQaEEUxUgkyvM8wzAiFt1u54vPHzp67HhNdVXmYuQsNN+6x1L1W4+Bx+OSjvEhhBw5 enz3zh27d+3gef7y5Sud3T0Oh73ver/FYo5GY6HQAoSwp/fSwsICyzCRSFQUl2eFEUSovKy0oaGO EPLpZ18kyVBfVyv9TJrI0+t065yOpadpvnejEDY01H3x1ZGfffDnxcVFH/7u93v27Jqdm/P5/P/2 r//kKLAHAoHjJ5ouX77KcdymjQ3btzX+4dPPW1ra1GoVQmj7tsamb89iYclF7z8UuVyu1mii0ejt Ke/szGxpacn8/N2Ozq7Nmzf6fH5BEAghGQ6WYIwvXuyU8zzGYjQSFUUCANBo1BXlZbFYrOn0GW1C ams2mxsa6jLVKgGr1aJSqSCCDoejqNDT0dVdWOg5cbLpnbfebNy6BQDQ2nbhfEsbgpCTcTKZrKqq svncrxBCe/fskmas2PsPAIxFcN8fMMb2ApvFkqk/AAAQQo1bt7S0tPl8/tnZ2c2bNoL7dpie9knG hwmpJ8ZYqVBUVZY3NZ1xOAoWQgvbt28FAJhMxrramkAgePzEyZcPv6jNy/SFYWh4eHh4RCrOlV79 k9BqtRDCI0eOjYyOFq8vQght3Fjf33+DZdlwOLKhuEilUnEct2FDsVKl+vrro4FAYCY4U1paAgAI h8NdXT1en29jQ71Uir5oZyEutLd3psZj4E7g4sXOm2Nj2xq3Zj72KREIPHTNRDtHotEzZ5tT/eT2 lLeltW107NaWLZuWRQaQ0B8CAGLxeGrsJ+orimTr1s3jE5Pt7R2zc3MulzNtGZnH45I6t7YL7SaT 8T//4991Ou3o2Ni3p7+bmHywhPPa9T4AgMFoSJrFyyldxsbGU22e5J9JcVRSsqG759LP//5vKirK w+HwyabT51paAYAV5WUVFeUMc+xs87mG+rqFpf0wS/F+vqU11belTE7EOLwQhhBu3bK599IVCOH0 tM9sNlktlvHxCbPZ3Ni4RW/QnznbbLFaCj3uzIXJQZi3f/ySp7gaxyOz/lGjrWTuzqgyz8pyT92m GnFBIADZ7A4ghqMLM3lGJyGYENE3OczIVBZbmomn0cFuo9WpVGkSPwwvhI0Gg8NRAADAGI/dGq+v r3U516nVKrvd5vcHystLBUH4rvk8y7GvvXrYbDLptHlXrl7ruXSlpqZqx45tqW+WRBRuDV+x2Deo 84zJXxFx6Fqbu7iOfbiPnp+/6yl063W6tDI41znkCnlZyYapqame3svXrvfZbLYHr0QZtKvT6hBC u3fvsJjNCMFNmxp4mQxA2Lh1i0ajNhqNCCEAgVanq62p0mg0BQX28fEJuy2f52XVVZUmo1GpVG5s aJDexhIbnJ/xzs4EXMX1qTfCd3sEAGCyrkssKBCwACEsLdkQCi243S6FQlFbU81xMplM1tnZrdNp N2/eaDIZk/ItLERGbvR6SjdzsuS7EI9Fbt7oKirbBBI2JIMQKpXK1rb24ZGb+/fvqayqgBBACMvL y4wGAxFJLBpTqVSeQrdao4IQlpWlqXd+bB1lMl6hkBcVFpaWFOv1er1OX1Nd5Z2e3rdnt8lkVKvV ZrNpfHzC6VxntVgcjgKVUokx9njcNdVVLMuGF8LdPb3X+/qvXe9jGba0pHhqaqr30pVINLpv7551 joLUZPSH2gchZC+wDQwM9vZeXr++qNDjJoBIdojHhVAoVF9XNzs729PTe62vX/JDt9tlL7B3dfcM DQ3X1FTZbPmRcMRoMLhczvx86/z8XYVcLq38emC4Hx6nGo3m1q3xC+0dVqvlxecPaTQacN9npHuk UauVCsXFzi61Wv3Ga6/o9Tq73e7z+dsvdhgM+qrKcghRKBSqr6/T67RyOT9yc7Sw0F1bWy0IeHBo qK9vgOf5Zw7u1+t1iXaGECqVqtR4HBgcHBoeybdaDj17gOdTu9/H8f9Ll68mXjMYnFm0s9FgQAil +snlK1cnJ28Xry/auWNbatqXYX8IAJDGLKurKxNjv69/QDJOMBhsaKgvsNu83uk/fvFV87mWtKsH Fq9JCJm67XU4HJUVZWq1Ot9qnZ+/m6fRcBzXUP/Ar1iGLStNrtPIHV26e3oXbY4Qkq5pNBgT/VOr zUuMI7PJFAgEDx7Yp9XmabV5BoM+GJixWExFRYVmk9HhKJj2TiuVymnvdF9/ej/MUrzfGp+ora1O 9e3+/gGO41599bDVYrHbbfN377a2XRAxfuaZAw5HgRR35eVlBr1eoZD7/f516xyCgKX+IelZIGJh LjDGyzWIkSnUhlw+lZgQMTQziVheqTEFfWNz8yF48sv/2XvoJ9GFmdG+s8V1L40PnDUVVPNKTS6r kSUgYgBAoZmJWf9oQfE2EcdEMX6t6xTitBX1+8DDvkhEseXU70qqthsttmzbCgvh1qZP1lftsTlL kkoXhXj09Fe/2vHs27xs+Se5V6vdVAgRJ29eujk0sO3g2zBpJo6Q6z2nEcOWVP4JER+oHwcAAAR1 SURBVDPdCSYWnjnzzcfbnnkvNcW8O3en9dTH+w//FSBZOfRpxXTMhFW0zyPIkTjNHjniGytpZ7// zm9++9Hs3Nzbb7352edfSGsXwP26qB+2niAda0mX7JGD8S7EwuM3zml0dkam0luLVrc/fDSiGPeO dLC8xmQvHb527taEN3fv9AqTtn4LAmgwOwb7ek98diUp7iAEcrlaocpKIVQK0OpYf73n9OWL36SI AbV6C8fxYMld4J/EdtOg0ugBEE9+/l9J1cQQApblqzYdWJZWIGLyHevbT/9fPB5L+gohZM53QwSz t73fyuiYCatrnyWlypU4zSK54BsraWeDQf/WT3/sv3Mn32o5uH/fotZSXVTm119LumSP3Iz3Jxc6 vnWP4ZGx+/Vb4cXxLQAAAQBjkroXCwCAYViO5cjSh2wsH4QAJMQFMd3+0SzLsSyXnZO2V6vddKIA IIpASNnmGACAIOJkPAA4c6clgBCC4vF4un2lIcfJGAYRMVt3fGV0zITVtc8jBcuFOM0iOeIba8nO a0mXLJGD8U7Ht9YCS+2/BQFgGcgy6WfNViogIQSE4xgA0hfSZi3pWa1204kCAIMAs9T05TLdCAgg hISXLRUXIlmmBQ1LtL4SOmbC6trnEeRGnGaRHPGNtWTntaRLlsjZeH9CofnWPZZx/y0KhUKhUChZ 4Al+QNN86wFExABgACGAgKzqqcAUCoVCoVCSEEWcdN7lE8STKnf2YFgZhEwkFKApF4VCoVAoOYKI hYW5ablSB5bjkImVh45vJSPj1XKVNugd4GTKJzePplAoFAplLYFxTIhHDfmloZmJ1ZblcUjOtyAA T/T8aOZAxOQZnDJeE4stPN2WoFAoFAolV+DkeXK1QcZr1kq+BRlRxE95noEYTplnVUH4hA5aUigU CoWyBiGEiHHpmIrVFuUHk5RvEV6pjdz1y3gFw8qSthR/yiCEkKc876RQKBQKJZcgsUgIxyMKtSXX H9CEJCVR9/MtCBBEsfCsWl8QnB4MTA0wDPt051sUCoVCoVByCEJEIR5mOaVCbczlERFCMBaiACLE PBjVuvcXw3AKjdE/cVVndmu01mhknhBEq8UpFAqFQqHkCBAilcogV+qwsEDwSh/V+v0Ribgw5xOE qFZtWvzwXr6FGNaQvyEw1T85fBELcQgRRCytXqJQKBQKhZJLECJiIuJcXtsHESNT5OlMHoXaAO7v LbU40gV5RZ7VWStigTxlJydSKBQKhUKhLBsQQIgYRgYhIon5lhALCdG7qyoahUKhUCgUyhqBACDG wwAAQrCUcrG3bw18e/RDHA+vtmxZBGMMIUIou9OjhBBBEFiWBQTEBYHj2MUFq6IoCoLAspwkg/RL hmEghBhjhBBCD0rlYrGYTCZLEF4kRGQYhhAiiqL0X1lS4RFtYYwxxouCEULicYHjWACApHWiVItf AQAIARgLEEKGYTDGAACGSX/6deY8uq14PE4ISVQh9X6l1UsURYwxwzCJt4lCoVAolO9DJBLOMzr/ H0TyDRO5smJVAAAAAElFTkSuQmCC " id="image7309" x="159.41721" y="812.08984" /> <flowRoot transform="translate(-332.84714,572.62323)" style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" id="flowRoot4230-65" xml:space="preserve"><flowRegion id="flowRegion4232-0"><rect y="205.21935" x="521.42859" height="34.285721" width="375.49951" id="rect4234-1" /></flowRegion><flowPara style="font-size:22.5px" id="flowPara4236-2">multi-area dashboard and xterm</flowPara></flowRoot> </g> <image y="147.08878" x="484.35513" id="image12827" xlink:href="data:image/png;base64,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 36xKAgD0qz5LjGnZ+/6J+w/V1rr5VrNaLH/Jyn91/+W+2FcXyk5f/NGu8mJT19+vA6plz/ZvV7aP 19sormpY+PrJiyXqm1ep3pq0aFbN1uU1W5fXDNAQOxERCYYPCZPYXlsOFlV3XKM8V3FMx/KvfzEh OpooefpEe80XD/gQ+7k8JR+vSySBR/84t2brsi9/OV7WxUYeYr/99KJzvOgsO6/mtU8vsvY1vztw 2SlebFVQpnxu1zm24xtkOfnp+RcKXWxCRETa93bkOcfrTqzPZF3/vsBbev6Z/RfcH4Uz9TsfFXcn sncygO3PfrnrnHO87oTbkV3+hdeczXbS/mXfn3uwTbzu9JZC/df9lwz9WjMAgJuIYfoiZD9/KOfX Z2zfvX6+/u+uGlHw8pKarcsLnp32xiSpn20tbsuXZefLtJ7v7hZw/lDOEzm24VShSPTbO5PPPvuj mq3Lq7YsPPFQ+qpBtjZr1DY/8vGFWrOrr2PoIGnSoLsktv6893tlRfv32SvFDfbgyG/6sEE3sWrd wlpt0V54mH90bBCRIDhU0vkmHjKoS7ecsEXGidHSr56aU7N12bnHh84OEfILPzihKDWz/JqvHFPx C2ePjL348pLyl+e8lhnML9mbXXOpsrnNsZib9v/v+E++dB1OEZG6uGKnPQ5LS5R989Scmq3LTq5O SRMxRERk2nvpRt8daO/VXru00f1ROGG/y7roJgJ2awDbn6jqgzO2P0HBIYH7H59RtXX5xSeH2XfN br9c4w3xbuft7zjLJRL+fcnQki3Lyl++4+8jbZemDucoS9Q9+0QAALyVgGEEnibGsOaKt76q4/+k BocEZz05I81+LTI4ImbZz6JiQ20XLq2Wlj05pWMSRztt25R7/NqbZ+r4TMpgie+cwaGPzBnWLpO1 9MQZPuE4MT7iwNPTqo6fe+lbBZ/NOXZw6NOtmZfqF//+7ZYKk30705ItR4loembCrtWOFJk2aaN+ vqJZySFrp6a0y910Ss5uk+KsKrg8f0t+GRE5pVTu2X7wsRwdET0xN+1HgbrHvqgp1lmjgv033pOy 8o6Mji1mUJdssbeYUOT30UMTpo2I5t8S+IiHjBnx8vC44e989/srOiIqq1Dt+Sp/3dyhjioJRYHf vHpPitN18JoL5+/5d7GSiEjwnwcnz50Qyy9vrC7b80XRW/mNFTqrUCQcmxD860kJM6fJnRJky1es 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 " style="image-rendering:optimizeSpeed" preserveAspectRatio="none" height="212.02832" width="219.69937" /> <path style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#marker5274-8-6-7-5)" d="m 595.90413,398.08621 10e-6,-33.39285" id="path5272-7-4-2-4" inkscape:connector-type="polyline" inkscape:connector-curvature="0" /> <path style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#marker5302-0-9-7-7-6)" d="M 534.72767,365.82626 420.30501,434.93302" id="path5270-0-9-2-0-53" inkscape:connector-type="polyline" inkscape:connector-curvature="0" /> <path style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#marker5302-0-9-7-7-6-8)" d="m 228.84532,348.8328 12.46187,49.84749" id="path5270-0-9-2-0-53-2" inkscape:connector-type="polyline" inkscape:connector-curvature="0" /> <flowRoot xml:space="preserve" id="flowRoot4230-55" style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" transform="translate(-20.16739,-91.254775)"><flowRegion id="flowRegion4232-1"><rect id="rect4234-5" width="188.57143" height="34.285721" x="521.42859" y="205.21935" /></flowRegion><flowPara id="flowPara4236-68" style="font-size:22.5px">multi-area web</flowPara></flowRoot> <flowRoot transform="matrix(0.11890794,-0.99290529,0.99290529,0.11890794,-227.17711,1076.0558)" xml:space="preserve" id="flowRoot4230-8-8" style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" inkscape:transform-center-y="0.6888992" inkscape:transform-center-x="3.4259773"><flowRegion id="flowRegion4232-46-4"><rect id="rect4234-30-1" width="176.59036" height="20.865274" x="521.42859" y="205.21935" /></flowRegion><flowPara id="flowPara4236-6-4" style="font-size:15px">direct read and control</flowPara></flowRoot> <g id="g19871" transform="translate(0,87.233115)"> <rect y="320.43707" x="175.52585" height="182.54306" width="239.18793" id="rect4881" style="fill:#bcd35f;fill-opacity:1;stroke:#445016;stroke-width:1.8534621;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> <flowRoot style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" id="flowRoot4230-3" xml:space="preserve" transform="translate(-328.31553,121.72999)"><flowRegion id="flowRegion4232-81"><rect y="205.21935" x="521.42859" height="139.6452" width="279.20322" id="rect4234-6" /></flowRegion><flowPara style="font-size:22.5px" id="flowPara4236-3">multi-area control:</flowPara><flowPara id="flowPara4910" style="font-size:22.5px">- contours</flowPara><flowPara id="flowPara4912" style="font-size:22.5px">- sub-runs</flowPara><flowPara id="flowPara4914" style="font-size:22.5px">- file/vcs sensors</flowPara><flowPara id="flowPara4916" style="font-size:22.5px">- events</flowPara></flowRoot> <rect y="446.1608" x="176.39276" height="55.511982" width="236.7756" id="rect4598-37" style="fill:#d3bc5f;fill-opacity:1;stroke:none;stroke-width:2;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> <flowRoot style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" id="flowRoot4230-6-7-1-4" xml:space="preserve" transform="translate(-358.53963,247.54394)"><flowRegion id="flowRegion4232-8-9-2-1"><rect y="205.21935" x="521.42859" height="52.412083" width="264.47556" id="rect4234-36-4-9-7" /></flowRegion><flowPara style="font-size:17.5px;text-align:center;text-anchor:middle" id="flowPara4236-0-4-9-8">configs and custom automation</flowPara></flowRoot> </g> <flowRoot xml:space="preserve" id="flowRoot19887" style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" transform="translate(-24.923747,28.32244)"><flowRegion id="flowRegion19889"><rect id="rect19891" width="704.66223" height="84.967316" x="55.511982" y="19.159592" /></flowRegion><flowPara id="flowPara19893">Megatest Full System Architecture</flowPara></flowRoot> </g> </svg> |
Modified docs/manual/megatest_manual.html from [2f3ab9d0a7] to [6159ff4e70].
︙ | ︙ | |||
781 782 783 784 785 786 787 788 789 790 791 792 793 794 | </div> </div> <div id="content"> <div class="sect1"> <h2 id="_preface">Preface</h2> <div class="sectionbody"> <div class="paragraph"><p>This book is organised as three sub-books; getting started, writing tests and reference.</p></div> </div> </div> <div class="sect1"> <h2 id="_why_megatest">Why Megatest?</h2> <div class="sectionbody"> <div class="paragraph"><p>The Megatest project was started for two reasons, the first was an immediate and pressing need for a generalized tool to manage a suite | > > > > > > > > > > > > > > > > > > > > | | | | | | > > > > | | | | | | | < | | > | > > > > > > > > > > > > | < < < < < < < < < < < | > | | | > > > > | > > > > | | | > > > | < | > > | < | < < < | < < < < < < < < < < < < < < < < < < < < | > > > > > | < > > > > > | < > > > | > | | < < < < < < < < < < < | < < < < < | | < | < < < < < < < < < < < < < < < < < < < < < < < < < > | < < < | | | | 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 | </div> </div> <div id="content"> <div class="sect1"> <h2 id="_preface">Preface</h2> <div class="sectionbody"> <div class="paragraph"><p>This book is organised as three sub-books; getting started, writing tests and reference.</p></div> <div class="listingblock"> <div class="title">License</div> <div class="content monospaced"> <pre> Copyright 2006-2017, Matthew Welland. This document is part of Megatest. Megatest is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Megatest is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Megatest. If not, see <http://www.gnu.org/licenses/>.</pre> </div></div> </div> </div> <div class="sect1"> <h2 id="_why_megatest">Why Megatest?</h2> <div class="sectionbody"> <div class="paragraph"><p>The Megatest project was started for two reasons, the first was an immediate and pressing need for a generalized tool to manage a suite of regression tests and the second was the fact that I had written or maintained several such tools at different companies over the years. I thought a single open source tool, flexible enough to meet the needs of any team doing continuous integrating and or running a complex suite of tests for release qualification would solve some problems for me and for others.</p></div> <div class="literalblock"> <div class="content monospaced"> <pre>-- Matt Welland, original author of the Megatest tool suite.</pre> </div></div> </div> </div> <div class="sect1"> <h2 id="_megatest_design_philosophy">Megatest Design Philosophy</h2> <div class="sectionbody"> <div class="paragraph"><p>Megatest is a distributed system intended to provide the minimum needed resources to make writing a suite of tests and tasks for implementing continuous build for software, design engineering or process control (via owlfs for example) without being specialized for any specific problem space. Megatest in of itself does not know what constitutes a PASS or FAIL of a test or task. In most cases megatest is best used in conjunction with logpro or a similar tool to parse, analyze and decide on the test outcome.</p></div> <div class="ulist"><ul> <li> <p> Self-checking - make it as easy as possible to write self-checking tests (as opposed to using deltas, i.e. tests that compare with a previous measurement to deterine PASS/FAIL). </p> </li> <li> <p> Traceable - environment variables, host OS and other possibly influential variables are captured and kept recorded. </p> </li> <li> <p> Immutable - once a test is run it cannot be easily overwritten or modified accidentally. </p> </li> <li> <p> Repeatable - test results can be recreated in the future using all the original variables. </p> </li> <li> <p> Relocatable - the testsuite or automation area can be checked out and the tests run anywhere in the disk hierarchy. </p> </li> <li> <p> Encapsulated - the tests run in self-contained directories and all inputs and outputs to the process can be found in the run areas. </p> </li> <li> <p> Deployable - a testsuite is self-contained and can be bundled with a software project and easily used by others with little to no setup burden. </p> </li> </ul></div> </div> </div> <div class="sect1"> <h2 id="_megatest_architecture">Megatest Architecture</h2> <div class="sectionbody"> <div class="sect2"> <h3 id="_data_separation">Data separation</h3> <div class="paragraph"><p>All data to specify the tests and configure the system is stored in plain text config files. All system state is stored in an sqlite3 database.</p></div> </div> <div class="sect2"> <h3 id="_distributed_compute">Distributed Compute</h3> <div class="paragraph"><p>Tests are launched using the launching system available for the distributed compute platform in use. A template script is provided which can launch jobs on local and remote Linux hosts. Currently megatest uses the network filesystem to call home to your master sqlite3 database. Megatest has been used with the Intel Netbatch and lsf (also known as openlava) batch systems and it should be straightforward to use it with other similar systems.</p></div> </div> </div> </div> <div class="sect1"> <h2 id="_overview">Overview</h2> <div class="sectionbody"> <div class="sect2"> <h3 id="_stand_alone_megatest_area">Stand-alone Megatest Area</h3> <div class="paragraph"><p>A single, stand-alone, Megatest based testsuite or "area" is sufficient for most validation, automation and build problems.</p></div> <div class="imageblock"> <div class="content"> <img src="megatest-stand-alone-area.png" alt="Static"> </div> </div> <div class="paragraph"><p>Megatest is designed as a distributed or decoupled system. This means you can run the areas stand-alone with no additional infrastructure. I.e. there are no databases, web servers or other centralized resources needed. However as your needs grow you can integrate multiple areas into a bigger system.</p></div> <div class="sect3"> <h4 id="_component_descriptions">Component Descriptions</h4> <div class="olist arabic"><ol class="arabic"> <li> <p> Multi-area dashboard and xterm. A gui (the dashboard) is usually the best option for controlling and launching runs but all operations can also be done from the commandline. Note: The not yet released multi-area dashboard replaces the old dashboard for browsing and controlling runs but for managing a single area the old dashboard works very well. </p> </li> <li> <p> Area/testsuite. This is your testsuite or automation definition and consists of the information in megatest.config, runconfigs.config and your testconfigs along with any custom scripting that can’t be done with the native Megatest features. </p> </li> <li> <p> If your testsuite or build automation is too large to run on a single instance you can distribute your jobs into a compute server pool. The only current requirements are password-less ssh access and a network filesystem. </p> </li> </ol></div> </div> </div> <div class="sect2"> <h3 id="_full_system_architecture">Full System Architecture</h3> <div class="imageblock"> <div class="content"> <img src="megatest-system-architecture.png" alt="Static"> </div> </div> </div> </div> </div> <div class="sect1"> <h2 id="_installation">Installation</h2> <div class="sectionbody"> <div class="sect2"> <h3 id="_dependencies">Dependencies</h3> <div class="paragraph"><p>Chicken scheme and a number of "eggs" are required for building Megatest. See the script installall.sh in the utils directory of the source distribution for an automated way to install everything needed for building Megatest on Linux.</p></div> </div> </div> </div> <div class="sect1"> <h2 id="_getting_started">Getting Started</h2> <div class="sectionbody"> <div class="listingblock"> <div class="title">Getting started with Megatest</div> <div class="content monospaced"> <pre>Creating a testsuite or flow and your first test or task.</pre> </div></div> <div class="paragraph"><p>After installing Megatest you can create a flow or testsuite and add some tests using the helpers. Here is a quickstart sequence to get you up and running your first automated testsuite.</p></div> <div class="sect2"> <h3 id="_creating_a_megatest_area">Creating a Megatest Area</h3> <div class="sect3"> |
︙ | ︙ | |||
1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 | <div class="listingblock"> <div class="title">Starting dashboard</div> <div class="content monospaced"> <pre>dashboard -rows 24</pre> </div></div> </div> </div> </div> <div class="sect1"> <h2 id="_writing_tests">Writing Tests</h2> <div class="sectionbody"> <div class="sect2"> <h3 id="_creating_a_new_test">Creating a new Test</h3> <div class="paragraph"><p>The following steps will add a test "yourtestname" to your testsuite. This assumes | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 | <div class="listingblock"> <div class="title">Starting dashboard</div> <div class="content monospaced"> <pre>dashboard -rows 24</pre> </div></div> </div> </div> </div> <div class="sect1"> <h2 id="_study_plan">Study Plan</h2> <div class="sectionbody"> <div class="paragraph"><p>Megatest is an extensive program with a lot to learn. Following are some paths through the material to smooth the learning path.</p></div> <div class="sect2"> <h3 id="_basic_concepts_suggest_you_pick_these_up_on_the_way">Basic Concepts (suggest you pick these up on the way)</h3> <div class="ulist"><ul> <li> <p> Components of automation; run, test, iteration </p> </li> <li> <p> Selectors; target, runname, and testpatt </p> </li> </ul></div> </div> <div class="sect2"> <h3 id="_running_testsuites_or_automation">Running Testsuites or Automation</h3> <div class="ulist"><ul> <li> <p> Using the dashboard gui (recommended) </p> <div class="ulist"><ul> <li> <p> Using the "Runs" panel. </p> </li> <li> <p> Using the "Run Control" panel. </p> </li> <li> <p> Using a test control panel </p> </li> <li> <p> The Right Mouse Button menu </p> </li> <li> <p> Debug features </p> <div class="ulist"><ul> <li> <p> xterm </p> <div class="ulist"><ul> <li> <p> pstree </p> </li> <li> <p> log files; mt_copy.log, mt_launch.log </p> </li> <li> <p> variables; megatest.csh, megatest.sh </p> </li> <li> <p> testconfig dump, *testconfig </p> </li> </ul></div> </li> <li> <p> State/status buttons </p> </li> <li> <p> Run, Clean, KillReq </p> </li> <li> <p> ReRunClean </p> </li> </ul></div> </li> </ul></div> </li> <li> <p> Using the command line </p> <div class="ulist"><ul> <li> <p> Getting help; megatest -h, megatest -manual </p> </li> <li> <p> Starting runs; megatest -run </p> <div class="ulist"><ul> <li> <p> Selection controls; -target, -runname and -testpatt </p> </li> </ul></div> </li> </ul></div> </li> </ul></div> </div> <div class="sect2"> <h3 id="_writing_tests_and_flows">Writing Tests and Flows</h3> <div class="ulist"><ul> <li> <p> environment variables (table 5) </p> </li> <li> <p> tests/<em>testname</em>/testconfig <a href="megatest_manual.html#_the_testconfig_file">testconfig details</a> </p> <div class="ulist"><ul> <li> <p> ezsteps and logpro section </p> </li> <li> <p> iteration (one test applied to many inputs), items, itemstable <a href="megatest_manual.html#_iteration">test iteration</a> </p> </li> <li> <p> dependencies, waiton, itemmatch, itemwait <a href="megatest_manual.html#_requirements_section">test requirements</a> </p> </li> <li> <p> miscellaneous; mode toplevel, runtimelim, skip on file, no file, script or on running, waiver propagation </p> </li> </ul></div> </li> <li> <p> megatest areas </p> <div class="ulist"><ul> <li> <p> megatest.config </p> </li> <li> <p> runconfigs.config </p> </li> <li> <p> config language features; include, shell, system, scheme, rp|realpath, getenv, get, rget, scriptinc <a href="megatest.html#_config_file_helpers">config file helpers</a> </p> </li> </ul></div> </li> </ul></div> </div> <div class="sect2"> <h3 id="_advanced_topics">Advanced Topics</h3> <div class="ulist"><ul> <li> <p> Removing and keeping runs selectively <a href="megatest_manual.html#_managing_old_runs">managing runs</a> </p> </li> <li> <p> Subruns <a href="megatest_manual.html#_nested_runs">nested runs</a> </p> </li> <li> <p> Config file features <a href="megatest_manual.html#_config_file_helpers">config file features</a> </p> </li> <li> <p> HTML output with -generate-html </p> </li> <li> <p> Triggers, post run, state/status </p> </li> <li> <p> MTLOWESTLOAD </p> </li> <li> <p> flexilauncher </p> </li> <li> <p> env delta and testconfig </p> </li> <li> <p> capturing test data, extracting values from logpro and using them for pass/fail </p> </li> <li> <p> mtutil, postgres connection, packets for cross-site/cross-user control (e.g. mcrun). </p> </li> </ul></div> </div> <div class="sect2"> <h3 id="_maintenance_and_troubleshooting">Maintenance and Troubleshooting</h3> <div class="ulist"><ul> <li> <p> cleanup-db, database structure of Megatest 1.6x </p> </li> <li> <p> archiving </p> </li> <li> <p> homehost management </p> </li> <li> <p> show-runconfig </p> </li> <li> <p> show-config </p> </li> <li> <p> show with -debug 0,9 </p> </li> <li> <p> load management </p> </li> </ul></div> </div> </div> </div> <div class="sect1"> <h2 id="_writing_tests">Writing Tests</h2> <div class="sectionbody"> <div class="sect2"> <h3 id="_creating_a_new_test">Creating a new Test</h3> <div class="paragraph"><p>The following steps will add a test "yourtestname" to your testsuite. This assumes |
︙ | ︙ | |||
1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 | <div class="paragraph"><p>Hint: You can browse the archive using bup commands directly.</p></div> <div class="listingblock"> <div class="content monospaced"> <pre>bup -d /path/to/bup/archive ftp</pre> </div></div> </div> </div> </div> <div class="sect2"> <h3 id="_submit_jobs_to_host_types_based_on_test_name">Submit jobs to Host Types based on Test Name</h3> <div class="listingblock"> <div class="title">In megatest.config</div> <div class="content monospaced"> <pre>[host-types] | > > > > > > > > > > > > > > > > | 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 | <div class="paragraph"><p>Hint: You can browse the archive using bup commands directly.</p></div> <div class="listingblock"> <div class="content monospaced"> <pre>bup -d /path/to/bup/archive ftp</pre> </div></div> </div> </div> </div> <div class="sect2"> <h3 id="_pass_data_from_test_to_test">Pass Data from Test to Test</h3> <div class="listingblock"> <div class="title">To save the data call archive save within your test:</div> <div class="content monospaced"> <pre>megatest -archive save</pre> </div></div> <div class="listingblock"> <div class="title">To retrieve the data call archive get using patterns as needed</div> <div class="content monospaced"> <pre># Put the retrieved data into /tmp DESTPATH=/tmp/$USER/$MT_TARGET/$MT_RUN_NAME/$MT_TESTNAME/$MT_ITEMPATH/my_data mkdir -p $DESTPATH megatest -archive get -runname % -dest $DESTPATH</pre> </div></div> </div> <div class="sect2"> <h3 id="_submit_jobs_to_host_types_based_on_test_name">Submit jobs to Host Types based on Test Name</h3> <div class="listingblock"> <div class="title">In megatest.config</div> <div class="content monospaced"> <pre>[host-types] |
︙ | ︙ | |||
1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 | </div></div> </div> </div> </div> <div class="sect1"> <h2 id="_reference">Reference</h2> <div class="sectionbody"> <div class="sect2"> <h3 id="_config_file_helpers">Config File Helpers</h3> <div class="paragraph"><p>Various helpers for more advanced config files.</p></div> <table class="tableblock frame-topbot grid-all" style=" width:80%; "> | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 | </div></div> </div> </div> </div> <div class="sect1"> <h2 id="_reference">Reference</h2> <div class="sectionbody"> <div class="sect2"> <h3 id="_megatest_use_modes">Megatest Use Modes</h3> <table class="tableblock frame-topbot grid-all" style=" width:80%; "> <caption class="title">Table 2. Base commands</caption> <col style="width:20%;"> <col style="width:40%;"> <col style="width:40%;"> <thead> <tr> <th class="tableblock halign-center valign-top" >Use case </th> <th class="tableblock halign-left valign-top" > Megatest command </th> <th class="tableblock halign-left valign-top" > mtutil</th> </tr> </thead> <tbody> <tr> <td class="tableblock halign-center valign-top" ><p class="tableblock">Start from scratch</p></td> <td class="tableblock halign-left valign-top" ><p class="tableblock monospaced">-rerun-all</p></td> <td class="tableblock halign-left valign-top" ><p class="tableblock monospaced">restart</p></td> </tr> <tr> <td class="tableblock halign-center valign-top" ><p class="tableblock">Rerun non-good completed</p></td> <td class="tableblock halign-left valign-top" ><p class="tableblock monospaced">-rerun-clean</p></td> <td class="tableblock halign-left valign-top" ><p class="tableblock monospaced">rerunclean</p></td> </tr> <tr> <td class="tableblock halign-center valign-top" ><p class="tableblock">Rerun all non-good and not completed yet</p></td> <td class="tableblock halign-left valign-top" ><p class="tableblock monospaced">-set-state-status KILLREQ; -rerun-</p></td> <td class="tableblock halign-left valign-top" ><p class="tableblock monospaced">clean</p></td> </tr> <tr> <td class="tableblock halign-center valign-top" ><p class="tableblock">killrerun</p></td> <td class="tableblock halign-left valign-top" ><p class="tableblock monospaced">Continue run</p></td> <td class="tableblock halign-left valign-top" ><p class="tableblock monospaced">-run</p></td> </tr> <tr> <td class="tableblock halign-center valign-top" ><p class="tableblock">resume</p></td> <td class="tableblock halign-left valign-top" ><p class="tableblock monospaced">Remove run</p></td> <td class="tableblock halign-left valign-top" ><p class="tableblock monospaced">-remove-runs</p></td> </tr> <tr> <td class="tableblock halign-center valign-top" ><p class="tableblock">clean</p></td> <td class="tableblock halign-left valign-top" ><p class="tableblock monospaced">Lock run</p></td> <td class="tableblock halign-left valign-top" ><p class="tableblock monospaced">-lock</p></td> </tr> <tr> <td class="tableblock halign-center valign-top" ><p class="tableblock">lock</p></td> <td class="tableblock halign-left valign-top" ><p class="tableblock monospaced">Unlock run</p></td> <td class="tableblock halign-left valign-top" ><p class="tableblock monospaced">-unlock</p></td> </tr> <tr> <td class="tableblock halign-center valign-top" ><p class="tableblock">unlock</p></td> <td class="tableblock halign-left valign-top" ><p class="tableblock monospaced">killrun</p></td> <td class="tableblock halign-left valign-top" ><p class="tableblock monospaced">-set-state-status KILLREQ; -kill-run</p></td> </tr> </tbody> </table> </div> <div class="sect2"> <h3 id="_config_file_helpers">Config File Helpers</h3> <div class="paragraph"><p>Various helpers for more advanced config files.</p></div> <table class="tableblock frame-topbot grid-all" style=" width:80%; "> <caption class="title">Table 3. Helpers</caption> <col style="width:14%;"> <col style="width:28%;"> <col style="width:28%;"> <col style="width:28%;"> <thead> <tr> <th class="tableblock halign-center valign-top" >Helper </th> |
︙ | ︙ | |||
1413 1414 1415 1416 1417 1418 1419 | <div class="listingblock"> <div class="content monospaced"> <pre>[items] A a b c B d e f</pre> </div></div> <div class="paragraph"><p>Then the config file would effectively appear to contain an items section | | | | | | > > > > > > > > > > > > > > > > > > > > > | | | | | | | | < | 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 | <div class="listingblock"> <div class="content monospaced"> <pre>[items] A a b c B d e f</pre> </div></div> <div class="paragraph"><p>Then the config file would effectively appear to contain an items section exactly like the output from the script. This is useful when dynamically creating items, itemstables and other config structures. You can see the expansion of the call by looking in the cached files (look in your linktree for megatest.config and runconfigs.config cache files and in your test run areas for the expanded and cached testconfig).</p></div> <div class="paragraph"><p>Wildcards and regexes in Targets</p></div> <div class="listingblock"> <div class="content monospaced"> <pre>[a/2/b] VAR1 VAL1 [a/%/b] VAR1 VAL2</pre> </div></div> <div class="paragraph"><p>Will result in:</p></div> <div class="listingblock"> <div class="content monospaced"> <pre>[a/2/b] VAR1 VAL2</pre> </div></div> <div class="paragraph"><p>Can use either wildcard of "%" or a regular expression:</p></div> <div class="listingblock"> <div class="content monospaced"> <pre>[/abc.*def/]</pre> </div></div> </div> <div class="sect2"> <h3 id="_disk_space_checks">Disk Space Checks</h3> <div class="paragraph"><p>Some parameters you can put in the [setup] section of megatest.config:</p></div> <div class="listingblock"> <div class="content monospaced"> <pre># minimum space required in a run disk minspace 10000000 # minimum space required in dbdir: dbdir-space-required 100000 # script that takes path as parameter and returns number of bytes available: free-space-script check-space.sh</pre> </div></div> </div> <div class="sect2"> <h3 id="_trim_trailing_spaces">Trim trailing spaces</h3> <div class="listingblock"> <div class="content monospaced"> <pre>[configf:settings trim-trailing-spaces yes]</pre> </div></div> </div> <div class="sect2"> <h3 id="_job_submission_control">Job Submission Control</h3> <div class="sect3"> <h4 id="_submit_jobs_to_host_types_based_on_test_name_2">Submit jobs to Host Types based on Test Name</h4> <div class="listingblock"> <div class="title">In megatest.config</div> <div class="content monospaced"> <pre>[host-types] general nbfake remote bsub [launchers] runfirst/sum% remote % general [jobtools] launcher bsub # if defined and not "no" flexi-launcher will bypass launcher unless # there is no host-type match. flexi-launcher yes</pre> </div></div> <div class="sect4"> <h5 id="_host_types">host-types</h5> <div class="paragraph"><p>List of host types and the commandline to run a job on that host type.</p></div> <div class="listingblock"> <div class="title">host-type ⇒ launch command</div> <div class="content monospaced"> <pre>general nbfake</pre> |
︙ | ︙ | |||
1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 | <h5 id="_miscellaneous_setup_items">Miscellaneous Setup Items</h5> <div class="paragraph"><p>Attempt to rerun tests in "STUCK/DEAD", "n/a", "ZERO_ITEMS" states.</p></div> <div class="listingblock"> <div class="title">In megatest.config</div> <div class="content monospaced"> <pre>[setup] reruns 5</pre> </div></div> </div> <div class="sect4"> <h5 id="_run_time_limit">Run time limit</h5> <div class="listingblock"> <div class="content monospaced"> <pre>[setup] | > > > > > > > > > | 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 | <h5 id="_miscellaneous_setup_items">Miscellaneous Setup Items</h5> <div class="paragraph"><p>Attempt to rerun tests in "STUCK/DEAD", "n/a", "ZERO_ITEMS" states.</p></div> <div class="listingblock"> <div class="title">In megatest.config</div> <div class="content monospaced"> <pre>[setup] reruns 5</pre> </div></div> <div class="paragraph"><p>Replace the default blacklisted environment variables with user supplied list.</p></div> <div class="paragraph"><p>Default list: USER HOME DISPLAY LS_COLORS XKEYSYMDB EDITOR MAKEFLAGS MAKEF MAKEOVERRIDES</p></div> <div class="paragraph"><div class="title">Add a "bad" variable "PROMPT" to the variables that will be commented out</div><p>in the megatest.sh and megatest.csh files:</p></div> <div class="listingblock"> <div class="content monospaced"> <pre>[setup] blacklistvars USER HOME DISPLAY LS_COLORS XKEYSYMDB EDITOR MAKEFLAGS PROMPT</pre> </div></div> </div> <div class="sect4"> <h5 id="_run_time_limit">Run time limit</h5> <div class="listingblock"> <div class="content monospaced"> <pre>[setup] |
︙ | ︙ | |||
1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 | <div class="paragraph"><p>The default is the graphviz based tree but if your tests don’t view well in that mode then use "nodot" to turn it off.</p></div> <div class="listingblock"> <div class="content monospaced"> <pre>[setup] nodot</pre> </div></div> </div> <div class="sect2"> <h3 id="_dashboard_settings">Dashboard settings</h3> <div class="listingblock"> <div class="title">Runs tab buttons, font and size</div> <div class="content monospaced"> <pre>[dashboard] btn-height x14 btn-fontsz 10 cell-width 60</pre> </div></div> </div> <div class="sect2"> <h3 id="_database_settings">Database settings</h3> <table class="tableblock frame-topbot grid-all" style=" width:70%; "> | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | < < < < < < | 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 | <div class="paragraph"><p>The default is the graphviz based tree but if your tests don’t view well in that mode then use "nodot" to turn it off.</p></div> <div class="listingblock"> <div class="content monospaced"> <pre>[setup] nodot</pre> </div></div> </div> <div class="sect2"> <h3 id="_capturing_test_data">Capturing Test Data</h3> <div class="paragraph"><p>In a test you can capture arbitrary variables and roll them up in the megatest database for viewing on the dashboard or web app.</p></div> <div class="listingblock"> <div class="title">In a test as a script</div> <div class="content monospaced"> <pre>$MT_MEGATEST -load-test-data << EOF foo,bar, 1.2, 1.9, > foo,rab, 1.0e9, 10e9, 1e9 foo,bla, 1.2, 1.9, < foo,bal, 1.2, 1.2, < , ,Check for overload foo,alb, 1.2, 1.2, <= , Amps,This is the high power circuit test foo,abl, 1.2, 1.3, 0.1 foo,bra, 1.2, pass, silly stuff faz,bar, 10, 8mA, , ,"this is a comment" EOF</pre> </div></div> <div class="paragraph"><p>Alternatively you can use logpro triggers to capture values and inject them into megatest using the -set-values mechanism:</p></div> <div class="listingblock"> <div class="title">Megatest help related to -set-values</div> <div class="content monospaced"> <pre>Test data capture -set-values : update or set values in the testdata table :category : set the category field (optional) :variable : set the variable name (optional) :value : value measured (required) :expected : value expected (required) :tol : |value-expect| <= tol (required, can be <, >, >=, <= or number) :units : name of the units for value, expected_value etc. (optional)</pre> </div></div> </div> <div class="sect2"> <h3 id="_dashboard_settings">Dashboard settings</h3> <div class="listingblock"> <div class="title">Runs tab buttons, font and size</div> <div class="content monospaced"> <pre>[dashboard] btn-height x14 btn-fontsz 10 cell-width 60</pre> </div></div> </div> <div class="sect2"> <h3 id="_database_settings">Database settings</h3> <table class="tableblock frame-topbot grid-all" style=" width:70%; "> <caption class="title">Table 4. Database config settings in [setup] section of megatest.config</caption> <col style="width:14%;"> <col style="width:28%;"> <col style="width:28%;"> <col style="width:28%;"> <thead> <tr> <th class="tableblock halign-center valign-top" >Var </th> <th class="tableblock halign-left valign-top" > Purpose </th> <th class="tableblock halign-left valign-top" > Valid values </th> <th class="tableblock halign-left valign-top" > Comments</th> </tr> </thead> <tbody> <tr> <td class="tableblock halign-center valign-top" ><p class="tableblock">delay-on-busy</p></td> <td class="tableblock halign-left valign-top" ><p class="tableblock monospaced">Prevent concurrent access issues</p></td> <td class="tableblock halign-left valign-top" ><p class="tableblock monospaced">yes|no or not defined</p></td> <td class="tableblock halign-left valign-top" ><p class="tableblock monospaced">Default=no, may help on some network file systems, may slow things down also.</p></td> </tr> <tr> <td class="tableblock halign-center valign-top" ><p class="tableblock">faststart</p></td> <td class="tableblock halign-left valign-top" ><p class="tableblock monospaced">All direct file access to sqlite db files</p></td> <td class="tableblock halign-left valign-top" ><p class="tableblock monospaced">yes|no or not defined</p></td> <td class="tableblock halign-left valign-top" ><p class="tableblock monospaced">Default=yes, suggest no for central automated systems and yes for interactive use</p></td> </tr> <tr> <td class="tableblock halign-center valign-top" ><p class="tableblock">homehost</p></td> |
︙ | ︙ | |||
1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 | <div class="paragraph"><p>The runscript method is a brute force way to run scripts where the user is responsible for setting STATE and STATUS</p></div> <div class="listingblock"> <div class="content monospaced"> <pre>runscript main.csh</pre> </div></div> </div> </div> <div class="sect2"> <h3 id="_requirements_section">Requirements section</h3> <div class="listingblock"> <div class="title">Header</div> <div class="content monospaced"> <pre>[requirements]</pre> </div></div> | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | | | 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 | <div class="paragraph"><p>The runscript method is a brute force way to run scripts where the user is responsible for setting STATE and STATUS</p></div> <div class="listingblock"> <div class="content monospaced"> <pre>runscript main.csh</pre> </div></div> </div> </div> <div class="sect2"> <h3 id="_iteration">Iteration</h3> <div class="listingblock"> <div class="title">Sections for iteration</div> <div class="content monospaced"> <pre># full combinations [items] A x y B 1 2 # Yields: x/1 x/2 y/1 y/2 # tabled [itemstable] A x y B 1 2 # Yields x/1 y/2</pre> </div></div> <div class="listingblock"> <div class="title">Or use files</div> <div class="content monospaced"> <pre>[itemopts] slash path/to/file/with/items # or space path/to/file/with/items</pre> </div></div> <div class="listingblock"> <div class="title">File format for / delimited</div> <div class="content monospaced"> <pre>key1/key2/key3 val1/val2/val2 ...</pre> </div></div> <div class="listingblock"> <div class="title">File format for space delimited</div> <div class="content monospaced"> <pre>key1 key2 key3 val1 val2 val2 ...</pre> </div></div> </div> <div class="sect2"> <h3 id="_requirements_section">Requirements section</h3> <div class="listingblock"> <div class="title">Header</div> <div class="content monospaced"> <pre>[requirements]</pre> </div></div> </div> <div class="sect2"> <h3 id="_wait_on_other_tests">Wait on Other Tests</h3> <div class="listingblock"> <div class="content monospaced"> <pre># A normal waiton waits for the prior tests to be COMPLETED # and PASS, CHECK or WAIVED waiton test1 test2</pre> </div></div> </div> <div class="sect2"> <h3 id="_mode">Mode</h3> <div class="paragraph"><p>The default (i.e. if mode is not specified) is normal. All pre-dependent tests must be COMPLETED and PASS, CHECK or WAIVED before the test will start</p></div> <div class="listingblock"> <div class="content monospaced"> <pre>[requirements] mode normal</pre> </div></div> |
︙ | ︙ | |||
1673 1674 1675 1676 1677 1678 1679 | "itemmatch" are synonyms.</p></div> <div class="listingblock"> <div class="content monospaced"> <pre>[requirements] mode itemmatch</pre> </div></div> </div> | < | 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 | "itemmatch" are synonyms.</p></div> <div class="listingblock"> <div class="content monospaced"> <pre>[requirements] mode itemmatch</pre> </div></div> </div> <div class="sect2"> <h3 id="_overriding_enviroment_variables">Overriding Enviroment Variables</h3> <div class="paragraph"><p>Override variables before starting the test. Can include files (perhaps generated by megatest -envdelta or similar).</p></div> <div class="listingblock"> <div class="content monospaced"> <pre>[pre-launch-env-vars] VAR1 value1 |
︙ | ︙ | |||
1695 1696 1697 1698 1699 1700 1701 1702 1703 | </div> <div class="sect2"> <h3 id="_itemmap_handling">Itemmap Handling</h3> <div class="paragraph"><p>For cases were the dependent test has a similar but not identical itempath to the downstream test an itemmap can allow for itemmatch mode</p></div> <div class="listingblock"> <div class="content monospaced"> <pre>[requirements] | > | > | | > > > | > > > | < > > > > > > > > | | > > > > > > > > > > > > > > | > > | | | > | > | | > > | | > > | < < < < < < < | | < < < < < < < < < < < < < < < < | > | | < | < < | | | > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > | | | | | | | | | | > > > > > > > > > > > > > > > > | | | | | | 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 | </div> <div class="sect2"> <h3 id="_itemmap_handling">Itemmap Handling</h3> <div class="paragraph"><p>For cases were the dependent test has a similar but not identical itempath to the downstream test an itemmap can allow for itemmatch mode</p></div> <div class="listingblock"> <div class="title">example for removing part of itemmap for waiton test (eg: item <span class="monospaced">foo-x/bar</span> depends on waiton’s item <span class="monospaced">y/bar</span>)</div> <div class="content monospaced"> <pre>[requirements] mode itemwait # itemmap <item pattern for this test> <item replacement pattern for waiton test> itemmap .*x/ y/</pre> </div></div> <div class="listingblock"> <div class="title">example for removing part of itemmap for waiton test (eg: item <span class="monospaced">foo/bar/baz</span> in this test depends on waiton’s item <span class="monospaced">baz</span>)</div> <div class="content monospaced"> <pre># ## pattern replacement notes # # ## Example # ## Remove everything up to the last / [requirements] mode itemwait # itemmap <item pattern for this test> <nothing here indicates removal> itemmap .*/</pre> </div></div> <div class="listingblock"> <div class="title">example replacing part of itemmap for (eg: item <span class="monospaced">foo/1234</span> will imply waiton’s item <span class="monospaced">bar/1234</span>)</div> <div class="content monospaced"> <pre># # ## Example # ## Replace foo/ with bar/ [requirements] mode itemwait # itemmap <item pattern for this test> <item replacement pattern for waiton test> itemmap foo/ bar/</pre> </div></div> <div class="listingblock"> <div class="title">example for backreference (eg: item <span class="monospaced">foo23/thud</span> will imply waiton’s item <span class="monospaced">num-23/bar/thud</span></div> <div class="content monospaced"> <pre># # ## Example # ## can use \{number} in replacement pattern to backreference a (capture) from matching pattern similar to sed or perl [requirements] mode itemwait # itemmap <item pattern for this test> <item replacement pattern for waiton test> itemmap foo(\d+)/ num-\1/bar/</pre> </div></div> <div class="listingblock"> <div class="title">example multiple itemmaps</div> <div class="content monospaced"> <pre># multi-line; matches are applied in the listed order # The following would map: # a123b321 to b321fooa123 then to 321fooa123p # [requirements] itemmap (a\d+)(b\d+) \2foo\1 b(.*) \1p</pre> </div></div> </div> <div class="sect2"> <h3 id="_complex_mapping">Complex mapping</h3> <div class="paragraph"><p>Complex mappings can be handled with a separate [itemmap] section (instead if an itemmap line in the [requirements] section)</p></div> <div class="paragraph"><p>Each line in an itemmap section starts with a waiton test name followed by an itemmap expression</p></div> <div class="listingblock"> <div class="title">eg: The following causes waiton test A item <span class="monospaced">bar/1234</span> to run when our test’s <span class="monospaced">foo/1234</span> item is requested as well as causing waiton test B’s <span class="monospaced">blah</span> item to run when our test’s <span class="monospaced">stuff/blah</span> item is requested</div> <div class="content monospaced"> <pre>[itemmap] A foo/ bar/ B stuff/</pre> </div></div> </div> <div class="sect2"> <h3 id="_complex_mapping_example">Complex mapping example</h3> <div class="imageblock"> <div class="content"> <img src="complex-itemmap.png" alt="complex-itemmap.png"> </div> </div> <div class="paragraph"><p>We accomplish this by configuring the testconfigs of our tests C D and E as follows:</p></div> <div class="listingblock"> <div class="title">Testconfig for Test E has</div> <div class="content monospaced"> <pre>[requirements] waiton C itemmap (\d+)/res \1/bb</pre> </div></div> <div class="listingblock"> <div class="title">Testconfig for Test D has</div> <div class="content monospaced"> <pre>[requirements] waiton C itemmap (\d+)/res \1/aa</pre> </div></div> <div class="listingblock"> <div class="title">Testconfig for Test C has</div> <div class="content monospaced"> <pre>[requirements] waiton A B [itemmap] A (\d+)/aa aa/\1 B (\d+)/bb bb/\1</pre> </div></div> <div class="listingblock"> <div class="title">Testconfigs for Test B and Test A have no waiton or itemmap configured</div> <div class="content monospaced"> <pre></pre> </div></div> <div class="olist arabic"><div class="title">Walk through one item — we want the following to happen for testpatt <span class="monospaced">D/1/res</span> (see blue boxes in complex itemmaping figure above):</div><ol class="arabic"> <li> <p> eg from command line <span class="monospaced">megatest -run -testpatt D/1/res -target mytarget -runname myrunname</span> </p> </li> <li> <p> Full list to be run is now: <span class="monospaced">D/1/res</span> </p> </li> <li> <p> Test D has a waiton - test C. Test D’s itemmap rule <span class="monospaced">itemmap (\d+)/res \1/aa</span> → causes <span class="monospaced">C/1/aa</span> to run before <span class="monospaced">D/1/res</span> </p> </li> <li> <p> Full list to be run is now: <span class="monospaced">D/1/res</span>, <span class="monospaced">C/1/aa</span> </p> </li> <li> <p> Test C was a waiton - test A. Test C’s rule <span class="monospaced">A (\d+)/aa aa/\1</span> → causes <span class="monospaced">A/aa/1</span> to run before <span class="monospaced">C/1/aa</span> </p> </li> <li> <p> Full list to be run is now: <span class="monospaced">D/1/res</span>, <span class="monospaced">C/1/aa</span>, <span class="monospaced">A/aa/1</span> </p> </li> <li> <p> Test A has no waitons. All waitons of all tests in full list have been processed. Full list is finalized. </p> </li> </ol></div> </div> <div class="sect2"> <h3 id="_itemstable">itemstable</h3> <div class="paragraph"><p>An alternative to defining items is the itemstable section. This lets you define the itempath in a table format rather than specifying components and relying on getting all permutations of those components.</p></div> </div> <div class="sect2"> <h3 id="_dynamic_flow_dependency_tree">Dynamic Flow Dependency Tree</h3> <div class="listingblock"> <div class="title">Autogeneration waiton list for dynamic flow dependency trees</div> <div class="content monospaced"> <pre>[requirements] # With a toplevel test you may wish to generate your list # of tests to run dynamically # waiton #{shell get-valid-tests-to-run.sh}</pre> </div></div> </div> <div class="sect2"> <h3 id="_run_time_limit_2">Run time limit</h3> <div class="listingblock"> <div class="content monospaced"> <pre>[requirements] runtimelim 1h 2m 3s # this will automatically kill the test if it runs for more than 1h 2m and 3s</pre> </div></div> </div> <div class="sect2"> <h3 id="_skip">Skip</h3> <div class="paragraph"><p>A test with a skip section will conditional skip running.</p></div> <div class="listingblock"> <div class="title">Skip section example</div> <div class="content monospaced"> <pre>[skip] prevrunning x # rundelay 30m 15s</pre> </div></div> </div> <div class="sect2"> <h3 id="_skip_on_still_running_tests">Skip on Still-running Tests</h3> <div class="listingblock"> <div class="content monospaced"> <pre># NB// If the prevrunning line exists with *any* value the test will # automatically SKIP if the same-named test is currently RUNNING. The # "x" can be any string. Comment out the prevrunning line to turn off # skip. [skip] prevrunning x</pre> </div></div> </div> <div class="sect2"> <h3 id="_skip_if_a_file_exists">Skip if a File Exists</h3> <div class="listingblock"> <div class="content monospaced"> <pre>[skip] fileexists /path/to/a/file # skip if /path/to/a/file exists</pre> </div></div> </div> <div class="sect2"> <h3 id="_skip_if_a_file_does_not_exist">Skip if a File Does not Exist</h3> <div class="listingblock"> <div class="content monospaced"> <pre>[skip] filenotexists /path/to/a/file # skip if /path/to/a/file does not exist</pre> </div></div> </div> <div class="sect2"> <h3 id="_skip_if_a_script_completes_with_0_status">Skip if a script completes with 0 status</h3> <div class="listingblock"> <div class="content monospaced"> <pre>[skip] script /path/to/a/script # skip if /path/to/a/script completes with 0 status</pre> </div></div> </div> <div class="sect2"> <h3 id="_skip_if_test_ran_more_recently_than_specified_time">Skip if test ran more recently than specified time</h3> <div class="listingblock"> <div class="title">Skip if this test has been run in the past fifteen minutes and 15 seconds.</div> <div class="content monospaced"> <pre>[skip] rundelay 15m 15s</pre> </div></div> </div> <div class="sect2"> <h3 id="_disks">Disks</h3> <div class="paragraph"><p>A disks section in testconfig will override the disks section in megatest.config. This can be used to allocate disks on a per-test or per item basis.</p></div> </div> <div class="sect2"> <h3 id="_controlled_waiver_propagation">Controlled waiver propagation</h3> <div class="paragraph"><p>If test is FAIL and previous test in run with same MT_TARGET is WAIVED then apply the following rules from the testconfig: If a waiver check is specified in the testconfig apply the check and if it passes then set this FAIL to WAIVED</p></div> <div class="paragraph"><p>Waiver check has two parts, 1) a list of waiver, rulename, filepatterns and 2) the rulename script spec (note that "diff" and "logpro" are predefined)</p></div> <div class="listingblock"> <div class="content monospaced"> <pre>###### EXAMPLE FROM testconfig ######### # matching file(s) will be diff'd with previous run and logpro applied |
︙ | ︙ | |||
1869 1870 1871 1872 1873 1874 1875 | # This builtin rule is the default if there is no <waivername>.logpro file # diff diff %file1% %file2% # This builtin rule is applied if a <waivername>.logpro file exists # logpro diff %file1% %file2% | logpro %waivername%.logpro %waivername%.html</pre> </div></div> </div> | < > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > | > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 | # This builtin rule is the default if there is no <waivername>.logpro file # diff diff %file1% %file2% # This builtin rule is applied if a <waivername>.logpro file exists # logpro diff %file1% %file2% | logpro %waivername%.logpro %waivername%.html</pre> </div></div> </div> <div class="sect2"> <h3 id="_ezsteps">Ezsteps</h3> <div class="listingblock"> <div class="title">Example ezsteps with logpro rules</div> <div class="content monospaced"> <pre>[ezsteps] lookittmp ls /tmp [logpro] lookittmp ;; Note: config file format supports multi-line entries where leading whitespace is removed from each line ;; a blank line indicates the end of the block of text (expect:required in "LogFileBody" > 0 "A file name that should never exist!" #/This is a awfully stupid file name that should never be found in the temp dir/)</pre> </div></div> <div class="paragraph"><p>To transfer the environment to the next step you can do the following:</p></div> <div class="listingblock"> <div class="title">Propagate environment to next step</div> <div class="content monospaced"> <pre>$MT_MEGATEST -env2file .ezsteps/${stepname}</pre> </div></div> </div> <div class="sect2"> <h3 id="_scripts">Scripts</h3> <div class="listingblock"> <div class="title">Specifying scripts inline (best used for only simple scripts)</div> <div class="content monospaced"> <pre>[scripts] loaddb #!/bin/bash sqlite3 $1 <<EOF .mode tabs .import $2 data .q EOF</pre> </div></div> <div class="paragraph"><p>The above snippet results in the creation of an executable script called "loaddb" in the test directory. NOTE: every line in the script must be prefixed with the exact same number of spaces. Lines beginning with a # will not work as expected. Currently you cannot indent intermediate lines.</p></div> <div class="listingblock"> <div class="title">Full example with ezsteps, logpro rules, scripts etc.</div> <div class="content monospaced"> <pre># You can include a common file # [include #{getenv MT_RUN_AREA_HOME}/global-testconfig.inc] # Use "var" for a scratch pad # [var] dumpsql select * from data; sepstr ..................................... # NOT IMPLEMENTED YET! # [ezsteps-addendum] prescript something.sh postscript something2.sh # Add additional steps here. Format is "stepname script" [ezsteps] importdb loaddb prod.db prod.sql dumpprod dumpdata prod.db "#{get var dumpsql}" diff (echo "prod#{get var sepstr}test";diff --side-by-side \ dumpprod.log reference.log ;echo DIFFDONE) [scripts] loaddb #!/bin/bash sqlite3 $1 <<EOF .mode tabs .import $2 data .q EOF dumpdata #!/bin/bash sqlite3 $1 <<EOF .separator , $2 .q EOF # Test requirements are specified here [requirements] waiton setup priority 0 # Iteration for your test is controlled by the items section # The complicated if is needed to allow processing of the config for the dashboard when there are no actual runs. [items] THINGNAME [system generatethings.sh | sort -u] # Logpro rules for each step can be captured here in the testconfig # note: The ;; after the stepname and the leading whitespace are required # [logpro] inputdb ;; (expect:ignore in "LogFileBody" < 99 "Ignore error in comments" #/^\/\/.*error/) (expect:warning in "LogFileBody" = 0 "Any warning" #/warn/) (expect:required in "LogFileBody" > 0 "Some data found" #/^[a-z]{3,4}[0-9]+_r.*/) diff ;; (expect:ignore in "LogFileBody" < 99 "Ignore error in comments" #/^\/\/.*error/) (expect:warning in "LogFileBody" = 0 "Any warning" #/warn/) (expect:error in "LogFileBody" = 0 "< or > indicate missing entry" (list #/(<|>)/ #/error/i)) (expect:error in "LogFileBody" = 0 "Difference in data" (list #/\s+\|\s+/ #/error/i)) (expect:required in "LogFileBody" > 0 "DIFFDONE Marker found" #/DIFFDONE/) (expect:required in "LogFileBody" > 0 "Some things found" #/^[a-z]{3,4}[0-9]+_r.*/) # NOT IMPLEMENTED YET! # ## Also: enhance logpro to take list of command files: file1,file2... [waivers] createprod{target=%78/%/%/%} ;; (disable:required "DIFFDONE Marker found") (disable:error "Some error") (expect:waive in "LogFileBody" < 99 "Waive if failed due to version" #/\w+3\.6.*/) # test_meta is a section for storing additional data on your test [test_meta] author matt owner matt description Compare things tags tagone,tagtwo reviewed never</pre> </div></div> </div> <div class="sect2"> <h3 id="_triggers">Triggers</h3> <div class="paragraph"><p>In your testconfig or megatest.config triggers can be specified</p></div> <div class="listingblock"> <div class="title">Triggers spec</div> <div class="content monospaced"> <pre>[triggers] # Call script running.sh when test goes to state=RUNNING, status=PASS RUNNING/PASS running.sh # Call script running.sh any time state goes to RUNNING RUNNING/ running.sh # Call script onpass.sh any time status goes to PASS PASS/ onpass.sh</pre> </div></div> <div class="paragraph"><p>Scripts called will have; test-id test-rundir trigger test-name item-path state status event-time, added to the commandline.</p></div> <div class="paragraph"><p>HINT</p></div> <div class="paragraph"><p>To start an xterm (useful for debugging), use a command line like the following:</p></div> <div class="listingblock"> <div class="title">Start an xterm using a trigger for test completed.</div> <div class="content monospaced"> <pre>[triggers] COMPLETED/ xterm -e bash -s --</pre> </div></div> <div class="admonitionblock"> <table><tr> <td class="icon"> <img src="/nfs/pdx/disks/ice.disk.002/icfadm/pkgs/asciidoc/8.6.7/images/icons/note.png" alt="Note"> </td> <td class="content">There is a trailing space after the double-dash</td> </tr></table> </div> <div class="paragraph"><p>There are a number of environment variables available to the trigger script but since triggers can be called in various contexts not all variables are available at all times. The trigger script should check for the variable and fail gracefully if it doesn’t exist.</p></div> <table class="tableblock frame-topbot grid-all" style=" width:90%; "> <caption class="title">Table 5. Environment variables visible to the trigger script</caption> <col style="width:50%;"> <col style="width:50%;"> <thead> <tr> <th class="tableblock halign-left valign-top" > Variable </th> <th class="tableblock halign-left valign-top" > Purpose</th> </tr> </thead> <tbody> <tr> <td class="tableblock halign-left valign-top" ><p class="tableblock">MT_TEST_RUN_DIR</p></td> <td class="tableblock halign-left valign-top" ><p class="tableblock">The directory where Megatest ran this test</p></td> </tr> <tr> <td class="tableblock halign-left valign-top" ><p class="tableblock">MT_CMDINFO</p></td> <td class="tableblock halign-left valign-top" ><p class="tableblock">Encoded command data for the test</p></td> </tr> <tr> <td class="tableblock halign-left valign-top" ><p class="tableblock">MT_DEBUG_MODE</p></td> <td class="tableblock halign-left valign-top" ><p class="tableblock">Used to pass the debug mode to nested calls to Megatest</p></td> </tr> <tr> <td class="tableblock halign-left valign-top" ><p class="tableblock">MT_RUN_AREA_HOME</p></td> <td class="tableblock halign-left valign-top" ><p class="tableblock">Megatest home area</p></td> </tr> <tr> <td class="tableblock halign-left valign-top" ><p class="tableblock">MT_TESTSUITENAME</p></td> <td class="tableblock halign-left valign-top" ><p class="tableblock">The name of this testsuite or area</p></td> </tr> <tr> <td class="tableblock halign-left valign-top" ><p class="tableblock">MT_TEST_NAME</p></td> <td class="tableblock halign-left valign-top" ><p class="tableblock">The name of this test</p></td> </tr> <tr> <td class="tableblock halign-left valign-top" ><p class="tableblock">MT_ITEM_INFO</p></td> <td class="tableblock halign-left valign-top" ><p class="tableblock">The variable and values for the test item</p></td> </tr> <tr> <td class="tableblock halign-left valign-top" ><p class="tableblock">MT_MEGATEST</p></td> <td class="tableblock halign-left valign-top" ><p class="tableblock">Which Megatest binary is being used by this area</p></td> </tr> <tr> <td class="tableblock halign-left valign-top" ><p class="tableblock">MT_TARGET</p></td> <td class="tableblock halign-left valign-top" ><p class="tableblock">The target variable values, separated by <em>/</em></p></td> </tr> <tr> <td class="tableblock halign-left valign-top" ><p class="tableblock">MT_LINKTREE</p></td> <td class="tableblock halign-left valign-top" ><p class="tableblock">The base of the link tree where all run tests can be found</p></td> </tr> <tr> <td class="tableblock halign-left valign-top" ><p class="tableblock">MT_ITEMPATH</p></td> <td class="tableblock halign-left valign-top" ><p class="tableblock">The values of the item path variables, separated by <em>/</em></p></td> </tr> <tr> <td class="tableblock halign-left valign-top" ><p class="tableblock">MT_RUNNAME</p></td> <td class="tableblock halign-left valign-top" ><p class="tableblock">The name of the run</p></td> </tr> </tbody> </table> </div> <div class="sect2"> <h3 id="_override_the_toplevel_html_file">Override the Toplevel HTML File</h3> <div class="paragraph"><p>Megatest generates a simple html file summary for top level tests of iterated tests. The generation can be overridden. NOTE: the output of the script is captured from stdout to create the html.</p></div> <div class="listingblock"> |
︙ | ︙ | |||
1959 1960 1961 1962 1963 1964 1965 | # Within the archive the data is structured like this: # <target>/<runname>/<test>/ archive0 /mfs/myarchive-data/adisk1</pre> </div></div> </div> </div> <div class="sect1"> | | | > > < < | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 | # Within the archive the data is structured like this: # <target>/<runname>/<test>/ archive0 /mfs/myarchive-data/adisk1</pre> </div></div> </div> </div> <div class="sect1"> <h2 id="_environment_variables">Environment Variables</h2> <div class="sectionbody"> <div class="paragraph"><p>It is often necessary to capture and or manipulate environment variables. Megatest has some facilities built in to help.</p></div> <div class="sect2"> <h3 id="_capture_variables">Capture variables</h3> <div class="listingblock"> <div class="title">Commands</div> <div class="content monospaced"> <pre># capture the current enviroment into a db called envdat.db under # the context "before" megatest -envcap before # capture the current environment into a db called startup.db with # context "after" megatest -envcap after startup.db # write the diff from before to after megatest -envdelta before-after -dumpmode bash</pre> </div></div> <div class="paragraph"><p>Dump modes include bash, csh and config. You can include config data into megatest.config, runconfigs.config and testconfig files. This is useful for capturing a complex environment in a special-purpose test and then utilizing that environment in downstream tests.</p></div> <div class="listingblock"> <div class="title">Example of generating and using config data</div> <div class="content monospaced"> <pre>megatest -envcap original # do some stuff here megatest -envcap munged megatest -envdelta original-munged -dumpmode ini -o modified.config</pre> </div></div> <div class="paragraph"><p>Then in runconfigs.config</p></div> <div class="listingblock"> <div class="title">Example of using modified.config in a testconfig</div> <div class="content monospaced"> <pre>[pre-launch-env-vars] [include modified.config]</pre> </div></div> </div> </div> </div> <div class="sect1"> <h2 id="_managing_old_runs">Managing Old Runs</h2> <div class="sectionbody"> <div class="paragraph"><p>It is often desired to keep some older runs around but this must be balanced with the costs of disk space.</p></div> <div class="olist arabic"><ol class="arabic"> <li> <p> Use -remove-keep </p> </li> <li> <p> Use -archive (can also be done from the -remove-keep interface) </p> </li> <li> <p> use -remove-runs with -keep-records </p> </li> </ol></div> <div class="listingblock"> <div class="title">For each target, remove all runs but the most recent 3 if they are over 1 week old</div> <div class="content monospaced"> <pre># use -precmd 'sleep 5;nbfake' to limit overloading the host computer but to allow the removes to run in parallel. megatest -actions print,remove-runs -remove-keep 3 -target %/%/%/% -runname % -age 1w -precmd 'sleep 5;nbfake'"</pre> </div></div> </div> </div> <div class="sect1"> <h2 id="_nested_runs">Nested Runs</h2> <div class="sectionbody"> <div class="paragraph"><p>A Megatest test can run a full Megatest run in either the same Megatest area or in another area. This is a powerful way of chaining complex suites of tests and or actions.</p></div> <div class="paragraph"><p>If you are not using the current area you can use ezsteps to retrieve and setup the sub-Megatest run area.</p></div> <div class="paragraph"><p>In the testconfig:</p></div> <div class="listingblock"> <div class="content monospaced"> <pre>[subrun] # Required: wait for the run or just launch it # if no then the run will be an automatic PASS irrespective of the actual result run-wait yes|no # Optional: where to execute the run. Default is the current runarea run-area /some/path/to/megatest/area # Optional: method to use to determine pass/fail status of the run # auto (default) - roll up the net state/status of the sub-run # logpro - use the provided logpro rules, happens automatically if there is a logpro section # passfail auto|logpro # Example of logpro: passfail logpro # Optional: logpro ;; if this section exists then logpro is used to determine pass/fail (expect:required in "LogFileBody" >= 1 "At least one pass" #/PASS/) (expect:error in "LogFileBody" = 0 "No FAILs allowed" #/FAIL/) # Optional: target translator, default is to use the parent target target #{shell somescript.sh} # Optional: runname translator/generator, default is to use the parent runname run-name #{somescript.sh} # Optional: testpatt spec, default is to first look for TESTPATT spec from runconfigs unless there is a contour spec test-patt %/item1,test2 # Optional: contour spec, use the named contour from the megatest.config contour spec contour contourname ### NOTE: Not implemented yet! Let us know if you need this feature. # Optional: mode-patt, use this spec for testpatt from runconfigs mode-patt TESTPATT # Optional: tag-expr, use this tag-expr to select tests tag-expr quick # Optional: (not yet implemented, remove-runs is always propagated at this time), propagate these actions from the parent # test # Note// default is % for all propagate remove-runs archive ...</pre> </div></div> </div> </div> <div class="sect1"> <h2 id="_programming_api">Programming API</h2> <div class="sectionbody"> <div class="paragraph"><p>These routines can be called from the megatest repl.</p></div> <table class="tableblock frame-topbot grid-all" style=" width:70%; "> <caption class="title">Table 6. API Keys Related Calls</caption> <col style="width:14%;"> <col style="width:28%;"> <col style="width:28%;"> <col style="width:28%;"> <thead> <tr> <th class="tableblock halign-center valign-top" >API Call </th> |
︙ | ︙ | |||
2052 2053 2054 2055 2056 2057 2058 | <div class="content"> <img src="server.png" alt="server.png"> </div> </div> </div> </div> <div class="sect1"> | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985 2986 2987 2988 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005 3006 3007 3008 3009 3010 3011 3012 3013 3014 3015 3016 3017 3018 3019 3020 3021 3022 3023 3024 3025 3026 3027 3028 3029 3030 3031 3032 3033 3034 3035 3036 3037 3038 3039 3040 3041 3042 3043 3044 3045 3046 3047 3048 3049 3050 3051 3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066 3067 3068 3069 3070 3071 3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090 3091 3092 3093 3094 3095 3096 3097 3098 3099 3100 3101 3102 3103 3104 3105 3106 3107 3108 3109 3110 3111 3112 3113 3114 3115 3116 3117 3118 3119 3120 3121 3122 3123 3124 3125 3126 3127 3128 3129 3130 3131 3132 3133 3134 3135 3136 3137 3138 3139 3140 3141 3142 3143 3144 3145 3146 3147 3148 3149 3150 3151 3152 3153 3154 3155 3156 3157 3158 3159 3160 3161 3162 3163 3164 3165 3166 3167 3168 3169 3170 3171 3172 3173 3174 3175 3176 3177 3178 3179 3180 3181 3182 3183 3184 3185 3186 3187 3188 3189 3190 3191 3192 3193 3194 3195 3196 3197 3198 3199 3200 | <div class="content"> <img src="server.png" alt="server.png"> </div> </div> </div> </div> <div class="sect1"> <h2 id="_road_map">Road Map</h2> <div class="sectionbody"> <div class="paragraph"><p>Note 1: This road-map continues to evolve and subject to change without notice.</p></div> <div class="sect2"> <h3 id="_here_is_a_smattering_of_ideas_for_megatest_2_0">Here is a smattering of ideas for Megatest 2.0</h3> <div class="olist arabic"><ol class="arabic"> <li> <p> Add variable $MT_RUNPATH = $MT_LINKTREE/$MT_TARGET/$MT_RUNNAME </p> </li> </ol></div> <div class="listingblock"> <div class="content monospaced"> <pre>[db] api legacy|new</pre> </div></div> <div class="olist arabic"><ol class="arabic"> <li> <p> One big lesson from the 1.63-1.65 generation was that the main.db, 1.db … model was really good at scaling. I’d like to combine that model with the current also-very-good model. Obviously this is a disruptive change. I think making the old model the default and the new model an option for at least one generation would be fair. </p> </li> <li> <p> Rigorous megatest.config and runconfig.config caching. </p> <div class="olist loweralpha"><ol class="loweralpha"> <li> <p> Cache the configs in $MT_RUNPATH </p> </li> <li> <p> Following invocations of –run, -rerun* will calculate the new config but only overwrite the cached file IF changed </p> </li> </ol></div> </li> <li> <p> If the cached file changes ALL existing tests go from COMPLETED → STALE, I’m not sure what to do about RUNNING tests </p> </li> <li> <p> !VARS in runconfigs are not exported to the environment. They are accessed via rget as if the ! was not there. </p> </li> <li> <p> Per test copy commands (crude example below is not correct). </p> </li> </ol></div> <div class="listingblock"> <div class="content monospaced"> <pre>[testcopy] %/iind% unison SRC DEST % cp –r SRC DEST</pre> </div></div> <div class="olist arabic"><ol class="arabic"> <li> <p> Test management via pkts (optional?) </p> <div class="olist loweralpha"><ol class="loweralpha"> <li> <p> Control pkt types: run, kill, rerunclean, clean, archive, status? </p> </li> <li> <p> Status pkt types: ack, step, status_change </p> </li> </ol></div> </li> <li> <p> Add nanomsg as a transport option . </p> </li> </ol></div> </div> <div class="sect2"> <h3 id="_rfc_m01_add_ability_to_move_runs_to_other_areas">RFC M01: Add ability to move runs to other Areas</h3> <div class="paragraph"><p><strong>Purpose</strong>: allow shrinking megatest.db data by moving runs to an alternate Megatest area with same keys.</p></div> <div class="paragraph"><p><strong>Method</strong>: extend db sync to take a different megatest area as a destination.</p></div> <div class="paragraph"><p><strong>Design</strong>:</p></div> <div class="olist arabic"><ol class="arabic"> <li> <p> add param -destination [area|path]. when specified runs are copied to new area and removed from local db. </p> </li> <li> <p> the data move would involve these steps </p> <div class="olist loweralpha"><ol class="loweralpha"> <li> <p> copy the run data to destination area megatest.db </p> </li> <li> <p> mark the run records as deleted, do not remove the run data on disk </p> </li> </ol></div> </li> <li> <p> accessing the data would be by running dashboard in the satellite area </p> </li> <li> <p> future versions of Megatest dashboard should support displaying areas in a merged way. </p> </li> <li> <p> some new controls would be supported in the config </p> <div class="olist loweralpha"><ol class="loweralpha"> <li> <p> [setup] ⇒ allow-runs [no|yes] ⇐= used to disallow runs </p> </li> <li> <p> [setup] ⇒ auto-migrate=[areaname|path] ⇐= used to automatically migrate data to a satellite area. </p> </li> </ol></div> </li> </ol></div> <div class="paragraph"><p><strong>Branch</strong>: This work is taking place on branch v1.65-reduce-records</p></div> </div> <div class="sect2"> <h3 id="_rfc_m02_move_data_into_completed_runs_db">RFC M02: Move data into completed-runs.db</h3> <div class="paragraph"><p><strong>Purpose</strong>: shrink megatest.db data to enable lower load and higher performance.</p></div> <div class="paragraph"><p><strong>Method</strong>: add a completed-runs.db and automatically move runs data from megatest.db to that db</p></div> <div class="paragraph"><p><strong>Design</strong>:</p></div> <div class="olist arabic"><ol class="arabic"> <li> <p> completed-runs.db is a full megatest database with complete schema </p> </li> <li> <p> the data move would involve these steps </p> <div class="olist loweralpha"><ol class="loweralpha"> <li> <p> copy the run data to completed-runs.db </p> </li> <li> <p> remove the run data, first from /tmp/…/megatest.db and /tmp/…/megatest_ref.db, followed by megatest.db </p> </li> </ol></div> </li> <li> <p> accessing the data would be unchanged for most operations. </p> </li> <li> <p> a mode -full-db will be added which when specified would attach the completed-runs.db to megatest.db before doing the query </p> </li> <li> <p> mechanisms for moving runs to/from the megatest.db would be added </p> <div class="olist loweralpha"><ol class="loweralpha"> <li> <p> -reduce-records ⇒ move runs to completed-runs.db </p> </li> <li> <p> -restore-records ⇒ move runs from completed-runs.db to megatest.db </p> </li> </ol></div> </li> </ol></div> <div class="paragraph"><p><strong>Branch</strong>: This work is taking place on branch v1.65-reduce-records</p></div> </div> <div class="sect2"> <h3 id="_rfc_m03_automatic_homehost_migrations">RFC M03: Automatic homehost migrations</h3> <div class="paragraph"><p><strong>Purpose</strong>: Automatically migrate homehost.</p></div> <div class="paragraph"><p><strong>Method</strong>: Check that there are no tests running, launched or remotehoststart in past ½ hour then if not on homehost migrate the db to current host</p></div> <div class="paragraph"><p><strong>Design</strong>:</p></div> <div class="olist arabic"><ol class="arabic"> <li> <p> Check that the system is quiescent, i.e. that there are no runs in flight or recently run </p> </li> <li> <p> Create a lock </p> </li> <li> <p> Migrate the /tmp cache db to the current host </p> </li> <li> <p> Update the .homehost file </p> </li> <li> <p> Remove the lock </p> </li> </ol></div> <div class="paragraph"><p><strong>Branch</strong>: This work not yet started</p></div> </div> <div class="sect2"> <h3 id="_architecture_refactor">Architecture Refactor</h3> <div class="sect3"> <h4 id="_goals">Goals</h4> <div class="olist arabic"><ol class="arabic"> <li> <p> Reduce load on the file system. Sqlite3 files on network filesystem can be a burden. <span class="green">[DONE]</span> </p> </li> <li> <p> Reduce number of servers and frequency of start/stop. This is mostly an issue of clutter but also a reduction in "moving parts". <span class="green">[DONE]</span> </p> </li> <li> <p> Coalesce activities to a single home host where possible. Give the user feedback that they have started the dashboard on a host other than the home host. <span class="green">[DONE]</span> </p> </li> <li> <p> Reduce number of processes involved in managing running tests. </p> </li> </ol></div> </div> <div class="sect3"> <h4 id="_changes_needed">Changes Needed</h4> <div class="olist arabic"><ol class="arabic"> <li> <p> ACID compliant db will be on /tmp and synced to megatest.db with a five second max delay. <span class="green">[DONE]</span> </p> </li> <li> <p> Read/writes to db for processes on homehost will go direct to /tmp megatest.db file. <span class="green">[DONE]</span> </p> </li> <li> <p> Read/wites fron non-homehost processes will go through one server. Bulk reads (e.g. for dashboard or list-runs) will be cached on the current host in /tmp and synced from the home megatest.db in the testsuite area. <span class="green">[DONE]</span> </p> </li> <li> <p> Db syncs rely on the target db file timestame minus some margin. <span class="green">[DONE]</span> </p> </li> <li> <p> Since bulk reads do not use the server we can switch to simple RPC for the network transport. <span class="green">[DONE]</span> </p> </li> <li> <p> Test running manager process extended to manage multiple running tests. </p> </li> </ol></div> </div> </div> <div class="sect2"> <h3 id="_current_items">Current Items</h3> <div class="sect3"> <h4 id="_ww05_migrate_to_inmem_db">ww05 - migrate to inmem-db</h4> <div class="olist arabic"><ol class="arabic"> <li> <p> Switch to inmem db with fast sync to on disk db’s <span class="green">[DONE]</span> </p> </li> <li> <p> Server polls tasks table for next action </p> <div class="olist loweralpha"><ol class="loweralpha"> <li> <p> Task table used for tracking runner process <span class="red">[Replaced by mtutil]</span> </p> </li> <li> <p> Task table used for jobs to run <span class="red">[Replaced by mtutil]</span> </p> </li> <li> <p> Task table used for queueing runner actions (remove runs, cleanRunExecute, etc) <span class="red">[Replaced by mtutil</span>] </p> </li> </ol></div> </li> </ol></div> <div class="paragraph"><p>shifting, note that the preceding blank line is needed.</p></div> </div> </div> </div> </div> <div class="sect1"> <h2 id="_index">Index</h2> <div class="sectionbody"> </div> </div> </div> <div id="footnotes"><hr></div> <div id="footer"> <div id="footer-text"> Version 1.0<br> Last updated 2020-07-22 14:21:46 PDT </div> </div> </body> </html> |
Modified docs/manual/megatest_manual.txt from [c82fa9e963] to [2589d78a96].
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | The Megatest Users Manual ========================= Matt Welland <matt@kiatoa.com> v1.0, April 2012 :doctype: book [preface] Preface ------- This book is organised as three sub-books; getting started, writing tests and reference. Why Megatest? ------------- The Megatest project was started for two reasons, the first was an immediate and pressing need for a generalized tool to manage a suite | > > > > > > > > > > > > > > > > > > > > > | | | | | > | > | | | | | | | < | | > | | | | | > | > | | | > > > > > | > > > > > | | | > > | < < < > > | > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 | The Megatest Users Manual ========================= Matt Welland <matt@kiatoa.com> v1.0, April 2012 :doctype: book [preface] Preface ------- This book is organised as three sub-books; getting started, writing tests and reference. .License ---------------------------- Copyright 2006-2017, Matthew Welland. This document is part of Megatest. Megatest is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Megatest is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Megatest. If not, see <http://www.gnu.org/licenses/>. ---------------------------- Why Megatest? ------------- The Megatest project was started for two reasons, the first was an immediate and pressing need for a generalized tool to manage a suite of regression tests and the second was the fact that I had written or maintained several such tools at different companies over the years. I thought a single open source tool, flexible enough to meet the needs of any team doing continuous integrating and or running a complex suite of tests for release qualification would solve some problems for me and for others. -- Matt Welland, original author of the Megatest tool suite. Megatest Design Philosophy -------------------------- Megatest is a distributed system intended to provide the minimum needed resources to make writing a suite of tests and tasks for implementing continuous build for software, design engineering or process control (via owlfs for example) without being specialized for any specific problem space. Megatest in of itself does not know what constitutes a PASS or FAIL of a test or task. In most cases megatest is best used in conjunction with logpro or a similar tool to parse, analyze and decide on the test outcome. * Self-checking - make it as easy as possible to write self-checking tests (as opposed to using deltas, i.e. tests that compare with a previous measurement to deterine PASS/FAIL). * Traceable - environment variables, host OS and other possibly influential variables are captured and kept recorded. * Immutable - once a test is run it cannot be easily overwritten or modified accidentally. * Repeatable - test results can be recreated in the future using all the original variables. * Relocatable - the testsuite or automation area can be checked out and the tests run anywhere in the disk hierarchy. * Encapsulated - the tests run in self-contained directories and all inputs and outputs to the process can be found in the run areas. * Deployable - a testsuite is self-contained and can be bundled with a software project and easily used by others with little to no setup burden. Megatest Architecture --------------------- Data separation ~~~~~~~~~~~~~~~ All data to specify the tests and configure the system is stored in plain text config files. All system state is stored in an sqlite3 database. Distributed Compute ~~~~~~~~~~~~~~~~~~~ Tests are launched using the launching system available for the distributed compute platform in use. A template script is provided which can launch jobs on local and remote Linux hosts. Currently megatest uses the network filesystem to call home to your master sqlite3 database. Megatest has been used with the Intel Netbatch and lsf (also known as openlava) batch systems and it should be straightforward to use it with other similar systems. include::overview.txt[] include::installation.txt[] include::getting_started.txt[] include::study_plan.txt[] // :leveloffset: 0 include::writing_tests.txt[] include::howto.txt[] include::reference.txt[] Megatest Internals ------------------ ["graphviz", "server.png"] ---------------------------------------------------------------------- include::server.dot[] ---------------------------------------------------------------------- include::plan.txt[] // to allow the getting_started.txt to be a stand-alone document use level shifting, note that the preceding blank line is needed. // :leveloffset: 2 // [appendix] // Example Appendix // ================ // One or more optional appendixes go here at section level zero. // |
︙ | ︙ | |||
130 131 132 133 134 135 136 | // // [colophon] // Example Colophon // ================ // Text at the end of a book describing facts about its production. [index] | | | | 173 174 175 176 177 178 179 180 181 182 183 184 185 | // // [colophon] // Example Colophon // ================ // Text at the end of a book describing facts about its production. [index] Index ----- //////////////////////////////////////////////////////////////// The index is normally left completely empty, it's contents are generated automatically by the DocBook toolchain. //////////////////////////////////////////////////////////////// |
Added docs/manual/overview.txt version [79d741067f].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | Overview -------- Stand-alone Megatest Area ~~~~~~~~~~~~~~~~~~~~~~~~~ A single, stand-alone, Megatest based testsuite or "area" is sufficient for most validation, automation and build problems. image::megatest-stand-alone-area.png[Static,300] Megatest is designed as a distributed or decoupled system. This means you can run the areas stand-alone with no additional infrastructure. I.e. there are no databases, web servers or other centralized resources needed. However as your needs grow you can integrate multiple areas into a bigger system. Component Descriptions ^^^^^^^^^^^^^^^^^^^^^^ . Multi-area dashboard and xterm. A gui (the dashboard) is usually the best option for controlling and launching runs but all operations can also be done from the commandline. Note: The not yet released multi-area dashboard replaces the old dashboard for browsing and controlling runs but for managing a single area the old dashboard works very well. . Area/testsuite. This is your testsuite or automation definition and consists of the information in megatest.config, runconfigs.config and your testconfigs along with any custom scripting that can't be done with the native Megatest features. . If your testsuite or build automation is too large to run on a single instance you can distribute your jobs into a compute server pool. The only current requirements are password-less ssh access and a network filesystem. Full System Architecture ~~~~~~~~~~~~~~~~~~~~~~~~ image::megatest-system-architecture.png[Static,300] |
Added docs/manual/plan.txt version [660a99057c].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 | Road Map -------- // This file is part of Megatest. // // Megatest is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Megatest is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Megatest. If not, see <http://www.gnu.org/licenses/>. // Copyright 2006-2012, Matthew Welland. Note 1: This road-map continues to evolve and subject to change without notice. Here is a smattering of ideas for Megatest 2.0 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ . Add variable $MT_RUNPATH = $MT_LINKTREE/$MT_TARGET/$MT_RUNNAME ---------------- [db] api legacy|new ---------------- . One big lesson from the 1.63-1.65 generation was that the main.db, 1.db … model was really good at scaling. I’d like to combine that model with the current also-very-good model. Obviously this is a disruptive change. I think making the old model the default and the new model an option for at least one generation would be fair. . Rigorous megatest.config and runconfig.config caching. .. Cache the configs in $MT_RUNPATH .. Following invocations of –run, -rerun* will calculate the new config but only overwrite the cached file IF changed . If the cached file changes ALL existing tests go from COMPLETED -> STALE, I’m not sure what to do about RUNNING tests . !VARS in runconfigs are not exported to the environment. They are accessed via rget as if the ! was not there. . Per test copy commands (crude example below is not correct). ---------------- [testcopy] %/iind% unison SRC DEST % cp –r SRC DEST ---------------- . Test management via pkts (optional?) .. Control pkt types: run, kill, rerunclean, clean, archive, status? .. Status pkt types: ack, step, status_change . Add nanomsg as a transport option . RFC M01: Add ability to move runs to other Areas ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ *Purpose*: allow shrinking megatest.db data by moving runs to an alternate Megatest area with same keys. *Method*: extend db sync to take a different megatest area as a destination. *Design*: . add param -destination [area|path]. when specified runs are copied to new area and removed from local db. . the data move would involve these steps .. copy the run data to destination area megatest.db .. mark the run records as deleted, do not remove the run data on disk . accessing the data would be by running dashboard in the satellite area . future versions of Megatest dashboard should support displaying areas in a merged way. . some new controls would be supported in the config .. [setup] => allow-runs [no|yes] <== used to disallow runs .. [setup] => auto-migrate=[areaname|path] <== used to automatically migrate data to a satellite area. *Branch*: This work is taking place on branch v1.65-reduce-records RFC M02: Move data into completed-runs.db ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ *Purpose*: shrink megatest.db data to enable lower load and higher performance. *Method*: add a completed-runs.db and automatically move runs data from megatest.db to that db *Design*: . completed-runs.db is a full megatest database with complete schema . the data move would involve these steps .. copy the run data to completed-runs.db .. remove the run data, first from /tmp/…/megatest.db and /tmp/…/megatest_ref.db, followed by megatest.db . accessing the data would be unchanged for most operations. . a mode -full-db will be added which when specified would attach the completed-runs.db to megatest.db before doing the query . mechanisms for moving runs to/from the megatest.db would be added .. -reduce-records => move runs to completed-runs.db .. -restore-records => move runs from completed-runs.db to megatest.db *Branch*: This work is taking place on branch v1.65-reduce-records RFC M03: Automatic homehost migrations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ *Purpose*: Automatically migrate homehost. *Method*: Check that there are no tests running, launched or remotehoststart in past ½ hour then if not on homehost migrate the db to current host *Design*: . Check that the system is quiescent, i.e. that there are no runs in flight or recently run . Create a lock . Migrate the /tmp cache db to the current host . Update the .homehost file . Remove the lock *Branch*: This work not yet started Architecture Refactor ~~~~~~~~~~~~~~~~~~~~~ Goals ^^^^^ . Reduce load on the file system. Sqlite3 files on network filesystem can be a burden. [green]#[DONE]# . Reduce number of servers and frequency of start/stop. This is mostly an issue of clutter but also a reduction in "moving parts". [green]#[DONE]# . Coalesce activities to a single home host where possible. Give the user feedback that they have started the dashboard on a host other than the home host. [green]#[DONE]# . Reduce number of processes involved in managing running tests. Changes Needed ^^^^^^^^^^^^^^ . ACID compliant db will be on /tmp and synced to megatest.db with a five second max delay. [green]#[DONE]# . Read/writes to db for processes on homehost will go direct to /tmp megatest.db file. [green]#[DONE]# . Read/wites fron non-homehost processes will go through one server. Bulk reads (e.g. for dashboard or list-runs) will be cached on the current host in /tmp and synced from the home megatest.db in the testsuite area. [green]#[DONE]# . Db syncs rely on the target db file timestame minus some margin. [green]#[DONE]# . Since bulk reads do not use the server we can switch to simple RPC for the network transport. [green]#[DONE]# . Test running manager process extended to manage multiple running tests. Current Items ~~~~~~~~~~~~~ ww05 - migrate to inmem-db ^^^^^^^^^^^^^^^^^^^^^^^^^^ . Switch to inmem db with fast sync to on disk db's [green]#[DONE]# . Server polls tasks table for next action .. Task table used for tracking runner process [red]#[Replaced by mtutil]# .. Task table used for jobs to run [red]#[Replaced by mtutil]# .. Task table used for queueing runner actions (remove runs, cleanRunExecute, etc) [red]#[Replaced by mtutil#] // ww32 // ~~~~ // // . Rerun step and or subsequent steps from gui // . Refresh test area files from gui // . Clean and re-run button // . Clean up STATE and STATUS handling. // .. Dashboard and Test control panel are reverse order - choose and fix // .. Move seldom used states and status to drop down selector // . Access test control panel when clicking on Run Summary tests // . Feature: -generate-index-tree // . Change specifing of state and status to use STATE1/STATUS1,STATE2/STATUS2 // // ww33 // ~~~~ // // . http api available for use with Perl, Ruby etc. scripts // . megatest.config setup entries for: // .. run launching (e.g. /bin/sh %CMD% > /dev/null) // .. browser "konqueror %FNAME% // // ww34 // ~~~~ // // . Mark dependent tests for clean/rerun -rerun-downstream // . On run start check for defunct tests in RUNNING, LAUNCHED or REMOTEHOSTSTART and correct or notify // . Fix: refresh of gui sometimes fails on last item (race condition?) // // ww35 // ~~~~ // // . refdb: Add export of csv, json and sexp // . Convert to using call-with-environment-variables where possible. Should allow handling of parallel runs in same process. // . Re-work text interface wizards. Several bugs on record. Possibly convert to gui based. // . Add to testconfig requirements section; launchlimiter scriptname, calls scriptname to check if ok to launch test // . Refactor Run Summary view, currently very clumsy // . Add option to show steps in Run Summary view // // ww36 // ~~~~ // // . Refactor guis for resizeablity // . Add filters to Run Summary view and Run Control view // . Add to megatest.config or testconfig; rerunok STATE/STATUS,STATE/STATUS... // . Launch gates for diskspace; /path/one>1G,/path/two>200M,/tmp>5G,#{scheme *toppath*}>1G // // Bin List // ~~~~~~~~ // // . Quality improvements // .. Server stutters occasionally // .. Large number of items or tests still has some issues. // .. Code refactoring // .. Replace remote process with true API using json (supports Web app also) // . Streamline the gui // .. Everything resizable // .. Less clutter // .. Tool tips // .. Filters on Run Summary, Summary and Run Control panel // .. Built in log viewer (partially implemented) // .. Refactor the test control panel // . Help and documentation // .. Complete the user manual (I’ve been working on this lately). // .. Online help in the gui // . Streamlined install // .. Deployed version (download a location independent ready to run binary bundle) // .. Install Makefile (in progress, needed for Mike to install on VMs) // .. Added option to compile IUP (needed for VMs) // . Server side run launching // . Support for re-running, cleaning etc. of individual steps (ezsteps makes this very easy to implement). // . Launch process needs built in daemonizing (easy to do, just need to test it thoroughly). // . Wizards for creating tests, regression areas (current ones are text only and limited). // . Fully functional built in web service (currently you can browse runs but it is very simplistic). // . Wildcards in runconfigs: e.g. [p1271/9/%/%] // . Gui panels for editing megatest.config and runconfigs.config // . Fully isolated tests (no use of NFS to see regression area files) // . Windows version |
Modified docs/manual/reference.txt from [45163346ae] to [4a0af0abde].
1 2 3 4 5 6 7 8 9 10 11 | Reference --------- Config File Helpers ~~~~~~~~~~~~~~~~~~~ Various helpers for more advanced config files. .Helpers [width="80%",cols="^,2m,2m,2m",frame="topbot",options="header"] | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | // This file is part of Megatest. // // Megatest is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Megatest is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Megatest. If not, see <http://www.gnu.org/licenses/>. Reference --------- Megatest Use Modes ~~~~~~~~~~~~~~~~~~ .Base commands [width="80%",cols="^,2m,2m",frame="topbot",options="header"] |====================== |Use case | Megatest command | mtutil |Start from scratch | -rerun-all | restart |Rerun non-good completed | -rerun-clean | rerunclean |Rerun all non-good and not completed yet | -set-state-status KILLREQ; -rerun-|clean | killrerun |Continue run | -run | resume |Remove run | -remove-runs | clean |Lock run | -lock | lock |Unlock run | -unlock | unlock |killrun | -set-state-status KILLREQ; -kill-run | killrun |====================== Config File Helpers ~~~~~~~~~~~~~~~~~~~ Various helpers for more advanced config files. .Helpers [width="80%",cols="^,2m,2m,2m",frame="topbot",options="header"] |
︙ | ︙ | |||
65 66 67 68 69 70 71 72 73 74 | ------------------------- [a/2/b] VAR1 VAL2 ------------------------- Can use either wildcard of "%" or a regular expression: [/abc.*def/] Disk Space Checks | > > < > < > < > < > | 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 | ------------------------- [a/2/b] VAR1 VAL2 ------------------------- Can use either wildcard of "%" or a regular expression: ------------------------- [/abc.*def/] ------------------------- Disk Space Checks ~~~~~~~~~~~~~~~~~ Some parameters you can put in the [setup] section of megatest.config: ------------------- # minimum space required in a run disk minspace 10000000 # minimum space required in dbdir: dbdir-space-required 100000 # script that takes path as parameter and returns number of bytes available: free-space-script check-space.sh ------------------- Trim trailing spaces ~~~~~~~~~~~~~~~~~~~~ ------------------ [configf:settings trim-trailing-spaces yes] ------------------ Job Submission Control ~~~~~~~~~~~~~~~~~~~~~~ Submit jobs to Host Types based on Test Name ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .In megatest.config ------------------------ [host-types] general nbfake remote bsub |
︙ | ︙ | |||
142 143 144 145 146 147 148 149 150 151 152 153 154 155 | .In megatest.config ------------------ [setup] reruns 5 ------------------ Run time limit ++++++++++++++ ----------------- [setup] # this will automatically kill the test if it runs for more than 1h 2m and 3s runtimelim 1h 2m 3s | > > > > > > > > > > > > | 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 | .In megatest.config ------------------ [setup] reruns 5 ------------------ Replace the default blacklisted environment variables with user supplied list. Default list: USER HOME DISPLAY LS_COLORS XKEYSYMDB EDITOR MAKEFLAGS MAKEF MAKEOVERRIDES .Add a "bad" variable "PROMPT" to the variables that will be commented out in the megatest.sh and megatest.csh files: ----------------- [setup] blacklistvars USER HOME DISPLAY LS_COLORS XKEYSYMDB EDITOR MAKEFLAGS PROMPT ----------------- Run time limit ++++++++++++++ ----------------- [setup] # this will automatically kill the test if it runs for more than 1h 2m and 3s runtimelim 1h 2m 3s |
︙ | ︙ | |||
167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 | well in that mode then use "nodot" to turn it off. ----------------- [setup] nodot ----------------- Dashboard settings ~~~~~~~~~~~~~~~~~~ .Runs tab buttons, font and size ------------------ [dashboard] btn-height x14 btn-fontsz 10 cell-width 60 ------------------ Database settings ~~~~~~~~~~~~~~~~~ .Database config settings in [setup] section of megatest.config [width="70%",cols="^,2m,2m,2m",frame="topbot",options="header"] |====================== |Var | Purpose | Valid values | Comments |delay-on-busy | Prevent concurrent access issues | yes\|no or not defined | Default=no, may help on some network file systems, may slow things down also. | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > < | 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 | well in that mode then use "nodot" to turn it off. ----------------- [setup] nodot ----------------- Capturing Test Data ~~~~~~~~~~~~~~~~~~~ In a test you can capture arbitrary variables and roll them up in the megatest database for viewing on the dashboard or web app. .In a test as a script ------------------------ $MT_MEGATEST -load-test-data << EOF foo,bar, 1.2, 1.9, > foo,rab, 1.0e9, 10e9, 1e9 foo,bla, 1.2, 1.9, < foo,bal, 1.2, 1.2, < , ,Check for overload foo,alb, 1.2, 1.2, <= , Amps,This is the high power circuit test foo,abl, 1.2, 1.3, 0.1 foo,bra, 1.2, pass, silly stuff faz,bar, 10, 8mA, , ,"this is a comment" EOF ------------------------ Alternatively you can use logpro triggers to capture values and inject them into megatest using the -set-values mechanism: .Megatest help related to -set-values ------------------------ Test data capture -set-values : update or set values in the testdata table :category : set the category field (optional) :variable : set the variable name (optional) :value : value measured (required) :expected : value expected (required) :tol : |value-expect| <= tol (required, can be <, >, >=, <= or number) :units : name of the units for value, expected_value etc. (optional) ------------------------ Dashboard settings ~~~~~~~~~~~~~~~~~~ .Runs tab buttons, font and size ------------------ [dashboard] btn-height x14 btn-fontsz 10 cell-width 60 ------------------ Database settings ~~~~~~~~~~~~~~~~~ .Database config settings in [setup] section of megatest.config [width="70%",cols="^,2m,2m,2m",frame="topbot",options="header"] |====================== |Var | Purpose | Valid values | Comments |delay-on-busy | Prevent concurrent access issues | yes\|no or not defined | Default=no, may help on some network file systems, may slow things down also. |faststart | All direct file access to sqlite db files | yes\|no or not defined | Default=yes, suggest no for central automated systems and yes for interactive use |homehost | Start servers on this host | <hostname> | Defaults to local host |hostname | Hostname to bind to | <hostname>\|- | On multi-homed hosts allows binding to specific hostname |lowport | Start searching for a port at this portnum| 32768 | |required | Server required | yes\|no or not defined | Default=no, force start of server always |server-query-threshold | Start server when queries take longer than this | number in milliseconds | Default=300 |timeout | http api timeout | number in hours | Default is 1 minute, do not change |
︙ | ︙ | |||
216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 | The runscript method is a brute force way to run scripts where the user is responsible for setting STATE and STATUS ------------------- runscript main.csh ------------------- Requirements section ~~~~~~~~~~~~~~~~~~~~ .Header ------------------- [requirements] ------------------- Wait on Other Tests | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > < > < > | 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 | The runscript method is a brute force way to run scripts where the user is responsible for setting STATE and STATUS ------------------- runscript main.csh ------------------- Iteration ~~~~~~~~~ .Sections for iteration ------------------ # full combinations [items] A x y B 1 2 # Yields: x/1 x/2 y/1 y/2 # tabled [itemstable] A x y B 1 2 # Yields x/1 y/2 ------------------ .Or use files ------------------ [itemopts] slash path/to/file/with/items # or space path/to/file/with/items ------------------ .File format for / delimited ------------------ key1/key2/key3 val1/val2/val2 ... ------------------ .File format for space delimited ------------------ key1 key2 key3 val1 val2 val2 ... ------------------ Requirements section ~~~~~~~~~~~~~~~~~~~~ .Header ------------------- [requirements] ------------------- Wait on Other Tests ~~~~~~~~~~~~~~~~~~~ ------------------- # A normal waiton waits for the prior tests to be COMPLETED # and PASS, CHECK or WAIVED waiton test1 test2 ------------------- Mode ~~~~ The default (i.e. if mode is not specified) is normal. All pre-dependent tests must be COMPLETED and PASS, CHECK or WAIVED before the test will start ------------------- [requirements] mode normal |
︙ | ︙ | |||
284 285 286 287 288 289 290 291 292 | Itemmap Handling ~~~~~~~~~~~~~~~~ For cases were the dependent test has a similar but not identical itempath to the downstream test an itemmap can allow for itemmatch mode ------------------- [requirements] | > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | < | | < < | < < < < < < | < | < < < | | | | > > | | | | | > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > < > < > < > < > > | > > > > > > > > > > > > > > > | < > < > < > | 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 | Itemmap Handling ~~~~~~~~~~~~~~~~ For cases were the dependent test has a similar but not identical itempath to the downstream test an itemmap can allow for itemmatch mode .example for removing part of itemmap for waiton test (eg: item +foo-x/bar+ depends on waiton's item +y/bar+) ------------------- [requirements] mode itemwait # itemmap <item pattern for this test> <item replacement pattern for waiton test> itemmap .*x/ y/ ------------------- .example for removing part of itemmap for waiton test (eg: item +foo/bar/baz+ in this test depends on waiton's item +baz+) ------------------- # ## pattern replacement notes # # ## Example # ## Remove everything up to the last / [requirements] mode itemwait # itemmap <item pattern for this test> <nothing here indicates removal> itemmap .*/ ------------------- .example replacing part of itemmap for (eg: item +foo/1234+ will imply waiton's item +bar/1234+) ------------------- # # ## Example # ## Replace foo/ with bar/ [requirements] mode itemwait # itemmap <item pattern for this test> <item replacement pattern for waiton test> itemmap foo/ bar/ ------------------- .example for backreference (eg: item +foo23/thud+ will imply waiton's item +num-23/bar/thud+ ------------------- # # ## Example # ## can use \{number} in replacement pattern to backreference a (capture) from matching pattern similar to sed or perl [requirements] mode itemwait # itemmap <item pattern for this test> <item replacement pattern for waiton test> itemmap foo(\d+)/ num-\1/bar/ ------------------- .example multiple itemmaps ------------------- # multi-line; matches are applied in the listed order # The following would map: # a123b321 to b321fooa123 then to 321fooa123p # [requirements] itemmap (a\d+)(b\d+) \2foo\1 b(.*) \1p ------------------- Complex mapping ~~~~~~~~~~~~~~~ Complex mappings can be handled with a separate [itemmap] section (instead if an itemmap line in the [requirements] section) Each line in an itemmap section starts with a waiton test name followed by an itemmap expression .eg: The following causes waiton test A item +bar/1234+ to run when our test's +foo/1234+ item is requested as well as causing waiton test B's +blah+ item to run when our test's +stuff/blah+ item is requested -------------- [itemmap] A foo/ bar/ B stuff/ -------------- Complex mapping example ~~~~~~~~~~~~~~~~~~~~~~~ // image::itemmap.png[] image::complex-itemmap.png[] We accomplish this by configuring the testconfigs of our tests C D and E as follows: .Testconfig for Test E has ---------------------- [requirements] waiton C itemmap (\d+)/res \1/bb ---------------------- .Testconfig for Test D has ---------------------- [requirements] waiton C itemmap (\d+)/res \1/aa ---------------------- .Testconfig for Test C has ---------------------- [requirements] waiton A B [itemmap] A (\d+)/aa aa/\1 B (\d+)/bb bb/\1 ---------------------- .Testconfigs for Test B and Test A have no waiton or itemmap configured ------------------- ------------------- .Walk through one item -- we want the following to happen for testpatt +D/1/res+ (see blue boxes in complex itemmaping figure above): . eg from command line +megatest -run -testpatt D/1/res -target mytarget -runname myrunname+ . Full list to be run is now: +D/1/res+ . Test D has a waiton - test C. Test D's itemmap rule +itemmap (\d+)/res \1/aa+ -> causes +C/1/aa+ to run before +D/1/res+ . Full list to be run is now: +D/1/res+, +C/1/aa+ . Test C was a waiton - test A. Test C's rule +A (\d+)/aa aa/\1+ -> causes +A/aa/1+ to run before +C/1/aa+ . Full list to be run is now: +D/1/res+, +C/1/aa+, +A/aa/1+ . Test A has no waitons. All waitons of all tests in full list have been processed. Full list is finalized. itemstable ~~~~~~~~~~ An alternative to defining items is the itemstable section. This lets you define the itempath in a table format rather than specifying components and relying on getting all permutations of those components. Dynamic Flow Dependency Tree ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .Autogeneration waiton list for dynamic flow dependency trees ------------------- [requirements] # With a toplevel test you may wish to generate your list # of tests to run dynamically # waiton #{shell get-valid-tests-to-run.sh} ------------------- Run time limit ~~~~~~~~~~~~~~ ----------------- [requirements] runtimelim 1h 2m 3s # this will automatically kill the test if it runs for more than 1h 2m and 3s ----------------- Skip ~~~~ A test with a skip section will conditional skip running. .Skip section example ----------------- [skip] prevrunning x # rundelay 30m 15s ----------------- Skip on Still-running Tests ~~~~~~~~~~~~~~~~~~~~~~~~~~~ ----------------- # NB// If the prevrunning line exists with *any* value the test will # automatically SKIP if the same-named test is currently RUNNING. The # "x" can be any string. Comment out the prevrunning line to turn off # skip. [skip] prevrunning x ----------------- Skip if a File Exists ~~~~~~~~~~~~~~~~~~~~~ ----------------- [skip] fileexists /path/to/a/file # skip if /path/to/a/file exists ----------------- Skip if a File Does not Exist ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ----------------- [skip] filenotexists /path/to/a/file # skip if /path/to/a/file does not exist ----------------- Skip if a script completes with 0 status ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ----------------- [skip] script /path/to/a/script # skip if /path/to/a/script completes with 0 status ----------------- Skip if test ran more recently than specified time ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .Skip if this test has been run in the past fifteen minutes and 15 seconds. ----------------- [skip] rundelay 15m 15s ----------------- Disks ~~~~~ A disks section in testconfig will override the disks section in megatest.config. This can be used to allocate disks on a per-test or per item basis. Controlled waiver propagation ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ If test is FAIL and previous test in run with same MT_TARGET is WAIVED then apply the following rules from the testconfig: If a waiver check is specified in the testconfig apply the check and if it passes then set this FAIL to WAIVED Waiver check has two parts, 1) a list of waiver, rulename, filepatterns and 2) the rulename script spec (note that "diff" and "logpro" are predefined) ----------------- |
︙ | ︙ | |||
459 460 461 462 463 464 465 466 467 468 469 470 471 472 | ;; a blank line indicates the end of the block of text (expect:required in "LogFileBody" > 0 "A file name that should never exist!" #/This is a awfully stupid file name that should never be found in the temp dir/) ----------------- To transfer the environment to the next step you can do the following: ---------------------------- $MT_MEGATEST -env2file .ezsteps/${stepname} ---------------------------- Triggers ~~~~~~~~ | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > | > | > > > > > > > > > > > > > > > > > > > > > > > > > | 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 | ;; a blank line indicates the end of the block of text (expect:required in "LogFileBody" > 0 "A file name that should never exist!" #/This is a awfully stupid file name that should never be found in the temp dir/) ----------------- To transfer the environment to the next step you can do the following: .Propagate environment to next step ---------------------------- $MT_MEGATEST -env2file .ezsteps/${stepname} ---------------------------- Scripts ~~~~~~~ .Specifying scripts inline (best used for only simple scripts) ---------------------------- [scripts] loaddb #!/bin/bash sqlite3 $1 <<EOF .mode tabs .import $2 data .q EOF ---------------------------- The above snippet results in the creation of an executable script called "loaddb" in the test directory. NOTE: every line in the script must be prefixed with the exact same number of spaces. Lines beginning with a # will not work as expected. Currently you cannot indent intermediate lines. .Full example with ezsteps, logpro rules, scripts etc. ----------------- # You can include a common file # [include #{getenv MT_RUN_AREA_HOME}/global-testconfig.inc] # Use "var" for a scratch pad # [var] dumpsql select * from data; sepstr ..................................... # NOT IMPLEMENTED YET! # [ezsteps-addendum] prescript something.sh postscript something2.sh # Add additional steps here. Format is "stepname script" [ezsteps] importdb loaddb prod.db prod.sql dumpprod dumpdata prod.db "#{get var dumpsql}" diff (echo "prod#{get var sepstr}test";diff --side-by-side \ dumpprod.log reference.log ;echo DIFFDONE) [scripts] loaddb #!/bin/bash sqlite3 $1 <<EOF .mode tabs .import $2 data .q EOF dumpdata #!/bin/bash sqlite3 $1 <<EOF .separator , $2 .q EOF # Test requirements are specified here [requirements] waiton setup priority 0 # Iteration for your test is controlled by the items section # The complicated if is needed to allow processing of the config for the dashboard when there are no actual runs. [items] THINGNAME [system generatethings.sh | sort -u] # Logpro rules for each step can be captured here in the testconfig # note: The ;; after the stepname and the leading whitespace are required # [logpro] inputdb ;; (expect:ignore in "LogFileBody" < 99 "Ignore error in comments" #/^\/\/.*error/) (expect:warning in "LogFileBody" = 0 "Any warning" #/warn/) (expect:required in "LogFileBody" > 0 "Some data found" #/^[a-z]{3,4}[0-9]+_r.*/) diff ;; (expect:ignore in "LogFileBody" < 99 "Ignore error in comments" #/^\/\/.*error/) (expect:warning in "LogFileBody" = 0 "Any warning" #/warn/) (expect:error in "LogFileBody" = 0 "< or > indicate missing entry" (list #/(<|>)/ #/error/i)) (expect:error in "LogFileBody" = 0 "Difference in data" (list #/\s+\|\s+/ #/error/i)) (expect:required in "LogFileBody" > 0 "DIFFDONE Marker found" #/DIFFDONE/) (expect:required in "LogFileBody" > 0 "Some things found" #/^[a-z]{3,4}[0-9]+_r.*/) # NOT IMPLEMENTED YET! # ## Also: enhance logpro to take list of command files: file1,file2... [waivers] createprod{target=%78/%/%/%} ;; (disable:required "DIFFDONE Marker found") (disable:error "Some error") (expect:waive in "LogFileBody" < 99 "Waive if failed due to version" #/\w+3\.6.*/) # test_meta is a section for storing additional data on your test [test_meta] author matt owner matt description Compare things tags tagone,tagtwo reviewed never ----------------- Triggers ~~~~~~~~ In your testconfig or megatest.config triggers can be specified .Triggers spec ----------------- [triggers] # Call script running.sh when test goes to state=RUNNING, status=PASS RUNNING/PASS running.sh # Call script running.sh any time state goes to RUNNING RUNNING/ running.sh # Call script onpass.sh any time status goes to PASS PASS/ onpass.sh ----------------- Scripts called will have; test-id test-rundir trigger test-name item-path state status event-time, added to the commandline. HINT To start an xterm (useful for debugging), use a command line like the following: .Start an xterm using a trigger for test completed. ----------------- [triggers] COMPLETED/ xterm -e bash -s -- ----------------- NOTE: There is a trailing space after the double-dash There are a number of environment variables available to the trigger script but since triggers can be called in various contexts not all variables are available at all times. The trigger script should check for the variable and fail gracefully if it doesn't exist. // ,cols="^,2m" .Environment variables visible to the trigger script [width="90%",frame="topbot",options="header"] |====================== | Variable | Purpose | MT_TEST_RUN_DIR | The directory where Megatest ran this test | MT_CMDINFO | Encoded command data for the test | MT_DEBUG_MODE | Used to pass the debug mode to nested calls to Megatest | MT_RUN_AREA_HOME | Megatest home area | MT_TESTSUITENAME | The name of this testsuite or area | MT_TEST_NAME | The name of this test | MT_ITEM_INFO | The variable and values for the test item | MT_MEGATEST | Which Megatest binary is being used by this area | MT_TARGET | The target variable values, separated by '/' | MT_LINKTREE | The base of the link tree where all run tests can be found | MT_ITEMPATH | The values of the item path variables, separated by '/' | MT_RUNNAME | The name of the run |====================== Override the Toplevel HTML File ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Megatest generates a simple html file summary for top level tests of iterated tests. The generation can be overridden. NOTE: the output of |
︙ | ︙ | |||
530 531 532 533 534 535 536 | # Archives will be organised under these paths like this: # <testsuite>/<creationdate> # Within the archive the data is structured like this: # <target>/<runname>/<test>/ archive0 /mfs/myarchive-data/adisk1 -------------- | | | | 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 | # Archives will be organised under these paths like this: # <testsuite>/<creationdate> # Within the archive the data is structured like this: # <target>/<runname>/<test>/ archive0 /mfs/myarchive-data/adisk1 -------------- Environment Variables --------------------- It is often necessary to capture and or manipulate environment variables. Megatest has some facilities built in to help. Capture variables ~~~~~~~~~~~~~~~~~ |
︙ | ︙ | |||
554 555 556 557 558 559 560 | megatest -envcap after startup.db # write the diff from before to after megatest -envdelta before-after -dumpmode bash ------------------------------ Dump modes include bash, csh and config. You can include config data | | > > < < > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > < | 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 | megatest -envcap after startup.db # write the diff from before to after megatest -envdelta before-after -dumpmode bash ------------------------------ Dump modes include bash, csh and config. You can include config data into megatest.config, runconfigs.config and testconfig files. This is useful for capturing a complex environment in a special-purpose test and then utilizing that environment in downstream tests. .Example of generating and using config data ------------------------------ megatest -envcap original # do some stuff here megatest -envcap munged megatest -envdelta original-munged -dumpmode ini -o modified.config ------------------------------ Then in runconfigs.config .Example of using modified.config in a testconfig ------------------------------ [pre-launch-env-vars] [include modified.config] ------------------------------ Managing Old Runs ----------------- It is often desired to keep some older runs around but this must be balanced with the costs of disk space. . Use -remove-keep . Use -archive (can also be done from the -remove-keep interface) . use -remove-runs with -keep-records .For each target, remove all runs but the most recent 3 if they are over 1 week old --------------------- # use -precmd 'sleep 5;nbfake' to limit overloading the host computer but to allow the removes to run in parallel. megatest -actions print,remove-runs -remove-keep 3 -target %/%/%/% -runname % -age 1w -precmd 'sleep 5;nbfake'" --------------------- Nested Runs ----------- A Megatest test can run a full Megatest run in either the same Megatest area or in another area. This is a powerful way of chaining complex suites of tests and or actions. If you are not using the current area you can use ezsteps to retrieve and setup the sub-Megatest run area. In the testconfig: --------------- [subrun] # Required: wait for the run or just launch it # if no then the run will be an automatic PASS irrespective of the actual result run-wait yes|no # Optional: where to execute the run. Default is the current runarea run-area /some/path/to/megatest/area # Optional: method to use to determine pass/fail status of the run # auto (default) - roll up the net state/status of the sub-run # logpro - use the provided logpro rules, happens automatically if there is a logpro section # passfail auto|logpro # Example of logpro: passfail logpro # Optional: logpro ;; if this section exists then logpro is used to determine pass/fail (expect:required in "LogFileBody" >= 1 "At least one pass" #/PASS/) (expect:error in "LogFileBody" = 0 "No FAILs allowed" #/FAIL/) # Optional: target translator, default is to use the parent target target #{shell somescript.sh} # Optional: runname translator/generator, default is to use the parent runname run-name #{somescript.sh} # Optional: testpatt spec, default is to first look for TESTPATT spec from runconfigs unless there is a contour spec test-patt %/item1,test2 # Optional: contour spec, use the named contour from the megatest.config contour spec contour contourname ### NOTE: Not implemented yet! Let us know if you need this feature. # Optional: mode-patt, use this spec for testpatt from runconfigs mode-patt TESTPATT # Optional: tag-expr, use this tag-expr to select tests tag-expr quick # Optional: (not yet implemented, remove-runs is always propagated at this time), propagate these actions from the parent # test # Note// default is % for all propagate remove-runs archive ... --------------- Programming API --------------- These routines can be called from the megatest repl. .API Keys Related Calls [width="70%",cols="^,2m,2m,2m",frame="topbot",options="header,footer"] |====================== |API Call | Purpose comments | Returns | Comments |(rmt:get-keys run-id) | | ( key1 key2 ... ) | | (rmt:get-key-val-pairs run-id) | | #t=success/#f=fail | Works only if the server is still reachable |====================== :numbered!: |
Modified docs/manual/server.dot from [5b6f6b599f] to [3e029f5fe5].
1 2 3 4 5 6 7 | digraph G { subgraph cluster_1 { node [style=filled,shape=box]; check_available_queue -> remove_entries_over_10s_old; remove_entries_over_10s_old -> set_available [label="num_avail < 3"]; | > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | // Copyright 2006-2017, Matthew Welland. // // This file is part of Megatest. // // Megatest is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Megatest is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Megatest. If not, see <http://www.gnu.org/licenses/>. digraph G { subgraph cluster_1 { node [style=filled,shape=box]; check_available_queue -> remove_entries_over_10s_old; remove_entries_over_10s_old -> set_available [label="num_avail < 3"]; |
︙ | ︙ |
Added docs/manual/stand-alone-megatest-area.svg version [0556f7fe69].
cannot compute difference between binary files
Added docs/manual/study_plan.txt version [775824943a].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 | // This file is part of Megatest. // // Megatest is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Megatest is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Megatest. If not, see <http://www.gnu.org/licenses/>. // // Copyright 2006-2012, Matthew Welland. Study Plan ---------- Megatest is an extensive program with a lot to learn. Following are some paths through the material to smooth the learning path. Basic Concepts (suggest you pick these up on the way) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * Components of automation; run, test, iteration * Selectors; target, runname, and testpatt Running Testsuites or Automation ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * Using the dashboard gui (recommended) ** Using the "Runs" panel. ** Using the "Run Control" panel. ** Using a test control panel ** The Right Mouse Button menu ** Debug features *** xterm **** pstree **** log files; mt_copy.log, mt_launch.log **** variables; megatest.csh, megatest.sh **** testconfig dump, *testconfig *** State/status buttons *** Run, Clean, KillReq *** ReRunClean * Using the command line ** Getting help; megatest -h, megatest -manual ** Starting runs; megatest -run *** Selection controls; -target, -runname and -testpatt Writing Tests and Flows ~~~~~~~~~~~~~~~~~~~~~~~ * environment variables (table 5) * tests/_testname_/testconfig link:megatest_manual.html#_the_testconfig_file[testconfig details] ** ezsteps and logpro section ** iteration (one test applied to many inputs), items, itemstable link:megatest_manual.html#_iteration[test iteration] ** dependencies, waiton, itemmatch, itemwait link:megatest_manual.html#_requirements_section[test requirements] ** miscellaneous; mode toplevel, runtimelim, skip on file, no file, script or on running, waiver propagation * megatest areas ** megatest.config ** runconfigs.config ** config language features; include, shell, system, scheme, rp|realpath, getenv, get, rget, scriptinc link:megatest.html#_config_file_helpers[config file helpers] Advanced Topics ~~~~~~~~~~~~~~~ * Removing and keeping runs selectively link:megatest_manual.html#_managing_old_runs[managing runs] * Subruns link:megatest_manual.html#_nested_runs[nested runs] * Config file features link:megatest_manual.html#_config_file_helpers[config file features] * HTML output with -generate-html * Triggers, post run, state/status * MTLOWESTLOAD * flexilauncher * env delta and testconfig * capturing test data, extracting values from logpro and using them for pass/fail * mtutil, postgres connection, packets for cross-site/cross-user control (e.g. mcrun). Maintenance and Troubleshooting ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * cleanup-db, database structure of Megatest 1.6x * archiving * homehost management * show-runconfig * show-config * show with -debug 0,9 * load management |
Modified docs/manual/thoughts.fig from [4fef1b0e2f] to [55404efc82].
|
| | > > > > > > > > > > > > > > > > | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 | #FIG 3.2 Produced by xfig version 3.2.5-alpha5 Landscape Center Inches Letter 100.00 Single -2 # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. 1200 2 2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5 1800 3000 10800 3000 10800 4800 1800 4800 1800 3000 2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5 14475 975 15975 975 15975 1500 14475 1500 14475 975 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2 15075 2550 14100 3675 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2 14175 4275 15150 5475 4 0 0 50 -1 0 24 0.0000 4 270 1050 3150 1800 -runall\001 4 0 0 50 -1 0 24 0.0000 4 375 5040 2175 5190 (expect:ignore Test: abc FAIL/)\001 4 0 0 50 -1 0 24 0.0000 4 375 1200 2400 6225 [group]\001 4 0 0 50 -1 0 24 0.0000 4 375 2610 2625 8085 megatest -runall\001 4 0 0 50 -1 0 24 0.0000 4 405 1275 5250 8025 $(TAG)\001 4 0 0 50 -1 0 24 0.0000 4 270 3255 4650 8700 make TARGET=foo\001 4 0 0 50 -1 0 24 0.0000 4 375 5160 2625 6825 TAG1 envsetup test1 test2 testx\001 4 0 0 50 -1 0 24 0.0000 4 375 1575 7875 1425 testconfig\001 4 0 0 50 -1 0 24 0.0000 4 375 2400 7875 1845 [requirements]\001 4 0 0 50 -1 0 24 0.0000 4 270 2910 3150 2220 -runtests standard\001 4 0 0 50 -1 0 24 0.0000 4 345 1440 14625 2325 envsetup\001 4 0 0 50 -1 0 24 0.0000 4 270 780 13650 4125 test1\001 4 0 0 50 -1 0 24 0.0000 4 270 1545 14550 5850 testsuite2\001 4 0 0 50 -1 0 24 0.0000 4 270 855 10200 6300 waito\001 4 0 0 50 -1 0 24 0.0000 4 375 4290 7875 2265 testmode normal | toplevel \001 4 0 0 50 -1 0 24 0.0000 4 375 2820 7875 2685 waitoncompleted \001 4 0 0 50 -1 0 24 0.0000 4 420 9900 2175 4350 megatest -list-runs $MT_RUNNAME -target $MT_TARGET\001 4 0 0 50 -1 0 24 0.0000 4 375 2010 10050 7275 test_toplevel\001 4 0 0 50 -1 0 24 0.0000 4 375 2400 10050 7695 [requirements]\001 4 0 0 50 -1 0 24 0.0000 4 375 2805 10050 8115 testmode toplevel\001 4 0 0 50 -1 0 24 0.0000 4 375 2805 10050 8535 waiton testx testy\001 4 0 0 50 -1 0 24 0.0000 4 240 885 10050 9375 testx:\001 4 0 0 50 -1 0 24 0.0000 4 345 1155 10050 9795 [items]\001 4 0 0 50 -1 0 24 0.0000 4 345 855 10050 11055 testy:\001 4 0 0 50 -1 0 24 0.0000 4 345 1155 10050 11475 [items]\001 4 0 0 50 -1 0 24 0.0000 4 375 2400 10800 13170 [requirements]\001 4 0 0 50 -1 0 24 0.0000 4 345 855 10050 12735 testy:\001 4 0 0 50 -1 0 24 0.0000 4 375 3615 10800 13590 waitoncompleted testx\001 4 0 0 50 -1 0 24 0.0000 4 270 2835 10800 14010 waitonitems testx\001 4 0 0 50 -1 0 24 0.0000 4 270 1680 10050 10215 X A B D E\001 4 0 0 50 -1 0 24 0.0000 4 270 1335 10050 11895 Y A B C\001 4 0 0 50 -1 0 24 0.0000 4 375 7170 2100 3450 waiton #{shell get-valid-tests-for-dotproc.sh}\001 |
Modified docs/manual/writing_tests.txt from [c1e61ad2b4] to [e1b4c175dc].
1 2 3 4 5 6 7 | Writing Tests ------------- Creating a new Test ~~~~~~~~~~~~~~~~~~~ | > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | // Copyright 2006-2017, Matthew Welland. // // This file is part of Megatest. // // Megatest is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Megatest is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Megatest. If not, see <http://www.gnu.org/licenses/>. Writing Tests ------------- Creating a new Test ~~~~~~~~~~~~~~~~~~~ |
︙ | ︙ |
Added docs/megatest-desktop.png version [6aea694236].
cannot compute difference between binary files
Modified docs/megatest-state-status.dot from [45d0ee8608] to [dc07177953].
1 2 3 4 5 6 7 | digraph megatest_state_status { ranksep=0.05 // rankdir=LR node [shape=box,style=filled]; // subgraph cluster_notstarted { | > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | // Copyright 2006-2017, Matthew Welland. // // This file is part of Megatest. // // Megatest is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Megatest is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Megatest. If not, see <http://www.gnu.org/licenses/>. // digraph megatest_state_status { ranksep=0.05 // rankdir=LR node [shape=box,style=filled]; // subgraph cluster_notstarted { |
︙ | ︙ | |||
29 30 31 32 33 34 35 | "RUNNING" [ shape="record"; label="{RUNNING|{n/a|<here> PASS |<here> FAIL}}"; ] "COMPLETED" [ shape="record"; | | | 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 | "RUNNING" [ shape="record"; label="{RUNNING|{n/a|<here> PASS |<here> FAIL}}"; ] "COMPLETED" [ shape="record"; label = "{COMPLETED|{PASS | SKIP | WAIVED | FAIL | CHECK| ABORT}}"; ] "RUNNING" -> "COMPLETED"; "RUNNING" -> "INCOMPLETE" [label="test dead for > 24hrs"]; "LAUNCHED n/a" -> "REMOTEHOSTSTART n/a" -> "RUNNING"; } |
Modified docs/megatest-training.odp from [ba7ab2ab9e] to [f923ec026f].
cannot compute difference between binary files
Deleted docs/megatest.lyx version [4ed5338fae].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Modified docs/mt/megatest.config from [da39a3ee5e] to [cb4ec4abf7].
> > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. |
Modified docs/mt/runconfigs.config from [da39a3ee5e] to [cb4ec4abf7].
> > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. |
Modified docs/mt/tests/mytest/main.sh from [da39a3ee5e] to [cb4ec4abf7].
> > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. |
Modified docs/mt/tests/mytest/testconfig from [da39a3ee5e] to [cb4ec4abf7].
> > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. |
Added docs/pkts.dot version [fcd0b8523f].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 | // Copyright 2006-2017, Matthew Welland. // // This file is part of Megatest. // // Megatest is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Megatest is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Megatest. If not, see <http://www.gnu.org/licenses/>. // digraph megatest_pkts { ranksep=0.05 // rankdir=LR node [shape=box,style=filled]; "SENSORS" [ label = "{ Sensor Processing | { file | git | fossil | script }}" shape = "record"; ]; "RUNS" [ label = "{ Runs Processing | { launch | clean | re-run | archive } | { dispatcher }}"; shape = "record"; ]; "WORK" [ label = "{ Work Items | { start task | task competed }}"; shape = "record"; ]; "USERREQ" [ label = "{ User Requests (Unix and Web) | { launch | clean | re-run | archive }}"; shape = "record"; ]; "MTAREA1" [ label = "{ Megatest Area 1 | { parallel job\nmanagement | test\nmanagement | data\nrollup }}"; shape = "record"; ]; "MTAREA2" [ label = "{ Megatest Area 2 | { parallel job\nmanagement | test\nmanagement | data\nrollup }}"; shape = "record"; ]; "MTAREA3" [ label = "More Megatest Areas ... "; shape = "record"; ]; "PGDB" [ label = "postgres database"; shape = "cylinder"; ]; "WEBAPP" [ label = "{ Web View | { Runs | Contours | Control | Time View }}"; shape = "record"; ]; // "WEBCTRL" [ label = "{ Web View \n(control) }"; // shape = "record"; ]; "SENSORS" -> "SPKTS"; "RUNS" -> "run pkts"; "run pkts" -> "RUNS"; "WORK" -> "work pkts"; "work pkts" -> "RUNS"; "USERREQ" -> "user request pkts"; "SPKTS" -> "RUNS"; "user request pkts" -> "RUNS"; "RUNS" -> "MTAREA1" -> "PGDB"; "RUNS" -> "MTAREA2" -> "PGDB"; "RUNS" -> "MTAREA3" -> "PGDB"; "PGDB" -> "WEBAPP"; // "WEBCTRL" -> "run pkts"; subgraph cluster_pkts { label="Packets"; "SPKTS" [ label = "Sensor Packets" ]; "run pkts"; "work pkts"; "user request pkts"; } } |
Added docs/pkts.pdf version [d5020c63eb].
cannot compute difference between binary files
Deleted docs/plan.txt version [92bba79ce7].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Added docs/ulex-transition.fig version [a312994a51].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | #FIG 3.2 Produced by xfig version 3.2.5-alpha5 Landscape Center Inches Letter 100.00 Single -2 1200 2 5 1 0 1 0 7 50 -1 -1 0.000 0 1 1 0 3450.000 7793.750 2475 8625 3450 9075 4425 8625 0 0 1.00 60.00 120.00 5 1 0 1 0 7 50 -1 -1 0.000 0 0 1 0 3450.000 7762.500 4725 8625 3375 9300 2175 8625 0 0 1.00 60.00 120.00 2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5 1200 1425 3675 1425 3675 4800 1200 4800 1200 1425 2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5 3825 1425 7425 1425 7425 4800 3825 4800 3825 1425 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2 2325 4950 2325 7200 2 4 0 1 0 7 50 -1 -1 0.000 0 0 7 0 0 5 3150 8550 3150 7200 1650 7200 1650 8550 3150 8550 2 4 0 1 0 7 50 -1 -1 0.000 0 0 7 0 0 5 5700 8550 5700 7200 3975 7200 3975 8550 5700 8550 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2 0 0 1.00 60.00 120.00 4800 4875 4800 7125 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2 0 0 1.00 60.00 120.00 4800 4875 2700 7125 4 0 0 50 -1 0 12 0.0000 4 150 1185 1350 1725 runs and tests\001 4 0 0 50 -1 0 12 0.0000 4 195 1065 1725 7650 megatest.db\001 4 0 0 50 -1 0 12 0.0000 4 195 1140 4950 5775 config setting\001 4 0 0 50 -1 0 12 0.0000 4 150 375 4125 7575 1.db\001 4 0 0 50 -1 0 12 0.0000 4 150 375 4125 7830 2.db\001 4 0 0 50 -1 0 12 0.0000 4 15 240 4125 8085 ....\001 4 0 0 50 -1 0 12 0.0000 4 150 360 4875 5325 ulex\001 4 0 0 50 -1 0 12 0.0000 4 150 690 1125 825 v1.6535\001 4 0 0 50 -1 0 12 0.0000 4 195 2190 2400 9600 import/export steps script\001 4 0 0 50 -1 0 12 0.0000 4 195 1590 3900 1725 steps and test data\001 |
Deleted ducttape/Makefile version [7c53ca1a83].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted ducttape/README version [bc9be285fc].
|
| < < < < < < < < |
Deleted ducttape/ducttape-lib.meta version [a22283c9d8].
|
| < < < < < < < < < < < < < |
Deleted ducttape/ducttape-lib.scm version [789effec13].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted ducttape/ducttape-lib.setup version [f078cc60c2].
|
| < |
Deleted ducttape/mimetypes.scm version [391fe0b393].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted ducttape/sample_ducttape.scm version [d6ebb1f644].
|
| < < < < |
Deleted ducttape/test_ducttape.scm version [f1892fd163].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted ducttape/test_example.scm version [74b706bd1d].
|
| < < < |
Deleted ducttape/useargs-example.scm version [c73af521bf].
|
| < < < < < < < < < < < < < < < < < < < |
Deleted ducttape/workweekdate.scm version [075bec1c4d].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Modified env.scm from [d8ef48f13e] to [028e47144f].
1 2 3 | ;;====================================================================== ;; Copyright 2006-2013, Matthew Welland. ;; | | | > > > > > | | > > > > | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | ;;====================================================================== ;; Copyright 2006-2013, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. ;;====================================================================== (declare (unit env)) (use sql-de-lite) ;; srfi-1 posix regex regex-case srfi-69 srfi-18 call-with-environment-variables) (define (env:open-db fname) (let* ((db-exists (common:file-exists? fname)) (db (open-database fname))) (if (not db-exists) (begin (exec (sql db "CREATE TABLE envvars ( id INTEGER PRIMARY KEY, context TEXT NOT NULL, var TEXT NOT NULL, |
︙ | ︙ | |||
57 58 59 60 61 62 63 | (lambda (context) (query (for-each-row (lambda (row) (let ((var (car row)) (val (cadr row))) (hash-table-set! result var | | | | | 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 | (lambda (context) (query (for-each-row (lambda (row) (let ((var (car row)) (val (cadr row))) (hash-table-set! result var (if (and (hash-table-ref/default result var #f) (assoc var paths)) ;; this var is a path and there is a previous path (let ((sep (cadr (assoc var paths)))) (env:merge-path-envvar sep (hash-table-ref result var) val)) val))))) (sql db "SELECT var,val FROM envvars WHERE context=?") context)) contexts) result)) ;; get list of removed variables between two contexts ;; |
︙ | ︙ | |||
106 107 108 109 110 111 112 | (query (for-each-row (lambda (row) (let ((var (car row)) (val (cadr row))) (hash-table-set! result var val)))) (sql db "SELECT var,val FROM envvars AS a WHERE context=? AND val != (SELECT val FROM envvars WHERE var=a.var AND context=?)") | | | 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 | (query (for-each-row (lambda (row) (let ((var (car row)) (val (cadr row))) (hash-table-set! result var val)))) (sql db "SELECT var,val FROM envvars AS a WHERE context=? AND val != (SELECT val FROM envvars WHERE var=a.var AND context=?)") contextb contexta) result)) ;; (define (env:blind-merge l1 l2) (if (null? l1) l2 (if (null? l2) l1 (cons (car l1) (cons (car l2) (env:blind-merge (cdr l1) (cdr l2))))))) |
︙ | ︙ |
Added example/README version [4c8f7424f4].
> > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | ;;====================================================================== ;; Copyright 2006-2012, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. You can get the example from the Megatest tests fossil at: http://www.kiatoa.com/fossils/megatest_qa |
Deleted example/cfg/machines.dat version [ef87a55f85].
|
| < < < < < < < < < < < < < < < < |
Deleted example/cfg/sheet-names.cfg version [02dee9de7f].
|
| < |
Deleted example/cfg/sxml/_sheets.sxml version [84106e33a9].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted example/cfg/sxml/_workbook.sxml version [96ffb7f9d5].
|
| < |
Deleted example/cfg/sxml/machines.sxml version [59def89588].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted example/megatest.config version [ce9f9de360].
|
| < < < < < < < < < < < < < < < < < < < < < < |
Deleted example/runconfigs.config version [52dcfef0ef].
|
| < < < < < < < < < |
Deleted example/tests/diskspace/diskspace.logpro version [49d20f5850].
|
| < < < < < < |
Deleted example/tests/diskspace/diskspace.sh version [ce15f82073].
|
| < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted example/tests/diskspace/hostname.logpro version [d00e9233db].
|
| < < < < |
Deleted example/tests/diskspace/testconfig version [e3bae930a1].
|
| < < < < < < < < < < < < |
Deleted example/tests/ping/ping.logpro version [e41ac50178].
|
| < < < |
Deleted example/tests/ping/testconfig version [bcb5cfda73].
|
| < < < < < < < |
Modified ezsteps.scm from [0cbe12a80c] to [b166d59095].
1 2 3 | ;; Copyright 2006-2012, Matthew Welland. ;; | | | > > > > > | | > | > > > | < > > > > > > > | > > | | | > > > > | | > | > > | | | > | | | | | < | > | < | | > | > > > | | > > | | > > > | | < < < < < < | | > | | | | | | | | | | | | | | | | | > | | > | | > | | > | < < < | < | | < < | | | < < | < < < < < < < | | | | > > | < | > > > | | < < < < < < < < | | | | | | | | | > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 | ;; Copyright 2006-2012, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. ;; ;; strftime('%m/%d/%Y %H:%M:%S','now','localtime') (use srfi-1 posix regex srfi-69 directory-utils) (declare (unit ezsteps)) (declare (uses db)) (declare (uses common)) (declare (uses items)) (declare (uses runconfig)) ;; (declare (uses sdb)) ;; (declare (uses filedb)) (include "common_records.scm") (include "key_records.scm") (include "db_records.scm") (include "run_records.scm") ;;(rmt:get-test-info-by-id run-id test-id) -> testdat (define (ezsteps:run-from testdat start-step-name run-one) ;;# TODO - recapture item variables, debug repeated step eval; regen logpro from test (let* ((do-update-test-state-status #f) (test-run-dir ;; (filedb:get-path *fdb* (db:test-get-rundir testdat)) ;; ) (testconfig (read-config (conc test-run-dir "/testconfig") #f #t environ-patt: "pre-launch-env-vars")) (ezstepslst (hash-table-ref/default testconfig "ezsteps" '())) (run-mutex (make-mutex)) (rollup-status 0) (rollup-status-string #f) (rollup-status-sym #f) (exit-info (vector #t #t #t)) (test-id (db:test-get-id testdat)) (run-id (db:test-get-run_id testdat)) (test-name (db:test-get-testname testdat)) (orig-test-state (db:test-get-state testdat)) (orig-test-status (db:test-get-status testdat)) (kill-job #f)) ;; for future use (on re-factoring with launch.scm code ;; keep trying till NFS deigns to populate test run dir on this host (let loop ((count 5)) (if (not (common:file-exists? test-run-dir)) ;;(push-directory test-run-dir) (if (> count 0) (begin (debug:print 0 *default-log-port* "WARNING: ezsteps attempting to run but test run directory " test-run-dir " is not there. Waiting and trying again " count " more times") (sleep 3) (loop (- count 1)))))) (debug:print-info 0 *default-log-port* "Running in directory " test-run-dir) (if (not (common:file-exists? ".ezsteps"))(create-directory ".ezsteps")) ;; if ezsteps was defined then we are sure to have at least one step but check anyway (if (not (> (length ezstepslst) 0)) (message-window "ERROR: You can only re-run steps defined via ezsteps") (begin (let loop ((ezstep (car ezstepslst)) (tal (cdr ezstepslst)) (status-sym-so-far 'pass) ;;(runflag #f) (saw-start-step-name #f)) ;; flag used to skip steps when not starting at the beginning (if (vector-ref exit-info 1) (let* ((stepname (car ezstep)) ;; do stuff to run the step (logpro-used (common:file-exists? (conc test-run-dir "/" stepname ".logpro"))) (stepinfo (cadr ezstep)) (stepparts (string-match (regexp "^(\\{([^\\}]*)\\}\\s*|)(.*)$") stepinfo)) (stepparms (list-ref stepparts 2)) ;; for future use, {VAR=1,2,3}, run step for each (stepcmd (list-ref stepparts 3)) (script (conc "mt_ezstep '"test-run-dir"' '"stepname"' '"stepcmd"'")) ;; call the command using mt_ezstep (saw-start-step-name-next (or saw-start-step-name (equal? stepname start-step-name))) (proceed-with-this-step (or (not start-step-name) (equal? stepname start-step-name) (and saw-start-step-name (not run-one)) saw-start-step-name-next (and start-step-name (equal? stepname start-step-name)))) ) (set! do-update-test-state-status (and proceed-with-this-step (null? tal))) ;;(BB> "stepname="stepname" proceed-with-this-step="proceed-with-this-step " do-update-test-state-status="do-update-test-state-status " orig-test-state="orig-test-state" orig-test-status="orig-test-status) (cond ((and (not proceed-with-this-step) (null? tal)) 'done) ((not proceed-with-this-step) (loop (car tal) (cdr tal) status-sym-so-far saw-start-step-name-next)) (else (debug:print 4 *default-log-port* "ezsteps:\n stepname: " stepname " stepinfo: " stepinfo " stepparts: " stepparts " stepparms: " stepparms " stepcmd: " stepcmd) (debug:print 4 *default-log-port* "script: " script) (rmt:teststep-set-status! run-id test-id stepname "start" "-" #f #f) ;; now launch the script (let ((pid (process-run script))) (let processloop ((i 0)) (let-values (((pid-val exit-status exit-code)(process-wait pid #t))) (mutex-lock! run-mutex) (vector-set! exit-info 0 pid) (vector-set! exit-info 1 exit-status) (vector-set! exit-info 2 exit-code) (mutex-unlock! run-mutex) (if (eq? pid-val 0) (begin (thread-sleep! 1) (processloop (+ i 1)))) )) (let ((exinfo (vector-ref exit-info 2)) (logfna (if logpro-used (conc stepname ".html") ""))) (rmt:teststep-set-status! run-id test-id stepname "end" exinfo #f logfna)) (if logpro-used (rmt:test-set-log! run-id test-id (conc stepname ".html"))) ;; set the test final status (let* ((this-step-status (cond (logpro-used (common:logpro-exit-code->status-sym (vector-ref exit-info 2))) ((eq? (vector-ref exit-info 2) 0) 'pass) (else 'fail))) (overall-status-sym (common:worse-status-sym this-step-status status-sym-so-far)) (overall-status-string (status-sym->string overall-status-sym))) (debug:print 4 *default-log-port* "Exit value received: " (vector-ref exit-info 2) " logpro-used: " logpro-used " this-step-status: " this-step-status " overall-status: " overall-status-sym) ;;" next-status: " next-status " rollup-status: " rollup-status) (set! rollup-status-string overall-status-string) (set! rollup-status-sym overall-status-sym) (tests:test-set-status! run-id test-id "RUNNING" overall-status-string #f #f))) (if (and (not run-one) (common:steps-can-proceed-given-status-sym rollup-status-sym) (not (null? tal))) (loop (car tal) (cdr tal) rollup-status-sym saw-start-step-name-next))))) (debug:print 4 *default-log-port* "WARNING: a prior step failed, stopping at " ezstep))) ;; Once done with step/steps update the test record ;; (let* ((item-path (db:test-get-item-path testdat)) ;; (item-list->path itemdat)) (testinfo (rmt:get-testinfo-state-status run-id test-id))) ;; refresh the testdat, call it iteminfo in case need prev/curr ;; Am I completed? (if (equal? (db:test-get-state testinfo) "RUNNING") ;; (not (equal? (db:test-get-state testinfo) "COMPLETED")) (let ((new-state (if kill-job "KILLED" "COMPLETED") ;; (if (eq? (vector-ref exit-info 2) 0) ;; exited with "good" status ;; "COMPLETED" ;; (db:test-get-state testinfo))) ;; else preseve the state as set within the test ) (new-status rollup-status-string) ) ;; (db:test-get-status testinfo))) (debug:print-info 2 *default-log-port* "Test NOT logged as COMPLETED, (state=" (db:test-get-state testinfo) "), updating result, rollup-status is " rollup-status) (tests:test-set-status! run-id test-id (if do-update-test-state-status new-state orig-test-state) (if do-update-test-state-status new-status orig-test-status) (args:get-arg "-m") #f) ;; need to update the top test record if PASS or FAIL and this is a subtest (if (and (not (equal? item-path "")) do-update-test-state-status) (rmt:set-state-status-and-roll-up-items run-id test-name item-path new-state new-status #f)))) ;; for automated creation of the rollup html file this is a good place... (if (not (equal? item-path "")) (tests:summarize-items run-id test-id test-name #f)) ;; don't force - just update if no ))) ;;(pop-directory) rollup-status-string)) (define (ezsteps:spawn-run-from testdat start-step-name run-one) (thread-start! (make-thread (lambda () (ezsteps:run-from testdat start-step-name run-one)) (conc "ezstep run single step " start-step-name " run-one="run-one))) ) |
Modified fdb_records.scm from [bbb0371221] to [f1c8030bb0].
1 2 3 4 5 6 7 | ;; Single record for managing a filedb ;; make-vector-record "Filedb record" filedb fdb db dbpath pathcache idcache partcache ;; Filedb record (define (make-filedb:fdb)(make-vector 5)) (define-inline (filedb:fdb-get-db vec) (vector-ref vec 0)) (define-inline (filedb:fdb-get-dbpath vec) (vector-ref vec 1)) (define-inline (filedb:fdb-get-pathcache vec) (vector-ref vec 2)) | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | ;; Copyright 2006-2017, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. ;; Single record for managing a filedb ;; make-vector-record "Filedb record" filedb fdb db dbpath pathcache idcache partcache ;; Filedb record (define (make-filedb:fdb)(make-vector 5)) (define-inline (filedb:fdb-get-db vec) (vector-ref vec 0)) (define-inline (filedb:fdb-get-dbpath vec) (vector-ref vec 1)) (define-inline (filedb:fdb-get-pathcache vec) (vector-ref vec 2)) |
︙ | ︙ |
Modified filedb.scm from [91e90bcdc7] to [f18fb77b48].
1 2 | ;; Copyright 2006-2011, Matthew Welland. ;; | | | > > > > | > | | > | > > > | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | ;; Copyright 2006-2011, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. ;; ;; (require-extension synch sqlite3 posix srfi-13 srfi-1 utils regex) (use sqlite3 srfi-1 posix regex srfi-69 srfi-13 posix-extras) (import (prefix sqlite3 sqlite3:)) (declare (unit filedb)) (include "fdb_records.scm") ;; (include "settings.scm") (define (filedb:open-db dbpath) (let* ((fdb (make-filedb:fdb)) (dbexists (common:file-exists? dbpath)) (db (sqlite3:open-database dbpath))) (filedb:fdb-set-db! fdb db) (filedb:fdb-set-dbpath! fdb dbpath) (filedb:fdb-set-pathcache! fdb (make-hash-table)) (filedb:fdb-set-idcache! fdb (make-hash-table)) (filedb:fdb-set-partcache! fdb (make-hash-table)) (sqlite3:set-busy-handler! db (make-busy-timeout 136000)) |
︙ | ︙ |
Modified fs-transport.scm from [28e812486e] to [d1050dcefe].
1 2 3 | ;; Copyright 2006-2012, Matthew Welland. ;; | | | > > > > > | | > | > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | ;; Copyright 2006-2012, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. (require-extension (srfi 18) extras tcp s11n) (use sqlite3 srfi-1 posix regex regex-case srfi-69 hostinfo md5 message-digest) (import (prefix sqlite3 sqlite3:)) (use spiffy uri-common intarweb http-client spiffy-request-vars) |
︙ | ︙ |
Deleted fsl-rebase.scm version [d4dd53982d].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Added ftail.scm version [96a7ff77a3].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 | ;;====================================================================== ;; Copyright 2017, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. ;;====================================================================== (declare (unit ftail)) (module ftail ( open-tail-db tail-write tail-get-fid file-tail ) (import scheme chicken data-structures extras) (use (prefix sqlite3 sqlite3:) posix typed-records) (define (open-tail-db ) (let* ((basedir (create-directory (conc "/tmp/" (current-user-name)))) (dbpath (conc basedir "/megatest_logs.db")) (dbexists (file-exists? dbpath)) (db (sqlite3:open-database dbpath)) (handler (sqlite3:make-busy-timeout 136000))) (sqlite3:set-busy-handler! db handler) (sqlite3:execute db "PRAGMA synchronous = 0;") (if (not dbexists) (begin (sqlite3:execute db "CREATE TABLE IF NOT EXISTS log_files (id INTEGER PRIMARY KEY,filename TEXT,event_time TIMESTAMP DEFAULT (strftime('%s','now')));") (sqlite3:execute db "CREATE TABLE IF NOT EXISTS log_data (id INTEGER PRIMARY KEY,fid INTEGER,line TEXT,event_time TIMESTAMP DEFAULT (strftime('%s','now')));") )) db)) (define (tail-write db fid lines) (sqlite3:with-transaction db (lambda () (for-each (lambda (line) (sqlite3:execute db "INSERT INTO log_data (fid,line) VALUES (?,?);" fid line)) lines)))) (define (tail-get-fid db fname) (let ((fid (handle-exceptions exn #f (sqlite3:first-result db "SELECT id FROM log_files WHERE filename=?;" fname)))) (if fid fid (begin (sqlite3:execute db "INSERT INTO log_files (filename) VALUES (?);" fname) (tail-get-fid db fname))))) (define (file-tail fname #!key (db-in #f)) (let* ((inp (open-input-file fname)) (db (or db-in (open-tail-db))) (fid (tail-get-fid db fname))) (let loop ((inl (read-line inp)) (lines '()) (lastwr (current-seconds))) (if (eof-object? inl) (let ((timed-out (> (- (current-seconds) lastwr) 60))) (if timed-out (tail-write db fid (reverse lines))) (sleep 1) (if timed-out (loop (read-line inp) '() (current-seconds)) (loop (read-line inp) lines lastwr))) (let* ((savelines (> (length lines) 19))) ;; (print inl) (if savelines (tail-write db fid (reverse lines))) (loop (read-line inp) (if savelines '() (cons inl lines)) (if savelines (current-seconds) lastwr))))))) ;; offset -20 means get last 20 lines ;; (define (tail-get-lines db fid offset count) (if (> offset 0) (sqlite3:map-row (lambda (id line) (vector id line)) db "SELECT id,line FROM log_data WHERE fid=? OFFSET ? LIMIT ?;" fid offset count) (reverse ;; get N from the end (sqlite3:map-row (lambda (id line) (vector id line)) db "SELECT id,line FROM log_data WHERE fid=? ORDER BY id DESC LIMIT ?;" fid (abs offset))))) ) |
Modified gen-data-for-graph.scm from [6dacda5542] to [253156d2fd].
1 2 3 4 5 6 7 | (use foof-loop sql-de-lite posix) (define beginning-2016 1451636435.0) (define now (current-seconds)) (define one-year-ago (- now (* 365 24 60 60))) (define db (open-database "example.db")) | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | ;; Copyright 2006-2017, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. ;; (use foof-loop sql-de-lite posix) (define beginning-2016 1451636435.0) (define now (current-seconds)) (define one-year-ago (- now (* 365 24 60 60))) (define db (open-database "example.db")) |
︙ | ︙ |
Modified genexample.scm from [fa6512266d] to [2597a6cc06].
1 2 3 | ;;====================================================================== ;; Copyright 2006-2012, Matthew Welland. ;; | | | > > > > > | | > > > > | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | ;;====================================================================== ;; Copyright 2006-2012, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. ;;====================================================================== (declare (unit genexample)) (use posix regex) (define genexample:example-logpro #<<EOF |
︙ | ︙ | |||
54 55 56 57 58 59 60 | (if (not (directory? path)) (begin (print "The path " path " does not exist or is not a directory. Attempting to create it now") (create-directory path #t))) ;; First check that the directory is empty! | | | 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 | (if (not (directory? path)) (begin (print "The path " path " does not exist or is not a directory. Attempting to create it now") (create-directory path #t))) ;; First check that the directory is empty! (if (and (common:file-exists? path) (not (null? (glob (conc path "/*"))))) (begin (print "WARNING: directory " path " is not empty, are you sure you want to continue?") (display "Enter y/n: ") (if (equal? "y" (read-line)) (print "Using directory " path " for your Megatest area.") (begin |
︙ | ︙ | |||
145 146 147 148 149 150 151 | (print "[fields]") (map (lambda (k)(print k " TEXT")) keys) (print "") (print "[setup]") (print "# Adjust max_concurrent_jobs to limit how much you load your machines") (print "max_concurrent_jobs 50\n") (print "# This is your link path. Avoid moving it once set.") | | | | | 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 | (print "[fields]") (map (lambda (k)(print k " TEXT")) keys) (print "") (print "[setup]") (print "# Adjust max_concurrent_jobs to limit how much you load your machines") (print "max_concurrent_jobs 50\n") (print "# This is your link path. Avoid moving it once set.") (print "linktree " lntree) ;; (common:real-path lntree)) (print "\n# Job tools are more advanced ways to control how your jobs are launched") (print "[jobtools]\nuseshell yes\nlauncher nbfake\nmaxload 1.5\n") (print "# You can override environment variables for all your tests here") (print "[env-override]\nEXAMPLE_VAR example value\n") (print "# As you run more tests you may need to add additional disks, the names are arbitrary but must be unique") (print "[disks]\ndisk0 " firstd))) ;; (common:real-path firstd)))) (print "================== I'm now creating a runconfigs.config file for you with a default section. You can use this file to set variables for your tests based on the \"target\" (the combination of keys). |
︙ | ︙ | |||
184 185 186 187 188 189 190 | (print "# Override settings in ../runconfigs.config for user " (current-user-name) " here."))) ;; Now create a test and logpro file (print "================== You now have the basic common files for your megatest setup. Next run | | | 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 | (print "# Override settings in ../runconfigs.config for user " (current-user-name) " here."))) ;; Now create a test and logpro file (print "================== You now have the basic common files for your megatest setup. Next run \"megatest -create-test <testname>\" to create a test. Thank you for using Megatest. You can edit your config files and create tests in the " path " directory "))) |
︙ | ︙ | |||
208 209 210 211 212 213 214 | (description #f) (steps '()) (scripts '()) (items '()) (rel-path #f)) (cond | | | | | | | 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 | (description #f) (steps '()) (scripts '()) (items '()) (rel-path #f)) (cond ((common:file-exists? "megatest.config") (set! rel-path "./")) ((common:file-exists? "../megatest.config") (set! rel-path "../")) ((common:file-exists? "../../megatest.config") (set! rel-path "../../")) ((common:file-exists? "../../../megatest.config")(set! rel-path "../../../"))) ;; good enough dang it. ;; Don't gather data or continue if a) megatest.config can't be found or b) testconfig already exists (if (not rel-path) (begin (print "ERROR: I could not find megatest.config, please run -create-test in the top dir of your megatest area") (exit 1))) (if (common:file-exists? (conc rel-path "tests/" testname "/testconfig")) (begin (print "WARNING: You already have a testconfig in " rel-path "tests/" testname ", do you want to clobber your files?") (display "Enter y/n: ") (if (not (equal? "y" (read-line))) (begin (print "INFO: user abort of creation of test " testname) (exit 1))))) |
︙ | ︙ |
Modified gentargets.sh from [430721a6b7] to [42e51b7b59].
1 2 | #!/bin/bash | > > > > > > > > > > > > > > > > > | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | #!/bin/bash # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. echo '[all/v1.65/tip/dev]' echo 'x 1' echo '[all/v1.64/tip/dev]' echo 'x 1' |
Added get-config-settings.sh version [9655579d16].
> > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. grep configf:lookup *.scm | sed 's/^.*:lookup//; s/^-number//; s/^ //' | grep -v '^\(section\|test-conf\|tconfig\|testconfig\|dat\|config\|views-cfgdat\)' | perl -pe 's/^\s*(\*configdat\*|configdat|mtconf)//; s/^\s+//; s/\).*$//; s/"//g' | awk '{print $1,$2}' | sort | grep -v section | sort | uniq |
Modified gutils.scm from [4ace6c42c8] to [94030f1a6e].
1 2 3 | ;;====================================================================== ;; Copyright 2006-2012, Matthew Welland. ;; | | | > > > > > | | > | > > > > > > > > > > > > > > > > | > | | > > | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 | ;;====================================================================== ;; Copyright 2006-2012, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. ;; ;;====================================================================== (require-library iup) (import (prefix iup iup:)) (use canvas-draw) (use srfi-1 regex regex-case srfi-69) (declare (unit gutils)) ;; NOTE: These functions will move to iuputils (define (gutils:colors-similar? color1 color2) (let* ((c1 (map string->number (string-split color1))) (c2 (map string->number (string-split color2))) (delta (map (lambda (a b)(abs (- a b))) c1 c2))) (null? (filter (lambda (x)(> x 3)) delta)))) (define gutils:colors '((PASS . "70 249 73") (FAIL . "253 33 49") (SKIP . "230 230 0"))) (define (gutils:get-color-spec effective-state) (or (alist-ref effective-state gutils:colors) (alist-ref 'FAIL gutils:colors))) ;; BBnote - state status dashboard button color / text defined here (define (gutils:get-color-for-state-status state status);; #!key (get-label #f)) ;; ((if get-label cadr car) (case (string->symbol state) ((COMPLETED) ;; ARCHIVED) (case (string->symbol status) ((PASS) (list "70 249 73" status)) ((PREQ_FAIL PREQ_DISCARDED) (list "255 127 127" status)) ((WARN WAIVED) (list "255 172 13" status)) ((SKIP) (list (gutils:get-color-spec 'SKIP) status)) ((ABORT) (list "198 36 166" status)) (else (list "253 33 49" status)))) ((ARCHIVED) (case (string->symbol status) ((PASS) (list "70 170 73" status)) ((WARN WAIVED) (list "200 130 13" status)) ((SKIP) (list (gutils:get-color-spec 'SKIP) status)) (else (list "180 33 49" status)))) ;; (if (equal? status "PASS") ;; '("70 249 73" "PASS") ;; (if (or (equal? status "WARN") ;; (equal? status "WAIVED")) ;; (list "255 172 13" status) ;; (list "223 33 49" status)))) ;; greenish orangeish redish ((LAUNCHED) (list "101 123 142" state)) ((CHECK) (list "255 100 50" state)) ((REMOTEHOSTSTART) (list "50 130 195" state)) ((RUNNING STARTED) (list "9 131 232" state)) ((KILLREQ) (list "39 82 206" state)) ((KILLED) (list "234 101 17" state)) ((NOT_STARTED) (case (string->symbol status) ((CHECK STARTED)(list (gutils:get-color-spec 'SKIP) state)) (else (list "240 240 240" state)))) ;; for xor mode below ;; ((CLEAN) (case (string->symbol status) ((CLEAN-FAIL CLEAN-CHECK CLEAN-ABORT) (list "200 130 13" status)) ;; orange requested for these (else (list "60 235 63" status)))) ((DIRTY-BETTER) (list "160 255 153" status)) |
︙ | ︙ |
Modified http-transport.scm from [de2800221f] to [19992c5895].
1 2 3 | ;; Copyright 2006-2012, Matthew Welland. ;; | | | > > > > > | | > | > > > | < | > > | > > > | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 | ;; Copyright 2006-2012, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. (require-extension (srfi 18) extras tcp s11n) (use srfi-1 posix regex regex-case srfi-69 hostinfo md5 message-digest posix-extras) (use spiffy uri-common intarweb http-client spiffy-request-vars intarweb spiffy-directory-listing) ;; Configurations for server (tcp-buffer-size 2048) (max-connections 2048) (declare (unit http-transport)) (declare (uses common)) (declare (uses db)) (declare (uses tests)) (declare (uses tasks)) ;; tasks are where stuff is maintained about what is running. (declare (uses server)) ;; (declare (uses daemon)) (declare (uses portlogger)) (declare (uses rmt)) (include "common_records.scm") (include "db_records.scm") (include "js-path.scm") (require-library stml) (define (http-transport:make-server-url hostport) (if (not hostport) #f (conc "http://" (car hostport) ":" (cadr hostport)))) (define *server-loop-heart-beat* (current-seconds)) ;;====================================================================== ;; S E R V E R ;; ====================================================================== ;; Call this to start the actual server ;; (define *db:process-queue-mutex* (make-mutex)) (define (http-transport:run hostn) ;; Configurations for server (tcp-buffer-size 2048) (max-connections 2048) (debug:print 2 *default-log-port* "Attempting to start the server ...") (let* ((db #f) ;; (open-db)) ;; we don't want the server to be opening and closing the db unnecesarily (hostname (get-host-name)) (ipaddrstr (let ((ipstr (if (string=? "-" hostn) ;; (string-intersperse (map number->string (u8vector->list (hostname->ip hostname))) ".") (server:get-best-guess-address hostname) #f))) (if ipstr ipstr hostn))) ;; hostname))) (start-port (portlogger:open-run-close portlogger:find-port)) (link-tree-path (common:get-linktree)) (tmp-area (common:get-db-tmp-area)) (start-file (conc tmp-area "/.server-start"))) (debug:print-info 0 *default-log-port* "portlogger recommended port: " start-port) ;; set some parameters for the server (root-path (if link-tree-path link-tree-path (current-directory))) ;; WARNING: SECURITY HOLE. FIX ASAP! (handle-directory spiffy-directory-listing) (handle-exception (lambda (exn chain) (signal (make-composite-condition (make-property-condition |
︙ | ︙ | |||
99 100 101 102 103 104 105 | (send-response body: (http-transport:main-page))) ((equal? (uri-path (request-uri (current-request))) '(/ any)) (send-response body: "hey there!\n" headers: '((content-type text/plain)))) ((equal? (uri-path (request-uri (current-request))) '(/ "hey")) | | > > > > > > > > > > > > > | > > > | | 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 | (send-response body: (http-transport:main-page))) ((equal? (uri-path (request-uri (current-request))) '(/ any)) (send-response body: "hey there!\n" headers: '((content-type text/plain)))) ((equal? (uri-path (request-uri (current-request))) '(/ "hey")) (send-response body: "hey there!\n" headers: '((content-type text/plain)))) ((equal? (uri-path (request-uri (current-request))) '(/ "jquery3.1.0.js")) (send-response body: (http-transport:show-jquery) headers: '((content-type application/javascript)))) ((equal? (uri-path (request-uri (current-request))) '(/ "test_log")) (send-response body: (http-transport:html-test-log $) headers: '((content-type text/HTML)))) ((equal? (uri-path (request-uri (current-request))) '(/ "dashboard")) (send-response body: (http-transport:html-dboard $) headers: '((content-type text/HTML)))) (else (continue)))))))) (with-output-to-file start-file (lambda ()(print (current-process-id)))) (http-transport:try-start-server ipaddrstr start-port))) ;; This is recursively run by http-transport:run until sucessful ;; (define (http-transport:try-start-server ipaddrstr portnum) (let ((config-hostname (configf:lookup *configdat* "server" "hostname")) (config-use-proxy (equal? (configf:lookup *configdat* "client" "use-http_proxy") "yes"))) (if (not config-use-proxy) (determine-proxy (constantly #f))) (debug:print-info 0 *default-log-port* "http-transport:try-start-server time=" (seconds->time-string (current-seconds)) " ipaddrsstr=" ipaddrstr " portnum=" portnum " config-hostname=" config-hostname) (handle-exceptions exn (begin (print-error-message exn) (if (< portnum 64000) (begin (debug:print 0 *default-log-port* "WARNING: attempt to start server failed. Trying again ...") (debug:print 0 *default-log-port* " message: " ((condition-property-accessor 'exn 'message) exn)) (debug:print 5 *default-log-port* "exn=" (condition->list exn)) (portlogger:open-run-close portlogger:set-failed portnum) (debug:print 0 *default-log-port* "WARNING: failed to start on portnum: " portnum ", trying next port") (thread-sleep! 0.1) ;; get_next_port goes here (http-transport:try-start-server ipaddrstr (portlogger:open-run-close portlogger:find-port))) |
︙ | ︙ | |||
231 232 233 234 235 236 237 | success (db:string->obj (handle-exceptions exn (let ((call-chain (get-call-chain)) (msg ((condition-property-accessor 'exn 'message) exn))) (set! success #f) | > > > | | | > | | | 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 | success (db:string->obj (handle-exceptions exn (let ((call-chain (get-call-chain)) (msg ((condition-property-accessor 'exn 'message) exn))) (set! success #f) (if (debug:debug-mode 1) (debug:print-info 0 *default-log-port* "couldn't talk to server, trying again ...") (begin (debug:print 0 *default-log-port* "WARNING: failure in with-input-from-request to " fullurl ".") (debug:print 0 *default-log-port* " message: " msg) (debug:print 0 *default-log-port* " cmd: " cmd " params: " params) (debug:print 0 *default-log-port* " call-chain: " call-chain))) (if runremote (remote-conndat-set! runremote #f)) ;; Killing associated server to allow clean retry.") ;; (tasks:kill-server-run-id run-id) ;; better to kill the server in the logic that called this routine? (mutex-unlock! *http-mutex*) ;;; (signal (make-composite-condition ;;; (make-property-condition 'commfail 'message "failed to connect to server"))) ;;; "communications failed" (db:obj->string #f)) (with-input-from-request ;; was dat fullurl (list (cons 'key (or *server-id* "thekey")) (cons 'cmd cmd) (cons 'params sparams)) read-string)) transport: 'http) 0)) ;; added this speculatively ;; Shouldn't this be a call to the managed call-all-connections stuff above? (close-all-connections!) |
︙ | ︙ | |||
271 272 273 274 275 276 277 | (debug:print-info 11 *default-log-port* "got res=" res) (if (vector? res) (if (vector-ref res 0) ;; this is the first flag or the second flag? res ;; this is the *inner* vector? seriously? why? (if (debug:debug-mode 11) (let ((call-chain (get-call-chain))) ;; note: this code also called in nmsg-transport - consider consolidating it (print-call-chain (current-error-port)) | | > > > > > | > | | 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 | (debug:print-info 11 *default-log-port* "got res=" res) (if (vector? res) (if (vector-ref res 0) ;; this is the first flag or the second flag? res ;; this is the *inner* vector? seriously? why? (if (debug:debug-mode 11) (let ((call-chain (get-call-chain))) ;; note: this code also called in nmsg-transport - consider consolidating it (print-call-chain (current-error-port)) (debug:print-error 11 *default-log-port* "error above occured at server, res=" res) ;; " message: " ((condition-property-accessor 'exn 'message) exn)) (debug:print 11 *default-log-port* " server call chain:") (pp (vector-ref res 1) (current-error-port)) (signal (vector-ref res 0))) res)) (signal (make-composite-condition (make-property-condition 'timeout 'message "nmsg-transport:client-api-send-receive-raw timed out talking to server"))))))) ;; careful closing of connections stored in *runremote* ;; (define (http-transport:close-connections #!key (area-dat #f)) (let* ((runremote (or area-dat *runremote*)) (server-dat (if runremote (remote-conndat runremote) #f))) ;; (hash-table-ref/default *runremote* run-id #f))) (if (vector? server-dat) (let ((api-dat (http-transport:server-dat-get-api-uri server-dat))) (handle-exceptions exn (begin (print-call-chain *default-log-port*) (debug:print-error 0 *default-log-port* " closing connection failed with error: " ((condition-property-accessor 'exn 'message) exn))) (close-connection! api-dat) ;;(close-idle-connections!) #t)) #f))) (define (make-http-transport:server-dat)(make-vector 6)) (define (http-transport:server-dat-get-iface vec) (vector-ref vec 0)) (define (http-transport:server-dat-get-port vec) (vector-ref vec 1)) (define (http-transport:server-dat-get-api-uri vec) (vector-ref vec 2)) |
︙ | ︙ | |||
338 339 340 341 342 343 344 | ;; used and to shutdown after sometime if it is not. ;; (define (http-transport:keep-running) ;; if none running or if > 20 seconds since ;; server last used then start shutdown ;; This thread waits for the server to come alive (debug:print-info 0 *default-log-port* "Starting the sync-back, keep alive thread in server") | > > > | | > > > > > > > > > > > > > | | > > > | | 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 | ;; used and to shutdown after sometime if it is not. ;; (define (http-transport:keep-running) ;; if none running or if > 20 seconds since ;; server last used then start shutdown ;; This thread waits for the server to come alive (debug:print-info 0 *default-log-port* "Starting the sync-back, keep alive thread in server") (let* ((sdat #f) (tmp-area (common:get-db-tmp-area)) (started-file (conc tmp-area "/.server-started")) (server-start-time (current-seconds)) (server-info (let loop ((start-time (current-seconds)) (changed #t) (last-sdat "not this")) (begin ;; let ((sdat #f)) (thread-sleep! 0.01) (debug:print-info 0 *default-log-port* "Waiting for server alive signature") (mutex-lock! *heartbeat-mutex*) (set! sdat *server-info*) (mutex-unlock! *heartbeat-mutex*) (if (and sdat (not changed) (> (- (current-seconds) start-time) 2)) (begin (debug:print-info 0 *default-log-port* "Received server alive signature") (common:save-pkt `((action . alive) (T . server) (pid . ,(current-process-id)) (ipaddr . ,(car sdat)) (port . ,(cadr sdat))) *configdat* #t) sdat) (begin (debug:print-info 0 *default-log-port* "Still waiting, last-sdat=" last-sdat) (sleep 4) (if (> (- (current-seconds) start-time) 120) ;; been waiting for two minutes (begin (debug:print-error 0 *default-log-port* "transport appears to have died, exiting server") (common:save-pkt `((action . died) (T . server) (pid . ,(current-process-id)) (ipaddr . ,(car sdat)) (port . ,(cadr sdat)) (msg . "Transport died?")) *configdat* #t) (exit)) (loop start-time (equal? sdat last-sdat) sdat))))))) (iface (car server-info)) (port (cadr server-info)) (last-access 0) (server-timeout (server:expiration-timeout)) (server-going #f) (server-log-file (args:get-arg "-log"))) ;; always set when we are a server (with-output-to-file started-file (lambda ()(print (current-process-id)))) (let loop ((count 0) (server-state 'available) (bad-sync-count 0) (start-time (current-milliseconds))) ;; Use this opportunity to sync the tmp db to megatest.db (if (not server-going) ;; *dbstruct-db* (begin (debug:print 0 *default-log-port* "SERVER: dbprep") (set! *dbstruct-db* (db:setup #t)) ;; run-id)) (set! server-going #t) (debug:print 0 *default-log-port* "SERVER: running, megatest version: " (common:get-full-version)) ;; NOTE: the server is NOT yet marked as running in the log. We do that in the keep-running routine. (thread-start! *watchdog*))) ;; when things go wrong we don't want to be doing the various queries too often ;; so we strive to run this stuff only every four seconds or so. (let* ((sync-time (- (current-milliseconds) start-time)) |
︙ | ︙ | |||
421 422 423 424 425 426 427 | (begin (debug:print 0 *default-log-port* "SERVER STARTED: " iface ":" port " AT " (current-seconds)) (flush-output *default-log-port*))) (if (common:low-noise-print 60 "dbstats") (begin (debug:print 0 *default-log-port* "Server stats:") (db:print-current-query-stats))) | | < < < < < | < > | | 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 | (begin (debug:print 0 *default-log-port* "SERVER STARTED: " iface ":" port " AT " (current-seconds)) (flush-output *default-log-port*))) (if (common:low-noise-print 60 "dbstats") (begin (debug:print 0 *default-log-port* "Server stats:") (db:print-current-query-stats))) (let* ((hrs-since-start (/ (- (current-seconds) server-start-time) 3600))) (cond ((and *server-run* (> (+ last-access server-timeout) (current-seconds))) (if (common:low-noise-print 120 "server continuing") (debug:print-info 0 *default-log-port* "Server continuing, seconds since last db access: " (- (current-seconds) last-access)) (let ((curr-time (current-seconds))) (handle-exceptions exn (debug:print 0 *default-log-port* "ERROR: Failed to change timestamp on log file " server-log-file ". Are you out of space on that disk?") (if (not *server-overloaded*) (change-file-times server-log-file curr-time curr-time))))) (loop 0 server-state bad-sync-count (current-milliseconds))) (else (debug:print-info 0 *default-log-port* "Server timed out. seconds since last db access: " (- (current-seconds) last-access)) (http-transport:server-shutdown port))))))) (define (http-transport:server-shutdown port) (begin |
︙ | ︙ | |||
472 473 474 475 476 477 478 | ;; (if (eq? *number-non-write-queries* 0) ;; "n/a (no queries)" ;; (/ *total-non-write-delay* ;; *number-non-write-queries*)) ;; " ms") (db:print-current-query-stats) | | > > > > > > > > > > > > > > > > | > > > > > | < < > > > > > | > > > | | > | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 | ;; (if (eq? *number-non-write-queries* 0) ;; "n/a (no queries)" ;; (/ *total-non-write-delay* ;; *number-non-write-queries*)) ;; " ms") (db:print-current-query-stats) (common:save-pkt `((action . exit) (T . server) (pid . ,(current-process-id))) *configdat* #t) (debug:print-info 0 *default-log-port* "Server shutdown complete. Exiting") (exit))) ;; all routes though here end in exit ... ;; ;; start_server? ;; (define (http-transport:launch) ;; check that a server start is in progress, pause or exit if so (let* ((tmp-area (common:get-db-tmp-area)) (server-start (conc tmp-area "/.server-start")) (server-started (conc tmp-area "/.server-started")) (start-time (common:lazy-modification-time server-start)) (started-time (common:lazy-modification-time server-started)) (server-starting (< start-time started-time)) ;; if start-time is less than started-time then a server is still starting (start-time-old (> (- (current-seconds) start-time) 5)) (cleanup-proc (lambda (msg) (let* ((serv-fname (conc "server-" (current-process-id) "-" (get-host-name) ".log")) (full-serv-fname (conc *toppath* "/logs/" serv-fname)) (new-serv-fname (conc *toppath* "/logs/" "defunct-" serv-fname))) (debug:print 0 *default-log-port* msg) (if (common:file-exists? full-serv-fname) (system (conc "sleep 1;mv -f " full-serv-fname " " new-serv-fname)) (debug:print 0 *default-log-port* "INFO: cannot move " full-serv-fname " to " new-serv-fname)) (exit))))) (if (and (not start-time-old) ;; last server start try was less than five seconds ago (not server-starting)) (begin (cleanup-proc "NOT starting server, there is either a recently started server or a server in process of starting") (exit))) ;; lets not even bother to start if there are already three or more server files ready to go (let* ((num-alive (server:get-num-alive (server:get-list *toppath*)))) (if (> num-alive 3) (begin (cleanup-proc (conc "ERROR: Aborting server start because there are already " num-alive " possible servers either running or starting up")) (exit)))) (common:save-pkt `((action . start) (T . server) (pid . ,(current-process-id))) *configdat* #t) (let* ((th2 (make-thread (lambda () (debug:print-info 0 *default-log-port* "Server run thread started") (http-transport:run (if (args:get-arg "-server") (args:get-arg "-server") "-") )) "Server run")) (th3 (make-thread (lambda () (debug:print-info 0 *default-log-port* "Server monitor thread started") (http-transport:keep-running) "Keep running")))) (thread-start! th2) (thread-sleep! 0.25) ;; give the server time to settle before starting the keep-running monitor. (thread-start! th3) (set! *didsomething* #t) (thread-join! th2) (exit)))) ;; (define (http-transport:server-signal-handler signum) ;; (signal-mask! signum) ;; (handle-exceptions ;; exn ;; (debug:print 0 *default-log-port* " ... exiting ...") ;; (let ((th1 (make-thread (lambda () ;; (thread-sleep! 1)) ;; "eat response")) ;; (th2 (make-thread (lambda () ;; (debug:print-error 0 *default-log-port* "Received ^C, attempting clean exit. Please be patient and wait a few seconds before hitting ^C again.") ;; (thread-sleep! 3) ;; give the flush three seconds to do it's stuff ;; (debug:print 0 *default-log-port* " Done.") ;; (exit 4)) ;; "exit on ^C timer"))) ;; (thread-start! th2) ;; (thread-start! th1) ;; (thread-join! th2)))) ;;=============================================== ;; Java script ;;=============================================== (define (http-transport:show-jquery) (let* ((data (tests:readlines *java-script-lib*))) (string-join data "\n"))) ;;====================================================================== ;; web pages ;;====================================================================== (define (http-transport:html-test-log $) (let* ((run-id ($ 'runid)) (test-item ($ 'testname)) (parts (string-split test-item ":")) (test-name (car parts)) (item-name (if (equal? (length parts) 1) "" (cadr parts)))) ;(print $) (tests:get-test-log run-id test-name item-name))) (define (http-transport:html-dboard $) (let* ((page ($ 'page)) (oup (open-output-string)) (bdy "--------------------------") (ret (tests:dynamic-dboard page))) (s:output-new oup ret) (close-output-port oup) (set! bdy (get-output-string oup)) (conc "<h1>Dashboard</h1>" bdy "<br/> <br/> " ))) (define (http-transport:main-page) (let ((linkpath (root-path))) (conc "<head><h1>" (pathname-strip-directory *toppath*) "</h1></head>" "<body>" "Run area: " *toppath* "<h2>Server Stats</h2>" (http-transport:stats-table) "<hr>" (http-transport:runs linkpath) "<hr>" ;; (http-transport:run-stats) "</body>" ))) (define (http-transport:stats-table) (mutex-lock! *heartbeat-mutex*) (let ((res (conc "<table>" |
︙ | ︙ | |||
573 574 575 576 577 578 579 | (string-intersperse (let ((files (map pathname-strip-directory (glob (conc linkpath "/*"))))) (map (lambda (p) (conc "<a href=\"" p "\">" p "</a><br>")) files)) " "))) | | | 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 | (string-intersperse (let ((files (map pathname-strip-directory (glob (conc linkpath "/*"))))) (map (lambda (p) (conc "<a href=\"" p "\">" p "</a><br>")) files)) " "))) #;(define (http-transport:run-stats) (let ((stats (open-run-close db:get-running-stats #f))) (conc "<table>" (string-intersperse (map (lambda (stat) (conc "<tr><td>" (car stat) "</td><td>" (cadr stat) "</td></tr>")) stats) " ") "</table>"))) |
Modified index-tree.scm from [09941b0f00] to [10c620fbfc].
1 2 3 | ;;====================================================================== ;; Copyright 2006-2013, Matthew Welland. ;; | | | > > > > > | | > | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | ;;====================================================================== ;; Copyright 2006-2013, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. ;; ;;====================================================================== ;;====================================================================== ;; Tests ;;====================================================================== (use sqlite3 srfi-1 posix regex regex-case srfi-69 dot-locking tcp directory-utils) |
︙ | ︙ |
Modified items.scm from [0624dd0189] to [16328a4b96].
1 2 3 | ;; Copyright 2006-2012, Matthew Welland. ;; | | | > > > > > | | > | > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | ;; Copyright 2006-2012, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. ;; (define itemdat '((ripeness "green ripe overripe") ;; (temperature "cool medium hot") ;; (season "summer winter fall spring"))) (declare (unit items)) |
︙ | ︙ | |||
107 108 109 110 111 112 113 | (loop (+ indx 1) '() #f))) res))) ;; Nope, not now, return null as of 6/6/2011 (define (items:check-valid-items class item) | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | | > > > > | > > > | 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 | (loop (+ indx 1) '() #f))) res))) ;; Nope, not now, return null as of 6/6/2011 (define (items:check-valid-items class item) (let ((valid-values (let ((s (configf:lookup *configdat* "validvalues" class))) (if s (string-split s) #f)))) (if valid-values (if (member item valid-values) item #f) item))) ;; '(("k1" "k2" "k3") ;; ("a" "b" "c") ;; ("d" "e" "f")) ;; ;; => '((("k1" "a")("k2" "b")("k3" "c")) ;; (("k1" "d")("k2" "e")("k3" "f"))) ;; (define (items:first-row-intersperse data) (if (< (length data) 2) '() (let ((header (car data)) (rows (cdr data))) (map (lambda (row) (map list header row)) rows)))) ;; k1/k2/k3 ;; a/b/c ;; d/e/f ;; => '(("k1" "k2" "k3") ;; ("a" "b" "c") ;; ("d" "e" "f")) ;; ;; => '((("k1" "a")("k2" "b")("k3" "c")) ;; (("k1" "d")("k2" "e")("k3" "f"))) ;; (define (items:read-items-file fname ftype) ;; 'sxml 'slash 'space (if (and fname (file-exists? fname)) (items:first-row-intersperse (case ftype ((slash space) (let ((splitter (case ftype ((slash) (lambda (x)(string-split x "/"))) (else string-split)))) (debug:print 0 *default-log-port* "Reading " fname " of type " ftype) (with-input-from-file fname (lambda () (let loop ((inl (read-line)) (res '())) (if (eof-object? inl) res (loop (read-line)(cons (splitter inl) res)))))))) ((sxml)(with-input-from-file fname read)) (else (debug:print 0 *default-log-port* "items file type " ftype " not recognised")))) (begin (if fname (debug:print 0 *default-log-port* "no items file " fname " found")) '()))) (define (items:get-items-from-config tconfig) (let* ((slashf (configf:lookup tconfig "itemopts" "slash")) ;; a/b/c\nd/e/f\n ... (sxmlf (configf:lookup tconfig "itemopts" "sxml")) ;; '(("a" "b" "c")("d" "e" "f") ...) (spacef (configf:lookup tconfig "itemopts" "space")) ;; a b c\nd e f\n ... (have-items (hash-table-ref/default tconfig "items" #f)) (have-itable (hash-table-ref/default tconfig "itemstable" #f)) (items (hash-table-ref/default tconfig "items" '())) (itemstable (hash-table-ref/default tconfig "itemstable" '()))) (debug:print 5 *default-log-port* "items: " items " itemstable: " itemstable) (set! items (map (lambda (item) (if (procedure? (cadr item)) (list (car item)((cadr item))) ;; evaluate the proc item)) items)) (set! itemstable (map (lambda (item) (if (procedure? (cadr item)) (list (car item)((cadr item))) ;; evaluate the proc item)) itemstable)) (if (and have-items (null? items)) (debug:print 0 *default-log-port* "WARNING:[items] section in testconfig but no entries defined")) (if (and have-itable (null? itemstable))(debug:print 0 *default-log-port* "WARNNG:[itemstable] section in testconfig but no entries defined")) (if (or (not (null? items)) (not (null? itemstable)) slashf sxmlf spacef) (append (item-assoc->item-list items) (item-table->item-list itemstable) (items:read-items-file slashf 'slash) (items:read-items-file sxmlf 'sxml) (items:read-items-file spacef 'space)) '(())))) ;; (pp (item-assoc->item-list itemdat)) |
Added iup-test/Makefile version [2356e68571].
> > > > > | 1 2 3 4 5 | LIBSRC = "<$PATH>/chicken-4.10.0-patch" sample : sample.c gcc -I$(LIBSRC)/include/ -L$(LIBSRC)/lib -L$(LIBSRC)/lib64 -liup -liupimglib -o sample sample.c |
Added iup-test/matrix.c version [651f14d0b4].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 | #include <stdio.h> #include <stdlib.h> #include <string.h> #include <stdarg.h> #undef __IUPDEF_H #include "iup.h" #include "iupcontrols.h" #include "iupcbs.h" #include "iup_plus.h" #define TEST_IMAGE_SIZE 20 static unsigned char image_data_32 [TEST_IMAGE_SIZE*TEST_IMAGE_SIZE*4] = { 000,000,000,255,000,000,000,255,000,000,000,255,000,000,000,255,000,000,000,255,000,000,000,255,000,000,000,255,000,000,000,255,000,000,000,255,000,000,000,255,000,000,000,255,000,000,000,255,000,000,000,255,000,000,000,255,000,000,000,255,000,000,000,255,000,000,000,255,000,000,000,255,000,000,000,255,000,000,000,255, 000,000,000,255,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,255, 000,000,000,255,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,255, 000,000,000,255,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,255, 000,000,000,255,000,000,000,000,000,000,000,000,000,000,000,000,255,000,000,255,255,000,000,255,255,000,000,255,255,000,000,255,255,000,000,255,255,000,000,255,000,255,000,255,000,255,000,255,000,255,000,255,000,255,000,255,000,255,000,255,000,255,000,255,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,255, 000,000,000,255,000,000,000,000,000,000,000,000,000,000,000,000,255,000,000,255,255,000,000,255,255,000,000,255,255,000,000,255,255,000,000,255,255,000,000,255,000,255,000,255,000,255,000,255,000,255,000,255,000,255,000,255,000,255,000,255,000,255,000,255,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,255, 000,000,000,255,000,000,000,000,000,000,000,000,000,000,000,000,255,000,000,255,255,000,000,255,255,000,000,255,255,000,000,255,255,000,000,255,255,000,000,255,000,255,000,255,000,255,000,255,000,255,000,255,000,255,000,255,000,255,000,255,000,255,000,255,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,255, 000,000,000,255,000,000,000,000,000,000,000,000,000,000,000,000,255,000,000,255,255,000,000,255,255,000,000,255,255,000,000,255,255,000,000,255,255,000,000,255,000,255,000,255,000,255,000,255,000,255,000,255,000,255,000,255,000,255,000,255,000,255,000,255,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,255, 000,000,000,255,000,000,000,000,000,000,000,000,000,000,000,000,255,000,000,255,255,000,000,255,255,000,000,255,255,000,000,255,255,000,000,255,255,000,000,255,000,255,000,255,000,255,000,255,000,255,000,255,000,255,000,255,000,255,000,255,000,255,000,255,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,255, 000,000,000,255,000,000,000,000,000,000,000,000,000,000,000,000,255,000,000,255,255,000,000,255,255,000,000,255,255,000,000,255,255,000,000,255,255,000,000,255,000,255,000,255,000,255,000,255,000,255,000,255,000,255,000,255,000,255,000,255,000,255,000,255,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,255, 000,000,000,255,000,000,000,000,000,000,000,000,000,000,000,000,000,000,255,255,000,000,255,255,000,000,255,255,000,000,255,255,000,000,255,255,000,000,255,255,255,255,255,192,255,255,255,192,255,255,255,192,255,255,255,192,255,255,255,192,255,255,255,192,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,255, 000,000,000,255,000,000,000,000,000,000,000,000,000,000,000,000,000,000,255,255,000,000,255,255,000,000,255,255,000,000,255,255,000,000,255,255,000,000,255,255,255,255,255,192,255,255,255,192,255,255,255,192,255,255,255,192,255,255,255,192,255,255,255,192,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,255, 000,000,000,255,000,000,000,000,000,000,000,000,000,000,000,000,000,000,255,255,000,000,255,255,000,000,255,255,000,000,255,255,000,000,255,255,000,000,255,255,255,255,255,192,255,255,255,192,255,255,255,192,255,255,255,192,255,255,255,192,255,255,255,192,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,255, 000,000,000,255,000,000,000,000,000,000,000,000,000,000,000,000,000,000,255,255,000,000,255,255,000,000,255,255,000,000,255,255,000,000,255,255,000,000,255,255,255,255,255,192,255,255,255,192,255,255,255,192,255,255,255,192,255,255,255,192,255,255,255,192,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,255, 000,000,000,255,000,000,000,000,000,000,000,000,000,000,000,000,000,000,255,255,000,000,255,255,000,000,255,255,000,000,255,255,000,000,255,255,000,000,255,255,255,255,255,192,255,255,255,192,255,255,255,192,255,255,255,192,255,255,255,192,255,255,255,192,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,255, 000,000,000,255,000,000,000,000,000,000,000,000,000,000,000,000,000,000,255,255,000,000,255,255,000,000,255,255,000,000,255,255,000,000,255,255,000,000,255,255,255,255,255,192,255,255,255,192,255,255,255,192,255,255,255,192,255,255,255,192,255,255,255,192,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,255, 000,000,000,255,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,255, 000,000,000,255,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,255, 000,000,000,255,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,255, 000,000,000,255,000,000,000,255,000,000,000,255,000,000,000,255,000,000,000,255,000,000,000,255,000,000,000,255,000,000,000,255,000,000,000,255,000,000,000,255,000,000,000,255,000,000,000,255,000,000,000,255,000,000,000,255,000,000,000,255,000,000,000,255,000,000,000,255,000,000,000,255,000,000,000,255,000,000,000,255, }; static int mousemove_cb(Ihandle *ih, int lin, int col) { printf("mousemove_cb(%d, %d)\n", lin, col); return IUP_DEFAULT; } static int drop(Ihandle *self, Ihandle *drop, int lin, int col) { printf("drop_cb(%d, %d)\n", lin, col); if(lin == 3 && col == 1) { IupSetAttribute(drop, "1", "A - Test of Very Big String for Dropdown!"); IupSetAttribute(drop, "2", "B"); IupSetAttribute(drop, "3", "C"); IupSetAttribute(drop, "4", "XXX"); IupSetAttribute(drop, "5", "5"); IupSetAttribute(drop, "6", "6"); IupSetAttribute(drop, "7", "7"); IupSetAttribute(drop, "8", NULL); IupSetAttribute(drop, "VALUE", "4"); return IUP_DEFAULT; } return IUP_IGNORE; } static int dropcheck_cb(Ihandle *self, int lin, int col) { if (lin == 3 && col == 1) return IUP_DEFAULT; if (lin == 4 && col == 4) return IUP_CONTINUE; return IUP_IGNORE; } static int togglevalue_cb(Ihandle *self, int lin, int col, int value) { printf("togglevalue_cb(%d, %d)=%d\n", lin, col, value); return IUP_DEFAULT; } static int click(Ihandle *self, int lin, int col) { printf("click_cb(%d, %d)\n", lin, col); IupSetAttribute(self,"MARKED", NULL); /* clear all marks */ IupSetAttributeId2(self,"MARK", lin, 0, "1"); IupSetfAttribute(self,"REDRAW", "L%d", lin); return IUP_DEFAULT; } static int enteritem_cb(Ihandle *ih, int lin, int col) { IupSetAttribute(ih,"MARKED", NULL); /* clear all marks */ IupSetAttributeId2(ih,"MARK", lin, 0, "1"); IupSetfAttribute(ih,"REDRAW", "L%d", lin); return IUP_DEFAULT; } static Ihandle* create_matrix(void) { Ihandle* mat = IupMatrix(NULL); // IupSetAttribute(mat, "NUMLIN", "3"); IupSetAttribute(mat, "NUMLIN", "20"); IupSetAttribute(mat, "NUMCOL", "8"); // IupSetAttribute(mat, "NUMCOL", "15"); // IupSetAttribute(mat, "NUMLIN", "3"); // IupSetAttribute(mat, "NUMCOL", "2"); // IupSetAttribute(mat, "NUMLIN", "8"); // IupSetAttribute(mat, "NUMCOL", "5"); // IupSetAttribute(mat, "ACTIVE", "NO"); // IupSetAttribute(mat, "EDITHIDEONFOCUS", "NO"); // IupSetAttribute(mat, "EDITALIGN", "Yes"); // IupSetAttribute(mat, "EDITFITVALUE", "Yes"); // IupSetAttribute(mat, "READONLY", "Yes"); //IupSetAttribute(mat, "0:0", "Inflation"); //IupSetAttribute(mat, "1:0", "Medicine\nPharma"); //IupSetAttribute(mat, "2:0", "Food"); //IupSetAttribute(mat, "3:0", "Energy"); //IupSetAttribute(mat, "0:1", "January 2000"); //IupSetAttribute(mat, "0:2", "February 2000"); IupSetAttribute(mat, "1:1", "5.6\n3.33"); IupSetAttribute(mat, "2:1", "2.2"); IupSetAttribute(mat, "3:2", "Very Very Very Very Very Large Text"); IupSetAttribute(mat, "1:2", "4.5"); if (IupGetInt(NULL, "UTF8MODE")) IupSetAttribute(mat, "2:2", "(çãõáóé)"); else IupSetAttribute(mat, "2:2", "(çãõáóé)"); IupSetAttribute(mat, "3:1", "3.4"); IupSetAttribute(mat, "3:3", "Font Test"); // IupSetAttribute(mat, "HEIGHT2", "30"); // IupSetAttribute(mat, "WIDTH2", "190"); // IupSetAttributeId(mat, "WIDTH", 2, "190"); IupSetAttribute(mat,"SORTSIGN2","DOWN"); // IupSetAttribute(mat, "WIDTHDEF", "34"); // IupSetAttribute(mat,"MULTILINE", "YES"); IupSetAttribute(mat,"RESIZEMATRIX", "YES"); // IupSetAttribute(mat,"HIDDENTEXTMARKS", "YES"); // IupSetAttribute(mat,"USETITLESIZE", "YES"); //IupSetAttribute(mat,"SCROLLBAR", "NO"); //IupSetAttribute(mat, "BGCOLOR1:2", "255 92 255"); //IupSetAttribute(mat, "BGCOLOR2:*", "92 92 255"); //IupSetAttribute(mat, "BGCOLOR*:3", "255 92 92"); //IupSetAttribute(mat, "FGCOLOR1:2", "255 0 0"); //IupSetAttribute(mat, "FGCOLOR2:*", "0 128 0"); //IupSetAttribute(mat, "FGCOLOR*:3", "0 0 255"); IupSetAttribute(mat, "FONT3:3", "Helvetica, 24"); //IupSetAttribute(mat, "FONT2:*", "Courier, 14"); //IupSetAttribute(mat, "FONT*:3", "Times, Bold 14"); // IupSetAttribute(mat, "ALIGNMENT1", "ALEFT"); // IupSetAttribute(mat, "ALIGNMENT3", "ARIGHT"); // IupSetAttribute(mat, "ALIGN2:1", ":ARIGHT"); // IupSetAttribute(mat, "LINEALIGNMENT1", "ATOP"); // IupSetAttribute(mat, "ACTIVE", "NO"); // IupSetAttribute(mat, "EXPAND", "NO"); // IupSetAttribute(mat, "ALIGNMENT", "ALEFT"); // IupSetAttribute(mat, "MASK1:3", IUP_MASK_FLOAT); // IupSetAttribute(mat, "MASK1:3", "[a-zA-Z][0-9a-zA-Z_]*"); // IupSetAttribute(mat, "MASKFLOAT1:3", "0.0:10.0"); IupSetAttribute(mat, "MASK*:3", "[a-zA-Z][0-9a-zA-Z_]*"); IupSetAttribute(mat, "TYPE4:1", "COLOR"); IupSetAttribute(mat, "4:1", "255 0 128"); IupSetAttribute(mat, "TYPE4:2", "FILL"); IupSetAttribute(mat, "4:2", "60"); IupSetAttribute(mat, "SHOWFILLVALUE", "Yes"); { Ihandle* image = IupImageRGBA(TEST_IMAGE_SIZE, TEST_IMAGE_SIZE, image_data_32); IupSetAttribute(mat, "TYPE4:3", "IMAGE"); IupSetAttributeHandle(mat, "4:3", image); } // IupSetAttribute(mat, "TOGGLEVALUE4:4", "ON"); // IupSetAttribute(mat, "VALUE4:4", "1"); IupSetAttribute(mat, "TOGGLECENTERED", "Yes"); IupSetAttribute(mat,"MARKMODE","CELL"); // IupSetAttribute(mat,"MARKMODE","LIN"); // IupSetAttribute(mat,"MARKMULTIPLE","NO"); IupSetAttribute(mat,"MARKMULTIPLE","YES"); // IupSetAttribute(mat,"MARKAREA","NOT_CONTINUOUS"); // IupSetAttribute(mat,"MARK2:2","YES"); // IupSetAttribute(mat,"MARK2:3","YES"); // IupSetAttribute(mat,"MARK3:3","YES"); IupSetAttribute(mat,"FRAMEVERTCOLOR1:2","BGCOLOR"); IupSetAttribute(mat,"FRAMEHORIZCOLOR1:2","0 0 255"); IupSetAttribute(mat,"FRAMEHORIZCOLOR1:3","0 255 0"); IupSetAttribute(mat,"FRAMEVERTCOLOR2:2","255 255 0"); IupSetAttribute(mat,"FRAMEVERTCOLOR*:4","0 255 0"); IupSetAttribute(mat,"FRAMEVERTCOLOR*:5","BGCOLOR"); // IupSetAttribute(mat,"MARKMODE","LINCOL"); //IupSetAttribute(mat, "NUMCOL_VISIBLE_LAST", "YES"); //IupSetAttribute(mat, "NUMLIN_VISIBLE_LAST", "YES"); // IupSetAttribute(mat, "WIDTHDEF", "15"); IupSetAttribute(mat, "20:8", "The End"); //IupSetAttribute(mat, "10:0", "Middle Line"); //IupSetAttribute(mat, "15:0", "Middle Line"); //IupSetAttribute(mat, "0:4", "Middle Column"); //IupSetAttribute(mat, "20:0", "Line Title Test"); //IupSetAttribute(mat, "0:8", "Column Title Test"); IupSetAttribute(mat, "NUMCOL_VISIBLE", "3"); IupSetAttribute(mat, "NUMLIN_VISIBLE", "5"); // IupSetAttribute(mat,"EDITNEXT","COLCR"); // IupSetAttribute(mat, "NUMCOL_NOSCROLL", "1"); // IupSetAttribute(mat, "LIMITEXPAND", "Yes"); // IupSetAttribute(mat, "XAUTOHIDE", "NO"); // IupSetAttribute(mat, "YAUTOHIDE", "NO"); // IupSetAttribute(mat,"RASTERSIZE","x300"); // IupSetAttribute(mat,"FITTOSIZE","LINES"); // IupSetAttribute(mat,"TYPECOLORINACTIVE","No"); // IupSetAttribute(mat, "ACTIVE", "No"); IupSetAttribute(mat, "FRAMEBORDER", "Yes"); /* test for custom matrix attributes */ //{ // char* v; // IupSetAttribute(mat, "MTX_LINE_ACTIVE_FLAG3:4", "Test1"); // IupSetAttributeId2(mat, "MTX_LINE_ACTIVE_FLAG", 5, 7, "Test2"); // printf("Test1=%s\n", IupGetAttribute(mat, "MTX_LINE_ACTIVE_FLAG3:4")); // printf("Test2=%s\n", IupGetAttributeId2(mat, "MTX_LINE_ACTIVE_FLAG", 5, 7)); //} IupSetCallback(mat, "DROPCHECK_CB", (Icallback)dropcheck_cb); IupSetCallback(mat,"DROP_CB",(Icallback)drop); // IupSetCallback(mat,"MENUDROP_CB",(Icallback)drop); // IupSetCallback(mat, "MOUSEMOVE_CB", (Icallback)mousemove_cb); // IupSetCallback(mat,"CLICK_CB",(Icallback)click); // IupSetCallback(mat,"ENTERITEM_CB",(Icallback)enteritem_cb); IupSetCallback(mat,"TOGGLEVALUE_CB",(Icallback)togglevalue_cb); return mat; } void MatrixTest(void) { Ihandle* dlg, *box, *mat; box = IupVbox(mat = create_matrix(), NULL); IupSetAttribute(box, "MARGIN", "10x10"); // IupSetAttribute(box, "FONT", "Arial, 7"); dlg = IupDialog(box); IupSetAttribute(dlg, "TITLE", "IupMatrix Simple Test"); IupShowXY(dlg, IUP_CENTER, IUP_CENTER); // IupSetAttribute(mat, "ADDLIN", "1"); // IupSetAttribute(mat,"4:0","Teste"); // IupSetAttribute(mat, "REDRAW", "ALL"); } #ifndef BIG_TEST int main(int argc, char* argv[]) { IupOpen(&argc, &argv); IupControlsOpen(); MatrixTest(); IupMainLoop(); IupClose(); return EXIT_SUCCESS; } #endif |
Added iup-test/sample.c version [a4958dc1ab].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 | #include <stdlib.h> #include <stdio.h> #include <stdarg.h> #include <string.h> #undef __IUPDEF_H #include <iup.h> #include "iupcontrols.h" #include "iupcbs.h" #define TEST_IMAGE_SIZE 20 static unsigned char image_data_32 [TEST_IMAGE_SIZE*TEST_IMAGE_SIZE*4] = { 000,000,000,255,000,000,000,255,000,000,000,255,000,000,000,255,000,000,000,255,000,000,000,255,000,000,000,255,000,000,000,255,000,000,000,255,000,000,000,255,000,000,000,255,000,000,000,255,000,000,000,255,000,000,000,255,000,000,000,255,000,000,000,255,000,000,000,255,000,000,000,255,000,000,000,255,000,000,000,255, 000,000,000,255,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,255, 000,000,000,255,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,255, 000,000,000,255,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,255, 000,000,000,255,000,000,000,000,000,000,000,000,000,000,000,000,255,000,000,255,255,000,000,255,255,000,000,255,255,000,000,255,255,000,000,255,255,000,000,255,000,255,000,255,000,255,000,255,000,255,000,255,000,255,000,255,000,255,000,255,000,255,000,255,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,255, 000,000,000,255,000,000,000,000,000,000,000,000,000,000,000,000,255,000,000,255,255,000,000,255,255,000,000,255,255,000,000,255,255,000,000,255,255,000,000,255,000,255,000,255,000,255,000,255,000,255,000,255,000,255,000,255,000,255,000,255,000,255,000,255,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,255, 000,000,000,255,000,000,000,000,000,000,000,000,000,000,000,000,255,000,000,255,255,000,000,255,255,000,000,255,255,000,000,255,255,000,000,255,255,000,000,255,000,255,000,255,000,255,000,255,000,255,000,255,000,255,000,255,000,255,000,255,000,255,000,255,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,255, 000,000,000,255,000,000,000,000,000,000,000,000,000,000,000,000,255,000,000,255,255,000,000,255,255,000,000,255,255,000,000,255,255,000,000,255,255,000,000,255,000,255,000,255,000,255,000,255,000,255,000,255,000,255,000,255,000,255,000,255,000,255,000,255,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,255, 000,000,000,255,000,000,000,000,000,000,000,000,000,000,000,000,255,000,000,255,255,000,000,255,255,000,000,255,255,000,000,255,255,000,000,255,255,000,000,255,000,255,000,255,000,255,000,255,000,255,000,255,000,255,000,255,000,255,000,255,000,255,000,255,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,255, 000,000,000,255,000,000,000,000,000,000,000,000,000,000,000,000,255,000,000,255,255,000,000,255,255,000,000,255,255,000,000,255,255,000,000,255,255,000,000,255,000,255,000,255,000,255,000,255,000,255,000,255,000,255,000,255,000,255,000,255,000,255,000,255,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,255, 000,000,000,255,000,000,000,000,000,000,000,000,000,000,000,000,000,000,255,255,000,000,255,255,000,000,255,255,000,000,255,255,000,000,255,255,000,000,255,255,255,255,255,192,255,255,255,192,255,255,255,192,255,255,255,192,255,255,255,192,255,255,255,192,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,255, 000,000,000,255,000,000,000,000,000,000,000,000,000,000,000,000,000,000,255,255,000,000,255,255,000,000,255,255,000,000,255,255,000,000,255,255,000,000,255,255,255,255,255,192,255,255,255,192,255,255,255,192,255,255,255,192,255,255,255,192,255,255,255,192,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,255, 000,000,000,255,000,000,000,000,000,000,000,000,000,000,000,000,000,000,255,255,000,000,255,255,000,000,255,255,000,000,255,255,000,000,255,255,000,000,255,255,255,255,255,192,255,255,255,192,255,255,255,192,255,255,255,192,255,255,255,192,255,255,255,192,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,255, 000,000,000,255,000,000,000,000,000,000,000,000,000,000,000,000,000,000,255,255,000,000,255,255,000,000,255,255,000,000,255,255,000,000,255,255,000,000,255,255,255,255,255,192,255,255,255,192,255,255,255,192,255,255,255,192,255,255,255,192,255,255,255,192,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,255, 000,000,000,255,000,000,000,000,000,000,000,000,000,000,000,000,000,000,255,255,000,000,255,255,000,000,255,255,000,000,255,255,000,000,255,255,000,000,255,255,255,255,255,192,255,255,255,192,255,255,255,192,255,255,255,192,255,255,255,192,255,255,255,192,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,255, 000,000,000,255,000,000,000,000,000,000,000,000,000,000,000,000,000,000,255,255,000,000,255,255,000,000,255,255,000,000,255,255,000,000,255,255,000,000,255,255,255,255,255,192,255,255,255,192,255,255,255,192,255,255,255,192,255,255,255,192,255,255,255,192,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,255, 000,000,000,255,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,255, 000,000,000,255,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,255, 000,000,000,255,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,255, 000,000,000,255,000,000,000,255,000,000,000,255,000,000,000,255,000,000,000,255,000,000,000,255,000,000,000,255,000,000,000,255,000,000,000,255,000,000,000,255,000,000,000,255,000,000,000,255,000,000,000,255,000,000,000,255,000,000,000,255,000,000,000,255,000,000,000,255,000,000,000,255,000,000,000,255,000,000,000,255, }; static int drop(Ihandle *self, Ihandle *drop, int lin, int col) { printf("drop_cb(%d, %d)\n", lin, col); if(lin == 3 && col == 1) { IupSetAttribute(drop, "1", "A - Test of Very Big String for Dropdown!"); IupSetAttribute(drop, "2", "B"); IupSetAttribute(drop, "3", "C"); IupSetAttribute(drop, "4", "XXX"); IupSetAttribute(drop, "5", "5"); IupSetAttribute(drop, "6", "6"); IupSetAttribute(drop, "7", "7"); IupSetAttribute(drop, "8", NULL); IupSetAttribute(drop, "VALUE", "4"); return IUP_DEFAULT; } return IUP_IGNORE; } static int togglevalue_cb(Ihandle *self, int lin, int col, int value) { printf("togglevalue_cb(%d, %d)=%d\n", lin, col, value); return IUP_DEFAULT; } static Ihandle* load_image_Tecgraf(void) { unsigned char imgdata[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 88, 95, 108, 1, 90, 100, 117, 99, 123, 138, 166, 126, 137, 152, 181, 60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 95, 105, 123, 147, 122, 137, 165, 255, 136, 152, 183, 255, 132, 149, 179, 250, 133, 149, 178, 69, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 92, 100, 115, 43, 111, 125, 150, 253, 140, 158, 190, 255, 135, 151, 182, 255, 132, 149, 179, 255, 131, 147, 177, 217, 153, 164, 188, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 102, 113, 134, 148, 134, 151, 182, 255, 137, 154, 185, 255, 115, 129, 154, 252, 114, 128, 155, 255, 130, 146, 175, 255, 132, 147, 175, 71, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 158, 159, 162, 3, 108, 121, 145, 230, 144, 162, 195, 255, 137, 154, 185, 197, 74, 79, 86, 45, 41, 46, 55, 246, 120, 134, 162, 255, 129, 145, 174, 156, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 95, 101, 113, 48, 124, 139, 167, 255, 144, 161, 194, 255, 138, 155, 186, 67, 0, 0, 0, 0, 49, 54, 62, 150, 87, 98, 118, 255, 128, 144, 173, 223, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 102, 113, 132, 105, 137, 154, 185, 255, 139, 156, 188, 231, 143, 159, 187, 3, 0, 0, 0, 0, 64, 68, 76, 61, 70, 79, 95, 255, 127, 143, 172, 254, 134, 149, 175, 25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 109, 121, 142, 153, 141, 159, 191, 255, 139, 156, 188, 164, 0, 0, 0, 0, 0, 0, 0, 0, 79, 82, 87, 3, 69, 77, 92, 241, 122, 137, 165, 255, 127, 142, 170, 70, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 110, 122, 146, 191, 145, 163, 196, 255, 139, 156, 188, 107, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 77, 86, 101, 190, 115, 129, 156, 255, 126, 141, 170, 113, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 112, 125, 149, 227, 150, 168, 201, 255, 141, 157, 188, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 82, 91, 107, 144, 113, 127, 153, 255, 125, 140, 169, 144, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 163, 165, 167, 2, 112, 125, 150, 252, 155, 173, 203, 255, 143, 159, 189, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 94, 110, 109, 114, 128, 155, 255, 125, 140, 168, 175, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 160, 167, 181, 1, 120, 130, 149, 33, 48, 53, 59, 69, 43, 46, 52, 100, 50, 54, 59, 137, 116, 130, 156, 255, 155, 171, 201, 255, 105, 118, 142, 155, 104, 117, 141, 151, 105, 118, 141, 151, 105, 118, 142, 151, 101, 113, 136, 185, 111, 124, 150, 255, 116, 130, 156, 220, 112, 125, 148, 95, 115, 127, 150, 67, 123, 134, 156, 33, 168, 176, 190, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 119, 129, 147, 5, 109, 121, 142, 71, 106, 118, 140, 140, 105, 117, 140, 197, 107, 120, 144, 242, 120, 135, 162, 255, 123, 137, 163, 255, 44, 49, 58, 255, 28, 32, 39, 255, 125, 139, 164, 255, 150, 167, 197, 255, 138, 155, 186, 255, 131, 148, 178, 255, 125, 141, 170, 255, 119, 134, 162, 255, 114, 128, 154, 255, 108, 122, 147, 255, 104, 117, 141, 255, 102, 115, 138, 255, 103, 116, 139, 255, 107, 120, 145, 255, 111, 124, 149, 245, 113, 126, 151, 200, 113, 127, 152, 140, 116, 129, 154, 71, 122, 135, 158, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 118, 128, 145, 14, 106, 118, 140, 130, 104, 116, 139, 234, 105, 118, 142, 255, 128, 144, 173, 255, 147, 165, 199, 255, 157, 177, 213, 255, 150, 168, 202, 255, 140, 156, 187, 229, 41, 45, 52, 196, 39, 43, 51, 183, 130, 143, 168, 255, 144, 161, 192, 233, 109, 122, 145, 109, 105, 116, 138, 109, 99, 110, 130, 109, 92, 103, 123, 109, 91, 100, 117, 145, 97, 109, 131, 255, 95, 106, 128, 248, 74, 83, 97, 193, 64, 72, 85, 227, 56, 63, 75, 255, 55, 62, 75, 255, 65, 73, 88, 255, 90, 101, 121, 255, 111, 125, 150, 255, 114, 128, 154, 236, 116, 129, 155, 130, 127, 140, 165, 16, 0, 0, 0, 0, 95, 101, 113, 22, 103, 115, 137, 220, 103, 116, 140, 255, 110, 123, 148, 255, 146, 165, 198, 255, 147, 165, 197, 232, 142, 158, 188, 147, 131, 144, 169, 78, 115, 123, 139, 20, 0, 0, 0, 0, 0, 0, 0, 0, 91, 97, 108, 68, 128, 142, 167, 255, 144, 162, 193, 212, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 95, 100, 107, 31, 120, 135, 163, 255, 133, 150, 180, 231, 0, 0, 0, 0, 0, 0, 0, 0, 86, 89, 93, 20, 50, 54, 61, 73, 37, 40, 46, 141, 33, 36, 42, 230, 46, 52, 63, 255, 107, 120, 144, 255, 116, 130, 157, 255, 118, 133, 159, 223, 132, 147, 174, 24, 76, 83, 95, 114, 104, 117, 140, 255, 105, 117, 141, 255, 118, 133, 160, 253, 139, 155, 184, 116, 134, 143, 161, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 93, 100, 110, 74, 122, 137, 163, 255, 143, 160, 191, 200, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 110, 114, 120, 31, 123, 138, 166, 255, 136, 153, 183, 228, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 90, 93, 97, 5, 42, 45, 51, 111, 86, 97, 117, 253, 118, 133, 160, 255, 119, 133, 161, 255, 133, 149, 180, 116, 46, 50, 56, 109, 67, 76, 91, 255, 105, 118, 142, 255, 107, 120, 145, 254, 112, 125, 149, 131, 127, 139, 161, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 93, 98, 109, 74, 116, 130, 156, 255, 142, 159, 190, 200, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 112, 115, 122, 31, 128, 143, 172, 255, 141, 157, 185, 228, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 124, 137, 163, 7, 122, 136, 162, 122, 120, 135, 162, 254, 121, 136, 164, 255, 136, 152, 184, 255, 126, 141, 168, 116, 71, 74, 79, 17, 31, 35, 41, 206, 42, 47, 57, 255, 77, 87, 105, 255, 103, 116, 140, 255, 110, 124, 149, 239, 112, 125, 150, 157, 115, 128, 153, 89, 122, 134, 158, 30, 147, 158, 177, 2, 0, 0, 0, 0, 81, 87, 96, 65, 109, 123, 148, 255, 141, 158, 190, 212, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 98, 103, 112, 31, 135, 151, 180, 255, 141, 156, 183, 231, 0, 0, 0, 0, 153, 164, 183, 1, 134, 147, 171, 30, 124, 138, 165, 84, 123, 138, 165, 154, 122, 137, 164, 235, 127, 143, 172, 255, 140, 157, 189, 255, 144, 162, 195, 255, 129, 144, 172, 218, 126, 138, 161, 22, 0, 0, 0, 0, 64, 68, 73, 7, 39, 43, 49, 118, 32, 36, 42, 225, 30, 35, 42, 255, 50, 57, 68, 255, 72, 81, 97, 255, 91, 102, 123, 255, 105, 118, 142, 255, 113, 127, 152, 240, 115, 129, 155, 204, 111, 124, 149, 196, 111, 125, 150, 255, 126, 141, 170, 234, 119, 133, 159, 120, 120, 134, 160, 116, 121, 135, 161, 117, 121, 135, 162, 119, 116, 130, 155, 152, 127, 142, 170, 255, 125, 140, 168, 248, 123, 138, 166, 199, 130, 145, 173, 235, 140, 155, 183, 255, 143, 160, 190, 255, 143, 161, 193, 255, 147, 165, 199, 255, 145, 164, 197, 255, 132, 148, 177, 230, 127, 140, 166, 126, 124, 134, 151, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 138, 141, 144, 3, 55, 58, 63, 58, 37, 40, 46, 126, 34, 38, 44, 184, 34, 38, 44, 235, 35, 39, 47, 254, 49, 55, 66, 255, 64, 72, 87, 255, 77, 87, 104, 255, 88, 98, 118, 255, 96, 108, 130, 255, 103, 116, 139, 255, 108, 122, 147, 255, 113, 127, 153, 255, 118, 133, 160, 255, 124, 140, 168, 255, 133, 148, 176, 255, 141, 156, 183, 255, 146, 161, 187, 255, 144, 159, 186, 255, 131, 146, 174, 254, 127, 141, 168, 237, 126, 141, 168, 188, 123, 137, 162, 131, 112, 123, 143, 61, 128, 132, 140, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 91, 94, 98, 19, 64, 68, 73, 56, 53, 57, 65, 82, 62, 67, 76, 116, 66, 74, 89, 255, 95, 107, 129, 255, 80, 88, 103, 155, 81, 90, 105, 151, 86, 95, 112, 151, 95, 104, 122, 151, 98, 109, 128, 180, 124, 139, 166, 255, 109, 122, 146, 218, 100, 110, 128, 84, 96, 104, 118, 56, 105, 109, 117, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 173, 174, 176, 2, 74, 83, 98, 252, 131, 147, 178, 255, 140, 155, 184, 29, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 122, 134, 157, 114, 151, 169, 203, 255, 123, 138, 165, 174, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 76, 90, 224, 122, 137, 165, 255, 136, 152, 182, 69, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 125, 139, 165, 147, 146, 164, 198, 255, 122, 137, 165, 144, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 62, 69, 81, 191, 110, 124, 149, 255, 134, 151, 181, 113, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 143, 170, 193, 142, 160, 192, 255, 122, 137, 164, 111, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 58, 63, 74, 150, 94, 105, 127, 255, 133, 149, 179, 166, 0, 0, 0, 0, 0, 0, 0, 0, 115, 119, 128, 5, 130, 145, 174, 242, 137, 154, 186, 255, 125, 139, 166, 70, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 54, 58, 66, 102, 72, 81, 97, 255, 132, 148, 178, 236, 148, 161, 187, 5, 0, 0, 0, 0, 110, 121, 140, 64, 140, 157, 189, 255, 127, 142, 171, 254, 131, 144, 169, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 62, 65, 71, 43, 47, 52, 63, 255, 127, 143, 172, 255, 132, 148, 177, 75, 0, 0, 0, 0, 121, 134, 158, 160, 139, 156, 188, 255, 123, 138, 165, 223, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 154, 156, 158, 1, 36, 39, 46, 227, 106, 119, 143, 255, 130, 145, 175, 203, 114, 125, 147, 51, 123, 138, 166, 247, 131, 147, 177, 255, 123, 138, 165, 151, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 37, 41, 47, 143, 68, 77, 93, 255, 128, 144, 174, 255, 126, 141, 170, 252, 129, 145, 174, 255, 123, 138, 166, 255, 127, 141, 167, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 65, 68, 73, 40, 34, 38, 46, 250, 117, 131, 158, 255, 126, 142, 171, 255, 124, 140, 168, 255, 125, 139, 166, 214, 140, 152, 172, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 41, 44, 50, 134, 58, 66, 79, 255, 123, 138, 166, 255, 123, 138, 166, 250, 127, 140, 165, 66, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 154, 156, 158, 1, 46, 50, 55, 83, 82, 89, 102, 123, 106, 116, 136, 51, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; Ihandle* image = IupImageRGBA(32, 32, imgdata); return image; } static Ihandle* load_image_LogoTecgraf(void) { unsigned char imgdata[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 108, 120, 143, 125, 132, 148, 178, 173, 133, 149, 178, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100, 110, 130, 48, 130, 147, 177, 254, 124, 139, 167, 254, 131, 147, 176, 137, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 115, 128, 153, 134, 142, 159, 191, 194, 47, 52, 61, 110, 114, 128, 154, 222, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 143, 172, 192, 140, 156, 188, 99, 65, 69, 76, 16, 97, 109, 131, 251, 129, 144, 172, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 131, 147, 175, 232, 140, 157, 188, 43, 0, 0, 0, 0, 100, 112, 134, 211, 126, 141, 169, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 72, 78, 88, 26, 48, 52, 57, 60, 135, 150, 178, 254, 108, 121, 145, 83, 105, 118, 142, 76, 106, 119, 143, 201, 118, 133, 159, 122, 117, 129, 152, 25, 168, 176, 190, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 118, 128, 145, 3, 104, 117, 140, 92, 114, 127, 152, 180, 131, 147, 177, 237, 133, 149, 178, 249, 38, 42, 50, 222, 137, 152, 180, 249, 126, 142, 170, 182, 114, 128, 154, 182, 104, 117, 140, 227, 95, 107, 128, 238, 83, 93, 112, 248, 84, 95, 113, 239, 104, 117, 141, 180, 115, 129, 155, 93, 127, 140, 165, 4, 98, 109, 130, 153, 109, 123, 147, 254, 145, 163, 195, 153, 138, 154, 182, 56, 115, 123, 138, 5, 92, 99, 109, 35, 134, 149, 177, 230, 0, 0, 0, 0, 0, 0, 0, 0, 120, 133, 159, 143, 135, 151, 181, 115, 86, 89, 93, 5, 41, 45, 51, 54, 40, 45, 53, 150, 107, 120, 144, 254, 122, 137, 164, 154, 51, 57, 66, 147, 83, 93, 112, 255, 108, 121, 145, 159, 113, 126, 151, 62, 123, 136, 159, 8, 87, 93, 103, 35, 125, 141, 169, 230, 0, 0, 0, 0, 0, 0, 0, 0, 129, 143, 169, 143, 140, 156, 184, 115, 134, 147, 172, 8, 124, 138, 165, 60, 124, 139, 167, 155, 131, 147, 177, 255, 131, 147, 176, 153, 64, 68, 73, 2, 36, 39, 45, 86, 41, 46, 54, 173, 60, 67, 80, 232, 75, 84, 101, 251, 89, 100, 120, 228, 105, 118, 142, 250, 110, 123, 148, 187, 118, 132, 158, 187, 126, 141, 169, 229, 134, 149, 177, 239, 136, 152, 179, 250, 136, 152, 181, 234, 139, 156, 186, 175, 130, 145, 173, 90, 124, 134, 151, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 71, 74, 79, 19, 60, 64, 73, 50, 92, 103, 124, 254, 86, 95, 111, 84, 90, 100, 117, 76, 126, 141, 168, 201, 113, 126, 150, 119, 99, 105, 117, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 93, 105, 125, 231, 135, 151, 181, 46, 0, 0, 0, 0, 137, 154, 184, 212, 123, 137, 164, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 74, 83, 98, 191, 133, 149, 179, 102, 111, 121, 139, 17, 134, 150, 180, 252, 126, 140, 166, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 43, 48, 57, 132, 121, 136, 164, 197, 121, 135, 161, 115, 130, 146, 175, 221, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 43, 47, 52, 46, 87, 98, 118, 254, 126, 142, 170, 254, 124, 139, 166, 135, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 51, 57, 67, 118, 115, 128, 152, 170, 127, 140, 164, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; Ihandle* image = IupImageRGBA(16, 16, imgdata); return image; } static unsigned char img_bits1[] = { 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1 ,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1 ,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1 ,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1 ,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,1 ,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,1,1 ,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,1,1,1 ,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1 ,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2 ,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2 ,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2 ,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2 ,2,2,2,0,2,0,2,0,2,2,0,2,2,2,0,0,0,2,2,2,0,0,2,0,2,2,0,0,0,2,2,2 ,2,2,2,0,2,0,0,2,0,0,2,0,2,0,2,2,2,0,2,0,2,2,0,0,2,0,2,2,2,0,2,2 ,2,2,2,0,2,0,2,2,0,2,2,0,2,2,2,2,2,0,2,0,2,2,2,0,2,0,2,2,2,0,2,2 ,2,2,2,0,2,0,2,2,0,2,2,0,2,2,0,0,0,0,2,0,2,2,2,0,2,0,0,0,0,0,2,2 ,2,2,2,0,2,0,2,2,0,2,2,0,2,0,2,2,2,0,2,0,2,2,2,0,2,0,2,2,2,2,2,2 ,2,2,2,0,2,0,2,2,0,2,2,0,2,0,2,2,2,0,2,0,2,2,0,0,2,0,2,2,2,0,2,2 ,2,2,2,0,2,0,2,2,0,2,2,0,2,2,0,0,0,0,2,2,0,0,2,0,2,2,0,0,0,2,2,2 ,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,2 ,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,0,2,2,2,2,2,2,2,2 ,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,2,2,2,2,2,2,2,2,2 ,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2 ,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2 ,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1 ,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1 ,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1 ,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1 ,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 ,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 ,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 ,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 }; static unsigned char img_bits2[] = { 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2 ,2,2,2,2,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,2 ,2,2,2,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,2,2 ,2,2,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,2,2,2 ,2,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,2,2,2,2 ,2,2,2,2,2,2,2,2,2,2,3,3,3,3,1,1,3,3,3,3,3,3,3,3,3,3,2,2,2,2,2,2 ,2,2,2,2,2,2,2,2,2,3,3,3,3,3,1,1,3,3,3,3,3,3,3,3,3,2,2,2,2,2,2,2 ,2,2,2,2,2,2,2,2,3,3,3,3,3,3,1,1,3,3,3,3,3,3,3,3,2,2,2,2,2,2,2,2 ,3,3,3,3,3,3,3,3,3,3,3,3,3,3,1,1,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3 ,3,3,3,3,3,3,3,3,3,3,3,3,3,3,1,1,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3 ,3,3,3,0,3,3,3,3,3,3,3,3,3,3,1,1,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3 ,3,3,3,0,3,3,3,3,3,3,3,3,3,3,1,1,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3 ,3,3,3,0,3,0,3,0,3,3,0,3,3,3,1,1,0,3,3,3,0,0,3,0,3,3,0,0,0,3,3,3 ,3,3,3,0,3,0,0,3,0,0,3,0,3,0,1,1,3,0,3,0,3,3,0,0,3,0,3,3,3,0,3,3 ,3,3,3,0,3,0,3,3,0,3,3,0,3,3,1,1,3,0,3,0,3,3,3,0,3,0,3,3,3,0,3,3 ,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 ,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 ,3,3,3,0,3,0,3,3,0,3,3,0,3,0,1,1,3,0,3,0,3,3,0,0,3,0,3,3,3,0,3,3 ,3,3,3,0,3,0,3,3,0,3,3,0,3,3,1,1,0,0,3,3,0,0,3,0,3,3,0,0,0,3,3,3 ,3,3,3,3,3,3,3,3,3,3,3,3,3,3,1,1,3,3,3,3,3,3,3,0,3,3,3,3,3,3,3,3 ,3,3,3,3,3,3,3,3,3,3,3,3,3,3,1,1,3,3,3,0,3,3,3,0,3,3,3,3,3,3,3,3 ,3,3,3,3,3,3,3,3,3,3,3,3,3,3,1,1,3,3,3,3,0,0,0,3,3,3,3,3,3,3,3,3 ,3,3,3,3,3,3,3,3,3,3,3,3,3,3,1,1,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3 ,3,3,3,3,3,3,3,3,3,3,3,3,3,3,1,1,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3 ,2,2,2,2,2,2,2,3,3,3,3,3,3,3,1,1,3,3,3,3,3,2,2,2,2,2,2,2,2,2,2,2 ,2,2,2,2,2,2,3,3,3,3,3,3,3,3,1,1,3,3,3,3,2,2,2,2,2,2,2,2,2,2,2,2 ,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,2,2,2,2,2,2,2,2,2,2,2,2 ,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,2,2,2,2,2,2,2,2,2,2,2,2,2 ,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2 ,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2 ,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2 ,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2 }; static int copydata_cb(Ihandle* ih, char* value, int size) { printf("COPYDATA(%s, %d)\n", value, size); return IUP_DEFAULT; } static int valuechanged_cb(Ihandle *ih) { printf("VALUECHANGED_CB(%s)=%s\n", IupGetClassName(ih), IupGetAttribute(ih, "VALUE")); return IUP_DEFAULT; } static int getfocus_cb(Ihandle *ih) { printf("GETFOCUS_CB(%s)\n", IupGetClassName(ih)); return IUP_DEFAULT; } static int killfocus_cb(Ihandle *ih) { printf("KILLFOCUS_CB(%s)\n", IupGetClassName(ih)); return IUP_DEFAULT; } static int leavewindow_cb(Ihandle *ih) { printf("LEAVEWINDOW_CB(%s)\n", IupGetClassName(ih)); return IUP_DEFAULT; } static int enterwindow_cb(Ihandle *ih) { printf("ENTERWINDOW_CB(%s)\n", IupGetClassName(ih)); return IUP_DEFAULT; } /* Internal SDK function */ char *iupKeyCodeToName(int code); static int k_any(Ihandle *ih, int c) { if (iup_isprint(c)) printf("K_ANY(%s, %d = %s \'%c\')\n", IupGetClassName(ih), c, iupKeyCodeToName(c), (char)c); else printf("K_ANY(%s, %d = %s)\n", IupGetClassName(ih), c, iupKeyCodeToName(c)); if (c==K_r) { IupRecordInput("inputtest.iup", IUP_RECTEXT); return IUP_IGNORE; } //IUP_RECBINARY, IUP_RECTEXT if (c==K_s) { IupRecordInput(NULL, 0); IupPlayInput(NULL); return IUP_IGNORE; } if (c==K_p) { IupPlayInput("inputtest.iup"); return IUP_IGNORE; } return IUP_CONTINUE; } static int help_cb(Ihandle* ih) { printf("HELP_CB(%s)\n", IupGetClassName(ih)); return IUP_DEFAULT; } static void show_menu(Ihandle* ih) { int x, y; Ihandle* menu_file = IupMenu( IupSetAttributes(IupItem("Item with Image", "item_cb"), "IMAGE=image_tec"), IupSetAttributes(IupItem("Toggle using VALUE", NULL), "VALUE=ON, KEY=K_V"), IupSetAttributes(IupItem("Auto &Toggle", "item_cb"), "AUTOTOGGLE=YES, VALUE=OFF, IMAGE=image_test, IMPRESS=image_test_pressed"), IupSeparator(), IupItem("E&xit (Close)", NULL), NULL); Ihandle* menu = IupMenu( IupSetAttributes(IupSubmenu("Submenu", menu_file), "KEY=K_S, IMAGE=image_tec"), IupItem("Item", "item_cb"), IupSetAttributes(IupItem("Item", "item_cb"), "VALUE=ON"), IupSetAttributes(IupItem("Item", "item_cb"), "KEY=K_I, IMAGE=image_tec"), NULL); x = IupGetInt(ih, "X"); y = IupGetInt(ih, "Y") + IupGetInt2(ih, "RASTERSIZE"); IupPopup(menu, x, y); IupDestroy(menu); } static int action1_cb(Ihandle* ih) { // IupSetAttribute(IupGetDialog(ih), "BACKGROUND", "255 128 128"); show_menu(ih); return IUP_DEFAULT; } static int action2_cb(Ihandle* ih) { IupSetAttribute(IupGetDialog(ih), "BGCOLOR", "0 128 0"); return IUP_DEFAULT; } static int action3_cb(Ihandle* ih) { printf("ACTION3\n"); // IupSetAttribute(IupGetChild(IupGetDialog(ih), 0), "BGCOLOR", "128 0 0"); return IUP_DEFAULT; } static Ihandle* set_callbacks(Ihandle* ih) { IupSetCallback(ih, "VALUECHANGED_CB", (Icallback)valuechanged_cb); // IupSetCallback(ih, "GETFOCUS_CB", (Icallback)getfocus_cb); // IupSetCallback(ih, "KILLFOCUS_CB", (Icallback)killfocus_cb); // IupSetCallback(ih, "ENTERWINDOW_CB", (Icallback)enterwindow_cb); // IupSetCallback(ih, "LEAVEWINDOW_CB", (Icallback)leavewindow_cb); IupSetCallback(ih, "K_ANY", (Icallback)k_any); // IupSetCallback(ih, "HELP_CB", (Icallback)help_cb); return ih; } int btn_big_button_cb(Ihandle *self, int button, int press) { printf("BUTTON_CB(button=%c, press=%d)\n", button, press); return IUP_DEFAULT; } static void globalkeypress_cb(int code, int pressed) { printf("GLOBALKEYPRESS_CB(code=%s, pressed=%d)\n", iupKeyCodeToName(code), pressed); } static void globalmotion_cb(int x, int y, char* status) { printf("GLOBALMOTION_CB(x=%d, y=%d, status=%s)\n", x, y, status); } static void globalbutton_cb(int button, int pressed, int x, int y, char* status) { printf("GLOBALBUTTON_CB(button=%c, pressed=%d, x=%d, y=%d, status=%s)\n", (char)button, pressed, x, y, status); } static void globalwheel_cb(float delta,int x, int y, char* status) { printf("GLOBALWHEEL_CB(delta=%g, x=%d, y=%d, status=%s)\n", delta, x, y, status); } int btn_image_button_cb( Ihandle *self,int b, int e ) { /* If the left button changed its state... */ if( b == IUP_BUTTON1 ) { /* IUP handles */ Ihandle* text; /* Recovers "text" handle */ text = IupGetHandle( "text" ); /* If the button was pressed... */ if(e == 1) { /* Sets text's value */ IupSetAttribute( text, "VALUE", "Red button pressed" ); } /* else the button was released */ else { /* Sets text's value */ IupSetAttribute( text, "VALUE", "Red button released" ); } } /* Executed function successfully */ return IUP_DEFAULT; } void SampleTest(void) { Ihandle *mnu, *_hbox_1, *_cnv_1, *_vbox_1, *dlg, *img, *_frm_1, *_frm_2, *_frm_3, *_frm_4, *_frm_5, *pbar, *val, *tabs, *_list_1, *_list_2, *_list_3, *_text_1, *_ml_1, *tree; //img = IupImage(32,32, img_bits1); //IupSetHandle ("img1", img); //IupSetAttribute (img, "0", "0 0 0"); //IupSetAttribute (img, "1", "BGCOLOR"); //IupSetAttribute (img, "2", "255 0 0"); img = load_image_Tecgraf(); IupSetHandle ("img1", img); img = IupImage(32,32, img_bits2); IupSetHandle ("img2", img); IupSetAttribute (img, "0", "0 0 0"); IupSetAttribute (img, "1", "0 255 0"); IupSetAttribute (img, "2", "BGCOLOR"); IupSetAttribute (img, "3", "255 0 0"); mnu = IupMenu( IupSubmenu("IupSubmenu 1", IupMenu( IupSetAttributes(IupItem("IupItem 1 Checked", NULL), "VALUE=ON"), IupSeparator(), IupSetAttributes(IupItem("IupItem 2 Disabled", NULL), "VALUE=ON"), NULL)), IupItem("IupItem 3", NULL), IupItem("IupItem 4", NULL), NULL); IupSetHandle("mnu",mnu); _frm_1 = IupFrame( IupVbox( set_callbacks(IupSetAttributes(IupButton("Button Text", NULL), "PADDING=5x5")), IupSetCallbacks(set_callbacks(IupSetAttributes(IupButton("Text", NULL), "IMAGE=img1, PADDING=5x5")),"ACTION", action1_cb, NULL), IupSetCallbacks(set_callbacks(IupSetAttributes(IupButton(NULL, NULL), "IMAGE=img1")),"ACTION", action2_cb, NULL), IupSetCallbacks(set_callbacks(IupSetAttributes(IupButton("Text", NULL), "IMAGE=img1")),"BUTTON_CB", (Icallback)btn_big_button_cb, NULL), IupSetCallbacks(set_callbacks(IupSetAttributes(IupButton("", NULL), "IMAGE=img1,IMPRESS=img2")),"ACTION", action3_cb, NULL), IupSetCallbacks(set_callbacks(IupSetAttributes(IupButton(NULL, NULL), "BGCOLOR=\"255 0 128\", SIZE=20x10")),"ACTION", action3_cb, NULL), NULL)); IupSetAttribute(_frm_1,"TITLE","IupButton"); _frm_2 = IupFrame( IupVbox( IupLabel("Label Text"), IupSetAttributes(IupLabel(NULL), "SEPARATOR=HORIZONTAL, MAXSIZE=150, NAME=SAMP_SEP"), IupSetAttributes(IupLabel(NULL), "IMAGE=img1"), NULL)); IupSetAttribute(_frm_2,"TITLE","IupLabel"); _frm_3 = IupFrame( IupVbox( set_callbacks(IupSetAttributes(IupToggle("Toggle Text", NULL), "VALUE=ON")), set_callbacks(IupSetAttributes(IupToggle(NULL, NULL), "VALUE=ON,IMAGE=img1,IMPRESS=img2")), set_callbacks(IupSetAttributes(IupToggle(NULL, NULL), "VALUE=ON,IMAGE=img1")), IupSetAttributes(IupFrame(IupRadio(IupVbox( set_callbacks(IupToggle("Toggle Text", NULL)), set_callbacks(IupToggle("Toggle Text", NULL)), NULL))), "TITLE=IupRadio"), NULL)); IupSetAttribute(_frm_3,"TITLE","IupToggle"); _text_1 = IupText( NULL); IupSetAttribute(_text_1,"VALUE","Single Line Text"); IupSetAttribute(_text_1,"SIZE","80x"); _ml_1 = IupMultiLine( NULL); IupSetAttribute(_ml_1,"VALUE","Multiline Text\nSecond Line\nThird Line"); IupSetAttribute(_ml_1,"EXPAND","YES"); IupSetAttribute(_ml_1,"SIZE","80x40"); _frm_4 = IupFrame(IupVbox( set_callbacks(_text_1), set_callbacks(_ml_1), NULL)); IupSetAttribute(_frm_4,"TITLE","IupText"); _list_1 = IupList( NULL); // IupSetAttribute(_list_1,"EXPAND","YES"); IupSetAttribute(_list_1,"VALUE","1"); IupSetAttribute(_list_1,"1","Item 1 Text"); IupSetAttribute(_list_1,"2","Item 2 Text"); IupSetAttribute(_list_1,"3","Item 3 Text"); IupSetAttribute(_list_1,"TIP","List 1"); _list_2 = IupList( NULL); IupSetAttribute(_list_2,"DROPDOWN","YES"); // IupSetAttribute(_list_2,"EXPAND","YES"); IupSetAttribute(_list_2,"VALUE","2"); IupSetAttribute(_list_2,"1","Item 1 Text"); IupSetAttribute(_list_2,"2","Item 2 Text"); IupSetAttribute(_list_2,"3","Item 3 Text"); IupSetAttribute(_list_2,"TIP","List 2"); _list_3 = IupList( NULL); IupSetAttribute(_list_3,"EDITBOX","YES"); // IupSetAttribute(_list_3,"EXPAND","YES"); IupSetAttribute(_list_3,"VALUE","3"); IupSetAttribute(_list_3,"1","Item 1 Text"); IupSetAttribute(_list_3,"2","Item 2 Text"); IupSetAttribute(_list_3,"3","Item 3 Text"); IupSetAttribute(_list_3,"TIP","List 3"); _frm_5 = IupFrame(IupVbox( set_callbacks(_list_1), set_callbacks(_list_2), set_callbacks(_list_3), NULL)); IupSetAttribute(_frm_5,"TITLE","IupList"); _hbox_1 = IupHbox( _frm_1, _frm_2, _frm_3, _frm_4, _frm_5, NULL); val = IupVal(NULL); set_callbacks(val); pbar = IupProgressBar(); IupSetAttribute(pbar, "VALUE", "0.5"); set_callbacks(pbar); tabs = IupTabs(IupVbox(IupLabel(""), NULL), IupVbox(IupFill(), NULL), IupVbox(IupFill(), NULL), NULL); IupSetAttribute(tabs,"TABTITLE0","Tab Title 0"); IupSetAttribute(tabs,"TABTITLE1","Tab Title 1"); IupSetAttributeHandle(tabs,"TABIMAGE1", load_image_LogoTecgraf()); IupSetAttribute(tabs,"TABTITLE2","Tab Title 2"); IupSetAttribute(tabs,"RASTERSIZE","300x50"); // IupSetAttribute(tabs,"TABPADDING","5x5"); set_callbacks(tabs); tree = IupTree(); IupSetAttribute(tree, "SHOWRENAME", "YES"); IupSetAttribute(tree,"RASTERSIZE","100x150"); set_callbacks(tree); _cnv_1 = IupCanvas(NULL); IupSetAttribute(_cnv_1,"BGCOLOR","128 255 0"); IupSetAttribute(_cnv_1,"SCROLLBAR","YES"); IupSetAttribute(_cnv_1,"EXPAND","HORIZONTAL"); IupSetAttribute(_cnv_1,"RASTERSIZE","x100"); // IupSetAttribute(_cnv_1,"CANFOCUS","NO"); set_callbacks(_cnv_1); _vbox_1 = IupVbox( _hbox_1, IupHbox(IupSetAttributes(IupFrame(IupHbox(val, NULL)), "TITLE=IupVal"), IupSetAttributes(IupFrame(IupHbox(pbar, NULL)), "TITLE=IupProgressBar"), IupSetAttributes(IupFrame(IupHbox(tabs, NULL)), "TITLE=IupTabs"), NULL), IupHbox(IupSetAttributes(IupFrame(IupHbox(_cnv_1, NULL)), "TITLE=IupCanvas"), IupSetAttributes(IupFrame(IupHbox(tree, NULL)), "TITLE=IupTree"), NULL), NULL); IupSetAttribute(_vbox_1,"MARGIN","5x5"); IupSetAttribute(_vbox_1,"GAP","5"); dlg = IupDialog(_vbox_1); IupSetHandle("dlg",dlg); IupSetAttribute(dlg,"MENU","mnu"); IupSetAttribute(dlg,"TITLE","Iup Sample Dialog Title"); // IupSetAttribute(dlg,"COMPOSITED","YES"); /* Windows Only */ // IupSetAttribute(dlg, "OPACITY", "192"); // IupSetAttribute(dlg, "BGCOLOR", "173 177 194"); // Motif BGCOLOR for documentation // IupSetAttribute(_vbox_1, "BGCOLOR", "92 92 255"); // IupSetAttribute(dlg, "BGCOLOR", "92 92 255"); // IupSetAttribute(dlg, "BACKGROUND", "200 10 80"); //IupSetGlobal("DLGBGCOLOR", "92 92 255"); //IupSetGlobal("TXTFGCOLOR", "255 92 92"); //IupSetGlobal("TXTBGCOLOR", "92 92 255"); // IupSetAttribute(dlg, "FONT", "Helvetica, 24"); // IupSetAttribute(dlg, "FONT", "-*-helvetica-*-r-*-*-18-*-*-*-*-*-*-*"); // IupSetAttribute(box, "FGCOLOR", "255 0 0"); // IupSetAttribute(dlg,"RASTERSIZE","1000x800"); IupSetCallback(dlg, "COPYDATA_CB", (Icallback)copydata_cb); //IupSetGlobal("INPUTCALLBACKS", "Yes"); //IupSetFunction("GLOBALKEYPRESS_CB", (Icallback)globalkeypress_cb); //IupSetFunction("GLOBALMOTION_CB", (Icallback)globalmotion_cb); IupSetFunction("GLOBALBUTTON_CB", (Icallback)globalbutton_cb); //IupSetFunction("GLOBALWHEEL_CB", (Icallback)globalwheel_cb); IupMap(dlg); IupSetAttribute(tree, "TITLE0", "Figures"); IupSetAttribute(tree, "ADDLEAF0", "Other"); /* new id=1 */ IupSetAttribute(tree, "ADDBRANCH1", "triangle"); /* new id=2 */ IupSetAttribute(tree, "ADDLEAF2", "equilateral"); /* ... */ IupSetAttribute(tree, "ADDLEAF3", "isoceles"); IupSetAttribute(tree, "ADDLEAF4", "scalenus"); IupShow(dlg); // IupSetAttribute(dlg,"RASTERSIZE", NULL); } static int dropcheck_cb(Ihandle *self, int lin, int col) { if (lin == 3 && col == 1) return IUP_DEFAULT; if (lin == 4 && col == 4) return IUP_CONTINUE; return IUP_IGNORE; } static Ihandle* create_matrix(void) { Ihandle *img; Ihandle* mat = IupMatrix(NULL); img = IupImage(32,32, img_bits2); IupSetHandle ("img2", img); IupSetAttribute(mat, "NUMLIN", "20"); IupSetAttribute(mat, "NUMCOL", "8"); IupSetAttribute(mat, "1:1", "5.6\n3.33"); IupSetAttribute(mat, "2:1", "2.2"); IupSetAttribute(mat, "3:2", "Very Very Very Very Very Large Text"); IupSetAttribute(mat, "1:2", "4.5"); if (IupGetInt(NULL, "UTF8MODE")) IupSetAttribute(mat, "2:2", "(çãõáóé)"); else IupSetAttribute(mat, "2:2", "(çãõáóé)"); IupSetAttribute(mat, "3:1", "3.4"); IupSetAttribute(mat, "3:3", "Font Test"); IupSetAttribute(mat,"SORTSIGN2","DOWN"); IupSetAttribute(mat,"RESIZEMATRIX", "YES"); IupSetAttribute(mat, "FONT3:3", "Helvetica, 24"); IupSetAttribute(mat, "MASK*:3", "[a-zA-Z][0-9a-zA-Z_]*"); IupSetAttribute(mat, "TYPE4:1", "COLOR"); IupSetAttribute(mat, "4:1", "255 0 128"); IupSetAttribute(mat, "TYPE4:2", "FILL"); IupSetAttribute(mat, "4:2", "60"); IupSetAttribute(mat, "SHOWFILLVALUE", "Yes"); { Ihandle* image = IupImageRGBA(TEST_IMAGE_SIZE, TEST_IMAGE_SIZE, image_data_32 ); IupSetAttribute(mat, "TYPE4:3", "IMAGE"); IupSetAttributeHandle(mat, "4:3", image); } IupSetAttribute(mat, "TOGGLECENTERED", "Yes"); IupSetAttribute(mat,"MARKMODE","CELL"); IupSetAttribute(mat,"MARKMULTIPLE","YES"); IupSetAttribute(mat,"FRAMEVERTCOLOR1:2","BGCOLOR"); IupSetAttribute(mat,"FRAMEHORIZCOLOR1:2","0 0 255"); IupSetAttribute(mat,"FRAMEHORIZCOLOR1:3","0 255 0"); IupSetAttribute(mat,"FRAMEVERTCOLOR2:2","255 255 0"); IupSetAttribute(mat,"FRAMEVERTCOLOR*:4","0 255 0"); IupSetAttribute(mat,"FRAMEVERTCOLOR*:5","BGCOLOR"); IupSetAttribute(mat, "20:8", "The End"); IupSetAttribute(mat, "NUMCOL_VISIBLE", "3"); IupSetAttribute(mat, "NUMLIN_VISIBLE", "5"); IupSetAttribute(mat, "FRAMEBORDER", "Yes"); IupSetCallback(mat, "DROPCHECK_CB", (Icallback)dropcheck_cb); IupSetCallback(mat,"DROP_CB",(Icallback)drop); IupSetCallback(mat,"TOGGLEVALUE_CB",(Icallback)togglevalue_cb); return mat; } void MatrixTest(void) { Ihandle* dlg, *box, *mat; box = IupVbox(mat = create_matrix(), NULL); IupSetAttribute(box, "MARGIN", "10x10"); // IupSetAttribute(box, "FONT", "Arial, 7"); dlg = IupDialog(box); IupSetAttribute(dlg, "TITLE", "IupMatrix Simple Test"); IupShowXY(dlg, IUP_CENTER, IUP_CENTER); } #ifndef BIG_TEST int main(int argc, char* argv[]) { IupOpen(&argc, &argv); IupSetGlobal("SINGLEINSTANCE", "Iup Sample"); /* must partially match dialog title so COPYDATA_CB can work */ if (!IupGetGlobal("SINGLEINSTANCE")) { IupClose(); return EXIT_SUCCESS; } SampleTest(); MatrixTest(); IupMainLoop(); IupClose(); return EXIT_SUCCESS; } #endif |
Added iup-test/sample.scm version [1ceaf48da8].
> > > > > > > > > | 1 2 3 4 5 6 7 8 9 | (use iup) (show (dialog (vbox (button "PUSHME" button-cb: (lambda (obj . param) (print "obj: " obj " param: " param)) action: (lambda (obj) (print "obj: " obj)))))) (main-loop) |
Deleted iupexamples/graph.scm version [5afd5f9dcd].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted iupexamples/iupwidgetinfo.scm version [c580d04776].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted iupexamples/tree.scm version [872c01f2cf].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Added js-path.scm version [c9e6b3b2ac].
> > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | ;; Copyright 2006-2017, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. ;; (define *java-script-lib* (conc (common:get-install-area) "/share/js/jquery-3.1.0.slim.min.js")) |
Added junk/cube.scm version [81ad57f1fa].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 | (use gl glut 3viewer typed-records matchable) (define red '#f32(1 0 0 1)) ;; (define blue '#f32(0 0 1 1)) ;; (define green '#f32(0 1 0 1)) ;; (define yellow '#f32(1 1 0 1)) ;; (define white '#f32(1 1 1 1)) ;; (define orange '#f32(1 0.5 0 1)) ;; (define black '#f32(0 0 0 1)) ;; (define colors `((1 . ,red ) ;; red (2 . ,blue ) ;; blue (3 . ,green ) ;; green (4 . ,yellow ) ;; yellow (5 . ,white ) ;; white (6 . ,orange ) ;; orange (7 . ,black ) ;; black )) ;; retrive color (define (rc c) (alist-ref c colors)) (defstruct cspec (x 0) (y 0) (z 0) (n (rc 1)) ;; north (s (rc 1)) ;; south (e (rc 1)) ;; east (w (rc 1)) ;; west (t (rc 1)) ;; top (b (rc 1))) ;; bottom (define a 0) (define (spin id) (set! a (modulo (+ a 1) 360))) (define (colorize id col) (gl:Materialfv gl:FRONT_AND_BACK gl:AMBIENT_AND_DIFFUSE (if (object-highlighted? id) '#f32(1 1 0 1) col))) (define (make-cuber cspec) (lambda (id) (gl:Translatef (cspec-x cspec)(cspec-y cspec)(cspec-z cspec)) (draw-side id (cspec-w cspec)) ;; west side (gl:Translatef 0 1 0) (gl:Rotatef 90 1 0 0) (draw-side id (cspec-e cspec)) ;; east side (gl:Translatef 0 0 1) (gl:Rotatef 90 0 1 0) (draw-side id (cspec-n cspec)) ;; east side (gl:Translatef 0 0 1) (gl:Rotatef 90 0 1 0) (draw-side id (cspec-s cspec)) ;; east side (gl:Translatef 0 0 1) (gl:Rotatef 90 0 1 0) (draw-side id (cspec-t cspec)) ;; east side (gl:Translatef 0 1 0) (gl:Rotatef 90 1 0 0) (draw-side id (cspec-b cspec)) ;; east side )) (define (draw-side id color) (colorize id color) ;; '#f32(1 0 0 1)) (gl:Begin gl:POLYGON) (gl:Vertex2f 0 0) (gl:Vertex2f 0 1) (gl:Vertex2f 1 1) (gl:Vertex2f 1 0) (gl:End) ) (define data (map (lambda (inl) (map string->number (string-split inl))) (with-input-from-file "data.txt" read-lines))) (print "data: " data) (use trace) ;; (add-object draw-cube animate: spin select: (lambda _ (print "oink!"))) ;; (add-object draw-polygon animate: spin select: (lambda _ (print "oink!"))) (gl:Clear gl:COLOR_BUFFER_BIT) (for-each (lambda (dat) ;; (let ((c1 (make-cspec e: red w: blue n: green s: yellow t: white b: orange))) (match dat ((x y z n s e w t b) (let ((c1 (make-cspec x: x y: y z: z n: (rc n) s: (rc s) e: (rc e) w: (rc w) t: (rc t) b: (rc b)))) (pp (cspec->alist c1)) (add-object (make-cuber c1) select: (lambda _ (print "oink!"))))) (else (print "bad object " dat)))) data) (gl:Flush) (start-viewer) |
Added junk/data.txt version [b9a9d33100].
> | 1 | 0 0 0 1 2 3 4 5 6 |
Modified key_records.scm from [b34127109e] to [0f706e37f0].
1 2 3 | ;;====================================================================== ;; Copyright 2006-2012, Matthew Welland. ;; | | | > > > > > | | > > > > | | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | ;;====================================================================== ;; Copyright 2006-2012, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. ;;====================================================================== (define-inline (keys->valslots keys) ;; => ?,?,? .... (string-intersperse (map (lambda (x) "?") keys) ",")) ;; (define-inline (keys->key/field keys . additional) ;; (string-join (map (lambda (k)(conc k " TEXT")) ;; (append keys additional)) ",")) (define-inline (item-list->path itemdat) (if (list? itemdat) (string-intersperse (map cadr itemdat) "/") "")) |
Modified keys.scm from [d7ceb127bd] to [9fa2c0cfa5].
1 2 3 | ;; Copyright 2006-2012, Matthew Welland. ;; | | | > > > > > | | > | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | ;; Copyright 2006-2012, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. ;; ;;====================================================================== ;; Run keys, these are used to hierarchially organise tests and run areas ;;====================================================================== (use sqlite3 srfi-1 posix regex regex-case srfi-69) (import (prefix sqlite3 sqlite3:)) |
︙ | ︙ | |||
62 63 64 65 66 67 68 | (list key targ)) keys targtweaked))) ;;====================================================================== ;; config file related routines ;;====================================================================== | | > | > > | > | 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 | (list key targ)) keys targtweaked))) ;;====================================================================== ;; config file related routines ;;====================================================================== (define keys:config-get-fields common:get-fields) (define (keys:make-key/field-string confdat) (let ((fields (configf:get-section confdat "fields"))) (string-join (map (lambda (field)(conc (car field) " " (cadr field))) fields) ","))) |
Modified launch.scm from [b1aa4537fd] to [961da27317].
1 2 3 | ;; Copyright 2006-2017, Matthew Welland. ;; | | | > > > > > | | > | > > > < < < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | ;; Copyright 2006-2017, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. ;;====================================================================== ;; launch a task - this runs on the originating host, tests themselves ;; ;;====================================================================== (use regex regex-case base64 sqlite3 srfi-18 directory-utils posix-extras z3 call-with-environment-variables csv) (use typed-records pathname-expand matchable) (import (prefix base64 base64:)) (import (prefix sqlite3 sqlite3:)) (declare (unit launch)) (declare (uses subrun)) (declare (uses common)) (declare (uses configf)) (declare (uses db)) (include "common_records.scm") (include "key_records.scm") (include "db_records.scm") ;;====================================================================== ;; ezsteps |
︙ | ︙ | |||
59 60 61 62 63 64 65 | (defstruct launch:einf (pid #t)(exit-status #t)(exit-code #t)(rollup-status 0)) ;; return (conc status ": " comment) from the final section so that ;; the comment can be set in the step record in launch.scm ;; (define (launch:load-logpro-dat run-id test-id stepname) (let ((cname (conc stepname ".dat"))) | | | > > > > | > > > | > > > > > > | > | > > > | | > > | > > > > > | | | 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 | (defstruct launch:einf (pid #t)(exit-status #t)(exit-code #t)(rollup-status 0)) ;; return (conc status ": " comment) from the final section so that ;; the comment can be set in the step record in launch.scm ;; (define (launch:load-logpro-dat run-id test-id stepname) (let ((cname (conc stepname ".dat"))) (if (common:file-exists? cname) (let* ((dat (read-config cname #f #f)) (csvr (db:logpro-dat->csv dat stepname)) (csvt (let-values (((fmt-cell fmt-record fmt-csv) (make-format ","))) (fmt-csv (map list->csv-record csvr)))) (status (configf:lookup dat "final" "exit-status")) (msg (configf:lookup dat "final" "message"))) (if csvt ;; this if blocked stack dump caused by .dat file from logpro being 0-byte. fixed by upgrading logpro (rmt:csv->test-data run-id test-id csvt) (debug:print 0 *default-log-port* "ERROR: no csvdat exists for run-id: " run-id " test-id: " test-id " stepname: " stepname ", check that logpro version is 1.15 or newer")) ;; (debug:print-info 13 *default-log-port* "Error: run-id/test-id/stepname="run-id"/"test-id"/"stepname" => bad csvr="csvr) ;; ) (cond ((equal? status "PASS") "PASS") ;; skip the message part if status is pass (status (conc (configf:lookup dat "final" "exit-status") ": " (if msg msg "no message"))) (else #f))) #f))) (define (launch:runstep ezstep run-id test-id exit-info m tal testconfig) ;;; TODO: deprecate me in favor of ezsteps.scm (let* ((stepname (car ezstep)) ;; do stuff to run the step (stepinfo (cadr ezstep)) ;; (let ((info (cadr ezstep))) ;; (if (proc? info) "" info))) ;; (stepproc (let ((info (cadr ezstep))) ;; (if (proc? info) info #f))) (stepparts (string-match (regexp "^(\\{([^\\}\\{]*)\\}\\s*|)(.*)$") stepinfo)) (stepparams (if (and (list? stepparts) (> (length stepparts) 1)) (list-ref stepparts 2) #f)) ;; for future use, {VAR=1,2,3}, run step for each (paramparts (if (string? stepparams) (map (lambda (x)(string-split x "=")) (string-split-fields "[^;]*=[^;]*" stepparams)) '())) (subrun (alist-ref "subrun" paramparts equal?)) (stepcmd (if (and (list? stepparts) (> (length stepparts) 2)) (list-ref stepparts 3) (conc "# error, no command for step "stepname))) (script "") ; "#!/bin/bash\n") ;; yep, we depend on bin/bash FIXME!!!\ (logpro-file (conc stepname ".logpro")) (html-file (conc stepname ".html")) (dat-file (conc stepname ".dat")) (tconfig-logpro (configf:lookup testconfig "logpro" stepname)) (logpro-used (common:file-exists? logpro-file))) (debug:print 0 *default-log-port* "stepparts: " stepparts ", stepparams: " stepparams ", paramparts: " paramparts ", subrun: " subrun ", stepcmd: " stepcmd) (if (and tconfig-logpro (not logpro-used)) ;; no logpro file found but have a defn in the testconfig (begin (with-output-to-file logpro-file (lambda () (print ";; logpro file extracted from testconfig\n" ";;") (print tconfig-logpro))) (set! logpro-used #t))) ;; NB// can safely assume we are in test-area directory (debug:print 4 *default-log-port* "ezsteps:\n stepname: " stepname " stepinfo: " stepinfo " stepparts: " stepparts " stepparams: " stepparams " stepcmd: " stepcmd) ;; ;; first source the previous environment ;; (let ((prev-env (conc ".ezsteps/" prevstep (if (string-search (regexp "csh") ;; (get-environment-variable "SHELL")) ".csh" ".sh")))) ;; (if (and prevstep (common:file-exists? prev-env)) ;; (set! script (conc script "source " prev-env)))) ;; call the command using mt_ezstep ;; (set! script (conc "mt_ezstep " stepname " " (if prevstep prevstep "x") " " stepcmd)) (debug:print 4 *default-log-port* "script: " script) (rmt:teststep-set-status! run-id test-id stepname "start" "-" #f #f) ;; now launch the actual process (call-with-environment-variables (list (cons "PATH" (conc (get-environment-variable "PATH") ":."))) (lambda () ;; (process-run "/bin/bash" "-c" "exec ls -l /tmp/foobar > /tmp/delme-more.log 2>&1") (let* ((cmd (conc stepcmd " > " stepname ".log 2>&1")) ;; >outfile 2>&1 (pid #f)) (let ((proc (lambda () (set! pid (process-run "/bin/bash" (list "-c" cmd)))))) (if subrun (begin (debug:print-info 0 *default-log-port* "Running without MT_.* environment variables.") (common:without-vars proc "^MT_.*")) (proc))) (with-output-to-file "Makefile.ezsteps" (lambda () (print stepname ".log :") (print "\t" cmd) (if (common:file-exists? (conc stepname ".logpro")) (print "\tlogpro " stepname ".logpro " stepname ".html < " stepname ".log")) (print) (print stepname " : " stepname ".log") (print)) #:append) (rmt:test-set-top-process-pid run-id test-id pid) |
︙ | ︙ | |||
149 150 151 152 153 154 155 | (begin (thread-sleep! 2) (processloop (+ i 1)))) ))))) (debug:print-info 0 *default-log-port* "step " stepname " completed with exit code " (launch:einf-exit-code exit-info)) ;; (vector-ref exit-info 2)) ;; now run logpro if needed (if logpro-used | > | | | 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 | (begin (thread-sleep! 2) (processloop (+ i 1)))) ))))) (debug:print-info 0 *default-log-port* "step " stepname " completed with exit code " (launch:einf-exit-code exit-info)) ;; (vector-ref exit-info 2)) ;; now run logpro if needed (if logpro-used (let* ((logpro-exe (or (getenv "LOGPRO_EXE") "logpro")) (pid (process-run (conc "/bin/sh -c '"logpro-exe" "logpro-file " " (conc stepname ".html") " < " stepname ".log > /dev/null'")))) (let processloop ((i 0)) (let-values (((pid-val exit-status exit-code)(process-wait pid #t))) (mutex-lock! m) ;; (make-launch:einf pid: pid exit-status: exit-status exit-code: exit-code) (launch:einf-pid-set! exit-info pid) ;; (vector-set! exit-info 0 pid) (launch:einf-exit-status-set! exit-info exit-status) ;; (vector-set! exit-info 1 exit-status) (launch:einf-exit-code-set! exit-info exit-code) ;; (vector-set! exit-info 2 exit-code) (mutex-unlock! m) (if (eq? pid-val 0) (begin (thread-sleep! 2) (processloop (+ i 1))))) (debug:print-info 0 *default-log-port* "logpro for step " stepname " exited with code " (launch:einf-exit-code exit-info))))) ;; (vector-ref exit-info 2))))) (let ((exinfo (launch:einf-exit-code exit-info)) ;; (vector-ref exit-info 2)) (logfna (if logpro-used (conc stepname ".html") "")) (comment #f)) (if logpro-used (let ((datfile (conc stepname ".dat"))) ;; load the .dat file into the test_data table if it exists (if (common:file-exists? datfile) (set! comment (launch:load-logpro-dat run-id test-id stepname))) (rmt:test-set-log! run-id test-id (conc stepname ".html")))) (rmt:teststep-set-status! run-id test-id stepname "end" exinfo comment logfna)) ;; set the test final status (let* ((process-exit-status (launch:einf-exit-code exit-info)) ;; (vector-ref exit-info 2)) (this-step-status (cond ((and (eq? process-exit-status 2) logpro-used) 'warn) ;; logpro 2 = warnings |
︙ | ︙ | |||
241 242 243 244 245 246 247 | (tests:test-set-status! run-id test-id next-state "PASS" #f #f)) (else ;; 'fail (launch:einf-rollup-status-set! exit-info 1) ;; (vector-set! exit-info 3 1) ;; force fail, this used to be next-state but that doesn't make sense. should always be "COMPLETED" (tests:test-set-status! run-id test-id "COMPLETED" "FAIL" (conc "Failed at step " stepname) #f) ))) logpro-used)) | | | 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 | (tests:test-set-status! run-id test-id next-state "PASS" #f #f)) (else ;; 'fail (launch:einf-rollup-status-set! exit-info 1) ;; (vector-set! exit-info 3 1) ;; force fail, this used to be next-state but that doesn't make sense. should always be "COMPLETED" (tests:test-set-status! run-id test-id "COMPLETED" "FAIL" (conc "Failed at step " stepname) #f) ))) logpro-used)) (define (launch:manage-steps run-id test-id item-path fullrunscript ezsteps subrun test-name tconfigreg exit-info m) ;; (let-values ;; (((pid exit-status exit-code) ;; (run-n-wait fullrunscript))) ;; (tests:test-set-status! test-id "RUNNING" "n/a" #f #f) ;; Since we should have a clean slate at this time there is no need to do ;; any of the other stuff that tests:test-set-status! does. Let's just ;; force RUNNING/n/a |
︙ | ︙ | |||
275 276 277 278 279 280 281 | (if (eq? pid-val 0) (begin (thread-sleep! 2) (loop (+ i 1))) ))))) ;; then, if runscript ran ok (or did not get called) ;; do all the ezsteps (if any) | | > | > > > > > > > > > > > > > > > > > > > > > | | | | | | | > | | | | | | | | | | | | > | > | > > > | | | | | | > > | > | | | > > > > > > > > > | > > | < < < | | > > > > | > > > > > > > | > > > | 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 | (if (eq? pid-val 0) (begin (thread-sleep! 2) (loop (+ i 1))) ))))) ;; then, if runscript ran ok (or did not get called) ;; do all the ezsteps (if any) (if (or ezsteps subrun) (let* ((test-run-dir (tests:get-test-path-from-environment)) (testconfig ;; (read-config (conc work-area "/testconfig") #f #t environ-patt: "pre-launch-env-vars")) ;; FIXME??? is allow-system ok here? ;; NOTE: it is tempting to turn off force-create of testconfig but dynamic ;; ezstep names need a full re-eval here. (tests:get-testconfig test-name item-path tconfigreg #t force-create: #t)) ;; 'return-procs))) (ezstepslst (if (hash-table? testconfig) (hash-table-ref/default testconfig "ezsteps" '()) #f))) (if testconfig (hash-table-set! *testconfigs* test-name testconfig) ;; cached for lazy reads later ... (begin (launch:setup) (debug:print 0 *default-log-port* "WARNING: no testconfig found for " test-name " in search path:\n " (string-intersperse (tests:get-tests-search-path *configdat*) "\n ")))) ;; after all that, still no testconfig? Time to abort (if (not testconfig) (begin (debug:print-error 0 *default-log-port* "Failed to resolve megatest.config, runconfigs.config and testconfig issues. Giving up now") (exit 1))) ;; create a proc for the subrun if requested, save that proc in the ezsteps table as the last entry ;; 1. get section [runarun] ;; 2. unset MT_* vars ;; 3. fix target ;; 4. fix runname ;; 5. fix testpatt or calculate it from contour ;; 6. launch the run ;; 7. roll up the run result and or roll up the logpro processed result (when (configf:lookup testconfig "subrun" "runwait") ;; we use runwait as the flag that a subrun is requested (subrun:initialize-toprun-test testconfig test-run-dir) (let* ((mt-cmd (subrun:launch-cmd test-run-dir))) (debug:print-info 0 *default-log-port* "Subrun command is \"" mt-cmd "\"") (set! ezsteps #t) ;; set the needed flag (set! ezstepslst (append (or ezstepslst '()) (list (list "subrun" (conc "{subrun=true} " mt-cmd))))))) ;; process the ezsteps (if ezsteps (begin (if (not (common:file-exists? ".ezsteps"))(create-directory ".ezsteps")) ;; if ezsteps was defined then we are sure to have at least one step but check anyway (if (not (> (length ezstepslst) 0)) (debug:print-error 0 *default-log-port* "ezsteps defined but ezstepslst is zero length") (let loop ((ezstep (car ezstepslst)) (tal (cdr ezstepslst)) (prevstep #f)) (debug:print-info 0 *default-log-port* "Processing ezstep \"" (string-intersperse ezstep " ") "\"") ;; check exit-info (vector-ref exit-info 1) (if (launch:einf-exit-status exit-info) ;; (vector-ref exit-info 1) (let ((logpro-used (launch:runstep ezstep run-id test-id exit-info m tal testconfig)) (stepname (car ezstep))) ;; if logpro-used read in the stepname.dat file (if (and logpro-used (common:file-exists? (conc stepname ".dat"))) (launch:load-logpro-dat run-id test-id stepname)) (if (steprun-good? logpro-used (launch:einf-exit-code exit-info)) (if (not (null? tal)) (loop (car tal) (cdr tal) stepname)) (debug:print 0 *default-log-port* "WARNING: step " (car ezstep) " failed. Stopping"))) (debug:print 0 *default-log-port* "WARNING: a prior step failed, stopping at " ezstep))))))))) (define (launch:monitor-job run-id test-id item-path fullrunscript ezsteps test-name tconfigreg exit-info m work-area runtlim misc-flags) (let* ((update-period (string->number (or (configf:lookup *configdat* "setup" "test-stats-update-period") "30"))) (start-seconds (current-seconds)) (calc-minutes (lambda () (inexact->exact (round (- (current-seconds) start-seconds))))) (kill-tries 0)) ;; (tests:set-full-meta-info #f test-id run-id (calc-minutes) work-area) ;; (tests:set-full-meta-info test-id run-id (calc-minutes) work-area) (tests:set-full-meta-info #f test-id run-id (calc-minutes) work-area 10) (let loop ((minutes (calc-minutes)) (cpu-load (alist-ref 'adj-core-load (common:get-normalized-cpu-load #f))) (disk-free (get-df (current-directory))) (last-sync (current-seconds))) (common:telemetry-log "zombie" (conc "launch:monitor-job - top of loop encountered at "(current-seconds)" with last-sync="last-sync)) (let* ((over-time (> (current-seconds) (+ last-sync update-period))) (new-cpu-load (let* ((load (alist-ref 'adj-core-load (common:get-normalized-cpu-load #f))) (delta (abs (- load cpu-load)))) (if (> delta 0.1) ;; don't bother updating with small changes load #f))) (new-disk-free (let* ((df (if over-time ;; only get df every 30 seconds (get-df (current-directory)) disk-free)) (delta (abs (- df disk-free)))) (if (and (> df 0) (> (/ delta df) 0.1)) ;; (> delta 200) ;; ignore changes under 200 Meg df #f))) (do-sync (or new-cpu-load new-disk-free over-time)) (test-info (rmt:get-test-info-by-id run-id test-id)) (state (db:test-get-state test-info)) (status (db:test-get-status test-info)) (kill-reason "no kill reason specified") (kill-job? #f)) (common:telemetry-log "zombie" (conc "launch:monitor-job - decision time encountered at "(current-seconds)" with last-sync="last-sync" do-sync="do-sync" over-time="over-time" update-period="update-period)) (cond ((test-get-kill-request run-id test-id) (set! kill-reason "KILLING TEST since received kill request (KILLREQ)") (set! kill-job? #t)) ((and runtlim (> (- (current-seconds) start-seconds) runtlim)) (set! kill-reason (conc "KILLING TEST DUE TO TIME LIMIT EXCEEDED! Runtime=" (- (current-seconds) start-seconds) " seconds, limit=" runtlim)) (set! kill-job? #t)) ((equal? status "DEAD") (tests:update-central-meta-info run-id test-id new-cpu-load new-disk-free (calc-minutes) #f #f) (rmt:set-state-status-and-roll-up-items run-id test-id 'foo "RUNNING" "n/a" "was marked dead; really still running.") ;;(set! kill-reason "KILLING TEST because it was marked as DEAD by launch:handle-zombie-tests (might indicate really overloaded server or else overzealous setup.deadtime)") ;; MARK RUNNING (set! kill-job? #f))) (debug:print 4 *default-log-port* "cpu: " new-cpu-load " disk: " new-disk-free " last-sync: " last-sync " do-sync: " do-sync) (launch:handle-zombie-tests run-id) (when do-sync ;;(with-output-to-file (conc (getenv "MT_TEST_RUN_DIR") "/last-loadinfo.log" #:append) ;; (lambda () (pp (list (current-seconds) new-cpu-load new-disk-free (calc-minutes))))) (common:telemetry-log "zombie" (conc "launch:monitor-job - dosync started at "(current-seconds))) (tests:update-central-meta-info run-id test-id new-cpu-load new-disk-free (calc-minutes) #f #f) (common:telemetry-log "zombie" (conc "launch:monitor-job - dosync finished at "(current-seconds)))) (if kill-job? (begin (debug:print-info 0 *default-log-port* "proceeding to kill test: "kill-reason) (mutex-lock! m) ;; NOTE: The pid can change as different steps are run. Do we need handshaking between this ;; section and the runit section? Or add a loop that tries three times with a 1/4 second ;; between tries? (let* ((pid1 (launch:einf-pid exit-info)) ;; (vector-ref exit-info 0)) (pid2 (rmt:test-get-top-process-pid run-id test-id)) (pids (delete-duplicates (filter number? (list pid1 pid2))))) |
︙ | ︙ | |||
383 384 385 386 387 388 389 | (handle-exceptions exn #f (process-signal pid-num signal/kill))) (process:get-sub-pids pid)))) ;; (debug:print-info 0 *default-log-port* "not killing process " pid " as it is not alive")))) pids) | > | | | > | > > > > | 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 | (handle-exceptions exn #f (process-signal pid-num signal/kill))) (process:get-sub-pids pid)))) ;; (debug:print-info 0 *default-log-port* "not killing process " pid " as it is not alive")))) pids) ;; BB: question to Matt -- does the tests:test-state-status! encompass rollup to toplevel? If not, should it? (tests:test-set-status! run-id test-id "KILLED" "KILLED" (conc (args:get-arg "-m")" "kill-reason) #f)) ;; BB ADDED kill-reason -- confirm OK with Matt (begin (debug:print-error 0 *default-log-port* "Nothing to kill, pid1=" pid1 ", pid2=" pid2) (tests:test-set-status! run-id test-id "KILLED" "FAILED TO KILL" (conc (args:get-arg "-m")" "kill-reason) #f) ;; BB ADDED kill-reason -- confirm OK with Matt ))) (mutex-unlock! m) ;; no point in sticking around. Exit now. But run end of run before exiting? (launch:end-of-run-check run-id) (exit))) (if (hash-table-ref/default misc-flags 'keep-going #f) (begin (thread-sleep! 3) ;; (+ 3 (random 6))) ;; add some jitter to the call home time to spread out the db accesses (if (hash-table-ref/default misc-flags 'keep-going #f) ;; keep originals for cpu-load and disk-free unless they change more than the allowed delta (loop (calc-minutes) (or new-cpu-load cpu-load) (or new-disk-free disk-free) (if do-sync (current-seconds) last-sync))))))) (tests:update-central-meta-info run-id test-id (get-cpu-load) (get-df (current-directory))(calc-minutes) #f #f))) ;; NOTE: Checking twice for keep-going is intentional (define (launch:execute encoded-cmd) (let* ((cmdinfo (common:read-encoded-string encoded-cmd)) (tconfigreg #f)) (setenv "MT_CMDINFO" encoded-cmd) ;;(bb-check-path msg: "launch:execute incoming") (if (list? cmdinfo) ;; ((testpath /tmp/mrwellan/jazzmind/src/example_run/tests/sqlitespeed) ;; (test-name sqlitespeed) (runscript runscript.rb) (db-host localhost) (run-id 1)) (let* ((testpath (assoc/default 'testpath cmdinfo)) ;; testpath is the test spec area (top-path (assoc/default 'toppath cmdinfo)) (work-area (assoc/default 'work-area cmdinfo)) ;; work-area is the test run area (test-name (assoc/default 'test-name cmdinfo)) (runscript (assoc/default 'runscript cmdinfo)) (ezsteps (assoc/default 'ezsteps cmdinfo)) (subrun (assoc/default 'subrun cmdinfo)) ;; (runremote (assoc/default 'runremote cmdinfo)) ;; (transport (assoc/default 'transport cmdinfo)) ;; not used ;; (serverinf (assoc/default 'serverinf cmdinfo)) ;; (port (assoc/default 'port cmdinfo)) (serverurl (assoc/default 'serverurl cmdinfo)) (homehost (assoc/default 'homehost cmdinfo)) (run-id (assoc/default 'run-id cmdinfo)) |
︙ | ︙ | |||
437 438 439 440 441 442 443 | (mt-bindir-path (assoc/default 'mt-bindir-path cmdinfo)) (keys #f) (keyvals #f) (fullrunscript (if (not runscript) #f (if (substring-index "/" runscript) runscript ;; use unadultered if contains slashes | | | > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < | | > | > < | > | > > > > > > > > | > > > > | > > | < < | > | > > > | | > > > > > | | > | | | | | | | | | > > > | 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 | (mt-bindir-path (assoc/default 'mt-bindir-path cmdinfo)) (keys #f) (keyvals #f) (fullrunscript (if (not runscript) #f (if (substring-index "/" runscript) runscript ;; use unadultered if contains slashes (let ((fulln (conc work-area "/" runscript))) (if (and (common:file-exists? fulln) (file-execute-access? fulln)) fulln runscript))))) ;; assume it is on the path (check-work-area (lambda () ;; NFS might not have propagated the directory meta data to the run host - give it time if needed (let loop ((count 0)) (if (or (common:directory-exists? work-area) (> count 10)) (change-directory work-area) (begin (debug:print 0 *default-log-port* "INFO: Not starting job yet - directory " work-area " not found") (thread-sleep! 10) (loop (+ count 1))))) (if (not (string=? (common:real-path work-area)(common:real-path (current-directory)))) (begin (debug:print 0 *default-log-port* "INFO: we are expecting to be in directory " work-area "\n" " but we are actually in the directory " (current-directory) "\n" " doing another change dir.") (change-directory work-area))) ;; spot check that the files in testpath are available. Too often NFS delays cause problems here. (let ((files (glob (conc testpath "/*"))) (bad-files '())) (for-each (lambda (fullname) (let* ((fname (pathname-strip-directory fullname)) (targn (conc work-area "/" fname))) (if (not (file-exists? targn)) (set! bad-files (cons fname bad-files))))) files) (if (not (null? bad-files)) (begin (debug:print 0 *default-log-port* "INFO: test data from " testpath " not copied properly or filesystem problems causing data to not be found. Re-running the copy command.") (debug:print 0 *default-log-port* "INFO: missing files from " work-area ": " (string-intersperse bad-files ", ")) (launch:test-copy testpath work-area)))) ;; one more time, change to the work-area directory (change-directory work-area))) ) ;; let* (if contour (setenv "MT_CONTOUR" contour)) ;; immediated set some key variables from CMDINFO data, yes, these will be set again below ... ;; (setenv "MT_TESTSUITENAME" areaname) (setenv "MT_RUN_AREA_HOME" top-path) (set! *toppath* top-path) (change-directory *toppath*) ;; temporarily switch to the run area home (setenv "MT_TEST_RUN_DIR" work-area) (launch:setup) ;; should be properly in the run area home now (if contour (setenv "MT_CONTOUR" contour)) ;; immediated set some key variables from CMDINFO data, yes, these will be set again below ... ;; (setenv "MT_TESTSUITENAME" areaname) (setenv "MT_RUN_AREA_HOME" top-path) (set! *toppath* top-path) (change-directory *toppath*) ;; temporarily switch to the run area home (setenv "MT_TEST_RUN_DIR" work-area) (launch:setup) ;; should be properly in the run area home now (set! tconfigreg (tests:get-all)) ;; mapping of testname => test source path (let ((sighand (lambda (signum) ;; (signal-mask! signum) ;; to mask or not? seems to cause issues in exiting (if (eq? signum signal/stop) (debug:print-error 0 *default-log-port* "attempt to STOP process. Exiting.")) (set! *time-to-exit* #t) (print "Received signal " signum ", cleaning up before exit (set this test to COMPLETED/ABORT) . Please wait...") (let ((th1 (make-thread (lambda () (print "set test to COMPLETED/ABORT begin.") (rmt:test-set-state-status run-id test-id "COMPLETED" "ABORT" "received kill signal") (print "set test to COMPLETED/ABORT complete.") (print "Killed by signal " signum ". Exiting") (exit 1)))) (th2 (make-thread (lambda () (thread-sleep! 20) (debug:print 0 *default-log-port* "Done") (exit 4))))) (thread-start! th2) (thread-start! th1) (thread-join! th2))))) (set-signal-handler! signal/int sighand) (set-signal-handler! signal/term sighand) ) ;; (set-signal-handler! signal/stop sighand) ;; Do not run the test if it is REMOVING, RUNNING, KILLREQ or REMOTEHOSTSTART, ;; Mark the test as REMOTEHOSTSTART *IMMEDIATELY* ;; (let* ((test-info (let loop ((tries 0)) (let ((tinfo (rmt:get-test-info-by-id run-id test-id))) (if tinfo tinfo (if (> tries 5) #f (begin (thread-sleep! (+ 1 (* tries 10))) (loop (+ tries 1)))))))) (test-host (if test-info (db:test-get-host test-info) (begin (debug:print 0 *default-log-port* "ERROR: failed to find a record for test-id " test-id ", exiting.") (exit)))) (test-pid (db:test-get-process_id test-info))) (cond ;; -mrw- I'm removing KILLREQ from this list so that a test in KILLREQ state is treated as a "do not run" flag. ((member (db:test-get-state test-info) '("INCOMPLETE" "KILLED" "UNKNOWN" "STUCK")) ;; prior run of this test didn't complete, go ahead and try to rerun (debug:print 0 *default-log-port* "INFO: test is INCOMPLETE or KILLED, treat this execute call as a rerun request") ;; (tests:test-force-state-status! run-id test-id "REMOTEHOSTSTART" "n/a") (rmt:general-call 'set-test-start-time #f test-id) (rmt:test-set-state-status run-id test-id "REMOTEHOSTSTART" "n/a" #f) ) ;; prime it for running ((member (db:test-get-state test-info) '("RUNNING" "REMOTEHOSTSTART")) (if (process:alive-on-host? test-host test-pid) (debug:print-error 0 *default-log-port* "test state is " (db:test-get-state test-info) " and process " test-pid " is still running on host " test-host ", cannot proceed") (exit))) ((not (member (db:test-get-state test-info) '("REMOVING" "REMOTEHOSTSTART" "RUNNING" "KILLREQ"))) ;; (tests:test-force-state-status! run-id test-id "REMOTEHOSTSTART" "n/a") (rmt:general-call 'set-test-start-time #f test-id) (rmt:test-set-state-status run-id test-id "REMOTEHOSTSTART" "n/a" #f) ) (else ;; (member (db:test-get-state test-info) '("REMOVING" "REMOTEHOSTSTART" "RUNNING" "KILLREQ")) (debug:print-error 0 *default-log-port* "test state is " (db:test-get-state test-info) ", cannot proceed") (exit)))) ;; cleanup prior execution's steps (rmt:delete-steps-for-test! run-id test-id) (debug:print 2 *default-log-port* "Executing " test-name " (id: " test-id ") on " (get-host-name)) (set! keys (rmt:get-keys)) ;; (runs:set-megatest-env-vars run-id inkeys: keys inkeyvals: keyvals) ;; these may be needed by the launching process ;; one of these is defunct/redundant ... (if (not (launch:setup force-reread: #t)) (begin (debug:print 0 *default-log-port* "Failed to setup, exiting") ;; (sqlite3:finalize! db) ;; (sqlite3:finalize! tdb) (exit 1))) ;; validate that the test run area is available (check-work-area) ;; still need to go back to run area home for next couple steps (change-directory *toppath*) ;; NOTE: Current order is to process runconfigs *before* setting the MT_ vars. This ;; seems non-ideal but could well break stuff ;; BUG? BUG? BUG? (let ((rconfig (full-runconfigs-read)) ;; (read-config (conc *toppath* "/runconfigs.config") #f #t sections: (list "default" target)))) (wconfig (read-config "waivers.config" #f #t sections: `( "default" ,target )))) ;; read the waivers config if it exists ;; (setup-env-defaults (conc *toppath* "/runconfigs.config") run-id (make-hash-table) keyvals target) ;; (set-run-config-vars run-id keyvals target) ;; (db:get-target db run-id)) ;; Now have runconfigs data loaded, set environment vars (for-each (lambda (section) (for-each (lambda (varval) (let ((var (car varval)) (val (cadr varval))) (if (and (string? var)(string? val)) (begin (safe-setenv var (config:eval-string-in-environment val))) ;; val) (debug:print-error 0 *default-log-port* "bad variable spec, " var "=" val)))) (configf:get-section rconfig section))) (list "default" target))) ;;(bb-check-path msg: "launch:execute post block 1") ;; NFS might not have propagated the directory meta data to the run host - give it time if needed (let loop ((count 0)) (if (or (common:file-exists? work-area) (> count 10)) (change-directory work-area) (begin (debug:print 0 *default-log-port* "INFO: Not starting job yet - directory " work-area " not found") (thread-sleep! 10) (loop (+ count 1))))) ;; now we can switch to the work-area? (change-directory work-area) ;;(bb-check-path msg: "launch:execute post block 1.5") ;; (change-directory work-area) (set! keyvals (keys:target->keyval keys target)) ;; apply pre-overrides before other variables. The pre-override vars must not ;; clobbers things from the official sources such as megatest.config and runconfigs.config (if (string? set-vars) (let ((varpairs (string-split set-vars ","))) |
︙ | ︙ | |||
654 655 656 657 658 659 660 | ;; environment overrides are done *before* the remaining critical envars. (alist->env-vars env-ovrd) ;;(bb-check-path msg: "launch:execute post block 41") (runs:set-megatest-env-vars run-id inkeys: keys inkeyvals: keyvals) ;;(bb-check-path msg: "launch:execute post block 42") (set-item-env-vars itemdat) ;;(bb-check-path msg: "launch:execute post block 43") | > > > > > > > | | > > > > > > > > > > > > > > > > > > > > > > | < | > > > > | > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | | | 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 | ;; environment overrides are done *before* the remaining critical envars. (alist->env-vars env-ovrd) ;;(bb-check-path msg: "launch:execute post block 41") (runs:set-megatest-env-vars run-id inkeys: keys inkeyvals: keyvals) ;;(bb-check-path msg: "launch:execute post block 42") (set-item-env-vars itemdat) ;;(bb-check-path msg: "launch:execute post block 43") (let ((blacklist (configf:lookup *configdat* "setup" "blacklistvars"))) (if blacklist (let ((vars (string-split blacklist))) (save-environment-as-files "megatest" ignorevars: vars) (for-each (lambda (var) (unsetenv var)) vars)) (save-environment-as-files "megatest"))) ;;(bb-check-path msg: "launch:execute post block 44") ;; open-run-close not needed for test-set-meta-info ;; (tests:set-full-meta-info #f test-id run-id 0 work-area) ;; (tests:set-full-meta-info test-id run-id 0 work-area) (tests:set-full-meta-info #f test-id run-id 0 work-area 10) ;; (thread-sleep! 0.3) ;; NFS slowness has caused grief here (if (args:get-arg "-xterm") (set! fullrunscript "xterm") (if (and fullrunscript (common:file-exists? fullrunscript) (not (file-execute-access? fullrunscript))) (system (conc "chmod ug+x " fullrunscript)))) ;; We are about to actually kick off the test ;; so this is a good place to remove the records for ;; any previous runs ;; (db:test-remove-steps db run-id testname itemdat) ;; now is also a good time to write the .testconfig file (let* ((tconfig-fname (conc work-area "/.testconfig")) (tconfig-tmpfile (conc tconfig-fname ".tmp")) (tconfig (tests:get-testconfig test-name item-path tconfigreg #t force-create: #t)) ;; 'return-procs))) (scripts (configf:get-section tconfig "scripts"))) ;; create .testconfig file (configf:write-alist tconfig tconfig-tmpfile) (file-move tconfig-tmpfile tconfig-fname #t) (delete-file* ".final-status") ;; extract scripts from testconfig and write them to files in test run dir (for-each (lambda (scriptdat) (match scriptdat ((name content) (with-output-to-file name (lambda () (print content) (change-file-mode name (bitwise-ior perm/irwxg perm/irwxu))))) (else (debug:print-info 0 "Invalid script definiton found in [scripts] section of testconfig. \"" scriptdat "\"")))) scripts)) ;; (let* ((m (make-mutex)) (kill-job? #f) (exit-info (make-launch:einf pid: #t exit-status: #t exit-code: #t rollup-status: 0)) ;; pid exit-status exit-code (i.e. process was successfully run) rollup-status (job-thread #f) ;; (keep-going #t) (misc-flags (let ((ht (make-hash-table))) (hash-table-set! ht 'keep-going #t) ht)) (runit (lambda () (launch:manage-steps run-id test-id item-path fullrunscript ezsteps subrun test-name tconfigreg exit-info m))) (monitorjob (lambda () (launch:monitor-job run-id test-id item-path fullrunscript ezsteps test-name tconfigreg exit-info m work-area runtlim misc-flags))) (th1 (make-thread monitorjob "monitor job")) (th2 (make-thread runit "run job"))) (set! job-thread th2) (thread-start! th1) (thread-start! th2) (thread-join! th2) (debug:print-info 0 *default-log-port* "Megatest exectute of test " test-name ", item path " item-path " complete. Notifying the db ...") (hash-table-set! misc-flags 'keep-going #f) (thread-join! th1) (thread-sleep! 1) ;; givbe thread th1 a chance to be done TODO: Verify this is needed. At 0.1 I was getting fail to stop, increased to total of 1.1 sec. (mutex-lock! m) (let* ((item-path (item-list->path itemdat)) ;; only state and status needed - use lazy routine (testinfo (rmt:get-testinfo-state-status run-id test-id))) ;; Am I completed? (if (member (db:test-get-state testinfo) '("REMOTEHOSTSTART" "RUNNING")) ;; NOTE: It should *not* be REMOTEHOSTSTART but for reasons I don't yet understand it sometimes gets stuck in that state ;; (not (equal? (db:test-get-state testinfo) "COMPLETED")) (let ((new-state (if kill-job? "KILLED" "COMPLETED") ;; (if (eq? (vector-ref exit-info 2) 0) ;; exited with "good" status ;; "COMPLETED" ;; (db:test-get-state testinfo))) ;; else preseve the state as set within the test ) (new-status (cond ((not (launch:einf-exit-status exit-info)) "FAIL") ;; job failed to run ... (vector-ref exit-info 1) ((eq? (launch:einf-rollup-status exit-info) 0) ;; (vector-ref exit-info 3) ;; if the current status is AUTO then defer to the calculated value (i.e. leave this AUTO) (if (equal? (db:test-get-status testinfo) "AUTO") "AUTO" "PASS")) ((eq? (launch:einf-rollup-status exit-info) 1) "FAIL") ;; (vector-ref exit-info 3) ((eq? (launch:einf-rollup-status exit-info) 2) ;; (vector-ref exit-info 3) ;; if the current status is AUTO the defer to the calculated value but qualify (i.e. make this AUTO-WARN) (if (equal? (db:test-get-status testinfo) "AUTO") "AUTO-WARN" "WARN")) ((eq? (launch:einf-rollup-status exit-info) 3) "CHECK") ((eq? (launch:einf-rollup-status exit-info) 4) "WAIVED") ((eq? (launch:einf-rollup-status exit-info) 5) "ABORT") ((eq? (launch:einf-rollup-status exit-info) 6) "SKIP") (else "FAIL")))) ;; (db:test-get-status testinfo))) (debug:print-info 1 *default-log-port* "Test exited in state=" (db:test-get-state testinfo) ", setting state/status based on exit code of " (launch:einf-exit-status exit-info) " and rollup-status of " (launch:einf-rollup-status exit-info)) ;; Leave a .final-status file for each sub-test (tests:save-final-status run-id test-id) (tests:test-set-status! run-id test-id new-state new-status (args:get-arg "-m") #f) ;; need to update the top test record if PASS or FAIL and this is a subtest ;; NO NEED TO CALL set-state-status-and-roll-up-items HERE, THIS IS DONE IN set-state-status-and-roll-up-items called by tests:test-set-status! )) ;; for automated creation of the rollup html file this is a good place... (if (not (equal? item-path "")) (tests:summarize-items run-id test-id test-name #f)) (tests:summarize-test run-id test-id) ;; don't force - just update if no ;; Leave a .final-status file for the top level test (tests:save-final-status run-id test-id) (rmt:update-run-stats run-id (rmt:get-raw-run-stats run-id))) (mutex-unlock! m) (launch:end-of-run-check run-id ) (debug:print 2 *default-log-port* "Output from running " fullrunscript ", pid " (launch:einf-pid exit-info) " in work area " work-area ":\n====\n exit code " (launch:einf-exit-code exit-info) "\n" "====\n") (if (not (launch:einf-exit-status exit-info)) (exit 4)))) ))) ;; Spec for End of test ;; At end of each test call, after marking self as COMPLETED do run-state-status-rollup ;; At transition to run COMPLETED/X do hooks ;; Definition: test_dead if event_time + duration + 1 minute? < current_time AND ;; we can prove the process is not alive (ssh host pstree -A pid) ;; if dead safe to mark the test as killed in the db ;; State/status table ;; new ;; 100% COMPLETED/ (PASS,FAIL,ABORT etc.) ==> COMPLETED / X where X is same as itemized rollup ;; > 3 RUNNING with not test_dead do nothing (run should already be RUNNING/ na ;; > 0 RUNNING and test_dead then send KILLREQ ==> COMPLETED ;; 0 RUNNING ==> this is actually the first condition, should not get here (define (launch:end-of-run-check run-id ) (let* ((not-completed-cnt (rmt:get-not-completed-cnt run-id)) (running-cnt (rmt:get-count-tests-running-for-run-id run-id)) (all-test-launched (rmt:get-var (conc "lunch-complete-" run-id))) (current-state (rmt:get-run-state run-id)) (current-status (rmt:get-run-status run-id))) ;;get-vars run-id to query metadata table to check if all completed. if all-test-launched = yes then only not-completed-cnt = 0 means everyting is completed if no entry found in the table do nothing (debug:print 0 *default-log-port* "Running test cnt :" running-cnt) (rmt:set-state-status-and-roll-up-run run-id current-state current-status) (runs:update-junit-test-reporter-xml run-id) (cond ((and all-test-launched (eq? not-completed-cnt 0) (equal? all-test-launched "yes" )) (if (and (equal? (rmt:get-var (conc "end-of-run-" run-id)) "no") (common:simple-lock (conc "endOfRun" run-id))) (begin (debug:print 4 *default-log-port* "look for post hook. currseconds: " (current-seconds) " EOR " (rmt:get-var (conc "end-of-run-" run-id))) (debug:print 0 *default-log-port* "End of Run Detected.") (rmt:set-var (conc "end-of-run-" run-id) "yes") ;(thread-sleep! 10) (runs:run-post-hook run-id) (debug:print 4 *default-log-port* "currseconds: " (current-seconds)" eor: " (rmt:get-var (conc "end-of-run-" run-id))) (common:simple-unlock (conc "endOfRun" run-id))) (debug:print 0 *default-log-port* "End of Run Detected but not running post hook. This should happen when eor is set to yes. This will happen only when 2 tests exit at smae time. eor= " (rmt:get-var (conc "end-of-run-" run-id))))) ((> running-cnt 3) (debug:print 0 *default-log-port* "There are " running-cnt " tests running." )) ((> running-cnt 0) (debug:print 0 *default-log-port* "running cnt > 0 but <= 3 kill-running-tests-if-dead" ) (let ((kill-cnt (launch:kill-tests-if-dead run-id))) (if (and all-test-launched (equal? all-test-launched "yes") (eq? kill-cnt running-cnt)) (launch:end-of-run-check run-id)))) ;;todo (else (debug:print 0 *default-log-port* "Should it get here?? May be everything is not launched yet. Running test cnt:" running-cnt " Not completed test cnt:" not-completed-cnt) (let* ((not-completed-tests (rmt:get-tests-for-run run-id "%" `("NOT_STARTED" "RUNNING" "LAUNCHED" "REMOTEHOSTSTART") `() #f #f #f #f #f #f #f #f))) (if (> (length not-completed-tests) 0) (let loop ((running-test (car not-completed-tests)) (tal (cdr not-completed-tests))) (let* ((test-name (vector-ref running-test 2)) (item-path (vector-ref running-test 11))) (debug:print 0 *default-log-port* "test " test-name "/" item-path " not completed") (if (not (null? tal)) (loop (car tal) (cdr tal))))))))))) (define (launch:is-test-alive host pid) (if (and host pid (not (equal? host "n/a"))) (let* ((cmd (conc "ssh " host " pstree -A " pid)) (output (with-input-from-pipe cmd read-lines))) (debug:print 2 *default-log-port* "Running " cmd " received " output) (if (eq? (length output) 0) #f #t)) #t)) (define (launch:kill-tests-if-dead run-id) (let* ((running-tests (rmt:get-tests-for-run run-id "%" `("RUNNING" "LAUNCHED" "REMOTEHOSTSTART") `() #f #f #f #f #f #f #f #f))) (let loop ((running-test (car running-tests)) (tal (cdr running-tests)) (kill-cnt 0)) (let* ((test-name (vector-ref running-test 2)) (item-path (vector-ref running-test 11)) (test-id (vector-ref running-test 0)) (host (vector-ref running-test 6)) (pid (rmt:test-get-top-process-pid run-id test-id)) (event-time (vector-ref running-test 5)) (duration (vector-ref running-test 12)) (flag 0) (curr-time (current-seconds))) (if (and (< (+ event-time duration 600) curr-time) (not (launch:is-test-alive host pid))) ;;test has not updated duration in last 10 min then likely its not running but confirm before marking it as killed (begin (debug:print 0 *default-log-port* "test " test-name "/" item-path " needs to be killed") (set! flag 1) (rmt:set-state-status-and-roll-up-items run-id test-name item-path "KILLREQ" "n/a" #f))) (if (not (null? tal)) (loop (car tal) (cdr tal) (+ kill-cnt flag)) (+ kill-cnt flag)))))) ;; DO NOT USE - caching of configs is handled in launch:setup now. ;; (define (launch:cache-config) ;; if we have a linktree and -runtests and -target and the directory exists dump the config ;; to megatest-(current-seconds).cfg and symlink it to megatest.cfg (if (and *configdat* (or (args:get-arg "-run") (args:get-arg "-runtests") (args:get-arg "-execute"))) (let* ((linktree (common:get-linktree)) ;; (get-environment-variable "MT_LINKTREE")) (target (common:args-get-target exit-if-bad: #t)) (runname (or (args:get-arg "-runname") (args:get-arg ":runname") (getenv "MT_RUNNAME"))) (fulldir (conc linktree "/" target "/" runname))) (if (and linktree (common:file-exists? linktree)) ;; can't proceed without linktree (begin (debug:print-info 0 *default-log-port* "Have -run with target=" target ", runname=" runname ", fulldir=" fulldir ", testpatt=" (or (args:get-arg "-testpatt") "%")) (if (not (common:file-exists? fulldir)) (create-directory fulldir #t)) ;; need to protect with exception handler (if (and target runname (common:file-exists? fulldir)) (let ((tmpfile (conc fulldir "/.megatest.cfg." (current-seconds))) (targfile (conc fulldir "/.megatest.cfg-" megatest-version "-" megatest-fossil-hash)) (rconfig (conc fulldir "/.runconfig." megatest-version "-" megatest-fossil-hash))) (if (common:file-exists? rconfig) ;; only cache megatest.config AFTER runconfigs has been cached (begin (debug:print-info 0 *default-log-port* "Caching megatest.config in " tmpfile) (if (not (common:in-running-test?)) (configf:write-alist *configdat* tmpfile)) (system (conc "ln -sf " tmpfile " " targfile)))) ))) (debug:print-info 1 *default-log-port* "No linktree yet, no caching configs."))))) |
︙ | ︙ | |||
792 793 794 795 796 797 798 | ;; returns: ;; *toppath* ;; side effects: ;; sets; *configdat* (megatest.config info) ;; *runconfigdat* (runconfigs.config info) ;; *configstatus* (status of the read data) ;; | | | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > | < | < < < > > | < | < | > > | < < | < < < < > > > > | > > > | > > > | > > > > | > | > > > > > > > > > > | > > > > > > < | > > > | > > > | > | < | | > > > > > > > > > > > > > > > > > > > > > > > > | | | > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > | 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 | ;; returns: ;; *toppath* ;; side effects: ;; sets; *configdat* (megatest.config info) ;; *runconfigdat* (runconfigs.config info) ;; *configstatus* (status of the read data) ;; (define (launch:setup #!key (force-reread #f) (areapath #f)) (mutex-lock! *launch-setup-mutex*) (if (and *toppath* (eq? *configstatus* 'fulldata) (not force-reread)) ;; got it all (begin (debug:print 2 *default-log-port* "NOTE: skipping launch:setup-body call since we have fulldata") (mutex-unlock! *launch-setup-mutex*) *toppath*) (let ((res (launch:setup-body force-reread: force-reread areapath: areapath))) (mutex-unlock! *launch-setup-mutex*) res))) ;; return paths depending on what info is available. ;; (define (launch:get-cache-file-paths areapath toppath target mtconfig) (let* ((use-cache (common:use-cache?)) (runname (common:args-get-runname)) (linktree (common:get-linktree)) (testname (common:get-full-test-name)) (rundir (if (and runname target linktree) (common:directory-writable? (conc linktree "/" target "/" runname)) #f)) (testdir (if (and rundir testname) (common:directory-writable? (conc rundir "/" testname)) #f)) (cachedir (or testdir rundir)) (mtcachef (and cachedir (conc cachedir "/" ".megatest.cfg-" megatest-version "-" megatest-fossil-hash))) (rccachef (and cachedir (conc cachedir "/" ".runconfigs.cfg-" megatest-version "-" megatest-fossil-hash)))) (debug:print-info 6 *default-log-port* "runname=" runname "\n linktree=" linktree "\n testname=" testname "\n rundir=" rundir "\n testdir=" testdir "\n cachedir=" cachedir "\n mtcachef=" mtcachef "\n rccachef=" rccachef) (cons mtcachef rccachef))) (define (launch:setup-body #!key (force-reread #f) (areapath #f)) (if (and (eq? *configstatus* 'fulldata) *toppath* (not force-reread)) ;; no need to reprocess *toppath* ;; return toppath (let* ((use-cache (common:use-cache?)) ;; BB- use-cache checks *configdat* for use-cache setting. We do not have *configdat*. Bootstrapping problem here. (toppath (common:get-toppath areapath)) (target (common:args-get-target)) (sections (if target (list "default" target) #f)) ;; for runconfigs (mtconfig (or (args:get-arg "-config") "megatest.config")) ;; allow overriding megatest.config (cachefiles (launch:get-cache-file-paths areapath toppath target mtconfig)) ;; checking for null cachefiles should not be necessary, I was seeing error car of '(), might be a chicken bug or a red herring ... (mtcachef (if (null? cachefiles) #f (car cachefiles))) ;; (and cachedir (conc cachedir "/" ".megatest.cfg-" megatest-version "-" megatest-fossil-hash))) (rccachef (if (null? cachefiles) #f (cdr cachefiles)))) ;; (and cachedir (conc cachedir "/" ".runconfigs.cfg-" megatest-version "-" megatest-fossil-hash))) ;; (cancreate (and cachedir (common:file-exists? cachedir)(file-write-access? cachedir) (not (common:in-running-test?))))) (set! *toppath* toppath) ;; This is needed when we are running as a test using CMDINFO as a datasource ;;(BB> "launch:setup-body -- cachefiles="cachefiles) (cond ;; if mtcachef exists just read it, however we need to assume toppath is available in $MT_RUN_AREA_HOME ((and (not force-reread) mtcachef rccachef use-cache (get-environment-variable "MT_RUN_AREA_HOME") (common:file-exists? mtcachef) (common:file-exists? rccachef)) ;;(BB> "launch:setup-body -- cond branch 1 - use-cache") (set! *configdat* (configf:read-alist mtcachef)) ;;(BB> "launch:setup-body -- 1 set! *configdat*="*configdat*) (set! *runconfigdat* (configf:read-alist rccachef)) (set! *configinfo* (list *configdat* (get-environment-variable "MT_RUN_AREA_HOME"))) (set! *configstatus* 'fulldata) (set! *toppath* (get-environment-variable "MT_RUN_AREA_HOME")) *toppath*) ;; there are no existing cached configs, do full reads of the configs and cache them ;; we have all the info needed to fully process runconfigs and megatest.config ((and ;; (not force-reread) ;; force-reread is irrelevant in the AND, could however OR it? mtcachef rccachef) ;; BB- why are we doing this without asking if caching is desired? ;;(BB> "launch:setup-body -- cond branch 2") (let* ((first-pass (find-and-read-config ;; NB// sets MT_RUN_AREA_HOME as side effect mtconfig environ-patt: "env-override" given-toppath: toppath pathenvvar: "MT_RUN_AREA_HOME")) (first-rundat (let ((toppath (if toppath toppath (car first-pass)))) (read-config ;; (conc toppath "/runconfigs.config") ;; this should be converted to runconfig:read but it is non-trivial, leaving it for now. (conc (if (string? toppath) toppath (get-environment-variable "MT_RUN_AREA_HOME")) "/runconfigs.config") *runconfigdat* #t sections: sections)))) (set! *runconfigdat* first-rundat) (if first-pass ;; (begin ;;(BB> "launch:setup-body -- \"first-pass\"=first-pass") (set! *configdat* (car first-pass)) ;;(BB> "launch:setup-body -- 2 set! *configdat*="*configdat*) (set! *configinfo* first-pass) (set! *toppath* (or toppath (cadr first-pass))) ;; use the gathered data unless already have it (set! toppath *toppath*) (if (not *toppath*) (begin (debug:print-error 0 *default-log-port* "you are not in a megatest area!") (exit 1))) (setenv "MT_RUN_AREA_HOME" *toppath*) ;; the seed read is done, now read runconfigs, cache it then read megatest.config one more time and cache it (let* ((keys (common:list-or-null (rmt:get-keys) message: "Failed to retrieve keys in launch.scm. Please report this to the developers.")) (key-vals (keys:target->keyval keys target)) (linktree (common:get-linktree)) ;; (or (getenv "MT_LINKTREE")(if *configdat* (configf:lookup *configdat* "setup" "linktree") #f))) ; (if *configdat* ; (configf:lookup *configdat* "setup" "linktree") ; (conc *toppath* "/lt")))) (second-pass (find-and-read-config mtconfig environ-patt: "env-override" given-toppath: toppath pathenvvar: "MT_RUN_AREA_HOME")) (runconfigdat (begin ;; this read of the runconfigs will see any adjustments made by re-reading megatest.config (for-each (lambda (kt) (setenv (car kt) (cadr kt))) key-vals) (read-config (conc toppath "/runconfigs.config") *runconfigdat* #t ;; consider using runconfig:read some day ... sections: sections))) (cachefiles (launch:get-cache-file-paths areapath toppath target mtconfig)) (mtcachef (car cachefiles)) (rccachef (cdr cachefiles))) ;; trap exception due to stale NFS handle -- Error: (open-output-file) cannot open file - Stale NFS file handle: "/p/fdk/gwa/lefkowit/mtTesting/qa/primbeqa/links/p1222/11/PDK_r1.1.1/prim/clean/pcell_testgen/.runconfigs.cfg-1.6427-7d1e789cb3f62f9cde719a4865bb51b3c17ea853" - ticket 220546342 ;; TODO - consider 1) using simple-lock to bracket cache write ;; 2) cache in hash on server, since need to do rmt: anyway to lock. (if rccachef (common:fail-safe (lambda () (configf:write-alist runconfigdat rccachef)) (conc "Could not write cache file - "rccachef))) (if mtcachef (common:fail-safe (lambda () (configf:write-alist *configdat* mtcachef)) (conc "Could not write cache file - "mtcachef))) (set! *runconfigdat* runconfigdat) (if (and rccachef mtcachef) (set! *configstatus* 'fulldata)))) ;; no configs found? should not happen but let's try to recover gracefully, return an empty hash-table (set! *configdat* (make-hash-table)) ))) ;; else read what you can and set the flag accordingly ;; here we don't have either mtconfig or rccachef (else ;;(BB> "launch:setup-body -- cond branch 3 - else") (let* ((cfgdat (find-and-read-config (or (args:get-arg "-config") "megatest.config") environ-patt: "env-override" given-toppath: (get-environment-variable "MT_RUN_AREA_HOME") pathenvvar: "MT_RUN_AREA_HOME"))) (if (and cfgdat (list? cfgdat) (> (length cfgdat) 0) (hash-table? (car cfgdat))) (let* ((toppath (or (get-environment-variable "MT_RUN_AREA_HOME")(cadr cfgdat))) (rdat (read-config (conc toppath ;; convert this to use runconfig:read! "/runconfigs.config") *runconfigdat* #t sections: sections))) (set! *configinfo* cfgdat) (set! *configdat* (car cfgdat)) (set! *runconfigdat* rdat) (set! *toppath* toppath) (set! *configstatus* 'partial)) (begin (debug:print-error 0 *default-log-port* "No " mtconfig " file found. Giving up.") (exit 2)))))) ;; COND ends here. ;; additional house keeping (let* ((linktree (or (common:get-linktree) (conc *toppath* "/lt")))) (if linktree (begin (if (not (common:file-exists? linktree)) (begin (handle-exceptions exn (begin (debug:print-error 0 *default-log-port* "Something went wrong when trying to create linktree dir at " linktree) (debug:print 0 *default-log-port* " message: " ((condition-property-accessor 'exn 'message) exn)) (exit 1)) (create-directory linktree #t)))) (handle-exceptions exn (begin (debug:print-error 0 *default-log-port* "Something went wrong when trying to create link to linktree at " *toppath*) (debug:print 0 *default-log-port* " message: " ((condition-property-accessor 'exn 'message) exn))) (let ((tlink (conc *toppath* "/lt"))) (if (not (common:file-exists? tlink)) (create-symbolic-link linktree tlink))))) (begin (debug:print-error 0 *default-log-port* "linktree not defined in [setup] section of megatest.config") ))) (if (and *toppath* (directory-exists? *toppath*)) (begin (setenv "MT_RUN_AREA_HOME" *toppath*) (setenv "MT_TESTSUITENAME" (common:get-testsuite-name))) (begin (debug:print-error 0 *default-log-port* "failed to find the top path to your Megatest area.") (set! *toppath* #f) ;; force it to be false so we return #f #f)) ;; one more attempt to cache the configs for future reading (let* ((cachefiles (launch:get-cache-file-paths areapath toppath target mtconfig)) (mtcachef (car cachefiles)) (rccachef (cdr cachefiles))) ;; trap exception due to stale NFS handle -- Error: (open-output-file) cannot open file - Stale NFS file handle: "...somepath.../.runconfigs.cfg-1.6427-7d1e789cb3f62f9cde719a4865bb51b3c17ea853" - ticket 220546342 ;; TODO - consider 1) using simple-lock to bracket cache write ;; 2) cache in hash on server, since need to do rmt: anyway to lock. (if (and rccachef *runconfigdat* (not (common:file-exists? rccachef))) (common:fail-safe (lambda () (configf:write-alist *runconfigdat* rccachef)) (conc "Could not write cache file - "rccachef)) ) (if (and mtcachef *configdat* (not (common:file-exists? mtcachef))) (common:fail-safe (lambda () (configf:write-alist *configdat* mtcachef)) (conc "Could not write cache file - "mtcachef)) ) (if (and rccachef mtcachef *runconfigdat* *configdat*) (set! *configstatus* 'fulldata))) ;; if have -append-config then read and append here (let ((cfname (args:get-arg "-append-config"))) (if (and cfname (file-read-access? cfname)) (read-config cfname *configdat* #t))) ;; values are added to the hash, no need to do anything special. *toppath*))) (define (get-best-disk confdat testconfig) (let* ((disks (or (and testconfig (hash-table-ref/default testconfig "disks" #f)) (hash-table-ref/default confdat "disks" #f))) (minspace (let ((m (configf:lookup confdat "setup" "minspace"))) (string->number (or m "10000"))))) (if disks (let ((res (common:get-disk-with-most-free-space disks minspace))) ;; min size of 1000, seems tad dumb (if res (cdr res) (begin ;; DEAD CODE PATH - REVISIT! ;; (if (common:low-noise-print 20 "No valid disks or no disk with enough space") ;; (debug:print-error 0 *default-log-port* "No valid disks found in megatest.config. Please add some to your [disks] section and ensure the directory exists and has enough space!\n You can change minspace in the [setup] section of megatest.config. Current setting is: " minspace)) ;;(exit 1) (if (null? disks) (cons 1 (conc *toppath* "/runs")) (let ((paths (sort disks (lambda (x y) (> (string-length (cadr x)) (string-length (cadr y))))))) (let loop ((head (car paths)) (tail (cdr paths))) (let ((result (handle-exceptions exn #f (create-directory (cadr head) #t)))) (if result result (if (null? tail) (cons 1 (conc *toppath* "/runs")) (loop (car tail) (cdr tail))))))))))) ;; no disks definition - use mtrah/runs, fall back to currdir/runs (let* ((toppath (or *toppath* (common:get-toppath *toppath*) (begin (debug:print-error 0 *default-log-port* "Creating runs dir in current directory, this is probably not what you wanted. Please check your setup.") (current-directory)))) (runsdir (conc toppath "/runs"))) (if (not (file-exists? runsdir))(create-directory runsdir)) runsdir) ))) ;; the code creates the necessary directories if it does not exist and returns the path. (define (launch:test-copy test-src-path test-path) (let* ((ovrcmd (let ((cmd (configf:lookup *configdat* "setup" "testcopycmd"))) (if cmd ;; substitute the TEST_SRC_PATH and TEST_TARG_PATH (string-substitute "TEST_TARG_PATH" test-path (string-substitute "TEST_SRC_PATH" test-src-path cmd #t) #t) #f))) (cmd (if ovrcmd ovrcmd (conc "rsync -av" (if (debug:debug-mode 1) "" "q") " " test-src-path "/ " test-path "/" " >> " test-path "/mt_launch.log 2>> " test-path "/mt_launch.log"))) (status (system cmd))) (if (not (eq? status 0)) (debug:print 2 *default-log-port* "ERROR: problem with running \"" cmd "\"")))) ;; Desired directory structure: ;; ;; <linkdir> - <target> - <testname> -. ;; | ;; v ;; <rundir> - <target> - <testname> -|- <itempath(s)> |
︙ | ︙ | |||
1008 1009 1010 1011 1012 1013 1014 | ;; nb// if itempath is not "" then it is prefixed with "/" (toptest-path (conc disk-path (if contour (conc "/" contour) "") "/" testtop-base)) (test-path (conc disk-path (if contour (conc "/" contour) "") "/" test-base)) ;; ensure this exists first as links to subtests must be created there (linktree (common:get-linktree)) | | | > | | | | | | | > | > > > | | | | | | | | | 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 | ;; nb// if itempath is not "" then it is prefixed with "/" (toptest-path (conc disk-path (if contour (conc "/" contour) "") "/" testtop-base)) (test-path (conc disk-path (if contour (conc "/" contour) "") "/" test-base)) ;; ensure this exists first as links to subtests must be created there (linktree (common:get-linktree)) ;; WAS: (let ((rd (configf:lookup *configdat* "setup" "linktree"))) ;; (if rd rd (conc *toppath* "/runs")))) ;; which seems wrong ... (lnkbase (conc linktree (if contour (conc "/" contour) "") "/" target "/" runname)) (lnkpath (conc lnkbase "/" testname)) (lnkpathf (conc lnkpath (if not-iterated "" "/") item-path)) (lnktarget (conc lnkpath "/" item-path))) ;; Update the rundir path in the test record for all, rundir=physical, shortdir=logical ;; rundir shortdir (rmt:general-call 'test-set-rundir-shortdir run-id lnkpathf test-path testname item-path run-id) (debug:print 2 *default-log-port* "INFO:\n lnkbase=" lnkbase "\n lnkpath=" lnkpath "\n toptest-path=" toptest-path "\n test-path=" test-path) (if (not (common:file-exists? linktree)) (begin (debug:print 0 *default-log-port* "WARNING: linktree did not exist! Creating it now at " linktree) (create-directory linktree #t))) ;; (system (conc "mkdir -p " linktree)))) ;; create the directory for the tests dir links, this is needed no matter what... try up to three times (let loop ((done 3)) (let ((success (if (and (not (common:directory-exists? lnkbase)) (not (common:file-exists? lnkbase))) (handle-exceptions exn (begin (debug:print-error 0 *default-log-port* "Problem creating linktree base at " lnkbase) (print-error-message exn (current-error-port)) #t) (create-directory lnkbase #t) #f)))) (if (and (not success)(> done 0)) (loop (- done 1))))) ;; update the toptest record with its location rundir, cache the path ;; This wass highly inefficient, one db write for every subtest, potentially ;; thousands of unnecessary updates, cache the fact it was set and don't set it ;; again. ;; Now create the link from the test path to the link tree, however ;; if the test is iterated it is necessary to create the parent path ;; to the iteration. use pathname-directory to trim the path by one ;; level (if (not not-iterated) ;; i.e. iterated (let ((iterated-parent (pathname-directory (conc lnkpath "/" item-path)))) (debug:print-info 2 *default-log-port* "Creating iterated parent " iterated-parent) (handle-exceptions exn (begin (debug:print-error 0 *default-log-port* " Failed to create directory " iterated-parent ((condition-property-accessor 'exn 'message) exn) ", continuing but link tree may be corrupted") #;(exit 1)) (create-directory iterated-parent #t)))) (if (symbolic-link? lnkpath) (handle-exceptions exn (begin (debug:print-error 0 *default-log-port* " Failed to remove symlink " lnkpath ((condition-property-accessor 'exn 'message) exn) ", continuing but link tree may be corrupted.") #;(exit 1)) (delete-file lnkpath))) (if (not (or (common:file-exists? lnkpath) (symbolic-link? lnkpath))) (handle-exceptions exn (begin (debug:print-error 0 *default-log-port* " Failed to create symlink " lnkpath ((condition-property-accessor 'exn 'message) exn) ", continuing but link tree may be corrupted.") #;(exit 1)) (create-symbolic-link toptest-path lnkpath))) ;; NB - This was not working right - some top tests are not getting the path set!!! ;; ;; Do the setting of this record after the paths are created so that the shortdir can ;; be set to the real directory location. This is safer for future clean up if the link ;; tree is damaged or lost. ;; (if (not (hash-table-ref/default *toptest-paths* testname #f)) (let* ((testinfo (rmt:get-test-info-by-id run-id test-id)) ;; run-id testname item-path)) (curr-test-path (if testinfo ;; (filedb:get-path *fdb* ;; (db:get-path dbstruct ;; (rmt:sdb-qry 'getstr (db:test-get-rundir testinfo) ;; ) ;; ) #f))) (hash-table-set! *toptest-paths* testname curr-test-path) ;; NB// Was this for the test or for the parent in an iterated test? (rmt:general-call 'test-set-rundir-shortdir run-id lnkpath (if (common:file-exists? lnkpath) ;; (resolve-pathname lnkpath) (common:nice-path lnkpath) lnkpath) testname "" run-id) ;; (rmt:general-call 'test-set-rundir run-id lnkpath testname "") ;; toptest-path) (if (or (not curr-test-path) (not (directory-exists? toptest-path))) |
︙ | ︙ | |||
1127 1128 1129 1130 1131 1132 1133 | ;; If there is already a symlink delete it and recreate it. (handle-exceptions exn (begin (debug:print-error 0 *default-log-port* " Failed to re-create link " lnktarget ((condition-property-accessor 'exn 'message) exn) ", exiting") (exit)) (if (symbolic-link? lnktarget) (delete-file lnktarget)) | | < < < < | < < < < < < < < > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | > | | | | > | | | | | | 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 | ;; If there is already a symlink delete it and recreate it. (handle-exceptions exn (begin (debug:print-error 0 *default-log-port* " Failed to re-create link " lnktarget ((condition-property-accessor 'exn 'message) exn) ", exiting") (exit)) (if (symbolic-link? lnktarget) (delete-file lnktarget)) (if (not (common:file-exists? lnktarget)) (create-symbolic-link test-path lnktarget))))) (if (not (directory? test-path)) (create-directory test-path #t)) ;; this is a hack, I don't know why out of the blue this path does not exist sometimes (if (and test-src-path (directory? test-path)) (begin (launch:test-copy test-src-path test-path) (list lnkpathf lnkpath )) (if (and test-src-path (> remtries 0)) (begin (debug:print-error 0 *default-log-port* "Failed to create work area at " test-path " with link at " lnktarget ", remaining attempts " remtries) ;; (create-work-area run-id run-info keyvals test-id test-src-path disk-path testname itemdat remtries: (- remtries 1))) (list #f #f))))) (define (launch:handle-zombie-tests run-id) (let* ((key (conc "zombiescan-runid-"run-id)) (now (current-seconds)) (threshold (- (current-seconds) (* 2 (or (configf:lookup-number *configdat* "setup" "deadtime") 120)))) (val (rmt:get-var key)) (do-scan? (cond ((not val) #t) ((< val threshold) #t) (else #f)))) (when do-scan? (debug:print 1 *default-log-port* "INFO: search and mark zombie tests") (rmt:set-var key (current-seconds)) (rmt:find-and-mark-incomplete run-id #f)))) ;; 1. look though disks list for disk with most space ;; 2. create run dir on disk, path name is meaningful ;; 3. create link from run dir to megatest runs area ;; 4. remotely run the test on allocated host ;; - could be ssh to host from hosts table (update regularly with load) ;; - could be netbatch ;; (launch-test db (cadr status) test-conf)) (define (launch-test test-id run-id run-info keyvals runname test-conf test-name test-path itemdat params) (mutex-lock! *launch-setup-mutex*) ;; setting variables and processing the testconfig is NOT thread-safe, reuse the launch-setup mutex (let* ( ;; (lock-key (conc "test-" test-id)) ;; (got-lock (let loop ((lock (rmt:no-sync-get-lock lock-key)) ;; (expire-time (+ (current-seconds) 15))) ;; give up on getting the lock and steal it after 15 seconds ;; (if (car lock) ;; #t ;; (if (> (current-seconds) expire-time) ;; (begin ;; (debug:print-info 0 *default-log-port* "Timed out waiting for a lock to launch test " keyvals " " runname " " test-name " " test-path) ;; (rmt:no-sync-del! lock-key) ;; destroy the lock ;; (loop (rmt:no-sync-get-lock lock-key) expire-time)) ;; ;; (begin ;; (thread-sleep! 1) ;; (loop (rmt:no-sync-get-lock lock-key) expire-time)))))) (item-path (item-list->path itemdat)) (contour #f)) ;; NOT READY FOR THIS (args:get-arg "-contour"))) (let loop ((delta (- (current-seconds) *last-launch*)) (launch-delay (configf:lookup-number *configdat* "setup" "launch-delay" default: 1))) (if (> launch-delay delta) (begin (if (common:low-noise-print 1200 "test launch delay") ;; every two hours or so remind the user about launch delay. (debug:print-info 0 *default-log-port* "NOTE: test launches are delayed by " launch-delay " seconds. See megatest.config launch-delay setting to adjust.")) ;; launch of " test-name " for " (- launch-delay delta) " seconds")) (thread-sleep! (- launch-delay delta)) (loop (- (current-seconds) *last-launch*) launch-delay)))) (change-directory *toppath*) (alist->env-vars ;; consolidate this code with the code in megatest.scm for "-execute", *maybe* - the longer they are set the longer each launch takes (must be non-overlapping with the vars) (append (list (list "MT_RUN_AREA_HOME" *toppath*) (list "MT_TEST_NAME" test-name) (list "MT_RUNNAME" runname) (list "MT_ITEMPATH" item-path) (list "MT_CONTOUR" contour) ) itemdat)) (let* ((tregistry (tests:get-all)) ;; third param (below) is system-allowed ;; for tconfig, why do we allow fallback to test-conf? (tconfig (or (tests:get-testconfig test-name item-path tregistry #t force-create: #t) (begin (debug:print 0 *default-log-port* "WARNING: falling back to pre-calculated testconfig. This is likely not desired.") test-conf))) ;; force re-read now that all vars are set (useshell (let ((ush (configf:lookup *configdat* "jobtools" "useshell"))) (if ush (if (equal? ush "no") ;; must use "no" to NOT use shell #f ush) #t))) ;; default is yes (runscript (configf:lookup tconfig "setup" "runscript")) (ezsteps (> (length (hash-table-ref/default tconfig "ezsteps" '())) 0)) ;; don't send all the steps, could be big, just send a flag (subrun (> (length (hash-table-ref/default tconfig "subrun" '())) 0)) ;; send a flag to process a subrun ;; (diskspace (configf:lookup tconfig "requirements" "diskspace")) ;; (memory (configf:lookup tconfig "requirements" "memory")) ;; (hosts (configf:lookup *configdat* "jobtools" "workhosts")) ;; I'm pretty sure this was never completed (remote-megatest (configf:lookup *configdat* "setup" "executable")) (run-time-limit (or (configf:lookup tconfig "requirements" "runtimelim") (configf:lookup *configdat* "setup" "runtimelim"))) ;; FIXME SOMEDAY: not good how this is so obtuse, this hack is to ;; allow running from dashboard. Extract the path ;; from the called megatest and convert dashboard ;; or dboard to megatest (local-megatest (let* ((lm (car (argv))) (dir (pathname-directory lm)) (exe (pathname-strip-directory lm))) (conc (if dir (conc dir "/") "") (case (string->symbol exe) ((dboard) "../megatest") ((mtest) "../megatest") ((dashboard) "megatest") (else exe))))) (launcher (common:get-launcher *configdat* test-name item-path)) ;; (configf:lookup *configdat* "jobtools" "launcher")) (test-sig (conc (common:get-testsuite-name) ":" test-name ":" item-path)) ;; (item-list->path itemdat))) ;; test-path is the full path including the item-path (work-area #f) (toptest-work-area #f) ;; for iterated tests the top test contains data relevant for all (diskpath #f) (cmdparms #f) (fullcmd #f) ;; (define a (with-output-to-string (lambda ()(write x)))) (mt-bindir-path #f) |
︙ | ︙ | |||
1281 1282 1283 1284 1285 1286 1287 | (list 'test-name test-name) (list 'runscript runscript) (list 'run-id run-id ) (list 'test-id test-id ) ;; (list 'item-path item-path ) (list 'itemdat itemdat ) (list 'megatest remote-megatest) | | > | | 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 | (list 'test-name test-name) (list 'runscript runscript) (list 'run-id run-id ) (list 'test-id test-id ) ;; (list 'item-path item-path ) (list 'itemdat itemdat ) (list 'megatest remote-megatest) (list 'ezsteps ezsteps) (list 'subrun subrun) (list 'target mt_target) (list 'contour contour) (list 'runtlim (if run-time-limit (common:hms-string->seconds run-time-limit) #f)) (list 'env-ovrd (hash-table-ref/default *configdat* "env-override" '())) (list 'set-vars (if params (hash-table-ref/default params "-setvars" #f))) (list 'runname runname) (list 'mt-bindir-path mt-bindir-path)))))))) ;; clean out step records from previous run if they exist ;; (rmt:delete-test-step-records run-id test-id) ;; if the dir does not exist we may have a itempath where individual variables are a path, launch anyway (if (common:file-exists? work-area) (change-directory work-area)) ;; so that log files from the launch process don't clutter the test dir (cond ;; ((and launcher hosts) ;; must be using ssh hostname ;; (set! fullcmd (append launcher (car hosts)(list remote-megatest "-m" test-sig "-execute" cmdparms) debug-param))) ;; (set! fullcmd (append launcher (car hosts)(list remote-megatest test-sig "-execute" cmdparms)))) (launcher (set! fullcmd (append launcher (list remote-megatest "-m" test-sig "-execute" cmdparms) debug-param))) |
︙ | ︙ | |||
1326 1327 1328 1329 1330 1331 1332 | (list "MT_ITEMPATH" item-path) ) itemdat))) (testprevvals (alist->env-vars (hash-table-ref/default tconfig "pre-launch-env-overrides" '()))) ;; Launchwait defaults to true, must override it to turn off wait (launchwait (if (equal? (configf:lookup *configdat* "setup" "launchwait") "no") #f #t)) | | | | > > > > > | 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 | (list "MT_ITEMPATH" item-path) ) itemdat))) (testprevvals (alist->env-vars (hash-table-ref/default tconfig "pre-launch-env-overrides" '()))) ;; Launchwait defaults to true, must override it to turn off wait (launchwait (if (equal? (configf:lookup *configdat* "setup" "launchwait") "no") #f #t)) (launch-results-prev (apply (if launchwait ;; BB: TODO: refactor this to examine return code of launcher, if nonzero, set state to launch failed. process:cmd-run-with-stderr-and-exitcode->list process-run) (if useshell (let ((cmdstr (string-intersperse fullcmd " "))) (if launchwait cmdstr (conc cmdstr " >> mt_launch.log 2>&1 &"))) (car fullcmd)) (if useshell '() (cdr fullcmd)))) (success (if launchwait (equal? 0 (cadr launch-results-prev)) #t)) (launch-results (if launchwait (car launch-results-prev) launch-results-prev))) (if (not success) (tests:test-set-status! run-id test-id "COMPLETED" "DEAD" "launcher failed; exited non-zero; check mt_launch.log" #f)) ;; (if launch-results launch-results "FAILED")) (mutex-unlock! *launch-setup-mutex*) ;; yes, really should mutex all the way to here. Need to put this entire process into a fork. ;; (rmt:no-sync-del! lock-key) ;; release the lock for starting this test (if (not launchwait) ;; give the OS a little time to allow the process to start (thread-sleep! 0.01)) (with-output-to-file "mt_launch.log" (lambda () (print "LAUNCHCMD: " (string-intersperse fullcmd " ")) (if (list? launch-results) (apply print launch-results) |
︙ | ︙ | |||
1378 1379 1380 1381 1382 1383 1384 | ;; 1. look at the process from pid ;; - is it owned by calling user ;; - it it's run directory correct for the test ;; - is there a controlling mtest (maybe stuck) ;; 2. if recovery is needed watch pid ;; - when it exits take the exit code and do the needful ;; | | | 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 | ;; 1. look at the process from pid ;; - is it owned by calling user ;; - it it's run directory correct for the test ;; - is there a controlling mtest (maybe stuck) ;; 2. if recovery is needed watch pid ;; - when it exits take the exit code and do the needful ;; (let* ((pid (rmt:test-get-top-process-pid run-id test-id)) (psres (with-input-from-pipe (conc "ps -F -u " (current-user-name) " | grep -E '" pid " ' | grep -v 'grep -E " pid "'") (lambda () (read-line)))) (rundir (if (string? psres) ;; real process owned by user (read-symbolic-link (conc "/proc/" pid "/cwd")) #f))) ;; now wait on that process if all is correct ;; periodically update the db with runtime ;; when the process exits look at the db, if still RUNNING after 10 seconds set ;; state/status appropriately (process-wait pid))) |
Deleted loadwatch/Makefile version [d2fa89fb63].
|
| < < < < < < < < < < < |
Deleted loadwatch/bjob-count.sh version [0c8ad639ee].
|
| < < < |
Deleted loadwatch/launch-many.scm version [141ac70432].
|
| < < < < < < < < < |
Deleted loadwatch/loadwatch.scm version [d281425009].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted loadwatch/queuefeeder-server.scm version [4584852f4e].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted loadwatch/queuefeeder.scm version [b7ca858163].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted loadwatch/testopenlava.sh version [1f61657fdf].
|
| < < < < < < < < < |
Modified lock-queue.scm from [9c528b71c8] to [21543b63ce].
1 2 | ;; Copyright 2006-2013, Matthew Welland. ;; | | | > > > > > | | > | > > > < | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | ;; Copyright 2006-2013, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. ;; (use (prefix sqlite3 sqlite3:) srfi-18) (declare (unit lock-queue)) (declare (uses common)) (declare (uses tasks)) ;;====================================================================== ;; attempt to prevent overlapping updates of rollup files by queueing |
︙ | ︙ | |||
31 32 33 34 35 36 37 | (define (lock-queue:delete-lock-db dbdat) (let ((fname (lock-queue:db-dat-get-path dbdat))) (system (conc "rm -f " fname "*")))) (define (lock-queue:open-db fname #!key (count 10)) (let* ((actualfname (conc fname ".lockdb")) | | | 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | (define (lock-queue:delete-lock-db dbdat) (let ((fname (lock-queue:db-dat-get-path dbdat))) (system (conc "rm -f " fname "*")))) (define (lock-queue:open-db fname #!key (count 10)) (let* ((actualfname (conc fname ".lockdb")) (dbexists (common:file-exists? actualfname)) (db (sqlite3:open-database actualfname)) (handler (make-busy-timeout 136000))) (if dbexists (vector db actualfname) (begin (handle-exceptions exn |
︙ | ︙ | |||
162 163 164 165 166 167 168 | (lock-queue:release-lock fname test-id count: (- count 1))) (let ((journal (conc fname "-journal"))) ;; If we've tried ten times and failed there is a serious problem ;; try to remove the lock db and allow it to be recreated (handle-exceptions exn #f | | | | 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 | (lock-queue:release-lock fname test-id count: (- count 1))) (let ((journal (conc fname "-journal"))) ;; If we've tried ten times and failed there is a serious problem ;; try to remove the lock db and allow it to be recreated (handle-exceptions exn #f (if (common:file-exists? journal)(delete-file journal)) (if (common:file-exists? fname) (delete-file fname)) #f)))) (sqlite3:execute (lock-queue:db-dat-get-db dbdat) "DELETE FROM runlocks WHERE test_id=?;" test-id) (sqlite3:finalize! (lock-queue:db-dat-get-db dbdat))))) (define (lock-queue:steal-lock dbdat test-id #!key (count 10)) (debug:print-info 0 *default-log-port* "Attempting to steal lock at " (lock-queue:db-dat-get-path dbdat)) (tasks:wait-on-journal (lock-queue:db-dat-get-path dbdat) 1200 "lock-queue:steal-lock; waiting on journal") |
︙ | ︙ |
Modified margs.scm from [22bfa302f5] to [812fd1b225].
1 2 | ;; Copyright 2007-2010, Matthew Welland. ;; | | | > > > > | > | | > > > > | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | ;; Copyright 2007-2010, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. (declare (unit margs)) ;; (declare (uses common)) (define args:arg-hash (make-hash-table)) (define (args:get-arg arg . default) |
︙ | ︙ |
Modified megatest-version.scm from [2192f48d99] to [5d53cbbe46].
1 2 3 4 5 | ;; Always use two or four digit decimal ;; 1.01, 1.02...1.10,1.11,1.1101 ... 1.99,2.00.. (declare (unit megatest-version)) | > > > > > > > > > > > > > > > > > | < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | ;; Copyright 2006-2017, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. ;; Always use two or four digit decimal ;; 1.01, 1.02...1.10,1.11,1.1101 ... 1.99,2.00.. (declare (unit megatest-version)) (define megatest-version 1.6557) |
Modified megatest.config from [c34072fd64] to [660bed5542].
|
| > > > > > > > > > > > > > > > > > > | | | | > > > > | > | > | | > > | | > | | > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 | # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. ## commented out due to a bug in v1.6501 in mtutil ## [fields] ## a text ## b text ## c text usercode .mtutil.scm areafilter area-to-run targtrans generic-target-translator runtrans generic-runname-translator [setup] pktsdirs /tmp/mt_pkts /some/other/source [areas] # path-to-area map-target-script(future, optional) # someqa path=../megatestqa/someqa; targtrans=somefunc; areafilter=area-to-run fullrun path=tests/fullrun; # targtrans is name of scheme proc stored in .mtutil.scm, which lives in PWD where mtutil is run # the target translator can return: a/target OR (list/of targets/to apply/run) OR #f i.e. run nothing # ext-tests path=ext-tests; targtrans=prefix-contour; ext path=ext-tests [contours] # selector=tag-expr/mode-patt quick areas=ext; selector=/QUICKPATT quick2 areafn=check-area; selector=/QUICKPATT # quick areas=fullrun,ext-tests; selector=QUICKPATT/quick # full areas=fullrun,ext-tests; selector=MAXPATT/ # short areas=fullrun,ext-tests; selector=MAXPATT/ # all areas=fullrun,ext-tests # snazy selector=QUICKPATT/ [nopurpose] [access] ext #{getenv USER}:admin matt:admin mattw:owner [accesstypes] admin run rerun resume remove set-ss rerun-clean owner run rerun resume remove rerun-all badguy set-ss [setup] maxload 1.2 [listeners] localhost:12345 contact=matt@kiatoa.com localhost:54321 contact=matt@kiatoa.com [listener] script nbfake echo [server] timeout 1 [include local.config] |
Modified megatest.scm from [d6dfc96888] to [c7191390c1].
1 2 | ;; Copyright 2006-2017, Matthew Welland. ;; | | | > > > > > | | > | > > > > | | < < < | > > > > > > > | > > > > > > > > > > > > > > > > > > > | | | > > > > > > > > > > | > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 | ;; Copyright 2006-2017, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. ;; ;; (include "common.scm") ;; (include "megatest-version.scm") ;; fake out readline usage of toplevel-command (define (toplevel-command . a) #f) (use (prefix sqlite3 sqlite3:) srfi-1 posix regex regex-case srfi-69 (prefix base64 base64:) readline apropos json http-client directory-utils typed-records http-client srfi-18 extras format) ;; Added for csv stuff - will be removed ;; (use sparse-vectors) (require-library mutils) ;; (use zmq) (declare (uses common)) (declare (uses megatest-version)) (declare (uses margs)) (declare (uses runs)) (declare (uses launch)) (declare (uses server)) (declare (uses client)) (declare (uses tests)) (declare (uses genexample)) ;; (declare (uses daemon)) (declare (uses db)) ;; (declare (uses dcommon)) (declare (uses tdb)) (declare (uses mt)) (declare (uses api)) (declare (uses tasks)) ;; only used for debugging. (declare (uses env)) (declare (uses diff-report)) (declare (uses ftail)) (import ftail) (define *db* #f) ;; this is only for the repl, do not use in general!!!! (include "common_records.scm") (include "key_records.scm") (include "db_records.scm") (include "run_records.scm") (include "megatest-fossil-hash.scm") (define *usage-log-file* #f) ;; put path to file for logging usage in this var in the ~/.megatestrc file (define *usage-use-seconds* #t) ;; for Epoc seconds in usage logging change this to #t in ~/.megatestrc file ;; load the ~/.megatestrc file, put (use trace)(trace-call-sites #t)(trace function-you-want-to-trace) in this file ;; (let ((debugcontrolf (conc (get-environment-variable "HOME") "/.megatestrc"))) (if (common:file-exists? debugcontrolf) (load debugcontrolf))) ;; usage logging, careful with this, it is not designed to deal with all real world challenges! ;; (if (and *usage-log-file* (file-write-access? *usage-log-file*)) (with-output-to-file *usage-log-file* (lambda () (print (if *usage-use-seconds* (current-seconds) (time->string (seconds->local-time (current-seconds)) "%Yww%V.%w %H:%M:%S")) " " (current-user-name) " " (current-directory) " " "\"" (string-intersperse (argv) " ") "\"")) #:append)) ;; Disabled help items ;; -rollup : (currently disabled) fill run (set by :runname) with latest test(s) ;; from prior runs with same keys ;; -daemonize : fork into background and disconnect from stdin/out (define help (conc " Megatest, documentation at http://www.kiatoa.com/fossils/megatest version " megatest-version " license GPL, Copyright Matt Welland 2006-2017 Usage: megatest [options] -h : this help -manual : show the Megatest user manual -version : print megatest version (currently " megatest-version ") Launching and managing runs -run : run all tests or as specified by -testpatt -remove-runs : remove the data for a run, requires -runname and -testpatt Optionally use :state and :status, use -keep-records to remove only the run data. Use -kill-wait to override the 10 second per test wait after kill delay. -kill-runs : kill existing run(s) (all incomplete tests killed) -kill-rerun : kill an existing run (all incomplete tests killed and run is rerun) -set-state-status X,Y : set state to X and status to Y, requires controls per -remove-runs -rerun FAIL,WARN... : force re-run for tests with specificed status(s) -rerun-clean : set all tests not COMPLETED+PASS,WARN,WAIVED to NOT_STARTED,n/a and then run the specified testpatt with -preclean -rerun-all : set all tests to NOT_STARTED,n/a and run with -preclean -lock : lock run specified by target and runname -unlock : unlock run specified by target and runname -set-run-status status : sets status for run to status, requires -target and -runname -get-run-status : gets status for run specified by target and runname -run-wait : wait on run specified by target and runname -preclean : remove the existing test directory before running the test -clean-cache : remove the cached megatest.config and runconfigs.config files -no-cache : do not use the cached config files. -one-pass : launch as many tests as you can but do not wait for more to be ready -remove-keep N : remove all but N most recent runs per target; use '-actions, -age, -precmd' -age <age> : 120d,3h,20m to apply only to runs older than the specified age. NB// M=month, m=minute -actions <action>[,...] : actions to take; print,remove-runs,archive,kill-runs -precmd : insert a wrapper command in front of the commands run Selectors (e.g. use for -runtests, -remove-runs, -set-state-status, -list-runs etc.) -target key1/key2/... : run for key1, key2, etc. -reqtarg key1/key2/... : run for key1, key2, etc. but key1/key2 must be in runconfigs -testpatt patt1/patt2,patt3/... : % is wildcard -runname : required, name for this particular test run -state : Applies to runs, tests or steps depending on context -status : Applies to runs, tests or steps depending on context -modepatt key : load testpatt from <key> in runconfigs instead of default TESTPATT if -testpatt and -tagexpr are not specified -tagexpr tag1,tag2%,.. : select tests with tags matching expression Test helpers (for use inside tests) -step stepname -test-status : set the state and status of a test (use :state and :status) -setlog logfname : set the path/filename to the final log relative to the test directory. may be used with -test-status -set-toplog logfname : set the overall log for a suite of sub-tests |
︙ | ︙ | |||
131 132 133 134 135 136 137 | -test-paths : get the test paths matching target, runname, item and test patterns. -list-disks : list the disks available for storing runs -list-targets : list the targets in runconfigs.config -list-db-targets : list the target combinations used in the db -show-config : dump the internal representation of the megatest.config file -show-runconfig : dump the internal representation of the runconfigs.config file | | > > > | 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 | -test-paths : get the test paths matching target, runname, item and test patterns. -list-disks : list the disks available for storing runs -list-targets : list the targets in runconfigs.config -list-db-targets : list the target combinations used in the db -show-config : dump the internal representation of the megatest.config file -show-runconfig : dump the internal representation of the runconfigs.config file -dumpmode MODE : dump in MODE format instead of sexpr, MODE=json,ini,sexp etc. (add -debug 0,9 to see which file contributes each line) -show-cmdinfo : dump the command info for a test (run in test environment) -section sectionName -var varName : for config and runconfig lookup value for sectionName varName -since N : get list of runs changed since time N (Unix seconds) -fields fieldspec : fields to include in json dump; runs:id,runame+tests:testname+steps -sort fieldname : in -list-runs sort tests by this field -testdata-csv [categorypatt/]varpatt : dump testdata for given category Misc -start-dir path : switch to this directory before running megatest -contour cname : add a level of hierarcy to the linktree and run paths -area-tag tagname : add a tag to an area while syncing to pgdb -run-tag tagname : add a tag to a run while syncing to pgdb -rebuild-db : bring the database schema up to date -cleanup-db : remove any orphan records, vacuum the db -import-megatest.db : push data from megatest.db to cache db files in /tmp/$USER -sync-to-megatest.db : pull data from cache files in /tmp/$USER to megatest.db -sync-to dest : sync to new postgresql central style database -update-meta : update the tests metadata for all tests -setvars VAR1=val1,VAR2=val2 : Add environment variables to a run NB// these are |
︙ | ︙ | |||
177 178 179 180 181 182 183 | -refdb2dat refdb : convert refdb to sexp or to format specified by s-dumpmode formats: perl, ruby, sqlite3, csv (for csv the -o param will substitute %s for the sheet name in generating multiple sheets) -o : output file for refdb2dat (defaults to stdout) -archive cmd : archive runs specified by selectors to one of disks specified in the [archive-disks] section. | | > | > > > > > > > > | 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 | -refdb2dat refdb : convert refdb to sexp or to format specified by s-dumpmode formats: perl, ruby, sqlite3, csv (for csv the -o param will substitute %s for the sheet name in generating multiple sheets) -o : output file for refdb2dat (defaults to stdout) -archive cmd : archive runs specified by selectors to one of disks specified in the [archive-disks] section. cmd: keep-html, restore, save, save-remove, get (use -dest to set destination), -include path1,path2... to get or save specific files -generate-html : create a simple html dashboard for browsing your runs -generate-html-structure : create a top level html veiw to list targets/runs and a Run view within each run directory. -list-run-time : list time requered to complete runs. It supports following switches -run-patt <patt> -target-patt <patt> -dumpmode <csv,json,plain-text> -list-test-time : list time requered to complete each test in a run. It following following arguments -runname <patt> -target <patt> -dumpmode <csv,json,plain-text> Diff report -diff-rep : generate diff report (must include -src-target, -src-runname, -target, -runname and either -diff-email or -diff-html) -src-target <target> -src-runname <target> -diff-email <emails> : comma separated list of email addresses to send diff report |
︙ | ︙ | |||
226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 | ":runname" "-runname" ":state" "-state" ":status" "-status" "-list-runs" "-testpatt" "--modepatt" "-tagexpr" "-itempatt" "-setlog" "-set-toplog" "-runstep" "-logpro" "-m" "-rerun" "-days" "-rename-run" "-to" ;; values and messages ":category" ":variable" ":value" ":expected" ":tol" ":units" ;; misc "-start-dir" "-contour" "-server" "-transport" "-port" "-extract-ods" "-pathmod" "-env2file" "-envcap" "-envdelta" "-setvars" "-set-state-status" "-set-run-status" "-debug" ;; for *verbosity* > 2 "-create-test" "-override-timeout" "-test-files" ;; -test-paths is for listing all "-load" ;; load and exectute a scheme file "-section" "-var" "-dumpmode" "-run-id" "-ping" "-refdb2dat" "-o" "-log" | > > > > > > > > > > > > > > > > > > > > > > | > | 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 | ":runname" "-runname" ":state" "-state" ":status" "-status" "-list-runs" "-testdata-csv" "-testpatt" "--modepatt" "-modepatt" "-tagexpr" "-itempatt" "-setlog" "-set-toplog" "-runstep" "-logpro" "-m" "-rerun" "-days" "-rename-run" "-to" "-dest" ;; values and messages ":category" ":variable" ":value" ":expected" ":tol" ":units" ;; misc "-start-dir" "-run-patt" "-target-patt" "-contour" "-area-tag" "-area" "-run-tag" "-server" "-transport" "-port" "-extract-ods" "-pathmod" "-env2file" "-envcap" "-envdelta" "-setvars" "-set-state-status" ;; move runs stuff here "-remove-keep" "-set-run-status" "-age" ;; archive "-archive" "-actions" "-precmd" "-include" "-exclude-rx" "-exclude-rx-from" "-debug" ;; for *verbosity* > 2 "-create-test" "-override-timeout" "-test-files" ;; -test-paths is for listing all "-load" ;; load and exectute a scheme file "-section" "-var" "-dumpmode" "-run-id" "-ping" "-refdb2dat" "-o" "-log" "-sync-log" "-since" "-fields" "-recover-test" ;; run-id,test-id - used internally to recover a test stuck in RUNNING state "-sort" "-target-db" "-source-db" "-prefix-target" "-src-target" "-src-runname" "-diff-email" "-sync-to" "-pgsync" "-kill-wait" ;; wait this long before removing test (default is 10 sec) "-diff-html" ) (list "-h" "-help" "--help" "-manual" "-version" "-force" "-xterm" |
︙ | ︙ | |||
308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 | "-daemonize" "-preclean" "-rerun-clean" "-rerun-all" "-clean-cache" "-no-cache" "-cache-db" "-use-db-cache" "-prepend-contour" ;; misc "-repl" "-lock" "-unlock" "-list-servers" "-kill-servers" "-run-wait" ;; wait on a run to complete (i.e. no RUNNING) "-local" ;; run some commands using local db access | > > > > | > > > | > > > | | 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 | "-daemonize" "-preclean" "-rerun-clean" "-rerun-all" "-clean-cache" "-no-cache" "-cache-db" "-cp-eventtime-to-publishtime" "-use-db-cache" "-prepend-contour" ;; misc "-repl" "-lock" "-unlock" "-list-servers" "-kill-servers" "-run-wait" ;; wait on a run to complete (i.e. no RUNNING) "-one-pass" ;; "-local" ;; run some commands using local db access "-generate-html" "-generate-html-structure" "-list-run-time" "-list-test-time" ;; misc queries "-list-disks" "-list-targets" "-list-db-targets" "-show-runconfig" "-show-config" "-show-cmdinfo" "-get-run-status" ;; queries "-test-paths" ;; get path(s) to a test, ordered by youngest first "-runall" ;; run all tests, respects -testpatt, defaults to % "-run" ;; alias for -runall "-remove-runs" "-kill-runs" "-kill-rerun" "-keep-records" ;; use with -remove-runs to remove only the run data "-rebuild-db" "-cleanup-db" "-rollup" "-update-meta" "-create-megatest-area" "-mark-incompletes" "-convert-to-norm" "-convert-to-old" "-import-megatest.db" "-sync-to-megatest.db" "-sync-brute-force" "-logging" "-v" ;; verbose 2, more than normal (normal is 1) "-q" ;; quiet 0, errors/warnings only "-diff-rep" ) args:arg-hash |
︙ | ︙ | |||
370 371 372 373 374 375 376 | ) )) (debug:print-error 0 *default-log-port* "Unrecognised arguments: " (string-intersperse (if (list? remargs) remargs (argv)) " "))) ;; before doing anything else change to the start-dir if provided ;; (if (args:get-arg "-start-dir") | | | > > > > > > > > > | > | | > > > > > > | > > > | | | 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 | ) )) (debug:print-error 0 *default-log-port* "Unrecognised arguments: " (string-intersperse (if (list? remargs) remargs (argv)) " "))) ;; before doing anything else change to the start-dir if provided ;; (if (args:get-arg "-start-dir") (if (common:file-exists? (args:get-arg "-start-dir")) (let ((fullpath (common:real-path (args:get-arg "-start-dir")))) (setenv "PWD" fullpath) (change-directory fullpath)) (begin (debug:print-error 0 *default-log-port* "non-existant start dir " (args:get-arg "-start-dir") " specified, exiting.") (exit 1)))) ;; immediately set MT_TARGET if -reqtarg or -target are available ;; (let ((targ (or (args:get-arg "-reqtarg")(args:get-arg "-target")))) (if targ (setenv "MT_TARGET" targ))) ;; The watchdog is to keep an eye on things like db sync etc. ;; ;; TODO: for multiple areas, we will have multiple watchdogs; and multiple threads to manage (define *watchdog* (make-thread (lambda () (handle-exceptions exn (begin (print-call-chain) (print " message: " ((condition-property-accessor 'exn 'message) exn))) (common:watchdog))) "Watchdog thread")) ;;(if (not (args:get-arg "-server")) ;; (thread-start! *watchdog*)) ;; if starting a server; wait till we get to running state before kicking off watchdog (let* ((no-watchdog-args '("-list-runs" "-testdata-csv" "-list-servers" "-server" "-list-disks" "-list-targets" "-show-runconfig" ;;"-list-db-targets" "-show-runconfig" "-show-config" "-show-cmdinfo" "-cleanup-db")) (no-watchdog-args-vals (filter (lambda (x) x) (map args:get-arg no-watchdog-args))) (start-watchdog (null? no-watchdog-args-vals))) ;;(BB> "no-watchdog-args="no-watchdog-args "no-watchdog-args-vals="no-watchdog-args-vals) (if start-watchdog (thread-start! *watchdog*))) ;; bracket open-output-file with code to make leading directory if it does not exist and handle exceptions (define (open-logfile logpath-in) (condition-case (let* ((log-dir (or (pathname-directory logpath-in) ".")) (fname (pathname-strip-directory logpath-in)) (logpath (if (> (string-length fname) 250) (let ((newlogf (conc log-dir "/" (common:get-signature fname) ".log"))) (debug:print 0 *default-log-port* "WARNING: log file " logpath-in " path too long, converted to " newlogf) newlogf) logpath-in))) (if (not (directory-exists? log-dir)) (system (conc "mkdir -p " log-dir))) (open-output-file logpath)) (exn () (debug:print-error 0 *default-log-port* "Could not open log file for write: "logpath) (define *didsomething* #t) (exit 1)))) ;; this segment will run launch:setup only if -log is not set. This is fairly safe as servers are not ;; manually started and thus should never be started in a non-megatest area. Thus no need to handle situation ;; where (launch:setup) returns #f? ;; (if (or (args:get-arg "-log")(args:get-arg "-server")) ;; redirect the log always when a server (handle-exceptions exn (begin (print "ERROR: Failed to switch to log output. " ((condition-property-accessor 'exn 'message) exn)) ) (let* ((tl (or (args:get-arg "-log")(launch:setup))) ;; run launch:setup if -server, ensure we do NOT run launch:setup if -log specified (logf (or (args:get-arg "-log") ;; use -log unless we are a server, then craft a logfile name (conc tl "/logs/server-" (current-process-id) "-" (get-host-name) ".log"))) (oup (open-logfile logf))) (if (not (args:get-arg "-log")) (hash-table-set! args:arg-hash "-log" logf)) ;; fake out future queries of -log (debug:print-info 0 *default-log-port* "Sending log output to " logf) (set! *default-log-port* oup)))) |
︙ | ︙ | |||
451 452 453 454 455 456 457 | (if (args:get-arg "-manual") (let* ((htmlviewercmd (or (configf:lookup *configdat* "setup" "htmlviewercmd") (common:which '("firefox" "arora")))) (install-home (common:get-install-area)) (manual-html (conc install-home "/share/docs/megatest_manual.html"))) (if (and install-home | | | 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 | (if (args:get-arg "-manual") (let* ((htmlviewercmd (or (configf:lookup *configdat* "setup" "htmlviewercmd") (common:which '("firefox" "arora")))) (install-home (common:get-install-area)) (manual-html (conc install-home "/share/docs/megatest_manual.html"))) (if (and install-home (common:file-exists? manual-html)) (system (conc "(" htmlviewercmd " " manual-html " ) &")) (system (conc "(" htmlviewercmd " http://www.kiatoa.com/cgi-bin/fossils/megatest/doc/tip/docs/manual/megatest_manual.html ) &"))) (exit))) (if (args:get-arg "-version") (begin (print (common:version-signature)) ;; (print megatest-version) |
︙ | ︙ | |||
490 491 492 493 494 495 496 | (printf "Sending signal/term to ~A\n" pid) (process-signal pid signal/term)))))) (process:children #f)) (original-exit exit-code))))) ;; for some switches always print the command to stderr ;; | | > > > > > > > > > > > > > > | | | 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 | (printf "Sending signal/term to ~A\n" pid) (process-signal pid signal/term)))))) (process:children #f)) (original-exit exit-code))))) ;; for some switches always print the command to stderr ;; (if (args:any? "-run" "-runall" "-remove-runs" "-set-state-status" "-kill-runs" "-kill-rerun") (debug:print 0 *default-log-port* (string-intersperse (argv) " "))) ;; some switches imply homehost. Exit here if not on homehost ;; (let ((homehost-required (list "-cleanup-db" "-server"))) (if (apply args:any? homehost-required) (if (not (common:on-homehost?)) (for-each (lambda (switch) (if (args:get-arg switch) (begin (debug:print 0 *default-log-port* "ERROR: you must be on the homehost to run with " switch ", you can move homehost by removing the .homehost file but this will disrupt any runs in progress.") (exit 1)))) homehost-required)))) ;;====================================================================== ;; Misc setup stuff ;;====================================================================== (debug:setup) (if (args:get-arg "-logging")(set! *logging* #t)) ;;(if (debug:debug-mode 3) ;; we are obviously debugging ;; (set! open-run-close open-run-close-no-exception-handling)) (if (args:get-arg "-itempatt") (let ((newval (conc (args:get-arg "-testpatt") "/" (args:get-arg "-itempatt")))) (debug:print 0 *default-log-port* "WARNING: -itempatt has been deprecated, please use -testpatt testpatt/itempatt method, new testpatt is "newval) (hash-table-set! args:arg-hash "-testpatt" newval) (hash-table-delete! args:arg-hash "-itempatt"))) |
︙ | ︙ | |||
532 533 534 535 536 537 538 | (set! *didsomething* #t))) ;; handle a clean-cache request as early as possible ;; (if (args:get-arg "-clean-cache") (let ((toppath (launch:setup))) (set! *didsomething* #t) ;; suppress the help output. | > | > | 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 | (set! *didsomething* #t))) ;; handle a clean-cache request as early as possible ;; (if (args:get-arg "-clean-cache") (let ((toppath (launch:setup))) (set! *didsomething* #t) ;; suppress the help output. (runs:clean-cache (common:args-get-target) (args:get-arg "-runname") toppath))) (if (args:get-arg "-env2file") (begin (save-environment-as-files (args:get-arg "-env2file")) (set! *didsomething* #t))) (if (args:get-arg "-list-disks") |
︙ | ︙ | |||
688 689 690 691 692 693 694 | (display "\n") (loop (+ row 1) 0 '() (append result (list curr-row)))) (else (loop row (+ col 1) (append curr-row (list val)) result))))))))) (hash-table-keys results)))) ((sqlite3) (let* ((db-file (or out-file (pathname-file input-db))) | | | 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 | (display "\n") (loop (+ row 1) 0 '() (append result (list curr-row)))) (else (loop row (+ col 1) (append curr-row (list val)) result))))))))) (hash-table-keys results)))) ((sqlite3) (let* ((db-file (or out-file (pathname-file input-db))) (db-exists (common:file-exists? db-file)) (db (sqlite3:open-database db-file))) (if (not db-exists)(sqlite3:execute db "CREATE TABLE data (sheet,section,var,val);")) (configf:map-all-hier-alist data (lambda (sheetname sectionname varname val) (sqlite3:execute db "INSERT OR REPLACE INTO data (sheet,section,var,val) VALUES (?,?,?,?);" |
︙ | ︙ | |||
748 749 750 751 752 753 754 | (with-output-to-file (args:get-arg "-o") (lambda () (env:print added removed changed))) (env:print added removed changed)) (env:close-database db) (set! *didsomething* #t)) | | | 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 | (with-output-to-file (args:get-arg "-o") (lambda () (env:print added removed changed))) (env:print added removed changed)) (env:close-database db) (set! *didsomething* #t)) (debug:print-error 0 *default-log-port* "Parameter to -envdelta should be new=start-end"))))) ;;====================================================================== ;; Start the server - can be done in conjunction with -runall or -runtests (one day...) ;; we start the server if not running else start the client thread ;;====================================================================== ;; Server? Start up here. |
︙ | ︙ | |||
836 837 838 839 840 841 842 | ;; *runconfigdat*))) (let* ((rundir (if (and (getenv "MT_LINKTREE")(getenv "MT_TARGET")(getenv "MT_RUNNAME")) (conc (getenv "MT_LINKTREE") "/" (getenv "MT_TARGET") "/" (getenv "MT_RUNNAME")) #f)) (cfgf (if rundir (conc rundir "/.runconfig." megatest-version "-" megatest-fossil-hash) #f))) (if (and cfgf | | | 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 | ;; *runconfigdat*))) (let* ((rundir (if (and (getenv "MT_LINKTREE")(getenv "MT_TARGET")(getenv "MT_RUNNAME")) (conc (getenv "MT_LINKTREE") "/" (getenv "MT_TARGET") "/" (getenv "MT_RUNNAME")) #f)) (cfgf (if rundir (conc rundir "/.runconfig." megatest-version "-" megatest-fossil-hash) #f))) (if (and cfgf (common:file-exists? cfgf) (file-write-access? cfgf) (common:use-cache?)) (configf:read-alist cfgf) (let* ((keys (rmt:get-keys)) (target (common:args-get-target)) (key-vals (if target (keys:target->keyval keys target) #f)) (sections (if target (list "default" target) #f)) |
︙ | ︙ | |||
859 860 861 862 863 864 865 | (if (and rundir ;; have all needed variabless (directory-exists? rundir) (file-write-access? rundir)) (begin (if (not (common:in-running-test?)) (configf:write-alist data cfgf)) ;; force re-read of megatest.config - this resolves circular references between megatest.config | | > | | 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 | (if (and rundir ;; have all needed variabless (directory-exists? rundir) (file-write-access? rundir)) (begin (if (not (common:in-running-test?)) (configf:write-alist data cfgf)) ;; force re-read of megatest.config - this resolves circular references between megatest.config (launch:setup force-reread: #t) ;; (launch:cache-config) ;; there are two independent config cache locations, turning this one off for now. MRW. )) ;; we can safely cache megatest.config since we have a valid runconfig data)))) (if (args:get-arg "-show-runconfig") (let ((tl (launch:setup))) (push-directory *toppath*) (let ((data (full-runconfigs-read))) ;; keep this one local |
︙ | ︙ | |||
899 900 901 902 903 904 905 | ((and (args:get-arg "-section") (args:get-arg "-var")) (let ((val (configf:lookup data (args:get-arg "-section")(args:get-arg "-var")))) (if val (print val)))) ;; print just a section if only -section | | | > | | 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 | ((and (args:get-arg "-section") (args:get-arg "-var")) (let ((val (configf:lookup data (args:get-arg "-section")(args:get-arg "-var")))) (if val (print val)))) ;; print just a section if only -section ((equal? (args:get-arg "-dumpmode") "sexp") (pp (hash-table->alist data))) ((equal? (args:get-arg "-dumpmode") "json") (json-write data)) ((or (not (args:get-arg "-dumpmode")) (string=? (args:get-arg "-dumpmode") "ini")) (configf:config->ini data)) (else (debug:print-error 0 *default-log-port* "-dumpmode of " (args:get-arg "-dumpmode") " not recognised"))) (set! *didsomething* #t) (pop-directory) (set! *time-to-exit* #t))) |
︙ | ︙ | |||
926 927 928 929 930 931 932 | ;;====================================================================== ;; Remove old run(s) ;;====================================================================== ;; since several actions can be specified on the command line the removal ;; is done first | | > > > > > > > > | > | > < | | > | | > | | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > | 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 | ;;====================================================================== ;; Remove old run(s) ;;====================================================================== ;; since several actions can be specified on the command line the removal ;; is done first (define (operate-on action #!key (mode #f)(target-in #f)(runname-in #f)(keys-in #f)(keyvals-in #f)) ;; #f is "use default" (let* ((runrec (runs:runrec-make-record)) (target (or target-in (common:args-get-target))) ;; eventually get rid of the call to common:args-get-target (runname (or runname-in (args:get-arg "-runname"))) ;; eventually get rid of the get-arg calls (testpatt (or (args:get-arg "-testpatt") (and (eq? action 'archive) ;; if it is an archive command fallback to MT_TEST_NAME and MT_ITEMPATH (common:get-full-test-name)) (and (eq? action 'kill-runs) "%/%") ;; I'm just guessing that this is correct :( (common:args-get-testpatt #f) ;; (args:get-arg "-testpatt"))) ))) ;; (cond ((not target) (debug:print-error 0 *default-log-port* "Missing required parameter for " action ", you must specify -target or -reqtarg") (exit 1)) ((not runname) (debug:print-error 0 *default-log-port* "Missing required parameter for " action ", you must specify the run name pattern with -runname patt") (exit 2)) ((not testpatt) (debug:print-error 0 *default-log-port* "Missing required parameter for " action ", you must specify the test pattern with -testpatt") (exit 3)) (else (if (not (car *configinfo*)) (begin (debug:print-error 0 *default-log-port* "Attempted " action "on test(s) but run area config file not found") (exit 1)) ;; put test parameters into convenient variables (begin ;; check for correct version, exit with message if not correct (common:exit-on-version-changed) (runs:operate-on action target runname testpatt state: (common:args-get-state) status: (common:args-get-status) new-state-status: (args:get-arg "-set-state-status") mode: mode))) (set! *didsomething* #t))))) (if (args:get-arg "-kill-runs") (general-run-call "-kill-runs" "kill runs" (lambda (target runname keys keyvals) (operate-on 'kill-runs mode: #f) ))) (if (args:get-arg "-kill-rerun") (let* ((target-patt (common:args-get-target)) (runname-patt (args:get-arg "-runname"))) (cond ((not target-patt) (debug:print-error 0 *default-log-port* "Missing target, must specify target for -kill-rerun with -target <target name>") (exit 1)) ((not runname-patt) (debug:print-error 0 *default-log-port* "Missing runname, must specify runname for -kill-rerun with -runname <run name>") (exit 1)) ((string-search "[ ,%]" target-patt) (debug:print-error 0 *default-log-port* "Invalid target ["target-patt"], must specify exact target (no wildcards) for -kill-rerun with -target <target name>") (exit 1)) ((string-search "[ ,%]" runname-patt) (debug:print-error 0 *default-log-port* "Invalid runname ["runname-patt"], must specify exact runname (no wildcards) for -kill-rerun with -runname <runname name>") (exit 1)) (else (general-run-call "-kill-runs" "kill runs" (lambda (target runname keys keyvals) (operate-on 'kill-runs mode: #f) )) (thread-sleep! 15)) ;; fall thru and let "-run" loop fire ))) (if (args:get-arg "-remove-runs") (general-run-call "-remove-runs" "remove runs" (lambda (target runname keys keyvals) (operate-on 'remove-runs mode: (if (args:get-arg "-keep-records") 'remove-data-only 'remove-all))))) (if (args:get-arg "-remove-keep") (general-run-call "-remove-keep" "remove keep" (lambda (target runname keys keyvals) (let ((actions (map string->symbol (string-split (or (args:get-arg "-actions") "print") ",")))) ;; default to printing the output (runs:remove-all-but-last-n-runs-per-target target runname (string->number (args:get-arg "-remove-keep")) actions: actions))))) (if (args:get-arg "-set-state-status") (general-run-call "-set-state-status" "set state and status" (lambda (target runname keys keyvals) (operate-on 'set-state-status)))) |
︙ | ︙ | |||
1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 | (define (get-value-by-fieldname datavec test-field-index fieldname) (let ((indx (hash-table-ref/default test-field-index fieldname #f))) (if indx (if (>= indx (vector-length datavec)) #f ;; index too high, should raise an error I suppose (vector-ref datavec indx)) #f))) ;; NOTE: list-runs and list-db-targets operate on local db!!! ;; ;; IDEA: megatest list -runname blah% ... ;; (if (or (args:get-arg "-list-runs") (args:get-arg "-list-db-targets")) | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 | (define (get-value-by-fieldname datavec test-field-index fieldname) (let ((indx (hash-table-ref/default test-field-index fieldname #f))) (if indx (if (>= indx (vector-length datavec)) #f ;; index too high, should raise an error I suppose (vector-ref datavec indx)) #f))) (when (args:get-arg "-testdata-csv") (if (launch:setup) (let* ((keys (rmt:get-keys)) ;; (db:get-keys dbstruct)) (runpatt (or (args:get-arg "-runname") "%")) (testpatt (common:args-get-testpatt #f)) (datapatt (args:get-arg "-testdata-csv")) (match-data (string-match "^([^/]+)/(.*)" (args:get-arg "-testdata-csv"))) (categorypatt (if match-data (list-ref match-data 1) "%")) (setvarpatt (if match-data (list-ref match-data 2) (args:get-arg "-testdata-csv"))) (runsdat (rmt:get-runs-by-patt keys (or runpatt "%") (common:args-get-target) #f #f '("id" "runname" "state" "status" "owner" "event_time" "comment") 0)) (header (db:get-header runsdat)) (access-mode (db:get-access-mode)) (testpatt (common:args-get-testpatt #f)) (fields-spec (if (args:get-arg "-fields") (extract-fields-constraints (args:get-arg "-fields")) (list (cons "runs" (append keys (list "id" "runname" "state" "status" "owner" "event_time" "comment" "fail_count" "pass_count"))) (cons "tests" db:test-record-fields) ;; "id" "testname" "test_path") (list "steps" "id" "stepname")))) (tests-spec (let ((t (alist-ref "tests" fields-spec equal?))) (if (and t (null? t)) ;; all fields db:test-record-fields t))) (adj-tests-spec (delete-duplicates (if tests-spec (cons "id" tests-spec) db:test-record-fields))) (test-field-index (make-hash-table)) (runs (db:get-rows runsdat)) ) (if (and tests-spec (not (null? tests-spec))) ;; do some validation and processing of the test-spec (let ((invalid-tests-spec (filter (lambda (x)(not (member x db:test-record-fields))) tests-spec))) (if (null? invalid-tests-spec) ;; generate the lookup map test-field-name => index-number (let loop ((hed (car adj-tests-spec)) (tal (cdr adj-tests-spec)) (idx 0)) (hash-table-set! test-field-index hed idx) (if (not (null? tal))(loop (car tal)(cdr tal)(+ idx 1)))) (begin (debug:print-error 0 *default-log-port* "Invalid test fields specified: " (string-intersperse invalid-tests-spec ", ")) (exit))))) (let* ((table-header (string-split "target,run,test,itempath,category,var,value,comment" ",")) (table-rows (apply append (map (lambda (run) (let* ((target (string-intersperse (map (lambda (x) (db:get-value-by-header run header x)) keys) "/")) (statuses (string-split (or (args:get-arg "-status") "") ",")) (run-id (db:get-value-by-header run header "id")) (runname (db:get-value-by-header run header "runname")) (states (string-split (or (args:get-arg "-state") "") ",")) (tests (if tests-spec (rmt:get-tests-for-run run-id testpatt states statuses #f #f #f 'testname 'asc ;; (db:get-tests-for-run dbstruct run-id testpatt '() '() #f #f #f 'testname 'asc ;; use qryvals if test-spec provided (if tests-spec (string-intersperse adj-tests-spec ",") ;; db:test-record-fields #f) #f 'normal) '()))) (apply append (map (lambda (test) (let* ( (test-id (if (member "id" tests-spec)(get-value-by-fieldname test test-field-index "id" ) #f)) ;; (db:test-get-id test)) (testname (if (member "testname" tests-spec)(get-value-by-fieldname test test-field-index "testname" ) #f)) ;; (db:test-get-testname test)) (itempath (if (member "item_path" tests-spec)(get-value-by-fieldname test test-field-index "item_path" ) #f)) ;; (db:test-get-item-path test)) (fullname (conc testname (if (equal? itempath "") "" (conc "/" itempath )))) (testdat-raw (map vector->list (rmt:read-test-data* run-id test-id categorypatt setvarpatt))) (testdat (filter (lambda (x) (not (equal? "logpro" (list-ref x 10)))) testdat-raw))) (map (lambda (item) (receive (id test_id category variable value expected tol units comment status type) (apply values item) (list target runname testname itempath category variable value comment))) testdat))) tests)))) runs)))) (print (string-join table-header ",")) (for-each (lambda(table-row) (print (string-join (map ->string table-row) ","))) table-rows)))) (set! *didsomething* #t) (set! *time-to-exit* #t)) ;; NOTE: list-runs and list-db-targets operate on local db!!! ;; ;; IDEA: megatest list -runname blah% ... ;; (if (or (args:get-arg "-list-runs") (args:get-arg "-list-db-targets")) |
︙ | ︙ | |||
1111 1112 1113 1114 1115 1116 1117 | (hash-table-set! data "targets" (cons targetstr (hash-table-ref/default data "targets" '()))) ))) (let* ((run-id (db:get-value-by-header run header "id")) (runname (db:get-value-by-header run header "runname")) (states (string-split (or (args:get-arg "-state") "") ",")) (statuses (string-split (or (args:get-arg "-status") "") ",")) (tests (if tests-spec | | | 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 | (hash-table-set! data "targets" (cons targetstr (hash-table-ref/default data "targets" '()))) ))) (let* ((run-id (db:get-value-by-header run header "id")) (runname (db:get-value-by-header run header "runname")) (states (string-split (or (args:get-arg "-state") "") ",")) (statuses (string-split (or (args:get-arg "-status") "") ",")) (tests (if tests-spec (rmt:get-tests-for-run run-id testpatt states statuses #f #f #f 'testname 'asc ;; (db:get-tests-for-run dbstruct run-id testpatt '() '() #f #f #f 'testname 'asc ;; use qryvals if test-spec provided (if tests-spec (string-intersperse adj-tests-spec ",") ;; db:test-record-fields #f) #f 'normal) |
︙ | ︙ | |||
1158 1159 1160 1161 1162 1163 1164 | (for-each (lambda (test) (common:debug-handle-exceptions #f exn (begin (debug:print-error 0 *default-log-port* "Bad data in test record? " test) | | | 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 | (for-each (lambda (test) (common:debug-handle-exceptions #f exn (begin (debug:print-error 0 *default-log-port* "Bad data in test record? " test) (debug:print-error 5 *default-log-port* "exn=" (condition->list exn)) (debug:print 0 *default-log-port* " message: " ((condition-property-accessor 'exn 'message) exn)) (print-call-chain (current-error-port))) (let* ((test-id (if (member "id" tests-spec)(get-value-by-fieldname test test-field-index "id" ) #f)) ;; (db:test-get-id test)) (testname (if (member "testname" tests-spec)(get-value-by-fieldname test test-field-index "testname" ) #f)) ;; (db:test-get-testname test)) (itempath (if (member "item_path" tests-spec)(get-value-by-fieldname test test-field-index "item_path" ) #f)) ;; (db:test-get-item-path test)) (comment (if (member "comment" tests-spec)(get-value-by-fieldname test test-field-index "comment" ) #f)) ;; (db:test-get-comment test)) (tstate (if (member "state" tests-spec)(get-value-by-fieldname test test-field-index "state" ) #f)) ;; (db:test-get-state test)) |
︙ | ︙ | |||
1236 1237 1238 1239 1240 1241 1242 | (conc "\n rundir: " (get-value-by-fieldname test test-field-index "rundir")) ;; (db:test-get-rundir test) "") ;; "\n rundir: " (get-value-by-fieldname test test-field-index "") ;; (sdb:qry 'getstr ;; (filedb:get-path *fdb* ;; (db:test-get-rundir test) ;; ) ) ;; Each test ;; DO NOT remote run | | | 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 | (conc "\n rundir: " (get-value-by-fieldname test test-field-index "rundir")) ;; (db:test-get-rundir test) "") ;; "\n rundir: " (get-value-by-fieldname test test-field-index "") ;; (sdb:qry 'getstr ;; (filedb:get-path *fdb* ;; (db:test-get-rundir test) ;; ) ) ;; Each test ;; DO NOT remote run (let ((steps (rmt:get-steps-for-test run-id (db:test-get-id test)))) ;; (db:get-steps-for-test dbstruct run-id (db:test-get-id test)))) (for-each (lambda (step) (format #t " Step: ~20a State: ~10a Status: ~10a Time ~22a\n" (tdb:step-get-stepname step) (tdb:step-get-state step) (tdb:step-get-status step) |
︙ | ︙ | |||
1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 | ;; (print (sort run-ids <)) ;; (set! *didsomething* #t))) ;;====================================================================== ;; full run ;;====================================================================== ;; get lock in db for full run for this directory ;; for all tests with deps ;; walk tree of tests to find head tasks ;; add head tasks to task queue ;; add dependant tasks to task queue ;; add remaining tasks to task queue ;; for each task in task queue ;; if have adequate resources ;; launch task ;; else ;; put task in deferred queue ;; if still ok to run tasks ;; process deferred tasks per above steps ;; run all tests are are Not COMPLETED and PASS or CHECK (if (or (args:get-arg "-runall") (args:get-arg "-run") (args:get-arg "-rerun-clean") (args:get-arg "-rerun-all") | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > | | | | < < < < < < < | < < < < < | < > | < < < < < > < | > | | < | < < > | < < | < < | < < < | > > | | < < < < | | 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 | ;; (print (sort run-ids <)) ;; (set! *didsomething* #t))) ;;====================================================================== ;; full run ;;====================================================================== (define (handle-run-requests target runname keys keyvals need-clean) (if (or (args:get-arg "-kill-rerun") (args:get-arg "-rerun-clean")) ;; first set states/statuses correct ;; For rerun-clean do we or do we not support the testpatt? (let ((states (or (configf:lookup *configdat* "validvalues" "cleanrerun-states") "KILLREQ,KILLED,UNKNOWN,INCOMPLETE,STUCK,NOT_STARTED")) (statuses (or (configf:lookup *configdat* "validvalues" "cleanrerun-statuses") "FAIL,INCOMPLETE,ABORT,CHECK,DEAD,PREQ_FAIL,PREQ_DISCARDED"))) (hash-table-set! args:arg-hash "-preclean" #t) (runs:operate-on 'set-state-status target (common:args-get-runname) ;; (or (args:get-arg "-runname")(args:get-arg ":runname")) ;; "%" ;; (common:args-get-testpatt #f) ;; (args:get-arg "-testpatt") (common:args-get-testpatt #f) ;; (args:get-arg "-testpatt") state: states ;; status: statuses new-state-status: "NOT_STARTED,n/a") (runs:clean-cache target runname *toppath*) (runs:operate-on 'set-state-status target (common:args-get-runname) ;; (or (args:get-arg "-runname")(args:get-arg ":runname")) ;; "%" ;; (common:args-get-testpatt #f) ;; (args:get-arg "-testpatt") (common:args-get-testpatt #f) ;; (args:get-arg "-testpatt") ;; state: states status: statuses new-state-status: "NOT_STARTED,n/a"))) ;; RERUN ALL (if (args:get-arg "-rerun-all") ;; first set states/statuses correct (let* ((rconfig (full-runconfigs-read))) (hash-table-set! args:arg-hash "-preclean" #t) (runs:operate-on 'set-state-status target (common:args-get-runname) ;; (or (args:get-arg "-runname")(args:get-arg ":runname")) (common:args-get-testpatt rconfig) ;; (args:get-arg "-testpatt") state: #f ;; status: statuses new-state-status: "NOT_STARTED,n/a") (runs:clean-cache target runname *toppath*) (runs:operate-on 'set-state-status target (common:args-get-runname) ;; (or (args:get-arg "-runname")(args:get-arg ":runname")) (common:args-get-testpatt rconfig) ;; (args:get-arg "-testpatt") ;; state: states status: #f new-state-status: "NOT_STARTED,n/a"))) (let* ((config-reruns (let ((x (configf:lookup *configdat* "setup" "reruns"))) (if x (string->number x) #f))) (rerun-cnt (if config-reruns config-reruns 1))) (runs:run-tests target runname #f ;; (common:args-get-testpatt #f) ;; (or (args:get-arg "-testpatt") ;; "%") user args:arg-hash run-count: rerun-cnt))) ;; get lock in db for full run for this directory ;; for all tests with deps ;; walk tree of tests to find head tasks ;; add head tasks to task queue ;; add dependant tasks to task queue ;; add remaining tasks to task queue ;; for each task in task queue ;; if have adequate resources ;; launch task ;; else ;; put task in deferred queue ;; if still ok to run tasks ;; process deferred tasks per above steps ;; run all tests are are Not COMPLETED and PASS or CHECK (if (or (args:get-arg "-runall") (args:get-arg "-run") (args:get-arg "-rerun-clean") (args:get-arg "-rerun-all") (args:get-arg "-runtests") (args:get-arg "-kill-rerun")) (let ((need-clean (or (args:get-arg "-rerun-clean") (args:get-arg "-rerun-all"))) (orig-cmdline (string-intersperse (argv) " "))) (general-run-call "-runall" "run all tests" (lambda (target runname keys keyvals) (if (or (string-search "%" target) (string-search "%" runname)) ;; we are being asked to re-run multiple runs (let* ((run-specs (rmt:simple-get-runs runname #f #f target #f))) ;; list of simple-run records (debug:print-info 0 *default-log-port* "Pattern supplied for target or runname with " (length run-specs) " matches round. Running each in turn.") (if (null? run-specs) (debug:print 0 *default-log-port* "WARNING: No runs match target " target " and runname " runname)) (for-each (lambda (spec) (let* ((newcmdline (string-substitute (conc "target " target) (conc "target " (simple-run-target spec)) (string-substitute (conc "runname " runname) (conc "runname " (simple-run-runname spec)) orig-cmdline)))) (debug:print 0 *default-log-port* "ORIG: " orig-cmdline) (debug:print 0 *default-log-port* "NEW: " newcmdline) (system newcmdline))) run-specs)) (handle-run-requests target runname keys keyvals need-clean)))))) ;;====================================================================== ;; run one test ;;====================================================================== ;; 1. find the config file ;; 2. change to the test directory |
︙ | ︙ | |||
1541 1542 1543 1544 1545 1546 1547 | (test-name (assoc/default 'test-name cmdinfo)) (runscript (assoc/default 'runscript cmdinfo)) (db-host (assoc/default 'db-host cmdinfo)) (run-id (assoc/default 'run-id cmdinfo)) (itemdat (assoc/default 'itemdat cmdinfo)) (state (args:get-arg ":state")) (status (args:get-arg ":status")) | | > | > > > > > > > | | | | | | 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 | (test-name (assoc/default 'test-name cmdinfo)) (runscript (assoc/default 'runscript cmdinfo)) (db-host (assoc/default 'db-host cmdinfo)) (run-id (assoc/default 'run-id cmdinfo)) (itemdat (assoc/default 'itemdat cmdinfo)) (state (args:get-arg ":state")) (status (args:get-arg ":status")) ;;(target (args:get-arg "-target")) (target (common:args-get-target)) (toppath (assoc/default 'toppath cmdinfo))) (change-directory toppath) (if (not target) (begin (debug:print-error 0 *default-log-port* "-target is required.") (exit 1))) (if (not (launch:setup)) (begin (debug:print 0 *default-log-port* "Failed to setup, giving up on -test-paths or -test-files, exiting") (exit 1))) (let* ((keys (rmt:get-keys)) ;; db:test-get-paths must not be run remote (paths (tests:test-get-paths-matching keys target (args:get-arg "-test-files")))) (set! *didsomething* #t) (for-each (lambda (path) (if (common:file-exists? path) (print path))) paths))) ;; else do a general-run-call (general-run-call "-test-files" "Get paths to test" (lambda (target runname keys keyvals) (let* ((db #f) ;; DO NOT run remote (paths (tests:test-get-paths-matching keys target (args:get-arg "-test-files")))) (for-each (lambda (path) (print path)) paths)))))) ;;====================================================================== ;; Archive tests ;;====================================================================== ;; Archive tests matching target, runname, and testpatt (if (args:get-arg "-archive") ;; else do a general-run-call (begin ;; for the archive get we need to preserve the starting dir as part of the target path (if (and (args:get-arg "-dest") (not (equal? (substring (args:get-arg "-dest") 0 1) "/"))) (let ((newpath (conc (current-directory) "/" (args:get-arg "-dest")))) (debug:print-info 1 *default-log-port* "Preserving original path to destination, was " (args:get-arg "-dest") ", now " newpath) (hash-table-set! args:arg-hash "-dest" newpath))) (general-run-call "-archive" "Archive" (lambda (target runname keys keyvals) (operate-on 'archive target-in: target runname-in: runname ))))) ;;====================================================================== ;; Extract a spreadsheet from the runs database ;;====================================================================== (if (args:get-arg "-extract-ods") (general-run-call |
︙ | ︙ | |||
1847 1848 1849 1850 1851 1852 1853 | (if (args:get-arg "-rebuild-db") (begin (if (not (launch:setup)) (begin (debug:print 0 *default-log-port* "Failed to setup, exiting") (exit 1))) ;; keep this one local | | > > | | 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 | (if (args:get-arg "-rebuild-db") (begin (if (not (launch:setup)) (begin (debug:print 0 *default-log-port* "Failed to setup, exiting") (exit 1))) ;; keep this one local ;; (open-run-close patch-db #f) (let ((dbstruct (db:setup #f areapath: *toppath*))) (common:cleanup-db dbstruct full: #t)) (set! *didsomething* #t))) (if (args:get-arg "-cleanup-db") (begin (if (not (launch:setup)) (begin (debug:print 0 *default-log-port* "Failed to setup, exiting") (exit 1))) (let ((dbstruct (db:setup #f areapath: *toppath*))) (common:cleanup-db dbstruct)) (set! *didsomething* #t))) (if (args:get-arg "-mark-incompletes") (begin (if (not (launch:setup)) (begin |
︙ | ︙ | |||
1915 1916 1917 1918 1919 1920 1921 | (if (or (getenv "MT_RUNSCRIPT") (args:get-arg "-repl") (args:get-arg "-load")) (let* ((toppath (launch:setup)) (dbstruct (if (and toppath (common:on-homehost?)) | | | 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 | (if (or (getenv "MT_RUNSCRIPT") (args:get-arg "-repl") (args:get-arg "-load")) (let* ((toppath (launch:setup)) (dbstruct (if (and toppath (common:on-homehost?)) (db:setup #t) #f))) ;; make-dbr:dbstruct path: toppath local: (args:get-arg "-local")) #f))) (if *toppath* (cond ((getenv "MT_RUNSCRIPT") ;; How to run megatest scripts ;; ;; #!/bin/bash |
︙ | ︙ | |||
2004 2005 2006 2007 2008 2009 2010 | ;; ;; ;; redo me (db:close-all dbstruct) ;; ;; ;; redo me (list "uname" "rundir" "final_logf" "comment")) ;; ;; ;; redo me (set! *didsomething* #t))) (if (args:get-arg "-import-megatest.db") (begin (db:multi-db-sync | | > > > > < > > > > > | | | | > > > > > > > > > > > > > > > | | > > > > > > | 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 | ;; ;; ;; redo me (db:close-all dbstruct) ;; ;; ;; redo me (list "uname" "rundir" "final_logf" "comment")) ;; ;; ;; redo me (set! *didsomething* #t))) (if (args:get-arg "-import-megatest.db") (begin (db:multi-db-sync (db:setup #f) 'killservers 'dejunk 'adj-testids 'old2new ;; 'new2old ) (set! *didsomething* #t))) (when (args:get-arg "-sync-brute-force") ((server:get-bruteforce-syncer (db:setup #t) persist-until-sync: #t)) (set! *didsomething* #t)) (if (args:get-arg "-sync-to-megatest.db") (let* ((dbstruct (db:setup #f)) (tmpdbpth (cdr (dbr:dbstruct-tmpdb dbstruct))) (lockfile (conc tmpdbpth ".lock")) (locked (common:simple-file-lock lockfile)) (res (if locked (db:multi-db-sync dbstruct 'new2old) #f))) (if res (begin (common:simple-file-release-lock lockfile) (print "Synced " res " records to megatest.db")) (print "Skipping sync, there is a sync in progress.")) (set! *didsomething* #t))) (if (args:get-arg "-sync-to") (let ((toppath (launch:setup))) (tasks:sync-to-postgres *configdat* (args:get-arg "-sync-to")) (set! *didsomething* #t))) (if (args:get-arg "-list-test-time") (let* ((toppath (launch:setup))) (task:get-test-times) (set! *didsomething* #t))) (if (args:get-arg "-list-run-time") (let* ((toppath (launch:setup))) (task:get-run-times) (set! *didsomething* #t))) (if (args:get-arg "-generate-html") (let* ((toppath (launch:setup))) (if (tests:create-html-tree #f) (debug:print-info 0 *default-log-port* "HTML output created in " toppath "/lt/page0.html") (debug:print 0 *default-log-port* "Failed to create HTML output in " toppath "/lt/runs-index.html")) (set! *didsomething* #t))) (if (args:get-arg "-generate-html-structure") (let* ((toppath (launch:setup))) ;(if (tests:create-html-tree #f) (if (tests:create-html-summary #f) (debug:print-info 0 *default-log-port* "HTML output created in " toppath "/lt/targets.html") (debug:print 0 *default-log-port* "Failed to create HTML output in " toppath "/lt/runs-index.html")) (set! *didsomething* #t))) ;;====================================================================== ;; Exit and clean up ;;====================================================================== (if (not *didsomething*) (debug:print 0 *default-log-port* help) (set! *time-to-exit* #t) |
︙ | ︙ |
Modified minimal/manyservers.sh from [1fde698cb9] to [4d2e898ea9].
1 2 3 4 5 6 7 8 9 | #!/bin/bash echo manyservers.sh pid $$ logdir=$PWD/log-manysrv function reset { rm -f .homehost .server .server.lock links/.db/monitor.db .starting-server | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | #!/bin/bash # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. echo manyservers.sh pid $$ logdir=$PWD/log-manysrv function reset { rm -f .homehost .server .server.lock links/.db/monitor.db .starting-server |
︙ | ︙ |
Modified minimal/megatest.config from [a6a614bda6] to [b7d7fe455e].
1 2 3 4 5 6 7 | [fields] RUNTYPE text [setup] linktree #{getenv PWD}/linktree max_concurrent_jobs 20 | > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. [fields] RUNTYPE text [setup] linktree #{getenv PWD}/linktree max_concurrent_jobs 20 |
︙ | ︙ |
Modified minimal/runconfigs.config from [2c0464015a] to [988c28af94].
1 2 3 | [default] EXAMPLEVAR 1 | > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. [default] EXAMPLEVAR 1 |
Modified minimal/tests/tmpspace/testconfig from [030bb5974a] to [0280bd0687].
1 2 3 4 5 6 7 | [ezsteps] df [ `df -m /tmp | grep /tmp | awk '{print $3}'` -gt 200000 ] [items] TARGETHOST chlr10722 \ chlr15003 \ | > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. [ezsteps] df [ `df -m /tmp | grep /tmp | awk '{print $3}'` -gt 200000 ] [items] TARGETHOST chlr10722 \ chlr15003 \ |
︙ | ︙ |
Added minimt/Makefile version [548a2b6098].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. minimt : minimt.scm db.scm setup.scm direct.scm csc minimt.scm run : minimt export PATH="$(PWD)":$(PATH) ; minimt runrun foo/bar run1 runseq : clean run sleep 5;tail -F runtest/*log clean : rm -rf runtest/* |
Added minimt/db.scm version [e6fa6d3980].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 | ;; Copyright 2006-2017, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. ;; ;; pretend to be a simplified Megatest (use sql-de-lite defstruct) ;; init the db - NOTE: takes a db NOT a dbconn ;; (define (init-db db) (with-transaction db (lambda () (for-each (lambda (qrystr) (exec (sql db qrystr))) '("CREATE TABLE IF NOT EXISTS runs (id INTEGER PRIMARY KEY, target TEXT NOT NULL, run_name TEXT NOT NULL, state TEXT NOT NULL, status TEXT NOT NULL, CONSTRAINT runs_constraint UNIQUE (run_name));" "CREATE TABLE IF NOT EXISTS tests (id INTEGER PRIMARY KEY, run_id INTEGER NOT NULL, test_name TEXT NOT NULL, state TEXT NOT NULL, status TEXT NOT NULL, start_time INTEGER DEFAULT (strftime('%s','now')), end_time INTEGER DEFAULT -1, CONSTRAINT tests_constraint UNIQUE (run_id,test_name));" "CREATE TABLE IF NOT EXISTS steps (id INTEGER PRIMARY KEY, test_id INTEGER NOT NULL, step_name TEXT NOT NULL, state TEXT NOT NULL, status TEXT NOT NULL, CONSTRAINT step_constraint UNIQUE (test_id,step_name));"))))) (defstruct dbconn-dat dbh ;; the database handle writeable ;; do we have write access? path ;; where the db lives name ;; name of the db ) ;; open the database, return a dbconn struct (define (open-create-db path fname init) (let* ((fullname (conc path "/" fname)) (already-exists (file-exists? fullname)) (write-access (and (file-write-access? path) (or (not already-exists) (and already-exists (file-write-access? fullname))))) (db (if (or already-exists write-access) (open-database fullname) (begin (print "FATAL: No existing db and no write access thus cannot create " fullname) ;; no db and no write access cannot proceed. (exit 1)))) (dbconn (make-dbconn-dat))) (set-busy-handler! db (busy-timeout 120000)) ;; set a busy timeout (exec (sql db "PRAGMA synchronous=0;")) (if (and init write-access (not already-exists)) (init db)) (dbconn-dat-dbh-set! dbconn db) (dbconn-dat-writeable-set! dbconn write-access) (dbconn-dat-path-set! dbconn path) (dbconn-dat-name-set! dbconn fname) dbconn)) (define-inline (get-db dbconn) (dbconn-dat-dbh dbconn)) ;; RUNS ;; create a run (define (create-run dbconn target run-name) (exec (sql (get-db dbconn) "INSERT INTO runs (run_name,target,state,status) VALUES (?,?,'NEW','na');") run-name target)) ;; get a run id (define (get-run-id dbconn target run-name) (first-column (query fetch (sql (get-db dbconn) "SELECT id FROM runs WHERE target=? AND run_name=?;") target run-name))) ;; TESTS (defstruct test-dat id run-id test-name state status) ;; create a test (define (create-test dbconn run-id test-name) (exec (sql (get-db dbconn) "INSERT INTO tests (run_id,test_name,state,status) VALUES (?,?,'NOT_STARTED','na');") run-id test-name)) ;; get a test id (define (get-test-id dbconn run-id test-name) (first-column (query fetch (sql (get-db dbconn) "SELECT id FROM tests WHERE run_id=? AND test_name=?;") run-id test-name))) (define-inline (test-row->test-dat row) (make-test-dat id: (list-ref row 0) run-id: (list-ref row 1) test-name: (list-ref row 2) state: (list-ref row 3) status: (list-ref row 4))) ;; get the data for given test-id (define (test-get-record dbconn test-id) (let* ((row (query fetch-row (sql (get-db dbconn) "SELECT id,run_id,test_name,state,status FROM tests WHERE test_id=?;") test-id))) (test-row->test-dat row))) ;; get a bunch of tests data (define (test-get-tests dbconn run-ids test-name-patt) (let* ((rows (query fetch-rows (sql (get-db dbconn) (conc "SELECT id,run_id,test_name,state,status FROM tests WHERE test_name LIKE ? AND run_id IN (" (string-intersperse (map conc run-ids) ",") ");")) test-name-patt))) (map test-row->test-dat rows))) (define (test-set-state-status dbconn test-id new-state new-status) (exec (sql (get-db dbconn) "UPDATE tests SET state=?,status=?,end_time=? WHERE id=?;") new-state new-status (current-seconds) test-id)) ;; STEPS ;; create a step (define (create-step dbconn test-id step-name) (exec (sql (get-db dbconn) "INSERT INTO steps (test_id,step_name,state,status) VALUES (?,?,'NOT_STARTED','na');") test-id step-name)) ;; get a step id (define (get-step-id dbconn test-id step-name) (first-column (query fetch (sql (get-db dbconn) "SELECT id FROM steps WHERE test_id=? AND step_name=?;") test-id step-name))) (define (step-set-state-status dbconn step-id new-state new-status) (exec (sql (get-db dbconn) "UPDATE steps SET state=?,status=? WHERE id=?;") new-state new-status step-id)) ;;====================================================================== ;; Statistics gathering ;;====================================================================== (define *stats* (make-hash-table)) (define (update-stats key duration) (let ((rec (or (hash-table-ref/default *stats* key #f) (let ((new (vector 0 0 0))) (hash-table-set! *stats* key new) new)))) (vector-set! rec 0 (+ (vector-ref rec 0) 1)) ;; num calls (vector-set! rec 1 (+ (vector-ref rec 1) duration)) ;; total duration (if (> duration (vector-ref rec 2) ) (vector-set! rec 2 duration)))) (define (statwrap name proc) (lambda params (let ((start-time (current-milliseconds)) (res (apply proc params))) (update-stats name (- (current-milliseconds) start-time)) res))) (define (print-stats statdat) (hash-table-for-each statdat (lambda (key val) (print key " count: " (vector-ref val 0) " avg: " (/ (vector-ref val 1)(vector-ref val 0)) " max: " (vector-ref val 2))))) |
Added minimt/direct.scm version [d835943b15].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | ;; Copyright 2006-2017, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. ;; direct API, call the db calls directly (define rmt:create-run (statwrap 'create-run create-run)) (define rmt:create-step (statwrap 'create-step create-step)) (define rmt:create-test (statwrap 'create-test create-test)) (define rmt:get-test-id (statwrap 'get-test-id get-test-id)) (define rmt:get-run-id (statwrap 'get-run-id get-run-id)) (define rmt:open-create-db (statwrap 'open open-create-db)) (define rmt:step-set-state-status (statwrap 'step-set-state-status step-set-state-status)) (define rmt:test-set-state-status (statwrap 'test-set-state-status test-set-state-status)) (define rmt:test-get-tests (statwrap 'test-get-tests test-get-tests)) |
Added minimt/minimt.scm version [9a5af2fd8b].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 | ;; Copyright 2006-2017, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. ;; (use posix) (include "db.scm") ;; define following in setup.scm ;; *remotehost* => host for "tests" ;; *homehost* => host for servers ;; *homepath* => directory from which to run ;; *numtests* => how many tests to simulate for each run ;; *numruns* => how many runs to simulate ;; (include "setup.scm") (include "direct.scm") ;; direct db calls ;; RUN A TEST (define (run-test dbconn run-id test-name) (rmt:create-test dbconn run-id test-name) (let ((test-id (rmt:get-test-id dbconn run-id test-name))) (rmt:test-set-state-status dbconn test-id "LAUNCHED" "na") (thread-sleep! *launchdelay*) (rmt:test-set-state-status dbconn test-id "RUNNING" "na") (let loop ((step-num 0)) (let ((step-name (conc "step" step-num))) (rmt:create-step dbconn test-id step-name) (let ((step-id (get-step-id dbconn test-id step-name))) (rmt:step-set-state-status dbconn step-id "START" -1) (thread-sleep! *stepdelay*) (rmt:step-set-state-status dbconn step-id "END" 0) (print" STEP: " step-name " done."))) (if (< step-num *numsteps*) (loop (+ step-num 1)))) ;; we will do a large but bogus read to simulate the logic in Megatest (rmt:test-get-tests dbconn `(,run-id) "%") (rmt:test-set-state-status dbconn test-id "COMPLETED" (if (> (random 10) 2) "PASS" "FAIL")) (print "TEST: " test-name " done.") (print "Stats:") (print-stats *stats*) test-id)) ;; RUN A RUN (define (run-run dbconn target run-name num-tests) (rmt:create-run dbconn target run-name) (let ((run-id (rmt:get-run-id dbconn target run-name))) (let loop ((test-num 0)) (system (conc "NBFAKE_LOG=test-" test-num "-run-id-" run-id ".log NBFAKE_HOST=" *remotehost* " nbfake minimt runtest " run-id " test-" test-num)) (if (< test-num num-tests) (loop (+ test-num 1)))))) ;; Do what is asked (let ((args (cdr (argv)))) (if (< (length args) 1) (print "Usage: minimt [options]" " runtest run-id testname runrun target runname") (let ((cmd (car args)) (dbconn (rmt:open-create-db *homepath* "mt.db" init-db))) (thread-sleep! 0.5) ;; be sure the db is written out to disk? Should really not be needed. (change-directory *homepath*) (case (string->symbol cmd) ((runtest) (let ((run-id (string->number (cadr args))) (test-name (caddr args))) (print "Launching test " test-name " for run-id " run-id) (run-test dbconn run-id test-name))) ((runrun) (let ((target (cadr args)) (run-name (caddr args))) (run-run dbconn target run-name *numtests*) (print "Use: sqlite3 runtest/mt.db 'select max(end_time)-min(start_time) from tests;' to see the total run time") )) ((runall) (for-each (lambda (target) (let loop ((run-num 0)) (thread-sleep! *rundelay*) (system (conc "NBFAKE_LOG=run-" target "-" run-num ".log nbfake minimt runrun " target " run-" run-num)) (if (< run-num *numruns*) (loop (+ run-num 1))))) *targets*)) ((server) (start-server dbconn)) (else (print "Command: " cmd " not recognised. Run without params to see help."))) (close-database (dbconn-dat-dbh dbconn))))) |
Added minimt/queued.scm version [a237123d86].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 | ;; Copyright 2006-2017, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. (use nanomsg defstruct srfi-18) ;;====================================================================== ;; Commands ;;====================================================================== (define *commands* (make-hash-table)) (defstruct cmd key proc ctype ;; command type; 'r (read), 'w (write) or 't (transaction) ) (define (register-command key ctype proc) (hash-table-set! *commands* key (make-cmd key: key ctype: ctype proc: proc))) (define (get-proc key) (cmd-proc (hash-table-ref key *commands*))) (for-each (lambda (dat) (apply register-command dat)) `( (create-run w ,create-run) (create-step w ,create-step) (create-test w ,create-test) (get-test-id r ,get-test-id) (get-run-id r ,get-run-id) ;; (open-db w ,open-create-db) (step-set-ss w ,step-set-state-status) (test-set-ss w ,test-set-state-status) (test-get-tests r ,test-get-tests) )) ;;====================================================================== ;; Server/client stuff ;;====================================================================== (define-inline (encode data) (with-output-to-string (lambda () (write data)))) (define-inline (decode data) (with-input-from-string data (lambda () (read)))) ;;====================================================================== ;; Command queue ;;====================================================================== (defstruct qitem command params host-port) (define *cmd-queue* '()) (define *queue-mutex* (make-mutex)) (define (queue-push cmddat) (mutex-lock! *queue-mutex*) (set! *cmd-queue* (cons cmddat *cmd-queue*)) (mutex-unlock! *queue-mutex*)) ;; get all the cmds of type ctype and return them, also remove them from the queue (define (queue-take ctype) (mutex-lock! *queue-mutex*) (let ((res (filter (lambda (x)(eq? (cmd-ctype x) ctype)) *cmd-queue*)) (rem (filter (lambda (x)(not (eq? (cmd-ctype x) ctype))) *cmd-queue*))) (set! *queue* rem) (mutex-unlock! *queue-mutex*) res)) (define (queue-process-commands dbconn commands) (for-each (lambda (qitem) (let ((soc (request-connect (qitem-host-port qitem))) ;; we will be sending the data back to host-port via soc (cmd (hash-table-ref/default *commands* (qitem-command qitem) #f))) (if cmd (let* ((res (apply (get-proc cmd) dbconn (qitem-params qitem))) (pkg (encode `((r . ,res))))) (nn-send soc pkg) (if (not (eq? (nn-recv soc)) "ok") (print "Client failed to receive properly the data from " cmd " request")))))) commands)) ;; the continuously running queue processor ;; (define ((queue-processor dbconn)) (let loop () (queue-process-commands dbconn (queue-take 'r)) ;; reads first, probably largest numbers of them (queue-process-commands dbconn (queue-take 'w)) ;; writes next (queue-process-commands dbconn (queue-take 't)) ;; lastly process transactions (thread-sleep! 0.2) ;; open up the db for any other processes to access (loop))) ;;====================================================================== ;; Client stuff ;;====================================================================== ;; client struct (defstruct client host-port socket last-access) (define *clients* (make-hash-table)) ;; host:port -> client struct (define *client-mutex* (make-mutex)) ;; add a channel or return existing channel, this is a normal req ;; (define (request-connect host-port) (mutex-lock! *client-mutex*) (let* ((curr (hash-table-ref/default *clients* host-port #f))) (if curr (begin (mutex-unlock! *client-mutex*) curr) (let ((req (nn-socket 'req))) (nn-connect req host-port) ;; "inproc://test") (hash-table-set! *clients* host-port req) (mutex-unlock! *client-mutex*) req)))) ;; open up a channel to the server and send a package of info for the server to act on ;; host-port needs to be found and provided ;; (define (generic-db-access host-port) (let* ((soc (request-connect host-port)) ;; NEED *MY* host/port also to let the server know where to send the results ))) (define (client-send-receive soc msg) (nn-send soc msg) (nn-recv soc)) ;;====================================================================== ;; Server ;;====================================================================== (defstruct srvdat host port soc) ;; remember, everyone starts a server, both client and the actual server alike. ;; clients start a server for the server to return results to. ;; (define (start-raw-server #!key (given-host-name #f)) (let ((srvdat (let loop ((portnum 10000)) (handle-exceptions exn (if (< portnum 64000) (loop (+ portnum 1)) #f) (let* ((rep (nn-socket 'rep))) (nn-bind rep (conc "tcp://*:" portnum)) ;; "inproc://test") (make-srvdat port: portnum soc: rep))))) (host-name (or give-host-name (get-host-name))) (soc (srvdat-soc srvdat))) (srvdat-host-set! srvdat host-name) srvdat)) ;; The actual *server* side server ;; (define (start-server dbconn #!key (given-host-name #f)) (let* ((srvdat (start-raw-server given-host-name: given-host-name)) (host-name (srvdat-host srvdat)) (soc (srvdat-soc srvdat))) ;; start the queue processor (thread-start! (queue-processory dbconn) "Queue processor") ;; msg is an alist ;; 'r host:port <== where to return the data ;; 'p params <== data to apply the command to ;; 'e j|s|l <== encoding of the params. default is s (sexp), if not specified is assumed to be default ;; 'c command <== look up the function to call using this key ;; (let loop ((msg-in (nn-recv soc))) (if (not (equal? msg-in "quit")) (let* ((dat (decode msg-in)) (host-port (alist-ref 'r dat)) ;; this is for the reverse req rep where the server is a client of the original client (params (alist-ref 'p dat)) (command (let ((c (alist-ref 'c dat)))(if c (string->symbol c) #f))) (all-good (and host-port params command (hash-table-exists? *commands* command)))) (if all-good (let ((cmddat (make-qitem command: command host-port: host-port params: params))) (queue-push cmddat) ;; put request into the queue (nn-send soc "queued")) ;; reply with "queued" (print "ERROR: BAD request " dat)) (loop (nn-recv soc))))) (nn-close soc))) ;;====================================================================== ;; Gasket layer ;;====================================================================== (define rmt:open-create-db open-create-db) (define (rmt:create-run . params) |
Added minimt/setup.scm version [77f0a14424].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | ;; Copyright 2006-2017, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. ;; (define *remotehost* "orion") (define *homehost* "zeus") (define *homepath* "/nfs/phoebe/disk1/home/mfs_matt/data/megatest/minimt/runtest") (define *numsteps* 20) (define *numtests* 20) (define *numruns* 5) (define *targets* '("targ1")) (define *testdelay* 0) (define *rundelay* 0) (define *launchdelay* 0) (define *stepdelay* 0) (use trace) (trace-call-sites #t) (trace ;; open-create-db ) |
Modified mkdeploy/megatest.config from [abe5540207] to [1ef7c42725].
1 2 3 4 5 6 7 | [fields] PLATFORM TEXT OS TEXT OSVER TEXT [setup] # Adjust max_concurrent_jobs to limit parallel jobs | > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. [fields] PLATFORM TEXT OS TEXT OSVER TEXT [setup] # Adjust max_concurrent_jobs to limit parallel jobs |
︙ | ︙ |
Modified mkdeploy/runconfigs.config from [739b3a2709] to [7ba07535a3].
1 2 3 4 5 6 7 | [default] TARGDIR_tmp /tmp TARGDIR_opt /opt TARGDIR_runs #{getenv MT_RUN_AREA_HOME}/runs BUILDDIR #{getenv MT_RUN_AREA_HOME}/.. # Your variables here are grouped by targets [SYSTEM/RELEASE] | > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. [default] TARGDIR_tmp /tmp TARGDIR_opt /opt TARGDIR_runs #{getenv MT_RUN_AREA_HOME}/runs BUILDDIR #{getenv MT_RUN_AREA_HOME}/.. # Your variables here are grouped by targets [SYSTEM/RELEASE] |
︙ | ︙ |
Modified mkdeploy/tests/checkspace/checkspace.logpro from [ee0eb59e56] to [56f70bc81e].
1 2 3 | (expect:error in "LogFileBody" = 0 "Any error" #/err/i) (expect:required in "LogFileBody" = 1 "Sucess signature" #/adequate space/) | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | ;; Copyright 2006-2017, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. (expect:error in "LogFileBody" = 0 "Any error" #/err/i) (expect:required in "LogFileBody" = 1 "Sucess signature" #/adequate space/) |
Modified mkdeploy/tests/checkspace/checkspace.sh from [dc233ea2bc] to [5bd9381323].
1 2 3 4 5 6 7 8 | #!/bin/bash -e freespace=`df -k /$DIRECTORY | grep $DIRECTORY | awk '{print $4}'` if [[ $freespace -lt $REQUIRED ]];then echo "ERROR: insufficient space on /$DIRECTORY" exit 1 else echo "There is adequate space on /$DIRECTORY" fi | > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | #!/bin/bash -e # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. freespace=`df -k /$DIRECTORY | grep $DIRECTORY | awk '{print $4}'` if [[ $freespace -lt $REQUIRED ]];then echo "ERROR: insufficient space on /$DIRECTORY" exit 1 else echo "There is adequate space on /$DIRECTORY" fi |
Modified mkdeploy/tests/checkspace/testconfig from [64ad5ec3fd] to [9e8b6b6c4a].
1 2 3 4 5 6 7 | # Add steps here. Format is "stepname script" [ezsteps] checkspace checkspace.sh # Iteration for your tests are controlled by the items section # However it is impractical to code the actual directory here # so use names here and dereference to variables in runconfigs | > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. # Add steps here. Format is "stepname script" [ezsteps] checkspace checkspace.sh # Iteration for your tests are controlled by the items section # However it is impractical to code the actual directory here # so use names here and dereference to variables in runconfigs |
︙ | ︙ |
Modified mkdeploy/tests/eggs/install.logpro from [6d91c96c24] to [51672bd87a].
1 2 3 4 5 | (expect:ignore in "LogFileBody" >= 0 "ignore setup-error-handling" #/setup-error-handling/) (expect:ignore in "LogFileBody" >= 0 "ignore check-errors" (list #/check-errors/ #/type-errors/ #/srfi-4-errors/)) (expect:error in "LogFileBody" = 0 "Any error" #/error/i) (expect:required in "LogFileBody" = 1 "Sucess signature" #/DONE/) | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | ;; Copyright 2006-2017, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. (expect:ignore in "LogFileBody" >= 0 "ignore setup-error-handling" #/setup-error-handling/) (expect:ignore in "LogFileBody" >= 0 "ignore check-errors" (list #/check-errors/ #/type-errors/ #/srfi-4-errors/)) (expect:error in "LogFileBody" = 0 "Any error" #/error/i) (expect:required in "LogFileBody" = 1 "Sucess signature" #/DONE/) |
Modified mkdeploy/tests/eggs/install.sh from [f4ea44ce25] to [4bce64895a].
1 2 3 4 | #!/bin/bash -e targpath=`megatest -test-paths -target $MT_TARGET :runname $MT_RUNNAME -testpatt executables/megatest` chicken-install -prefix $targpath/megatest -deploy $EGGNAME echo DONE | > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | #!/bin/bash -e # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. targpath=`megatest -test-paths -target $MT_TARGET :runname $MT_RUNNAME -testpatt executables/megatest` chicken-install -prefix $targpath/megatest -deploy $EGGNAME echo DONE |
Modified mkdeploy/tests/eggs/testconfig from [9e809f74ce] to [98c5c77496].
1 2 3 4 5 6 7 | # Add steps here. Format is "stepname script" [ezsteps] install install.sh [requirements] waiton executables | > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. # Add steps here. Format is "stepname script" [ezsteps] install install.sh [requirements] waiton executables |
︙ | ︙ |
Modified mkdeploy/tests/executables/addlibs.logpro from [6af16367a1] to [b0010b1be7].
1 2 3 | (expect:error in "LogFileBody" = 0 "Any error" #/err/i) (expect:required in "LogFileBody" = 1 "Sucess signature" #/libchicken.so.6/) | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | ;; Copyright 2006-2017, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. (expect:error in "LogFileBody" = 0 "Any error" #/err/i) (expect:required in "LogFileBody" = 1 "Sucess signature" #/libchicken.so.6/) |
Modified mkdeploy/tests/executables/addlibs.sh from [8e40255426] to [80ef7c0644].
1 2 3 4 5 6 7 8 9 | #!/bin/bash -e CSIPATH=$(echo $(type csi)|awk '{print $3}') CKPATH=$(dirname $(dirname $CSIPATH)) rsync -av $EXECUTABLE/ ../deploytarg/ for i in iup im cd av call sqlite; do cp $(CKPATH)/lib/lib$i* ../deploytarg/ done | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | #!/bin/bash -e # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. CSIPATH=$(echo $(type csi)|awk '{print $3}') CKPATH=$(dirname $(dirname $CSIPATH)) rsync -av $EXECUTABLE/ ../deploytarg/ for i in iup im cd av call sqlite; do cp $(CKPATH)/lib/lib$i* ../deploytarg/ done |
︙ | ︙ |
Modified mkdeploy/tests/executables/install.logpro from [6af16367a1] to [b0010b1be7].
1 2 3 | (expect:error in "LogFileBody" = 0 "Any error" #/err/i) (expect:required in "LogFileBody" = 1 "Sucess signature" #/libchicken.so.6/) | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | ;; Copyright 2006-2017, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. (expect:error in "LogFileBody" = 0 "Any error" #/err/i) (expect:required in "LogFileBody" = 1 "Sucess signature" #/libchicken.so.6/) |
Modified mkdeploy/tests/executables/install.sh from [de5fcdb1f7] to [d61294c054].
1 2 3 4 5 6 7 | #!/bin/bash -e unset LD_LIBRARY_PATH rm -rf $EXECUTABLE mkdir $EXECUTABLE csc -deploy $EXECUTABLE ls $EXECUTABLE | > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | #!/bin/bash -e # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. unset LD_LIBRARY_PATH rm -rf $EXECUTABLE mkdir $EXECUTABLE csc -deploy $EXECUTABLE ls $EXECUTABLE |
Modified mkdeploy/tests/executables/linksrc.logpro from [174fad494f] to [6f3ff134ec].
1 2 3 | (expect:error in "LogFileBody" = 0 "Any error" #/err/i) (expect:required in "LogFileBody" = 1 "Sucess signature" #/Makefile/) | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | ;; Copyright 2006-2017, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. (expect:error in "LogFileBody" = 0 "Any error" #/err/i) (expect:required in "LogFileBody" = 1 "Sucess signature" #/Makefile/) |
Modified mkdeploy/tests/executables/linksrc.sh from [aeb7742b04] to [12739c4889].
1 2 3 4 5 6 | #!/bin/bash -e rm -f *.scm *.o Makefile ln -s $BUILDDIR/*.scm . ln -s $BUILDDIR/Makefile . ls Makefile *.scm | > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | #!/bin/bash -e # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. rm -f *.scm *.o Makefile ln -s $BUILDDIR/*.scm . ln -s $BUILDDIR/Makefile . ls Makefile *.scm |
Modified mkdeploy/tests/executables/make_mt.logpro from [bd9b47de4a] to [94a0cc202f].
1 2 3 | (expect:error in "LogFileBody" = 0 "Any error" #/err/i) (expect:required in "LogFileBody" = 1 "Sucess signature" #/mtest/) | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | ;; Copyright 2006-2017, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. (expect:error in "LogFileBody" = 0 "Any error" #/err/i) (expect:required in "LogFileBody" = 1 "Sucess signature" #/mtest/) |
Modified mkdeploy/tests/executables/testconfig from [d82229732d] to [6ac6c24a53].
1 2 3 4 5 6 7 | # Add steps here. Format is "stepname script" [ezsteps] linksrc linksrc.sh make_mt make install install.sh addlibs addlibs.sh | > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. # Add steps here. Format is "stepname script" [ezsteps] linksrc linksrc.sh make_mt make install install.sh addlibs addlibs.sh |
︙ | ︙ |
Modified mkdeploy/tests/helpers/install.logpro from [ee0eb59e56] to [56f70bc81e].
1 2 3 | (expect:error in "LogFileBody" = 0 "Any error" #/err/i) (expect:required in "LogFileBody" = 1 "Sucess signature" #/adequate space/) | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | ;; Copyright 2006-2017, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. (expect:error in "LogFileBody" = 0 "Any error" #/err/i) (expect:required in "LogFileBody" = 1 "Sucess signature" #/adequate space/) |
Modified mkdeploy/tests/helpers/install.sh from [dc233ea2bc] to [5bd9381323].
1 2 3 4 5 6 7 8 | #!/bin/bash -e freespace=`df -k /$DIRECTORY | grep $DIRECTORY | awk '{print $4}'` if [[ $freespace -lt $REQUIRED ]];then echo "ERROR: insufficient space on /$DIRECTORY" exit 1 else echo "There is adequate space on /$DIRECTORY" fi | > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | #!/bin/bash -e # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. freespace=`df -k /$DIRECTORY | grep $DIRECTORY | awk '{print $4}'` if [[ $freespace -lt $REQUIRED ]];then echo "ERROR: insufficient space on /$DIRECTORY" exit 1 else echo "There is adequate space on /$DIRECTORY" fi |
Modified mkdeploy/tests/helpers/testconfig from [f444692bff] to [b9f3cd9a84].
1 2 3 4 5 6 7 | # Add steps here. Format is "stepname script" [ezsteps] install install.sh # Iteration for your tests are controlled by the items section # However it is impractical to code the actual directory here # so use names here and dereference to variables in runconfigs | > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. # Add steps here. Format is "stepname script" [ezsteps] install install.sh # Iteration for your tests are controlled by the items section # However it is impractical to code the actual directory here # so use names here and dereference to variables in runconfigs |
︙ | ︙ |
Modified mlaunch.scm from [4f4e7034c8] to [5bcd34288f].
1 2 | ;; Copyright 2006-2014, Matthew Welland. ;; | | | > > > > > | | > | > > | < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | ;; Copyright 2006-2014, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. ;; strftime('%m/%d/%Y %H:%M:%S','now','localtime') ;;====================================================================== ;; MLAUNCH ;; ;; take jobs from the given queue and keep launching them keeping ;; the cpu load at the targeted level ;; ;;====================================================================== (use sqlite3 srfi-1 posix regex regex-case srfi-69 format) (declare (unit mlaunch)) (declare (uses db)) (declare (uses common)) |
Modified mockup-cached-writes.scm from [2795191c23] to [5621476534].
1 2 3 4 5 6 7 | (define (make-cached-writer the-db) (let ((db the-db) (queue '())) (lambda (cacheable . qry-params) ;; fn qry (if cacheable | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | ;; Copyright 2006-2017, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. ;; (define (make-cached-writer the-db) (let ((db the-db) (queue '())) (lambda (cacheable . qry-params) ;; fn qry (if cacheable |
︙ | ︙ |
Modified monitor.scm from [00d6efd991] to [3df55c85ea].
1 2 | ;; Copyright 2006-2012, Matthew Welland. ;; | | | > > > > > | | > | > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | ;; Copyright 2006-2012, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. ;; strftime('%m/%d/%Y %H:%M:%S','now','localtime') (use sqlite3 srfi-1 posix regex regex-case srfi-69 dot-locking) (import (prefix sqlite3 sqlite3:)) (declare (unit runs)) |
︙ | ︙ |
Modified mt-pg.sql from [538f0610d2] to [b692b264d4].
1 2 3 4 5 | -- CREATE TABLE IF NOT EXISTS keys ( -- id SERIAL PRIMARY KEY, -- fieldname TEXT, -- fieldtype TEXT, -- CONSTRAINT keyconstraint UNIQUE (fieldname)); | > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 | -- Copyright 2006-2017, Matthew Welland. -- -- This file is part of Megatest. -- -- Megatest is free software: you can redistribute it and/or modify -- it under the terms of the GNU General Public License as published by -- the Free Software Foundation, either version 3 of the License, or -- (at your option) any later version. -- -- Megatest is distributed in the hope that it will be useful, -- but WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- GNU General Public License for more details. -- -- You should have received a copy of the GNU General Public License -- along with Megatest. If not, see <http://www.gnu.org/licenses/>. -- CREATE TABLE IF NOT EXISTS keys ( -- id SERIAL PRIMARY KEY, -- fieldname TEXT, -- fieldtype TEXT, -- CONSTRAINT keyconstraint UNIQUE (fieldname)); DROP VIEW IF EXISTS area_tag_view; DROP TABLE IF EXISTS areas; DROP TABLE IF EXISTS ttype; DROP TABLE IF EXISTS runs; DROP TABLE IF EXISTS run_stats; DROP TABLE IF EXISTS test_meta; DROP TABLE IF EXISTS tasks_queue; DROP TABLE IF EXISTS archive_disks; DROP TABLE IF EXISTS archive_blocks; DROP TABLE IF EXISTS archive_allocations; DROP TABLE IF EXISTS extradat; DROP TABLE IF EXISTS metadat; DROP TABLE IF EXISTS access_log; DROP TABLE IF EXISTS tests; DROP TABLE IF EXISTS test_steps; DROP TABLE IF EXISTS test_data; DROP TABLE IF EXISTS test_rundat; DROP TABLE IF EXISTS archives; DROP TABLE IF EXISTS session_vars; DROP TABLE IF EXISTS sessions; DROP TABLE IF EXISTS tags; DROP TABLE IF EXISTS users; DROP TABLE IF EXISTS webviews; DROP TABLE IF EXISTS area_tags; DROP TABLE IF EXISTS run_tags; DROP TABLE IF EXISTS users_webviews; DROP TABLE IF EXISTS base_paths; DROP TABLE IF EXISTS area_owners; DROP TABLE IF EXISTS shared_user_views; DROP TABLE IF EXISTS cctrl_info; DROP TABLE IF EXISTS cctrl_config; DROP TABLE IF EXISTS platforms; CREATE TABLE IF NOT EXISTS session_vars ( id SERIAL PRIMARY KEY, session_id INTEGER, page TEXT, key TEXT, value TEXT); CREATE TABLE IF NOT EXISTS sessions ( id SERIAL PRIMARY KEY, session_key TEXT NOT NULL, last_used TIMESTAMP WITHOUT TIME ZONE DEFAULT now()); CREATE TABLE IF NOT EXISTS areas ( id SERIAL PRIMARY KEY, area_name TEXT NOT NULL, area_path TEXT NOT NULL, last_sync INTEGER DEFAULT 0, CONSTRAINT areaconstraint UNIQUE (area_name)); CREATE TABLE IF NOT EXISTS tags ( id SERIAL PRIMARY KEY, tag_name TEXT NOT NULL, CONSTRAINT tagconstraint UNIQUE (tag_name)); CREATE TABLE IF NOT EXISTS area_tags ( id SERIAL PRIMARY KEY, tag_id INTEGER DEFAULT 0, area_id INTEGER DEFAULT 0, CONSTRAINT areatagconstraint UNIQUE (tag_id, area_id)); CREATE TABLE IF NOT EXISTS run_tags ( id SERIAL PRIMARY KEY, tag_id INTEGER DEFAULT 0, run_id INTEGER DEFAULT 0, CONSTRAINT areatagconstraint UNIQUE (tag_id, run_id)); CREATE VIEW area_tag_view as select a.id as aid, t.id as tid,area_name,tag_name,area_path from areas as a inner join area_tags as at on at.area_id = a.id inner join tags as t on t.id = at.tag_id ; CREATE VIEW run_tag_view as select r.id as rid, t.id as tid,tag_name from runs as r inner join run_tags as rt on rt.run_id = r.id inner join tags as t on t.id = rt.tag_id ; INSERT INTO areas (id,area_name,area_path) VALUES (0,'local','.'); CREATE TABLE IF NOT EXISTS ttype ( id SERIAL PRIMARY KEY, target_spec TEXT DEFAULT ''); |
︙ | ︙ | |||
59 60 61 62 63 64 65 | owner TEXT DEFAULT '', event_time INTEGER DEFAULT extract(epoch from now()), comment TEXT DEFAULT '', fail_count INTEGER DEFAULT 0, pass_count INTEGER DEFAULT 0, last_update INTEGER DEFAULT extract(epoch from now()), area_id INTEGER DEFAULT 0, | > | > > > > > > > > | 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 | owner TEXT DEFAULT '', event_time INTEGER DEFAULT extract(epoch from now()), comment TEXT DEFAULT '', fail_count INTEGER DEFAULT 0, pass_count INTEGER DEFAULT 0, last_update INTEGER DEFAULT extract(epoch from now()), area_id INTEGER DEFAULT 0, publish_time INTEGER default date_part('epoch'::text, now()), CONSTRAINT runsconstraint UNIQUE (target,ttype_id,run_name, area_id)); create Table if not exists change_triggers ( id SERIAL PRIMARY KEY, target TEXT NOT NULL, area TEXT NOT NULL, iteration INTEGER NOT NULL, iteration_timestamp TIMESTAMP WITHOUT TIME ZONE DEFAULT now(), reason TEXT Not null); CREATE TABLE IF NOT EXISTS run_stats ( id SERIAL PRIMARY KEY, run_id INTEGER, state TEXT, status TEXT, count INTEGER, |
︙ | ︙ | |||
206 207 208 209 210 211 212 213 214 215 216 | test_id INTEGER, state TEXT DEFAULT 'new', status TEXT DEFAULT 'n/a', archive_type TEXT DEFAULT 'bup', du INTEGER, archive_path TEXT); -- TRUNCATE archive_blocks, archive_allocations, extradat, metadat, -- access_log, tests, test_steps, test_data, test_rundat, archives, runs, -- run_stats, test_meta, tasks_queue, archive_disks; | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 | test_id INTEGER, state TEXT DEFAULT 'new', status TEXT DEFAULT 'n/a', archive_type TEXT DEFAULT 'bup', du INTEGER, archive_path TEXT); CREATE TABLE IF NOT EXISTS users( id SERIAL PRIMARY KEY , username TEXT NOT NULL, fullname TEXT NOT NULL, email TEXT NOT NULL, default_view TEXT default '', is_admin boolean default 'f', deleted INTEGER default 0 ); CREATE TABLE IF NOT EXISTS base_paths( id SERIAL PRIMARY KEY , path TEXT NOT NULL, deleted INTEGER default 0 ); CREATE TABLE IF NOT EXISTS area_owners( id SERIAL PRIMARY KEY , user_id INTEGER, base_path_id INTEGER, deleted INTEGER default 0 ); CREATE TABLE IF NOT EXISTS shared_user_views( id SERIAL PRIMARY KEY , user_id INTEGER, view_id INTEGER, deleted INTEGER default 0 ); CREATE TABLE IF NOT EXISTS webviews( id SERIAL PRIMARY KEY , owner_id INTEGER NOT NULL, name TEXT NOT NULL, ttype_id INTEGER DEFAULT 0, view_specifics TEXT , col TEXT NOT NULL, row TEXT NOT NULL, public INTEGER DEFAULT 0, search_patt TEXT default '.*', deleted INTEGER default 0 ); CREATE TABLE IF NOT EXISTS flexviews( id SERIAL PRIMARY KEY , public INTEGER DEFAULT 0, attributes TEXT NOT NULL, name TEXT NOT NULL, deleted INTEGER default 0 ); CREATE TABLE IF NOT EXISTS users_webviews( id SERIAL PRIMARY KEY , user_id INTEGER NOT NULL, webview_id INTEGER NOT NULL, deleted INTEGER default 0, searchpattern TEXT Default '', web_page TEXT Default '', is_default boolean default 'f', other_search_data TEXT Default '' ); CREATE TABLE IF NOT EXISTS cctrl_info( id SERIAL PRIMARY KEY , user_id INTEGER NOT NULL, input TEXT Default '', result_file TEXT Default NULL, chksum TEXT ); CREATE TABLE IF NOT EXISTS cctrl_config( id SERIAL PRIMARY KEY , area_type Text, metadata text default '', cmd TEXT ); CREATE TABLE IF NOT EXISTS platforms( id SERIAL PRIMARY KEY , name Text ); -- TRUNCATE archive_blocks, archive_allocations, extradat, metadat, -- access_log, tests, test_steps, test_data, test_rundat, archives, runs, -- run_stats, test_meta, tasks_queue, archive_disks; |
Modified mt-sqlite3.sql from [cedc7d700d] to [a9c108974b].
1 2 3 4 5 6 7 | -- CREATE TABLE IF NOT EXISTS keys ( -- id SERIAL PRIMARY KEY, -- fieldname TEXT, -- fieldtype TEXT, -- CONSTRAINT keyconstraint UNIQUE (fieldname)); DROP TABLE IF EXISTS areas; | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | -- Copyright 2006-2017, Matthew Welland. -- -- This file is part of Megatest. -- -- Megatest is free software: you can redistribute it and/or modify -- it under the terms of the GNU General Public License as published by -- the Free Software Foundation, either version 3 of the License, or -- (at your option) any later version. -- -- Megatest is distributed in the hope that it will be useful, -- but WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- GNU General Public License for more details. -- -- You should have received a copy of the GNU General Public License -- along with Megatest. If not, see <http://www.gnu.org/licenses/>. -- CREATE TABLE IF NOT EXISTS keys ( -- id SERIAL PRIMARY KEY, -- fieldname TEXT, -- fieldtype TEXT, -- CONSTRAINT keyconstraint UNIQUE (fieldname)); DROP TABLE IF EXISTS areas; |
︙ | ︙ |
Modified mt.scm from [410c526eee] to [6bcd02e8ac].
1 2 | ;; Copyright 2006-2013, Matthew Welland. ;; | | | > > > > > | | > | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | ;; Copyright 2006-2013, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. ;; (use sqlite3 srfi-1 posix regex regex-case srfi-69 dot-locking (srfi 18) posix-extras directory-utils call-with-environment-variables) (import (prefix sqlite3 sqlite3:)) (declare (unit mt)) (declare (uses db)) |
︙ | ︙ | |||
125 126 127 128 129 130 131 132 133 | (debug:print 0 *default-log-port* "Discarding test " testn "(" test-dat ") due to " failed-test) res) (cons testn res))))))))) ;;====================================================================== ;; T R I G G E R S ;;====================================================================== (define (mt:process-triggers dbstruct run-id test-id newstate newstatus) | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | < | | > > > > | | | > | < > > > > | | > > > > > > > > > > | | | | | > | > | | > > > | > | > | < < < < < < | | | | | > > | | 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 | (debug:print 0 *default-log-port* "Discarding test " testn "(" test-dat ") due to " failed-test) res) (cons testn res))))))))) ;;====================================================================== ;; T R I G G E R S ;;====================================================================== (define (mt:run-trigger cmd test-id test-rundir trigger logname test-name item-path event-time actual-state actual-status) ;; Putting the commandline into ( )'s means no control over the shell. ;; stdout and stderr will be caught in the NBFAKE or mt_launch.log files ;; or equivalent. No need to do this. Just run it? (let* ((fullcmd (conc "nbfake " cmd " " test-id " " test-rundir " " trigger " " test-name " " item-path " " ;; has / prepended to deal with toplevel tests actual-state " " actual-status " " event-time )) (prev-nbfake-log (get-environment-variable "NBFAKE_LOG"))) (setenv "NBFAKE_LOG" (conc (cond ((and (directory-exists? test-rundir) (file-write-access? test-rundir)) test-rundir) ((and (directory-exists? *toppath*) (file-write-access? *toppath*)) *toppath*) (else (conc "/tmp/" (current-user-name)))) "/" logname)) (debug:print-info 0 *default-log-port* "TRIGGERED on " trigger ", running command " fullcmd " output at " (get-environment-variable "NBFAKE_LOG")) ;; (call-with-environment-variables ;; `(("NBFAKE_LOG" . ,(conc test-rundir "/" logname))) ;; (lambda () (process-run fullcmd) (if prev-nbfake-log (setenv "NBFAKE_LOG" prev-nbfake-log) (unsetenv "NBFAKE_LOG")) )) ;; )) (define (mt:process-triggers dbstruct run-id test-id newstate newstatus) (if test-id (let* ((test-dat (db:get-test-info-by-id dbstruct run-id test-id))) (if test-dat (let* ((test-rundir (db:test-get-rundir test-dat)) ;; ) ;; ) (test-name (db:test-get-testname test-dat)) (item-path (db:test-get-item-path test-dat)) (duration (db:test-get-run_duration test-dat)) (comment (db:test-get-comment test-dat)) (event-time (db:test-get-event_time test-dat)) (tconfig #f) (state (if newstate newstate (db:test-get-state test-dat))) (status (if newstatus newstatus (db:test-get-status test-dat)))) ;; (mutex-lock! *triggers-mutex*) (handle-exceptions exn (begin (debug:print-error 0 *default-log-port* " Exception in mt:process-triggers for run-id="run-id" test-id="test-id" newstate="newstate" newstatus="newstatus "\n error: " ((condition-property-accessor 'exn 'message) exn) "\n test-rundir="test-rundir "\n test-name="test-name "\n item-path="item-path "\n state="state "\n status="status "\n") (print-call-chain (current-error-port)) #f) (if (and test-name test-rundir) ;; #f means no dir set yet ;; (common:file-exists? test-rundir) ;; (directory? test-rundir)) (call-with-environment-variables (list (cons "MT_TEST_NAME" (or test-name "no such test")) (cons "MT_TEST_RUN_DIR" (or test-rundir "no test directory yet")) (cons "MT_ITEMPATH" (or item-path ""))) (lambda () (if (directory-exists? test-rundir) (push-directory test-rundir) (push-directory *toppath*)) (set! tconfig (mt:lazy-read-test-config test-name)) (for-each (lambda (trigger) (let* ((munged-trigger (string-translate trigger "/ " "--")) (logname (conc "last-trigger-" munged-trigger ".log"))) ;; first any triggers from the testconfig (let ((cmd (configf:lookup tconfig "triggers" trigger))) (if cmd (mt:run-trigger cmd test-id test-rundir trigger (conc "tconfig-" logname) test-name item-path event-time state status))) ;; next any triggers from megatest.config (let ((cmd (configf:lookup *configdat* "triggers" trigger))) (if cmd (mt:run-trigger cmd test-id test-rundir trigger (conc "mtconfig-" logname) test-name item-path event-time state status))))) (list (conc state "/" status) (conc state "/") (conc "/" status))) (pop-directory)) ))) ;; (mutex-unlock! *triggers-mutex*) ))))) ;;====================================================================== ;; S T A T E A N D S T A T U S F O R T E S T S ;;====================================================================== ;; speed up for common cases with a little logic (define (mt:test-set-state-status-by-id run-id test-id newstate newstatus newcomment) |
︙ | ︙ | |||
188 189 190 191 192 193 194 195 | ;; (if newstate (rmt:general-call 'set-test-state run-id newstate test-id)) ;; (if newstatus (rmt:general-call 'set-test-status run-id newstatus test-id)) ;; (if newcomment (rmt:general-call 'set-test-comment run-id newcomment test-id)))) (rmt:set-state-status-and-roll-up-items run-id test-id #f newstate newstatus newcomment) ;; (mt:process-triggers run-id test-id newstate newstatus) #t))) (define (mt:test-set-state-status-by-testname run-id test-name item-path new-state new-status new-comment) | > > > > > > > > > | | | | > > > > | | 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 | ;; (if newstate (rmt:general-call 'set-test-state run-id newstate test-id)) ;; (if newstatus (rmt:general-call 'set-test-status run-id newstatus test-id)) ;; (if newcomment (rmt:general-call 'set-test-comment run-id newcomment test-id)))) (rmt:set-state-status-and-roll-up-items run-id test-id #f newstate newstatus newcomment) ;; (mt:process-triggers run-id test-id newstate newstatus) #t))) (define (mt:test-set-state-status-by-id-unless-completed run-id test-id newstate newstatus newcomment) (let* ((test-vec (rmt:get-testinfo-state-status run-id test-id)) (state (vector-ref test-vec 3))) (if (equal? state "COMPLETED") #t (rmt:set-state-status-and-roll-up-items run-id test-id #f newstate newstatus newcomment)))) (define (mt:test-set-state-status-by-testname run-id test-name item-path new-state new-status new-comment) ;(let ((test-id (rmt:get-test-id run-id test-name item-path))) (rmt:set-state-status-and-roll-up-items run-id test-name item-path new-state new-status new-comment) ;; (mt:process-triggers run-id test-id new-state new-status) #t);) ;;(mt:test-set-state-status-by-id run-id test-id new-state new-status new-comment))) (define (mt:test-set-state-status-by-testname-unless-completed run-id test-name item-path new-state new-status new-comment) (let ((test-id (rmt:get-test-id run-id test-name item-path))) (mt:test-set-state-status-by-id-unless-completed run-id test-id new-state new-status new-comment))) (define (mt:lazy-read-test-config test-name) (let ((tconf (hash-table-ref/default *testconfigs* test-name #f))) (if tconf tconf (let ((test-dirs (tests:get-tests-search-path *configdat*))) (let loop ((hed (car test-dirs)) (tal (cdr test-dirs))) ;; Setting MT_LINKTREE here is almost certainly unnecessary. (let ((tconfig-file (conc hed "/" test-name "/testconfig"))) (if (and (common:file-exists? tconfig-file) (file-read-access? tconfig-file)) (let ((link-tree-path (common:get-linktree)) ;; (configf:lookup *configdat* "setup" "linktree")) (old-link-tree (get-environment-variable "MT_LINKTREE"))) (if link-tree-path (setenv "MT_LINKTREE" link-tree-path)) (let ((newtcfg (read-config tconfig-file #f #f))) ;; NOTE: Does NOT run [system ...] (hash-table-set! *testconfigs* test-name newtcfg) (if old-link-tree |
︙ | ︙ |
Added mtexec.scm version [63fcb68d27].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 | ; Copyright 2006-2017, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. ;; ;; (include "common.scm") ;; (include "megatest-version.scm") ;; fake out readline usage of toplevel-command (define (toplevel-command . a) #f) (use srfi-1 posix srfi-69 readline ;; regex regex-case srfi-69 apropos json http-client directory-utils rpc typed-records;; (srfi 18) extras) srfi-19 srfi-18 extras format pkts regex regex-case (prefix dbi dbi:) ) ;; (declare (uses common)) (declare (uses megatest-version)) (declare (uses margs)) (declare (uses configf)) ;; (declare (uses rmt)) ;; (use ducttape-lib) (include "megatest-fossil-hash.scm") ;; (require-library stml) (define help (conc " mtutil, part of the Megatest tool suite, documentation at http://www.kiatoa.com/fossils/megatest version " megatest-version " license GPL, Copyright Matt Welland 2006-2017 Usage: mtutil action [options] -h : this help -manual : show the Megatest user manual -version : print megatest version (currently " megatest-version ") Queries: show [areas|contours... ] : show areas, contours or other section from megatest.config gendot : generate a graphviz dot file from pkts. Contour actions: process : runs import, rungen and dispatch Trigger propagation actions: tsend a=b,c=d... : send trigger info to all recpients in the [listeners] section tlisten -port N : listen for trigger info on port N Misc -start-dir path : switch to this directory before running mtutil -set-vars V1=1,V2=2 : Add environment variables to a run NB// these are overwritten by values set in config files. -log logfile : send stdout and stderr to logfile -repl : start a repl (useful for extending megatest) -load file.scm : load and run file.scm -debug N|N,M,O... : enable debug messages 0-N or N and M and O ... -list-pkt-keys : list all pkt keys Examples: # Start a megatest run in the area \"mytests\" mtutil run -area mytests -target v1.63/aa3e -mode-patt MYPATT -tag-expr quick # Start a contour mtutil run -contour quick -target v1.63/aa3e Called as " (string-intersperse (argv) " ") " Version " megatest-version ", built from " megatest-fossil-hash )) ;; first token is our action, but only if no leading dash (define *action* (if (and (> (length (argv)) 1) (not (string-match "^\\-.*" (cadr (argv))))) (cadr (argv)) #f)) (define *remargs* (args:get-args (if *action* (cdr (argv)) (argv)) '("-log") '("-h") args:arg-hash 0)) (if (args:get-arg "-h") (begin (print help) (exit))) (if (or (args:get-arg "-repl") (args:get-arg "-load")) (begin (import extras) ;; might not be needed ;; (import csi) (import readline) (import apropos) ;; (import (prefix sqlite3 sqlite3:)) ;; doesn't work ... (install-history-file (get-environment-variable "HOME") ".mtutil_history") ;; [homedir] [filename] [nlines]) (current-input-port (make-readline-port "mtutil> ")) (if (args:get-arg "-repl") (repl) (load (args:get-arg "-load"))))) #| (define mtconf (car (simple-setup #f))) (define dat (common:with-queue-db mtconf (lambda (conn)(get-pkts conn '())))) (pp (pkts#flatten-all dat '((cmd . ((parent . P)(url . M)))(runtype . ((parent . P)))) 'id 'group-id 'uuid 'parent 'pkt-type 'pkt 'processed)) |# |
Modified mtut.scm from [2f0384f486] to [0bb9309c94].
|
| | | | > > > > > | | > | > > > | | > > > > > > | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | | > > > > > > > > > | | | | | | > > > | > | | | | | > > > > | | > > > > | | | | | | | | | | | | | | | | | | | | | > | | | > > | > | > > > > > > > > > < > > > > > > > > | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > | < < < < < | | < < < < < < < < < < < | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 | ; Copyright 2006-2017, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. ;; ;; (include "common.scm") ;; (include "megatest-version.scm") ;; fake out readline usage of toplevel-command (define (toplevel-command . a) #f) (use srfi-1 posix srfi-69 readline ;; regex regex-case srfi-69 apropos json http-client directory-utils rpc typed-records;; (srfi 18) extras) srfi-19 srfi-18 extras format pkts regex regex-case (prefix dbi dbi:) (prefix sqlite3 sqlite3:) nanomsg) (declare (uses common)) (declare (uses megatest-version)) (declare (uses margs)) (declare (uses configf)) ;; (declare (uses rmt)) (use ducttape-lib) (include "megatest-fossil-hash.scm") (require-library stml) ;; stuff for the mapper and checker functions ;; (define *target-mappers* (make-hash-table)) (define *runname-mappers* (make-hash-table)) (define *area-checkers* (make-hash-table)) (define (mtut:stml->string in-stml) (with-output-to-string (lambda () (s:output-new (current-output-port) in-stml)))) ;; helpers for mappers/checkers (define (add-target-mapper name proc) (hash-table-set! *target-mappers* name proc)) (define (add-runname-mapper name proc) (hash-table-set! *runname-mappers* name proc)) (define (add-area-checker name proc) (hash-table-set! *area-checkers* name proc)) ;; given a runkey, xlatr-key and other info return one of the following: ;; list of targets, null list to skip processing ;; (define (map-targets mtconf aval-alist runkey area contour #!key (xlatr-key-in #f)) (pp aval-alist) (print "In Map-targets") (let* ((xlatr-key (or xlatr-key-in (conf-get/default mtconf aval-alist 'targtrans))) (proc (hash-table-ref/default *target-mappers* xlatr-key #f))) (if proc (begin (print "Using target mapper: " xlatr-key) (handle-exceptions exn (begin (print "FAILED TO RUN TARGET MAPPER FOR " area ", called " xlatr-key) (print " function is: " (hash-table-ref/default *target-mappers* xlatr-key #f ) ) (print " message: " ((condition-property-accessor 'exn 'message) exn)) runkey) (proc runkey area contour))) (begin (if xlatr-key (print "ERROR: Failed to find named target translator " xlatr-key ", using original target.")) `(,runkey))))) ;; no proc then use runkey ;; given mtconf and areaconf extract a translator/filter, first look at areaconf ;; then if not found look at default ;; (define (conf-get/default mtconf areaconf keyname #!key (default #f)) (let ((res (or (alist-ref keyname areaconf) (configf:lookup mtconf "default" (conc keyname)) default))) (if res (string->symbol res) res))) ;; this needs some thought regarding security implications. ;; ;; i. Check that owner of the file and calling user are same? ;; ii. Check that we are in a legal megatest area? ;; iii. Have some form of authentication or record of the md5sum or similar of the file? ;; iv. Use compiled version in preference to .scm version. Thus there is a manual "blessing" ;; required to use .mtutil.scm. ;; (if (common:file-exists? "megatest.config") (if (common:file-exists? ".mtutil.so") (load ".mtutil.so") (if (common:file-exists? ".mtutil.scm") (load ".mtutil.scm")))) ;; main three types of run ;; "-run" => initiate a run ;; "-rerun-clean" => set failed, aborted, killed, etc. (not pass/fail) to NOT_STARTED and kick off run ;; "-rerun-all" => set all tests NOT_STARTED and kick off run again ;; deprecated/do not use ;; "-runall" => synonym for run, do not use ;; "-runtests" => synonym for run, do not use ;; Disabled help items ;; -rollup : (currently disabled) fill run (set by :runname) with latest test(s) ;; from prior runs with same keys ;; Contour actions ;; import : import pkts ;; dispatch : dispatch queued run jobs from imported pkts ;; rungen : look at input sense list in [rungen] and generate run pkts (define help (conc " mtutil, part of the Megatest tool suite, documentation at http://www.kiatoa.com/fossils/megatest version " megatest-version " license GPL, Copyright Matt Welland 2006-2017 Usage: mtutil action [options] -h : this help -manual : show the Megatest user manual -version : print megatest version (currently " megatest-version ") Run management: run : initiate or resume a run, already completed and in-progress tests are not affected. rerun-clean : clean and rerun all not completed pass/fail tests rerun-all : clean and rerun entire run kill-run : kill all tests in run kill-rerun : kill all tests in run and restart non-completed tests remove : remove runs set-ss : set state/status archive : compress and move test data to archive disk kill : stop tests or entire runs db : database utilities Queries: show [areas|contours... ] : show areas, contours or other section from megatest.config gendot : generate a graphviz dot file from pkts. Contour actions: process : runs import, rungen and dispatch Trigger propagation actions: tsend a=b,c=d... : send trigger info to all recpients in the [listeners] section tlisten -port N : listen for trigger info on port N Selectors -immediate : apply this action immediately, default is to queue up actions -area areapatt1,area2... : apply this action only to the specified areas -target key1/key2/... : run for key1, key2, etc. -test-patt p1/p2,p3/... : % is wildcard -run-name : required, name for this particular test run -contour contourname : run all targets for contourname, requires -run-name, -target -state-status c/p,c/f : Specify a list of state and status patterns -tag-expr tag1,tag2%,.. : select tests with tags matching expression -mode-patt key : load testpatt from <key> in runconfigs instead of default TESTPATT if -testpatt and -tagexpr are not specified -new state/status : specify new state/status for set-ss Misc -start-dir path : switch to this directory before running mtutil -set-vars V1=1,V2=2 : Add environment variables to a run NB// these are overwritten by values set in config files. -log logfile : send stdout and stderr to logfile -repl : start a repl (useful for extending megatest) -load file.scm : load and run file.scm -debug N|N,M,O... : enable debug messages 0-N or N and M and O ... -list-pkt-keys : list all pkt keys Utility db pgschema : emit postgresql schema; do \"mtutil db pgschema | psql -d mydb\" gatherdb [propagate] : gather dbs from all areas into /tmp/$USER_megatest/alldbs, optionally propagate the data to megatest2.0 format Examples: # Start a megatest run in the area \"mytests\" mtutil run -area mytests -target v1.63/aa3e -mode-patt MYPATT -tag-expr quick # Start a contour mtutil run -contour quick -target v1.63/aa3e Called as " (string-intersperse (argv) " ") " Version " megatest-version ", built from " megatest-fossil-hash )) ;; args and pkt key specs ;; (define *arg-keys* ;; used keys ;; a - action '( ("-area" . G) ;; maps to group ("-contour" . c) ("-append-config" . d) ("-state" . e) ("-item-patt" . i) ("-sync-to" . k) ("-new" . l) ;; l (see below) is new-ss ("-run-name" . n) ("-mode-patt" . o) ("-test-patt" . p) ;; idea, enhance margs ("-test-patt" "-testpatt") => yields one value in "-test-patt" ("-status" . s) ("-target" . t) ("-reqtarg" . R) ("-tag-expr" . x) ;; misc ("-debug" . #f) ;; for *verbosity* > 2 ("-load" . #f) ;; load and exectute a scheme file ("-log" . #f) ("-override-user" . #f) ("-msg" . M) ("-start-dir" . S) ("-set-vars" . v) ("-config" . h) ("-time-out" . u) ("-archive" . b) )) (define *switch-keys* '( ("-h" . #f) ("-help" . #f) ("--help" . #f) ("-manual" . #f) ("-version" . #f) ;; misc ("-repl" . #f) ("-immediate" . I) ("-preclean" . r) ("-prepend-contour" . w) ("-force" . F) ("-list-pkt-keys" . #f) )) ;; alist to map actions to old megatest commands (define *action-keys* '((run . "-run") (rerun-clean . "-rerun-clean") (rerun-all . "-rerun-all") (kill-run . "-kill-runs") (kill-rerun . "-kill-rerun") (lock . "-lock") (unlock . "-unlock") (sync . "") (archive . "") (set-ss . "-set-state-status") (remove . "-remove-runs"))) ;; manually keep this list updated from the keys to ;; the case *action* near the end of this file. (define *other-actions* '(run remove rerun set-ss archive kill list dispatch import rungen process show gendot db tsend tlisten)) ;; Card types: ;; ;; A action ;; U username (Unix) ;; D timestamp ;; T card type ;; a summary list of used card types for helping to not accidentally re-use them ;; ;; ADGIMSTUZabcdefghiklnoprstuvwx ;; utilitarian alist for standard cards ;; (define *additional-cards* '( ;; Standard Cards (A . action ) (D . timestamp ) (T . cardtype ) (U . user ) ;; username (Z . shar1sum ) ;; Extras (a . runkey ) ;; needed for matching up pkts with target derived from runkey ;; (l . new-ss ) ;; new state/status (b . branch ) ;; repository branch or tag (fossil or git) (f . url ) ;; repository URL (e.g. fossil or git) (g . clone ) ;; existing clone area (cached in /tmp) )) ;; inlst is an alternative input ;; (define (lookup-param-by-key key #!key (inlst #f)) (fold (lambda (a res) (if (eq? (cdr a) key) (car a) res)) #f (or inlst *arg-keys*))) (define (lookup-action-by-key key) (alist-ref (string->symbol key) *action-keys*)) (define (swizzle-alist lst) (map (lambda (x)(cons (cdr x)(car x))) lst)) ;;====================================================================== ;; U T I L S ;;====================================================================== ;; given a mtutil param, return the old megatest equivalent ;; (define (megatest-param->mtutil-param param) (let* ((mapping-alist (common:get-param-mapping flavor: 'switch-symbol))) (alist-ref (string->symbol param) mapping-alist eq? param) param)) (define val->alist common:val->alist) (define (push-run-spec torun contour runkey spec) (configf:section-var-set! torun contour runkey (cons spec (or (configf:lookup torun contour runkey) '())))) (define (fossil:clone-or-sync url name dest-dir) (let ((targ-file (conc dest-dir "/" name))) ;; do not force usage of .fossil extension (handle-exceptions exn (print "ERROR: failed to create directory " dest-dir " message: " ((condition-property-accessor 'exn 'message) exn)) (create-directory dest-dir #t)) (handle-exceptions exn (print "ERROR: failed to clone or sync 1ossil " url " message: " ((condition-property-accessor 'exn 'message) exn)) (if (common:file-exists? targ-file) (system (conc "fossil pull --once " url " -R " targ-file)) (system (conc "fossil clone " url " " targ-file)) )))) (define (fossil:last-change-node-and-time fossils-dir fossil-name branch) (let* ((fossil-file (conc fossils-dir "/" fossil-name)) (timeline-port (if (file-read-access? fossil-file) |
︙ | ︙ | |||
257 258 259 260 261 262 263 | (else ;; have some unrecognised junk? spit out error message (print "ERROR: fossil timeline returned unrecognisable junk \"" inl "\"") (loop (get-line) date node time)))) (else ;; no more datat and last node on branch not found (close-input-port timeline-port) (values (common:date-time->seconds (conc date " " time)) node)))))) | < < < < < < < | < | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > | | > > > | > | | > > | > > > > > | | < > > | > > > | < < > > > | > > > > > | < < | < | | > > | | | < | | | > > > | > > > > > > > > > | > > > > > > | | | | | | | > | > > > > > | > > > > > > > > | | > > > > > > > > | | > > > > > > > > > > > > > > > | > | > > > | | < < > | | > | < < > > | < < > > | | > > > > | | | | > > > > > > > > | > | < > | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > | | > | | | < < < < < < < < < < < < < < < < < | | > > | > > > | > | | < | | | > > > > > > > > > | | | | | | | | | | | | > > | | > > | > > > > | < < | | | > | | | > | > > > > > > > > > > > | 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 | (else ;; have some unrecognised junk? spit out error message (print "ERROR: fossil timeline returned unrecognisable junk \"" inl "\"") (loop (get-line) date node time)))) (else ;; no more datat and last node on branch not found (close-input-port timeline-port) (values (common:date-time->seconds (conc date " " time)) node)))))) ;;====================================================================== ;; GLOBALS ;;====================================================================== ;; first token is our action, but only if no leading dash (define *action* (if (and (> (length (argv)) 1) (not (string-match "^\\-.*" (cadr (argv))))) (cadr (argv)) #f)) ;; process arguments, extract switches and parameters first (define remargs (args:get-args (if *action* (cdr (argv)) (argv)) ;; args:get-args dumps first in argv list (the program name) (map car *arg-keys*) (map car *switch-keys*) args:arg-hash 0)) ;; handle requests for help ;; (if (or (member *action* '("-h" "-help" "help" "--help")) (args:any-defined? "-h" "-help" "--help")) (begin (print help) (exit 1))) (define (print-pkt-keys inlst) (for-each (lambda (p) (let ((sw (car p)) (c (cdr p))) (print (or c "n/a") "\t" sw))) inlst)) (define (print-duplicate-keys . all) (let ((card-hash (make-hash-table))) (for-each (lambda (lst) (for-each (lambda (card-spec) (let ((k (cdr card-spec))) ;; (print "card-spec: " card-spec ", k: " k) (if k (hash-table-set! card-hash k (+ (hash-table-ref/default card-hash k 0) 1))))) lst)) all) (for-each (lambda (k) (if (> (hash-table-ref card-hash k) 1) (print k "\t" (hash-table-ref card-hash k)))) (sort (hash-table-keys card-hash) (lambda (a b)(>= (hash-table-ref card-hash a)(hash-table-ref card-hash b))))) )) (define (print-pkt-key-info) (print "Argument keys") (print-pkt-keys *arg-keys*) (print "\nSwitch keys") (print-pkt-keys *switch-keys*) (print "\nAction keys") (print-pkt-keys *action-keys*) (print "\nAdditional cards") (print-pkt-keys (swizzle-alist *additional-cards*)) (print "\nDuplicate keys") (print-duplicate-keys *arg-keys* *switch-keys* *action-keys* (swizzle-alist *additional-cards*)) (print "\nEnd of report.") ) ;; list packet keys ;; (if (args:get-arg "-list-pkt-keys") (begin (print-pkt-key-info)(exit 0))) ;; (print "*action*: " *action*) ;; (let-values (((uuid pkt) ;; (command-line->pkt #f args:arg-hash))) ;; (print pkt)) ;; Add args that use remargs here ;; (if (and (not (null? remargs)) (not (or (args:get-arg "-runstep") (args:get-arg "-envcap") (args:get-arg "-envdelta") (member *action* '("db" "tsend" "tlisten")) ;; very loose checks on db and tsend/listen (equal? *action* "show") ;; just keep going if list ))) (debug:print-error 0 *default-log-port* "Unrecognised arguments: " (string-intersperse (if (list? remargs) remargs (argv)) " "))) (if (or (args:any? "-h" "help" "-help" "--help") (member *action* '("-h" "-help" "--help" "help"))) (begin (print help) (exit 1))) ;;====================================================================== ;; Nanomsg transport ;;====================================================================== (define-inline (encode data) (with-output-to-string (lambda () (write data)))) (define-inline (decode data) (with-input-from-string data (lambda () (read)))) (define (is-port-in-use port-num) (let* ((ret #f)) (let-values (((inp oup pid) (process "netstat" (list "-tulpn" )))) (let loop ((inl (read-line inp))) (if (not (eof-object? inl)) (begin (if (string-search (regexp (conc ":" port-num)) inl) (begin ;(print "Output: " inl) (set! ret #t)) (loop (read-line inp))))))) ret)) ;;start a server, returns the connection ;; (define (start-nn-server portnum ) (let ((rep (nn-socket 'rep))) (handle-exceptions exn (let ((emsg ((condition-property-accessor 'exn 'message) exn))) (print "ERROR: Failed to start server \"" emsg "\"") (exit 1)) (nn-bind rep (conc "tcp://*:" portnum))) rep)) (define (can-user-kill-listner user-info attrib) (let* ((contacts (alist-ref 'contact attrib)) (user-id (cadddr (cdr user-info))) (ret #f) (contact-list (string-split contacts ","))) (for-each (lambda (admin) (if (string-contains user-id (car (string-split admin "@"))) (set! ret #t))) contact-list) ret)) ;; open connection to server, send message, close connection ;; (define (open-send-close-nn host-port msg attrib #!key (timeout 3) ) ;; default timeout is 3 seconds (let ((req (nn-socket 'req)) (uri (conc "tcp://" host-port)) (res #f) (contacts (alist-ref 'contact attrib)) (mode (alist-ref 'mode attrib))) (handle-exceptions exn (let ((emsg ((condition-property-accessor 'exn 'message) exn))) ;; Send notification (print "ERROR: Failed to connect / send to " uri " message was \"" emsg "\"" ) (if (equal? mode "production") (begin (print " Sending email to contacts : " contacts ) (let ((email-body (mtut:stml->string (s:body (s:p (conc "We could not send messages to the server on " uri "." "Please check if the listner is running. It is possible that the host is overloaded due to which it may take too long to respond. \n Contact your system adminstrator if server load is high." (s:br)" Thank You ") ))))) (sendmail (string-join (string-split contacts ";" )) (conc "[Listner Error] Filed to connect to listner on " uri) email-body use_html: #t))) (print " mode : " mode " Not sending any emails" )) #f) (nn-connect req uri) (print "Connected to the server " ) (nn-send req msg) (print "Request Sent") (let* ((th1 (make-thread (lambda () (let ((resp (nn-recv req))) (nn-close req) (set! res (if (equal? resp "ok") #t #f)))) "recv thread")) (th2 (make-thread (lambda () (thread-sleep! timeout) (thread-terminate! th1)) "timer thread"))) (thread-start! th1) (thread-start! th2) (thread-join! th1) res)))) (define (open-send-receive-nn host-port msg attrib #!key (timeout 3) ) ;; default timeout is 3 seconds (let ((req (nn-socket 'req)) (uri (conc "tcp://" host-port)) (res #f) (contacts (alist-ref 'contact attrib)) (mode (alist-ref 'mode attrib))) (handle-exceptions exn (let ((emsg ((condition-property-accessor 'exn 'message) exn))) ;; Send notification (print "ERROR: Failed to connect / send to " uri " message was \"" emsg "\"" ) (if (equal? mode "production") (begin (print " Sending email to contacts : " contacts ) (let ((email-body (mtut:stml->string (s:body (s:p (conc "We could not send messages to the server on " uri "." "Please check if the listner is running. It is possible that the host is overloaded due to which it may take too long to respond. \n Contact your system adminstrator if server load is high." (s:br)" Thank You ") ))))) (sendmail (string-join (string-split contacts ";" )) (conc "[Listner Error] Filed to connect to listner on " uri) email-body use_html: #t))) (print " mode : " mode " Not sending any emails" )) #f) (nn-connect req uri) (print "Connected to the server " ) (nn-send req msg) (print "Request Sent") ;; receive code here ;;(print (nn-recv req)) (let* ((th1 (make-thread (lambda () (let ((resp (nn-recv req))) (nn-close req) (print resp) (set! res (if (equal? resp "ok") #t #f)))) "recv thread")) (th2 (make-thread (lambda () (thread-sleep! timeout) (thread-terminate! th1)) "timer thread"))) (thread-start! th1) (thread-start! th2) (thread-join! th1) res)))) ;;====================================================================== ;; Runs ;;====================================================================== ;; make a runname ;; (define (make-runname pre post) (time->string (seconds->local-time (current-seconds)) "%Yw%V.%w-%H%M")) ;; collect, translate, collate and assemble a pkt from the command-line ;; ;; sched => force the run start time to be recorded as sched Unix ;; epoch. This aligns times properly for triggers in some cases. ;; ;; extra-dat format is ( 'x xval 'y yval .... ) ;; (define (command-line->pkt action args-alist sched-in #!key (extra-dat '())(area-path #f)(new-ss #f)) (let* ((sched (cond ((vector? sched-in)(local-time->seconds sched-in)) ;; we recieved a time ((number? sched-in) sched-in) (else (current-seconds)))) (user (if (and args-alist (hash-table? args-alist)) (hash-table-ref/default args-alist "-override-user" (current-user-name)) (current-user-name))) (args-data (if args-alist (if (hash-table? args-alist) ;; seriously? (hash-table->alist args-alist) args-alist) (hash-table->alist args:arg-hash))) ;; if no args-alist then we assume this is a call driven directly by commandline (alldat (apply append (list 'A action 'U user 'D sched) (if area-path (list 'S area-path) ;; the area-path is mapped to the start-dir '()) (if (list? extra-dat) extra-dat (begin (debug:print 0 *default-log-port* "ERROR: command-line->pkt received bad extra-dat " extra-dat) '())) (map (lambda (x) (let* ((param (car x)) (value (cdr x)) (pmeta (assoc param *arg-keys*)) ;; translate the card key to a megatest switch or parameter (smeta (assoc param *switch-keys*)) ;; first lookup the key in arg-keys or switch-keys (meta (if (or pmeta smeta) (cdr (or pmeta smeta)) ;; found it? #f))) (if meta ;; construct the switch/param pair. (list meta value) '()))) (filter cdr args-data))))) (print "Alldat: " alldat ) ;;Do not remove. This is uesed by other applications to calculate z card ;(exit) (add-z-card (apply construct-sdat alldat)))) (define (simple-setup start-dir-in) (let* ((start-dir (or start-dir-in ".")) (mtconfig (or (args:get-arg "-config") "megatest.config")) (mtconfdat (find-and-read-config ;; NB// sets MT_RUN_AREA_HOME as side effect mtconfig ;; environ-patt: "env-override" given-toppath: start-dir ;; pathenvvar: "MT_RUN_AREA_HOME" )) (mtconf (if mtconfdat (car mtconfdat) #f))) ;; we set some dynamic data in a section called "scratchdata" (if mtconf (begin (configf:section-var-set! mtconf "scratchdat" "toppath" start-dir))) ;; (print "TOPPATH: " (configf:lookup mtconf "scratchdat" "toppath")) mtconfdat)) ;;====================================================================== ;; Areas ;;====================================================================== ;; look for areas=a1,a2,a3 OR areafn=somefuncname ;; (define (val-alist->areas val-alist) (let ((areas-string (alist-ref 'areas val-alist)) (areas-procname (alist-ref 'areafn val-alist))) (if areas-procname ;; areas-procname take precedence areas-procname (string-split (or areas-string "") ",")))) ;; area - the current area under consideration ;; areas - the list of allowed areas from the contour spec -OR- ;; if it is a string then it is the function to use to ;; lookup in *area-checkers* ;; (define (area-allowed? area areas runkey contour mode-patt) ;;(print "Areas: " areas) (cond ((not areas) #t) ;; no spec ((string? areas) ;; (let ((check-fn (hash-table-ref/default *area-checkers* (string->symbol areas) #f))) (if check-fn (check-fn area runkey contour mode-patt) #f))) ((list? areas)(member area areas)) (else #f))) ;; shouldn't get here (define (get-area-names mtconf) (map car (configf:get-section mtconf "areas"))) ;;====================================================================== ;; Pkts for remote control ;;====================================================================== ;; NEED TIMESTAMP ON PKTS for efficient loading of packets into db. ;; make a run request pkt from basic data, this seriously needs to be refactored ;; i. Take the code that builds the info to submit to create-run-pkt and have it ;; generate the pkt keys directly. ;; ii. Pass the pkt keys and values to this proc and go from there. ;; iii. Maybe have an abstraction alist with meaningful names for the pkt keys ;; ;; Override the run start time record with sched. Usually #f is fine. ;; (define (create-run-pkt mtconf action area runkey target runname mode-patt tag-expr pktsdir reason contour sched dbdest append-conf runtrans) (let* ((good-val (lambda (inval)(and inval (string? inval)(not (string-null? inval))))) (area-dat (common:val->alist (or (configf:lookup mtconf "areas" area) ""))) (area-path (alist-ref 'path area-dat)) ;; (area-xlatr (alist-ref 'targtrans area-dat)) ;; (xlatr-key (if area-xlatr (string->symbol area-xlatr) #f)) (new-runname (let* ((callname (if (string? runtrans)(string->symbol runtrans) #f)) (mapper (if callname (hash-table-ref/default *runname-mappers* callname #f) #f))) ;; (print "callname=" callname " runtrans=" runtrans " mapper=" mapper) (if (and callname (not (equal? callname "auto")) (not mapper)) (print "No mapper " callname " for area " area " using " callname " as the runname")) (if mapper (handle-exceptions exn (begin (print-call-chain) (print "FAILED TO RUN RUNNAME MAPPER " callname " FOR AREA " area) (print " message: " ((condition-property-accessor 'exn 'message) exn)) runname) (print "(mapper " (string-intersperse (list runkey runname area area-path reason contour mode-patt) ", ") ")") (mapper runkey runname area area-path reason contour mode-patt)) (case callname ((auto #f) runname) (else runtrans))))) (new-target target) ;; I believe we will want target manipulation here .. (map-targets xlatr-key runkey area contour)) (actual-action (if action (if (equal? action "sync-prepend") "sync" action) "run"))) ;; this has gotten a bit ugly. Need a function to handle actions processing. ;; some hacks to remove switches not needed in certain cases (case (string->symbol (or action "run")) ((sync sync-prepend) (set! new-target #f) (set! runame #f))) ;; (print "area-path: " area-path " orig-target: " runkey " new-target: " new-target) (let-values (((uuid pkt) (command-line->pkt actual-action (append `(("-start-dir" . ,area-path) ;;("-msg" . ,reason) ("-msg" . ,"Script-triggered") ("-contour" . ,contour)) (if (good-val new-runname) `(("-run-name" . ,new-runname)) '()) (if (good-val new-target) `(("-target" . ,new-target)) '()) (if (good-val area) `(("-area" . ,area)) '()) (if (good-val mode-patt) `(("-mode-patt" . ,mode-patt)) '()) (if (good-val tag-expr) `(("-tag-expr" . ,tag-expr)) '()) (if (good-val dbdest) `(("-sync-to" . ,dbdest)) '()) (if (good-val append-conf) `(("-append-config" . ,append-conf)) '()) (if (equal? action "sync-prepend") '(("-prepend-contour" . " ")) '()) (if (not (or mode-patt tag-expr)) `(("-testpatt" . "%")) '()) (if (or (not action) (equal? action "run")) `(("-preclean" . " ") ("-rerun-all" . " ")) ;; if run we *always* want preclean set, use single space as placeholder '()) ) sched extra-dat: `(a ,runkey) ;; we need the run key for marking the run as launched ))) (with-output-to-file (conc pktsdir "/" uuid ".pkt") (lambda () (print pkt)))))) ;; (use trace)(trace create-run-pkt) (define (contains list x) (cond ((null? list) #f) ((eq? (car list) x) #t) (else (contains (cdr list) x)))) ;; collect all needed data and create run pkts for contours with changed inputs ;; (define (generate-run-pkts mtconf toppath) (let ((std-runname (conc "sched" (time->string (seconds->local-time (current-seconds)) "%M%H%d"))) (packets-generated 0)) (common:with-queue-db mtconf (lambda (pktsdirs pktsdir pdb) (let* ((rgconfdat (find-and-read-config (conc toppath "/runconfigs.config"))) (rgconf (car rgconfdat)) (all-areas (map car (configf:get-section mtconf "areas"))) (contours (configf:get-section mtconf "contours")) (torun (make-hash-table)) ;; target => ( ... info ... ) (rgentargs (hash-table-keys rgconf))) ;; these are the targets registered for automatically triggering ;;(print "rgentargs: " rgentargs) (for-each (lambda (runkey) (let* ((keydats (configf:get-section rgconf runkey))) (for-each (lambda (sense) ;; these are the sense rules (let* ((key (car sense)) (val (cadr sense)) (keyparts (string-split key ":")) ;; contour:ruletype:action:optional (contour (car keyparts)) (len-key (length keyparts)) (ruletype (if (> len-key 1)(cadr keyparts) #f)) (action (if (> len-key 2)(caddr keyparts) #f)) (optional (if (> len-key 3)(cadddr keyparts) #f)) ;; (val-list (string-split-fields ";\\s*" val #:infix)) ;; (string-split val)) ;; runname-rule params (val-alist (common:val->alist val)) (runname (make-runname "" "")) (runtrans (alist-ref 'runtrans val-alist)) ;; these may or may not be defined and not all are used in each handler type in the case below (run-name (alist-ref 'run-name val-alist)) (target (alist-ref 'target val-alist)) (crontab (alist-ref 'cron val-alist)) (areas (val-alist->areas val-alist)) ;; areas can be a single string (a reference to call an areas function), or a list of area names. (dbdest (alist-ref 'dbdest val-alist)) (appendconf (alist-ref 'appendconf val-alist)) (file-globs (alist-ref 'glob val-alist)) (runstarts (find-pkts pdb '(runstart) `((c . ,contour) (t . ,runkey)))) (rspkts (common:get-pkt-alists runstarts)) ;; starttimes is for run start times and is used to know when the last run was launched (starttimes (common:get-pkt-times rspkts)) ;; sort by age (youngest first) and delete duplicates by target (last-run (if (null? starttimes) ;; if '() then it has never been run, else get the max 0 (apply max (map cdr starttimes)))) ;; synctimes is for figuring out the last time a sync was done (syncstarts (find-pkts pdb '(syncstart) '())) ;; no qualifiers, a sync does all tarets etc. (sspkts (common:get-pkt-alists syncstarts)) (synctimes (common:get-pkt-times sspkts)) (last-sync (if (null? synctimes) ;; if '() then it has never been run, else get the max 0 (apply max (map cdr synctimes)))) ) (let ((delta (lambda (x) (round (/ (- (current-seconds) x) 60))))) (if (args:get-arg "-target") (if (string= (args:get-arg "-target") runkey) (begin (print "runkey: " runkey ", ruletype: " ruletype ", action: " action ", last-run: " last-run " time since; last-run: " (delta last-run) ", last-sync: " (delta last-sync)) (print "val-alist=" val-alist " runtrans=" runtrans)) (if #f (print "skipping: " runkey))) (begin (print "runkey: " runkey ", ruletype: " ruletype ", action: " action ", last-run: " last-run " time since; last-run: " (delta last-run) ", last-sync: " (delta last-sync)) (print "val-alist=" val-alist " runtrans=" runtrans)) )) ;; look in runstarts for matching runs by target and contour ;; get the timestamp for when that run started and pass it ;; to the rule logic here where "ruletype" will be applied ;; if it comes back "changed" then proceed to register the runs (case (string->symbol (or ruletype "no-such-rule")) ((no-such-rule) (print "ERROR: no such rule for " sense)) ;; Handle crontab like rules ;; ((scheduled) (if (not (alist-ref 'cron val-alist)) ;; gotta have cron spec (print "ERROR: bad sense spec \"" (string-intersperse sense " ") "\" params: " val-alist) (let* ( ;; (action (alist-ref 'action val-alist)) (cron-safe-string (string-translate (string-intersperse (string-split crontab) "-") "*" "X")) (runname std-runname)) ;; (conc "sched" (time->string (seconds->local-time (current-seconds)) "%M%H%d"))))) ;; (print "last-run: " last-run " need-run: " need-run) ;; (if need-run (case (string->symbol action) ((sync sync-prepend) (if (common:extended-cron crontab #f last-sync) (push-run-spec torun contour runkey `((message . ,(conc ruletype ":sync-" cron-safe-string)) (action . ,action) (dbdest . ,dbdest) (append . ,appendconf) (areas . ,areas))))) ((run) (if (common:extended-cron crontab #f last-run) (push-run-spec torun contour runkey `((message . ,(conc ruletype ":" cron-safe-string)) (runname . ,runname) (runtrans . ,runtrans) (action . ,action) (areas . ,areas) (target . ,target))))) ((remove) (push-run-spec torun contour runkey `((message . ,(conc ruletype ":" cron-safe-string)) (runname . ,runname) (runtrans . ,runtrans) (action . ,action) (areas . ,areas) (target . ,target)))) (else (print "ERROR: action \"" action "\" has no scheduled handler") ))))) ;; script based sensors ;; ((script) ;; syntax is a little different here. It is a list of commands to run, "scriptname = extra_parameters;scriptname = ..." ;; where scriptname may be repeated multiple times. The script must return unix-epoch of last change, new-target-name and new-run-name ;; the script is called like this: scriptname contour runkey std-runname action extra_param1 extra_param2 ... (for-each (lambda (cmd) (print "cmd: " cmd) |
︙ | ︙ | |||
659 660 661 662 663 664 665 | (message (if (null? rem-lines) cmd (string-intersperse rem-lines "-"))) (need-run (> last-change last-run))) (print "last-run: " last-run " need-run: " need-run) (if need-run (let* ((key-msg `((message . ,(conc ruletype ":" message)) | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | > | > > | | > | > > > > > | > > < | | | | > | | | | > | < > > < | | | > | | | | | | > | < | | | | | | | > | | > > > > | | > | | | | | | > > > > > > > > | | | | | | | | > > | | > > | > | > > > | > | | < > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | | | > > > > > > > | > | > > > > > > > > > > > > > > > > | | | | | | | | | | > > > > > > > > > > > > > > | | | > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > | > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > | > | | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 | (message (if (null? rem-lines) cmd (string-intersperse rem-lines "-"))) (need-run (> last-change last-run))) (print "last-run: " last-run " need-run: " need-run) (if need-run (let* ((key-msg `((message . ,(conc ruletype ":" message)) (runname . ,new-runname) (runtrans . ,runtrans) (action . ,action) (areas . ,areas) ;;(target . ,(list new-target)) ;; overriding with result from runing the script ))) (print "key-msg: " key-msg) (push-run-spec torun contour (if optional ;; we need to be able to differentiate same contour, different behavior. (conc runkey ":" optional) ;; NOTE: NOT COMPLETELY IMPLEMENTED. DO NOT USE runkey) key-msg))))))) val-alist)) ;; iterate over the param split by ;\s* ;; script based sensors ;; ((area-script) ;; syntax is a little different here. It is a list of commands to run, "scriptname = extra_parameters;scriptname = ..." ;; where scriptname may be repeated multiple times. The script must return unix-epoch of last change, new-target-name and new-run-name ;; the script is called like this: scriptname contour runkey std-runname action extra_param1 extra_param2 ... (for-each (lambda (cmd) ;;(print "cmd: " cmd) ;;(print "Areas: " all-areas) (for-each (lambda (area) ;;(print "Area: " area) ;;(print "Target: " runkey) ;;(print "OR: " (or (string->number (if (configf:lookup mtconf "setup" "max_packets_per_run") (configf:lookup mtconf "setup" "max_packets_per_run") "10000" )))) ;;(print "Packets generated: " packets-generated) ;;(print "Comparison: " (< packets-generated 4)) ;;(print "Full Comparison: " ;; (and (< packets-generated (or (string->number (if (configf:lookup mtconf "setup" "max_packets_per_run") (configf:lookup mtconf "setup" "max_packets_per_run") "10000" )) 10000)) ;; (if (args:get-arg "-target") ;; (if (string= (args:get-arg "-target") runkey) (area-allowed? area "area-needs-to-be-run" runkey contour #f) #f) ;; (area-allowed? area "area-needs-to-be-run" runkey contour #f)))) ;;(print "Area Allowed: " (area-allowed? area "area-needs-to-be-run" runkey contour #f)) ;Add code to check whether area is valid (if ;; This code checks whether the target has been passed in via argument, and only runs the specified target (and (< packets-generated (or (string->number (if (configf:lookup mtconf "setup" "max_packets_per_run") (configf:lookup mtconf "setup" "max_packets_per_run") "10000" )) 10000)) (if (args:get-arg "-target") (if (string= (args:get-arg "-target") runkey) (area-allowed? area "area-needs-to-be-run" runkey contour #f) #f) (area-allowed? area "area-needs-to-be-run" runkey contour #f))) (let* ((script (car cmd)) (params (cdr cmd)) (cmd (conc script " " contour " " area " " runkey " " std-runname " " action " " params)) (res (handle-exceptions exn #f (print "Running " cmd) (with-input-from-pipe cmd read-lines))) (cval (or (configf:lookup mtconf "contours" contour) "")) (cval-alist (common:val->alist cval)) ;; BEWARE ... NOT the same val-alist as above! ;;(areas (val-alist->areas cval-alist)) (selector (alist-ref 'selector cval-alist)) (mode-tag (and selector (string-split-fields "/" selector #:infix))) (mode-patt (and mode-tag (if (eq? (length mode-tag) 2)(cadr mode-tag) #f))) (tag-expr (and mode-tag (if (null? mode-tag) #f (car mode-tag)))) ) (if (and res (not (null? res))) (let* ((parts (string-split (car res))) ;; (rem-lines (cdr res)) (num-parts (length parts)) (last-change (string->number (if (> num-parts 0)(car parts) "abc"))) ;; force no run if not a number returned (new-target (if (> num-parts 1) (cadr parts) runkey)) (new-runname (if (> num-parts 2) (caddr parts) std-runname)) (area-pkts (find-pkts pdb '(runstart) `((c . ,contour) (t . ,runkey) (G . ,area )))) (runstarts (filter (lambda (my-pkt) ;;(print my-pkt) (not (contains (map (lambda (c) ;;(print "C: " c "PKT: " my-pkt) (let* ((ctype (car c)) (rx (cdr c)) ;;(foo2 (print "Ctype: " ctype " RX: " rx)) (pkt (alist-ref 'pkt my-pkt)) (apkt (pkt->alist pkt)) (cdat (alist-ref ctype apkt))) (if rx (if (string-match "t" (symbol->string ctype) ) (begin (if #f (print "RX: " rx " CDAT: " (string-join (take (string-split cdat "/") 3) "/"))) (if cdat (string-match rx (string-join (take (string-split cdat "/") 3) "/")) #f)) (begin (if #f (print "RX: " rx " CDAT: " cdat)) (if cdat (string-match rx cdat) #f))) #f) )) `((c . ,contour) (t . ,runkey) (G . ,area))) #f))) area-pkts)) ;;(test (pp runstarts)) (rspkts (common:get-pkt-alists runstarts)) ;; starttimes is for run start times and is used to know when the last run was launched (starttimes (common:get-pkt-times rspkts)) ;; sort by age (youngest first) and delete duplicates by target (last-run (if (null? starttimes) ;; if '() then it has never been run, else get the max 0 (apply max (map cdr starttimes)))) ;; (last-run 9) ;; I think we can do a more valid calculation for this based on the run started packets for this particular area and target (reason "Area-script-triggered") ;;(mode-patt #f) ;;(tag-expr #f) (sched #f) (message (if (null? rem-lines) cmd (string-intersperse rem-lines "-"))) (need-run (> last-change last-run))) (print "last-change: " last-change " last-run: " last-run " need-run: " need-run) (if need-run (let* ((key-msg `((message . ,(conc ruletype ":" message)) (runname . ,new-runname) (runtrans . ,runtrans) (action . ,action) (areas . ,area) ;;(target . ,(list new-target)) ;; overriding with result from runing the script )) (aval (or (configf:lookup mtconf "areas" area) "")) (aval-alist (common:val->alist aval)) (targets (map-targets mtconf aval-alist runkey area contour))) (pp targets) (for-each (lambda (target) (create-run-pkt mtconf action area runkey target new-runname mode-patt tag-expr pktsdir reason contour sched dbdest append runtrans) (set! packets-generated (+ packets-generated 1)) ) targets) ;; Add filter for targets ;;(create-run-pkt mtconf action area runkey target runname ;; pktsdir reason contour dbdest append ;; runtrans) (print "key-msg: " key-msg) ;;(push-run-spec torun contour ;; (if optional ;; we need to be able to differentiate same contour, different behavior. ;; (conc runkey ":" optional) ;; NOTE: NOT COMPLETELY IMPLEMENTED. DO NOT USE ;; runkey) ;; key-msg) ))))) (if (>= packets-generated (string->number (configf:lookup mtconf "setup" "max_packets_per_run"))) (print "Skipping area: " area " and target: " runkey " due to packets-generated: " packets-generated " higher than " (configf:lookup mtconf "setup" "max_packets_per_run")))) ) (filter (lambda (x) (if (not (args:get-arg "-area")) #t (if (string= x (args:get-arg "-area")) #t #f))) all-areas)) ) val-alist)) ;; iterate over the param split by ;\s* ;; fossil scm based triggers ;; ((fossil) (for-each (lambda (fspec) (print "fspec: " fspec) (let* ((url (symbol->string (car fspec))) ;; THIS COULD BE TROUBLE. Add option to reading line to return as string. (branch (cdr fspec)) (url-is-file (string-match "^(/|file:).*$" url)) (fname (conc (common:get-signature url) ".fossil")) (fdir (conc "/tmp/" (current-user-name) "/mtutil_cache"))) ;; (if (not url-is-file) ;; need to sync first --- for now, clone 'em all. (fossil:clone-or-sync url fname fdir) ;; ) (let-values (((datetime node) (fossil:last-change-node-and-time fdir fname branch))) (if (null? starttimes) (push-run-spec torun contour runkey `((message . ,(conc "fossil:" branch "-neverrun")) (runname . ,(conc runname "-" node)) (runtrans . ,runtrans) (areas . ,areas) ;; (target . ,runkey) (action . ,action) )) (if (> datetime last-run) ;; change time is greater than last-run time (push-run-spec torun contour runkey `((message . ,(conc "fossil:" branch "-" node)) (runname . ,(conc runname "-" node)) (runtrans . ,runtrans) (areas . ,areas) ;; (target . ,runkey) (action . ,action) (branch . ,branch) (url . ,url) (clone . ,(conc fdir "/" fname)) )))) (print "Got datetime=" datetime " node=" node)))) val-alist)) ;; sensor looking for one or more files newer than reference ;; ((file file-or) ;; one or more files must be newer than the reference (let* ((youngestdat (common:get-youngest (common:bash-glob file-globs))) (youngestmod (car youngestdat))) ;; (print "youngestmod: " youngestmod " starttimes: " starttimes) (if (null? starttimes) ;; this target has never been run (push-run-spec torun contour runkey `((message . "file:neverrun") (action . ,action) (runtrans . ,runtrans) ;; (target . ,runkey) (areas . ,areas) (runname . ,runname))) ;; (for-each ;; (lambda (starttime) ;; look at the time the last run was kicked off for this contour ;; (if (> youngestmod (cdr starttime)) ;; (begin ;; (print "starttime younger than youngestmod: " starttime " Youngestmod: " youngestmod) (if (> youngestmod last-run) (push-run-spec torun contour runkey `((message . ,(conc ruletype ":" (cadr youngestdat))) (action . ,action) ;; (target . ,runkey) (runtrans . ,runtrans) (areas . ,areas) (runname . ,runname) )))))) ;; all globbed files must be newer than the reference ;; ((file-and) ;; all files must be newer than the reference (let* ((youngestdat (common:get-youngest file-globs)) (youngestmod (car youngestdat)) (success #t)) ;; any cases of not true, set flag to #f for AND ;; (print "youngestmod: " youngestmod " starttimes: " starttimes) (if (null? starttimes) ;; this target has never been run (push-run-spec torun contour runkey `((message . "file:neverrun") (runname . ,runname) (runtrans . ,runtrans) (areas . ,areas) ;; (target . ,runkey) (action . ,action))) ;; NB// I think this is wrong. It should be looking at last-run only. (if (> youngestmod last-run) ;; WAIT!! Shouldn't file-and be looking at the *oldest* file (thus all are younger than ...) ;; (for-each ;; (lambda (starttime) ;; look at the time the last run was kicked off for this contour ;; (if (< youngestmod (cdr starttime)) ;; (set! success #f))) ;; starttimes)) ;; (if success ;; (begin ;; (print "starttime younger than youngestmod: " starttime " Youngestmod: " youngestmod) (push-run-spec torun contour runkey `((message . ,(conc ruletype ":" (cadr youngestdat))) (runname . ,runname) (runtrans . ,runtrans) ;; (target . ,runkey) (areas . ,areas) (action . ,action) )))))) (else (print "ERROR: unrecognised rule \"" ruletype))))) keydats))) ;; sense rules (hash-table-keys rgconf)) ;; now have to run populated (for-each (lambda (contour) (let* ((cval (or (configf:lookup mtconf "contours" contour) "")) (cval-alist (common:val->alist cval)) ;; BEWARE ... NOT the same val-alist as above! (areas (val-alist->areas cval-alist)) (selector (alist-ref 'selector cval-alist)) (mode-tag (and selector (string-split-fields "/" selector #:infix))) (mode-patt (and mode-tag (if (eq? (length mode-tag) 2)(cadr mode-tag) #f))) (tag-expr (and mode-tag (if (null? mode-tag) #f (car mode-tag))))) (print "contour: " contour " areas=" areas " cval=" cval) (for-each (lambda (runkeydatset) ;; (print "runkeydatset: ")(pp runkeydatset) (let ((runkey (car runkeydatset)) (runkeydats (cadr runkeydatset)) ) (for-each (lambda (runkeydat) (for-each (lambda (area) (if (area-allowed? area areas runkey contour mode-patt) ;; is this area to be handled (from areas=a,b,c OR using areafn=abcfn and *area-checks* ...) (let* ((aval (or (configf:lookup mtconf "areas" area) "")) (aval-alist (common:val->alist aval)) (runname (alist-ref 'runname runkeydat)) (runtrans (alist-ref 'runtrans runkeydat)) (reason (alist-ref 'message runkeydat)) (sched (alist-ref 'sched runkeydat)) (action (alist-ref 'action runkeydat)) (dbdest (alist-ref 'dbdest runkeydat)) (append (alist-ref 'append runkeydat)) (targets ;;(or (alist-ref 'target runkeydat) (map-targets mtconf aval-alist runkey area contour))) ;; override with target if forced ;;(targets (or (alist-ref 'target runkeydat) ;; (map-targets mtconf aval-alist runkey area contour)))) ;; override with target if forced ;; NEED TO EXPAND RUNKEY => ALL TARGETS MAPPED AND THEN FOREACH .... ;;(print "Targets: " targets) ;;(print "alist: " (alist-ref 'target runkeydat)) (for-each (lambda (target) (print "Creating pkt for runkey=" runkey " target=" target " contour=" contour " area=" area " action=" action " tag-expr=" tag-expr " mode-patt=" mode-patt) (if (case (or (and action (string->symbol action)) 'noaction) ;; ensure we have the needed data to run this action ((noaction) #f) ((run) (and runname reason)) ((sync sync-prepend) (and reason dbdest)) (else #f)) ;; instead of unwrapping the runkeydat alist, pass it directly to create-run-pkt (create-run-pkt mtconf action area runkey target runname mode-patt tag-expr pktsdir reason contour sched dbdest append runtrans) (print "ERROR: Missing info to make a " action " call: runkey=" runkey " contour=" contour " area=" area " tag-expr=" tag-expr " mode-patt=" mode-patt " dbdest=" dbdest) )) targets)) (print "NOTE: skipping " runkeydat " for area \"" area "\", not in " areas))) all-areas)) runkeydats))) (let ((res (configf:get-section torun contour))) ;; each contour / target ;; (print "res=" res) res)))) (hash-table-keys torun))))))) (define (pkt->cmdline pkta) (let* ((param-mapping-alist (common:get-param-mapping flavor: 'switch-symbol)) (action (or (lookup-action-by-key (alist-ref 'A pkta)) "noaction")) (action-param (case (string->symbol action) ((-set-state-status) (conc (alist-ref 'l pkta) " ")) (else "")))) (fold (lambda (a res) (let* ((key (car a)) ;; get the key name (val (cdr a)) (par (or (lookup-param-by-key key) ;; need to check also if it is a switch (lookup-param-by-key key inlst: *switch-keys*)))) (print "key: " key " val: " val " par: " par) ;;(if (and par (not (string= (symbol->string key) "G"))) (if (and par) (conc res " " (alist-ref (string->symbol par) param-mapping-alist eq? par) " " val) (if (alist-ref key *additional-cards*) ;; these cards do not translate to parameters or switches res (begin (print "ERROR: Unknown key in packet \"" key "\" with value \"" val "\"") res))))) (conc "megatest " (if (not (member action '("sync"))) (conc action " " action-param) "")) pkta))) ;; (use trace)(trace pkt->cmdline) (define (write-pkt pktsdir uuid pkt) (if pktsdir (with-output-to-file (conc pktsdir "/" uuid ".pkt") (lambda () (print pkt))) (print "ERROR: cannot process commands without a pkts directory"))) (define (check-if-modepatt-defined pkta notification-hook pktfile) (let* ((start-dir (alist-ref 'S pkta)) (target (or (alist-ref 'R pkta) (alist-ref 't pkta))) (patt (alist-ref 'o pkta)) (uuid (alist-ref 'Z pkta)) (cmd (conc "megatest -show-runconfig -target " target " -start-dir " start-dir)) (res (handle-exceptions exn #f (print "Running " cmd) (with-input-from-pipe cmd read-lines)))) (let loop ((hed (car res)) (tail (cdr res))) (if (string-contains hed patt) #t (if (null? tail) (begin (if notification-hook (let* ((notification-cmd (conc notification-hook " --pkt " pktfile " --msg INVALID_MODEPATT"))) (print "Running " notification-cmd) (system notification-cmd))) #f) (loop (car tail) (cdr tail))))))) (define (check-if-target-defined pkta notification-hook pktfile) (let* ((start-dir (alist-ref 'S pkta)) (target (alist-ref 'R pkta)) (uuid (alist-ref 'Z pkta)) (cmd (conc "megatest -list-targets -start-dir " start-dir)) (res (handle-exceptions exn #f (print "Running " cmd) (with-input-from-pipe cmd read-lines)))) (if (member target res) #t (begin (if notification-hook (let* ((notification-cmd (conc notification-hook " --pkt " pktfile " --msg INVALID_TARGET"))) (print "Running " notification-cmd) (system notification-cmd))) #f)))) (define (validate-cmd cmd pkta notification-hook pktfile) (let ((ret #t)) (if (string-contains cmd "-reqtarg") (if (check-if-target-defined pkta notification-hook pktfile) (begin (print "Target is valid") (if (string-contains cmd "-modepatt") (if (check-if-modepatt-defined pkta notification-hook pktfile) (print "Modepatt is valid") (set! ret #f)))) (set! ret #f)) (if (string-contains cmd "-modepatt") (if (check-if-modepatt-defined pkta notification-hook pktfile) (print "Modepatt is valid") (set! ret #f)))) ret)) ;; collect all needed data and create run pkts for contours with changed inputs ;; (define (dispatch-commands mtconf toppath) ;; we are expecting a directory "logs", check and create it, create the log in /tmp if not able to create logs dir (let ((logdir (if (if (not (directory? "logs")) (handle-exceptions exn #f (create-directory "logs") #t) #t) "logs" "/tmp")) (cpuload (alist-ref 'adj-proc-load (common:get-normalized-cpu-load #f))) (maxload (string->number (or (configf:lookup mtconf "setup" "maxload") (configf:lookup mtconf "jobtools" "maxload") ;; respect value used by Megatest calls "1.1"))) (notification-hook (if (configf:lookup mtconf "setup" "notification-hook") (configf:lookup mtconf "setup" "notification-hook") #f))) (common:with-queue-db mtconf (lambda (pktsdirs pktsdir pdb) (let* ((rgconfdat (find-and-read-config (conc toppath "/runconfigs.config"))) (rgconf (car rgconfdat)) (areas (configf:get-section mtconf "areas")) (contours (configf:get-section mtconf "contours")) (pkts (find-pkts pdb '(cmd) '())) (torun (make-hash-table)) ;; target => ( ... info ... ) (rgentargs (hash-table-keys rgconf))) ;; these are the targets registered for automatically triggering (sqlite3:set-busy-handler! (dbi:db-conn pdb) (sqlite3:make-busy-timeout 10000)) (for-each (lambda (pktdat) (let* ((pkta (alist-ref 'apkt pktdat)) (action (alist-ref 'A pkta)) (cmdline (pkt->cmdline pkta)) (uuid (alist-ref 'Z pkta)) (user (alist-ref 'U pkta)) (area (alist-ref 'G pkta)) (logf (conc logdir "/" uuid "-run.log")) (pktfile (conc pktsdir "/" uuid ".pkt")) (fullcmd (conc "NBFAKE_LOG=" logf " nbfake " cmdline))) (if (check-access user mtconf action area) (if (and (> cpuload maxload) (member action '("run" "archive"))) ;; do not run archive or run if load is over the specified limit (begin (print "WARNING: cpuload too high, skipping processing of " uuid " due to " cpuload " > " maxload) (if notification-hook (let* ((notification-cmd (conc notification-hook " --pkt " pktfile " --msg HIGH_LOAD"))) (print "Running " notification-cmd) (system notification-cmd)))) (begin ;; if modepatt used chek if it is defined for the target. If -reqtarg check if target exist. (if (validate-cmd fullcmd pkta notification-hook pktfile) (begin (print "RUNNING: " fullcmd) (system fullcmd) ;; replace with process ... (mark-processed pdb (list (alist-ref 'id pktdat))) (let-values (((ack-uuid ack-pkt) (add-z-card (construct-sdat 'P uuid 'T (case (string->symbol action) ((run) "runstart") ((sync) "syncstart") ;; example of translating run -> runstart (else action)) 'G (alist-ref 'G pkta) 'c (alist-ref 'c pkta) ;; THIS IS WRONG! SHOULD BE 'c 't (alist-ref 't pkta))))) (write-pkt pktsdir ack-uuid ack-pkt)) (if notification-hook (let* ((notification-cmd (conc notification-hook " --pkt " pktfile " --msg RUN_LAUNCHED --contour " (caar contours) " --log_path " logf ))) (print "Running " notification-cmd) (system notification-cmd)))) (begin (mark-processed pdb (list (alist-ref 'id pktdat))) (let-values (((ack-uuid ack-pkt) (add-z-card (construct-sdat 'P uuid 'T "invalid-input" 'c (alist-ref 'o pkta) ;; THIS IS WRONG! SHOULD BE 'c 't (alist-ref 't pkta))))) (write-pkt pktsdir ack-uuid ack-pkt)))))) (begin ;; access denied! Mark as such (mark-processed pdb (list (alist-ref 'id pktdat))) (let-values (((ack-uuid ack-pkt) (add-z-card (construct-sdat 'P uuid 'T "access-denied" 'c (alist-ref 'o pkta) ;; THIS IS WRONG! SHOULD BE 'c 't (alist-ref 't pkta))))) (write-pkt pktsdir ack-uuid ack-pkt)) (if notification-hook (let* ((notification-cmd (conc notification-hook " --pkt " pktfile " --msg ACCESS_DENIED"))) (print "Running " notification-cmd) (system notification-cmd))))))) pkts)))))) (define (check-access user mtconf action area) ;; NOTE: Need control over defaults. E.g. default might be no access (let* ((access-ctrl (hash-table-exists? mtconf "access")) ;; if there is an access section the default is to REQUIRE enablement/access (access-list (map (lambda (x) (string-split x ":")) (string-split (or (configf:lookup mtconf "access" area) ;; userid:rightstype userid2:rightstype2 ... (if access-ctrl "*:none" ;; nobody has access by default "*:all"))))) (access-types-dat (configf:get-section mtconf "accesstypes"))) (debug:print 2 *default-log-port* "Checking access in " access-list " with access-ctrl " access-ctrl " for area " area) (if access-ctrl (let* ((user-access (or (assoc user access-list) (assoc "*" access-list))) (access-type (if user-access (cadr user-access) #f)) (access-types (let ((res (alist-ref access-type access-types-dat equal?))) (if res (car res) res))) (allowed-actions (string-split (or access-types "")))) (debug:print 2 *default-log-port* "Got " allowed-actions " for user " user " where access-types=" access-types " access-type=" access-type) (cond ((and access-types (member action allowed-actions)) ;; (print "Access granted for " user " for " action) #t) (else ;; (print "Access denied for " user " for " action) #f)))))) (define (open-logfile logpath) (condition-case (let* ((log-dir (or (pathname-directory logpath) "."))) (if (not (directory-exists? log-dir)) (system (conc "mkdir -p " log-dir))) (open-output-file logpath)) (exn () (debug:print-error 0 *default-log-port* "Could not open log file for write: "logpath) (define *didsomething* #t) (exit 1)))) (define (get-pkts-dir mtconf) (let ((pktsdirs (configf:lookup mtconf "setup" "pktsdirs")) (pktsdir (if pktsdirs (car (string-split pktsdirs " ")) #f))) pktsdir)) (let ((debugcontrolf (conc (get-environment-variable "HOME") "/.mtutilrc"))) (if (common:file-exists? debugcontrolf) (load debugcontrolf))) (if (args:get-arg "-log") ;; redirect the log always when a server (handle-exceptions exn (begin (print "ERROR: Failed to switch to log output. " ((condition-property-accessor 'exn 'message) exn)) ) (let* ((tl (args:get-arg "-log")) ;; run launch:setup if -server, ensure we do NOT run launch:setup if -log specified (logf (args:get-arg "-log")) ;; use -log unless we are a server, then craft a logfile name (oup (open-logfile logf))) ;(if (not (args:get-arg "-log")) ; (hash-table-set! args:arg-hash "-log" logf)) ;; fake out future queries of -log (print *default-log-port* "Sending log output to " logf) (set! *default-log-port* oup) ))) (if *action* (case (string->symbol *action*) ((run remove rerun rerun-clean rerun-all set-ss archive kill list kill-run kill-rerun lock unlock) (let* ((mtconfdat (simple-setup (args:get-arg "-start-dir"))) (mtconf (car mtconfdat)) (area (args:get-arg "-area")) ;; look up the area to dispatch to from [areas] section (areasec (if area (configf:lookup mtconf "areas" area) #f)) (areadat (if areasec (common:val->alist areasec) #f)) (area-path (if areadat (alist-ref 'path areadat) #f)) (pktsdirs (configf:lookup mtconf "setup" "pktsdirs")) (pktsdir (if pktsdirs (car (string-split pktsdirs " ")) #f)) (adjargs (hash-table-copy args:arg-hash)) (new-ss (args:get-arg "-new"))) ;; check a few things (cond ((and area (not area-path)) (print "ERROR: the specified area was not found in the [areas] table. Area name=" area) (exit 1)) ((not area) (print "ERROR: no area specified. Use -area <areaname>") (exit 1)) (else (let* ((usr-admin (check-access (current-user-name) mtconf "override" area)) (user (if (and usr-admin (args:get-arg "-override-user")) (args:get-arg "-override-user") (current-user-name)))) ; (print "user 123 " usr-admin ) ;(exit 1) (if (and (not usr-admin) (args:get-arg "-override-user")) (begin (print user " does not have access to override user") (exit 1))) (if (check-access user mtconf *action* area);; check rights (print "Access granted for " *action* " action by " user) (begin (print "Access denied for " *action* " action by " user) (exit 1)))))) ;; (for-each ;; (lambda (key) ;; (if (not (member key *legal-params*)) ;; (hash-table-delete! adjargs key))) ;; we need to delete any params intended for mtutil ;; (hash-table-keys adjargs)) (let-values (((uuid pkt) (command-line->pkt *action* adjargs #f area-path: area-path new-ss: new-ss))) (print "run log @ " (conc (current-directory) "/" uuid "-" *action* ".log")) (write-pkt pktsdir uuid pkt)))) ((dispatch import rungen process) (let* ((mtconfdat (simple-setup (args:get-arg "-start-dir"))) (mtconf (car mtconfdat)) (toppath (configf:lookup mtconf "scratchdat" "toppath"))) (case (string->symbol *action*) ((process) (begin (common:load-pkts-to-db mtconf) (generate-run-pkts mtconf toppath) (common:load-pkts-to-db mtconf) (dispatch-commands mtconf toppath))) ((import) (common:load-pkts-to-db mtconf)) ;; import pkts ((rungen) (generate-run-pkts mtconf toppath)) ((dispatch) (dispatch-commands mtconf toppath))))) ;; misc ((show) (if (> (length remargs) 0) (let* ((mtconfdat (simple-setup (args:get-arg "-start-dir"))) (mtconf (car mtconfdat)) (sect-dat (configf:get-section mtconf (car remargs)))) (if sect-dat (for-each (lambda (entry) (if (> (length entry) 1) (print (car entry) " " (cadr entry)) (print (car entry)))) sect-dat) (print "No section \"" (car remargs) "\" found"))) (print "ERROR: list requires section parameter; areas, setup or contours"))) ((gendot) (let* ((mtconfdat (simple-setup (args:get-arg "-start-dir"))) (mtconf (car mtconfdat))) (common:load-pkts-to-db mtconf use-lt: #t) ;; need to NOT do this by default ... (common:with-queue-db mtconf (lambda (pktsdirs pktsdir conn) ;; pktspec display-fields (make-report "out.dot" conn '((cmd . ((parent . P) (user . M) (target . t))) (runstart . ((parent . P) (target . t))) (runtype . ((parent . P)))) ;; pktspec '(P U t) ;; ))))) ;; no ptypes listed (ptypes are strings of pkt types to read from db ((db) (if (null? remargs) (print "ERROR: missing sub command for db command") (let ((subcmd (car remargs))) (case (string->symbol subcmd) ((pgschema) (let* ((install-home (common:get-install-area)) (schema-file (conc install-home "/share/db/mt-pg.sql"))) (if (common:file-exists? schema-file) (system (conc "/bin/cat " schema-file))))) ((sqlite3schema) (let* ((install-home (common:get-install-area)) (schema-file (conc install-home "/share/db/mt-sqlite3.sql"))) (if (common:file-exists? schema-file) (system (conc "/bin/cat " schema-file))))) ((junk) (rmt:get-keys)))))) ((tsend) (if (null? remargs) (print "ERROR: missing data to send to trigger listeners") (let* ((msg (car remargs)) (mtconfdat (simple-setup (args:get-arg "-start-dir"))) (mtconf (car mtconfdat)) (time-out (if (args:get-arg "-time-out") (string->number (args:get-arg "-time-out")) 5)) (listeners (configf:get-section mtconf "listeners")) (user-info (user-information (current-user-id))) (prev-seen (make-hash-table))) ;; catch duplicates (if user-info (begin (for-each (lambda (listener) (let ((host-port (car listener)) (attrib (val->alist (cadr listener)))) (if (and (equal? msg "time-to-die") (not (can-user-kill-listner user-info attrib))) (begin (debug:print-error 0 *default-log-port* "User " (car user-info) " is not allowed to send message '" msg"'") (exit 1))) (print "sending " msg " to " host-port ) (open-send-close-nn host-port msg attrib timeout: time-out ))) listeners)) (begin (debug:print-error 0 *default-log-port* "Could not Identify executing user. Will not send any message") (exit 1)))))) ((tquery) (if (null? remargs) (print "ERROR: missing data to send to trigger listeners") (let* ((msg (car remargs)) (mtconfdat (simple-setup (args:get-arg "-start-dir"))) (mtconf (car mtconfdat)) (time-out (if (args:get-arg "-time-out") (string->number (args:get-arg "-time-out")) 5)) (listeners (configf:get-section mtconf "listeners")) (user-info (user-information (current-user-id))) (prev-seen (make-hash-table))) ;; catch duplicates (if user-info (begin (for-each (lambda (listener) (let ((host-port (car listener)) (attrib (val->alist (cadr listener)))) (if (and (equal? msg "time-to-die") (not (can-user-kill-listner user-info attrib))) (begin (debug:print-error 0 *default-log-port* "User " (car user-info) " is not allowed to send message '" msg"'") (exit 1))) (print "sending " msg " to " host-port ) (open-send-receive-nn host-port msg attrib timeout: time-out ))) listeners)) (begin (debug:print-error 0 *default-log-port* "Could not Identify executing user. Will not send any message") (exit 1)))))) ((tquerylisten) (if (null? remargs) (print "ERROR: useage for tlisten is \"mtutil tlisten portnum\"") (let ((portnum (string->number (car remargs)))) (if (not portnum) (print "ERROR: the portnumber parameter must be a number, you gave: " (car remargs)) (begin (if (not (is-port-in-use portnum)) (let* ((rep (start-nn-server portnum)) (mtconfdat (simple-setup (args:get-arg "-start-dir"))) (mtconf (car mtconfdat)) (contact (configf:lookup mtconf "listener" "owner")) (script (configf:lookup mtconf "listener" "script"))) (print "Listening on port " portnum " for messages.") (set-signal-handler! signal/int (lambda (signum) (set! *time-to-exit* #t) (debug:print-error 0 *default-log-port* "Received signal " signum " sending email befor exiting !!") (let ((email-body (mtut:stml->string (s:body (s:p (conc "Received signal " signum ". Lister has been terminated on host " (get-environment-variable "HOST") ". ")))))) (sendmail contact "Listner has been terminated." email-body use_html: #t)) (exit))) (set-signal-handler! signal/term (lambda (signum) (set! *time-to-exit* #t) (debug:print-error 0 *default-log-port* "Received signal " signum " sending email befor exiting !!") (let ((email-body (mtut:stml->string (s:body (s:p (conc "Received signal " signum ". Lister has been terminated on host " (get-environment-variable "HOST") ". ")))))) (sendmail contact "Listner has been terminated." email-body use_html: #t)) (exit))) ;(set-signal-handler! signal/term special-signal-handler) (let loop ((instr (nn-recv rep))) ;;(nn-send rep "3.9") (with-input-from-pipe (conc "/usr/bin/uptime | cut -d':' -f4 | awk '{print $1}' | cut -d',' -f1") (lambda() (let loop ((inl (read-line))) (if (not (eof-object? inl)) (begin ;;(print "fdk73: " inl ":") ;;(set! current-list-ciaf (append! current-list-ciaf (list (string-substitute "\\s+$" "" inl)))) (nn-send rep inl) (loop(read-line))) )) ) ) ;;(print (isys "/usr/bin/uptime" foreach-stdout-thunk: foreach-stdout)) (let ((ctime (date->string (current-date)))) (if (equal? instr "time-to-die") (begin (debug:print 0 *default-log-port* ctime " received '" instr "'. Time to sucide." ) (let ((pid (current-process-id))) (debug:print 0 *default-log-port* "Killing current process (pid=" pid ")") (system (conc "kill " pid)))) (begin (debug:print 0 *default-log-port* ctime " received " instr ) ;(nn-send rep "ok") (if (not (equal? instr "ping")) (begin (debug:print 0 *default-log-port* ctime " running \"" script " " instr "\"") ;(system (conc script " '" instr "'")) (process-run script (list instr )) (debug:print 0 *default-log-port* ctime " done" )) (begin (if (not (equal? instr "load")) (print "Checking load") ) ) ) ))) (loop (nn-recv rep)))) (print "ERROR: Port " portnum " already in use. Try another port"))))))) ((tlisten) (if (null? remargs) (print "ERROR: useage for tlisten is \"mtutil tlisten portnum\"") (let ((portnum (string->number (car remargs)))) (if (not portnum) (print "ERROR: the portnumber parameter must be a number, you gave: " (car remargs)) (begin (if (not (is-port-in-use portnum)) (let* ((rep (start-nn-server portnum)) (mtconfdat (simple-setup (args:get-arg "-start-dir"))) (mtconf (car mtconfdat)) (contact (configf:lookup mtconf "listener" "owner")) (script (configf:lookup mtconf "listener" "script"))) (print "Listening on port " portnum " for messages.") (set-signal-handler! signal/int (lambda (signum) (set! *time-to-exit* #t) (debug:print-error 0 *default-log-port* "Received signal " signum " sending email befor exiting !!") (let ((email-body (mtut:stml->string (s:body (s:p (conc "Received signal " signum ". Lister has been terminated on host " (get-environment-variable "HOST") ". ")))))) (sendmail contact "Listner has been terminated." email-body use_html: #t)) (exit))) (set-signal-handler! signal/term (lambda (signum) (set! *time-to-exit* #t) (debug:print-error 0 *default-log-port* "Received signal " signum " sending email befor exiting !!") (let ((email-body (mtut:stml->string (s:body (s:p (conc "Received signal " signum ". Lister has been terminated on host " (get-environment-variable "HOST") ". ")))))) (sendmail contact "Listner has been terminated." email-body use_html: #t)) (exit))) ;(set-signal-handler! signal/term special-signal-handler) (let loop ((instr (nn-recv rep))) (nn-send rep "ok") (let ((ctime (date->string (current-date)))) (if (equal? instr "time-to-die") (begin (debug:print 0 *default-log-port* ctime " received '" instr "'. Time to sucide." ) (let ((pid (current-process-id))) (debug:print 0 *default-log-port* "Killing current process (pid=" pid ")") (system (conc "kill " pid)))) (begin (debug:print 0 *default-log-port* ctime " received " instr ) ;(nn-send rep "ok") (if (not (equal? instr "ping")) (begin (debug:print 0 *default-log-port* ctime " running \"" script " " instr "\"") (system (conc script " '" instr "' &")) ;(process-run script (list instr )) (debug:print 0 *default-log-port* ctime " done" )) (begin (if (not (equal? instr "load")) (print "Checking load") ) ) ) ))) (loop (nn-recv rep)))) (print "ERROR: Port " portnum " already in use. Try another port"))))))) ((gather) ;; gather all area db's into /tmp/$USER_megatest/alldbs (let* ((mtconfdat (simple-setup (args:get-arg "-start-dir"))) (mtconf (car mtconfdat)) (areas (get-area-names mtconf))) (print "areas: " areas))) (else (let ((all-actions (sort (map conc (delete-duplicates (append *other-actions* (map car *action-keys*)))) string<=?))) (print "unrecognised action: \"" *action* "\", try one of; \"" (string-intersperse all-actions "\", \"") "\""))) )) ;; the end ;; If HTTP_HOST is defined then we must be in the cgi environment ;; so run stml and exit ;; (if (get-environment-variable "HTTP_HOST") (begin (stml:main #f) |
︙ | ︙ | |||
961 962 963 964 965 966 967 | ;; (import (prefix sqlite3 sqlite3:)) ;; doesn't work ... (install-history-file (get-environment-variable "HOME") ".mtutil_history") ;; [homedir] [filename] [nlines]) (current-input-port (make-readline-port "mtutil> ")) (if (args:get-arg "-repl") (repl) (load (args:get-arg "-load"))))) | > > > > > > | 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 | ;; (import (prefix sqlite3 sqlite3:)) ;; doesn't work ... (install-history-file (get-environment-variable "HOME") ".mtutil_history") ;; [homedir] [filename] [nlines]) (current-input-port (make-readline-port "mtutil> ")) (if (args:get-arg "-repl") (repl) (load (args:get-arg "-load"))))) #| (define mtconf (car (simple-setup #f))) (define dat (common:with-queue-db mtconf (lambda (conn)(get-pkts conn '())))) (pp (pkts#flatten-all dat '((cmd . ((parent . P)(url . M)))(runtype . ((parent . P)))) 'id 'group-id 'uuid 'parent 'pkt-type 'pkt 'processed)) |# |
Modified newdashboard.scm from [7ae318679b] to [3cc17ecae4].
1 | ;;====================================================================== | | | < | < < < | < < < > | < > | | > > > > | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | ;;====================================================================== ;; Copyright 2006-2016, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. ;;====================================================================== (use format) (use (prefix iup iup:)) (use canvas-draw) |
︙ | ︙ | |||
82 83 84 85 86 87 88 | (if (args:get-arg "-h") (begin (print help) (exit))) ;; ease debugging by loading ~/.dashboardrc (let ((debugcontrolf (conc (get-environment-variable "HOME") "/.dashboardrc"))) | | | 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 | (if (args:get-arg "-h") (begin (print help) (exit))) ;; ease debugging by loading ~/.dashboardrc (let ((debugcontrolf (conc (get-environment-variable "HOME") "/.dashboardrc"))) (if (common:file-exists? debugcontrolf) (load debugcontrolf))) (debug:setup) (define *tim* (iup:timer)) (define *ord* #f) |
︙ | ︙ | |||
373 374 375 376 377 378 379 | (if (not (null? path)) (hash-table-ref/default (dboard:data-path-test-ids *data*) path #f) #f)) (define (test-panel window-id) (let* ((curr-row-num 0) (viewlog (lambda (x) | | | 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 | (if (not (null? path)) (hash-table-ref/default (dboard:data-path-test-ids *data*) path #f) #f)) (define (test-panel window-id) (let* ((curr-row-num 0) (viewlog (lambda (x) (if (common:file-exists? logfile) ;(system (conc "firefox " logfile "&")) (iup:send-url logfile) (message-window (conc "File " logfile " not found"))))) (xterm (lambda (x) (if (directory-exists? rundir) (let ((shell (if (get-environment-variable "SHELL") (conc "-e " (get-environment-variable "SHELL")) |
︙ | ︙ | |||
728 729 730 731 732 733 734 | (iup:callback-set! *tim* "ACTION_CB" (lambda (x) ;; Want to dedicate no more than 50% of the time to this so skip if ;; 2x delta time has not passed since last query (if (< nextmintime (current-milliseconds)) (let* ((starttime (current-milliseconds)) | | | > | 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 | (iup:callback-set! *tim* "ACTION_CB" (lambda (x) ;; Want to dedicate no more than 50% of the time to this so skip if ;; 2x delta time has not passed since last query (if (< nextmintime (current-milliseconds)) (let* ((starttime (current-milliseconds)) ;; (changes (dcommon:run-update keys data runname keypatts testpatt states statuses 'full my-window-id)) (endtime (current-milliseconds))) (set! nextmintime (+ endtime (* 2 (- endtime starttime)))) ;; (debug:print 11 *default-log-port* "CHANGE(S): " (car changes) "...")) ) (debug:print-info 11 *default-log-port* "Server overloaded")))))) ;; (dboard:data-updaters-set! *data* (make-hash-table)) (newdashboard #f) ;; *dbstruct-local*) (iup:main-loop) |
Added nexttag.rb version [08abd2a000].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 | #!/usr/bin/env ruby # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. def get_next_tag(branch) abort "Not on a version branch like v1.64 (got: >#{branch}<)" unless branch.match(/^v\d\.\d\d$/) #puts "this branch: #{branch}" tag_pat = /#{branch}(\d\d)/ remote=`fsl remote`.chomp.sub(/^file:\/\//,'') # get tagset from origin cmd="fossil tag -R '#{remote}' list" tags = `#{cmd}`.split /\n/ abort "fossil command failed [#{cmd}]" if $? != 0 branch_tags = tags.find_all{|x| x.match(tag_pat) }.sort if branch_tags.length == 0 return branch + "01" else latest_tag = branch_tags.last m1 = latest_tag.match(tag_pat) minor_digits = m1[1].to_i + 1 if (minor_digits % 10) == 0 minor_digits += 1 end new_tag=sprintf("%s%02d", branch, minor_digits) return new_tag end end branch = `fossil branch`.sub(/\A.*\* /m,'').sub(/\n.*\z/m,'') tag= get_next_tag(branch) puts "TODO: Write to megatest-version.scm:" puts ";; Always use two or four digit decimal ;; 1.01, 1.02...1.10,1.11,1.1101 ... 1.99,2.00.. (declare (unit megatest-version)) (define megatest-version #{tag.sub(/^v/,'')}) " puts "TODO: fossil tag add #{tag} #{branch}" puts "" |
Modified ods.scm from [9b470d03a5] to [42e94b826f].
1 2 | ;; Copyright 2011, Matthew Welland. ;; | | | > > > > > | | > | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | ;; Copyright 2011, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. ;; (use csv-xml regex) (declare (unit ods)) (declare (uses common)) (define ods:dirs '("Configurations2" |
︙ | ︙ | |||
195 196 197 198 199 200 201 | ;; data format: ;; '( (sheet1 (r1c1 r1c2 r1c3 ...) ;; (r2c1 r2c3 r2c3 ...) ) ;; (sheet2 ( ... ) ;; ( ... ) ) ) (define (ods:list->ods path fname data) | | | 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 | ;; data format: ;; '( (sheet1 (r1c1 r1c2 r1c3 ...) ;; (r2c1 r2c3 r2c3 ...) ) ;; (sheet2 ( ... ) ;; ( ... ) ) ) (define (ods:list->ods path fname data) (if (not (common:file-exists? path)) (print "ERROR: path to create ods data must pre-exist") (begin (with-output-to-file (conc path "/content.xml") (lambda () (ods:construct-dir path) (ods:add-non-content-files path) (ods:make-thumbnail path) |
︙ | ︙ |
Modified oldsrc/debugger.scm from [f446c83fb1] to [1c814d6c52].
1 2 3 4 5 6 7 | (use iup) (define *debugger-control* #f) (define *debugger-rownum* 0) (define *debugger-matrix* #f) (define *debugger* #f) | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | ;; Copyright 2006-2017, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. (use iup) (define *debugger-control* #f) (define *debugger-rownum* 0) (define *debugger-matrix* #f) (define *debugger* #f) |
︙ | ︙ |
Modified oldsrc/fs-transport.scm from [d187681c70] to [18790d5aa9].
1 2 3 | ;; Copyright 2006-2012, Matthew Welland. ;; | | | > > > > > | | > | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | ;; Copyright 2006-2012, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. ;; (require-extension (srfi 18) extras tcp s11n) (use sqlite3 srfi-1 posix regex regex-case srfi-69 hostinfo md5 message-digest) (import (prefix sqlite3 sqlite3:)) (use spiffy uri-common intarweb http-client spiffy-request-vars) |
︙ | ︙ |
Added oldsrc/multi-dboard.scm version [8f63a105a2].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 | ;;====================================================================== ;; Copyright 2006-2013, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. ;;====================================================================== (use format numbers sql-de-lite srfi-1 posix regex regex-case srfi-69 srfi-18 call-with-environment-variables) (require-library iup) (import (prefix iup iup:)) (use canvas-draw) (declare (uses margs)) (declare (uses megatest-version)) (declare (uses gutils)) (declare (uses tree)) (declare (uses configf)) (declare (uses portlogger)) (declare (uses keys)) (declare (uses common)) (include "common_records.scm") ;; (include "db_records.scm") ;; (include "key_records.scm") (define help (conc "Megatest Dashboard, documentation at http://www.kiatoa.com/fossils/megatest version " megatest-version " license GPL, Copyright (C) Matt Welland 2011 Usage: dashboard [options] -h : this help -group groupname : display this group of areas -test testid : control test identified by testid -guimonitor : control panel for runs Misc -rows N : set number of rows ")) ;; process args (define remargs (args:get-args (argv) (list "-group" ;; display this group of areas "-debug" ) (list "-h" "-v" "-q" ) args:arg-hash 0)) (if (args:get-arg "-h") (begin (print help) (exit))) ;; (if (args:get-arg "-host") ;; (begin ;; (set! (common:get-remote remote) (string-split (args:get-arg "-host" ":"))) ;; (client:launch)) ;; (client:launch)) (define *runremote* #f) (define *windows* (make-hash-table)) (define *changed-main* (make-hash-table)) ;; set path/... => #t (define *changed-mutex* (make-mutex)) ;; use for all incoming change requests (define *searchpatts* (make-hash-table)) (debug:setup) (define *tim* (iup:timer)) (define *ord* #f) (iup:attribute-set! *tim* "TIME" 300) (iup:attribute-set! *tim* "RUN" "YES") (define (message-window msg) (iup:show (iup:dialog (iup:vbox (iup:label msg #:margin "40x40"))))) (define (iuplistbox-fill-list lb items . default) (let ((i 1) (selected-item (if (null? default) #f (car default)))) (iup:attribute-set! lb "VALUE" (if selected-item selected-item "")) (for-each (lambda (item) (iup:attribute-set! lb (number->string i) item) (if selected-item (if (equal? selected-item item) (iup:attribute-set! lb "VALUE" item))) ;; (number->string i)))) (set! i (+ i 1))) items) i)) (define (pad-list l n)(append l (make-list (- n (length l))))) (define (mkstr . x) (string-intersperse (map conc x) ",")) (define (update-search x val) (hash-table-set! *searchpatts* x val)) ;;====================================================================== ;; R E C O R D S ;;====================================================================== ;; NOTE: Consider switching to defstruct. ;; data for an area (regression or testsuite) ;; (define-record areadat name ;; area name path ;; mt run area home configdat ;; megatest config denoise ;; focal point for not putting out same messages over and over client-signature ;; key for client-server conversation remote ;; hash of all the client side connnections run-keys ;; target keys for this area runs ;; used in dashboard, hash of run-ids -> rundat read-only ;; can I write to this area? monitordb ;; db handle for monitor.db maindb ;; db handle for main.db ) ;; rundat, basic run data ;; (define-record rundat id ;; the run-id target ;; val1/val2 ... corrosponding to run-keys in areadat runname state ;; state of the run, symbol status ;; status of the run, symbol event-time ;; when the run was initiated tests ;; hash of test-id -> testdat, QUESTION: separate by run-id? db ;; db handle ) ;; testdat, basic test data (define-record testdat run-id ;; what run is this from id ;; test id testname ;; test name itempath ;; item path state ;; test state, symbol status ;; test status, symbol event-time ;; when the test started duration ;; how long the test took ) ;; general data for the dboard application ;; (define-record data cfgdat ;; data from ~/.megatest/<group>.dat areas ;; hash of areaname -> area-rec current-window-id ;; current-tab-id ;; update-needed ;; flag to indicate that the tab pointed to by current tab id needs refreshing immediately tabs ;; hash of tab-id -> areaname (??) should be of type "tab" ) ;; all the components of an area display, all fits into a tab but ;; parts may be swapped in/out as needed ;; (define-record tab tree matrix ;; the spreadsheet areadat ;; the one-structure (one day dbstruct will be put in here) view-path ;; <target/path>/<runname>/... view-type ;; standard, etc. controls ;; the controls data ;; all the data kept in sync with db filters ;; user filters, alist name -> filter record, eventually store these in ~/.megatest/<group>.dat? run-id ;; the current run-id test-ids ;; the current test id hash, run-id => test-id command ;; the command from the entry field headers ;; hash of header -> colnum rows ;; hash of rowname -> rownum ) (define-record filter target ;; hash of widgets for the target runname ;; the runname widget testpatt ;; the testpatt widget ) ;;====================================================================== ;; D B ;;====================================================================== ;; These are all using sql-de-lite and independent of area so cannot use stuff ;; from db.scm ;; NB// run-id=#f => return dbdir only ;; (define (areadb:dbfile-path areadat run-id) (let* ((cfgdat (areadat-configdat areadat)) (dbdir (or (configf:lookup cfgdat "setup" "dbdir") (conc (configf:lookup cfgdat "setup" "linktree") "/.db"))) (fname (if run-id (case run-id ((-1) "monitor.db") ((0) "main.db") (else (conc run-id ".db"))) #f))) (handle-exceptions exn (begin (debug:print-error 0 *default-log-port* "Couldn't create path to " dbdir) (exit 1)) (if (not (directory? dbdir))(create-directory dbdir #t))) (if fname (conc dbdir "/" fname) dbdir))) ;; -1 => monitor.db ;; 0 => main.db ;; >1 => <run-id>.db ;; (define (areadb:open areadat run-id) (let* ((runs (areadat-runs areadat)) (rundat (if (> run-id 0) ;; it is a run (hash-table-ref/default runs run-id #f) #f)) (db (case run-id ;; if already opened, get the db and return it ((-1) (areadat-monitordb areadat)) ((0) (areadat-maindb areadat)) (else (if rundat (rundat-db rundat) #f))))) (if db db ;; merely return the already opened db (let* ((dbfile (areadb:dbfile-path areadat run-id)) ;; not already opened, so open it (db (if (file-exists? dbfile) (open-database dbfile) (begin (debug:print-error 0 *default-log-port* "I was asked to open " dbfile ", but file does not exist or is not readable.") #f)))) (case run-id ((-1)(areadat-monitordb-set! areadat db)) ((0) (areadat-maindb-set! areadat db)) (else (rundat-db-set! rundat db))) db)))) ;; populate the areadat tests info, does NOT fill the tests data itself unless asked ;; (define (areadb:populate-run-info areadat) (let* ((runs (or (areadat-runs areadat) (make-hash-table))) (keys (areadat-run-keys areadat)) (maindb (areadb:open areadat 0))) (if maindb (query (for-each-row (lambda (row) (let ((id (list-ref row 0)) (dat (apply make-rundat (append row (list #f #f))))) ;; add placeholders for tests and db (print row) (hash-table-set! runs id dat)))) (sql maindb (conc "SELECT id," (string-intersperse keys "||'/'||") ",runname,state,status,event_time FROM runs WHERE state != 'deleted';"))) (debug:print-error 0 *default-log-port* "no main.db found at " (areadb:dbfile-path areadat 0))) areadat)) ;; given an areadat and target/runname patt fill up runs data ;; ;; ?????/ ;; given a list of run-ids refresh/retrieve runs data into areadat ;; (define (areadb:fill-tests areadat #!key (run-ids #f)) (let* ((runs (or (areadat-runs areadat) (make-hash-table)))) (for-each (lambda (run-id) (let* ((rundat (hash-table-ref/default runs run-id #f)) (tests (if (and rundat (rundat-tests rundat)) ;; re-use existing hash table? (rundat-tests rundat) (let ((ht (make-hash-table))) (rundat-tests-set! rundat ht) ht))) (rundb (areadb:open areadat run-id))) (query (for-each-row (lambda (row) (let* ((id (list-ref row 0)) (testname (list-ref row 1)) (itempath (list-ref row 2)) (state (list-ref row 3)) (status (list-ref row 4)) (eventtim (list-ref row 5)) (duration (list-ref row 6))) (hash-table-set! tests id (make-testdat run-id id testname itempath state status eventtim duration))))) (sql rundb "SELECT id,testname,item_path,state,status,event_time,run_duration FROM tests WHERE state != 'DELETED';")))) (or run-ids (hash-table-keys runs))) areadat)) ;; initialize and refresh data ;; (define (dboard:general-updater con port) (for-each (lambda (window-id) ;; (print "Processing for window-id " window-id) (let* ((window-dat (hash-table-ref *windows* window-id)) (areas (data-areas window-dat)) ;; (keys (areadat-run-keys area-dat)) (tabs (data-tabs window-dat)) (tab-ids (hash-table-keys tabs)) (current-tab (if (null? tab-ids) #f (hash-table-ref tabs (car tab-ids)))) (current-tree (if (null? tab-ids) #f (tab-tree current-tab))) (current-node (if (null? tab-ids) 0 (string->number (iup:attribute current-tree "VALUE")))) (current-path (if (eq? current-node 0) "Areas" (string-intersperse (tree:node->path current-tree current-node) "/"))) (current-matrix (if (null? tab-ids) #f (tab-matrix current-tab))) (seen-nodes (make-hash-table)) (path-changed (if current-tab (equal? current-path (tab-view-path current-tab)) #t))) ;; (debug:print-info 0 *default-log-port* "Current path: " current-path) ;; now for each area in the window gather the data (if path-changed (begin (debug:print-info 0 *default-log-port* "clearing matrix - path changed") (dboard:clear-matrix current-tab))) (for-each (lambda (area-name) ;; (print "Processing for area-name " area-name) (let* ((area-dat (hash-table-ref areas area-name)) (area-path (areadat-path area-dat)) (runs (areadat-runs area-dat))) (if (hash-table-ref/default *changed-main* area-path 'processed) (begin (print "Processing " area-dat " for area-name " area-name) (hash-table-set! *changed-main* area-path #f) (areadb:populate-run-info area-dat) (for-each (lambda (run-id) (let* ((run (hash-table-ref runs run-id)) (target (rundat-target run)) (runname (rundat-runname run))) (if current-tree (let* ((partial-path (append (string-split target "/")(list runname))) (full-path (cons area-name partial-path))) (if (not (hash-table-exists? seen-nodes full-path)) (begin (print "INFO: Adding node " partial-path " to section " area-name) (tree:add-node current-tree "Areas" full-path) (areadb:fill-tests area-dat run-ids: (list run-id)))) (hash-table-set! seen-nodes full-path #t))))) (hash-table-keys runs)))) (if (or (equal? "Areas" current-path) (string-match (conc "^Areas/" area-name "(|\\/.*)$") current-path)) (dboard:redraw-area area-name area-dat current-tab current-matrix current-path)))) (hash-table-keys areas)))) (hash-table-keys *windows*))) ;;====================================================================== ;; D A S H B O A R D D B ;;====================================================================== ;; All moved to common.scm ;;====================================================================== ;; T R E E ;;====================================================================== ;; <area> - <target - ... > - <runname> - <test> - <itempath - ...> (define (dashboard:tree-browser data adat window-id) ;; (iup:split (let* ((tb (iup:treebox #:value 0 #:title "Areas" #:expand "YES" #:addexpanded "NO" #:selection-cb (lambda (obj id state) ;; (print "obj: " obj ", id: " id ", state: " state) (let* ((tree-path (tree:node->path obj id)) (area (car tree-path)) (areadat-path (cdr tree-path))) #f ;; (test-id (tree-path->test-id (cdr run-path)))) ;; (if test-id ;; (hash-table-set! (dboard:data-curr-test-ids *data*) ;; window-id test-id)) ;; (print "path: " (tree:node->path obj id) " test-id: " test-id)))))) ))))) ;; (iup:attribute-set! tb "VALUE" "0") ;; (iup:attribute-set! tb "NAME" "Runs") ;; (iup:attribute-set! tb "ADDEXPANDED" "NO") ;; (dboard:data-tests-tree-set! *data* tb) tb)) ;;====================================================================== ;; M A I N M A T R I X ;;====================================================================== ;; General displayer ;; (define (dashboard:main-matrix data adat window-id) (let* (;; (tab-dat (areadat- (view-matrix (iup:matrix ;; (runs-for-targ (db:get-runs-by-patt *dbstruct-local* *keys* "%" target #f #f #f)) #:expand "YES" ;; #:fittosize "YES" #:resizematrix "YES" #:scrollbar "YES" #:numcol 100 #:numlin 100 #:numcol-visible 3 #:numlin-visible 20 #:click-cb (lambda (obj lin col status) (print "obj: " obj " lin: " lin " col: " col " status: " status " value: " (iup:attribute obj "VALUE")))))) ;; (iup:attribute-set! view-matrix "RESIZEMATRIX" "YES") (iup:attribute-set! view-matrix "WIDTH0" "100") ;; (dboard:data-runs-matrix-set! *data* runs-matrix) ;; (iup:hbox ;; (iup:frame ;; #:title "Runs browser" ;; (iup:vbox view-matrix)) ;;====================================================================== ;; A R E A S ;;====================================================================== (define (dashboard:init-area data area-name apath) (let* ((mtconf (dboard:read-mtconf apath)) (area-dat (let ((ad (make-areadat area-name ;; area name apath ;; path to area ;; 'http ;; transport mtconf ;; megatest.config (make-hash-table) ;; denoise hash #f ;; client-signature #f ;; remote connections (keys:config-get-fields mtconf) ;; run keys (make-hash-table) ;; run-id -> (hash of test-ids => dat) (and (file-exists? apath)(file-write-access? apath)) ;; read-only #f #f ))) (hash-table-set! (data-areas data) area-name ad) ad))) area-dat)) ;; given the keys for an area and a path from the tree browser ;; return the level: areas area runs run tests test ;; (define (dboard:get-view-type keys current-path) (let* ((path-parts (string-split current-path "/")) (path-len (length path-parts))) (cond ((equal? current-path "Areas") 'areas) ((eq? path-len 2) 'area) ((<= (+ (length keys) 2) path-len) 'runs) (else 'run)))) (define (dboard:clear-matrix tab) (if tab (begin (iup:attribute-set! (tab-matrix tab) "CLEARVALUE" "ALL") (tab-headers-set! tab (make-hash-table)) (tab-rows-set! tab (make-hash-table))))) ;; full redraw of a given area ;; (define (dboard:redraw-area area-name area-dat tab-dat current-matrix current-path) (let* ((keys (areadat-run-keys area-dat)) (runs (areadat-runs area-dat)) (headers (tab-headers tab-dat)) (rows (tab-rows tab-dat)) (used-cols (hash-table-values headers)) (used-rows (hash-table-values rows)) (touched (make-hash-table)) ;; (vector row col) ==> true, touched cell (view-type (dboard:get-view-type keys current-path)) (changed #f) (state-statuses (list "PASS" "FAIL" "WARN" "CHECK" "SKIP" "RUNNING" "LAUNCHED"))) ;; (debug:print 0 *default-log-port* "current-matrix=" current-matrix) (case view-type ((areas) ;; find row for this area, if not found, create new entry (let* ((curr-rownum (hash-table-ref/default rows area-name #f)) (next-rownum (+ (apply max (cons 0 used-rows)) 1)) (rownum (or curr-rownum next-rownum)) (coord (conc rownum ":0"))) (if (not curr-rownum)(hash-table-set! rows area-name rownum)) (if (not (equal? (iup:attribute current-matrix coord) area-name)) (begin (let loop ((hed (car state-statuses)) (tal (cdr state-statuses)) (count 1)) (if (not (equal? (iup:attribute current-matrix (conc "0:" count)) hed)) (iup:attribute-set! current-matrix (conc "0:" count) hed)) (iup:attribute-set! current-matrix (conc rownum ":" count) "0") (if (not (null? tal)) (loop (car tal)(cdr tal)(+ count 1)))) (debug:print-info 0 *default-log-port* "view-type=" view-type ", rownum=" rownum ", curr-rownum=" curr-rownum ", next-rownum=" next-rownum ", coord=" coord ", area-name=" area-name) (iup:attribute-set! current-matrix coord area-name) (set! changed #t)))))) (if changed (iup:attribute-set! current-matrix "REDRAW" "ALL")))) ;; (dboard:clear-matrix current-matrix used-cols used-rows touched) ;; clear all ;;====================================================================== ;; D A S H B O A R D ;;====================================================================== (define (dashboard:area-panel aname data window-id) (let* ((apath (configf:lookup (data-cfgdat data) aname "path")) ;; (hash-table-ref (dboard:data-cfgdat data) area-name)) ;; (hash-table-ref (dboard:data-cfgdat data) aname)) (area-dat (dashboard:init-area data aname apath)) (tb (dashboard:tree-browser data area-dat window-id)) ;; (dboard:areas-tree-browser data) (ad (dashboard:main-matrix data area-dat window-id)) (areas (data-areas data)) (dboard-dat (make-tab #f ;; tree #f ;; matrix area-dat ;; #f ;; view path 'default ;; view type #f ;; controls (make-hash-table) ;; cached data? not sure how to use this yet :) #f ;; filters #f ;; the run-id (make-hash-table) ;; run-id -> test-id, for current test id "" (make-hash-table) ;; headername -> colnum (make-hash-table) ;; rowname -> rownum ))) (hash-table-set! (data-areas data) aname area-dat) ;; dboard-dat) (hash-table-set! (data-tabs data) window-id dboard-dat) (tab-tree-set! dboard-dat tb) (tab-matrix-set! dboard-dat ad) (iup:split #:value 200 tb ad))) ;; Main Panel ;; (define (dashboard:main-panel data window-id) (iup:dialog #:title "Megatest Control Panel" ;; #:menu (dcommon:main-menu data) #:shrink "YES" (iup:vbox (let* ((area-names (hash-table-keys (data-cfgdat data))) (area-panels (map (lambda (aname) (dashboard:area-panel aname data window-id)) area-names)) (tabtop (apply iup:tabs #:tabchangepos-cb (lambda (obj curr prev) (data-current-tab-id-set! data curr) (data-update-needed-set! data #t) (print "Tab is: " curr ", prev was " prev)) area-panels)) (tabs (data-tabs data))) (if (not (null? area-names)) (let loop ((index 0) (hed (car area-names)) (tal (cdr area-names))) ;; (hash-table-set! tabs index hed) (debug:print 0 *default-log-port* "Adding area " hed " with index " index " to dashboard") (iup:attribute-set! tabtop (conc "TABTITLE" index) hed) (if (not (null? tal)) (loop (+ index 1)(car tal)(cdr tal))))) tabtop)))) ;;====================================================================== ;; N A N O M S G S E R V E R ;;====================================================================== (define (dboard:server-service soc port) (print "server starting") (let loop ((msg-in (nn-recv soc)) (count 0)) (if (eq? 0 (modulo count 1000)) (print "server received: " msg-in ", count=" count)) (cond ;; ;; quit ;; ((equal? msg-in "quit") (nn-send soc "Ok, quitting")) ;; ;; ping ;; ((and (>= (string-length msg-in) 4) (equal? (substring msg-in 0 4) "ping")) (nn-send soc (conc (current-process-id))) (loop (nn-recv soc)(+ count 1))) ;; ;; main changed ;; ((and (>= (string-length msg-in) 4) (equal? (substring msg-in 0 4) "main")) (let ((parts (string-split msg-in " "))) (hash-table-set! *changed-main* (cadr parts) #t) (nn-send soc "got it!"))) ;; ;; ?? ;; (else (nn-send soc "hello " msg-in " you got to the else clause!"))) (loop (nn-recv soc)(if (> count 20000000) 0 (+ count 1))))) (define (dboard:one-time-ping-receive soc port) (let ((msg-in (nn-recv soc))) (if (and (>= (string-length msg-in) 4) (equal? (substring msg-in 0 4) "ping")) (nn-send soc (conc (current-process-id)))))) (define (dboard:server-start given-port #!key (num-tries 200)) (let* ((rep (nn-socket 'rep)) (port (or given-port (portlogger:main "find"))) (con (conc "tcp://*:" port))) ;; register this connect here .... (nn-bind rep con) (thread-start! (make-thread (lambda () (dboard:one-time-ping-receive rep port)) "one time receive thread")) (if (dboard:ping-self "localhost" port) (begin (print "INFO: dashboard nanomsg server started on " port) (values rep port)) (begin (print "WARNING: couldn't create server on port " port) (portlogger:main "set" "failed") (if (> num-tries 0) (dboard:server-start #f (- num-tries 1)) (begin (print "ERROR: failed to start nanomsg server") (values #f #f))))))) (define (dboard:server-close con port) (nn-close con) (portlogger:main "set" port "released")) (define (dboard:ping-self host port #!key (return-socket #t)) ;; send a random number along with pid and check that we get it back (let* ((req (nn-socket 'req)) (key "ping") (success #f) (keepwaiting #t) (ping (make-thread (lambda () (print "ping: sending string \"" key "\", expecting " (current-process-id)) (nn-send req key) (let ((result (nn-recv req))) (if (equal? (conc (current-process-id)) result) (begin (print "ping, success: received \"" result "\"") (set! success #t)) (begin (print "ping, failed: received key \"" result "\"") (set! keepwaiting #f) (set! success #f))))) "ping")) (timeout (make-thread (lambda () (let loop ((count 0)) (thread-sleep! 1) (print "still waiting after " count " seconds...") (if (and keepwaiting (< count 10)) (loop (+ count 1)))) (if keepwaiting (begin (print "timeout waiting for ping") (thread-terminate! ping)))) "timeout"))) (nn-connect req (conc "tcp://" host ":" port)) (handle-exceptions exn (begin (print-call-chain) (print 0 " message: " ((condition-property-accessor 'exn 'message) exn)) (print "exn=" (condition->list exn)) (print "ping failed to connect to " host ":" port)) (thread-start! timeout) (thread-start! ping) (thread-join! ping) (if success (thread-terminate! timeout))) (if return-socket (if success req #f) (begin (nn-close req) success)))) ;;====================================================================== ;; C O N F I G U R A T I O N ;;====================================================================== ;; Get the configuration file for a group name, if the group name is "default" and it doesn't ;; exist, create it and add the current path if it contains megatest.config ;; (define (dboard:get-config group-name) (let* ((fname (conc (getenv "HOME") "/.megatest/" group-name ".dat"))) (if (file-exists? fname) (read-config fname (make-hash-table) #t) (if (dboard:create-config fname) (dboard:get-config group-name) (make-hash-table))))) (define (dboard:create-config fname) ;; (handle-exceptions ;; exn ;; ;; #f ;; failed to create - just give up (let* ((dirname (pathname-directory fname)) (file-name (pathname-strip-directory fname)) (curr-mtcfgdat (find-config "megatest.config" toppath: (or (get-environment-variable "MT_RUN_AREA_HOME")(current-directory)))) (curr-mtcfg (if (and curr-mtcfgdat (not (null? curr-mtcfgdat)))(cadr curr-mtcfgdat) #f)) (curr-mtpath (if curr-mtcfg (car curr-mtcfgdat) #f))) (if curr-mtpath (begin (debug:print-info 0 *default-log-port* "Creating config file " fname) (if (not (file-exists? dirname)) (create-directory dirname #t)) (with-output-to-file fname (lambda () (let ((aname (pathname-strip-directory curr-mtpath))) (print "[" aname "]") (print "path " curr-mtpath)))) #t) (begin (debug:print-info 0 *default-log-port* "Need to create a config but no megatest.config found: " curr-mtcfgdat) #f)))) ;; ) (define (dboard:read-mtconf apath) (let* ((mtconffile (conc apath "/megatest.config"))) (call-with-environment-variables (list (cons "MT_RUN_AREA_HOME" apath)) (lambda () (read-config mtconffile (make-hash-table) #f)) ;; megatest.config ))) ;;====================================================================== ;; G U I S T U F F ;;====================================================================== ;;; main. Theoretically could have multiple windows (each with a group of tags, thus window-id ;;; (define (dboard:make-window window-id) (let* (;; (window-id 0) (groupn (or (args:get-arg "-group") "default")) (cfgdat (dboard:get-config groupn)) ;; (cfgdat (if (file-exists? cfname)(read-config cfname (make-hash-table) #t)(make-hash-table))) (data (make-data cfgdat ;; this is the data from ~/.megatest for the selected group (make-hash-table) ;; areaname -> area-rec 0 ;; current window id 0 ;; current tab id #f ;; redraw needed for current tab id (make-hash-table) ;; tab-id -> areaname ))) (hash-table-set! *windows* window-id data) (iup:show (dashboard:main-panel data window-id)) (iup:main-loop))) ;; ease debugging by loading ~/.dashboardrc (let ((debugcontrolf (conc (get-environment-variable "HOME") "/.dashboardrc"))) (if (file-exists? debugcontrolf) (load debugcontrolf))) (define (main) (let-values (((con port)(dboard:server-start #f))) (let ((portnum (if (string? port)(string->number port) port))) ;; got here, monitor/dashboard was started (mddb:register-dashboard portnum) (thread-start! (make-thread (lambda ()(dboard:server-service con portnum)) "server service")) (thread-start! (make-thread (lambda () (let loop () (dboard:general-updater con portnum) (thread-sleep! 1) (loop))) "general updater")) (dboard:make-window 0) (mddb:unregister-dashboard (get-host-name) portnum) (dboard:server-close con port)))) |
Modified oldsrc/newdashboard.scm from [6cbd88e309] to [2766d097fb].
1 2 3 | ;;====================================================================== ;; Copyright 2006-2013, Matthew Welland. ;; | | | > > > > > | | > | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | ;;====================================================================== ;; Copyright 2006-2013, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. ;; ;;====================================================================== (use format numbers) (require-library iup) (import (prefix iup iup:)) (use canvas-draw) |
︙ | ︙ |
Added oldsrc/nmsg-transport.scm version [adedc287f0].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 | ;; Copyright 2006-2012, Matthew Welland. ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. (require-extension (srfi 18) extras tcp s11n) (use sqlite3 srfi-1 posix regex regex-case srfi-69 hostinfo md5 message-digest) (import (prefix sqlite3 sqlite3:)) ;; (use nanomsg) (declare (unit nmsg-transport)) (declare (uses common)) (declare (uses db)) (declare (uses tests)) (declare (uses tasks)) ;; tasks are where stuff is maintained about what is running. (declare (uses server)) (include "common_records.scm") (include "db_records.scm") ;; Transition to pub --> sub with pull <-- push ;; ;; 1. client sends request to server via push to the pull port ;; 2. server puts request in queue or processes immediately as appropriate ;; 3. server puts responses from completed requests into pub port ;; ;; TODO ;; ;; Done Tested ;; [x] [ ] 1. Add columns pullport pubport to servers table ;; [x] [ ] 2. Add rm of monitor.db if older than 11/12/2012 ;; [x] [ ] 3. Add create of pullport and pubport with finding of available ports ;; [x] [ ] 4. Add client compose of request ;; [x] [ ] - name of client: testname/itempath-test_id-hostname ;; [x] [ ] - name of request: callname, params ;; [x] [ ] - request key: f(clientname, callname, params) ;; [x] [ ] 5. Add processing of subscription hits ;; [x] [ ] - done when get key ;; [x] [ ] - return results ;; [x] [ ] 6. Add timeout processing ;; [x] [ ] - after 60 seconds ;; [ ] [ ] i. check server alive, connect to new if necessary ;; [ ] [ ] ii. resend request ;; [ ] [ ] 7. Turn self ping back on (define (nmsg-transport:make-server-url hostport #!key (bindall #f)) (if (not hostport) #f (conc "tcp://" (if bindall "*" (car hostport)) ":" (cadr hostport)))) (define *server-loop-heart-beat* (current-seconds)) (define *heartbeat-mutex* (make-mutex)) ;;====================================================================== ;; S E R V E R ;;====================================================================== (define (nmsg-transport:run dbstruct hostn run-id server-id #!key (retrynum 1000)) (debug:print 2 *default-log-port* "Attempting to start the server ...") (let* ((start-port (portlogger:open-run-close portlogger:find-port)) (server-thread (make-thread (lambda () (nmsg-transport:try-start-server dbstruct run-id start-port server-id)) "server thread")) (tdbdat (tasks:open-db))) (thread-start! server-thread) (thread-sleep! 0.1) (if (nmsg-transport:ping hostn start-port timeout: 2 expected-key: (current-process-id)) (let ((interface (if (equal? hostn "-")(get-host-name) hostn))) (tasks:server-set-interface-port (db:delay-if-busy tdbdat) server-id interface start-port) (tasks:server-set-state! (db:delay-if-busy tdbdat) server-id "dbprep") (set! *server-info* (list hostn start-port)) ;; probably not needed anymore? currently used by keep-running (thread-sleep! 3) ;; give some margin for queries to complete before switching from file based access to server based access ;; (set! *inmemdb* dbstruct) (tasks:server-set-state! (db:delay-if-busy tdbdat) server-id "running") (thread-start! (make-thread (lambda ()(nmsg-transport:keep-running server-id run-id)) "keep running")) (thread-join! server-thread)) (if (> retrynum 0) (begin (debug:print 0 *default-log-port* "WARNING: Failed to connect to server (self) on host " hostn ":" start-port ", trying again.") (tasks:server-delete-record (db:delay-if-busy tdbdat) server-id "failed to start, never received server alive signature") (portlogger:open-run-close portlogger:set-failed start-port) (nmsg-transport:run dbstruct hostn run-id server-id)) (begin (debug:print-error 0 *default-log-port* "could not find an open port to start server on. Giving up") (exit 1)))))) (define (nmsg-transport:try-start-server dbstruct run-id portnum server-id) (let ((repsoc (nn-socket 'rep))) (nn-bind repsoc (conc "tcp://*:" portnum)) (let loop ((msg-in (nn-recv repsoc))) (let* ((dat (db:string->obj msg-in transport: 'nmsg))) (debug:print 0 *default-log-port* "server, received: " dat) (let ((result (api:execute-requests dbstruct dat))) (debug:print 0 *default-log-port* "server, sending: " result) (nn-send repsoc (db:obj->string result transport: 'nmsg))) (loop (nn-recv repsoc)))))) ;; all routes though here end in exit ... ;; (define (nmsg-transport:launch run-id) (let* ((tdbdat (tasks:open-db)) (dbstruct (db:setup run-id)) (hostn (or (args:get-arg "-server") "-"))) (set! *run-id* run-id) (set! *inmemdb* dbstruct) ;; with nbfake daemonize isn't really needed ;; ;; (if (args:get-arg "-daemonize") ;; (begin ;; (daemon:ize) ;; (if *alt-log-file* ;; we should re-connect to this port, I think daemon:ize disrupts it ;; (begin ;; (current-error-port *alt-log-file*) ;; (current-output-port *alt-log-file*))))) (if (server:check-if-running run-id) (begin (debug:print-info 0 *default-log-port* "Server for run-id " run-id " already running") (exit 0))) (let loop ((server-id (tasks:server-lock-slot (db:delay-if-busy tdbdat) run-id)) (remtries 4)) (if (not server-id) (if (> remtries 0) (begin (thread-sleep! 2) (if (not (server:check-if-running run-id)) (loop (tasks:server-lock-slot (db:delay-if-busy tdbdat) run-id) (- remtries 1)) (begin (debug:print-info 0 *default-log-port* "Another server took the slot, exiting") (exit 0)))) (begin ;; since we didn't get the server lock we are going to clean up and bail out (debug:print-info 2 *default-log-port* "INFO: server pid=" (current-process-id) ", hostname=" (get-host-name) " not starting due to other candidates ahead in start queue") (tasks:server-delete-records-for-this-pid (db:delay-if-busy tdbdat) " http-transport:launch") )) ;; locked in a server id, try to start up (nmsg-transport:run dbstruct hostn run-id server-id)) (set! *didsomething* #t) (exit)))) ;;====================================================================== ;; S E R V E R U T I L I T I E S ;;====================================================================== (define (nmsg-transport:mk-signature) (message-digest-string (md5-primitive) (with-output-to-string (lambda () (write (list (current-directory) (argv))))))) ;;====================================================================== ;; C L I E N T S ;;====================================================================== ;; ping the server at host:port ;; return the open socket if successful (return-socket == #t) ;; expect the key expected-key returned in payload ;; send our-key or #f as payload ;; (define (nmsg-transport:ping hostn port #!key (timeout 3)(return-socket #t)(expected-key #f)(our-key #f)(socket #f)) ;; send a random number along with pid and check that we get it back (let* ((host (if (or (not hostn) (equal? hostn "-")) ;; use localhost (get-host-name) hostn)) (req (or socket (let ((soc (nn-socket 'req))) (nn-connect soc (conc "tcp://" host ":" port)) soc))) (success #t) (dat (vector "ping" our-key)) (result (condition-case (nmsg-transport:client-api-send-receive-raw req dat timeout: timeout) ((timeout)(set! success #f) #f))) (key (if success (vector-ref result 1) #f))) (debug:print 0 *default-log-port* "success=" success ", key=" key ", expected-key=" expected-key ", equal? " (equal? key expected-key)) (if (and success (or (not expected-key) ;; just getting a reply is good enough then (equal? key expected-key))) (if return-socket req (begin (if (not socket)(nn-close req)) ;; don't want a side effect of closing socket if handed it #t)) (begin (if (not socket)(nn-close req)) ;; failed to ping, close socket as side effect #f)))) ;; send data to server, wait max of timeout seconds for a response. ;; return #( success/fail result ) ;; ;; for effiency it is easier to do the obj->string and string->obj here. ;; (define (nmsg-transport:client-api-send-receive-raw socreq indat #!key (enable-send #t)(timeout 25)) (let* ((success #f) (result #f) (keepwaiting #t) (dat (db:obj->string indat transport: 'nmsg)) (send-recv (make-thread (lambda () (nn-send socreq dat) (let* ((res (nn-recv socreq))) (set! success #t) (set! result (db:string->obj res transport: 'nmsg)))) "send-recv")) (timeout (make-thread (lambda () (let loop ((count 0)) (thread-sleep! 1) (debug:print-info 1 *default-log-port* "send-receive-raw, still waiting after " count " seconds...") (if (and keepwaiting (< count timeout)) ;; yes, this is very aproximate (loop (+ count 1)))) (if keepwaiting (begin (print "timeout waiting for ping") (thread-terminate! send-recv)))) "timeout"))) ;; replace with condition-case? (handle-exceptions exn (set! result "timeout") (thread-start! timeout) (thread-start! send-recv) (thread-join! send-recv) (if success (thread-terminate! timeout))) ;; raise timeout error if timed out (if success (if (and (vector? result) (vector-ref result 0)) ;; did it fail at the server? result ;; nope, all good (begin (debug:print-error 0 *default-log-port* "error occured at server, info=" (vector-ref result 2)) (debug:print 0 *default-log-port* " client call chain:") (print-call-chain (current-error-port)) (debug:print 0 *default-log-port* " server call chain:") (pp (vector-ref result 1) (current-error-port)) (signal (vector-ref result 0)))) (signal (make-composite-condition (make-property-condition 'timeout 'message "nmsg-transport:client-api-send-receive-raw timed out talking to server")))))) ;; run nmsg-transport:keep-running in a parallel thread to monitor that the db is being ;; used and to shutdown after sometime if it is not. ;; (define (nmsg-transport:keep-running server-id run-id) ;; if none running or if > 20 seconds since ;; server last used then start shutdown ;; This thread waits for the server to come alive (let* ((server-info (let loop () (let ((sdat #f)) (mutex-lock! *heartbeat-mutex*) (set! sdat *server-info*) (mutex-unlock! *heartbeat-mutex*) (if sdat (begin (debug:print-info 0 *default-log-port* "keep-running got sdat=" sdat) sdat) (begin (thread-sleep! 0.5) (loop)))))) (iface (car server-info)) (port (cadr server-info)) (last-access 0) (tdbdat (tasks:open-db)) (server-timeout (let ((tmo (configf:lookup *configdat* "server" "timeout"))) (if (and (string? tmo) (string->number tmo)) (* 60 60 (string->number tmo)) ;; (* 3 24 60 60) ;; default to three days (* 60 1) ;; default to one minute ;; (* 60 60 25) ;; default to 25 hours )))) (print "Keep-running got server pid " server-id ", using iface " iface " and port " port) (let loop ((count 0)) (thread-sleep! 4) ;; no need to do this very often ;; NB// sync currently does NOT return queue-length (let () ;; (queue-len (cdb:client-call server-info 'sync #t 1))) ;; (print "Server running, count is " count) (if (< count 1) ;; 3x3 = 9 secs aprox (loop (+ count 1))) (mutex-lock! *heartbeat-mutex*) (set! last-access *last-db-access*) (mutex-unlock! *heartbeat-mutex*) (db:sync-touched *inmemdb* run-id force-sync: #t) (if (and *server-run* (> (+ last-access server-timeout) (current-seconds))) (begin (debug:print-info 0 *default-log-port* "Server continuing, seconds since last db access: " (- (current-seconds) last-access)) (loop 0)) (begin (debug:print-info 0 *default-log-port* "Starting to shutdown the server.") (set! *time-to-exit* #t) (db:sync-touched *inmemdb* run-id force-sync: #t) (tasks:server-delete-record (db:delay-if-busy tdbdat) server-id " http-transport:keep-running") (debug:print-info 0 *default-log-port* "Server shutdown complete. Exiting") (exit) )))))) ;;====================================================================== ;; C L I E N T S ;;====================================================================== (define (nmsg-transport:client-connect iface portnum) (let* ((reqsoc (nmsg-transport:ping iface portnum return-socket: #t))) (vector iface portnum #f #f #f (current-seconds) reqsoc))) ;; returns result, there is no sucess/fail flag - handled via excpections ;; (define (nmsg-transport:client-api-send-receive run-id connection-info cmd param #!key (remtries 5)) ;; NB// In the html version of this routine there is a call to ;; tasks:kill-server-run-id when there is an exception (mutex-lock! *http-mutex*) (let* ((packet (vector cmd param)) (reqsoc (http-transport:server-dat-get-socket connection-info)) (res (nmsg-transport:client-api-send-receive-raw reqsoc packet))) ;; (status (vector-ref rawres 0)) ;; (result (vector-ref rawres 1))) (mutex-unlock! *http-mutex*) res)) ;; (vector status (if status (db:string->obj result transport: 'nmsg) result)))) ;;====================================================================== ;; J U N K ;;====================================================================== ;; DO NOT USE ;; (define (nmsg-transport:client-signal-handler signum) (handle-exceptions exn (debug:print 0 *default-log-port* " ... exiting ...") (let ((th1 (make-thread (lambda () (if (not *received-response*) (receive-message* *runremote*))) ;; flush out last call if applicable "eat response")) (th2 (make-thread (lambda () (debug:print-error 0 *default-log-port* "Received ^C, attempting clean exit. Please be patient and wait a few seconds before hitting ^C again.") (thread-sleep! 3) ;; give the flush three seconds to do it's stuff (debug:print 0 *default-log-port* " Done.") (exit 4)) "exit on ^C timer"))) (thread-start! th2) (thread-start! th1) (thread-join! th2)))) |
Modified oldsrc/zmq-transport.scm from [1f9025d277] to [7f966f650c].
1 2 3 | ;;====================================================================== ;; Copyright 2006-2012, Matthew Welland. ;; | | | > > > > > | | > | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | ;;====================================================================== ;; Copyright 2006-2012, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. ;; ;;====================================================================== (require-extension (srfi 18) extras tcp s11n) (use sqlite3 srfi-1 posix regex regex-case srfi-69 hostinfo md5 message-digest) (import (prefix sqlite3 sqlite3:)) |
︙ | ︙ |
Added path-glob/path-glob.scm version [80dc7776c7].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | (define (multi-glob pathspec) (let* ((path-parts (intersperse (string-split pathspec "/" #t) "/"))) (print "path-parts: " path-parts) (if (null? path-parts) '() (let loop ((parts (cdr path-parts)) (result (let ((p (car path-parts))) (if (string=? p "") '("") (glob (car path-parts)))))) (if (null? parts) result (let* ((part (car parts)) (rem (cdr parts))) (loop rem (apply append (map (lambda (curr) (let ((new (string-append curr part))) (print "new: " new " part: " part) (cond ((and (directory? curr)(file-read-access? curr)) (glob new)) ((member part '("." ".." "/")) (list new part)) (else '())))) result))))))))) ;; alternative implementation (define (path-glob pattern) (let ((parts (string-split pattern "/" '()))) (if (null? parts) '() (glob-expand (car parts) (cdr parts)) ))) (define (glob-expand pattern #!optional (rest '())) (let ((result '()) (expanded (glob pattern))) (apply append result (cond ((null? expanded) (list '())) ((null? rest) (list expanded)) (else (map (lambda (x) (if (directory? x) (glob-expand (conc x "/" (car rest)) (cdr rest)) '())) expanded)))))) |
Added path-glob/test.scm version [66f288bdb2].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | (use test posix srfi-1) (load "path-glob.scm") ;; (define globbers `((multi-glob . ,multi-glob)(path-glob . ,path-glob))) (define globbers `((path-glob . ,path-glob))) (define interesting-patts '("../*/*" "/*/bin/*" "./*/bin/*")) (define simple-patts '("../*" "/*" "/bin/*" "." ".." "*" "a[0-1]*")) (define (trim-list lst) (if (> (length lst) 3) (append (take lst 3) '(...)) lst)) (define (generate-prefix patt) (write (conc "patt: " patt (make-string (- 10 (string-length patt)) #\ )))) (print "\nCompare each globber with glob") ;; can only do one level globs here (for-each (lambda (globber) (print "\nGlobber: " globber " vs glob") (for-each (lambda (patt) (generate-prefix patt) (test #f '() (trim-list (lset-xor string=? ((alist-ref globber globbers) patt)(glob patt))))) simple-patts)) (map car globbers)) (print "\nTest the globbers against patts - only checks for resiliance, not correctness.") (for-each (lambda (patt) (generate-prefix patt)(test #f #t (list? (path-glob patt))) ;; (generate-prefix patt)(test #f #t (list? (multi-glob patt))) ) interesting-patts) (print "\nCompare the globbers against each other") #;(for-each (lambda (patt) (generate-prefix patt) (test #f '() (trim-list (lset-xor string=? (path-glob patt)(multi-glob patt))))) interesting-patts) (test-exit) |
Modified portlogger-example.scm from [bd21f0d600] to [79b0759ae8].
1 2 3 4 | (declare (uses portlogger)) (print (apply portlogger:main (cdr (argv)))) | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | ;; Copyright 2006-2017, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. (declare (uses portlogger)) (print (apply portlogger:main (cdr (argv)))) |
Modified portlogger.scm from [b8f7cf5181] to [36a4964f50].
1 2 3 | ;; Copyright 2006-2014, Matthew Welland. ;; | | | > > > > > | | > | > > > < | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | ;; Copyright 2006-2014, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. ;; (require-extension (srfi 18) extras tcp s11n) (use sqlite3 srfi-1 posix srfi-69 hostinfo dot-locking z3) (import (prefix sqlite3 sqlite3:)) (declare (unit portlogger)) (declare (uses db)) ;; lsof -i (define (portlogger:open-db fname) (let* ((avail (tasks:wait-on-journal fname 5 remove: #t)) ;; wait up to about 10 seconds for the journal to go away (exists (common:file-exists? fname)) (db (if avail (sqlite3:open-database fname) (begin (system (conc "rm -f " fname)) (sqlite3:open-database fname)))) (handler (sqlite3:make-busy-timeout 136000)) (canwrite (file-write-access? fname))) ;; (db-init (lambda () ;; (sqlite3:execute ;; db ;; "CREATE TABLE IF NOT EXISTS ports ( ;; port INTEGER PRIMARY KEY, ;; state TEXT DEFAULT 'not-used', |
︙ | ︙ | |||
54 55 56 57 58 59 60 | (avail (tasks:wait-on-journal fname 10))) ;; wait up to about 10 seconds for the journal to go away (handle-exceptions exn (begin ;; (release-dot-lock fname) (debug:print-error 0 *default-log-port* "portlogger:open-run-close failed. " proc " " params) (debug:print 0 *default-log-port* " message: " ((condition-property-accessor 'exn 'message) exn)) | | | | 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 | (avail (tasks:wait-on-journal fname 10))) ;; wait up to about 10 seconds for the journal to go away (handle-exceptions exn (begin ;; (release-dot-lock fname) (debug:print-error 0 *default-log-port* "portlogger:open-run-close failed. " proc " " params) (debug:print 0 *default-log-port* " message: " ((condition-property-accessor 'exn 'message) exn)) (debug:print 5 *default-log-port* "exn=" (condition->list exn)) (if (common:file-exists? fname)(delete-file fname)) ;; brutally get rid of it (print-call-chain (current-error-port))) (let* (;; (lock (obtain-dot-lock fname 2 9 10)) (db (portlogger:open-db fname)) (res (apply proc db params))) (sqlite3:finalize! db) ;; (release-dot-lock fname) res)))) |
︙ | ︙ | |||
101 102 103 104 105 106 107 | (define (portlogger:get-prev-used-port db) (handle-exceptions exn (begin (debug:print 0 *default-log-port* "EXCEPTION: portlogger database probably overloaded or unreadable. If you see this message again remove /tmp/.$USER-portlogger.db") (debug:print 0 *default-log-port* " message: " ((condition-property-accessor 'exn 'message) exn)) | | | 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 | (define (portlogger:get-prev-used-port db) (handle-exceptions exn (begin (debug:print 0 *default-log-port* "EXCEPTION: portlogger database probably overloaded or unreadable. If you see this message again remove /tmp/.$USER-portlogger.db") (debug:print 0 *default-log-port* " message: " ((condition-property-accessor 'exn 'message) exn)) (debug:print 5 *default-log-port* "exn=" (condition->list exn)) (print-call-chain (current-error-port)) (debug:print 0 *default-log-port* "Continuing anyway.") #f) (sqlite3:fold-row (lambda (var curr) (or curr var curr)) #f |
︙ | ︙ | |||
126 127 128 129 130 131 132 | (+ lowport ;; top of registered ports is 49152 but lets use ports in the registered range (random (- 64000 lowport)))))) (handle-exceptions exn (begin (debug:print 0 *default-log-port* "EXCEPTION: portlogger database probably overloaded or unreadable. If you see this message again remove /tmp/.$USER-portlogger.db") (debug:print 0 *default-log-port* " message: " ((condition-property-accessor 'exn 'message) exn)) | | | 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 | (+ lowport ;; top of registered ports is 49152 but lets use ports in the registered range (random (- 64000 lowport)))))) (handle-exceptions exn (begin (debug:print 0 *default-log-port* "EXCEPTION: portlogger database probably overloaded or unreadable. If you see this message again remove /tmp/.$USER-portlogger.db") (debug:print 0 *default-log-port* " message: " ((condition-property-accessor 'exn 'message) exn)) (debug:print 5 *default-log-port* "exn=" (condition->list exn)) (print-call-chain (current-error-port)) (debug:print 0 *default-log-port* "Continuing anyway.")) (portlogger:take-port db portnum)) portnum)) ;; set port to "released", "failed" etc. ;; |
︙ | ︙ | |||
156 157 158 159 160 161 162 | (numargs (length args)) (result (handle-exceptions exn (begin (debug:print 0 *default-log-port* "EXCEPTION: portlogger database at " dbfname " probably overloaded or unreadable. Try removing it.") (debug:print 0 *default-log-port* " message: " ((condition-property-accessor 'exn 'message) exn)) | | | 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 | (numargs (length args)) (result (handle-exceptions exn (begin (debug:print 0 *default-log-port* "EXCEPTION: portlogger database at " dbfname " probably overloaded or unreadable. Try removing it.") (debug:print 0 *default-log-port* " message: " ((condition-property-accessor 'exn 'message) exn)) (debug:print 5 *default-log-port* "exn=" (condition->list exn)) (debug:print 0 *default-log-port* " status: " ((condition-property-accessor 'sqlite3 'status) exn)) (print-call-chain (current-error-port)) #f) (case (string->symbol (car args)) ;; commands with two or more params ((take)(portlogger:take-port db (string->number (cadr args)))) ((find)(portlogger:find-port db)) ((set) (let ((port (cadr args)) |
︙ | ︙ |
Modified process.scm from [1851bdf789] to [b12ad1bbce].
1 2 3 | ;;====================================================================== ;; Copyright 2006-2012, Matthew Welland. ;; | | | > > > > > | | > > > > | | < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | ;;====================================================================== ;; Copyright 2006-2012, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. ;;====================================================================== ;;====================================================================== ;; Process convience utils ;;====================================================================== (use regex directory-utils) (declare (unit process)) (define (process:conservative-read port) (let loop ((res "")) (if (not (eof-object? (peek-char port))) (loop (conc res (read-char port))) res))) |
︙ | ︙ | |||
44 45 46 47 48 49 50 51 52 53 54 55 56 57 | (append result (list curr))) (begin (close-input-port fh) (close-input-port fhe) (close-output-port fho) result))))) ;; ) (define (process:cmd-run-proc-each-line cmd proc . params) ;; (print "Called with cmd=" cmd ", proc=" proc ", params=" params) (handle-exceptions exn (begin (print "ERROR: Failed to run command: " cmd " " (string-intersperse params " ")) (debug:print 0 *default-log-port* " message: " ((condition-property-accessor 'exn 'message) exn)) | > > > > > > > > > > > > > > > > > > > > > > > > > > | | | > > > | | | | | | 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 | (append result (list curr))) (begin (close-input-port fh) (close-input-port fhe) (close-output-port fho) result))))) ;; ) (define (process:cmd-run-with-stderr-and-exitcode->list cmd . params) ;; (print "Called with cmd=" cmd ", proc=" proc ", params=" params) ;; (handle-exceptions ;; exn ;; (begin ;; (print "ERROR: Failed to run command: " cmd " " (string-intersperse params " ")) ;; (print " " ((condition-property-accessor 'exn 'message) exn)) ;; #f) (let-values (((fh fho pid fhe) (if (null? params) (process* cmd) (process* cmd params)))) (let loop ((curr (read-line fh)) (result '())) (let ((errstr (process:conservative-read fhe))) (if (not (string=? errstr "")) (set! result (append result (list errstr))))) (if (not (eof-object? curr)) (loop (read-line fh) (append result (list curr))) (begin (let-values (((anotherpid normalexit? exitstatus) (process-wait pid))) (close-input-port fh) (close-input-port fhe) (close-output-port fho) (list result (if normalexit? exitstatus -1)))))))) (define (process:cmd-run-proc-each-line cmd proc . params) ;; (print "Called with cmd=" cmd ", proc=" proc ", params=" params) (handle-exceptions exn (begin (print "ERROR: Failed to run command: " cmd " " (string-intersperse params " ")) (debug:print 0 *default-log-port* " message: " ((condition-property-accessor 'exn 'message) exn)) (debug:print 5 *default-log-port* "exn=" (condition->list exn)) #f) (let-values (((fh fho pid) (if (null? params) (process cmd) (process cmd params)))) (let loop ((curr (read-line fh)) (result '())) (if (not (eof-object? curr)) (loop (read-line fh) (append result (list (proc curr)))) (begin (close-input-port fh) ;;(close-input-port fhe) (close-output-port fho) result)))))) (define (process:cmd-run-proc-each-line-alt cmd proc) (let* ((fh (open-input-pipe cmd)) (res (port-proc->list fh proc)) (status (close-input-pipe fh))) (if (eq? status 0) res #f))) (define (process:cmd-run->list cmd #!key (delta-env-alist-or-hash-table '())) (common:with-env-vars delta-env-alist-or-hash-table (lambda () (let* ((fh (open-input-pipe cmd)) (res (port->list fh)) (status (close-input-pipe fh))) (list res status))))) (define (port->list fh) (if (eof-object? fh) #f (let loop ((curr (read-line fh)) (result '())) (if (not (eof-object? curr)) (loop (read-line fh) (append result (list curr))) |
︙ | ︙ | |||
100 101 102 103 104 105 106 | (loop (let ((l (read-line fh))) (if (eof-object? l) l (proc l))) (append result (list curr))) result)))) ;; here is an example line where the shell is sh or bash ;; "find / -print 2&>1 > findall.log" | | > | > > > > > > > | | 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 | (loop (let ((l (read-line fh))) (if (eof-object? l) l (proc l))) (append result (list curr))) result)))) ;; here is an example line where the shell is sh or bash ;; "find / -print 2&>1 > findall.log" (define (run-n-wait cmdline #!key (params #f)(print-cmd #f)(run-dir #f)) (if print-cmd (debug:print 0 *default-log-port* (if (string? print-cmd) print-cmd "") (if run-dir (conc "Run in " run-dir ";") "") cmdline (if params (conc " " (string-intersperse params " ")) ""))) (if (and run-dir (directory-exists? run-dir)) (push-directory run-dir)) (let ((pid (if params (process-run cmdline params) (process-run cmdline)))) (let loop ((i 0)) (let-values (((pid-val exit-status exit-code) (process-wait pid #t))) (if (eq? pid-val 0) (begin (thread-sleep! 2) (loop (+ i 1))) (begin (if (and run-dir (directory-exists? run-dir)) (pop-directory)) (values pid-val exit-status exit-code))))))) ;;====================================================================== ;; MISC PROCESS RELATED STUFF ;;====================================================================== (define (process:children proc) (with-input-from-pipe |
︙ | ︙ | |||
141 142 143 144 145 146 147 | (if proc (proc pid)) (loop (read-line) (cons pid res)))))))) (define (process:alive? pid) (handle-exceptions exn ;; possibly pid is a process not a child, look in /proc to see if it is running still | | | 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 | (if proc (proc pid)) (loop (read-line) (cons pid res)))))))) (define (process:alive? pid) (handle-exceptions exn ;; possibly pid is a process not a child, look in /proc to see if it is running still (common:file-exists? (conc "/proc/" pid)) (let-values (((rpid exit-type exit-signal)(process-wait pid #t))) (and (number? rpid) (equal? rpid pid))))) (define (process:alive-on-host? host pid) (let ((cmd (conc "ssh " host " ps -o pid= -p " pid))) (handle-exceptions |
︙ | ︙ |
Modified records-vs-vectors-vs-coops.scm from [93fa590917] to [a207631458].
1 2 3 4 5 6 7 | ;; (include "vg.scm") ;; (declare (uses vg)) (use foof-loop defstruct coops) (defstruct obj type fill-color angle) | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | ;; Copyright 2006-2017, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. ;; (include "vg.scm") ;; (declare (uses vg)) (use foof-loop defstruct coops) (defstruct obj type fill-color angle) |
︙ | ︙ |
Modified records.sh from [97305b1392] to [abe356c38c].
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | #! /bin/bash # extents caches extents calculated on draw # proc is called on draw and takes the obj itself as a parameter # attrib is an alist of parameters # libs: hash of name->lib, insts: hash of instname->inst # # Add -safe when doing development # export MODE='-safe' (echo ";; Created by records.sh. DO NOT EDIT THIS FILE. Edit records.sh instead" make-vector-record $MODE vg lib comps make-vector-record $MODE vg comp objs name file make-vector-record $MODE vg obj type pts fill-color text line-color call-back angle font attrib extents proc make-vector-record $MODE vg inst libname compname theta xoff yoff scalex scaley mirrx mirry call-back cache make-vector-record $MODE vg drawing libs insts scalex scaley xoff yoff cnv cache ) > vg_records.scm | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | #! /bin/bash # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. # extents caches extents calculated on draw # proc is called on draw and takes the obj itself as a parameter # attrib is an alist of parameters # libs: hash of name->lib, insts: hash of instname->inst # # Add -safe when doing development # export MODE='-safe' (echo ";; Created by records.sh. DO NOT EDIT THIS FILE. Edit records.sh instead" echo <<EOF ;; Copyright 2006-2017, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. ;; EOF make-vector-record $MODE vg lib comps make-vector-record $MODE vg comp objs name file make-vector-record $MODE vg obj type pts fill-color text line-color call-back angle font attrib extents proc make-vector-record $MODE vg inst libname compname theta xoff yoff scalex scaley mirrx mirry call-back cache make-vector-record $MODE vg drawing libs insts scalex scaley xoff yoff cnv cache ) > vg_records.scm |
Deleted remotediff-nmsg.scm version [50100144d4].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Modified rmt.scm from [2cee428d81] to [e52432dc0d].
1 2 3 | ;;====================================================================== ;; Copyright 2006-2017, Matthew Welland. ;; | | | > > > > > | | > | > > > < < > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | ;;====================================================================== ;; Copyright 2006-2017, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. ;; ;;====================================================================== (use format typed-records) ;; RADT => purpose of json format?? (declare (unit rmt)) (declare (uses api)) (declare (uses http-transport)) (include "common_records.scm") ;; (declare (uses rmtmod)) ;; (import rmtmod) ;; ;; THESE ARE ALL CALLED ON THE CLIENT SIDE!!! ;; ;; generate entries for ~/.megatestrc with the following ;; |
︙ | ︙ | |||
46 47 48 49 50 51 52 53 54 | (define *send-receive-mutex* (make-mutex)) ;; should have separate mutex per run-id ;; RA => e.g. usage (rmt:send-receive 'get-var #f (list varname)) ;; (define (rmt:send-receive cmd rid params #!key (attemptnum 1)(area-dat #f)) ;; start attemptnum at 1 so the modulo below works as expected ;; do all the prep locked under the rmt-mutex (mutex-lock! *rmt-mutex*) | > > > > > > > > > > > > > > > > > > > > > | > | < < < < < < < < < < > > > | | | | | > > > > | | | | | | > > | | | > > > | | > > > | < < < < | | > > > > > > | | > > > > > > > | | | | > > > > | > > > | | > > > | | | | | | > > > | < > > > > | > > > > > > | > > > > | | | | | | > > > > > > > | | | | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > | | > | < > > > > > | | | < < < < < < < < < < < < > > | < < | < | < | 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 | (define *send-receive-mutex* (make-mutex)) ;; should have separate mutex per run-id ;; RA => e.g. usage (rmt:send-receive 'get-var #f (list varname)) ;; (define (rmt:send-receive cmd rid params #!key (attemptnum 1)(area-dat #f)) ;; start attemptnum at 1 so the modulo below works as expected #;(common:telemetry-log (conc "rmt:"(->string cmd)) payload: `((rid . ,rid) (params . ,params))) (if (> attemptnum 2) (debug:print 0 *default-log-port* "INFO: attemptnum in rmt:send-receive is " attemptnum)) (cond ((> attemptnum 2) (thread-sleep! 0.05)) ((> attemptnum 10) (thread-sleep! 0.5)) ((> attemptnum 20) (thread-sleep! 1))) (if (and (> attemptnum 5) (= 0 (modulo attemptnum 15))) (begin (server:run *toppath*) (thread-sleep! 3))) ;;DOT digraph megatest_state_status { ;;DOT ranksep=0; ;;DOT // rankdir=LR; ;;DOT node [shape="box"]; ;;DOT "rmt:send-receive" -> MUTEXLOCK; ;;DOT { edge [style=invis];"case 1" -> "case 2" -> "case 3" -> "case 4" -> "case 5" -> "case 6" -> "case 7" -> "case 8" -> "case 9" -> "case 10" -> "case 11"; } ;; do all the prep locked under the rmt-mutex (mutex-lock! *rmt-mutex*) ;; 1. check if server is started IFF cmd is a write OR if we are not on the homehost, store in runremote ;; 2. check the age of the connections. refresh the connection if it is older than timeout-20 seconds. ;; 3. do the query, if on homehost use local access ;; (let* ((start-time (current-seconds)) ;; snapshot time so all use cases get same value (areapath *toppath*);; TODO - resolve from dbstruct to be compatible with multiple areas (runremote (or area-dat *runremote*)) (attemptnum (+ 1 attemptnum)) (readonly-mode (rmtmod:calc-ro-mode runremote *toppath*))) ;; DOT INIT_RUNREMOTE; // leaving off - doesn't really add to the clarity ;; DOT MUTEXLOCK -> INIT_RUNREMOTE [label="no remote?"]; ;; DOT INIT_RUNREMOTE -> MUTEXLOCK; ;; ensure we have a record for our connection for given area (if (not runremote) ;; can remove this one. should never get here. (begin (set! *runremote* (make-remote)) (set! runremote *runremote*))) ;; new runremote will come from this on next iteration ;; DOT SET_HOMEHOST; // leaving off - doesn't really add to the clarity ;; DOT MUTEXLOCK -> SET_HOMEHOST [label="no homehost?"]; ;; DOT SET_HOMEHOST -> MUTEXLOCK; ;; ensure we have a homehost record (if (not (pair? (remote-hh-dat runremote))) ;; not on homehost (thread-sleep! 0.1) ;; since we shouldn't get here, delay a little (remote-hh-dat-set! runremote (common:get-homehost))) ;;(print "BB> readonly-mode is "readonly-mode" dbfile is "dbfile) (cond ;;DOT EXIT; ;;DOT MUTEXLOCK -> EXIT [label="> 15 attempts"]; {rank=same "case 1" "EXIT" } ;; give up if more than 150 attempts ((> attemptnum 150) (debug:print 0 *default-log-port* "ERROR: 150 tries to start/connect to server. Giving up.") (exit 1)) ;;DOT CASE2 [label="local\nreadonly\nquery"]; ;;DOT MUTEXLOCK -> CASE2; {rank=same "case 2" CASE2} ;;DOT CASE2 -> "rmt:open-qry-close-locally"; ;; readonly mode, read request- handle it - case 2 ((and readonly-mode (member cmd api:read-only-queries)) (mutex-unlock! *rmt-mutex*) (debug:print-info 12 *default-log-port* "rmt:send-receive, case 2") (rmt:open-qry-close-locally cmd 0 params) ) ;;DOT CASE3 [label="write in\nread-only mode"]; ;;DOT MUTEXLOCK -> CASE3 [label="readonly\nmode?"]; {rank=same "case 3" CASE3} ;;DOT CASE3 -> "#f"; ;; readonly mode, write request. Do nothing, return #f (readonly-mode (extras-readonly-mode *rmt-mutex* *default-log-port* cmd params)) ;; This block was for pre-emptively resetting the connection if there had been no communication for some time. ;; I don't think it adds any value. If the server is not there, just fail and start a new connection. ;; also, the expire-time calculation might not be correct. We want, time-since-last-server-access > (server:get-timeout) ;; ;;DOT CASE4 [label="reset\nconnection"]; ;;DOT MUTEXLOCK -> CASE4 [label="have connection,\nlast_access > expire_time"]; {rank=same "case 4" CASE4} ;;DOT CASE4 -> "rmt:send-receive"; ;; reset the connection if it has been unused too long ((and runremote (remote-conndat runremote) (> (current-seconds) ;; if it has been more than server-timeout seconds since last contact, close this connection and start a new on (+ (http-transport:server-dat-get-last-access (remote-conndat runremote)) (remote-server-timeout runremote)))) (debug:print-info 0 *default-log-port* "Connection to " (remote-server-url runremote) " expired due to no accesses, forcing new connection.") (http-transport:close-connections area-dat: runremote) (remote-conndat-set! runremote #f) ;; invalidate the connection, thus forcing a new connection. (mutex-unlock! *rmt-mutex*) (rmt:send-receive cmd rid params attemptnum: attemptnum)) ;;DOT CASE5 [label="local\nread"]; ;;DOT MUTEXLOCK -> CASE5 [label="server not required,\non homehost,\nread-only query"]; {rank=same "case 5" CASE5}; ;;DOT CASE5 -> "rmt:open-qry-close-locally"; ;; on homehost and this is a read ((and (not (remote-force-server runremote)) ;; honor forced use of server, i.e. server NOT required (cdr (remote-hh-dat runremote)) ;; on homehost (member cmd api:read-only-queries)) ;; this is a read (mutex-unlock! *rmt-mutex*) (debug:print-info 12 *default-log-port* "rmt:send-receive, case 5") (rmt:open-qry-close-locally cmd 0 params)) ;;DOT CASE6 [label="init\nremote"]; ;;DOT MUTEXLOCK -> CASE6 [label="on homehost,\nwrite query,\nhave server,\ncan't reach it"]; {rank=same "case 6" CASE6}; ;;DOT CASE6 -> "rmt:send-receive"; ;; on homehost and this is a write, we already have a server, but server has died ((and (cdr (remote-hh-dat runremote)) ;; on homehost (not (member cmd api:read-only-queries)) ;; this is a write (remote-server-url runremote) ;; have a server (not (server:ping (remote-server-url runremote)))) ;; server has died. NOTE: this is not a cheap call! Need better approach. (set! *runremote* (make-remote)) (remote-force-server-set! runremote (common:force-server?)) (mutex-unlock! *rmt-mutex*) (debug:print-info 12 *default-log-port* "rmt:send-receive, case 6") (rmt:send-receive cmd rid params attemptnum: attemptnum)) ;;DOT CASE7 [label="homehost\nwrite"]; ;;DOT MUTEXLOCK -> CASE7 [label="server not required,\non homehost,\na write,\nhave a server"]; {rank=same "case 7" CASE7}; ;;DOT CASE7 -> "rmt:open-qry-close-locally"; ;; on homehost and this is a write, we already have a server ((and (not (remote-force-server runremote)) ;; honor forced use of server, i.e. server NOT required (cdr (remote-hh-dat runremote)) ;; on homehost (not (member cmd api:read-only-queries)) ;; this is a write (remote-server-url runremote)) ;; have a server (mutex-unlock! *rmt-mutex*) (debug:print-info 12 *default-log-port* "rmt:send-receive, case 4.1") (rmt:open-qry-close-locally cmd 0 params)) ;;DOT CASE8 [label="force\nserver"]; ;;DOT MUTEXLOCK -> CASE8 [label="server not required,\nhave homehost info,\nno connection yet,\nnot a read-only query"]; {rank=same "case 8" CASE8}; ;;DOT CASE8 -> "rmt:open-qry-close-locally"; ;; on homehost, no server contact made and this is a write, passively start a server ((and (not (remote-force-server runremote)) ;; honor forced use of server, i.e. server NOT required (cdr (remote-hh-dat runremote)) ;; have homehost (not (remote-server-url runremote)) ;; no connection yet (not (member cmd api:read-only-queries))) ;; not a read-only query (debug:print-info 12 *default-log-port* "rmt:send-receive, case 8") (let ((server-url (server:check-if-running *toppath*))) ;; (server:read-dotserver->url *toppath*))) ;; (server:check-if-running *toppath*))) ;; Do NOT want to run server:check-if-running - very expensive to do for every write call (if server-url (remote-server-url-set! runremote server-url) ;; the string can be consumed by the client setup if needed (if (common:force-server?) (server:start-and-wait *toppath*) (server:kind-run *toppath*)))) (remote-force-server-set! runremote (common:force-server?)) (mutex-unlock! *rmt-mutex*) (debug:print-info 12 *default-log-port* "rmt:send-receive, case 8.1") (rmt:open-qry-close-locally cmd 0 params)) ;;DOT CASE9 [label="force server\nnot on homehost"]; ;;DOT MUTEXLOCK -> CASE9 [label="no connection\nand either require server\nor not on homehost"]; {rank=same "case 9" CASE9}; ;;DOT CASE9 -> "start\nserver" -> "rmt:send-receive"; ((or (and (remote-force-server runremote) ;; we are forcing a server and don't yet have a connection to one (not (remote-conndat runremote))) (and (not (cdr (remote-hh-dat runremote))) ;; not on a homehost (not (remote-conndat runremote)))) ;; and no connection (debug:print-info 12 *default-log-port* "rmt:send-receive, case 9, hh-dat: " (remote-hh-dat runremote) " conndat: " (remote-conndat runremote)) (mutex-unlock! *rmt-mutex*) (if (not (server:check-if-running *toppath*)) ;; who knows, maybe one has started up? (server:start-and-wait *toppath*)) (remote-conndat-set! runremote (rmt:get-connection-info *toppath*)) ;; calls client:setup which calls client:setup-http (rmt:send-receive cmd rid params attemptnum: attemptnum)) ;; TODO: add back-off timeout as ;;DOT CASE10 [label="on homehost"]; ;;DOT MUTEXLOCK -> CASE10 [label="server not required,\non homehost"]; {rank=same "case 10" CASE10}; ;;DOT CASE10 -> "rmt:open-qry-close-locally"; ;; all set up if get this far, dispatch the query ((and (not (remote-force-server runremote)) (cdr (remote-hh-dat runremote))) ;; we are on homehost (mutex-unlock! *rmt-mutex*) (debug:print-info 12 *default-log-port* "rmt:send-receive, case 10") (rmt:open-qry-close-locally cmd (if rid rid 0) params)) ;;DOT CASE11 [label="send_receive"]; ;;DOT MUTEXLOCK -> CASE11 [label="else"]; {rank=same "case 11" CASE11}; ;;DOT CASE11 -> "rmt:send-receive" [label="call failed"]; ;;DOT CASE11 -> "RESULT" [label="call succeeded"]; ;; not on homehost, do server query (else (extras-case-11 *default-log-port* runremote cmd params attemptnum rid))))) ;;DOT } ;; bunch of small functions factored out of send-receive to make debug easier ;; (define (extras-case-11 *default-log-port* runremote cmd params attemptnum rid) ;; (mutex-unlock! *rmt-mutex*) (debug:print-info 12 *default-log-port* "rmt:send-receive, case 9") ;; (mutex-lock! *rmt-mutex*) (let* ((conninfo (remote-conndat runremote)) (dat-in (case (remote-transport runremote) ((http) (condition-case ;; handling here has ;; caused a lot of ;; problems. However it ;; is needed to deal with ;; attemtped ;; communication to ;; servers that have gone ;; away (http-transport:client-api-send-receive 0 conninfo cmd params) ((commfail)(vector #f "communications fail")) ((exn)(vector #f "other fail" (print-call-chain))))) (else (debug:print 0 *default-log-port* "ERROR: transport " (remote-transport runremote) " not supported") (exit)))) ;; No Title ;; Error: (vector-ref) out of range ;; #(#<condition: (exn type)> (#("db.scm:3740: regex#regexp" #f #f) #("db.scm:3739: regex#string-substitute" #f #f) #("db.scm:3738: base64#base64-decode" #f #f) #("db.scm:3737: z3#z3:decode-buffer" #f #f) #("db.scm:3736: with-input-from-string" #f #f) #("db.scm:3741: s11n#deserialize" #f #f) #("api.scm:374: api:execute-requests" #f #f) #("api.scm:139: call-with-current-continuation" #f #f) #("api.scm:139: with-exception-handler" #f #f) #("api.scm:139: ##sys#call-with-values" #f #f) #("api.scm:158: string->symbol" #f #f) #("api.scm:160: current-milliseconds" #f #f) #("api.scm:161: dbr:dbstruct-read-only" #f #f) #("api.scm:139: k15" #f #f) #("api.scm:139: g19" #f #f) #("api.scm:142: get-call-chain" #f #f)) #("get-test-info-by-id" (1102 507299))) ;; 6 ;; ;; Call history: ;; ;; http-transport.scm:306: thread-terminate! ;; http-transport.scm:307: debug:print-info ;; common_records.scm:235: debug:debug-mode ;; rmt.scm:259: k587 ;; rmt.scm:259: g591 ;; rmt.scm:276: http-transport:server-dat-update-last-access ;; http-transport.scm:364: current-seconds ;; rmt.scm:282: debug:print-info ;; common_records.scm:235: debug:debug-mode ;; rmt.scm:283: mutex-unlock! ;; rmt.scm:287: extras-transport-succeded <-- ;; +-----------------------------------------------------------------------------+ ;; | Exit Status : 70 ;; (dat (if (and (vector? dat-in) ;; ... check it is a correct size (> (vector-length dat-in) 1)) dat-in (vector #f (conc "communications fail (type 2), dat-in=" dat-in)))) (success (if (vector? dat) (vector-ref dat 0) #f)) (res (if (vector? dat) (vector-ref dat 1) #f))) (if (and (vector? conninfo) (< 5 (vector-length conninfo))) (http-transport:server-dat-update-last-access conninfo) ;; refresh access time (begin (debug:print 0 *default-log-port* "INFO: Should not get here! conninfo=" conninfo) (set! conninfo #f) (remote-conndat-set! *runremote* #f) ;; NOTE: *runremote* is global copy of runremote. Purpose: factor out global. (http-transport:close-connections area-dat: runremote))) (debug:print-info 13 *default-log-port* "rmt:send-receive, case 9. conninfo=" conninfo " dat=" dat " runremote = " runremote) (mutex-unlock! *rmt-mutex*) (if success ;; success only tells us that the transport was ;; successful, have to examine the data to see if ;; there was a detected issue at the other end (extras-transport-succeded *default-log-port* *rmt-mutex* attemptnum runremote res params rid cmd) (extras-transport-failed *default-log-port* *rmt-mutex* attemptnum runremote cmd rid params) ))) ;; (define (rmt:update-db-stats run-id rawcmd params duration) ;; (mutex-lock! *db-stats-mutex*) ;; (handle-exceptions ;; exn ;; (begin ;; (debug:print 0 *default-log-port* "WARNING: stats collection failed in update-db-stats") |
︙ | ︙ | |||
273 274 275 276 277 278 279 | (loop (car tal)(cdr tal) newmax-cmd currmax))))))) (mutex-unlock! *db-stats-mutex*) res)) (define (rmt:open-qry-close-locally cmd run-id params #!key (remretries 5)) (let* ((qry-is-write (not (member cmd api:read-only-queries))) (db-file-path (db:dbfile-path)) ;; 0)) | | | | 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 | (loop (car tal)(cdr tal) newmax-cmd currmax))))))) (mutex-unlock! *db-stats-mutex*) res)) (define (rmt:open-qry-close-locally cmd run-id params #!key (remretries 5)) (let* ((qry-is-write (not (member cmd api:read-only-queries))) (db-file-path (db:dbfile-path)) ;; 0)) (dbstruct-local (db:setup #t)) ;; make-dbr:dbstruct path: dbdir local: #t))) (read-only (not (file-write-access? db-file-path))) (start (current-milliseconds)) (resdat (if (not (and read-only qry-is-write)) (let ((v (api:execute-requests dbstruct-local (vector (symbol->string cmd) params)))) (handle-exceptions ;; there has been a long history of receiving strange errors from values returned by the client when things go wrong.. exn ;; This is an attempt to detect that situation and recover gracefully (begin (debug:print 0 *default-log-port* "ERROR: bad data from server " v " message: " ((condition-property-accessor 'exn 'message) exn)) (vector #t '())) ;; should always get a vector but if something goes wrong return a dummy (if (and (vector? v) (> (vector-length v) 1)) (let ((newvec (vector (vector-ref v 0)(vector-ref v 1)))) newvec) ;; by copying the vector while inside the error handler we should force the detection of a corrupted record (vector #t '())))) ;; we could also check that the returned types are valid (vector #t '()))) |
︙ | ︙ | |||
388 389 390 391 392 393 394 395 396 397 398 399 400 401 | ;; add caching if qry is 'getid or 'getstr (rmt:send-receive 'sdb-qry run-id (list qry val))) ;; NOT COMPLETED (define (rmt:runtests user run-id testpatt params) (rmt:send-receive 'runtests run-id testpatt)) (define (rmt:get-changed-record-ids since-time) (rmt:send-receive 'get-changed-record-ids #f (list since-time)) ) ;;====================================================================== ;; T E S T M E T A ;;====================================================================== | > > > | 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 | ;; add caching if qry is 'getid or 'getstr (rmt:send-receive 'sdb-qry run-id (list qry val))) ;; NOT COMPLETED (define (rmt:runtests user run-id testpatt params) (rmt:send-receive 'runtests run-id testpatt)) (define (rmt:get-run-record-ids target run keynames test-patt) (rmt:send-receive 'get-run-record-ids #f (list target run keynames test-patt))) (define (rmt:get-changed-record-ids since-time) (rmt:send-receive 'get-changed-record-ids #f (list since-time)) ) ;;====================================================================== ;; T E S T M E T A ;;====================================================================== |
︙ | ︙ | |||
432 433 434 435 436 437 438 439 440 441 442 443 444 445 | res))) (define (rmt:get-targets) (rmt:send-receive 'get-targets #f '())) (define (rmt:get-target run-id) (rmt:send-receive 'get-target run-id (list run-id))) ;;====================================================================== ;; T E S T S ;;====================================================================== ;; Just some syntatic sugar (define (rmt:register-test run-id test-name item-path) | > > > > | 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 | res))) (define (rmt:get-targets) (rmt:send-receive 'get-targets #f '())) (define (rmt:get-target run-id) (rmt:send-receive 'get-target run-id (list run-id))) (define (rmt:get-run-times runpatt targetpatt) (rmt:send-receive 'get-run-times #f (list runpatt targetpatt ))) ;;====================================================================== ;; T E S T S ;;====================================================================== ;; Just some syntatic sugar (define (rmt:register-test run-id test-name item-path) |
︙ | ︙ | |||
472 473 474 475 476 477 478 | (define (rmt:test-set-state-status-by-id run-id test-id newstate newstatus newcomment) (rmt:send-receive 'test-set-state-status-by-id run-id (list run-id test-id newstate newstatus newcomment))) (define (rmt:set-tests-state-status run-id testnames currstate currstatus newstate newstatus) (rmt:send-receive 'set-tests-state-status run-id (list run-id testnames currstate currstatus newstate newstatus))) (define (rmt:get-tests-for-run run-id testpatt states statuses offset limit not-in sort-by sort-order qryvals last-update mode) | | | | | | | > > > | 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 | (define (rmt:test-set-state-status-by-id run-id test-id newstate newstatus newcomment) (rmt:send-receive 'test-set-state-status-by-id run-id (list run-id test-id newstate newstatus newcomment))) (define (rmt:set-tests-state-status run-id testnames currstate currstatus newstate newstatus) (rmt:send-receive 'set-tests-state-status run-id (list run-id testnames currstate currstatus newstate newstatus))) (define (rmt:get-tests-for-run run-id testpatt states statuses offset limit not-in sort-by sort-order qryvals last-update mode) ;; (if (number? run-id) (rmt:send-receive 'get-tests-for-run run-id (list run-id testpatt states statuses offset limit not-in sort-by sort-order qryvals last-update mode))) ;; (begin ;; (debug:print-error 0 *default-log-port* "rmt:get-tests-for-run called with bad run-id=" run-id) ;; (print-call-chain (current-error-port)) ;; '()))) ;; get stuff via synchash (define (rmt:synchash-get run-id proc synckey keynum params) (rmt:send-receive 'synchash-get run-id (list run-id proc synckey keynum params))) (define (rmt:get-tests-for-run-mindata run-id testpatt states status not-in) (rmt:send-receive 'get-tests-for-run-mindata run-id (list run-id testpatt states status not-in))) ;; IDEA: Threadify these - they spend a lot of time waiting ... ;; (define (rmt:get-tests-for-runs-mindata run-ids testpatt states status not-in) (let ((multi-run-mutex (make-mutex)) (run-id-list (if run-ids run-ids (rmt:get-all-run-ids))) |
︙ | ︙ | |||
584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 | ;; (rmt:send-receive #f 'get-run-ids-matching (list keynames target res))) (define (rmt:get-prereqs-not-met run-id waitons ref-test-name ref-item-path #!key (mode '(normal))(itemmaps #f)) (rmt:send-receive 'get-prereqs-not-met run-id (list run-id waitons ref-test-name ref-item-path mode itemmaps))) (define (rmt:get-count-tests-running-for-run-id run-id) (rmt:send-receive 'get-count-tests-running-for-run-id run-id (list run-id))) ;; Statistical queries (define (rmt:get-count-tests-running run-id) (rmt:send-receive 'get-count-tests-running run-id (list run-id))) (define (rmt:get-count-tests-running-for-testname run-id testname) (rmt:send-receive 'get-count-tests-running-for-testname run-id (list run-id testname))) (define (rmt:get-count-tests-running-in-jobgroup run-id jobgroup) (rmt:send-receive 'get-count-tests-running-in-jobgroup run-id (list run-id jobgroup))) ;; state and status are extra hints not usually used in the calculation ;; (define (rmt:set-state-status-and-roll-up-items run-id test-name item-path state status comment) (rmt:send-receive 'set-state-status-and-roll-up-items run-id (list run-id test-name item-path state status comment))) (define (rmt:update-pass-fail-counts run-id test-name) (rmt:general-call 'update-pass-fail-counts run-id test-name test-name test-name)) (define (rmt:top-test-set-per-pf-counts run-id test-name) (rmt:send-receive 'top-test-set-per-pf-counts run-id (list run-id test-name))) (define (rmt:get-raw-run-stats run-id) (rmt:send-receive 'get-raw-run-stats run-id (list run-id))) ;;====================================================================== ;; R U N S ;;====================================================================== (define (rmt:get-run-info run-id) (rmt:send-receive 'get-run-info run-id (list run-id))) (define (rmt:get-num-runs runpatt) (rmt:send-receive 'get-num-runs #f (list runpatt))) ;; Use the special run-id == #f scenario here since there is no run yet (define (rmt:register-run keyvals runname state status user contour) (rmt:send-receive 'register-run #f (list keyvals runname state status user contour))) (define (rmt:get-run-name-from-id run-id) (rmt:send-receive 'get-run-name-from-id run-id (list run-id))) (define (rmt:delete-run run-id) (rmt:send-receive 'delete-run run-id (list run-id))) (define (rmt:update-run-stats run-id stats) (rmt:send-receive 'update-run-stats #f (list run-id stats))) (define (rmt:delete-old-deleted-test-records) (rmt:send-receive 'delete-old-deleted-test-records #f '())) (define (rmt:get-runs runpatt count offset keypatts) (rmt:send-receive 'get-runs #f (list runpatt count offset keypatts))) (define (rmt:get-all-run-ids) (rmt:send-receive 'get-all-run-ids #f '())) (define (rmt:get-prev-run-ids run-id) (rmt:send-receive 'get-prev-run-ids #f (list run-id))) (define (rmt:lock/unlock-run run-id lock unlock user) (rmt:send-receive 'lock/unlock-run #f (list run-id lock unlock user))) ;; set/get status (define (rmt:get-run-status run-id) (rmt:send-receive 'get-run-status #f (list run-id))) (define (rmt:set-run-status run-id run-status #!key (msg #f)) (rmt:send-receive 'set-run-status #f (list run-id run-status msg))) (define (rmt:update-run-event_time run-id) (rmt:send-receive 'update-run-event_time #f (list run-id))) | > > > > > > > > > > > > > > > > > > > > > > > > > | | | 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 | ;; (rmt:send-receive #f 'get-run-ids-matching (list keynames target res))) (define (rmt:get-prereqs-not-met run-id waitons ref-test-name ref-item-path #!key (mode '(normal))(itemmaps #f)) (rmt:send-receive 'get-prereqs-not-met run-id (list run-id waitons ref-test-name ref-item-path mode itemmaps))) (define (rmt:get-count-tests-running-for-run-id run-id) (rmt:send-receive 'get-count-tests-running-for-run-id run-id (list run-id))) (define (rmt:get-not-completed-cnt run-id) (rmt:send-receive 'get-not-completed-cnt run-id (list run-id))) ;; Statistical queries (define (rmt:get-count-tests-running run-id) (rmt:send-receive 'get-count-tests-running run-id (list run-id))) (define (rmt:get-count-tests-running-for-testname run-id testname) (rmt:send-receive 'get-count-tests-running-for-testname run-id (list run-id testname))) (define (rmt:get-count-tests-running-in-jobgroup run-id jobgroup) (rmt:send-receive 'get-count-tests-running-in-jobgroup run-id (list run-id jobgroup))) ;; state and status are extra hints not usually used in the calculation ;; (define (rmt:set-state-status-and-roll-up-items run-id test-name item-path state status comment) (rmt:send-receive 'set-state-status-and-roll-up-items run-id (list run-id test-name item-path state status comment))) (define (rmt:set-state-status-and-roll-up-run run-id state status) (rmt:send-receive 'set-state-status-and-roll-up-run run-id (list run-id state status))) (define (rmt:update-pass-fail-counts run-id test-name) (rmt:general-call 'update-pass-fail-counts run-id test-name test-name test-name)) (define (rmt:top-test-set-per-pf-counts run-id test-name) (rmt:send-receive 'top-test-set-per-pf-counts run-id (list run-id test-name))) (define (rmt:get-raw-run-stats run-id) (rmt:send-receive 'get-raw-run-stats run-id (list run-id))) (define (rmt:get-test-times runname target) (rmt:send-receive 'get-test-times #f (list runname target ))) ;;====================================================================== ;; R U N S ;;====================================================================== (define (rmt:get-run-info run-id) (rmt:send-receive 'get-run-info run-id (list run-id))) (define (rmt:get-num-runs runpatt) (rmt:send-receive 'get-num-runs #f (list runpatt))) (define (rmt:get-runs-cnt-by-patt runpatt targetpatt keys) (rmt:send-receive 'get-runs-cnt-by-patt #f (list runpatt targetpatt keys))) ;; Use the special run-id == #f scenario here since there is no run yet (define (rmt:register-run keyvals runname state status user contour) (rmt:send-receive 'register-run #f (list keyvals runname state status user contour))) (define (rmt:get-run-name-from-id run-id) (rmt:send-receive 'get-run-name-from-id run-id (list run-id))) (define (rmt:delete-run run-id) (rmt:send-receive 'delete-run run-id (list run-id))) (define (rmt:update-run-stats run-id stats) (rmt:send-receive 'update-run-stats #f (list run-id stats))) (define (rmt:delete-old-deleted-test-records) (rmt:send-receive 'delete-old-deleted-test-records #f '())) (define (rmt:get-runs runpatt count offset keypatts) (rmt:send-receive 'get-runs #f (list runpatt count offset keypatts))) (define (rmt:simple-get-runs runpatt count offset target) (rmt:send-receive 'simple-get-runs #f (list runpatt count offset target))) (define (rmt:get-all-run-ids) (rmt:send-receive 'get-all-run-ids #f '())) (define (rmt:get-prev-run-ids run-id) (rmt:send-receive 'get-prev-run-ids #f (list run-id))) (define (rmt:lock/unlock-run run-id lock unlock user) (rmt:send-receive 'lock/unlock-run #f (list run-id lock unlock user))) ;; set/get status (define (rmt:get-run-status run-id) (rmt:send-receive 'get-run-status #f (list run-id))) (define (rmt:get-run-state run-id) (rmt:send-receive 'get-run-state #f (list run-id))) (define (rmt:set-run-status run-id run-status #!key (msg #f)) (rmt:send-receive 'set-run-status #f (list run-id run-status msg))) (define (rmt:set-run-state-status run-id state status ) (rmt:send-receive 'set-run-state-status #f (list run-id state status))) (define (rmt:update-run-event_time run-id) (rmt:send-receive 'update-run-event_time #f (list run-id))) (define (rmt:get-runs-by-patt keys runnamepatt targpatt offset limit fields last-runs-update #!key (sort-order "asc")) ;; fields of #f uses default (rmt:send-receive 'get-runs-by-patt #f (list keys runnamepatt targpatt offset limit fields last-runs-update sort-order))) (define (rmt:find-and-mark-incomplete run-id ovr-deadtime) ;; (if (rmt:send-receive 'have-incompletes? run-id (list run-id ovr-deadtime)) (rmt:send-receive 'mark-incomplete run-id (list run-id ovr-deadtime))) ;; ) (define (rmt:get-main-run-stats run-id) (rmt:send-receive 'get-main-run-stats #f (list run-id))) |
︙ | ︙ | |||
744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 | (let* ((state (items:check-valid-items "state" state-in)) (status (items:check-valid-items "status" status-in))) (if (or (not state)(not status)) (debug:print 3 *default-log-port* "WARNING: Invalid " (if status "status" "state") " value \"" (if status state-in status-in) "\", update your validvalues section in megatest.config")) (rmt:send-receive 'teststep-set-status! run-id (list run-id test-id teststep-name state-in status-in comment logfile)))) (define (rmt:get-steps-for-test run-id test-id) (rmt:send-receive 'get-steps-for-test run-id (list run-id test-id))) ;;====================================================================== ;; T E S T D A T A ;;====================================================================== (define (rmt:read-test-data run-id test-id categorypatt #!key (work-area #f)) (rmt:send-receive 'read-test-data run-id (list run-id test-id categorypatt))) | > > > > > > > | < | | > > | 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 | (let* ((state (items:check-valid-items "state" state-in)) (status (items:check-valid-items "status" status-in))) (if (or (not state)(not status)) (debug:print 3 *default-log-port* "WARNING: Invalid " (if status "status" "state") " value \"" (if status state-in status-in) "\", update your validvalues section in megatest.config")) (rmt:send-receive 'teststep-set-status! run-id (list run-id test-id teststep-name state-in status-in comment logfile)))) (define (rmt:delete-steps-for-test! run-id test-id) (rmt:send-receive 'delete-steps-for-test! run-id (list run-id test-id))) (define (rmt:get-steps-for-test run-id test-id) (rmt:send-receive 'get-steps-for-test run-id (list run-id test-id))) (define (rmt:get-steps-info-by-id test-step-id) (rmt:send-receive 'get-steps-info-by-id #f (list test-step-id))) ;;====================================================================== ;; T E S T D A T A ;;====================================================================== (define (rmt:read-test-data run-id test-id categorypatt #!key (work-area #f)) (rmt:send-receive 'read-test-data run-id (list run-id test-id categorypatt))) (define (rmt:read-test-data* run-id test-id categorypatt varpatt #!key (work-area #f)) (rmt:send-receive 'read-test-data* run-id (list run-id test-id categorypatt varpatt))) (define (rmt:get-data-info-by-id test-data-id) (rmt:send-receive 'get-data-info-by-id #f (list test-data-id))) (define (rmt:testmeta-add-record testname) (rmt:send-receive 'testmeta-add-record #f (list testname))) (define (rmt:testmeta-get-record testname) (rmt:send-receive 'testmeta-get-record #f (list testname))) |
︙ | ︙ | |||
788 789 790 791 792 793 794 795 796 797 798 799 800 801 | (rmt:send-receive 'tasks-add #f (list action owner target runname testpatt params))) (define (rmt:tasks-set-state-given-param-key param-key new-state) (rmt:send-receive 'tasks-set-state-given-param-key #f (list param-key new-state))) (define (rmt:tasks-get-last target runname) (rmt:send-receive 'tasks-get-last #f (list target runname))) ;;====================================================================== ;; A R C H I V E S ;;====================================================================== (define (rmt:archive-get-allocations testname itempath dneeded) (rmt:send-receive 'archive-get-allocations #f (list testname itempath dneeded))) | > > > > > > > > > > > > > > > > | 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 | (rmt:send-receive 'tasks-add #f (list action owner target runname testpatt params))) (define (rmt:tasks-set-state-given-param-key param-key new-state) (rmt:send-receive 'tasks-set-state-given-param-key #f (list param-key new-state))) (define (rmt:tasks-get-last target runname) (rmt:send-receive 'tasks-get-last #f (list target runname))) ;;====================================================================== ;; N O S Y N C D B ;;====================================================================== (define (rmt:no-sync-set var val) (rmt:send-receive 'no-sync-set #f `(,var ,val))) (define (rmt:no-sync-get/default var default) (rmt:send-receive 'no-sync-get/default #f `(,var ,default))) (define (rmt:no-sync-del! var) (rmt:send-receive 'no-sync-del! #f `(,var))) (define (rmt:no-sync-get-lock keyname) (rmt:send-receive 'no-sync-get-lock #f `(,keyname))) ;;====================================================================== ;; A R C H I V E S ;;====================================================================== (define (rmt:archive-get-allocations testname itempath dneeded) (rmt:send-receive 'archive-get-allocations #f (list testname itempath dneeded))) |
︙ | ︙ | |||
810 811 812 813 814 815 816 | (rmt:send-receive 'archive-register-disk #f (list bdisk-name bdisk-path df))) (define (rmt:test-set-archive-block-id run-id test-id archive-block-id) (rmt:send-receive 'test-set-archive-block-id run-id (list run-id test-id archive-block-id))) (define (rmt:test-get-archive-block-info archive-block-id) (rmt:send-receive 'test-get-archive-block-info #f (list archive-block-id))) | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 | (rmt:send-receive 'archive-register-disk #f (list bdisk-name bdisk-path df))) (define (rmt:test-set-archive-block-id run-id test-id archive-block-id) (rmt:send-receive 'test-set-archive-block-id run-id (list run-id test-id archive-block-id))) (define (rmt:test-get-archive-block-info archive-block-id) (rmt:send-receive 'test-get-archive-block-info #f (list archive-block-id))) (define (rmtmod:calc-ro-mode runremote *toppath*) (if (and runremote (remote-ro-mode-checked runremote)) (remote-ro-mode runremote) (let* ((dbfile (conc *toppath* "/megatest.db")) (ro-mode (not (file-write-access? dbfile)))) ;; TODO: use dbstruct or runremote to figure this out in future (if runremote (begin (remote-ro-mode-set! runremote ro-mode) (remote-ro-mode-checked-set! runremote #t) ro-mode) ro-mode)))) (define (extras-readonly-mode rmt-mutex log-port cmd params) (mutex-unlock! rmt-mutex) (debug:print-info 12 log-port "rmt:send-receive, case 3") (debug:print 0 log-port "WARNING: write transaction requested on a readonly area. cmd="cmd" params="params) #f) (define (extras-transport-failed *default-log-port* *rmt-mutex* attemptnum runremote cmd rid params) (debug:print 0 *default-log-port* "WARNING: communication failed. Trying again, try num: " attemptnum) (mutex-lock! *rmt-mutex*) (remote-conndat-set! runremote #f) (http-transport:close-connections area-dat: runremote) (remote-server-url-set! runremote #f) (mutex-unlock! *rmt-mutex*) (debug:print-info 12 *default-log-port* "rmt:send-receive, case 9.1") (rmt:send-receive cmd rid params attemptnum: (+ attemptnum 1))) (define (extras-transport-succeded *default-log-port* *rmt-mutex* attemptnum runremote res params rid cmd) (if (and (vector? res) (eq? (vector-length res) 2) (eq? (vector-ref res 1) 'overloaded)) ;; since we are ;; looking at the ;; data to carry the ;; error we'll use a ;; fairly obtuse ;; combo to minimise ;; the chances of ;; some sort of ;; collision. this ;; is the case where ;; the returned data ;; is bad or the ;; server is ;; overloaded and we ;; want to ease off ;; the queries (let ((wait-delay (+ attemptnum (* attemptnum 10)))) (debug:print 0 *default-log-port* "WARNING: server is overloaded. Delaying " wait-delay " seconds and trying call again.") (mutex-lock! *rmt-mutex*) (http-transport:close-connections area-dat: runremote) (set! *runremote* #f) ;; force starting over (mutex-unlock! *rmt-mutex*) (thread-sleep! wait-delay) (rmt:send-receive cmd rid params attemptnum: (+ attemptnum 1))) res)) ;; All good, return res #;(set-functions rmt:send-receive remote-server-url-set! http-transport:close-connections remote-conndat-set! debug:print debug:print-info remote-ro-mode remote-ro-mode-set! remote-ro-mode-checked-set! remote-ro-mode-checked) |
Modified rmtdb.scm from [afdb905959] to [62ddf7898c].
1 2 3 | ;;====================================================================== ;; Copyright 2006-2013, Matthew Welland. ;; | | | > > > > > | | > > > > | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | ;;====================================================================== ;; Copyright 2006-2013, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. ;;====================================================================== |
Added rmtmod.scm version [7098937896].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 | ;;====================================================================== ;; Copyright 2017, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. ;;====================================================================== (declare (unit rmtmod)) (declare (uses commonmod)) (module rmtmod * (import scheme chicken data-structures extras) (import (prefix sqlite3 sqlite3:) posix typed-records srfi-18) (import commonmod) ;; Hack to make these functions visible to the refactored code, goal is to eliminate these over time. (define (rmt:send-receive . params) #f) (define (http-transport:close-connections . params) #f) ;; from remote defstruct in common.scm (define (remote-conndat-set! . params) #f) (define (remote-server-url-set! . params) #f) (define (remote-ro-mode . params) #f) (define (remote-ro-mode-set! . params) #f) (define (remote-ro-mode-checked-set! . params) #f) (define (remote-ro-mode-checked . params) #f) (define (debug:print . params) #f) (define (debug:print-info . params) #f) (define (set-functions send-receive rsus close-connections rcs dbgp dbgpinfo ro-mode ro-mode-set ro-mode-checked-set ro-mode-checked ) (set! rmt:send-receive send-receive) (set! remote-server-url-set! rsus) (set! http-transport:close-connections close-connections) (set! remote-conndat-set! rcs) (set! debug:print dbgp) (set! debug:print-info dbgpinfo) (set! remote-ro-mode ro-mode) (set! remote-ro-mode-set! ro-mode-set) (set! remote-ro-mode-checked-set! ro-mode-checked-set) (set! remote-ro-mode-checked ro-mode-checked)) ) |
Modified rpc-transport.scm from [f2b0cd0198] to [dd887f94ec].
1 2 3 | ;; Copyright 2006-2012, Matthew Welland. ;; | | | > > > > > | | > | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | ;; Copyright 2006-2012, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. ;; (require-extension (srfi 18) extras tcp s11n rpc) (import (prefix rpc rpc:)) (use sqlite3 srfi-1 posix regex regex-case srfi-69 hostinfo md5 message-digest) (import (prefix sqlite3 sqlite3:)) |
︙ | ︙ |
Deleted rpctest/rpctest-continuous-client.scm version [ea7c1d49cf].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted rpctest/rpctest.scm version [900250564a].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted rpctest/run-client.sh version [7217b9abad].
|
| < < < < < < < < < < < < |
Modified run-eff.sql from [a9003b4b84] to [fc1187592b].
1 2 3 4 5 6 7 | .mode col .head on select runs.runname,num_items,printf("%.2f",wall_runtime) AS runtime,printf("%.2f",max_duration) AS duration,ratio,testname from (select run_id, count(id) AS num_items, (max(event_time+run_duration)-min(event_time))/3600.0 AS wall_runtime, max(run_duration)/3600.0 AS max_duration, | > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | -- Copyright 2006-2017, Matthew Welland. -- -- This file is part of Megatest. -- -- Megatest is free software: you can redistribute it and/or modify -- it under the terms of the GNU General Public License as published by -- the Free Software Foundation, either version 3 of the License, or -- (at your option) any later version. -- -- Megatest is distributed in the hope that it will be useful, -- but WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- GNU General Public License for more details. -- -- You should have received a copy of the GNU General Public License -- along with Megatest. If not, see <http://www.gnu.org/licenses/>. .mode col .head on select runs.runname,num_items,printf("%.2f",wall_runtime) AS runtime,printf("%.2f",max_duration) AS duration,ratio,testname from (select run_id, count(id) AS num_items, (max(event_time+run_duration)-min(event_time))/3600.0 AS wall_runtime, max(run_duration)/3600.0 AS max_duration, |
︙ | ︙ |
Deleted run-tests-queue-new.scm version [da39a3ee5e].
Modified run_records.scm from [1580836de1] to [737eaad866].
1 2 3 | ;;====================================================================== ;; Copyright 2006-2012, Matthew Welland. ;; | | | > > > > > | | > | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | ;;====================================================================== ;; Copyright 2006-2012, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. ;; ;;====================================================================== (define-inline (runs:runrec-make-record) (make-vector 13)) (define-inline (runs:runrec-get-target vec)(vector-ref vec 0)) ;; a/b/c (define-inline (runs:runrec-get-runname vec)(vector-ref vec 1)) ;; string (define-inline (runs:runrec-testpatt vec)(vector-ref vec 2)) ;; a,b/c,d% (define-inline (runs:runrec-keys vec)(vector-ref vec 3)) ;; (key1 key2 ...) |
︙ | ︙ |
Modified runconfig.scm from [6eed309bc6] to [66b9c38588].
1 2 3 4 5 6 7 | ;;====================================================================== ;; read a config file, loading only the section pertinent ;; to this run field1val/field2val/field3val ... ;;====================================================================== (use format directory-utils) | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | ;; Copyright 2006-2017, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. ;;====================================================================== ;; read a config file, loading only the section pertinent ;; to this run field1val/field2val/field3val ... ;;====================================================================== (use format directory-utils) |
︙ | ︙ | |||
71 72 73 74 75 76 77 | (define (set-run-config-vars run-id keyvals targ-from-db) (push-directory *toppath*) ;; the push/pop doesn't appear to do anything ... (let ((runconfigf (conc *toppath* "/runconfigs.config")) (targ (or (common:args-get-target) targ-from-db (get-environment-variable "MT_TARGET")))) (pop-directory) | | | 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 | (define (set-run-config-vars run-id keyvals targ-from-db) (push-directory *toppath*) ;; the push/pop doesn't appear to do anything ... (let ((runconfigf (conc *toppath* "/runconfigs.config")) (targ (or (common:args-get-target) targ-from-db (get-environment-variable "MT_TARGET")))) (pop-directory) (if (common:file-exists? runconfigf) (setup-env-defaults runconfigf run-id #t keyvals environ-patt: (conc "(default" (if targ (conc "|" targ ")") ")"))) (debug:print 0 *default-log-port* "WARNING: You do not have a run config file: " runconfigf)))) |
︙ | ︙ |
Modified runconfigs.config from [cd844a0844] to [11408e1be1].
1 2 3 4 5 6 7 8 9 10 | # To get emacs font highlighing in the various megatest configs do this: # # Install emacs-goodies-el: # sudo apt install emacs-goodies-el # Add to your ~/.emacs file: # (add-to-list 'auto-mode-alist '("config\\'" . conf-space-mode)) # # example of a cron entry to run sync using db spec pgdb, with pgdb setting in file local.config # | > > > > > > > > > > > > > > > > > | | | | > | | | | | | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 | # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. # To get emacs font highlighing in the various megatest configs do this: # # Install emacs-goodies-el: # sudo apt install emacs-goodies-el # Add to your ~/.emacs file: # (add-to-list 'auto-mode-alist '("config\\'" . conf-space-mode)) # # example of a cron entry to run sync using db spec pgdb, with pgdb setting in file local.config # [a/b/c/d] all:scheduled:sync cron= 0/5 * * * *;dbdest=pgdb;appendconf=/nfs/phoebe/disk1/home/mfs/matt/.sysmaint/local.config # quick:scheduled:sync cron= 0/5 * * * *;dbdest=pgdb;appendconf=/nfs/phoebe/disk1/home/mfs/matt/.sysmaint/local.config # fast:scheduled:sync-prepend cron= 0/1 * * * *;dbdest=pgdb;appendconf=/mfs/matt/.sysmaint/local.config [scriptinc ./gentargets.sh #{getenv USER}] # [v1.23/45/67] # tip will be replaced with hashkey? # [%/%/%] doesn't work [/.*/] # [v1.63/tip/dev] # file: files changes since last run trigger new run # script: script is called with unix seconds as last parameter (other parameters are preserved) # # contour:sensetype:action params data # commented out for debug quick:file:run runtrans=auto; glob=/home/matt/data/megatest/*.scm foo.touchme # snazy:file:run runtrans=corporate-ww; glob=/home/matt/data/megatest/*.scm # short:file:run runtrans=short; glob=/home/matt/data/megatest/*.scm # script returns change-time (unix epoch), new-target-name, run-name # # quick:script:run checkfossil = http://www.kiatoa.com/fossils/megatest v1.63;\ # checkfossil = http://www.kiatoa.com/fossils/megatest_qa trunk # # fossil based trigger # # # quick:fossil:run http://www.kiatoa.com/fossils/megatest=v1.63;\ # http://www.kiatoa.com/fossils/megatest_qa=trunk;\ # http://www.kiatoa.com/fossils/megatest=v1.64 # field allowed values # ----- -------------- # minute 0-59 # hour 0-23 # day of month 1-31 # month 1-12 (or names, future development) |
︙ | ︙ |
Modified runs-launch-loop-test.scm from [9a5282dbe4] to [a4977cdfc7].
1 2 3 4 5 6 7 | (use srfi-69) (define (runs:queue-next-hed tal reg n regful) (if regful (car reg) (car tal))) | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | ;; Copyright 2006-2017, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. ;; (use srfi-69) (define (runs:queue-next-hed tal reg n regful) (if regful (car reg) (car tal))) |
︙ | ︙ |
Modified runs.scm from [d97eca7b82] to [8eb0eeffbc].
|
| < | > | > > > > | | > | > > | | < < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | ;; Copyright 2006-2016, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. ;; strftime('%m/%d/%Y %H:%M:%S','now','localtime') (use (prefix sqlite3 sqlite3:) srfi-1 posix regex regex-case srfi-69 (srfi 18) posix-extras directory-utils pathname-expand typed-records format sxml-serializer sxml-modifications) (declare (unit runs)) (declare (uses db)) (declare (uses common)) (declare (uses items)) (declare (uses runconfig)) (declare (uses tests)) (declare (uses server)) (declare (uses mt)) (declare (uses archive)) ;; (declare (uses filedb)) (include "common_records.scm") (include "key_records.scm") (include "db_records.scm") (include "run_records.scm") (include "test_records.scm") |
︙ | ︙ | |||
46 47 48 49 50 51 52 53 54 55 56 57 58 59 | ((can-run-more-tests-count 0) : fixnum)) (defstruct runs:testdat hed tal reg reruns test-record test-name item-path jobgroup waitons testmode newtal itemmaps prereqs-not-met) ;; set up needed environment variables given a run-id and optionally a target, itempath etc. ;; (define (runs:set-megatest-env-vars run-id #!key (inkeys #f)(inrunname #f)(inkeyvals #f)(intarget #f)(testname #f)(itempath #f)) ;;(bb-check-path msg: "runs:set-megatest-env-vars entry") (let* ((target (or intarget (common:args-get-target) (get-environment-variable "MT_TARGET"))) | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 | ((can-run-more-tests-count 0) : fixnum)) (defstruct runs:testdat hed tal reg reruns test-record test-name item-path jobgroup waitons testmode newtal itemmaps prereqs-not-met) (define (runs:get-mt-env-alist run-id runname target testname itempath) ;;(bb-check-path msg: "runs:set-megatest-env-vars entry") `(("MT_TEST_NAME" . ,testname) ("MT_ITEMPATH" . ,itempath) ("MT_TARGET" . ,target) ("MT_RUNNAME" . ,runname) ("MT_RUN_AREA_HOME" . ,*toppath*) ,@(let* ((link-tree (common:get-linktree))) ;; (configf:lookup *configdat* "setup" "linktree"))) (if link-tree (list (cons "MT_LINKTREE" link-tree) (cons "MT_TEST_RUN_DIR" (conc link-tree "/" target "/" runname "/" testname (if (and (string? itempath) (not (equal? itempath ""))) (conc "/" itempath) ""))) ) '())) ,@(map (lambda (key) (cons (car key) (cadr key))) (keys:target->keyval (rmt:get-keys) target)) ,@(map (lambda (var) (let ((val (configf:lookup *configdat* "env-override" var))) (cons var val))) (configf:section-vars *configdat* "env-override")))) ;; set up needed environment variables given a run-id and optionally a target, itempath etc. ;; (define (runs:set-megatest-env-vars run-id #!key (inkeys #f)(inrunname #f)(inkeyvals #f)(intarget #f)(testname #f)(itempath #f)) ;;(bb-check-path msg: "runs:set-megatest-env-vars entry") (let* ((target (or intarget (common:args-get-target) (get-environment-variable "MT_TARGET"))) |
︙ | ︙ | |||
94 95 96 97 98 99 100 | exn (let ((call-chain (get-call-chain)) (msg ((condition-property-accessor 'exn 'message) exn))) (if (< count 5) (begin ;; this call is colliding, do some crude stuff to fix it. (debug:print 0 *default-log-port* "ERROR: *configdat* was inaccessible! This should never happen. Retry #" count) (launch:setup force-reread: #t) | | > | > > > > > > > > > | 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 | exn (let ((call-chain (get-call-chain)) (msg ((condition-property-accessor 'exn 'message) exn))) (if (< count 5) (begin ;; this call is colliding, do some crude stuff to fix it. (debug:print 0 *default-log-port* "ERROR: *configdat* was inaccessible! This should never happen. Retry #" count) (launch:setup force-reread: #t) (fatal-loop (+ count 1))) (begin (debug:print 0 *default-log-port* "FATAL: *configdat* was inaccessible! This should never happen. Retried " count " times. Message: " msg) (debug:print 0 *default-log-port* "Call chain:") (with-output-to-port *default-log-port* (lambda () (print "*configdat* is >>"*configdat*"<<") (pp *configdat*) (pp call-chain))) (exit 1)))) ;;(bb-check-path msg: "runs:set-megatest-env-vars block 1.5") (when (or (not *configdat*) (not (hash-table? *configdat*))) (debug:print 0 *default-log-port* "WARNING: *configdat* was inaccessible! This should never happen. Brute force reread.") ;;(BB> "ERROR: *configdat* was inaccessible! This should never happen. Brute force reread.") (thread-sleep! 2) ;; assuming nfs lag. (launch:setup force-reread: #t)) (alist->env-vars (hash-table-ref/default *configdat* "env-override" '())))) ;;;; environment is tainted HERE in this let block. ;;(bb-check-path msg: "runs:set-megatest-env-vars block 2") ;; Lets use this as an opportunity to put MT_RUNNAME in the environment (let ((runname (if inrunname inrunname (rmt:get-run-name-from-id run-id)))) (if runname (setenv "MT_RUNNAME" runname) (debug:print-error 0 *default-log-port* "no value for runname for id " run-id))) |
︙ | ︙ | |||
174 175 176 177 178 179 180 181 182 183 184 | (if (> (- currtime lasttime) waitval) (begin (hash-table-set! *runs:denoise* key currtime) #t) #f))) (define (runs:can-run-more-tests runsdat run-id jobgroup max-concurrent-jobs) ;; Take advantage of a good place to exit if running the one-pass methodology (if (and (> (runs:dat-can-run-more-tests-count runsdat) 20) (args:get-arg "-one-pass")) (exit 0)) | > > | > > > > | | | > > > | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > | | | | | 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 | (if (> (- currtime lasttime) waitval) (begin (hash-table-set! *runs:denoise* key currtime) #t) #f))) (define (runs:can-run-more-tests runsdat run-id jobgroup max-concurrent-jobs) ;; Take advantage of a good place to exit if running the one-pass methodology (if (and (> (runs:dat-can-run-more-tests-count runsdat) 20) (args:get-arg "-one-pass")) (exit 0)) (thread-sleep! (cond ;; BB: check with Matt. Should this sleep move ;; to cond clauses below where we determine we ;; have too many jobs running rather than each ;; time the and condition above is true (which ;; seems like always)? ((> (runs:dat-can-run-more-tests-count runsdat) 20) ;; original intent was - save cycles, wait a long time (if (runs:lownoise "waiting on tasks" 60)(debug:print-info 2 *default-log-port* "waiting for tasks to complete, sleeping briefly ...")) 10) ;; obviously haven't had any work to do for a while (else ;; if have a number for inter-test-delay, use it, else don't delay much, maybe even zero? (configf:lookup-number *configdat* "setup" "inter-test-delay" default: 0.01)))) (let* ((num-running (rmt:get-count-tests-running run-id)) (num-running-in-jobgroup (rmt:get-count-tests-running-in-jobgroup run-id jobgroup)) (job-group-limit (let ((jobg-count (configf:lookup *configdat* "jobgroups" jobgroup))) (if (string? jobg-count) (string->number jobg-count) jobg-count)))) (if (> (+ num-running num-running-in-jobgroup) 0) (runs:inc-can-run-more-tests-count runsdat)) ;; (set! *runs:can-run-more-tests-count* (+ *runs:can-run-more-tests-count* 1))) (if (not (eq? *last-num-running-tests* num-running)) (begin (debug:print 2 *default-log-port* "max-concurrent-jobs: " max-concurrent-jobs ", num-running: " num-running) (set! *last-num-running-tests* num-running))) (if (not (eq? 0 *globalexitstatus*)) (list #f num-running num-running-in-jobgroup max-concurrent-jobs job-group-limit) (let* ((can-not-run-more (cond ;; if max-concurrent-jobs is set and the number running is greater ;; than it then cannot run more jobs ((and max-concurrent-jobs (>= num-running max-concurrent-jobs)) (if (runs:lownoise "mcj msg" 60) (debug:print 0 *default-log-port* "WARNING: Max running jobs exceeded, current number running: " num-running ", max_concurrent_jobs: " max-concurrent-jobs)) #t) ;; if job-group-limit is set and number of jobs in the group is greater ;; than the limit then cannot run more jobs of this kind ((and job-group-limit (>= num-running-in-jobgroup job-group-limit)) (if (runs:lownoise (conc "maxjobgroup " jobgroup) 60) (debug:print 1 *default-log-port* "WARNING: number of jobs " num-running-in-jobgroup " in jobgroup \"" jobgroup "\" exceeds limit of " job-group-limit)) #t) (else #f)))) (list (not can-not-run-more) num-running num-running-in-jobgroup max-concurrent-jobs job-group-limit))))) (define (runs:run-pre-hook run-id) (let* ((run-pre-hook (configf:lookup *configdat* "runs" "pre-hook")) (existing-tests (if run-pre-hook (rmt:get-tests-for-run run-id "%" '() '() ;; run-id testpatt states statuses #f #f ;; offset limit #f ;; not-in #f ;; sort-by #f ;; sort-order #f ;; get full data (not 'shortlist) 0 ;; (runs:gendat-inc-results-last-update *runs:general-data*) ;; last update time 'dashboard) '())) (log-dir (conc *toppath* "/logs")) (log-file (conc "pre-hook-" (string-translate (getenv "MT_TARGET") "/" "-") "-" (getenv "MT_RUNNAME") ".log")) (full-log-fname (conc log-dir "/" log-file))) (if run-pre-hook (if (null? existing-tests) (let* ((use-log-dir (if (not (directory-exists? log-dir)) (handle-exceptions exn (begin (debug:print 0 *default-log-port* "WARNING: Failed to create " log-dir) #f) (create-directory log-dir #t) #t) #t)) (start-time (current-seconds)) (actual-logf (if use-log-dir full-log-fname log-file))) (handle-exceptions exn (begin (print-call-chain *default-log-port*) (debug:print 0 *default-log-port* "Message: " ((condition-property-accessor 'exn 'message) exn)) (debug:print 0 *default-log-port* "ERROR: failed to run pre-hook " run-pre-hook ", check the log " log-file)) (debug:print-info 0 *default-log-port* "running run-pre-hook: \"" run-pre-hook "\", log is " actual-logf) (system (conc run-pre-hook " >> " actual-logf " 2>&1")) (debug:print-info 0 *default-log-port* "pre-hook \"" run-pre-hook "\" took " (- (current-seconds) start-time) " seconds to run."))) (debug:print 0 *default-log-port* "Skipping pre-hook call \"" run-pre-hook "\" as there are existing tests for this run."))))) (define (runs:run-post-hook run-id) (let* ((run-post-hook (configf:lookup *configdat* "runs" "post-hook")) (existing-tests (if run-post-hook (rmt:get-tests-for-run run-id "%" '() '() ;; run-id testpatt states statuses #f #f ;; offset limit #f ;; not-in #f ;; sort-by #f ;; sort-order #f ;; get full data (not 'shortlist) 0 ;; (runs:gendat-inc-results-last-update *runs:general-data*) ;; last update time 'dashboard) '())) (log-dir (conc *toppath* "/logs")) (log-file (conc "post-hook-" (string-translate (getenv "MT_TARGET") "/" "-") "-" (getenv "MT_RUNNAME") ".log")) (full-log-fname (conc log-dir "/" log-file))) (if run-post-hook ;; (if (null? existing-tests) ;; (debug:print 0 *default-log-port* "Skipping post-hook call \"" run-post-hook "\" as there are existing tests for this run."))))) (let* ((use-log-dir (if (not (directory-exists? log-dir)) (handle-exceptions exn (begin (debug:print 0 *default-log-port* "WARNING: Failed to create " log-dir) #f) (create-directory log-dir #t) #t) #t)) (start-time (current-seconds)) (actual-logf (if use-log-dir full-log-fname log-file))) (handle-exceptions exn (begin (print-call-chain *default-log-port*) (debug:print 0 *default-log-port* "Message: " ((condition-property-accessor 'exn 'message) exn)) (debug:print 0 *default-log-port* "ERROR: failed to run post-hook " run-post-hook ", check the log " log-file)) (debug:print-info 0 *default-log-port* "running run-post-hook: \"" run-post-hook "\", log is " actual-logf) (system (conc run-post-hook " >> " actual-logf " 2>&1")) (debug:print-info 0 *default-log-port* "post-hook \"" run-post-hook "\" took " (- (current-seconds) start-time) " seconds to run.")))))) ;; return #t when all items in waitors-upon list are represented in test-patt, #f otherwise. (define (runs:testpatts-mention-waitors-upon? test-patt waitors-upon) (null? (tests:filter-test-names-not-matched waitors-upon test-patt))) ;;====================================================================== ;; runs:run-tests is called from megatest.scm and itself ;;====================================================================== ;; ;; test-names: Comma separated patterns same as test-patts but used in selection ;; of tests to run. The item portions are not respected. ;; FIXME: error out if /patt specified ;; (define (runs:run-tests target runname test-patts user flags #!key (run-count 1)) ;; test-names (let* ((keys (keys:config-get-fields *configdat*)) (keyvals (keys:target->keyval keys target)) (run-id (rmt:register-run keyvals runname "new" "n/a" user (args:get-arg "-contour"))) ;; test-name))) ;; (deferred '()) ;; delay running these since they have a waiton clause (runconfigf (conc *toppath* "/runconfigs.config")) (dbfile (conc *toppath* "/megatest.db")) (readonly-mode (not (file-write-access? dbfile))) (test-records (make-hash-table)) ;; need to process runconfigs before generating these lists (all-tests-registry #f) ;; (tests:get-all)) ;; (tests:get-valid-tests (make-hash-table) test-search-path)) ;; all valid tests to check waiton names (all-test-names #f) ;; (hash-table-keys all-tests-registry)) (test-names #f) ;; Generated by a call to (tests:filter-test-names all-test-names test-patts)) (required-tests #f) ;; Put fully qualified test/testpath names in this list to be done (waitors-upon (make-hash-table)) ;; given a test, return list of tests waiting upon this test. (task-key (conc (hash-table->alist flags) " " (get-host-name) " " (current-process-id))) ;; (tdbdat (tasks:open-db)) (config-reruns (let ((x (configf:lookup *configdat* "setup" "reruns"))) (if x (string->number x) #f))) (allowed-tests #f) (runconf #f)) ;; check if readonly (when readonly-mode (debug:print-error 0 *default-log-port* "megatest.db is readonly. Cannot proceed.") (exit 1)) ;; per user request. If less than 100Meg space on dbdir partition, bail out with error ;; this will reduce issues in database corruption (common:check-db-dir-and-exit-if-insufficient) ;; override the number of reruns from the configs ;; this needs to be done at the place where is first runs:run-tests called ;(if (and config-reruns ; (> run-count config-reruns)) ;(set! run-count config-reruns)) ;; (if (tasks:need-server run-id)(tasks:start-and-wait-for-server tdbdat run-id 10)) (let ((sighand (lambda (signum) ;; (signal-mask! signum) ;; to mask or not? seems to cause issues in exiting (set! *time-to-exit* #t) (print "Received signal " signum ", cleaning up before exit. Please wait...") (let ((th1 (make-thread (lambda () |
︙ | ︙ | |||
277 278 279 280 281 282 283 | (exit 4))))) (thread-start! th2) (thread-start! th1) (thread-join! th2))))) (set-signal-handler! signal/int sighand) (set-signal-handler! signal/term sighand)) | | | | | > > > > > > > > > > > > > > > < | 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 | (exit 4))))) (thread-start! th2) (thread-start! th1) (thread-join! th2))))) (set-signal-handler! signal/int sighand) (set-signal-handler! signal/term sighand)) ;; force the starting of a server -- removed BB 17ww28 - no longer needed. ;;(debug:print 0 *default-log-port* "waiting on server...") ;;(server:start-and-wait *toppath*) (runs:set-megatest-env-vars run-id inkeys: keys inrunname: runname) ;; these may be needed by the launching process (set! runconf (if (common:file-exists? runconfigf) (setup-env-defaults runconfigf run-id *already-seen-runconfig-info* keyvals target) (begin (debug:print 0 *default-log-port* "WARNING: You do not have a run config file: " runconfigf) #f))) (if (not test-patts) ;; first time in - adjust testpatt (set! test-patts (common:args-get-testpatt runconf))) ;; if test-patts is #f at this point there is something wrong and we need to bail out (if (not test-patts) (begin (debug:print 0 *default-log-port* "WARNING: there is no test pattern for this run. Exiting now.") (exit 0))) (if (args:get-arg "-tagexpr") (begin (set! allowed-tests (string-join (runs:get-tests-matching-tags (args:get-arg "-tagexpr")) ",")) (debug:print-info 0 *default-log-port* "filtering initial test list with tagexpr: " (args:get-arg "-tagexpr") " => " allowed-tests) ));; tests will be ANDed with this list ;; register this run in monitor.db (rmt:tasks-add "run-tests" user target runname test-patts task-key) ;; params) (rmt:tasks-set-state-given-param-key task-key "running") (common:telemetry-log "run-tests" payload: `( (target . ,target) (run-name . ,runname) (test-patts . ,test-patts) ) ) ;; Now generate all the tests lists (set! all-tests-registry (tests:get-all)) ;; hash of testname => path-to-test (set! all-test-names (hash-table-keys all-tests-registry)) ;; filter first for allowed-tests (from -tagexpr) then for test-patts. (set! test-names (tests:filter-test-names (if allowed-tests (tests:filter-test-names all-test-names allowed-tests) all-test-names) test-patts)) ;; I think seeding required-tests with all test-names makes sense but lack analysis to back that up. ;; NEW STRATEGY HERE: ;; 1. fill required tests with test-patts ;; 2. scan testconfigs and if waitons, itemwait, itempatt calc prior test test-patt ;; 3. repeat until all deps propagated ;; any tests with direct mention in test-patts can be added to required ;;(set! required-tests (lset-intersection equal? (string-split test-patts ",") all-test-names)) (set! required-tests (tests:filter-test-names all-test-names test-patts)) ;; ;; (set! required-tests (lset-intersection equal? test-names all-test-names)) ;; look up all tests matching the comma separated list of globs in ;; test-patts (using % as wildcard) ;; (set! test-names (delete-duplicates (tests:get-valid-tests *toppath* test-patts))) (debug:print-info 0 *default-log-port* "tests search path: " (string-intersperse (tests:get-tests-search-path *configdat*) " ")) |
︙ | ︙ | |||
359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 | (rmt:set-tests-state-status run-id test-names state status "NOT_STARTED" status))) ;; list of state/status pairs separated by spaces (string-split (or (configf:lookup *configdat* "setup" "allow-auto-rerun") ""))))) ;; Ensure all tests are registered in the test_meta table (runs:update-all-test_meta #f) ;; now add non-directly referenced dependencies (i.e. waiton) ;;====================================================================== ;; refactoring this block into tests:get-full-data ;; ;; What happended, this code is now duplicated in tests!? ;; ;;====================================================================== | > > > > > > > > > > > > > > > | > | > > > > > > > > > | | | | | | | > | | > > > > > > > > > > | | < < | < < | > | | > | | | > > > | | | < < > | | < | | | | | < < < | | | | | | > > > | > > > > > > > | | | | > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > | > < | < < > > > > > | > > > > | > | > | 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 | (rmt:set-tests-state-status run-id test-names state status "NOT_STARTED" status))) ;; list of state/status pairs separated by spaces (string-split (or (configf:lookup *configdat* "setup" "allow-auto-rerun") ""))))) ;; Ensure all tests are registered in the test_meta table (runs:update-all-test_meta #f) ;; run the run prehook if there are no tests yet run for this run: ;; (runs:run-pre-hook run-id) ;; mark all test launced flag as false in the meta table (rmt:set-var (conc "lunch-complete-" run-id) "no") (debug:print-info 1 *default-log-port* "Setting end-of-run to no") (let* ((config-reruns (let ((x (configf:lookup *configdat* "setup" "reruns"))) (if x (string->number x) #f))) (config-rerun-cnt (if config-reruns config-reruns 1))) (if (eq? config-rerun-cnt run-count) (rmt:set-var (conc "end-of-run-" run-id) "no"))) (rmt:set-run-state-status run-id "new" "n/a") ;; now add non-directly referenced dependencies (i.e. waiton) ;;====================================================================== ;; refactoring this block into tests:get-full-data ;; ;; What happended, this code is now duplicated in tests!? ;; ;;====================================================================== (if (not (null? test-names)) ;; BEGIN test-names loop (let loop ((hed (car test-names)) ;; NOTE: This is the main loop that iterates over the test-names (tal (cdr test-names))) ;; 'return-procs tells the config reader to prep running system but return a proc (debug:print-info 4 *default-log-port* "\n\ntestpatt elaboration loop => hed="hed " tal="tal" test-patts="test-patts" test-names="test-names) (change-directory *toppath*) ;; PLEASE OPTIMIZE ME!!! I think this should be a no-op but there are several places where change-directories could be happening. (setenv "MT_TEST_NAME" hed) ;; (let*-values (((waitons waitors config) (tests:get-waitons hed all-tests-registry)) ;; NOTE: Have the config - can extract [waitons] section ((hed-mode) (let ((m (configf:lookup config "requirements" "mode"))) (if m (map string->symbol (string-split m)) '(normal)))) ((hed-itemized-waiton) ;; are items in hed waiting on items of waiton? (not (null? (lset-intersection eq? hed-mode '(itemmatch itemwait))))) ) (debug:print-info 8 *default-log-port* "waitons: " waitons) ;; check for hed in waitons => this would be circular, remove it and issue an ;; error (if (or (member hed waitons) (member hed waitors)) (begin (debug:print-error 0 *default-log-port* "test " hed " has listed itself as a waiton or waitor, please correct this!") (set! waitons (filter (lambda (x)(not (equal? x hed))) waitons)) (set! waitors (filter (lambda (x)(not (equal? x hed))) waitors)))) ;; (items (items:get-items-from-config config))) (if (not (hash-table-ref/default test-records hed #f)) ;; waiton-tconfig below will be #f until that test is visted here at least once (hash-table-set! test-records ;; BB: we are doing a manual make-tests:testqueue hed (vector hed ;; 0 ;; testname config ;; 1 waitons ;; 2 (configf:lookup config "requirements" "priority") ;; priority 3 (tests:get-items config) ;; 4 ;; expand the [items] and or [itemstable] into explict items #f ;; itemsdat 5 #f ;; spare - used for item-path waitors ;; ))) ;; update waitors-upon here (for-each (lambda (waiton) (let* ((current-waitors-upon (hash-table-ref/default waitors-upon waiton '()))) (debug:print-info 8 *default-log-port* " current-waiters-upon["waiton"] is "current-waitors-upon ) (when (not (member hed current-waitors-upon)) (debug:print-info 8 *default-log-port* " current-waiters-upon["waiton"] << "hed ) (hash-table-set! waitors-upon waiton (cons hed current-waitors-upon))))) (if (list? waitons) waitons '())) (debug:print-info 8 *default-log-port* " process waitons&waitors of "hed": "(delete-duplicates (append waitons waitors))) (for-each (lambda (waiton) (if (and waiton (not (member waiton test-names))) (let* ((waitors-in-testpatt (runs:testpatts-mention-waitors-upon? test-patts (hash-table-ref/default waitors-upon waiton '()))) (waiton-record (hash-table-ref/default test-records waiton #f)) (waiton-tconfig (if waiton-record (vector-ref waiton-record 1) #f)) (waiton-itemized (and waiton-tconfig (or (hash-table-ref/default waiton-tconfig "items" #f) (hash-table-ref/default waiton-tconfig "itemstable" #f)))) (itemmaps (tests:get-itemmaps config)) ;; (configf:lookup config "requirements" "itemmap")) (new-test-patts (tests:extend-test-patts test-patts hed waiton itemmaps hed-itemized-waiton))) (debug:print-info 0 *default-log-port* "Test " waiton " has " (if waiton-record "a" "no") " waiton-record and" (if waiton-itemized " " " no ") "items") ;; need to account for test-patt here, if I am test "a", selected with a test-patt of "hed/b%" ;; and we are waiting on "waiton" we need to add "waiton/,waiton/b%" to test-patt ;; is this satisfied by merely appending "/" to the waiton name added to the list? ;; ;; This approach causes all of the items in an upstream test to be run ;; if we have this waiton already processed once we can analzye it for extending ;; tests to be run, since we can't properly process waitons unless they have been ;; initially added we add them again to be processed on second round AND add the hed ;; back in to also be processed on second round (if waiton-tconfig ;; BB: waiter should be in test-patts as well as the waiton have a tconfig. (if waiton-itemized (if waitors-in-testpatt (begin (debug:print-info 0 *default-log-port* "New test patts: " new-test-patts ", prev test patts: " test-patts) (set! test-names (cons waiton test-names)) ;; need to process this one, only add once the waiton tconfig read (set! required-tests (cons (conc waiton "/") required-tests)) (set! test-patts new-test-patts)) (begin (debug:print-info 0 *default-log-port* "Waitor(s) not yet on testpatt for " waiton ", setting up to re-process it") (set! tal (append (cons waiton tal)(list hed))))) (begin (debug:print-info 0 *default-log-port* "Adding non-itemized test " waiton " to required-tests") (set! required-tests (cons waiton required-tests)) (set! test-patts new-test-patts))) (begin (debug:print-info 0 *default-log-port* "No testconfig info yet for " waiton ", setting up to re-process it") (set! tal (append (cons waiton tal)(list hed))))) ;; (cons (conc waiton "/") required-tests)) ;; NOPE: didn't work. required needs to be plain test names. Try tacking on to test-patts ;; - doesn't work ;; (set! test-patts (conc test-patts "," waiton "/")) ;; (set! test-names (cons waiton test-names))))) ;; was an append, now a cons ))) (delete-duplicates (append waitons waitors))) (let ((remtests (delete-duplicates (append waitons tal)))) (debug:print-info 8 *default-log-port* " remtests are "remtests) (if (not (null? remtests)) (begin ;; (debug:print-info 0 *default-log-port* "Preprocessing continues for " (string-intersperse remtests ", ")) (loop (car remtests)(cdr remtests)))))))) ;; END test-names loop (if (not (null? required-tests)) (debug:print-info 1 *default-log-port* "Adding \"" (string-intersperse required-tests " ") "\" to the run queue")) ;; NOTE: these are all parent tests, items are not expanded yet. (debug:print-info 4 *default-log-port* "test-records=" (hash-table->alist test-records)) (let ((reglen (configf:lookup *configdat* "setup" "runqueue"))) (if (> (length (hash-table-keys test-records)) 0) (let* ((keep-going #t) (run-queue-retries 5) #;(th1 (make-thread (lambda () (handle-exceptions exn (begin (print-call-chain) (print " message: " ((condition-property-accessor 'exn 'message) exn))) (runs:run-tests-queue run-id runname test-records keyvals flags test-patts required-tests (any->number reglen) all-tests-registry))) "runs:run-tests-queue")) (th2 (make-thread (lambda () ;; BBQ: why are we visiting ALL runs here? ;; (rmt:find-and-mark-incomplete-all-runs))))) CAN'T INTERRUPT IT ... (let ((run-ids (rmt:get-all-run-ids))) (for-each (lambda (run-id) (if keep-going (handle-exceptions exn (debug:print 0 *default-log-port* "error in calling find-and-mark-incomplete for run-id " run-id) (rmt:find-and-mark-incomplete run-id #f)))) ;; ovr-deadtime))) ;; could be root of https://hsdes.intel.com/appstore/article/#/220546828/main -- Title: Megatest jobs show DEAD even though they are still running (1.64/27) run-ids))) "runs: mark-incompletes"))) ;; (thread-start! th1) (thread-start! th2) ;; (thread-join! th1) ;; just do the main stuff in the main thread (runs:run-tests-queue run-id runname test-records keyvals flags test-patts required-tests (any->number reglen) all-tests-registry) (set! keep-going #f) (thread-join! th2) ;; if run-count > 0 call, set -preclean and -rerun STUCK/DEAD (if (> run-count 0) ;; handle reruns (begin (if (not (hash-table-ref/default flags "-preclean" #f)) (hash-table-set! flags "-preclean" #t)) (if (not (hash-table-ref/default flags "-rerun" #f)) (hash-table-set! flags "-rerun" "STUCK/DEAD,n/a,ZERO_ITEMS")) ;; recursive call to self (runs:run-tests target runname test-patts user flags run-count: (- run-count 1))) (launch:end-of-run-check run-id))) (debug:print-info 0 *default-log-port* "No tests to run"))) (debug:print-info 4 *default-log-port* "All done by here") ;; TODO: try putting post hook call here ; (debug:print-info 2 *default-log-port* " run-count " run-count) ; (runs:run-post-hook run-id)) ; (debug:print-info 2 *default-log-port* "Not calling post hook runcount = " run-count )) (rmt:tasks-set-state-given-param-key task-key "done") ;; (sqlite3:finalize! tasks-db) )) ;; loop logic. These are used in runs:run-tests-queue to make it a bit more readable. ;; ;; If reg not full and have items in tal then loop with (car tal)(cdr tal) reg reruns ;; If reg is full (i.e. length >= n ;; loop with (car reg) tal (cdr reg) reruns ;; If tal is empty ;; but have items in reg; loop with (car reg)(cdr reg) '() reruns ;; If reg is empty => all done (define (runs:queue-next-hed tal reg n regfull) (if regfull (if (null? reg) #f (car reg)) (if (null? tal) ;; tal is used up, pop from reg (if (null? reg) #f (car reg)) (car tal)))) (define (runs:queue-next-tal tal reg n regfull) (if regfull tal (if (null? tal) ;; must transfer from reg (if (null? reg) '() (cdr reg)) (cdr tal)))) (define (runs:queue-next-reg tal reg n regfull) (if regfull (if (null? reg) '() (cdr reg)) ;; EXPLORE: reorder (cdr reg) such that looping is more efficient (if (null? tal) ;; if tal is null and reg not full then '() as reg contents moved to tal '() reg))) ;; this is the list of parameters to the named loop "loop" near the top of runs:run-tests-queue, look around line 1216 ;; (define (runs:loop-values tal reg reglen regfull reruns) (list (runs:queue-next-hed tal reg reglen regfull) ;; hed (runs:queue-next-tal tal reg reglen regfull) ;; tal (runs:queue-next-reg tal reg reglen regfull) ;; reg reruns)) ;; reruns ;; objective - iterate thru tests ;; => want to prioritize tests we haven't seen before ;; => sometimes need to squeeze things in (added to reg) ;; => review of a previously seen test is higher priority of never visited test ;; reg - list of previously visited tests ;; tal - list of never visited tests ;; prefer next hed to be from reg than tal. (define runs:nothing-left-in-queue-count 0) ;;====================================================================== ;; runs:expand-items is called by runs:run-tests-queue ;;====================================================================== ;; ;; return value of runs:expand-items is passed back to runs-tests-queue and is fed to named loop with this signature: ;; (let loop ((hed (car sorted-test-names)) ;; (tal (cdr sorted-test-names)) ;; (reg '()) ;; registered, put these at the head of tal ;; (reruns '())) (define (runs:expand-items hed tal reg reruns regfull newtal jobgroup max-concurrent-jobs run-id waitons item-path testmode test-record can-run-more items runname tconfig reglen test-registry test-records itemmaps) (let* ((loop-list (list hed tal reg reruns)) (prereqs-not-met (let ((res (rmt:get-prereqs-not-met run-id waitons hed item-path mode: testmode itemmaps: itemmaps))) (if (list? res) res (begin (debug:print 0 *default-log-port* "ERROR: rmt:get-prereqs-not-met returned non-list!\n" " res=" res " run-id=" run-id " waitons=" waitons " hed=" hed " item-path=" item-path " testmode=" testmode " itemmaps=" itemmaps) '())))) (have-itemized (not (null? (lset-intersection eq? testmode '(itemmatch itemwait))))) ;; (prereqs-not-met (mt:lazy-get-prereqs-not-met run-id waitons item-path mode: testmode itemmap: itemmap)) (fails (runs:calc-fails prereqs-not-met)) (prereq-fails (runs:calc-prereq-fail prereqs-not-met)) (non-completed (runs:calc-not-completed prereqs-not-met)) (runnables (runs:calc-runnable prereqs-not-met)) (unexpanded-prereqs (filter (lambda (testname) (let* ((test-rec (hash-table-ref test-records testname)) (items (tests:testqueue-get-items test-rec))) ;;(BB> "HEY " testname "=>"items) (or (procedure? items)(eq? items 'have-procedure)))) waitons)) ) (debug:print-info 4 *default-log-port* "START OF INNER COND #2 " "\n can-run-more: " can-run-more "\n testname: " hed "\n prereqs-not-met: " (runs:pretty-string prereqs-not-met) "\n non-completed: " (runs:pretty-string non-completed) "\n prereq-fails: " (runs:pretty-string prereq-fails) "\n fails: " (runs:pretty-string fails) "\n testmode: " testmode "\n (member 'toplevel testmode): " (member 'toplevel testmode) "\n (null? non-completed): " (null? non-completed) "\n reruns: " reruns "\n items: " items "\n can-run-more: " can-run-more) (cond ;; all prereqs met, fire off the test ;; or, if it is a 'toplevel test and all prereqs not met are COMPLETED then launch ((and (not (member 'toplevel testmode)) (member (hash-table-ref/default test-registry (db:test-make-full-name hed item-path) 'n/a) '(DONOTRUN removed CANNOTRUN))) ;; *common:cant-run-states-sym*) ;; '(COMPLETED KILLED WAIVED UNKNOWN INCOMPLETE)) ;; try to catch repeat processing of COMPLETED tests here (debug:print-info 4 *default-log-port* "cond branch - " "ei-1") (debug:print-info 1 *default-log-port* "Test " hed " set to \"" (hash-table-ref test-registry (db:test-make-full-name hed item-path)) "\". Removing it from the queue") (if (or (not (null? tal)) (not (null? reg))) (runs:loop-values tal reg reglen regfull reruns) (begin (debug:print-info 0 *default-log-port* "Nothing left in the queue!") ;; If get here twice then we know we've tried to expand all items ;; since there must be a logic issue with the handling of loops in the ;; items expand phase we will brute force an exit here. (if (> runs:nothing-left-in-queue-count 2) (begin (debug:print 0 *default-log-port* "WARNING: this condition is triggered when there were no items to expand and nothing to run. Please check your run for completeness") (exit 0)) (set! runs:nothing-left-in-queue-count (+ runs:nothing-left-in-queue-count 1))) #f))) ;; desired result of below cond branch: ;; we want to expand items in our test of interest (hed) in the following cases: ;; case 1 - mode is itemmatch or itemwait: ;; - all prereq tests have been expanded ;; - at least one prereq's items have completed ;; case 2 - mode is toplevel ;; - prereqs are completed. ;; - or no prereqs can complete ;; case 3 - mode not specified ;; - prereqs are completed and passed (we could consider removing "and passed" -- it would change behavior from current) ((or (null? prereqs-not-met) (and (member 'toplevel testmode) (null? non-completed))) (debug:print-info 4 *default-log-port* "cond branch - " "ei-2") (debug:print-info 4 *default-log-port* "runs:expand-items: (or (null? prereqs-not-met) (and (member 'toplevel testmode)(null? non-completed)))") (let ((test-name (tests:testqueue-get-testname test-record))) (setenv "MT_TEST_NAME" test-name) ;; (setenv "MT_RUNNAME" runname) (runs:set-megatest-env-vars run-id inrunname: runname) ;; these may be needed by the launching process (let ((items-list (items:get-items-from-config tconfig))) (if (list? items-list) (begin (if (null? items-list) (let ((test-id (rmt:get-test-id run-id test-name "")) (num-items (rmt:test-toplevel-num-items run-id test-name))) (if (and test-id (not (> num-items 0))) (mt:test-set-state-status-by-id run-id test-id "NOT_STARTED" "ZERO_ITEMS" "Failed to run due to failed prerequisites")))) (tests:testqueue-set-items! test-record items-list) (list hed tal reg reruns)) (begin (debug:print-error 0 *default-log-port* "The proc from reading the items table did not yield a list - please report this") (exit 1)))))) ((and (null? fails) (null? prereq-fails) (not (null? non-completed))) (debug:print-info 4 *default-log-port* "cond branch - " "ei-3") (let* ((allinqueue (map (lambda (x)(if (string? x) x (db:test-get-testname x))) (append newtal reruns))) ;; prereqstrs is a list of test names as strings that are prereqs for hed (prereqstrs (delete-duplicates (map (lambda (x)(if (string? x) x (db:test-get-testname x))) prereqs-not-met))) ;; a prereq that is not found in allinqueue will be put in the notinqueue list ;; |
︙ | ︙ | |||
641 642 643 644 645 646 647 | (if (and give-up (not (and (null? tal)(null? reg)))) (let ((trimmed-tal (mt:discard-blocked-tests run-id hed tal test-records)) (trimmed-reg (mt:discard-blocked-tests run-id hed reg test-records))) (debug:print 1 *default-log-port* "WARNING: test " hed " has discarded prerequisites, removing it from the queue") (let ((test-id (rmt:get-test-id run-id hed ""))) | | < | < | | > | | < | < | | > | > > | < < < | > | > > > | > < < < < | 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 | (if (and give-up (not (and (null? tal)(null? reg)))) (let ((trimmed-tal (mt:discard-blocked-tests run-id hed tal test-records)) (trimmed-reg (mt:discard-blocked-tests run-id hed reg test-records))) (debug:print 1 *default-log-port* "WARNING: test " hed " has discarded prerequisites, removing it from the queue") (let ((test-id (rmt:get-test-id run-id hed ""))) (if test-id (mt:test-set-state-status-by-id run-id test-id "COMPLETED" "PREQ_DISCARDED" "Failed to run due to discarded prerequisites"))) (if (and (null? trimmed-tal) (null? trimmed-reg)) #f (runs:loop-values trimmed-tal trimmed-reg reglen regfull reruns) )) (list (car newtal)(append (cdr newtal) reg) '() reruns)))) ((and (null? fails) ;; have not-started tests, but unable to run them. everything looks completed with no prospect of unsticking something that is stuck. we should mark hed as moribund and exit or continue if there are more tests to consider (null? prereq-fails) (null? non-completed)) (debug:print-info 4 *default-log-port* "cond branch - " "ei-4") (if (runs:can-keep-running? hed 20) (begin (runs:inc-cant-run-tests hed) (debug:print-info 0 *default-log-port* "no fails in prerequisites for " hed " but also none running, keeping " hed " for now. Try count: " (hash-table-ref/default *seen-cant-run-tests* hed 0)) ;; ;; getting here likely means the system is way overloaded, kill a full minute before continuing (thread-sleep! 60) ;; TODO: gate by normalized server load > 1.0 (maxload config thing) ;; num-retries code was here ;; we use this opportunity to move contents of reg to tal (list (car newtal)(append (cdr newtal) reg) '() reruns)) ;; an issue with prereqs not yet met? (begin (debug:print-info 1 *default-log-port* "no fails in prerequisites for " hed " but nothing seen running in a while, dropping test " hed " from the run queue") (let ((test-id (rmt:get-test-id run-id hed ""))) (if test-id (mt:test-set-state-status-by-id run-id test-id "NOT_STARTED" "TIMED_OUT" "Nothing seen running in a while."))) (runs:loop-values tal reg reglen regfull reruns) ))) ((and (or (not (null? fails)) (not (null? prereq-fails))) (member 'normal testmode)) (debug:print-info 4 *default-log-port* "cond branch - " "ei-5") (debug:print-info 1 *default-log-port* "test " hed " (mode=" testmode ") has failed prerequisite(s); " (string-intersperse (map (lambda (t)(conc (db:test-get-testname t) ":" (db:test-get-state t)"/"(db:test-get-status t))) fails) ", ") ", removing it from to-do list") (let ((test-id (rmt:get-test-id run-id hed ""))) (if test-id (if (not (null? prereq-fails)) (mt:test-set-state-status-by-id-unless-completed run-id test-id "COMPLETED" "PREQ_DISCARDED" "Failed to run due to prior failed prerequisites") (mt:test-set-state-status-by-id-unless-completed run-id test-id "COMPLETED" "PREQ_FAIL" "Failed to run due to failed prerequisites")))) ;; (debug:print 4 *default-log-port*"BB> set PREQ_FAIL on "hed) ;; (mt:test-set-state-status-by-id run-id test-id "NOT_STARTED" "PREQ_FAIL" "Failed to run due to failed prerequisites")))) ;; BB: this works, btu equivalent for itemwait mode does not work. (if (or (not (null? reg))(not (null? tal))) (begin (hash-table-set! test-registry hed 'CANNOTRUN) (runs:loop-values tal reg reglen regfull (cons hed reruns)) ) #f)) ;; #f flags do not loop ((and (not (null? fails))(member 'toplevel testmode)) (debug:print-info 4 *default-log-port* "cond branch - " "ei-6") (if (or (not (null? reg))(not (null? tal))) (list (car newtal)(append (cdr newtal) reg) '() reruns) #f)) ((null? runnables) (debug:print-info 4 *default-log-port* "cond branch - " "ei-7") #f) ;; if we get here and non-completed is null then it is all over. (else (debug:print-info 4 *default-log-port* "cond branch - " "ei-8") (debug:print 0 *default-log-port* "WARNING: FAILS or incomplete tests maybe preventing completion of this run. Watch for issues with test " hed ", continuing for now") (list (car newtal)(cdr newtal) reg reruns))))) (define (runs:mixed-list-testname-and-testrec->list-of-strings inlst) (if (null? inlst) '() (map (lambda (t) (cond |
︙ | ︙ | |||
728 729 730 731 732 733 734 735 736 737 738 739 740 741 | (conc t)))) inlst))) ;; hed tal reg reruns reglen regfull test-record runname test-name item-path jobgroup max-concurrent-jobs run-id waitons item-path testmode test-patts required-tests test-registry registry-mutex flags keyvals run-info newtal all-tests-registry itemmaps) (define (runs:process-expanded-tests runsdat testdat) ;; unroll the contents of runsdat and testdat (due to ongoing refactoring). (let* ((hed (runs:testdat-hed testdat)) (tal (runs:testdat-tal testdat)) (reg (runs:testdat-reg testdat)) (reruns (runs:testdat-reruns testdat)) (test-name (runs:testdat-test-name testdat)) (item-path (runs:testdat-item-path testdat)) (jobgroup (runs:testdat-jobgroup testdat)) | > > > | 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 | (conc t)))) inlst))) ;; hed tal reg reruns reglen regfull test-record runname test-name item-path jobgroup max-concurrent-jobs run-id waitons item-path testmode test-patts required-tests test-registry registry-mutex flags keyvals run-info newtal all-tests-registry itemmaps) (define (runs:process-expanded-tests runsdat testdat) ;; unroll the contents of runsdat and testdat (due to ongoing refactoring). (debug:print 2 *default-log-port* "runs:process-expanded-tests; testdat:" ) (debug:print 2 *default-log-port* (with-output-to-string (lambda () (pp (runs:testdat->alist testdat) )))) (let* ((hed (runs:testdat-hed testdat)) (tal (runs:testdat-tal testdat)) (reg (runs:testdat-reg testdat)) (reruns (runs:testdat-reruns testdat)) (test-name (runs:testdat-test-name testdat)) (item-path (runs:testdat-item-path testdat)) (jobgroup (runs:testdat-jobgroup testdat)) |
︙ | ︙ | |||
765 766 767 768 769 770 771 | (have-resources (car run-limits-info)) (num-running (list-ref run-limits-info 1)) (num-running-in-jobgroup(list-ref run-limits-info 2)) (max-concurrent-jobs (list-ref run-limits-info 3)) (job-group-limit (list-ref run-limits-info 4)) ;; (prereqs-not-met (rmt:get-prereqs-not-met run-id waitons hed item-path mode: testmode itemmaps: itemmaps)) ;; (prereqs-not-met (mt:lazy-get-prereqs-not-met run-id waitons item-path mode: testmode itemmap: itemmap)) | | < | > | | < | < < | 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 | (have-resources (car run-limits-info)) (num-running (list-ref run-limits-info 1)) (num-running-in-jobgroup(list-ref run-limits-info 2)) (max-concurrent-jobs (list-ref run-limits-info 3)) (job-group-limit (list-ref run-limits-info 4)) ;; (prereqs-not-met (rmt:get-prereqs-not-met run-id waitons hed item-path mode: testmode itemmaps: itemmaps)) ;; (prereqs-not-met (mt:lazy-get-prereqs-not-met run-id waitons item-path mode: testmode itemmap: itemmap)) (fails (if (list? prereqs-not-met) ;; TODO: rename fails to failed-prereqs (runs:calc-fails prereqs-not-met) (begin (debug:print-error 0 *default-log-port* "prereqs-not-met is not a list! " prereqs-not-met) '()))) (non-completed (filter (lambda (x) ;; remove hed from not completed list, duh, of course it is not completed! (not (equal? x hed))) (runs:calc-not-completed prereqs-not-met))) (loop-list (list hed tal reg reruns)) ;; configure the load runner (maxload (string->number (or (configf:lookup *configdat* "jobtools" "maxload") "3.0"))) ;; use a non-number string to disable (maxhomehostload (string->number (or (configf:lookup *configdat* "jobtools" "maxhomehostload") "2.0"))) ;; use a non-number string to disable (waitdelay (string->number (or (configf:lookup *configdat* "jobtools" "waitdelay") "60")))) (debug:print-info 4 *default-log-port* "have-resources: " have-resources " prereqs-not-met: (" (string-intersperse (map (lambda (t) (if (vector? t) (conc (db:test-get-state t) "/" (db:test-get-status t)) (conc " WARNING: t is not a vector=" t ))) prereqs-not-met) ", ") ") fails: " fails "\nregistered? " (hash-table-ref/default test-registry (db:test-make-full-name test-name item-path) #f)) (if (and (not (null? prereqs-not-met)) (runs:lownoise (conc "waiting on tests " prereqs-not-met hed) 60)) (debug:print-info 2 *default-log-port* "waiting on tests; " (string-intersperse (runs:mixed-list-testname-and-testrec->list-of-strings prereqs-not-met) ", "))) ;; Don't know at this time if the test have been launched at some time in the past ;; i.e. is this a re-launch? (debug:print-info 4 *default-log-port* "run-limits-info = " run-limits-info) (cond ; cond 894- 1067 ;; Check item path against item-patts, ;; ((not (tests:match test-patts (tests:testqueue-get-testname test-record) item-path required: required-tests)) ;; This test/itempath is not to be run ;; else the run is stuck, temporarily or permanently ;; but should check if it is due to lack of resources vs. prerequisites (debug:print-info 1 *default-log-port* "Skipping " (tests:testqueue-get-testname test-record) " " item-path " as it doesn't match " test-patts) (if (or (not (null? tal))(not (null? reg))) (runs:loop-values tal reg reglen regfull reruns) #f)) ;; Register tests ;; ((not (hash-table-ref/default test-registry (db:test-make-full-name test-name item-path) #f)) (debug:print-info 4 *default-log-port* "Pre-registering test " test-name "/" item-path " to create placeholder" ) ;; always do firm registration now in v1.60 and greater ;; (eq? *transport-type* 'fs) ;; no point in parallel registration if use fs |
︙ | ︙ | |||
835 836 837 838 839 840 841 | (begin (rmt:register-test run-id test-name "") (if (rmt:get-test-id run-id test-name "") (hash-table-set! test-registry (db:test-make-full-name test-name "") 'done)))) (runs:shrink-can-run-more-tests-count runsdat) ;; DELAY TWEAKER (still needed?) (if (and (null? tal)(null? reg)) (list hed tal (append reg (list hed)) reruns) | | | 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 | (begin (rmt:register-test run-id test-name "") (if (rmt:get-test-id run-id test-name "") (hash-table-set! test-registry (db:test-make-full-name test-name "") 'done)))) (runs:shrink-can-run-more-tests-count runsdat) ;; DELAY TWEAKER (still needed?) (if (and (null? tal)(null? reg)) (list hed tal (append reg (list hed)) reruns) (list (runs:queue-next-hed tal reg reglen regfull) ;; cannot replace with a call to runs:loop-values as the logic is different for reg (runs:queue-next-tal tal reg reglen regfull) ;; NB// Here we are building reg as we register tests ;; if regfull we must pop the front item off reg (if regfull (append (cdr reg) (list hed)) (append reg (list hed))) reruns))) |
︙ | ︙ | |||
879 880 881 882 883 884 885 886 887 | (and (member 'toplevel testmode) ;; 'toplevel) (null? non-completed) (not (member 'exclusive testmode))))) ;; (hash-table-delete! *max-tries-hash* (db:test-make-full-name test-name item-path)) ;; we are going to reset all the counters for test retries by setting a new hash table ;; this means they will increment only when nothing can be run (set! *max-tries-hash* (make-hash-table)) ;; well, first lets see if cpu load throttling is enabled. If so wait around until the ;; average cpu load is under the threshold before continuing | > > > | > | > > > > < | < < | 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 | (and (member 'toplevel testmode) ;; 'toplevel) (null? non-completed) (not (member 'exclusive testmode))))) ;; (hash-table-delete! *max-tries-hash* (db:test-make-full-name test-name item-path)) ;; we are going to reset all the counters for test retries by setting a new hash table ;; this means they will increment only when nothing can be run (set! *max-tries-hash* (make-hash-table)) ;; well, first lets see if cpu load throttling is enabled. If so wait around until the ;; average cpu load is under the threshold before continuing ;; jobtools maxload is useful for where the full Megatest run is done on one machine (if maxload ;; only gate if maxload is specified, NOTE: maxload is normalized, i.e. load=1 means all cpus fully utilized (common:wait-for-normalized-load maxload "Waiting for load to drop before starting more tests" #f)) ;; jobtools maxhomehostload is intended to prevent overloading on the homehost which can cause database corruption issues (if maxhomehostload (common:wait-for-homehost-load maxhomehostload (conc "Waiting for homehost load to drop below normalized value of " maxhomehostload))) (run:test run-id run-info keyvals runname test-record flags #f test-registry all-tests-registry) (runs:incremental-print-results run-id) (hash-table-set! test-registry (db:test-make-full-name test-name item-path) 'running) (runs:shrink-can-run-more-tests-count runsdat) ;; DELAY TWEAKER (still needed?) ;; (thread-sleep! *global-delta*) (if (or (not (null? tal))(not (null? reg))) (runs:loop-values tal reg reglen regfull reruns) #f)) ;; must be we have unmet prerequisites ;; (else (debug:print 4 *default-log-port* "FAILS: " fails) ;; If one or more of the prereqs-not-met are FAIL then we can issue |
︙ | ︙ | |||
916 917 918 919 920 921 922 | (begin ;; couldn't run, take a breather (if (runs:lownoise "Waiting for more work to do..." 60) (debug:print-info 0 *default-log-port* "Waiting for more work to do...")) (thread-sleep! 1) (list (car newtal)(cdr newtal) reg reruns)) ;; the waiton is FAIL so no point in trying to run hed ever again | > > > > > > | | | > > > > | > < | < < < | > | < | < < | | < < < < | < < | | | > | < | | | | > > | | | < | < > > | | 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 | (begin ;; couldn't run, take a breather (if (runs:lownoise "Waiting for more work to do..." 60) (debug:print-info 0 *default-log-port* "Waiting for more work to do...")) (thread-sleep! 1) (list (car newtal)(cdr newtal) reg reruns)) ;; the waiton is FAIL so no point in trying to run hed ever again (begin (let ((my-test-id (rmt:get-test-id run-id test-name item-path))) (mt:test-set-state-status-by-id-unless-completed run-id my-test-id "COMPLETED" "PREQ_FAIL" "Failed to run due to failed prerequisites2")) (if (or (not (null? reg))(not (null? tal))) (if (vector? hed) (begin (debug:print 1 *default-log-port* "WARNING: Dropping test " test-name "/" item-path " from the launch list as it has prerequistes that are FAIL") (let ((test-id (rmt:get-test-id run-id hed ""))) (if test-id (mt:test-set-state-status-by-id-unless-completed run-id test-id "COMPLETED" "PREQ_FAIL" "Failed to run due to failed prerequisites"))) (runs:shrink-can-run-more-tests-count runsdat) ;; DELAY TWEAKER (still needed?) ;; (thread-sleep! *global-delta*) ;; This next is for the items (if (not (null? fails)) ;;(mt:test-set-state-status-by-testname run-id test-name item-path "NOT_STARTED" "PREQ_FAIL" #f) (rmt:set-state-status-and-roll-up-items run-id test-name item-path "NOT_STARTED" "PREQ_FAIL" #f) ;;(mt:test-set-state-status-by-testname run-id test-name item-path "NOT_STARTED" "BLOCKED" #f) (rmt:set-state-status-and-roll-up-items run-id test-name item-path "NOT_STARTED" "BLOCKED" #f) ) (hash-table-set! test-registry (db:test-make-full-name test-name item-path) 'removed) (runs:loop-values tal reg reglen regfull reruns)) (let ((nth-try (hash-table-ref/default test-registry hed 0))) ;; hed not a vector... (debug:print 2 *default-log-port* "nth-try("hed")="nth-try) (cond ((member "RUNNING" (map db:test-get-state prereqs-not-met)) (if (runs:lownoise (conc "possible RUNNING prerequistes " hed) 60) (debug:print 0 *default-log-port* "WARNING: test " hed " has possible RUNNING prerequisites, don't give up on it yet.")) (thread-sleep! 0.1) (runs:loop-values tal reg reglen regfull reruns)) ((or (not nth-try) ;; BB: condition on subsequent tries, condition below fires on first try (and (number? nth-try) (< nth-try 2))) (hash-table-set! test-registry hed (if (number? nth-try) (+ nth-try 1) 0)) (if (runs:lownoise (conc "not removing test " hed) 60) (debug:print 1 *default-log-port* "WARNING: not removing test " hed " from queue although it may not be runnable due to FAILED prerequisites")) ;; may not have processed correctly. Could be a race condition in your test implementation? Dropping test " hed) ;; " as it has prerequistes that are FAIL. (NOTE: hed is not a vector)") (runs:shrink-can-run-more-tests-count runsdat) ;; DELAY TWEAKER (still needed?) (runs:loop-values newtal reg reglen regfull reruns)) ((symbol? nth-try) ;; BB: 'done matches here in one case where prereq itemwait failed. This is first "try" (if (eq? nth-try 'removed) ;; removed is removed - drop it NOW (if (null? tal) #f ;; yes, really (list (car tal)(cdr tal) reg reruns)) (begin (if (runs:lownoise (conc "FAILED prerequisites or other issue" hed) 60) (debug:print 0 *default-log-port* "WARNING: test " hed " has FAILED prerequisites or other issue. Internal state >" nth-try "< will be overridden and we'll retry.")) ;; was: (mt:test-set-state-status-by-testname run-id test-name item-path "NOT_STARTED" "KEEP_TRYING" #f) (mt:test-set-state-status-by-testname-unless-completed run-id test-name item-path "COMPLETED" "PREQ_FAIL" #f) (hash-table-set! test-registry hed 'removed) ;; was 0 (if (not (and (null? reg) (null? tal))) (runs:loop-values tal reg reglen regfull reruns) #f)))) (else (if (runs:lownoise (conc "FAILED prerequitests and we tried" hed) 60) (debug:print 0 *default-log-port* "WARNING: test " hed " has FAILED prerequitests and we've tried at least 10 times to run it. Giving up now.")) ;; (debug:print 0 *default-log-port* " prereqs: " prereqs-not-met) (hash-table-set! test-registry hed 'removed) (mt:test-set-state-status-by-testname run-id test-name item-path "NOT_STARTED" "TEN_STRIKES" #f) ;; I'm unclear on if this roll up is needed - it may be the root cause of the "all set to FAIL" bug. (rmt:set-state-status-and-roll-up-items run-id test-name item-path #f "FAIL" #f) ;; treat as FAIL (list (if (null? tal)(car newtal)(car tal)) tal reg reruns))))) ;; ELSE: can't drop this - maybe running? Just keep trying ;;(if (not (or (not (null? reg))(not (null? tal)))) ;; old experiment (let ((runable-tests (runs:runable-tests prereqs-not-met))) ;; SUSPICIOUS: Should look at more than just prereqs-not-met? (if (null? runable-tests) #f ;; I think we are truly done here (runs:loop-values newtal reg reglen regfull reruns))) ;;) ;;from old experiment ) ;; end if (or (not (null? reg))(not (null? tal))) )))))) ;; scan a list of tests looking to see if any are potentially runnable ;; (define (runs:runable-tests tests) (filter (lambda (t) (if (not (vector? t)) t |
︙ | ︙ | |||
1026 1027 1028 1029 1030 1031 1032 | inc-results: (make-hash-table) inc-results-last-update: 0 inc-results-fmt: "~12a~12a~20a~12a~40a\n" ;; state status time duration test-name item-path run-info: #f runname: #f target: #f ) | | > | | | | | | | | > > > > > > > | 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 | inc-results: (make-hash-table) inc-results-last-update: 0 inc-results-fmt: "~12a~12a~20a~12a~40a\n" ;; state status time duration test-name item-path run-info: #f runname: #f target: #f ) ) (define (runs:incremental-print-results run-id) (let ((curr-sec (current-seconds))) (if (> (- curr-sec (runs:gendat-inc-results-last-update *runs:general-data*)) 5) ;; at least five seconds since last update (let* ((run-dat (or (runs:gendat-run-info *runs:general-data*)(rmt:get-run-info run-id))) (runname (or (runs:gendat-runname *runs:general-data*) (db:get-value-by-header (db:get-rows run-dat) (db:get-header run-dat) "runname"))) (target (or (runs:gendat-target *runs:general-data*)(rmt:get-target run-id))) (testsdat (let ((res (rmt:get-tests-for-run run-id "%" '() '() ;; run-id testpatt states statuses #f #f ;; offset limit #f ;; not-in #f ;; sort-by #f ;; sort-order #f ;; get full data (not 'shortlist) (runs:gendat-inc-results-last-update *runs:general-data*) ;; last update time 'dashboard))) (if (list? res) res (begin (debug:print-error 0 *default-log-port* "FAILED TO GET DATA using rmt:get-tests-for-run. Notify developers if you see this. result: " res) '()))))) (if (not (runs:gendat-run-info *runs:general-data*)) (runs:gendat-run-info-set! *runs:general-data* run-dat)) (if (not (runs:gendat-runname *runs:general-data*)) (runs:gendat-runname-set! *runs:general-data* runname)) (if (not (runs:gendat-target *runs:general-data*)) (runs:gendat-target-set! *runs:general-data* target)) (for-each |
︙ | ︙ | |||
1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 | (runs:gendat-inc-results-last-update-set! *runs:general-data* (- curr-sec 10)))) ;; every time though the loop increment the test/itempatt val. ;; when the min is > max-allowed and none running then force exit ;; (define *max-tries-hash* (make-hash-table)) ;; test-records is a hash table testname:item_path => vector < testname testconfig waitons priority items-info ... > (define (runs:run-tests-queue run-id runname test-records keyvals flags test-patts required-tests reglen-in all-tests-registry) ;; At this point the list of parent tests is expanded ;; NB// Should expand items here and then insert into the run queue. (debug:print 5 *default-log-port* "test-records: " test-records ", flags: " (hash-table->alist flags)) ;; Do mark-and-find clean up of db before starting runing of quue ;; ;; (rmt:find-and-mark-incomplete) | > > > > | | | | | | | | < < < | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | < > > > > > > > > > > > > > > > > > > > > | > | > > > | | | | | | 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 | (runs:gendat-inc-results-last-update-set! *runs:general-data* (- curr-sec 10)))) ;; every time though the loop increment the test/itempatt val. ;; when the min is > max-allowed and none running then force exit ;; (define *max-tries-hash* (make-hash-table)) ;;====================================================================== ;; runs:run-tests-queue is called by runs:run-tests ;;====================================================================== ;; ;; test-records is a hash table testname:item_path => vector < testname testconfig waitons priority items-info ... > (define (runs:run-tests-queue run-id runname test-records keyvals flags test-patts required-tests reglen-in all-tests-registry) ;; At this point the list of parent tests is expanded ;; NB// Should expand items here and then insert into the run queue. (debug:print 5 *default-log-port* "test-records: " test-records ", flags: " (hash-table->alist flags)) ;; Do mark-and-find clean up of db before starting runing of quue ;; ;; (rmt:find-and-mark-incomplete) (let* ((run-info (rmt:get-run-info run-id)) (tests-info (mt:get-tests-for-run run-id #f '() '())) ;; qryvals: "id,testname,item_path")) (sorted-test-names (tests:sort-by-priority-and-waiton test-records)) (test-registry (make-hash-table)) (registry-mutex (make-mutex)) (num-retries 0) (max-retries (configf:lookup *configdat* "setup" "maxretries")) (max-concurrent-jobs (configf:lookup-number *configdat* "setup" "max_concurrent_jobs" default: 50)) (reglen (if (number? reglen-in) reglen-in 1)) (last-time-incomplete (- (current-seconds) 900)) ;; force at least one clean up cycle (last-time-some-running (current-seconds)) ;; (tdbdat (tasks:open-db)) (runsdat (make-runs:dat ;; hed: hed ;; tal: tal ;; reg: reg ;; reruns: reruns reglen: reglen regfull: #f ;; regfull ;; test-record: test-record runname: runname ;; test-name: test-name ;; item-path: item-path ;; jobgroup: jobgroup max-concurrent-jobs: max-concurrent-jobs run-id: run-id ;; waitons: waitons ;; testmode: testmode test-patts: test-patts required-tests: required-tests test-registry: test-registry registry-mutex: registry-mutex flags: flags keyvals: keyvals run-info: run-info ;; newtal: newtal all-tests-registry: all-tests-registry ;; itemmaps: itemmaps ;; prereqs-not-met: (rmt:get-prereqs-not-met run-id waitons hed item-path mode: testmode itemmaps: itemmaps) ;; can-run-more-tests: (runs:can-run-more-tests run-id jobgroup max-concurrent-jobs) ;; look at the test jobgroup and tot jobs running ))) ;; Initialize the test-registery hash with tests that already have a record ;; convert state to symbol and use that as the hash value (for-each (lambda (trec) (let ((id (db:test-get-id trec)) (tn (db:test-get-testname trec)) (ip (db:test-get-item-path trec)) (st (db:test-get-state trec))) (if (not (equal? st "DELETED")) (hash-table-set! test-registry (db:test-make-full-name tn ip) (string->symbol st))))) tests-info) (set! max-retries (if (and max-retries (string->number max-retries))(string->number max-retries) 100)) (let loop ((hed (car sorted-test-names)) (tal (cdr sorted-test-names)) (reg '()) ;; registered, put these at the head of tal (reruns '())) (runs:incremental-print-results run-id) (if (not (null? reruns))(debug:print-info 4 *default-log-port* "reruns=" reruns)) ;; Here we mark any old defunct tests as incomplete. Do this every fifteen minutes ;; moving this to a parallel thread and just run it once. ;; (if (> (current-seconds)(+ last-time-incomplete 900)) (begin (set! last-time-incomplete (current-seconds)) ;; (rmt:find-and-mark-incomplete-all-runs) )) ;; (print "Top of loop, hed=" hed ", tal=" tal " ,reruns=" reruns) (let* ((test-record (hash-table-ref test-records hed)) (test-name (tests:testqueue-get-testname test-record)) (tconfig (tests:testqueue-get-testconfig test-record)) (jobgroup (configf:lookup tconfig "test_meta" "jobgroup")) (testmode (let ((m (configf:lookup tconfig "requirements" "mode"))) (if m (map string->symbol (string-split m)) '(normal)))) (itemmaps (tests:get-itemmaps tconfig)) ;; (configf:lookup tconfig "requirements" "itemmap")) (priority (tests:testqueue-get-priority test-record)) (itemdat (tests:testqueue-get-itemdat test-record)) ;; itemdat can be a string, list or #f (items (tests:testqueue-get-items test-record)) (item-path (item-list->path itemdat)) (tfullname (db:test-make-full-name test-name item-path)) ;; these are hard coded item-item waits test/item-path => test/item-path2 ... (extra-waits (let* ((section (configf:get-section (tests:testqueue-get-testconfig test-record) "waitons")) (myextra (alist-ref tfullname section equal?))) (if myextra (let ((extras (string-split (car myextra)))) (if (runs:lownoise (conc tfullname "extra-waitons" tfullname) 60) (debug:print-info 0 *default-log-port* "HAVE EXTRA WAITONS for test " tfullname ": " myextra)) (for-each (lambda (extra) ;; (debug:print 0 *default-log-port* "FYI: extra = " extra " reruns = " reruns) (let ((basetestname (car (string-split extra "/")))) #;(if (not (member extra tal)) (set! reruns (append tal (list extra)))) (if (not (member basetestname tal)) (set! reruns (append tal (list basetestname)))) )) extras) extras) '()))) (waitons (delete-duplicates (append (tests:testqueue-get-waitons test-record) extra-waits) equal?)) (newtal (append tal (list hed))) (regfull (>= (length reg) reglen)) (num-running (rmt:get-count-tests-running-for-run-id run-id)) (testdat (make-runs:testdat hed: hed tal: tal reg: reg reruns: reruns test-record: test-record test-name: test-name item-path: item-path jobgroup: jobgroup waitons: waitons testmode: testmode newtal: newtal itemmaps: itemmaps ;; prereqs-not-met: prereqs-not-met ))) (runs:dat-regfull-set! runsdat regfull) ;; -- removed BB 17ww28 - no longer needed. ;; every 15 minutes verify the server is there for this run ;; (if (and (common:low-noise-print 240 "try start server" run-id) ;; (not (or (and *runremote* ;; (remote-server-url *runremote*) ;; (server:ping (remote-server-url *runremote*))) ;; (server:check-if-running *toppath*)))) ;; (server:kind-run *toppath*)) (if (> num-running 0) (set! last-time-some-running (current-seconds))) (if (> (current-seconds)(+ last-time-some-running (or (configf:lookup *configdat* "setup" "give-up-waiting") 36000))) (hash-table-set! *max-tries-hash* tfullname (+ (hash-table-ref/default *max-tries-hash* tfullname 0) 1))) ;; (debug:print 0 *default-log-port* "max-tries-hash: " (hash-table->alist *max-tries-hash*)) ;; Ensure all top level tests get registered. This way they show up as "NOT_STARTED" on the dashboard ;; and it is clear they *should* have run but did not. (if (not (hash-table-ref/default test-registry (db:test-make-full-name test-name "") #f)) (begin (rmt:register-test run-id test-name "") |
︙ | ︙ | |||
1236 1237 1238 1239 1240 1241 1242 | (if (runs:lownoise (conc "been marked do not run " tfullname) 60) (debug:print-info 0 *default-log-port* "Skipping test " tfullname " as it has been marked do not run due to being completed or not runnable")) (if (or (not (null? tal))(not (null? reg))) (loop (runs:queue-next-hed tal reg reglen regfull) (runs:queue-next-tal tal reg reglen regfull) (runs:queue-next-reg tal reg reglen regfull) reruns)))) | | < > > > | < | < > | 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 | (if (runs:lownoise (conc "been marked do not run " tfullname) 60) (debug:print-info 0 *default-log-port* "Skipping test " tfullname " as it has been marked do not run due to being completed or not runnable")) (if (or (not (null? tal))(not (null? reg))) (loop (runs:queue-next-hed tal reg reglen regfull) (runs:queue-next-tal tal reg reglen regfull) (runs:queue-next-reg tal reg reglen regfull) reruns)))) ;; (loop (car tal)(cdr tal) reg reruns)))) (runs:incremental-print-results run-id) (debug:print 4 *default-log-port* "TOP OF LOOP => " "test-name: " test-name "\n hed: " hed "\n tal: " tal "\n reg: " reg "\n test-record " test-record "\n itemdat: " itemdat "\n items: " items "\n item-path: " item-path "\n waitons: " waitons "\n num-retries: " num-retries "\n reruns: " reruns "\n regfull: " regfull "\n reglen: " reglen "\n length reg: " (length reg) ) ;; check for hed in waitons => this would be circular, remove it and issue an ;; error (if (member test-name waitons) (begin (debug:print-error 0 *default-log-port* "test " test-name " has listed itself as a waiton, please correct this!") (set! waiton (filter (lambda (x)(not (equal? x hed))) waitons)))) |
︙ | ︙ | |||
1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 | number? (map (lambda (waiton) (if (and (not (member waiton tal)) ;; this waiton is not in the list to be tried to run (not (member waiton reruns))) 1 #f)) waitons))))) ;; could do this more elegantly with a marker.... (debug:print 0 *default-log-port* "WARNING: Marking test " tfullname " as not runnable. It is waiting on tests that cannot be run. Giving up now.") (hash-table-set! test-registry tfullname 'removed)) ;; items is #f then the test is ok to be handed off to launch (but not before) ;; ((not items) (debug:print-info 4 *default-log-port* "OUTER COND: (not items)") (if (and (not (tests:match test-patts (tests:testqueue-get-testname test-record) item-path required: required-tests)) (not (null? tal))) (loop (car tal)(cdr tal) reg reruns)) (runs:testdat-prereqs-not-met-set! testdat (rmt:get-prereqs-not-met run-id waitons hed item-path mode: testmode itemmaps: itemmaps)) (runs:dat-can-run-more-tests-set! runsdat (runs:can-run-more-tests runsdat run-id jobgroup max-concurrent-jobs)) ;; look at the test jobgroup and tot jobs running (let ((loop-list (runs:process-expanded-tests runsdat testdat))) | > > | > | | | | | | | | > > | > > > > > > > | | | | | | | | | | | | | | | > | | > > > | > > > > > > > > | | | 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 | number? (map (lambda (waiton) (if (and (not (member waiton tal)) ;; this waiton is not in the list to be tried to run (not (member waiton reruns))) 1 #f)) waitons))))) ;; could do this more elegantly with a marker.... (debug:print-info 4 *default-log-port* "cond branch - " "rtq-1") (debug:print 0 *default-log-port* "WARNING: Marking test " tfullname " as not runnable. It is waiting on tests that cannot be run. Giving up now.") (hash-table-set! test-registry tfullname 'removed)) ;; items is #f then the test is ok to be handed off to launch (but not before) ;; ((not items) (debug:print-info 4 *default-log-port* "cond branch - " "rtq-2") (debug:print-info 4 *default-log-port* "OUTER COND: (not items)") (if (and (not (tests:match test-patts (tests:testqueue-get-testname test-record) item-path required: required-tests)) (not (null? tal))) (loop (car tal)(cdr tal) reg reruns)) (runs:testdat-prereqs-not-met-set! testdat (rmt:get-prereqs-not-met run-id waitons hed item-path mode: testmode itemmaps: itemmaps)) (runs:dat-can-run-more-tests-set! runsdat (runs:can-run-more-tests runsdat run-id jobgroup max-concurrent-jobs)) ;; look at the test jobgroup and tot jobs running (let ((loop-list (runs:process-expanded-tests runsdat testdat))) (if loop-list (apply loop loop-list)))) ;; items processed into a list but not came in as a list been processed ;; ((and (list? items) ;; thus we know our items are already calculated (not itemdat)) ;; and not yet expanded into the list of things to be done (debug:print-info 4 *default-log-port* "cond branch - " "rtq-3") (debug:print-info 4 *default-log-port* "OUTER COND: (and (list? items)(not itemdat))") ;; Must determine if the items list is valid. Discard the test if it is not. (if (and (list? items) (> (length items) 0) (and (list? (car items)) (> (length (car items)) 0)) (debug:debug-mode 1)) (debug:print 2 *default-log-port* (map (lambda (row) (conc (string-intersperse (map (lambda (varval) (string-intersperse varval "=")) row) " ") "\n")) items))) (let* ((items-in-testpatt (filter (lambda (my-itemdat) (tests:match test-patts hed (item-list->path my-itemdat) )) ;; was: (tests:match test-patts hed (item-list->path my-itemdat) required: required-tests)) items) )) (if (null? items-in-testpatt) (debug:print-error 0 *default-log-port* "Test " (tests:testqueue-get-testname test-record) " is itemized but has no items matching the test pattern") (for-each (lambda (my-itemdat) (let* ((new-test-record (let ((newrec (make-tests:testqueue))) (vector-copy! test-record newrec) newrec)) (my-item-path (item-list->path my-itemdat)) (newtestname (db:test-make-full-name hed my-item-path))) ;; test names are unique on testname/item-path (tests:testqueue-set-items! new-test-record #f) (tests:testqueue-set-itemdat! new-test-record my-itemdat) (tests:testqueue-set-item_path! new-test-record my-item-path) (hash-table-set! test-records newtestname new-test-record) (set! tal (append tal (list newtestname))))) ;; since these are itemized create new test names testname/itempath items-in-testpatt))) ;; At this point we have possibly added items to tal but all must be handed off to ;; INNER COND logic. I think loop without rotating the queue ;; (loop hed tal reg reruns)) ;; (let ((newtal (append tal (list hed)))) ;; We should discard hed as it has been expanded into it's items? Yes, but only if this *is* an itemized test ;; (loop (car newtal)(cdr newtal) reg reruns) (if (null? tal) #f (loop (car tal)(cdr tal) reg reruns))) ;; if items is a proc then need to run items:get-items-from-config, get the list and loop ;; - but only do that if resources exist to kick off the job ;; EXPAND ITEMS ((or (procedure? items)(eq? items 'have-procedure)) (debug:print-info 4 *default-log-port* "cond branch - " "rtq-4") (let ((can-run-more (runs:can-run-more-tests runsdat run-id jobgroup max-concurrent-jobs))) (if (and (list? can-run-more) (car can-run-more)) (let ((loop-list (runs:expand-items hed tal reg reruns regfull newtal jobgroup max-concurrent-jobs run-id waitons item-path testmode test-record can-run-more items runname tconfig reglen test-registry test-records itemmaps))) ;; itemized test expanded here (if loop-list (apply loop loop-list) (debug:print-info 4 *default-log-port* " -- Can't expand hed="hed) ) ) ;; if can't run more just loop with next possible test (loop (car newtal)(cdr newtal) reg reruns)))) ;; this case should not happen, added to help catch any bugs ((and (list? items) itemdat) (debug:print-info 4 *default-log-port* "cond branch - " "rtq-5") (debug:print-error 0 *default-log-port* "Should not have a list of items in a test and the itemspath set - please report this") (exit 1)) ((not (null? reruns)) (debug:print-info 4 *default-log-port* "cond branch - " "rtq-6") (let* ((newlst (tests:filter-non-runnable run-id tal test-records)) ;; i.e. not FAIL, WAIVED, INCOMPLETE, PASS, KILLED, (junked (lset-difference equal? tal newlst))) (debug:print-info 4 *default-log-port* "full drop through, if reruns is less than 100 we will force retry them, reruns=" reruns ", tal=" tal) (if (< num-retries max-retries) (set! newlst (append reruns newlst))) (set! num-retries (+ num-retries 1)) ;; (thread-sleep! (+ 1 *global-delta*)) (if (not (null? newlst)) ;; since reruns have been tacked on to newlst create new reruns from junked (loop (car newlst)(cdr newlst) reg (delete-duplicates junked))))) ((not (null? tal)) (debug:print-info 4 *default-log-port* "cond branch - " "rtq-7") (debug:print-info 4 *default-log-port* "I'm pretty sure I shouldn't get here.")) ((not (null? reg)) ;; could we get here with leftovers? (debug:print-info 4 *default-log-port* "cond branch - " "rtq-8") (debug:print-info 0 *default-log-port* "Have leftovers!") (loop (car reg)(cdr reg) '() reruns)) (else (debug:print-info 4 *default-log-port* "cond branch - " "rtq-9") (debug:print-info 4 *default-log-port* "Exiting loop with...\n hed=" hed "\n tal=" tal "\n reruns=" reruns)) ))) ;; end loop on sorted test names ;; this is the point where everything is launched and now you can mark the run in metadata table as all launched (rmt:set-var (conc "lunch-complete-" run-id) "yes") ;; now *if* -run-wait we wait for all tests to be done ;; Now wait for any RUNNING tests to complete (if in run-wait mode) (thread-sleep! 10) ;; I think there is a race condition here. Let states/statuses settle (let wait-loop ((num-running (rmt:get-count-tests-running-for-run-id run-id)) (prev-num-running 0)) ;; (debug:print-info 13 *default-log-port* "num-running=" num-running ", prev-num-running=" prev-num-running) (if (and (or (args:get-arg "-run-wait") (equal? (configf:lookup *configdat* "setup" "run-wait") "yes")) (> num-running 0)) (begin |
︙ | ︙ | |||
1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 | (if (not (eq? num-running prev-num-running)) (debug:print-info 0 *default-log-port* "run-wait specified, waiting on " num-running " tests in RUNNING, REMOTEHOSTSTART or LAUNCHED state at " (time->string (seconds->local-time (current-seconds))))) (thread-sleep! 5) ;; (wait-loop (rmt:get-count-tests-running-for-run-id run-id) num-running)))) (wait-loop (rmt:get-count-tests-running-for-run-id run-id) num-running)))) ;; LET* ((test-record ;; we get here on "drop through". All done! (debug:print-info 1 *default-log-port* "All tests launched"))) (define (runs:calc-fails prereqs-not-met) (filter (lambda (test) (and (vector? test) ;; not (string? test)) | > > > | | | 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 | (if (not (eq? num-running prev-num-running)) (debug:print-info 0 *default-log-port* "run-wait specified, waiting on " num-running " tests in RUNNING, REMOTEHOSTSTART or LAUNCHED state at " (time->string (seconds->local-time (current-seconds))))) (thread-sleep! 5) ;; (wait-loop (rmt:get-count-tests-running-for-run-id run-id) num-running)))) (wait-loop (rmt:get-count-tests-running-for-run-id run-id) num-running)))) ;; LET* ((test-record ;; we get here on "drop through". All done! ;; this is moved to runs:run-testes since this function is getting called twice to ensure everthing is completed. ;; (debug:print-info 0 *default-log-port* "Calling Post Hook") ;; (runs:run-post-hook run-id) (debug:print-info 1 *default-log-port* "All tests launched"))) (define (runs:calc-fails prereqs-not-met) (filter (lambda (test) (and (vector? test) ;; not (string? test)) (member (db:test-get-state test) '("INCOMPLETE" "COMPLETED")) ;; TODO: pull from *common:stuff...* (not (member (db:test-get-status test) '("PASS" "WARN" "CHECK" "WAIVED" "SKIP"))))) prereqs-not-met)) (define (runs:calc-prereq-fail prereqs-not-met) ;; REMOVEME since NOT_STARTED/PREQ_FAIL is now COMPLETED/PREQ_FAIL (filter (lambda (test) (and (vector? test) ;; not (string? test)) (equal? (db:test-get-state test) "NOT_STARTED") (not (member (db:test-get-status test) '("n/a" "KEEP_TRYING"))))) prereqs-not-met)) |
︙ | ︙ | |||
1450 1451 1452 1453 1454 1455 1456 1457 1458 | (conc (db:test-get-testname t) ":" (db:test-get-state t) "/" (db:test-get-status t)))) lst)) ;; parent-test is there as a placeholder for when parent-tests can be run as a setup step ;; (define (run:test run-id run-info keyvals runname test-record flags parent-test test-registry all-tests-registry) ;; All these vars might be referenced by the testconfig file reader (let* ((test-name (tests:testqueue-get-testname test-record)) (test-waitons (tests:testqueue-get-waitons test-record)) | > > > > > < < < < < < > > > > > > > > > > > > > < | | | 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 | (conc (db:test-get-testname t) ":" (db:test-get-state t) "/" (db:test-get-status t)))) lst)) ;; parent-test is there as a placeholder for when parent-tests can be run as a setup step ;; (define (run:test run-id run-info keyvals runname test-record flags parent-test test-registry all-tests-registry) ;; All these vars might be referenced by the testconfig file reader ;; ;; NEED to reprocess testconfig here, ensuring that item variables are available. ;; This is for Tal's issue with item-specific env vars not being set for use in skip. ;; HSD https://hsdes.intel.com/appstore/icf/index.html#/article?articleId=1408763273 ;; (let* ((test-name (tests:testqueue-get-testname test-record)) (test-waitons (tests:testqueue-get-waitons test-record)) (itemdat (tests:testqueue-get-itemdat test-record)) (item-path "") (db #f) (full-test-name #f)) ;; setting itemdat to a list if it is #f (if (not itemdat)(set! itemdat '())) (set! item-path (item-list->path itemdat)) (set! full-test-name (db:test-make-full-name test-name item-path)) (runs:set-megatest-env-vars run-id inrunname: runname testname: test-name itempath: item-path) ;; these may be needed by the launching process (let* ((test-conf ;; re-instate the tests:get-testconfig once the kinks are worked out. FIXME!!! ;; (tests:get-testconfig test-name item-path all-tests-registry #t force-create: #t)) (tests:testqueue-get-testconfig test-record )) (test-path (hash-table-ref all-tests-registry test-name)) ;; (conc *toppath* "/tests/" test-name)) ;; could use tests:get-testconfig here ... (force (hash-table-ref/default flags "-force" #f)) (rerun (hash-table-ref/default flags "-rerun" #f)) (keepgoing (hash-table-ref/default flags "-keepgoing" #f)) (incomplete-timeout (string->number (or (configf:lookup *configdat* "setup" "incomplete-timeout") "x"))) ) (debug:print-info 4 *default-log-port* "\nTESTNAME: " full-test-name "\n test-config: " (hash-table->alist test-conf) "\n itemdat: " itemdat ) (debug:print 2 *default-log-port* "Attempting to launch test " full-test-name) ;; (setenv "MT_TEST_NAME" test-name) ;; ;; (setenv "MT_ITEMPATH" item-path) ;; (setenv "MT_RUNNAME" runname) (change-directory *toppath*) ;; Here is where the test_meta table is best updated ;; Yes, another use of a global for caching. Need a better way? ;; ;; There is now a single call to runs:update-all-test_meta and this ;; per-test call is not needed. Given the delicacy of the move to ;; v1.55 this code is being left in place for the time being. ;; (if (not (hash-table-ref/default *test-meta-updated* test-name #f)) (begin (hash-table-set! *test-meta-updated* test-name #t) (runs:update-test_meta test-name test-conf))) ;; itemdat => ((ripeness "overripe") (temperature "cool") (season "summer")) (let* ((new-test-path (string-intersperse (cons test-path (map cadr itemdat)) "/")) (test-id (rmt:get-test-id run-id test-name item-path)) (testdat (if test-id (rmt:get-test-info-by-id run-id test-id) #f))) (if (not testdat) (let loop () |
︙ | ︙ | |||
1521 1522 1523 1524 1525 1526 1527 | (begin (debug:print-info 0 *default-log-port* "WARNING: server is overloaded, trying again in one second") (thread-sleep! 1) (loop))))) (if (not testdat) ;; should NOT happen (debug:print-error 0 *default-log-port* "failed to get test record for test-id " test-id)) (set! test-id (db:test-get-id testdat)) | | | 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 | (begin (debug:print-info 0 *default-log-port* "WARNING: server is overloaded, trying again in one second") (thread-sleep! 1) (loop))))) (if (not testdat) ;; should NOT happen (debug:print-error 0 *default-log-port* "failed to get test record for test-id " test-id)) (set! test-id (db:test-get-id testdat)) (if (common:file-exists? test-path) (change-directory test-path) (begin (debug:print-error 0 *default-log-port* "test run path not created before attempting to run the test. Perhaps you are running -remove-runs at the same time?") (change-directory *toppath*))) (case (if force ;; (args:get-arg "-force") 'NOT_STARTED (if testdat |
︙ | ︙ | |||
1587 1588 1589 1590 1591 1592 1593 | ;; currently running ((and skip-check (configf:lookup test-conf "skip" "prevrunning")) ;; run-ids = #f means *all* runs (let ((running-tests (rmt:get-tests-for-runs-mindata #f full-test-name '("RUNNING" "REMOTEHOSTSTART" "LAUNCHED") '() #f))) (if (not (null? running-tests)) ;; have to skip (set! skip-test "Skipping due to previous tests running")))) | > > | | > > | | > | > > > > > > > > > > > > > > > | 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 | ;; currently running ((and skip-check (configf:lookup test-conf "skip" "prevrunning")) ;; run-ids = #f means *all* runs (let ((running-tests (rmt:get-tests-for-runs-mindata #f full-test-name '("RUNNING" "REMOTEHOSTSTART" "LAUNCHED") '() #f))) (if (not (null? running-tests)) ;; have to skip (set! skip-test "Skipping due to previous tests running")))) ;; split the string and OR of file-exists? ((and skip-check (configf:lookup test-conf "skip" "fileexists")) (let* ((files (string-split (configf:lookup test-conf "skip" "fileexists"))) (existing (filter common:file-exists? files))) (if (not (null? existing)) ;; (common:file-exists? (configf:lookup test-conf "skip" "fileexists")) (set! skip-test (conc "Skipping due to existance of file(s) " (string-intersperse existing ", ")))))) ;; (configf:lookup test-conf "skip" "fileexists"))))) ((and skip-check (configf:lookup test-conf "skip" "filenotexists")) (let* ((files (string-split (configf:lookup test-conf "skip" "filenotexists"))) (existing (filter common:file-exists? files))) (if (null? existing) ;; (common:file-exists? (configf:lookup test-conf "skip" "filenotexists"))) (set! skip-test (conc "Skipping due to non existance of files " (string-intersperse files ", ")))))) ;; (configf:lookup test-conf "skip" "filenotexists"))))) ((and skip-check (configf:lookup test-conf "skip" "script")) (if (= (system (configf:lookup test-conf "skip" "script")) 0) (set! skip-test (conc "Skipping due to zero return value of script " (configf:lookup test-conf "skip" "script"))))) ((and skip-check (configf:lookup test-conf "skip" "rundelay")) ;; run-ids = #f means *all* runs (let* ((numseconds (common:hms-string->seconds (configf:lookup test-conf "skip" "rundelay"))) (running-tests (rmt:get-tests-for-runs-mindata #f full-test-name '("RUNNING" "REMOTEHOSTSTART" "LAUNCHED") '() #f)) (completed-tests (rmt:get-tests-for-runs-mindata #f full-test-name '("COMPLETED" "INCOMPLETE") '("PASS" "FAIL" "ABORT") #f)) ;; ironically INCOMPLETE is same as COMPLETED in this contex (last-run-times (map db:mintest-get-event_time completed-tests)) (time-since-last (- (current-seconds) (if (null? last-run-times) 0 (common:max last-run-times))))) (if (or (not (null? running-tests)) ;; have to skip if test is running (> numseconds time-since-last)) (set! skip-test (conc "Skipping due to previous test run less than " (configf:lookup test-conf "skip" "rundelay") " ago")))))) (if skip-test (begin (mt:test-set-state-status-by-id run-id test-id "COMPLETED" "SKIP" skip-test) (debug:print-info 1 *default-log-port* "SKIPPING Test " full-test-name " due to " skip-test)) ;; ;; Here the test is handed off to launch.scm for launch-test to complete the launch process ;; (if (not (launch-test test-id run-id run-info keyvals runname test-conf test-name test-path itemdat flags)) (begin (print "ERROR: Failed to launch the test. Exiting as soon as possible") (set! *globalexitstatus* 1) ;; (process-signal (current-process-id) signal/kill)))))))) ((KILLED) (debug:print 1 *default-log-port* "NOTE: " full-test-name " is already running or was explictly killed, use -force to launch it.") |
︙ | ︙ | |||
1632 1633 1634 1635 1636 1637 1638 | ;; (debug:print 2 *default-log-port* "NOTE: " test-name " is already running"))) (else (debug:print-error 0 *default-log-port* "Failed to launch test " full-test-name ". Unrecognised state " (test:get-state testdat)) (case (string->symbol (test:get-state testdat)) ((COMPLETED INCOMPLETE) (hash-table-set! test-registry (db:test-make-full-name test-name test-path) 'DONOTRUN)) (else | | | 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 | ;; (debug:print 2 *default-log-port* "NOTE: " test-name " is already running"))) (else (debug:print-error 0 *default-log-port* "Failed to launch test " full-test-name ". Unrecognised state " (test:get-state testdat)) (case (string->symbol (test:get-state testdat)) ((COMPLETED INCOMPLETE) (hash-table-set! test-registry (db:test-make-full-name test-name test-path) 'DONOTRUN)) (else (hash-table-set! test-registry (db:test-make-full-name test-name test-path) 'DONOTRUN))))))))) ;;====================================================================== ;; END OF NEW STUFF ;;====================================================================== (define (get-dir-up-n dir . params) (let ((dparts (string-split dir "/")) |
︙ | ︙ | |||
1668 1669 1670 1671 1672 1673 1674 | ;; then files other than *testdat.db* (directory-fold (lambda (f x) (let ((fullname (conc real-dir "/" f))) (if (not (string-search (regexp "testdat.db") f)) (runs:recursive-delete-with-error-msg fullname))) (+ 1 x)) | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | > > | < | | | | | | > > > > > > > < > | > > | | > > | > > | | | | | > > > > > > | > > > > > | < | | | | | | | > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | | | | | | | | | | | | | | | | | | | | | > > > > > > > > > > | > > > > > > > > > > > > > > > > > | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | > > | | > > > | | | > | > | > > > | | | < < > | | | > | > > > > > > < > > > | > | | > > > > > > > > > > > > > > > > | | | | | | | | 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 | ;; then files other than *testdat.db* (directory-fold (lambda (f x) (let ((fullname (conc real-dir "/" f))) (if (not (string-search (regexp "testdat.db") f)) (runs:recursive-delete-with-error-msg fullname))) (+ 1 x)) 0 real-dir #t) ;; then the entire directory (runs:recursive-delete-with-error-msg real-dir)) ;; cleanup often needs to remove all but the last N runs per target ;; ;; target-patts a1/b1/c1,a2/b2/c2 ... ;; ;; This will fail if called with empty target or a bad target (i.e. missing or extra fields) ;; (define (runs:get-hash-by-target target-patts runpatt) (let* ((targets (string-split target-patts ",")) (keys (rmt:get-keys)) (res-ht (make-hash-table))) ;; target -> ( runrecord1 runrecord2 ... ) (for-each (lambda (target-patt) (let ((runs (rmt:simple-get-runs runpatt #f #f target-patt))) (for-each (lambda (run) (let ((target (simple-run-target run))) (hash-table-set! res-ht target (cons run (hash-table-ref/default res-ht target '()))))) runs))) targets) res-ht)) ;; delete runs older than X (weeks, days, months years etc.) ;; delete redundant runs within a target - N is the input ;; delete redundant runs within a target IFF older than given date/time AND keep at least N ;; (define (runs:remove-all-but-last-n-runs-per-target target-patts runpatt num-to-keep #!key (actions '(print))) (let* ((runs-ht (runs:get-hash-by-target target-patts runpatt)) (age (if (args:get-arg "-age")(common:hms-string->seconds (args:get-arg "-age")) #f)) (age-mark (if age (- (current-seconds) age) (+ (current-seconds) 86400))) (precmd (or (args:get-arg "-precmd") ""))) (print "Actions: " actions) (for-each (lambda (target) (let* ((runs (hash-table-ref runs-ht target)) (sorted (sort runs (lambda (a b)(< (simple-run-event_time a)(simple-run-event_time b))))) (to-remove (let* ((len (length sorted)) (trim-amt (- len num-to-keep))) (if (> trim-amt 0) (take sorted trim-amt) '())))) (hash-table-set! runs-ht target to-remove) (print target ":") (for-each (lambda (run) (let ((remove (member run to-remove (lambda (a b) (eq? (simple-run-id a) (simple-run-id b)))))) (if (and age (> (simple-run-event_time run) age-mark)) (print "Skipping handling of " target "/" (simple-run-runname run) " as it is younger than " (args:get-arg "-age")) (for-each (lambda (action) (case action ((print) (print " " (simple-run-runname run) " " (time->string (seconds->local-time (simple-run-event_time run)) "WW%V.%u %H:%M:%S") " " (if remove "REMOVE" ""))) ((remove-runs) (if remove (system (conc precmd " megatest -remove-runs -target " target " -runname " (simple-run-runname run) " -testpatt %" (if (member 'kill-runs actions) ;; if kill-runs is specified then set -kill-wait to 0 " -kill-wait 0" ""))))) ((archive) (if remove (system (conc precmd " megatest -archive save-remove -target " target " -runname " (simple-run-runname run) " -testpatt %")))) ((kill-runs) (if remove (system (conc precmd " megatest -kill-runs -target " target " -runname " (simple-run-runname run) " -testpatt %")))) )) actions)))) sorted))) ;; (print "Sorted: " (map simple-run-event_time sorted)) ;; (print "Remove: " (map simple-run-event_time to-remove)))) (hash-table-keys runs-ht)) runs-ht)) (define (remove-last-path-directory path-in) (let* ((dparts (string-split path-in "/")) (path-out (conc "/" (string-intersperse (take dparts (- (length dparts) 1)) "/"))) ) path-out ) ) ;; (define (runs:remove-all-but-last-n-runs-per-target target-patts runpatt num-to-keep) ;; (let ((data (runs:get-all-but-most-recent-n-per-target target-patts runpatt num-to-keep))) ;; (for-each ;; (lambda (target) ;; (let ((runs-to-remove (hash-table-ref data target ))) ;; (for-each ;; (lambda (run) ;; (print "megatest -remove-runs -target " target " -runname " (simple-run-runname run) " -testpatt %")) ;; runs-to-remove))) ;; (hash-table-keys data)))) ;; Remove runs ;; fields are passing in through ;; action: ;; 'remove-runs ;; 'set-state-status ;; ;; NB// should pass in keys? ;; (define (runs:operate-on action target runnamepatt testpatt #!key (state #f)(status #f)(new-state-status #f)(mode #f)(options '())) (common:clear-caches) ;; clear all caches (let* ((db #f) ;; (tdbdat (tasks:open-db)) (keys (rmt:get-keys)) (rundat (mt:get-runs-by-patt keys runnamepatt target)) (header (vector-ref rundat 0)) (runs (vector-ref rundat 1)) (states (if state (string-split state ",") '())) (statuses (if status (string-split status ",") '())) (state-status (if (string? new-state-status) (string-split new-state-status ",") '(#f #f))) (rp-mutex (make-mutex)) (bup-mutex (make-mutex)) (keep-records (args:get-arg "-keep-records")) ;; used in conjunction with -remove-runs to keep the records, TODO: consolidate this with "mode". (test-records '())) ;; for tasks that we wish to operate on all tests in one fell swoop (let* ((write-access-actions '(remove-runs set-state-status archive run-wait kill-runs)) (dbfile (conc *toppath* "/megatest.db")) (readonly-mode (not (file-write-access? dbfile)))) (when (and readonly-mode (member action write-access-actions)) (debug:print-error 0 *default-log-port* "megatest.db is readonly. Cannot proceed with action ["action"] in which write-access isrequired .") (exit 1))) (debug:print-info 4 *default-log-port* "runs:operate-on => Header: " header " action: " action " new-state-status: " new-state-status) (if (> 2 (length state-status)) (begin (debug:print-error 0 *default-log-port* "the parameter to -set-state-status is a comma delimited string. E.g. COMPLETED,FAIL") (exit))) (for-each (lambda (run) (let ((runkey (string-intersperse (map (lambda (k) (db:get-value-by-header run header k)) keys) "/")) (dirs-to-remove (make-hash-table)) (proc-get-tests (lambda (run-id) (mt:get-tests-for-run run-id testpatt states statuses not-in: #f sort-by: (case action ((remove-runs) 'rundir) (else 'event_time)))))) (let* ((run-id (db:get-value-by-header run header "id")) (run-state (db:get-value-by-header run header "state")) (run-name (db:get-value-by-header run header "runname")) (tests (if (not (equal? run-state "locked")) (proc-get-tests run-id) '())) (lasttpath "/does/not/exist/I/hope") (lastrealpath "/does/not/exist/I/hope") ;; there may be a number of different disks used in the same run. (run-paths-hash (make-hash-table)) (worker-thread #f)) (debug:print-info 4 *default-log-port* "runs:operate-on run=" run ", header=" header) (if (not (null? tests)) (begin (case action ((kill-runs) (tasks:kill-runner target run-name "%") (debug:print 1 *default-log-port* "Killing tests for run: " runkey " " (db:get-value-by-header run header "runname")) ) ((remove-runs) ;; (if (tasks:need-server run-id)(tasks:start-and-wait-for-server tdbdat run-id 10)) ;; seek and kill in flight -runtests with % as testpatt here ;; (if (equal? testpatt "%") (tasks:kill-runner target run-name testpatt) ;; (debug:print 0 *default-log-port* "not attempting to kill any run launcher processes as testpatt is " testpatt)) (debug:print 1 *default-log-port* "Removing tests for run: " runkey " " (db:get-value-by-header run header "runname"))) ((set-state-status) ;; (if (tasks:need-server run-id)(tasks:start-and-wait-for-server tdbdat run-id 10)) (debug:print 1 *default-log-port* "Modifying state and staus for tests for run: " runkey " " (db:get-value-by-header run header "runname"))) ((print-run) (debug:print 1 *default-log-port* "Printing info for run " runkey ", run=" run ", tests=" tests ", header=" header) action) ((run-wait) (debug:print 1 *default-log-port* "Waiting for run " runkey ", run=" runnamepatt " to complete")) ((archive) (debug:print 1 *default-log-port* "Archiving/restoring (" (args:get-arg "-archive") ") data for run: " runkey " " (db:get-value-by-header run header "runname")) (let ((op (string->symbol (args:get-arg "-archive")))) (set! worker-thread (make-thread (lambda () (case op ((save save-remove keep-html) (archive:run-bup op run-id run-name tests rp-mutex bup-mutex)) ((restore) (archive:bup-restore op run-id run-name tests rp-mutex bup-mutex)) ((get) ;;; NOTE: This is a special case. We wish to operate on ALL tests in one go (set! test-records (append tests test-records))) (else (debug:print-error 0 *default-log-port* "unrecognised sub command " op " for -archive. Run \"megatest\" to see help") (exit)))) "archive-bup-thread")) (thread-start! worker-thread) (if (eq? op 'get) (thread-join! worker-thread)) ;; we need the test-records set to not overlap )) (else (debug:print-info 0 *default-log-port* "action not recognised " action))) ;; actions that operate on one test at a time can be handled below ;; (let ((sorted-tests (filter vector? (sort tests (lambda (a b)(let ((dira ;; (rmt:sdb-qry 'getstr (db:test-get-rundir a)) ;; ) ;; (filedb:get-path *fdb* (db:test-get-rundir a))) (dirb ;; (rmt:sdb-qry 'getstr (db:test-get-rundir b))) ;; ) ;; ((filedb:get-path *fdb* (db:test-get-rundir b)))) (if (and (string? dira)(string? dirb)) (> (string-length dira)(string-length dirb)) #f)))))) (toplevel-retries (make-hash-table)) ;; try three times to loop through and remove top level tests (test-retry-time (make-hash-table)) (backgrounded-remove-status (make-hash-table)) (backgrounded-remove-last-visit (make-hash-table)) (backgrounded-remove-result (make-hash-table)) (allow-run-time (string->number (or (args:get-arg "-kill-wait") "10")))) ;; seconds to allow for killing tests before just brutally killing 'em (let loop ((test (car sorted-tests)) (tal (cdr sorted-tests))) (let* ((test-id (db:test-get-id test)) (new-test-dat (rmt:get-test-info-by-id run-id test-id))) (if (not new-test-dat) (begin (debug:print-error 0 *default-log-port* "We have a test-id of " test-id " but no record was found. NOTE: No locking of records is done between processes, do not simultaneously remove the same run from two processes!") (if (not (null? tal)) (loop (car tal)(cdr tal)))) (let* ((item-path (db:test-get-item-path new-test-dat)) (test-name (db:test-get-testname new-test-dat)) (run-dir ;;(filedb:get-path *fdb* ;; (rmt:sdb-qry 'getid (db:test-get-rundir new-test-dat)) ;; ) ;; run dir is from the link tree (has-subrun (and (subrun:subrun-test-initialized? run-dir) (not (subrun:subrun-removed? run-dir)))) (test-state (db:test-get-state new-test-dat)) (test-status (db:test-get-status new-test-dat)) (test-fulln (db:test-get-fullname new-test-dat)) (uname (db:test-get-uname new-test-dat)) (toplevel-with-children (and (db:test-get-is-toplevel test) (> (rmt:test-toplevel-num-items run-id test-name) 0)))) (case action ((remove-runs) ;; if the test is a toplevel-with-children issue an error and do not remove (cond (toplevel-with-children (debug:print 0 *default-log-port* "WARNING: skipping removal of " test-fulln " with run-id " run-id " as it has sub tests") (hash-table-set! toplevel-retries test-fulln (+ (hash-table-ref/default toplevel-retries test-fulln 0) 1)) (if (> (hash-table-ref toplevel-retries test-fulln) 3) (if (not (null? tal)) (loop (car tal)(cdr tal))) ;; no else clause - drop it if no more in queue and > 3 tries (let ((newtal (append tal (list test)))) (loop (car newtal)(cdr newtal))))) ;; loop with test still in queue (has-subrun ;; (let ((last-visit (hash-table-ref/default backgrounded-remove-last-visit test-fulln 0)) (now (current-seconds)) (rem-status (hash-table-ref/default backgrounded-remove-status test-fulln 'not-started))) (case rem-status ((not-started) (debug:print 0 *default-log-port* "WARNING: postponing removal of " test-fulln " with run-id " run-id " as it has a subrun") (hash-table-set! backgrounded-remove-status test-fulln 'started) (hash-table-set! backgrounded-remove-last-visit test-fulln (current-seconds)) (common:send-thunk-to-background-thread (lambda () (let* ((subrun-remove-succeeded (subrun:remove-subrun run-dir keep-records))) (hash-table-set! backgrounded-remove-result test-fulln subrun-remove-succeeded) (hash-table-set! backgrounded-remove-status test-fulln 'done))) name: (conc "remove-subrun:"test-fulln)) ;; send to back of line, loop (let ((newtal (append tal (list test)))) (loop (car newtal)(cdr newtal))) ) ((started) ;; if last visit was within last second, sleep 1 second (if (< (- now last-visit) 1.0) (thread-sleep! 1.0)) (hash-table-set! backgrounded-remove-last-visit test-fulln (current-seconds)) ;; send to back of line, loop (let ((newtal (append tal (list test)))) (loop (car newtal)(cdr newtal))) ) ((done) ;; drop this one; if remaining, loop, else finish (hash-table-set! backgrounded-remove-last-visit test-fulln (current-seconds)) (let ((subrun-remove-succeeded (hash-table-ref/default backgrounded-remove-result test-fulln 'exception))) (cond ((eq? subrun-remove-succeeded 'exception) (let* ((logfile (subrun:get-log-path run-dir "remove"))) (debug:print 0 *default-log-port* "ERROR: removing subrun of of " test-fulln " with run-id " run-id " ; see logfile @ "logfile)) (if (not (null? tal)) (loop (car tal)(cdr tal)))) (subrun-remove-succeeded (debug:print 0 *default-log-port* "Now removing of " test-fulln " with run-id " run-id " since subrun was removed.") ;;(runs:remove-test-directory new-test-dat mode) ;; let normal case handle this. it will go thru loop again as non-subrun (let ((newtal (append tal (list test)))) (loop (car newtal)(cdr newtal)))) (else (let* ((logfile (subrun:get-log-path run-dir "remove"))) (debug:print 0 *default-log-port* "WARNING: removal of subrun failed. Please check "logfile" for details.")) ;; send to back of line, loop (will not match has-subrun next time through) (if (not (null? tal)) (loop (car tal)(cdr tal)))))) ) ) ; end case rem-status ) ; end let ); end cond has-subrun (else ;; BB - TODO - consider backgrounding to threads to delete tests (work below) (debug:print-info 0 *default-log-port* "test: " test-name " itest-state: " test-state) (if (member test-state (list "RUNNING" "LAUNCHED" "REMOTEHOSTSTART" "KILLREQ")) (begin (if (not (hash-table-ref/default test-retry-time test-fulln #f)) (begin ;; want to set to REMOVING BUT CANNOT do it here? (hash-table-set! test-retry-time test-fulln (current-seconds)))) (if (> (- (current-seconds)(hash-table-ref test-retry-time test-fulln)) allow-run-time) ;; This test is not in a correct state for cleaning up. Let's try some graceful shutdown steps first ;; Set the test to "KILLREQ" and wait five seconds then try again. Repeat up to five times then give ;; up and blow it away. (begin (debug:print 0 *default-log-port* "WARNING: could not gracefully remove test " test-fulln ", tried to kill it to no avail. Forcing state to FAILEDKILL and continuing") (mt:test-set-state-status-by-id run-id (db:test-get-id test) "FAILEDKILL" "n/a" #f) (thread-sleep! 1)) (begin (mt:test-set-state-status-by-id run-id (db:test-get-id test) "KILLREQ" "n/a" #f) (thread-sleep! 1))) ;; NOTE: This is suboptimal as the testdata will be used later and the state/status may have changed ... (if (null? tal) (loop new-test-dat tal) (loop (car tal)(append tal (list new-test-dat))))) (begin (let ((rundir (db:test-get-rundir new-test-dat))) (if (and (not (string= rundir "/tmp/badname")) (file-exists? rundir) (substring-index run-name rundir) (substring-index target rundir) ) (begin (set! lasttpath (db:test-get-rundir new-test-dat)) ;; remember this path for run removal (set! lastrealpath (remove-last-path-directory (resolve-pathname lasttpath))) (hash-table-set! run-paths-hash lastrealpath 1) (runs:remove-test-directory new-test-dat mode) ;; 'remove-all) ) (begin (debug:print 2 *default-log-port* "Not removing directory " rundir " because either it doesn't exist or has a bad name") (debug:print 2 *default-log-port* "Is /tmp/badname: " (string= rundir "/tmp/badname")) (debug:print 2 *default-log-port* "Exists: " (file-exists? rundir)) (debug:print 2 *default-log-port* "Has run-name: " (substring-index run-name rundir)) (debug:print 2 *default-log-port* "Has target: " (substring-index target rundir)) ;;PJH remove record from db no need to cleanup directory (case mode ((remove-data-only)(mt:test-set-state-status-by-id (db:test-get-run_id test)(db:test-get-id test) (db:test-get-state test)(db:test-get-status test) #f)) ((archive-remove) (mt:test-set-state-status-by-id (db:test-get-run_id test)(db:test-get-id test) "ARCHIVED" #f #f)) (else (rmt:delete-test-records (db:test-get-run_id test) (db:test-get-id test)))) ) ) ) (if (not (null? tal)) (loop (car tal)(cdr tal))))))) (rmt:update-run-stats run-id (rmt:get-raw-run-stats run-id))) ((kill-runs) ;; RUNNING -> KILLREQ ;; LAUNCHED,RUNNING,REMOTEHOSTSTART -> NOT STARTED (cond ((and has-subrun (member test-state (list "RUNNING" "LAUNCHED" "REMOTEHOSTSTART" "KILLREQ"))) (common:send-thunk-to-background-thread (lambda () (let* ((subrun-remove-succeeded (subrun:kill-subrun run-dir keep-records))) #t))) (if (not (null? tal)) (loop (car tal)(cdr tal))) ) ((member test-state (list "RUNNING" "LAUNCHED" "REMOTEHOSTSTART" "KILLREQ")) (debug:print 1 *default-log-port* "INFO: issuing killreq to test "test-fulln) (mt:test-set-state-status-by-id run-id (db:test-get-id test) "KILLREQ" "n/a" #f) (if (not (null? tal)) (loop (car tal)(cdr tal)))) ((and (member test-status '("PREQ_FAIL" "PREQ_DISCARDED" "BLOCKED" "ZERO_ITEMS" "KEEP_TRYING" "TEN_STRIKES" "TIMED_OUT"))) (rmt:set-state-status-and-roll-up-items run-id (db:test-get-id test) 'foo "NOT_STARTED" "n/a" (conc "kill-run moved from "test-state":"test-status" to NOT_STARTED:n/a")) ;;(mt:test-set-state-status-by-id run-id (db:test-get-id test) "NOT_STARTED" "n/a" (conc "kill-run moved from "test-state":"test-status" to NOT_STARTED:n/a")) (if (not (null? tal)) (loop (car tal)(cdr tal))) ) (else (if (not (null? tal)) (loop (car tal)(cdr tal))) ))) ((set-state-status) (let* ((new-state (car state-status)) (new-status (cadr state-status)) (test-id (db:test-get-id test)) (test-run-dir (db:test-get-rundir new-test-dat)) (has-subrun (and (subrun:subrun-test-initialized? test-run-dir) (not (subrun:subrun-removed? test-run-dir))))) (when has-subrun (common:send-thunk-to-background-thread (lambda () (subrun:set-state-status test-run-dir state status new-state-status) ) ) ) (debug:print-info 2 *default-log-port* "new state " new-state ", new status " new-status ) (mt:test-set-state-status-by-id run-id test-id new-state new-status #f)) (if (not (null? tal)) (loop (car tal)(cdr tal)))) ((run-wait) ;; BB TODO - manage has-subrun case (debug:print-info 2 *default-log-port* "still waiting, " (length tests) " tests still running") (thread-sleep! 10) (let ((new-tests (proc-get-tests run-id))) (if (null? new-tests) (debug:print-info 1 *default-log-port* "Run completed according to zero tests matching provided criteria.") (loop (car new-tests)(cdr new-tests))))) ((archive) ;; BB TODO - manage has-subrun case (if (and run-dir (not toplevel-with-children)) (let ((ddir (conc run-dir "/"))) (case (string->symbol (args:get-arg "-archive")) ((save save-remove keep-html) (if (common:file-exists? ddir) (debug:print-info 0 *default-log-port* "Estimating disk space usage for " test-fulln ": " (common:get-disk-space-used ddir))))))) (if (not (null? tal)) (loop (car tal)(cdr tal)))) ))) ) (if worker-thread (thread-join! worker-thread))) (common:join-backgrounded-threads)))) ;; remove the run if zero tests remain (if (eq? action 'remove-runs) (let* ((run-id (db:get-value-by-header run header "id")) ;; NB// masks run-id from above? (remtests (mt:get-tests-for-run run-id #f '("DELETED") '("n/a") not-in: #t))) (if (null? remtests) ;; no more tests remaining (let* ((linkspath (remove-last-path-directory lasttpath)) (runpaths (hash-table-keys run-paths-hash)) ) (debug:print 2 *default-log-port* "run-paths-hash: " (hash-table-keys run-paths-hash)) (debug:print 1 *default-log-port* "Removing target " target "run: " run-name) (if (not keep-records) (begin (debug:print 1 *default-log-port* "Removing DB records for the run.") (rmt:delete-run run-id) (rmt:delete-old-deleted-test-records)) ) (if (not (equal? linkspath "/does/not/exist/I")) (begin (debug:print 1 *default-log-port* "Recursively removing links dir " linkspath) (runs:recursive-delete-with-error-msg linkspath))) (for-each (lambda(runpath) (debug:print 1 *default-log-port* "Recursively removing runs dir " runpath) (runs:recursive-delete-with-error-msg runpath) ) runpaths ) ))))) )) runs) ;; special case - archive get (if (equal? (args:get-arg "-archive") "get") (archive:bup-get-data "get" #f #f test-records rp-mutex bup-mutex)) ) #t ) (define (runs:remove-test-directory test mode) ;; remove-data-only) (let* ((run-dir (db:test-get-rundir test)) ;; run dir is from the link tree (real-dir (if (common:file-exists? run-dir) ;; (resolve-pathname run-dir) (common:nice-path run-dir) #f)) (clean-mode (or mode 'remove-all)) (test-id (db:test-get-id test)) ;; (lock-key (conc "test-" test-id)) ;; (got-lock (let loop ((lock (rmt:no-sync-get-lock lock-key)) ;; (expire-time (+ (current-seconds) 30))) ;; give up on getting the lock and steal it after 15 seconds ;; (if (car lock) ;; #t ;; (if (> (current-seconds) expire-time) ;; (begin ;; (debug:print-info 0 *default-log-port* "Timed out waiting for a lock to clean test with id " test-id) ;; (rmt:no-sync-del! lock-key) ;; destroy the lock ;; (loop (rmt:no-sync-get-lock lock-key) expire-time)) ;; ;; (begin ;; (thread-sleep! 1) ;; (loop (rmt:no-sync-get-lock lock-key) expire-time))))))) ) (case clean-mode ((remove-data-only)(mt:test-set-state-status-by-id (db:test-get-run_id test)(db:test-get-id test) "CLEANING" "LOCKED" #f)) ((remove-all) (mt:test-set-state-status-by-id (db:test-get-run_id test)(db:test-get-id test) "REMOVING" "LOCKED" #f)) ((archive-remove) (mt:test-set-state-status-by-id (db:test-get-run_id test)(db:test-get-id test) "ARCHIVE_REMOVING" #f #f))) (debug:print-info 1 *default-log-port* "Attempting to remove " (if real-dir (conc " dir " real-dir " and ") "") " link " run-dir) (if (and real-dir (> (string-length real-dir) 5) (common:file-exists? real-dir)) ;; bad heuristic but should prevent /tmp /home etc. (let* ((realpath (resolve-pathname run-dir))) (debug:print-info 1 *default-log-port* "Recursively removing " realpath) (if (common:file-exists? realpath) (runs:safe-delete-test-dir realpath) (debug:print 0 *default-log-port* "WARNING: test dir " realpath " appears to not exist or is not readable"))) (if real-dir (debug:print 0 *default-log-port* "WARNING: directory " real-dir " does not exist") (debug:print 0 *default-log-port* "WARNING: no real directory corrosponding to link " run-dir ", nothing done"))) (if (symbolic-link? run-dir) (begin (debug:print-info 1 *default-log-port* "Removing symlink " run-dir) (handle-exceptions |
︙ | ︙ | |||
1925 1926 1927 1928 1929 1930 1931 | (delete-directory run-dir))) (if (and run-dir (not (member run-dir (list "n/a" "/tmp/badname")))) (debug:print 0 *default-log-port* "WARNING: not removing " run-dir " as it either doesn't exist or is not a symlink") (debug:print 0 *default-log-port* "NOTE: the run dir for this test is undefined. Test may have already been deleted.")) )) ;; Only delete the records *after* removing the directory. If things fail we have a record | | | | > > | > | | 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 | (delete-directory run-dir))) (if (and run-dir (not (member run-dir (list "n/a" "/tmp/badname")))) (debug:print 0 *default-log-port* "WARNING: not removing " run-dir " as it either doesn't exist or is not a symlink") (debug:print 0 *default-log-port* "NOTE: the run dir for this test is undefined. Test may have already been deleted.")) )) ;; Only delete the records *after* removing the directory. If things fail we have a record (case clean-mode ((remove-data-only)(mt:test-set-state-status-by-id (db:test-get-run_id test)(db:test-get-id test) (db:test-get-state test)(db:test-get-status test) #f)) ((archive-remove) (mt:test-set-state-status-by-id (db:test-get-run_id test)(db:test-get-id test) "ARCHIVED" #f #f)) (else (rmt:delete-test-records (db:test-get-run_id test) (db:test-get-id test)))) ;; (rmt:no-sync-del! lock-key) )) ;;====================================================================== ;; Routines for manipulating runs ;;====================================================================== ;; Since many calls to a run require pretty much the same setup ;; this wrapper is used to reduce the replication of code (define (general-run-call switchname action-desc proc) (let ((runname (common:args-get-runname)) (target (common:args-get-target))) (cond ((not target) (debug:print-error 0 *default-log-port* "Missing required parameter for " switchname ", you must specify the target with -target") (exit 3)) ((not runname) (debug:print-error 0 *default-log-port* "Missing required parameter for " switchname ", you must specify the run name with -runname runname") (exit 3)) (else (let (;; (db #f) (keys #f)) (if (launch:setup) (begin (full-runconfigs-read) ;; cache the run config ;; (launch:cache-config) ;; there are two independent config cache locations, turning this one off for now. MRW. ) ;; do not cache here - need to be sure runconfigs is processed (begin (debug:print 0 *default-log-port* "Failed to setup, exiting") (exit 1))) (set! keys (keys:config-get-fields *configdat*)) ;; have enough to process -target or -reqtarg here |
︙ | ︙ | |||
1994 1995 1996 1997 1998 1999 2000 | (define (runs:handle-locking target keys runname lock unlock user) (let* ((db #f) (rundat (mt:get-runs-by-patt keys runname target)) (header (vector-ref rundat 0)) (runs (vector-ref rundat 1))) (for-each (lambda (run) | | > > > > | | > > | | > > | | | | 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 | (define (runs:handle-locking target keys runname lock unlock user) (let* ((db #f) (rundat (mt:get-runs-by-patt keys runname target)) (header (vector-ref rundat 0)) (runs (vector-ref rundat 1))) (for-each (lambda (run) (let ((run-id (db:get-value-by-header run header "id")) (str (if lock "lock" "unlock"))) (if (or lock (and unlock (or (args:get-arg "-force") (begin (print "Do you really wish to unlock run " run-id "?\n y/n: ") (equal? "y" (read-line)))))) (begin (rmt:lock/unlock-run run-id lock unlock user) (debug:print-info 0 *default-log-port* "Done " str " on run id " run-id)) (debug:print-info 0 *default-log-port* "Skipping lock/unlock on " run-id)))) runs))) ;;====================================================================== ;; Rollup runs ;;====================================================================== ;; Update the test_meta table for this test (define (runs:update-test_meta test-name test-conf) (let ((currrecord (rmt:testmeta-get-record test-name))) (if (not currrecord) (begin (set! currrecord (make-vector 11 #f)) (rmt:testmeta-add-record test-name))) (for-each (lambda (key) (let* ((idx (cadr key)) (fld (car key)) (val (configf:lookup test-conf "test_meta" fld))) ;; (debug:print 5 *default-log-port* "idx: " idx " fld: " fld " val: " val) (if (and val (not (equal? (vector-ref currrecord idx) val))) (begin (print "Updating " test-name " " fld " to " val) (rmt:testmeta-update-field test-name fld val))))) '(("author" 2)("owner" 3)("description" 4)("reviewed" 5)("tags" 9)("jobgroup" 10))))) ;; find tests with matching tags, tagpatt is a string "tagpatt1,tagpatt2%, ..." ;; (define (runs:get-tests-matching-tags tagpatt) (let* ((tagdata (rmt:get-tests-tags)) (res '())) ;; list of tests that match one or more tags (for-each (lambda (row) (let* ((tag (car row)) (tests (cdr row))) (if (patt-list-match tag tagpatt) (set! res (append tests res))))) tagdata) res)) ;; Update test_meta for all tests (define (runs:update-all-test_meta db) (let ((test-names (tests:get-all))) ;; (tests:get-valid-tests))) (for-each (lambda (test-name) (let* ((test-conf (mt:lazy-read-test-config test-name))) (if test-conf (runs:update-test_meta test-name test-conf)))) (hash-table-keys test-names)))) ;; This could probably be refactored into one complex query ... ;; NOT PORTED - DO NOT USE YET ;; #;(define (runs:rollup-run keys runname user keyvals) (debug:print 4 *default-log-port* "runs:rollup-run, keys: " keys " -runname " runname " user: " user) (let* ((db #f) ;; register run operates on the main db (new-run-id (rmt:register-run keyvals runname "new" "n/a" user (args:get-arg "-contour"))) (prev-tests (rmt:get-matching-previous-test-run-records new-run-id "%" "%")) (curr-tests (mt:get-tests-for-run new-run-id "%/%" '() '())) (curr-tests-hash (make-hash-table))) |
︙ | ︙ | |||
2105 2106 2107 2108 2109 2110 2111 | (sqlite3:execute db (conc "INSERT OR REPLACE INTO test_data (test_id,category,variable,value,expected,tol,units,comment) " "SELECT " (db:test-get-id new-testdat) ",category,variable,value,expected,tol,units,comment FROM test_data WHERE test_id=?;") (db:test-get-id testdat)))) )) prev-tests))) | | > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 | (sqlite3:execute db (conc "INSERT OR REPLACE INTO test_data (test_id,category,variable,value,expected,tol,units,comment) " "SELECT " (db:test-get-id new-testdat) ",category,variable,value,expected,tol,units,comment FROM test_data WHERE test_id=?;") (db:test-get-id testdat)))) )) prev-tests))) (define doc-template '(*TOP* (*PI* xml "version='1.0'") (testsuite))) (define (runs:update-junit-test-reporter-xml run-id) (let* ( (junit-test-reporter (configf:lookup *configdat* "runs" "junit-test-reporter-xml")) (junit-test-report-dir (configf:lookup *configdat* "runs" "junit-test-report-dir")) (xml-dir (if (and junit-test-reporter (equal? junit-test-reporter "yes" )) (if junit-test-report-dir junit-test-report-dir (conc (getenv "MT_LINKTREE") "/" (getenv "MT_TARGET") "/" (getenv "MT_RUNNAME"))) #f)) (xml-ts-name (if xml-dir (conc (getenv "MT_TESTSUITENAME")"."(string-translate (getenv "MT_TARGET") "/" ".") "." (getenv "MT_RUNNAME")) #f)) (keyname (if xml-ts-name (common:get-signature xml-ts-name) #f)) (xml-path (if xml-dir (conc xml-dir "/" keyname ".xml") #f)) (test-data (if xml-dir (rmt:get-tests-for-run run-id "%" '() '() ;; run-id testpatt states statuses #f #f ;; offset limit #f ;; not-in #f ;; sort-by #f ;; sort-order #f ;; get full data (not 'shortlist) 0 ;; (runs:gendat-inc-results-last-update *runs:general-data*) ;; last update time #f) '())) (tests-count (if xml-dir (length test-data) #f))) (if (and junit-test-reporter (equal? junit-test-reporter "yes" )) (begin ;((sxml-modify! `("testsuite" insert-into (@ (name ,xml-ts-name) (tests ,tests-count)))) doc) (let loop ((test (car test-data)) (tail (cdr test-data)) (doc doc-template) (fail-cnt 0) (error-cnt 0)) (let* ((test-name (vector-ref test 2)) (test-itempath (vector-ref test 11)) (tc-name (conc test-name (if (and test-itempath (not (equal? test-itempath ""))) (conc "." (string-translate test-itempath "/" "." )) ""))) (test-state (vector-ref test 3)) (comment (vector-ref test 14)) (test-status (vector-ref test 4)) (exc-msg (conc "No bucket for State " test-state " Status " test-status)) (new-doc (cond ((member test-state (list "RUNNING" )) ((sxml-modify `("testsuite" insert-into (testcase (@ (name ,tc-name)) (inProgress)))) doc)) ((member test-state (list "LAUNCHED" "REMOTEHOSTSTART" "NOT_STARTED")) ((sxml-modify `("testsuite" insert-into (testcase (@ (name ,tc-name)) (inQueue)))) doc)) ((member test-status (list "PASS" "WARN" "WAIVED")) ((sxml-modify `("testsuite" insert-into (testcase (@ (name ,tc-name))))) doc)) ((member test-status (list "FAIL" "CHECK")) ((sxml-modify `("testsuite" insert-into (testcase (@ (name ,tc-name)) (failure (@ (message ,comment) (type "failure")))))) doc)) ((member test-status (list "DEAD" "KILLED" "ABORT" "PREQ_FAIL" "PREQ_DISCARDED")) ((sxml-modify `("testsuite" insert-into (testcase (@ (name ,tc-name)) (failure (@ (message ,comment) (type "error")))))) doc)) ((member test-status (list "SKIP")) ((sxml-modify `("testsuite" insert-into (testcase (@ (name ,tc-name)) (skipped (@ (type "skipped")))))) doc)) (else (debug:print 0 *default-log-port* (conc "What do I do with State " test-state " Status " test-status)) ((sxml-modify `("testsuite" insert-into (testcase (@ (name ,tc-name)) (failure (@ (message ,exc-msg) (type "error")))))) doc)))) (new-error-cnt (if (member test-status (list "DEAD" "KILLED" "ABORT" "PREQ_FAIL" "PREQ_DISCARDED")) (+ error-cnt 1) error-cnt)) (new-fail-cnt (if (member test-status (list "FAIL" "CHECK")) (+ fail-cnt 1) fail-cnt))) (if (null? tail) (let* ((final-doc ((sxml-modify `("testsuite" insert-into (@ (name ,xml-ts-name) (tests ,tests-count) (errors ,error-cnt) (failures ,fail-cnt)))) new-doc))) (debug:print 0 *default-log-port* "modify attrib error=" error-cnt " fail= " fail-cnt) (handle-exceptions exn (let* ((msg ((condition-property-accessor 'exn 'message) exn))) (debug:print 0 *default-log-port* (conc "WARNING: Failed to update file" xml-path". Message:" msg))) (if (not (file-exists? xml-dir)) (create-directory xml-dir #t)) (if (not (rmt:no-sync-get/default keyname #f)) (begin (rmt:no-sync-set keyname "on") (debug:print 0 *default-log-port* "creating xml at " xml-path) (with-output-to-file xml-path (lambda () (print (sxml-serializer#serialize-sxml final-doc ns-prefixes: (list (cons 'gnm "http://foo")))))) (rmt:no-sync-del! keyname)) (debug:print 0 *default-log-port* "Could not get the lock. Skip writing the xml file.")))) (loop (car tail) (cdr tail) new-doc new-fail-cnt new-error-cnt)))))))) ;; clean cache files (define (runs:clean-cache target runname toppath) (if target (if runname (let* ((linktree (common:get-linktree)) ;; (if toppath (configf:lookup *configdat* "setup" "linktree"))) (runtop (conc linktree "/" target "/" runname)) (files (if (common:file-exists? runtop) (append (glob (conc runtop "/.megatest*")) (glob (conc runtop "/.runconfig*"))) '()))) (if (null? files) (debug:print-info 0 *default-log-port* "No cached megatest or runconfigs files found. None removed.") (begin (debug:print-info 0 *default-log-port* "Removing cached files:\n " (string-intersperse files "\n ")) |
︙ | ︙ |
Added sample-sauth-paths.scm version [8a357aad38].
> > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | ;; Copyright 2006-2017, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. ;; (define *db-path* "/path/to/db") (define *exe-path* "/path/to/store/suids") (define *exe-src* "/path/to/spublish/and/sretrieve/executables") (define *sauth-path* "/path/to/production/sauthorize/exe") (define *super-users* '("user1" "user2")) |
Added sauth-common.scm version [28ffd8e69e].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 | ;; Copyright 2006-2017, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. ;; Create the sqlite db (define (sauthorize:db-do proc) (if (or (not *db-path*) (not (file-exists? *db-path*))) (begin (print 0 "[database]\nlocation " *db-path* " \n\n Is missing from the config file!") (exit 1))) (if (and *db-path* (directory? *db-path*) (file-read-access? *db-path*)) (let* ((dbpath (conc *db-path* "/sauthorize.db")) (writeable (file-write-access? dbpath)) (dbexists (file-exists? dbpath))) (handle-exceptions exn (begin (print 2 "ERROR: problem accessing db " dbpath ((condition-property-accessor 'exn 'message) exn)) (exit 1)) ;(print "calling proc " proc "db path " dbpath ) (call-with-database dbpath (lambda (db) ;(print 0 "calling proc " proc " on db " db) (set-busy-handler! db (busy-timeout 10000)) ;; 10 sec timeout (if (not dbexists)(sauthorize:initialize-db db)) (proc db))))) (print 0 "ERROR: invalid path for storing database: " *db-path*))) ;;execute a query (define (sauthorize:db-qry db qry) ;(print qry) (exec (sql db qry))) (define (sauthorize:do-as-calling-user proc) (let ((eid (current-effective-user-id)) (cid (current-user-id))) (if (not (eq? eid cid)) ;; running suid (set! (current-effective-user-id) cid)) ;(print 0 "cid " cid " eid:" eid) (proc) (if (not (eq? eid cid)) (set! (current-effective-user-id) eid)))) (define (run-cmd cmd arg-list) ; (print (current-effective-user-id)) ;(handle-exceptions ; exn ; (print 0 "ERROR: failed to run script " cmd " with params " arg-list " " (exn assert)) (let ((pid (process-run cmd arg-list))) (process-wait pid)) ) ;) (define (regster-log inl usr-id area-id cmd) (sauth-common:shell-do-as-adm (lambda () (sauthorize:db-do (lambda (db) (sauthorize:db-qry db (conc "INSERT INTO actions (cmd,user_id,area_id,action_type ) VALUES ('sretrieve " inl "'," usr-id "," area-id ", 'cat' )"))))))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Check user types ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;check if a user is an admin (define (is-admin username) (let* ((admin #f)) (sauthorize:db-do (lambda (db) (let* ((data-row (query fetch (sql db (conc "SELECT users.is_admin FROM users where users.username = '" username "'"))))) (if (not (null? data-row)) (let ((col (car data-row))) (if (equal? col "yes") (set! admin #t))))))) admin)) ;;check if a user is an read-admin (define (is-read-admin username) (let* ((admin #f)) (sauthorize:db-do (lambda (db) (let* ((data-row (query fetch (sql db (conc "SELECT users.is_admin FROM users where users.username = '" username "'"))))) (if (not (null? data-row)) (let ((col (car data-row))) (if (equal? col "read-admin") (set! admin #t))))))) admin)) ;;check if user has specifc role for a area (define (is-user role username area) (let* ((has-access #f)) (sauthorize:db-do (lambda (db) (let* ((data-row (query fetch (sql db (conc "SELECT permissions.access_type, permissions.expiration FROM users , areas, permissions where permissions.user_id = users.id and permissions.area_id = areas.id and users.username = '" username "' and areas.code = '" area "'"))))) (if (not (null? data-row)) (begin (let* ((access-type (car data-row)) (exdate (cadr data-row))) (if (not (null? exdate)) (begin (let ((valid (is-access-valid exdate))) ;(print valid) (if (and (equal? access-type role) (equal? valid #t)) (set! has-access #t)))) (print "Access expired")))))))) ;(print has-access) has-access)) (define (is-access-valid exp-str) (let* ((ret-val #f ) (date-parts (string-split exp-str "/")) (yr (string->number (car date-parts))) (month (string->number(car (cdr date-parts)))) (day (string->number(caddr date-parts))) (exp-date (make-date 0 0 0 0 day month yr ))) ;(print exp-date) ;(print (current-date)) (if (> (date-compare exp-date (current-date)) 0) (set! ret-val #t)) ;(print ret-val) ret-val)) ;check if area exists (define (area-exists area) (let* ((area-defined #f)) (sauthorize:db-do (lambda (db) (let* ((data-row (query fetch (sql db (conc "SELECT id FROM areas where areas.code = '" area "'"))))) (if (not (null? data-row)) (set! area-defined #t))))) area-defined)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Get Record from database ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;gets area id by code (define (get-area area) (let* ((area-defined '())) (sauthorize:db-do (lambda (db) (let* ((data-row (query fetch (sql db (conc "SELECT id FROM areas where areas.code = '" area "'"))))) (set! area-defined data-row)))) area-defined)) ;get id of users table by user name (define (get-user user) (let* ((user-defined '())) (sauthorize:db-do (lambda (db) (let* ((data-row (query fetch (sql db (conc "SELECT id FROM users where users.username = '" user "'"))))) (set! user-defined data-row)))) user-defined)) ;get permissions id by userid and area id (define (get-perm userid areaid) (let* ((user-defined '())) (sauthorize:db-do (lambda (db) (let* ((data-row (query fetch (sql db (conc "SELECT id FROM permissions where user_id = " userid " and area_id = " areaid))))) (set! user-defined data-row)))) user-defined)) (define (get-restrictions base-path usr) (let* ((user-defined '())) (sauthorize:db-do (lambda (db) (let* ((data-row (query fetch (sql db (conc "SELECT restriction FROM areas, users, permissions where areas.id = permissions.area_id and users.id = permissions.user_id and users.username = '" usr "' and areas.basepath = '" base-path "'"))))) ;(print data-row) (set! user-defined data-row)))) ; (print user-defined) (if (null? user-defined) "" (car user-defined)))) (define (get-obj-by-path path) (let* ((obj '())) (sauthorize:db-do (lambda (db) (let* ((data-row (query fetch (sql db (conc "SELECT code,exe_name, id, basepath FROM areas where areas.basepath = '" path "'"))))) (set! obj data-row)))) obj)) (define (get-obj-by-code code ) (let* ((obj '())) (sauthorize:db-do (lambda (db) ;(print (conc "SELECT code, exe_name, id, basepath, required_grps FROM areas where areas.code = '" code "'")) (let* ((data-row (query fetch (sql db (conc "SELECT code, exe_name, id, basepath, required_grps FROM areas where areas.code = '" code "'"))))) ;(print data-row) (set! obj data-row) ;(print obj) ))) (if (not (null? obj)) (begin (let* ((req-grp (caddr (cddr obj)))) (sauthorize:do-as-calling-user (lambda () (sauth-common:check-user-groups req-grp)))))) obj)) (define (sauth-common:check-user-groups req-grp) (let* ((current-groups (get-groups) ) (req-grp-list (string-split req-grp ","))) ;(print req-grp-list) (for-each (lambda (grp) (let ((grp-info (group-information grp))) ;(print grp-info " " grp) (if (not (equal? grp-info #f)) (begin (if (not (member (caddr grp-info) current-groups)) (begin (sauth:print-error (conc "Please wash " grp " group in your xterm!! " )) (exit 1))))))) req-grp-list))) (define (get-obj-by-code-no-grp-validation code ) (let* ((obj '())) (sauthorize:db-do (lambda (db) (let* ((data-row (query fetch (sql db (conc "SELECT code, exe_name, id, basepath FROM areas where areas.code = '" code "'"))))) (set! obj data-row)))) ;(print obj) obj)) ;; function to validate the users input for target path and resolve the path ;; TODO: Check for restriction in subpath (define (sauth-common:resolve-path new current allowed-sheets) (let* ((target-path (append current (string-split new "/"))) (target-path-string (string-join target-path "/")) (normal-path (normalize-pathname target-path-string)) (normal-list (string-split normal-path "/")) (ret '())) (if (string-contains normal-path "..") (begin (print "ERROR: Path " new " resolved outside target area ") #f) (if(equal? normal-path ".") ret (if (not (member (car normal-list) allowed-sheets)) (begin (print "ERROR: Permision denied to " new ) #f) normal-list))))) (define (sauth-common:get-target-path base-path-list ext-path top-areas base-path) (let* ((resolved-path (sauth-common:resolve-path ext-path base-path-list top-areas )) (usr (current-user-name) ) ) (if (not (equal? resolved-path #f)) (if (null? resolved-path) #f (let* ((sheet (car resolved-path)) (restricted-areas (get-restrictions base-path usr)) (restrictions (conc ".*" (string-join (string-split restricted-areas ",") ".*|.*") ".*")) (target-path (if (null? (cdr resolved-path)) base-path (conc base-path "/" (string-join (cdr resolved-path) "/"))))) (if (and (not (equal? restricted-areas "" )) (string-match (regexp restrictions) target-path)) (begin (sauth:print-error "Access denied to " (string-join resolved-path "/")) ;(exit 1) #f) target-path) )) #f))) (define (sauth-common:shell-ls-cmd base-path-list ext-path top-areas base-path tail-cmd-list) (if (and (null? base-path-list) (equal? ext-path "") ) (print (string-intersperse top-areas " ")) (let* ((resolved-path (sauth-common:resolve-path ext-path base-path-list top-areas ))) ;(print resolved-path) (if (not (equal? resolved-path #f)) (if (null? resolved-path) (print (string-intersperse top-areas " ")) (let* ((target-path (sauth-common:get-target-path base-path-list ext-path top-areas base-path))) (print target-path) (if (not (equal? target-path #f)) (begin (cond ((null? tail-cmd-list) (run (pipe (ls "-lrt" ,target-path)))) ((not (equal? (car tail-cmd-list) "|")) (print "ls cmd cannot accept " (string-join tail-cmd-list) " as an argument!!")) (else (run (pipe (ls "-lrt" ,target-path) (begin (system (string-join (cdr tail-cmd-list)))))))))))))))) (define (sauth:print-error msg) (with-output-to-port (current-error-port) (lambda () (print (conc "ERROR: " msg))))) |
Added sauthorize.scm version [c2546fdee5].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 | ;; Copyright 2006-2013, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. ;; (use defstruct) (use scsh-process) (use srfi-18) (use srfi-19) (use refdb) (use sql-de-lite srfi-1 posix regex regex-case srfi-69) ;(declare (uses common)) ;(declare (uses configf)) (declare (uses margs)) (declare (uses megatest-version)) (include "megatest-fossil-hash.scm") ;;; please create this file before using sautherise. For sample file is avaliable sample-sauth-paths.scm. (include "sauth-paths.scm") (include "sauth-common.scm") ;; ;; GLOBALS ;; (define *verbosity* 1) (define *logging* #f) (define *exe-name* (pathname-file (car (argv)))) (define *sretrieve:current-tab-number* 0) (define *args-hash* (make-hash-table)) (define sauthorize:help (conc "Usage: " *exe-name* " [action [params ...]] list : list areas $USER's can access log : get listing of recent activity. sauth list-area-user <area code> : list the users that can access the area. sauth open <path> --group <grpname> : Open up an area. User needs to be the owner of the area to open it. --code <unique short identifier for an area> --retrieve|--publish [--additional-grps <comma separated unix grps requierd to get to the path>] sauth update <area code> --retrieve|--publish : update the binaries with the lates changes sauth grant <username> --area <area identifier> : Grant permission to read or write to a area that is alrady opend up. --expiration yyyy/mm/dd --retrieve|--publish [--restrict <comma separated directory names> ] sauth read-shell <area identifier> : Open sretrieve shell for reading. sauth write-shell <area identifier> : Open spublish shell for writing. Part of the Megatest tool suite. Learn more at http://www.kiatoa.com/fossils/megatest Version: " megatest-fossil-hash)) ;; " ;;====================================================================== ;; RECORDS ;;====================================================================== ;;====================================================================== ;; DB ;;====================================================================== ;; replace (strftime('%s','now')), with datetime('now')) (define (sauthorize:initialize-db db) (for-each (lambda (qry) (exec (sql db qry))) (list "CREATE TABLE IF NOT EXISTS actions (id INTEGER PRIMARY KEY, cmd TEXT NOT NULL, user_id INTEGER NOT NULL, datetime TIMESTAMP DEFAULT (datetime('now','localtime')), area_id INTEGER NOT NULL, comment TEXT DEFAULT '' NOT NULL, action_type TEXT NOT NULL);" "CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY, username TEXT NOT NULL, is_admin TEXT NOT NULL, datetime TIMESTAMP DEFAULT (datetime('now','localtime')) );" "CREATE TABLE IF NOT EXISTS areas (id INTEGER PRIMARY KEY, basepath TEXT NOT NULL, code TEXT NOT NULL, exe_name TEXT NOT NULL, required_grps TEXT DEFAULT '' NOT NULL, datetime TIMESTAMP DEFAULT (datetime('now','localtime')) );" "CREATE TABLE IF NOT EXISTS permissions (id INTEGER PRIMARY KEY, access_type TEXT NOT NULL, user_id INTEGER NOT NULL, datetime TIMESTAMP DEFAULT (datetime('now','localtime')), area_id INTEGER NOT NULL, restriction TEXT DEFAULT '' NOT NULL, expiration TIMESTAMP DEFAULT NULL);" ))) (define (get-access-type args) (let loop ((hed (car args)) (tal (cdr args))) (cond ((equal? hed "--retrieve") "retrieve") ((equal? hed "--publish") "publish") ((equal? hed "--area-admin") "area-admin") ((equal? hed "--writer-admin") "writer-admin") ((equal? hed "--read-admin") "read-admin") ((null? tal) #f) (else (loop (car tal)(cdr tal)))))) ;; check if user can gran access to an area (define (can-grant-perm username access-type area) (let* ((isadmin (is-admin username)) (is-area-admin (is-user "area-admin" username area )) (is-read-admin (is-user "read-admin" username area) ) (is-writer-admin (is-user "writer-admin" username area) ) ) (cond ((equal? isadmin #t) #t) ((equal? is-area-admin #t ) #t) ((and (equal? is-writer-admin #t ) (equal? access-type "retrieve")) #t) ((and (equal? is-read-admin #t ) (equal? access-type "retrieve")) #t) (else #f)))) (define (sauthorize:list-areausers area ) (sauthorize:db-do (lambda (db) (print "Users having access to " area ":") (query (for-each-row (lambda (row) (let* ((exp-date (cadr row))) (if (is-access-valid exp-date) (apply print (intersperse row " | ")))))) (sql db (conc "SELECT users.username, permissions.expiration, permissions.access_type FROM users, areas, permissions where permissions.user_id = users.id and permissions.area_id = areas.id and areas.code = '" area "'")))))) ; check if executable exists (define (exe-exist exe access-type) (let* ((filepath (conc *exe-path* "/" access-type "/" exe))) ; (print filepath) (if (file-exists? filepath) #t #f))) (define (copy-exe access-type exe-name group) (run-cmd "/bin/chmod" (list "g+w" (conc *exe-path* "/" access-type))) (let* ((spath (conc *exe-src* "/s" access-type)) (dpath (conc *exe-path* "/" access-type "/" exe-name))) (sauthorize:do-as-calling-user (lambda () (run-cmd "/bin/cp" (list spath dpath )) (if (equal? access-type "publish") (run-cmd "/bin/chmod" (list "u+s,o+rx" dpath)) (begin (if (equal? group "none") (run-cmd "/bin/chmod" (list "u+s,o+rx" dpath)) (begin (run-cmd "/bin/chgrp" (list group dpath)) (run-cmd "/bin/chmod" (list "g+s,o+rx" dpath)))))))) (run-cmd "chmod" (list "g-w" (conc *exe-path* "/" access-type))))) (define (get-exe-name path group) (let ((name "")) (sauthorize:do-as-calling-user (lambda () (if (equal? (current-effective-user-id) (file-owner path)) (set! name (conc (current-user-name) "_" group)) (begin (print "You cannot open areas that you dont own!!") (exit 1))))) name)) (define (sauthorize:valid-unix-user username) (let* ((ret-val #f)) (let-values (((inp oup pid) (process "/usr/bin/id" (list username)))) (let loop ((inl (read-line inp))) (if (string? inl) (if (string-contains inl "No such user") (set! ret-val #f) (set! ret-val #t))) (if (eof-object? inl) (begin (close-input-port inp) (close-output-port oup)) (loop (read-line inp))))) ret-val)) ;check if a paths/codes are vaid and if area is alrady open (define (open-area group path code access-type other-grps) (let* ((exe-name (get-exe-name path group)) (path-obj (get-obj-by-path path)) (code-obj (get-obj-by-code-no-grp-validation code))) ;(print path-obj) (cond ((not (null? path-obj)) (if (equal? code (car path-obj)) (begin (if (equal? exe-name (cadr path-obj)) (begin (if (not (exe-exist exe-name access-type)) (copy-exe access-type exe-name group) (begin (print "Area already open!!") (exit 1)))) (begin (if (not (exe-exist exe-name access-type)) (copy-exe access-type exe-name group)) ;; update exe-name in db (sauthorize:db-do (lambda (db) (sauthorize:db-qry db (conc "update areas set exe_name = '" exe-name "' where id = " (caddr path-obj))))) ))) (begin (print "Path " path " is registered with --code " (car path-obj) ". To open this area please execute following cmd: \n sauthorize open " path " --group " group " --code " (car path-obj) " --" access-type ) (exit 1)))) ((not (null? code-obj)) (print "Code " code " is used for diffrent path. Please try diffrent value of --code" ) (exit 1)) (else ; (print (exe-exist exe-name access-type)) (if (not (exe-exist exe-name access-type)) (copy-exe access-type exe-name group)) (sauthorize:db-do (lambda (db) (print conc "insert into areas (code, basepath, exe_name, required_grps) values ('" code "', '" path "', '" exe-name "', '" other-grps "') ") (sauthorize:db-qry db (conc "insert into areas (code, basepath, exe_name, required_grps) values ('" code "', '" path "', '" exe-name "', '" other-grps "') ")))))))) (define (user-has-open-perm user path access) (let* ((has-access #f) (eid (current-user-id))) (cond ((is-admin user) (set! has-access #t )) ((and (is-read-admin user) (equal? access "retrieve")) (set! has-access #t )) (else (print "User " user " does not have permission to open areas"))) has-access)) ;;check if user has group access (define (is-group-washed req_grpid current-grp-list) (let loop ((hed (car current-grp-list)) (tal (cdr current-grp-list))) (cond ((equal? hed req_grpid) #t) ((null? tal) #f) (else (loop (car tal)(cdr tal)))))) ;create executables with appropriate suids (define (sauthorize:open user path group code access-type other-groups) (let* ((gpid (group-information group)) (req_grpid (if (equal? group "none") group (if (equal? gpid #f) #f (caddr gpid)))) (current-grp-list (get-groups)) (valid-grp (if (equal? group "none") group (is-group-washed req_grpid current-grp-list)))) (if (and (not (equal? group "none")) (equal? valid-grp #f )) (begin (print "Group " group " is not washed in the current xterm!!") (exit 1)))) (if (not (file-write-access? path)) (begin (print "You can open areas owned by yourself. You do not have permissions to open path." path) (exit 1))) (if (user-has-open-perm user path access-type) (begin ;(print "here") (open-area group path code access-type other-groups) (sauthorize:grant user user code "2017/12/25" "read-admin" "") (sauthorize:db-do (lambda (db) (sauthorize:db-qry db (conc "INSERT INTO actions (cmd,user_id,area_id,action_type ) VALUES ('sauthorize open " path " --code " code " --group " group " --" access-type "'," (car (get-user user)) "," (car (get-area code)) ", 'open' )")))) (print "Area has " path " been opened for " access-type )))) (define (sauthorize:update username exe area access-type) (let* ((parts (string-split exe "_")) (owner (car parts)) (group (cadr parts)) (gpid (group-information group)) (req_grpid (if (equal? group "none") group (if (equal? gpid #f) #f (caddr gpid)))) (current-grp-list (get-groups)) (valid-grp (if (equal? group "none") group (is-group-washed req_grpid current-grp-list)))) (if (not (equal? username owner)) (begin (print "You cannot update " area ". Only " owner " can update this area!!") (exit 1))) (copy-exe access-type exe group) (print "recording action..") (sauthorize:db-do (lambda (db) (sauthorize:db-qry db (conc "INSERT INTO actions (cmd,user_id,area_id,action_type ) VALUES ('sauthorize update " area " --" access-type "'," (car (get-user username)) "," (car (get-area area)) ", 'update' )")))) (print "Area has " area " been update!!" ))) (define (sauthorize:grant auser guser area exp-date access-type restrict) ; check if user exist in db (let* ((area-obj (get-area area)) (auser-obj (get-user auser)) (user-obj (get-user guser))) (if (null? user-obj) (begin ;; is guser a valid unix user (if (not (sauthorize:valid-unix-user guser)) (begin (print "User " guser " is Invalid unix user!!") (exit 1))) (sauthorize:db-do (lambda (db) (sauthorize:db-qry db (conc "insert into users (username, is_admin) values ('" guser "', 'no') ")))) (set! user-obj (get-user guser)))) (let* ((perm-obj (get-perm (car user-obj) (car area-obj)))) (if(null? perm-obj) (begin ;; insert permissions (sauthorize:db-do (lambda (db) (sauthorize:db-qry db (conc "insert into permissions (access_type, user_id, area_id, restriction, expiration ) values ('" access-type "', " (car user-obj) ", " (car area-obj) ", '" restrict "', '" exp-date "')"))))) (begin ;update permissions (sauthorize:db-do (lambda (db) (sauthorize:db-qry db (conc "update permissions set access_type = '" access-type "' , restriction = '" restrict "', expiration = '" exp-date "' where user_id = " (car user-obj) " and area_id = " (car area-obj))))))) (sauthorize:db-do (lambda (db) (sauthorize:db-qry db (conc "INSERT INTO actions (cmd,user_id,area_id,action_type ) VALUES ('sauthorize grant " guser " --area " area " --expiration " exp-date " --" access-type " --restrict " restrict "'," (car auser-obj) "," (car area-obj) ", 'grant' )")))) (print "Permission has been sucessfully granted to user " guser)))) (define (sauthorize:process-action username action . args) (case (string->symbol action) ((grant) (if (< (length args) 6) (begin (print "ERROR: Missing arguments; " (string-intersperse args ", ")) (exit 1))) (let* ((remargs (args:get-args args '("--area" "--expiration" "--restrict") '() args:arg-hash 0)) (guser (car args)) (restrict (or (args:get-arg "--restrict") "")) (area (or (args:get-arg "--area") "")) (exp-date (or (args:get-arg "--expiration") "")) (access-type (get-access-type remargs))) ; (print "version " guser " restrict " restrict ) ; (print "area " area " exp-date " exp-date " access-type " access-type) (cond ((equal? guser "") (print "Username not found!! Try \"sauthorize help\" for useage ") (exit 1)) ((equal? area "") (print "Area not found!! Try \"sauthorize help\" for useage ") (exit 1)) ((equal? access-type #f) (print "Access type not found!! Try \"sauthorize help\" for useage ") (exit 1)) ((equal? exp-date "") (print "Date of expiration not found!! Try \"sauthorize help\" for useage ") (exit 1))) (if (not (area-exists area)) (begin (print "Area does not exisit!!") (exit 1))) (if (can-grant-perm username access-type area) (begin (print "calling sauthorize:grant ") (sauthorize:grant username guser area exp-date access-type restrict)) (begin (print "User " username " does not have permission to grant permissions to area " area "!!") (exit 1))))) ((list-area-user) (if (not (equal? (length args) 1)) (begin (print "Missing argument area code to list-area-user ") (exit 1))) (let* ((area (car args))) (if (not (area-exists area)) (begin (print "Area does not exisit!!") (exit 1))) (sauthorize:list-areausers area ) )) ((read-shell) (if (not (equal? (length args) 1)) (begin (print "Missing argument area code to read-shell ") (exit 1))) (let* ((area (car args)) (code-obj (get-obj-by-code area))) (if (or (null? code-obj) (not (exe-exist (cadr code-obj) "retrieve"))) (begin (print "Area " area " is not open for reading!!") (exit 1))) (sauthorize:do-as-calling-user (lambda () (run-cmd (conc *exe-path* "/retrieve/" (cadr code-obj) ) (list "shell" area )))))) ((write-shell) (if (not (equal? (length args) 1)) (begin (print "Missing argument area code to read-shell ") (exit 1))) (let* ((area (car args)) (code-obj (get-obj-by-code area))) (if (or (null? code-obj) (not (exe-exist (cadr code-obj) "publish"))) (begin (print "Area " area " is not open for Writing!!") (exit 1))) (sauthorize:do-as-calling-user (lambda () (run-cmd (conc *exe-path* "/publish/" (cadr code-obj) ) (list "shell" area)))))) ((publish) (if (< (length args) 2) (begin (print "Missing argument to publish. \n publish <action> <area> [opts] ") (exit 1))) (let* ((action (car args)) (area (cadr args)) (cmd-args (cddr args)) (code-obj (get-obj-by-code area))) ;(print "area " area) ;(print "code: " code-obj) ;(print (exe-exist (cadr code-obj) "publish")) (if (or (null? code-obj) (not (exe-exist (cadr code-obj) "publish"))) (begin (print "Area " area " is not open for writing!!") (exit 1))) ;(print "hear") (sauthorize:do-as-calling-user (lambda () ; (print *exe-path* "/publish/" (cadr code-obj) action area cmd-args ) (run-cmd (conc *exe-path* "/publish/" (cadr code-obj) ) (append (list action area ) cmd-args)))))) ((retrieve) (if (< (length args) 2) (begin (print "Missing argument to publish. \n publish <action> <area> [opts] ") (exit 1))) (let* ((action (car args)) (area (cadr args)) (cmd-args (cddr args)) (code-obj (get-obj-by-code area))) (if (or (null? code-obj) (not (exe-exist (cadr code-obj) "retrieve"))) (begin (print "Area " area " is not open for reading!!") (exit 1))) ;(print (conc *exe-path* "/retrieve/" (cadr code-obj) " " action " " area " " (string-join cmd-args))) (sauthorize:do-as-calling-user (lambda () (run-cmd (conc *exe-path* "/retrieve/" (cadr code-obj) ) (append (list action area ) cmd-args)))))) ((open) (if (< (length args) 6) (begin (print "sauthorize open cmd takes 6 arguments!! \n Useage: sauthorize open <path> --group <grpname> --code <unique short identifier for an area> --retrieve|--publish") (exit 1))) (let* ((remargs (args:get-args args '("--group" "--code" "--additional-grps") '() args:arg-hash 0)) (path (car args)) (group (or (args:get-arg "--group") "")) (area (or (args:get-arg "--code") "")) (other-grps (or (args:get-arg "--additional-grps") "")) (access-type (get-access-type remargs))) (cond ((equal? path "") (print "path not found!! Try \"sauthorize help\" for useage ") (exit 1)) ((equal? area "") (print "--code not found!! Try \"sauthorize help\" for useage ") (exit 1)) ((equal? access-type #f) (print "Access type not found!! Try \"sauthorize help\" for useage ") (exit 1)) ((and (not (equal? access-type "publish")) (not (equal? access-type "retrieve"))) (print "Access type can be eiter --retrieve or --publish !! Try \"sauthorize help\" for useage ") (exit 1))) ; (print other-grps) (sauthorize:open username path group area access-type other-grps))) ((update) (if (< (length args) 2) (begin (print "sauthorize update cmd takes 2 arguments!! \n Useage: sauthorize update <area-code> --retrieve|--publish") (exit 1))) (let* ((area (car args)) (code-obj (get-obj-by-code area)) (access-type (get-access-type (cdr args)))) (if (and (not (equal? access-type "publish")) (not (equal? access-type "retrieve"))) (begin (print "Access type can be --retrieve|--publish ") (exit 1))) (if (or (null? code-obj) (not (exe-exist (cadr code-obj) access-type))) (begin (print "Area " area " is not open for reading!!") (exit 1))) (sauthorize:update username (cadr code-obj) area access-type ))) ((area-admin) (let* ((usr (car args)) (usr-obj (get-user usr)) (user-id (car (get-user username)))) (if (is-admin username) (begin ; (print usr-obj) (if (null? usr-obj) (begin (sauthorize:db-do (lambda (db) ;(print (conc "INSERT INTO users (username,is_admin) VALUES ( '" usr "', 'read-admin' )")) (sauthorize:db-qry db (conc "INSERT INTO users (username,is_admin) VALUES ( '" usr "', 'read-admin' )"))))) (begin ; (print (conc "update users set is_admin = 'no' where id = " (car usr-obj) )) (sauthorize:db-do (lambda (db) (sauthorize:db-qry db (conc "update users set is_admin = 'read-admin' where id = " (car usr-obj))))))) (print "User " usr " is updated with area-admin access!")) (print "Admin only function")) (sauthorize:db-do (lambda (db) (sauthorize:db-qry db (conc "INSERT INTO actions (cmd,user_id,area_id,action_type ) VALUES ('area-admin " usr " ', " user-id ",0, 'area-admin ')" )))))) ((mk-admin) (let* ((usr (car args)) (usr-obj (get-user usr)) (user-id (car (get-user username)))) (if (not (sauthorize:valid-unix-user usr)) (begin (print "User " usr " is Invalid unix user!!") (exit 1))) (if (member username *super-users*) (begin (if (null? usr-obj) (begin (sauthorize:db-do (lambda (db) (sauthorize:db-qry db (conc "INSERT INTO users (username,is_admin) VALUES ( '" usr "', 'yes' )"))))) (begin (sauthorize:db-do (lambda (db) (sauthorize:db-qry db (conc "update users set is_admin = 'yes' where id = " (car usr-obj))))))) (print "User " usr " is updated with admin access!")) (print "Super-Admin only function")) (sauthorize:db-do (lambda (db) (sauthorize:db-qry db (conc "INSERT INTO actions (cmd,user_id,area_id,action_type ) VALUES ('mk-admin " usr " ', " user-id ",0, 'mk-admin ')" )))))) ((register-log) (if (< (length args) 4) (print "Invalid arguments")) ;(print args) (let* ((cmd-line (car args)) (user-id (cadr args)) (area-id (caddr args)) (user-obj (get-user username)) (cmd (cadddr args))) (if (and (not (null? user-obj)) (equal? user-id (number->string(car user-obj)))) (begin (sauthorize:db-do (lambda (db) (sauthorize:db-qry db (conc "INSERT INTO actions (cmd,user_id,area_id,action_type ) VALUES ('" cmd-line"', " user-id "," area-id ", '" cmd "')" ))))) (print "You ar not authorised to run this cmd") ))) (else (print 0 "Unrecognised command " action)))) (define (main) (let* ((args (argv)) (prog (car args)) (rema (cdr args)) (username (current-user-name))) ;; preserve the exe data in the config file (cond ;; one-word commands ((eq? (length rema) 1) (case (string->symbol (car rema)) ((help -h -help --h --help) (print sauthorize:help)) ((list) (sauthorize:db-do (lambda (db) (print "My Area accesses: ") (query (for-each-row (lambda (row) (let* ((exp-date (car row))) (if (is-access-valid exp-date) (apply print (intersperse (cdr row) " | ")))))) (sql db (conc "SELECT permissions.expiration, areas.basepath, areas.code, permissions.access_type FROM users, areas, permissions where permissions.user_id = users.id and permissions.area_id = areas.id and users.username = '" username "'")))))) ((log) (sauthorize:db-do (lambda (db) (print "Logs : ") (query (for-each-row (lambda (row) (apply print (intersperse row " | ")))) (sql db "SELECT actions.cmd, users.username, actions.action_type, actions.datetime, areas.code FROM actions, users, areas where actions.user_id = users.id and actions.area_id = areas.id "))))) (else (print "ERROR: Unrecognised command. Try \"sauthorize help\"")))) ;; multi-word commands ((null? rema)(print sauthorize:help)) ((>= (length rema) 2) (apply sauthorize:process-action username (car rema)(cdr rema))) (else (debug:print 0 "ERROR: Unrecognised command. Try \"sauthorize help\""))))) (main) |
Modified sdb.scm from [b5405355dd] to [3f78d1737e].
1 2 3 | ;;====================================================================== ;; Copyright 2006-2013, Matthew Welland. ;; | | | > > > > > | | > > > > | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | ;;====================================================================== ;; Copyright 2006-2013, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. ;;====================================================================== ;;====================================================================== ;; Simple persistant strings lookup table. Keep out of the main db ;; so writes/reads don't slow down central access. ;;====================================================================== (require-extension (srfi 18) extras) (use sqlite3 srfi-1 posix regex regex-case srfi-69 csv-xml s11n md5 message-digest base64) (import (prefix sqlite3 sqlite3:)) (import (prefix base64 base64:)) (declare (unit sdb)) ;; (define (sdb:open fname) (let* ((dbpath (pathname-directory fname)) (dbexists (let ((fe (common:file-exists? fname))) (if fe fe (begin (create-directory dbpath #t) #f)))) (sdb (sqlite3:open-database fname)) (handler (make-busy-timeout 136000))) |
︙ | ︙ |
Added serialize-env.scm version [e0a42785e8].
> > > > > > > > > | 1 2 3 4 5 6 7 8 9 | (use z3) (use base64) (let* ((env-str (with-output-to-string (lambda () (pp (get-environment-variables))))) (zipped-env-str (z3:encode-buffer env-str)) (b64-env-str (base64-encode zipped-env-str))) (print b64-env-str)) |
Modified server.scm from [32389a7830] to [b1a1de6e53].
|
| < | | > | > > > > | | > | > > > | < > | | < | > > > > > > > > > > > > | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 | ;; Copyright 2006-2017, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. ;; (require-extension (srfi 18) extras tcp s11n) (use srfi-1 posix regex regex-case srfi-69 hostinfo md5 message-digest directory-utils posix-extras matchable) (use spiffy uri-common intarweb http-client spiffy-request-vars) (declare (unit server)) (declare (uses common)) (declare (uses db)) (declare (uses tasks)) ;; tasks are where stuff is maintained about what is running. ;; (declare (uses synchash)) (declare (uses http-transport)) ;;(declare (uses rpc-transport)) (declare (uses launch)) ;; (declare (uses daemon)) (include "common_records.scm") (include "db_records.scm") (define (server:make-server-url hostport) (if (not hostport) #f (conc "http://" (car hostport) ":" (cadr hostport)))) (define *server-loop-heart-beat* (current-seconds)) ;;====================================================================== ;; P K T S S T U F F ;;====================================================================== ;; ??? ;;====================================================================== ;; P K T S S T U F F ;;====================================================================== ;; ??? ;;====================================================================== ;; S E R V E R ;;====================================================================== ;; Call this to start the actual server ;; ;; all routes though here end in exit ... ;; ;; start_server ;; (define (server:launch run-id transport-type) (case transport-type ((http)(http-transport:launch)) ;;((nmsg)(nmsg-transport:launch run-id)) ;;((rpc) (rpc-transport:launch run-id)) (else (debug:print-error 0 *default-log-port* "unknown server type " transport-type)))) ;;====================================================================== ;; S E R V E R U T I L I T I E S ;;====================================================================== ;; Get the transport |
︙ | ︙ | |||
110 111 112 113 114 115 116 | (logfile (conc areapath "/logs/server.log")) ;; -" curr-pid "-" target-host ".log")) (cmdln (conc (common:get-megatest-exe) " -server " (or target-host "-") (if (equal? (configf:lookup *configdat* "server" "daemonize") "yes") " -daemonize " "") ;; " -log " logfile " -m testsuite:" testsuite)) ;; (conc " >> " logfile " 2>&1 &"))))) | | > > | > | 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 | (logfile (conc areapath "/logs/server.log")) ;; -" curr-pid "-" target-host ".log")) (cmdln (conc (common:get-megatest-exe) " -server " (or target-host "-") (if (equal? (configf:lookup *configdat* "server" "daemonize") "yes") " -daemonize " "") ;; " -log " logfile " -m testsuite:" testsuite)) ;; (conc " >> " logfile " 2>&1 &"))))) (log-rotate (make-thread common:rotate-logs "server run, rotate logs thread")) (load-limit (configf:lookup-number *configdat* "jobtools" "max-server-start-load" default: 3.0))) ;; we want the remote server to start in *toppath* so push there (push-directory areapath) (debug:print 0 *default-log-port* "INFO: Trying to start server (" cmdln ") ...") (thread-start! log-rotate) ;; host.domain.tld match host? (if (and target-host ;; look at target host, is it host.domain.tld or ip address and does it ;; match current ip or hostname (not (string-match (conc "("curr-host "|" curr-host"\\..*)") target-host)) (not (equal? curr-ip target-host))) (begin (debug:print-info 0 *default-log-port* "Starting server on " target-host ", logfile is " logfile) (setenv "TARGETHOST" target-host))) (setenv "TARGETHOST_LOGF" logfile) (thread-sleep! (/ (random 5000) 1000)) ;; add about a random (up to 5 seconds) initial delay. It seems pretty common that many running tests request a server at the same time ;; (common:wait-for-normalized-load load-limit " delaying server start due to load" target-host) ;; do not try starting servers on an already overloaded machine, just wait forever (common:wait-for-homehost-load load-limit (conc " delaying server start due to load on homehost. limit is " load-limit)) (system (conc "nbfake " cmdln)) (unsetenv "TARGETHOST_LOGF") (if (get-environment-variable "TARGETHOST")(unsetenv "TARGETHOST")) (thread-join! log-rotate) (pop-directory))) ;; given a path to a server log return: host port startseconds |
︙ | ︙ | |||
204 205 206 207 208 209 210 | res (cons (append serv-rec (list pid)) res)))) (if (null? tal) (if (and limit (> (length new-res) limit)) new-res ;; (take new-res limit) <= need intelligent sorting before this will work new-res) | | > > > > > > > > > > > > > > | 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 | res (cons (append serv-rec (list pid)) res)))) (if (null? tal) (if (and limit (> (length new-res) limit)) new-res ;; (take new-res limit) <= need intelligent sorting before this will work new-res) (loop (car tal)(cdr tal) new-res))))))))) (define (server:get-num-alive srvlst) (let ((num-alive 0)) (for-each (lambda (server) (match-let (((mod-time host port start-time pid) server)) (let* ((uptime (- (current-seconds) mod-time)) (runtime (if start-time (- mod-time start-time) 0))) (if (< uptime 5)(set! num-alive (+ num-alive 1)))))) srvlst) num-alive)) ;; given a list of servers get a list of valid servers, i.e. at least ;; 10 seconds old, has started and is less than 1 hour old and is ;; active (i.e. mod-time < 10 seconds ;; ;; mod-time host port start-time pid ;; |
︙ | ︙ | |||
228 229 230 231 232 233 234 | (> (length rec) 2)) (let ((start-time (list-ref rec 3)) (mod-time (list-ref rec 0))) ;; (print "start-time: " start-time " mod-time: " mod-time) (and start-time mod-time (> (- now start-time) 0) ;; been running at least 0 seconds (< (- now mod-time) 16) ;; still alive - file touched in last 16 seconds | | | 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 | (> (length rec) 2)) (let ((start-time (list-ref rec 3)) (mod-time (list-ref rec 0))) ;; (print "start-time: " start-time " mod-time: " mod-time) (and start-time mod-time (> (- now start-time) 0) ;; been running at least 0 seconds (< (- now mod-time) 16) ;; still alive - file touched in last 16 seconds (< (- now start-time) (+ (- (string->number (or (configf:lookup *configdat* "server" "runtime") "3600")) 180) (random 360))) ;; under one hour running time +/- 180 )) #f)) srvlst) (lambda (a b) |
︙ | ︙ | |||
290 291 292 293 294 295 296 | (else 600)) (random 5))) ;; add a small random number just in case a lot of jobs hit the work hosts simultaneously (lock-file (conc areapath "/logs/server-start.lock"))) (if (> (- (current-seconds) when-run) run-delay) (begin (common:simple-file-lock-and-wait lock-file expire-time: 15) (server:run areapath) | | | 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 | (else 600)) (random 5))) ;; add a small random number just in case a lot of jobs hit the work hosts simultaneously (lock-file (conc areapath "/logs/server-start.lock"))) (if (> (- (current-seconds) when-run) run-delay) (begin (common:simple-file-lock-and-wait lock-file expire-time: 15) (server:run areapath) (thread-sleep! 2) ;; don't release the lock for at least a few seconds (common:simple-file-release-lock lock-file))) (hash-table-set! *server-kind-run* areapath (list (+ call-num 1)(current-seconds)))))) (define (server:start-and-wait areapath #!key (timeout 60)) (let ((give-up-time (+ (current-seconds) timeout))) (let loop ((server-url (server:check-if-running areapath)) (try-num 0)) |
︙ | ︙ | |||
422 423 424 425 426 427 428 | (define (server:login toppath) (lambda (toppath) (set! *db-last-access* (current-seconds)) ;; might not be needed. (if (equal? *toppath* toppath) #t #f))) | | > | | > | > | > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > | > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 | (define (server:login toppath) (lambda (toppath) (set! *db-last-access* (current-seconds)) ;; might not be needed. (if (equal? *toppath* toppath) #t #f))) ;; timeout is hms string: 1h 5m 3s, default is 1 minute ;; (define (server:expiration-timeout) (let ((tmo (configf:lookup *configdat* "server" "timeout"))) (if (and (string? tmo) (common:hms-string->seconds tmo)) ;; BUG: hms-string->seconds is broken, if given "10" returns 0. Also, it doesn't belong in this logic unless the string->number is changed below (* 3600 (string->number tmo)) 60))) (define (server:get-best-guess-address hostname) (let ((res #f)) (for-each (lambda (adr) (if (not (eq? (u8vector-ref adr 0) 127)) (set! res adr))) ;; NOTE: This can fail when there is no mention of the host in /etc/hosts. FIXME (vector->list (hostinfo-addresses (hostname->hostinfo hostname)))) (string-intersperse (map number->string (u8vector->list (if res res (hostname->ip hostname)))) "."))) ;; (define server:sync-lock-token "SERVER_SYNC_LOCK") ;; (define (server:release-sync-lock) ;; (db:no-sync-del! *no-sync-db* server:sync-lock-token)) ;; (define (server:have-sync-lock?) ;; (let* ((have-lock-pair (db:no-sync-get-lock *no-sync-db* server:sync-lock-token)) ;; (have-lock? (car have-lock-pair)) ;; (lock-time (cdr have-lock-pair)) ;; (lock-age (- (current-seconds) lock-time))) ;; (cond ;; (have-lock? #t) ;; ((>lock-age ;; (* 3 (configf:lookup-number *configdat* "server" "minimum-intersync-delay" default: 180))) ;; (server:release-sync-lock) ;; (server:have-sync-lock?)) ;; (else #f)))) ;; moving this here as it needs access to db and cannot be in common. ;; (define (server:get-bruteforce-syncer dbstruct #!key (fork-to-background #f) (persist-until-sync #f)) (let* ((sqlite-exe (or (get-environment-variable "MT_SQLITE3_EXE"))) ;; defined in cfg.sh (sync-log (or (args:get-arg "-sync-log") (conc *toppath* "/logs/sync-" (current-process-id) "-" (get-host-name) ".log"))) (tmp-area (common:get-db-tmp-area)) (tmp-db (conc tmp-area "/megatest.db")) (staging-file (conc *toppath* "/.megatest.db")) (mtdbfile (conc *toppath* "/megatest.db")) (lockfile (common:get-sync-lock-filepath)) (sync-cmd-core (conc sqlite-exe" " tmp-db " .dump | "sqlite-exe" " staging-file "&>"sync-log)) (sync-cmd (if fork-to-background (conc "/usr/bin/env NBFAKE_LOG="*toppath*"/logs/last-server-sync-"(current-process-id)".log nbfake \""sync-cmd-core" && /bin/mv -f " staging-file " " mtdbfile" \"") sync-cmd-core)) (default-min-intersync-delay 2) (min-intersync-delay (configf:lookup-number *configdat* "server" "minimum-intersync-delay" default: default-min-intersync-delay)) (default-duty-cycle 0.1) (duty-cycle (configf:lookup-number *configdat* "server" "sync-duty-cycle" default: default-duty-cycle)) (last-sync-seconds 10) ;; we will adjust this to a measurement and delay last-sync-seconds * (1 - duty-cycle) (calculate-off-time (lambda (work-duration duty-cycle) (* (/ (- 1 duty-cycle) duty-cycle) last-sync-seconds))) (off-time min-intersync-delay) ;; adjusted in closure below. (do-a-sync (lambda () (BB> "Start do-a-sync with fork-to-background="fork-to-background" persist-until-sync="persist-until-sync) (let* ((finalres (let retry-loop ((num-tries 0)) (if (common:simple-file-lock lockfile) (begin (cond ((not (or fork-to-background persist-until-sync)) (debug:print 0 *default-log-port* "INFO: syncer thread sleeping for max of (server.minimum-intersync-delay="min-intersync-delay " , off-time="off-time" seconds ]") (thread-sleep! (max off-time min-intersync-delay))) (else (debug:print 0 *default-log-port* "INFO: syncer thread NOT sleeping ; maybe time-to-exit..."))) (if (not (configf:lookup *configdat* "server" "disable-db-snapshot")) (common:snapshot-file mtdbfile subdir: ".db-snapshot")) (delete-file* staging-file) (let* ((start-time (current-milliseconds)) (res (system sync-cmd)) (res2 (cond ((eq? 0 res) (delete-file* (conc mtdbfile ".backup")) (if (eq? 0 (file-size sync-log)) (delete-file sync-log)) (system (conc "/bin/mv " staging-file " " mtdbfile)) (set! last-sync-seconds (/ (- (current-milliseconds) start-time) 1000)) (set! off-time (calculate-off-time last-sync-seconds (cond ((and (number? duty-cycle) (> duty-cycle 0) (< duty-cycle 1)) duty-cycle) (else (debug:print 0 *default-log-port* "WARNING: ["(common:human-time)"] server.sync-duty-cycle is invalid. Should be a number between 0 and 1, but "duty-cycle" was specified. Using default value: "default-duty-cycle) default-duty-cycle)))) (debug:print 1 *default-log-port* "INFO: ["(common:human-time)"] pid="(current-process-id)" SYNC took "last-sync-seconds" sec") (debug:print 1 *default-log-port* "INFO: ["(common:human-time)"] pid="(current-process-id)" SYNC took "last-sync-seconds" sec ; with duty-cycle of "duty-cycle" off time is now "off-time) 'sync-completed) (else (system (conc "/bin/cp "sync-log" "sync-log".fail")) (debug:print 0 *default-log-port* "ERROR: ["(common:human-time)"] Sync failed. See log at "sync-log".fail") (if (file-exists? (conc mtdbfile ".backup")) (system (conc "/bin/cp "mtdbfile ".backup " mtdbfile))) #f)))) (common:simple-file-release-lock lockfile) (BB> "released lockfile: " lockfile) (when (common:file-exists? lockfile) (BB> "DID NOT ACTUALLY RELEASE LOCKFILE")) res2) ;; end let );; end begin ;; else (cond (persist-until-sync (thread-sleep! 1) (debug:print 1 *default-log-port* "INFO: ["(common:human-time)"] pid="(current-process-id)" other SYNC in progress; we're in a fork-to-background so we need to succeed. Let's wait a jiffy and and try again. num-tries="num-tries" (waiting for lockfile="lockfile" to disappear)") (retry-loop (add1 num-tries))) (else (thread-sleep! (max off-time (+ last-sync-seconds min-intersync-delay))) (debug:print 1 *default-log-port* "INFO: ["(common:human-time)"] pid="(current-process-id)" other SYNC in progress; not syncing.") 'parallel-sync-in-progress)) ) ;; end if got lockfile ) )) (BB> "End do-a-sync with fork-to-background="fork-to-background" persist-until-sync="persist-until-sync" and result="finalres) finalres) ) ;; end lambda )) do-a-sync)) (define (server:writable-watchdog-bruteforce dbstruct) (thread-sleep! 1) ;; delay for startup (let* ((do-a-sync (server:get-bruteforce-syncer dbstruct)) (final-sync (server:get-bruteforce-syncer dbstruct fork-to-background: #t persist-until-sync: #t))) (when (and (not (args:get-arg "-sync-to-megatest.db")) ;; conditions under which we do not run the sync (args:get-arg "-server")) (let loop () (do-a-sync) (if (not *time-to-exit*) (loop))) ;; keep going unless time to exit ;; time to exit, close the no-sync db here (final-sync) (if (common:low-noise-print 30) (debug:print-info 0 *default-log-port* "Exiting watchdog timer, *time-to-exit* = " *time-to-exit*" pid="(current-process-id) ))))) (define (server:writable-watchdog-deltasync dbstruct) (thread-sleep! 0.05) ;; delay for startup (let ((legacy-sync (common:run-sync?)) (sync-stale-seconds (configf:lookup-number *configdat* "server" "sync-stale-seconds" default: 300)) (debug-mode (debug:debug-mode 1)) (last-time (current-seconds)) (no-sync-db (db:open-no-sync-db)) (sync-duration 0) ;; run time of the sync in milliseconds ;;(this-wd-num (begin (mutex-lock! *wdnum*mutex) (let ((x *wdnum*)) (set! *wdnum* (add1 *wdnum*)) (mutex-unlock! *wdnum*mutex) x))) ) (set! *no-sync-db* no-sync-db) ;; make the no sync db available to api calls (debug:print-info 2 *default-log-port* "Periodic sync thread started.") (debug:print-info 3 *default-log-port* "watchdog starting. legacy-sync is " legacy-sync" pid="(current-process-id) );; " this-wd-num="this-wd-num) (if (and legacy-sync (not *time-to-exit*)) (let* (;;(dbstruct (db:setup)) (mtdb (dbr:dbstruct-mtdb dbstruct)) (mtpath (db:dbdat-get-path mtdb)) (tmp-area (common:get-db-tmp-area)) (start-file (conc tmp-area "/.start-sync")) (end-file (conc tmp-area "/.end-sync"))) (debug:print-info 0 *default-log-port* "Server running, periodic sync started.") (let loop () ;; sync for filesystem local db writes ;; (mutex-lock! *db-multi-sync-mutex*) (let* ((need-sync (>= *db-last-access* *db-last-sync*)) ;; no sync since last write (sync-in-progress *db-sync-in-progress*) (min-intersync-delay (configf:lookup-number *configdat* "server" "minimum-intersync-delay" default: 5)) (should-sync (and (not *time-to-exit*) (> (- (current-seconds) *db-last-sync*) min-intersync-delay))) ;; sync every five seconds minimum, deprecated logic, can probably be removed (start-time (current-seconds)) (cpu-load-adj (alist-ref 'adj-proc-load (common:get-normalized-cpu-load #f))) (mt-mod-time (file-modification-time mtpath)) (last-sync-start (if (common:file-exists? start-file) (file-modification-time start-file) 0)) (last-sync-end (if (common:file-exists? end-file) (file-modification-time end-file) 10)) (sync-period (+ 3 (* cpu-load-adj 30))) ;; as adjusted load increases increase the sync period (recently-synced (and (< (- start-time mt-mod-time) sync-period) ;; not useful if sync didn't modify megatest.db! (< mt-mod-time last-sync-start))) (sync-done (<= last-sync-start last-sync-end)) (sync-stale (> start-time (+ last-sync-start sync-stale-seconds))) (will-sync (and (not *time-to-exit*) ;; do not start a sync if we are in the process of exiting (or need-sync should-sync) (or sync-done sync-stale) (not sync-in-progress) (not recently-synced)))) (debug:print-info 13 *default-log-port* "WD writable-watchdog top of loop. need-sync="need-sync" sync-in-progress=" sync-in-progress " should-sync="should-sync" start-time="start-time" mt-mod-time="mt-mod-time" recently-synced="recently-synced" will-sync="will-sync " sync-done=" sync-done " sync-period=" sync-period) (if (and (> sync-period 5) (common:low-noise-print 30 "sync-period")) (debug:print-info 0 *default-log-port* "Increased sync period due to long sync times, sync took: " sync-period " seconds.")) ;; (if recently-synced (debug:print-info 0 *default-log-port* "Skipping sync due to recently-synced flag=" recently-synced)) ;; (debug:print-info 0 *default-log-port* "need-sync: " need-sync " sync-in-progress: " sync-in-progress " should-sync: " should-sync " will-sync: " will-sync) (if will-sync (set! *db-sync-in-progress* #t)) (mutex-unlock! *db-multi-sync-mutex*) (if will-sync (let (;; (max-sync-duration (configf:lookup-number *configdat* "server" "max-sync-duration")) ;; KEEPING THIS AVAILABLE BUT SHOULD NOT USE, I'M PRETTY SURE IT DOES NOT WORK! (sync-start (current-milliseconds))) (with-output-to-file start-file (lambda ()(print (current-process-id)))) ;; put lock here ;; (if (or (not max-sync-duration) ;; (< sync-duration max-sync-duration)) ;; NOTE: db:sync-to-megatest.db keeps track of time of last sync and syncs incrementally (let ((res (db:sync-to-megatest.db dbstruct no-sync-db: no-sync-db))) ;; did we sync any data? If so need to set the db touched flag to keep the server alive (set! sync-duration (- (current-milliseconds) sync-start)) (if (> res 0) ;; some records were transferred, keep the db alive (begin (mutex-lock! *heartbeat-mutex*) (set! *db-last-access* (current-seconds)) (mutex-unlock! *heartbeat-mutex*) (debug:print-info 0 *default-log-port* "sync called, " res " records transferred.")) (debug:print-info 2 *default-log-port* "sync called but zero records transferred"))))) ;; ;; TODO: factor this next routine out into a function ;; (with-input-from-pipe ;; this should not block other threads but need to verify this ;; (conc "megatest -sync-to-megatest.db -m testsuite:" (common:get-area-name) ":" *toppath*) ;; (lambda () ;; (let loop ((inl (read-line)) ;; (res #f)) ;; (if (eof-object? inl) ;; (begin ;; (set! sync-duration (- (current-milliseconds) sync-start)) ;; (cond ;; ((not res) ;; (debug:print 0 *default-log-port* "ERROR: sync from /tmp db to megatest.db appears to have failed. Recommended that you stop your runs and run \"megatest -cleanup-db\"")) ;; ((> res 0) ;; (mutex-lock! *heartbeat-mutex*) ;; (set! *db-last-access* (current-seconds)) ;; (mutex-unlock! *heartbeat-mutex*)))) ;; (let ((num-synced (let ((matches (string-match "^Synced (\\d+).*$" inl))) ;; (if matches ;; (string->number (cadr matches)) ;; #f)))) ;; (loop (read-line) ;; (or num-synced res)))))))))) (if will-sync (begin (mutex-lock! *db-multi-sync-mutex*) (set! *db-sync-in-progress* #f) (set! *db-last-sync* start-time) (with-output-to-file end-file (lambda ()(print (current-process-id)))) ;; release lock here (mutex-unlock! *db-multi-sync-mutex*))) (if (and debug-mode (> (- start-time last-time) 60)) (begin (set! last-time start-time) (debug:print-info 4 *default-log-port* "timestamp -> " (seconds->time-string (current-seconds)) ", time since start -> " (seconds->hr-min-sec (- (current-seconds) *time-zero*)))))) ;; keep going unless time to exit ;; (if (not *time-to-exit*) (let delay-loop ((count 0)) ;;(debug:print-info 13 *default-log-port* "delay-loop top; count="count" pid="(current-process-id)" this-wd-num="this-wd-num" *time-to-exit*="*time-to-exit*) (if (and (not *time-to-exit*) (< count 6)) ;; was 11, changing to 4. (begin (thread-sleep! 1) (delay-loop (+ count 1)))) (if (not *time-to-exit*) (loop)))) ;; time to exit, close the no-sync db here (db:no-sync-close-db no-sync-db) (if (common:low-noise-print 30) (debug:print-info 0 *default-log-port* "Exiting watchdog timer, *time-to-exit* = " *time-to-exit*" pid="(current-process-id) ))))))) ;;" this-wd-num="this-wd-num))))))) |
Modified sharedat.scm from [aee689d39a] to [bb858ca5c8].
1 2 3 | ;; Copyright 2006-2013, Matthew Welland. ;; | | | > > > > > | | > > > > | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | ;; Copyright 2006-2013, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. (use defstruct) ;; (use ssax) ;; (use sxml-serializer) ;; (use sxml-modifications) ;; (use regex) |
︙ | ︙ |
Added show-uncalled-procedures.scm version [0afd5cabda].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | ;; Copyright 2006-2017, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. ;; (include "codescanlib.scm") (define (show-danglers) (let* ((all-scm-files (glob "*.scm")) (xref (get-xref all-scm-files)) (dangling-procs (map car (filter (lambda (x) (equal? 1 (length x))) xref)))) (for-each print dangling-procs) ;; our product. )) (show-danglers) |
Deleted spreadsheet/basic/Configurations2/accelerator/current.xml version [da39a3ee5e].
Deleted spreadsheet/basic/META-INF/manifest.xml version [d7d7c2a2dc].
|
| < < < < < < < < < < < < < < < < < < < < < < |
Deleted spreadsheet/basic/Thumbnails/thumbnail.png version [faa30ff37d].
cannot compute difference between binary files
Deleted spreadsheet/basic/content.xml version [2fc389eb9d].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted spreadsheet/basic/content.xml~ version [41688395c5].
|
| < < |
Deleted spreadsheet/basic/meta.xml version [a8103b8c6c].
|
| < < |
Deleted spreadsheet/basic/mimetype version [015538d968].
|
| < |
Deleted spreadsheet/basic/settings.xml version [ba07aed085].
|
| < < |
Deleted spreadsheet/basic/styles.xml version [e3b321fd12].
|
| < < |
Modified spublish.scm from [238d94c641] to [f88672550b].
1 2 3 | ;; Copyright 2006-2013, Matthew Welland. ;; | | | > > > > > | | > | > > < | < < | | < < < < | | < < < < < | | < < < < < > > > > > | | | | | | < | | > > > | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 | ;; Copyright 2006-2013, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. (use defstruct) (use scsh-process) (use refdb) (use srfi-18) (use srfi-19) (use format) (use sql-de-lite srfi-1 posix regex regex-case srfi-69) ;(declare (uses configf)) ;; (declare (uses tree)) (declare (uses margs)) (declare (uses megatest-version)) ;; (declare (uses tbd)) (include "megatest-fossil-hash.scm") ;;; please create this file before using sautherise. For sample file is avaliable sample-sauth-paths.scm. (include "sauth-paths.scm") (include "sauth-common.scm") (define (toplevel-command . args) #f) (use readline) ;; ;; GLOBALS ;; (define *spublish:current-tab-number* 0) (define *args-hash* (make-hash-table)) (define spublish:help (conc "Usage: spublish [action [params ...]] ls <area> : list contents of target area cp|publish <area> <src file> <destination> : copy file to target area mkdir <area> <dir name> : maks directory in target area rm <area> <file> : remove file <file> from target area ln <area> <target> <link name> : creates a symlink options: -m \"message\" : describe what was done Note: All the target locations relative to base path Part of the Megatest tool suite. Learn more at http://www.kiatoa.com/fossils/megatest Version: " megatest-fossil-hash)) ;; " ;;====================================================================== ;; RECORDS ;;====================================================================== ;;====================================================================== ;; DB ;;====================================================================== (define *default-log-port* (current-error-port)) (define *verbosity* 1) ;(define (spublish:initialize-db db) ; (for-each ; (lambda (qry) ; (exec (sql db qry))) ; (list ; "CREATE TABLE IF NOT EXISTS actions ; (id INTEGER PRIMARY KEY, ; action TEXT NOT NULL, ; submitter TEXT NOT NULL, ; datetime TIMESTAMP DEFAULT (strftime('%s','now')), ; srcpath TEXT NOT NULL, ; comment TEXT DEFAULT '' NOT NULL, ; state TEXT DEFAULT 'new');" ; ))) ;(define (spublish:register-action db action submitter source-path comment) ; (exec (sql db "INSERT INTO actions (action,submitter,srcpath,comment) ; VALUES(?,?,?,?)") ; action ; submitter ; source-path ; comment)) ;; (call-with-database ;; (lambda (db) ;; (set-busy-handler! db (busy-timeout 10000)) ; 10 second timeout ;; ...)) ;; Create the sqlite db ;(define (spublish:db-do configdat proc) ; (let ((path (configf:lookup configdat "database" "location"))) ; (if (not path) ; (begin ; (print "[database]\nlocation /some/path\n\n Is missing from the config file!") ; (exit 1))) ; (if (and path ; (directory? path) ; (file-read-access? path)) ; (let* ((dbpath (conc path "/spublish.db")) ; (writeable (file-write-access? dbpath)) ; (dbexists (file-exists? dbpath))) ; (handle-exceptions ; exn ; (begin ; (debug:print 2 *default-log-port* "ERROR: problem accessing db " dbpath ; ((condition-property-accessor 'exn 'message) exn)) ; (exit 1)) ; (call-with-database ; dbpath ; (lambda (db) ; ;; (print "calling proc " proc " on db " db) ; (set-busy-handler! db (busy-timeout 10000)) ;; 10 sec timeout ; (if (not dbexists)(spublish:initialize-db db)) ; (proc db))))) ; (print "ERROR: invalid path for storing database: " path)))) ; ;;; copy in file to dest, validation is done BEFORE calling this ;;; ;(define (spublish:cp configdat submitter source-path target-dir targ-file dest-dir comment) ; (let ((dest-dir-path (conc target-dir "/" dest-dir)) ; (targ-path (conc target-dir "/" dest-dir "/" targ-file))) ; (if (file-exists? targ-path) ; (begin ; (print "ERROR: target file already exists, remove it before re-publishing") ; (exit 1))) ; (if (not(file-exists? dest-dir-path)) ; (begin ; (print "ERROR: target directory " dest-dir-path " does not exists." ) ; (exit 1))) ; ; (spublish:db-do ; configdat ; (lambda (db) ; (spublish:register-action db "cp" submitter source-path comment))) ; (let* (;; (target-path (configf:lookup "settings" "target-path")) ; (th1 (make-thread ; (lambda () ; (file-copy source-path targ-path #t)) ; (print " ... file " targ-path " copied to " targ-path) ; ;; (let ((pid (process-run "cp" (list source-path target-dir)))) ; ;; (process-wait pid))) ; "copy thread")) ; (th2 (make-thread ; (lambda () ; (let loop () ; (thread-sleep! 15) ; (display ".") ; (flush-output) ; (loop))) ; "action is happening thread"))) ; (thread-start! th1) ; (thread-start! th2) ; (thread-join! th1)) ; (cons #t "Successfully saved data"))) ; ;;; copy directory to dest, validation is done BEFORE calling this ;;; ; ;(define (spublish:tar configdat submitter target-dir dest-dir comment) ; (let ((dest-dir-path (conc target-dir "/" dest-dir))) ; (if (not(file-exists? dest-dir-path)) ; (begin ; (print "ERROR: target directory " dest-dir-path " does not exists." ) ; (exit 1))) ; ;;(print dest-dir-path ) ; (spublish:db-do ; configdat ; (lambda (db) ; (spublish:register-action db "tar" submitter dest-dir-path comment))) ; (change-directory dest-dir-path) ; (process-wait (process-run "/bin/tar" (list "xf" "-"))) ; (print "Data copied to " dest-dir-path) ; ; (cons #t "Successfully saved data"))) ;(define (spublish:validate target-dir targ-mk) ; (let* ((normal-path (normalize-pathname targ-mk)) ; (targ-path (conc target-dir "/" normal-path))) ; (if (string-contains normal-path "..") ; (begin ; (print "ERROR: Path " targ-mk " resolved outside target area " target-dir ) ; (exit 1))) ; ; (if (not (string-contains targ-path target-dir)) ; (begin ; (print "ERROR: You cannot update data outside " target-dir ".") ; (exit 1))) ; (print "Path " targ-mk " is valid.") ; )) ;; make directory in dest ;; ;(define (spublish:mkdir configdat submitter target-dir targ-mk comment) ; (let ((targ-path (conc target-dir "/" targ-mk))) ; ; (if (file-exists? targ-path) ; (begin ; (print "ERROR: target Directory " targ-path " already exist!!") ; (exit 1))) ; (spublish:db-do ; configdat ; (lambda (db) ; (spublish:register-action db "mkdir" submitter targ-mk comment))) ; (let* ((th1 (make-thread ; (lambda () ; (create-directory targ-path #t) ; (print " ... dir " targ-path " created")) ; "mkdir thread")) ; (th2 (make-thread ; (lambda () ; (let loop () ; (thread-sleep! 15) ; (display ".") ; (flush-output) ; (loop))) ; "action is happening thread"))) ; (thread-start! th1) ; (thread-start! th2) ; (thread-join! th1)) ; (cons #t "Successfully saved data"))) ;; create a symlink in dest ;; ;(define (spublish:ln configdat submitter target-dir targ-link link-name comment) ; (let ((targ-path (conc target-dir "/" link-name))) ; (if (file-exists? targ-path) ; (begin ; (print "ERROR: target file " targ-path " already exist!!") ; (exit 1))) ; (if (not (file-exists? targ-link )) ; (begin ; (print "ERROR: target file " targ-link " does not exist!!") ; (exit 1))) ; ; (spublish:db-do ; configdat ; (lambda (db) ; (spublish:register-action db "ln" submitter link-name comment))) ; (let* ((th1 (make-thread ; (lambda () ; (create-symbolic-link targ-link targ-path ) ; (print " ... link " targ-path " created")) ; "symlink thread")) ; (th2 (make-thread ; (lambda () ; (let loop () ; (thread-sleep! 15) ; (display ".") ; (flush-output) ; (loop))) ; "action is happening thread"))) ; (thread-start! th1) ; (thread-start! th2) ; (thread-join! th1)) ; (cons #t "Successfully saved data"))) ;; remove copy of file in dest ;; ;(define (spublish:rm configdat submitter target-dir targ-file comment) ; (let ((targ-path (conc target-dir "/" targ-file))) ; (if (not (file-exists? targ-path)) ; (begin ; (print "ERROR: target file " targ-path " not found, nothing to remove.") ; (exit 1))) ; (spublish:db-do ; configdat ; (lambda (db) ; (spublish:register-action db "rm" submitter targ-file comment))) ; (let* ((th1 (make-thread ; (lambda () ; (delete-file targ-path) ; (print " ... file " targ-path " removed")) ; "rm thread")) ; (th2 (make-thread ; (lambda () ; (let loop () ; (thread-sleep! 15) ; (display ".") ; (flush-output) ; (loop))) ; "action is happening thread"))) ; (thread-start! th1) ; (thread-start! th2) ; (thread-join! th1)) ; (cons #t "Successfully saved data"))) (define (spublish:backup-move path) (let* ((trashdir (conc (pathname-directory path) "/.trash")) (trashfile (conc trashdir "/" (current-seconds) "-" (pathname-file path)))) (create-directory trashdir #t) (if (directory? path) (system (conc "mv " path " " trashfile)) |
︙ | ︙ | |||
321 322 323 324 325 326 327 | ((file-exists? path) "found") (else (conc path " not installed")))) ;;====================================================================== ;; MISC ;;====================================================================== | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | > > > > > > > > > > > > > > > > > > > > > | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > | > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > | > > > > > > | | > > > > > > > > > | | | > | > > > > > > > > | > > > > > > > > > > > > > > | | | | | | | | | | | | > > > | < < < > | | | < < < < | | | | | < | > | > | < | < | | < < < < | > > > | | | > | | > | | | < | > | < < < < < | < | > > | | > | | > > | | | > | < | < | < < < | < < | | | > | > | < | | | < | > | < < < < < | < > | > | | < < < < < < < | | | < < < | < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < | | 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 | ((file-exists? path) "found") (else (conc path " not installed")))) ;;====================================================================== ;; MISC ;;====================================================================== ;(define (spublish:do-as-calling-user proc) ; (let ((eid (current-effective-user-id)) ; (cid (current-user-id))) ; (if (not (eq? eid cid)) ;; running suid ; (set! (current-effective-user-id) cid)) ; ;; (print "running as " (current-effective-user-id)) ; (proc) ; (if (not (eq? eid cid)) ; (set! (current-effective-user-id) eid)))) ;(define (spublish:find name paths) ; (if (null? paths) ; #f ; (let loop ((hed (car paths)) ; (tal (cdr paths))) ; (if (file-exists? (conc hed "/" name)) ; hed ; (if (null? tal) ; #f ; (loop (car tal)(cdr tal))))))) ;;======================================================================== ;;Shell ;;======================================================================== (define (spublish:get-accessable-projects area) (let* ((projects `())) (if (spublish:has-permission area) (set! projects (cons area projects)) (begin (print "User cannot access area " area "!!") (exit 1))) projects)) ;; function to find sheets to which use has access (define (spublish:has-permission area) ;(print "in spublish:has-permission") (let* ((username (current-user-name)) (ret-val #f)) (cond ((equal? (is-admin username) #t) (set! ret-val #t)) ((equal? (is-user "publish" username area) #t) (set! ret-val #t)) ((equal? (is-user "writer-admin" username area) #t) (set! ret-val #t)) ((equal? (is-user "area-admin" username area) #t) (set! ret-val #t)) (else (set! ret-val #f))) ret-val)) (define (is_directory target-path) (let* ((retval #f)) (sauthorize:do-as-calling-user (lambda () ;(print (current-effective-user-id) ) (if (directory? target-path) (set! retval #t)))) ;(print (current-effective-user-id)) retval)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; shell functions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (define (spublish:shell-cp src-path target-path) (cond ((not (file-exists? target-path)) (sauth:print-error (conc " target Directory " target-path " does not exist!!"))) ((not (file-exists? src-path)) (sauth:print-error (conc "Source path " src-path " does not exist!!" ))) (else (if (is_directory src-path) (begin (let* ((parent-dir src-path) (start-dir target-path)) (run (pipe (begin (system (conc "cd " parent-dir " ;tar chf - ." ))) (begin (change-directory start-dir) ;(print "123") (run-cmd "tar" (list "xf" "-"))))) (print "Copied data to " start-dir))) (begin (let*((parent-dir (pathname-directory src-path)) (start-dir target-path) (filename (if (pathname-extension src-path) (conc(pathname-file src-path) "." (pathname-extension src-path)) (pathname-file src-path)))) ;(print "parent-dir " parent-dir " start-dir " start-dir) (run (pipe (begin (system (conc "cd " parent-dir ";tar chf - " filename ))) (begin (change-directory start-dir) (run-cmd "tar" (list "xf" "-"))))) (print "Copied data to " start-dir))))))) (define (spublish:shell-mkdir targ-path) (if (file-exists? targ-path) (begin (print "Info: Target Directory " targ-path " already exist!!")) (let* ((th1 (make-thread (lambda () (create-directory targ-path #t) (print " ... dir " targ-path " created")) "mkdir thread")) (th2 (make-thread (lambda () (let loop () (thread-sleep! 15) (display ".") (flush-output) (loop))) "action is happening thread"))) (thread-start! th1) (thread-start! th2) (thread-join! th1) (cons #t "Successfully saved data")))) (define (spublish:shell-rm targ-path iport) (if (not (file-exists? targ-path)) (begin (sauth:print-error (conc "target path " targ-path " does not exist!!"))) (begin (print "Are you sure you want to delete " targ-path "?[y/n]") (let* ((inl (read-line iport))) (if (equal? inl "y") (let* ((th1 (make-thread (lambda () (if (symbolic-link? targ-path) (delete-file targ-path ) (if (directory? targ-path) (delete-directory targ-path #t) (delete-file targ-path ))) (print " ... path " targ-path " deleted")) "rm thread")) (th2 (make-thread (lambda () (let loop () (thread-sleep! 15) (display ".") (flush-output) (loop))) "action is happening thread"))) (thread-start! th1) (thread-start! th2) (thread-join! th1) (cons #t "Successfully saved data"))))))) (define (spublish:shell-ln src-path target-path sub-path) (if (not (file-exists? sub-path)) (sauth:print-error (conc "Path " sub-path " does not exist!! cannot proceed with link creation!!")) (begin (if (not (file-exists? src-path)) (sauth:print-error (conc "Path " src-path " does not exist!! cannot proceed with link creation!!")) (begin (if (file-exists? target-path) (sauth:print-error (conc "Path " target-path "already exist!! cannot proceed with link creation!!")) (begin (create-symbolic-link src-path target-path ) (print " ... link " target-path " created")))))))) (define (spublish:shell-help) (conc "Usage: [action [params ...]] ls [target path] : list contents of target area. cd <target path> : To change the current directory within the sretrive shell. pwd : Prints the full pathname of the current directory within the sretrive shell. mkdir <path> : creates directory. Note it does not create's a path recursive manner. rm <target path> : removes files and emoty directories cp <src> <target path> : copy a file/dir to target path. if src is a dir it automatically makes a recursive copy. ln TARGET LINK_NAME : creates a symlink Part of the Megatest tool suite. Learn more at http://www.kiatoa.com/fossils/megatest Version: " megatest-fossil-hash) ) (define (toplevel-command . args) #f) (define (spublish:shell area) ; (print area) (use readline) (let* ((path '()) (prompt "spublish> ") (args (argv)) (usr (current-user-name) ) (top-areas (spublish:get-accessable-projects area)) (close-port #f) (area-obj (get-obj-by-code area)) (user-obj (get-user usr)) (base-path (if (null? area-obj) "" (caddr (cdr area-obj)))) (iport (make-readline-port prompt))) ;(print base-path) (if (null? area-obj) (begin (print "Area " area " does not exist") (exit 1))) ; (print "here") (let loop ((inl (read-line iport))) (if (not (or (or (eof-object? inl) (equal? inl "exit")) (port-closed? iport))) (let* ((parts (string-split inl)) (cmd (if (null? parts) #f (car parts)))) (if (and (not cmd) (not (port-closed? iport))) (loop (read-line)) (case (string->symbol cmd) ((cd) (if (> (length parts) 1) ;; have a parameter (begin (let*((arg (cadr parts)) (resolved-path (sauth-common:resolve-path arg path top-areas)) (target-path (sauth-common:get-target-path path arg top-areas base-path))) (if (not (equal? target-path #f)) (if (or (equal? resolved-path #f) (not (file-exists? target-path))) (print "Invalid argument " arg ".. ") (begin (set! path resolved-path) (sauthorize:do-as-calling-user (lambda () (run-cmd (conc *sauth-path* "/sauthorize") (list "register-log" (conc "\"" inl "\"") (number->string (car user-obj)) (number->string (caddr area-obj)) "cd")))) ))))) (set! path '()))) ((pwd) (if (null? path) (print "/") (print "/" (string-join path "/")))) ((ls) (let* ((thepath (if (> (length parts) 1) ;; have a parameter (cdr parts) `())) (plen (length thepath))) (cond ((null? thepath) (sauth-common:shell-ls-cmd path "" top-areas base-path '()) (sauthorize:do-as-calling-user (lambda () (run-cmd (conc *sauth-path* "/sauthorize") (list "register-log" (conc "\"" inl "\"") (number->string (car user-obj)) (number->string (caddr area-obj)) "ls")))) ) ((< plen 2) (sauth-common:shell-ls-cmd path (car thepath) top-areas base-path '()) (sauthorize:do-as-calling-user (lambda () (run-cmd (conc *sauth-path* "/sauthorize") (list "register-log" (conc "\"" inl "\"") (number->string (car user-obj)) (number->string (caddr area-obj)) "ls"))))) (else (if (equal? (car thepath) "|") (sauth-common:shell-ls-cmd path "" top-areas base-path thepath) (sauth-common:shell-ls-cmd path (car thepath) top-areas base-path (cdr thepath))) (sauthorize:do-as-calling-user (lambda () (run-cmd (conc *sauth-path* "/sauthorize") (list "register-log" (conc "\"" inl "\"") (number->string (car user-obj)) (number->string (caddr area-obj)) "ls")))))))) ((mkdir) (let* ((thepath (if (> (length parts) 1) ;; have a parameter (cdr parts) `())) (plen (length thepath))) (cond ((null? thepath) (print "mkdir takes one argument")) ((< plen 2) (let*((mk-path (cadr parts)) (resolved-path (sauth-common:resolve-path mk-path path top-areas)) (target-path (sauth-common:get-target-path path mk-path top-areas base-path))) (if (not (equal? target-path #f)) (if (equal? resolved-path #f) (print "Invalid argument " mk-path ".. ") (begin (print "here") (spublish:shell-mkdir target-path) (sauthorize:do-as-calling-user (lambda () (run-cmd (conc *sauth-path* "/sauthorize") (list "register-log" (conc "\"" inl "\"") (number->string (car user-obj)) (number->string (caddr area-obj)) "mkdir"))))))) ))))) ((rm) (let* ((thepath (if (> (length parts) 1) ;; have a parameter (cdr parts) `())) (plen (length thepath))) (cond ((null? thepath) (print "rm takes one argument")) ((< plen 2) (let*((rm-path (cadr parts)) (resolved-path (sauth-common:resolve-path rm-path path top-areas)) (target-path (sauth-common:get-target-path path rm-path top-areas base-path))) (if (not (equal? target-path #f)) (if (equal? resolved-path #f) (print "Invalid argument " rm-path ".. ") (begin (spublish:shell-rm target-path iport) (sauthorize:do-as-calling-user (lambda () (run-cmd (conc *sauth-path* "/sauthorize") (list "register-log" (conc "\"" inl "\"") (number->string (car user-obj)) (number->string (caddr area-obj)) "rm"))))))) ))))) ((cp publish) (let* ((thepath (if (> (length parts) 1) ;; have a parameter (cdr parts) `())) (plen (length thepath))) (cond ((or (null? thepath) (< plen 2)) (print "cp takes two argument")) ((< plen 3) (let*((src-path (car thepath)) (dest-path (cadr thepath)) (resolved-path (sauth-common:resolve-path dest-path path top-areas)) (target-path (sauth-common:get-target-path path dest-path top-areas base-path))) (if (not (equal? target-path #f)) (if (equal? resolved-path #f) (print "Invalid argument " dest-path ".. ") (begin (spublish:shell-cp src-path target-path) (sauthorize:do-as-calling-user (lambda () (run-cmd (conc *sauth-path* "/sauthorize") (list "register-log" (conc "\"" inl "\"") (number->string (car user-obj)) (number->string (caddr area-obj)) "cp"))))))) ))))) ((ln) (let* ((thepath (if (> (length parts) 1) ;; have a parameter (cdr parts) `())) (plen (length thepath))) (cond ((or (null? thepath) (< plen 2)) (print "ln takes two argument")) ((< plen 3) (let*((src-path (car thepath)) (dest-path (cadr thepath)) (resolved-path (sauth-common:resolve-path dest-path path top-areas)) (target-path (sauth-common:get-target-path path dest-path top-areas base-path)) (sub-path (conc "/" (string-reverse (string-join (cdr (string-split (string-reverse target-path) "/")) "/"))))) (if (not (equal? target-path #f)) (if (equal? resolved-path #f) (print "Invalid argument " dest-path ".. ") (begin (spublish:shell-ln src-path target-path sub-path) (sauthorize:do-as-calling-user (lambda () (run-cmd (conc *sauth-path* "/sauthorize") (list "register-log" (conc "\"" inl "\"") (number->string (car user-obj)) (number->string (caddr area-obj)) "ln"))))))) ))))) ((exit) (print "got exit")) ((help) (print (spublish:shell-help))) (else (print "Got command: " inl)))) (loop (read-line iport))))))) ;;====================================================================== ;; MAIN ;;====================================================================== ;(define (spublish:load-config exe-dir exe-name) ; (let* ((fname (conc exe-dir "/." exe-name ".config"))) ;; (ini:property-separator-patt " * *") ;; (ini:property-separator #\space) ; (if (file-exists? fname) ; ;; (ini:read-ini fname) ; (read-config fname #f #t) ; (make-hash-table)))) (define (spublish:process-action action . args) ;(print args) (let* ((usr (current-user-name)) (user-obj (get-user usr)) (area (car args)) (area-obj (get-obj-by-code area)) (top-areas (spublish:get-accessable-projects area)) (base-path (if (null? area-obj) "" (caddr (cdr area-obj)))) (remargs (cdr args))) (if (null? area-obj) (begin (print "Area " area " does not exist") (exit 1))) (case (string->symbol action) ((cp publish) (if (< (length remargs) 2) (begin (print "ERROR: Missing arguments; spublish <area> <src file> <destination>" ) (exit 1))) (let* ((filter-args (args:get-args args '("-m") '() args:arg-hash 0)) (src-path-in (car filter-args)) (dest-path (cadr filter-args)) (src-path (with-input-from-pipe (conc "readlink -f " src-path-in) (lambda () (read-line)))) (msg (or (args:get-arg "-m") "")) (resolved-path (sauth-common:resolve-path (conc area "/" dest-path) `() top-areas)) (target-path (sauth-common:get-target-path `() (conc area "/" dest-path) top-areas base-path))) (if (not (equal? target-path #f)) (if (equal? resolved-path #f) (print "Invalid argument " dest-path ".. ") (begin (spublish:shell-cp src-path target-path) (sauthorize:do-as-calling-user (lambda () (run-cmd (conc *sauth-path* "/sauthorize") (list "register-log" (conc "\" cp " src-path-in " " dest-path "\"") (number->string (car user-obj)) (number->string (caddr area-obj)) "cp"))))))))) ((mkdir) (if (< (length remargs) 1) (begin (print "ERROR: Missing arguments; <area> <path>") (exit 1))) (let* ((filter-args (args:get-args args '("-m") '() args:arg-hash 0)) (mk-path (car filter-args)) (msg (or (args:get-arg "-m") "")) (resolved-path (sauth-common:resolve-path mk-path (list area) top-areas)) (target-path (sauth-common:get-target-path (list area) mk-path top-areas base-path))) (print "attempting to create directory " mk-path ) (if (not (equal? target-path #f)) (if (equal? resolved-path #f) (print "Invalid argument " mk-path ".. ") (begin (spublish:shell-mkdir target-path) (sauthorize:do-as-calling-user (lambda () (run-cmd (conc *sauth-path* "/sauthorize") (list "register-log" (conc "\" mkdir " mk-path "\"") (number->string (car user-obj)) (number->string (caddr area-obj)) "mkdir"))))))))) ((ln) (if (< (length remargs) 2) (begin (print "ERROR: Missing arguments; <area> <target> <link name>" ) (exit 1))) (let* ((filter-args (args:get-args args '("-m") '() args:arg-hash 0)) (src-path (car filter-args)) (dest-path (cadr filter-args)) (resolved-path (sauth-common:resolve-path dest-path (list area) top-areas)) (target-path (sauth-common:get-target-path (list area) dest-path top-areas base-path)) (sub-path (conc "/" (string-reverse (string-join (cdr (string-split (string-reverse target-path) "/")) "/"))))) (if (not (equal? target-path #f)) (if (equal? resolved-path #f) (print "Invalid argument " dest-path ".. ") (begin (spublish:shell-ln src-path target-path sub-path) (sauthorize:do-as-calling-user (lambda () (run-cmd (conc *sauth-path* "/sauthorize") (list "register-log" (conc "\" ln " src-path " " dest-path "\"") (number->string (car user-obj)) (number->string (caddr area-obj)) "ln"))))))))) ((rm) (if (< (length remargs) 1) (begin (print "ERROR: Missing arguments; <area> <path> ") (exit 1))) (let* ((filter-args (args:get-args args '("-m") '() args:arg-hash 0)) (rm-path (car filter-args)) (resolved-path (sauth-common:resolve-path rm-path (list area) top-areas)) (prompt ">") (iport (make-readline-port prompt)) (target-path (sauth-common:get-target-path (list area) rm-path top-areas base-path))) (if (not (equal? target-path #f)) (if (equal? resolved-path #f) (print "Invalid argument " rm-path ".. ") (begin (spublish:shell-rm target-path iport) (sauthorize:do-as-calling-user (lambda () (run-cmd (conc *sauth-path* "/sauthorize") (list "register-log" (conc "\" rm " rm-path "\"") (number->string (car user-obj)) (number->string (caddr area-obj)) "rm"))))))))) ((shell) (if (< (length args) 1) (begin (print "ERROR: Missing arguments area!!" ) (exit 1)) (spublish:shell area))) (else (print "Unrecognised command " action))))) ;; ease debugging by loading ~/.dashboardrc - REMOVE FROM PRODUCTION! ;; (let ((debugcontrolf (conc (get-environment-variable "HOME") "/.spublishrc"))) ;; (if (file-exists? debugcontrolf) ;; (load debugcontrolf))) (define (main) (let* ((args (argv)) (prog (car args)) (rema (cdr args)) (exe-name (pathname-file (car (argv))))) (cond ;; one-word commands ((eq? (length rema) 1) (case (string->symbol (car rema)) ((help -h -help --h --help) (print spublish:help)) (else (print "ERROR: Unrecognised command. Try \"spublish help\"")))) ;; multi-word commands ((null? rema)(print spublish:help)) ((>= (length rema) 2) (apply spublish:process-action (car rema)(cdr rema))) (else (print "ERROR: Unrecognised command2. Try \"spublish help\""))))) (main) |
Modified sretrieve.scm from [f347600c92] to [d2b597ab3b].
1 2 3 | ;; Copyright 2006-2013, Matthew Welland. ;; | | | > > > > > | | > | > > > < | < < < | < < < < < | | < < < < < < | | < < < < < < | > > > > > > > > > | | | < < | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | < | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | < | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | < < < < | | < < < < | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | | | | | | | | | | | | | | | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 | ;; Copyright 2006-2013, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. ;; (use defstruct) (use scsh-process) (use srfi-18) (use srfi-19) (use refdb) (use sql-de-lite srfi-1 posix regex regex-case srfi-69) ;(declare (uses common)) ;(declare (uses configf)) (declare (uses margs)) (declare (uses megatest-version)) (include "megatest-fossil-hash.scm") ;;; please create this file before using sautherise. For sample file is avaliable sample-sauth-paths.scm. (include "sauth-paths.scm") (include "sauth-common.scm") (define (toplevel-command . args) #f) (use readline) ;; ;; GLOBALS ;; (define *verbosity* 1) (define *logging* #f) (define *exe-name* (pathname-file (car (argv)))) (define *sretrieve:current-tab-number* 0) (define *args-hash* (make-hash-table)) (define sretrieve:help (conc "Usage: " *exe-name* " [action [params ...]] ls <area> : list contents of target area get <area> <reletive path> : retrieve path to the data within <area> -m \"message\" : why retrieved? shell <area> : start a shell-like interface Part of the Megatest tool suite. Learn more at http://www.kiatoa.com/fossils/megatest Version: " megatest-fossil-hash)) ;; " ;;====================================================================== ;; RECORDS ;;====================================================================== ;;====================================================================== ;; DB ;;====================================================================== ;; replace (strftime('%s','now')), with datetime('now')) ;(define (sretrieve:initialize-db db) ; (for-each ; (lambda (qry) ; (exec (sql db qry))) ; (list ; "CREATE TABLE IF NOT EXISTS actions ; (id INTEGER PRIMARY KEY, ; action TEXT NOT NULL, ; retriever TEXT NOT NULL, ; datetime TIMESTAMP DEFAULT (datetime('now','localtime')), ; srcpath TEXT NOT NULL, ; comment TEXT DEFAULT '' NOT NULL, ; state TEXT DEFAULT 'new');" ; "CREATE TABLE IF NOT EXISTS bundles ; (id INTEGER PRIMARY KEY, ; bundle TEXT NOT NULL, ; release TEXT NOT NULL, ; status TEXT NOT NULL, ; event_date TEXT NOT NULL);" ; ))) ; ;(define (sretrieve:register-action db action submitter source-path comment) ; ; (print "(sretrieve:register-action db " db " action " action " submitter " submitter " source-path " source-path " comment " comment) ; (exec (sql db "INSERT INTO actions (action,retriever,srcpath,comment) ; VALUES(?,?,?,?)") ; action ; submitter ; source-path ; (or comment ""))) ;; (call-with-database ;; (lambda (db) ;; (set-busy-handler! db (busy-timeout 10000)) ; 10 second timeout ;; ...)) ;; Create the sqlite db ;(define (sretrieve:db-do configdat proc) ; (let ((path (configf:lookup configdat "database" "location"))) ; (if (not path) ; (begin ; (debug:print 0 "[database]\nlocation /some/path\n\n Is missing from the config file!") ; (exit 1))) ; (if (and path ; (directory? path) ; (file-read-access? path)) ; (let* ((dbpath (conc path "/" *exe-name* ".db")) ; (writeable (file-write-access? dbpath)) ; (dbexists (file-exists? dbpath))) ; (handle-exceptions ; exn ; (begin ; (debug:print 2 "ERROR: problem accessing db " dbpath ; ((condition-property-accessor 'exn 'message) exn)) ; (exit 1)) ; ;;(debug:print 0 "calling proc " proc "db path " dbpath ) ; (call-with-database ; dbpath ; (lambda (db) ; ;;(debug:print 0 "calling proc " proc " on db " db) ; (set-busy-handler! db (busy-timeout 10000)) ;; 10 sec timeout ; (if (not dbexists)(sretrieve:initialize-db db)) ; (proc db))))) ; (debug:print 0 "ERROR: invalid path for storing database: " path)))) ;; copy in directory to dest, validation is done BEFORE calling this ;; ;(define (sretrieve:get configdat retriever version comment) ; (let* ((base-dir (configf:lookup configdat "settings" "base-dir")) ; (datadir (conc base-dir "/" version))) ; (if (or (not base-dir) ; (not (file-exists? base-dir))) ; (begin ; (debug:print 0 "ERROR: Bad configuration! base-dir " base-dir " not found") ; (exit 1))) ; (print datadir) ; (if (not (file-exists? datadir)) ; (begin ; (debug:print 0 "ERROR: Bad version (" version "), no data found at " datadir "." ) ; (exit 1))) ; ; (sretrieve:db-do ; configdat ; (lambda (db) ; (sretrieve:register-action db "get" retriever datadir comment))) ; (sretrieve:do-as-calling-user ; (lambda () ; (if (directory? datadir) ; (begin ; (change-directory datadir) ; (let ((files (filter (lambda (x) ; (not (member x '("." "..")))) ; (glob "*" ".*")))) ; (print "files: " files) ; (process-execute "/bin/tar" (append (append (list "chfv" "-") files) (list "--ignore-failed-read"))))) ; (begin ; (let* ((parent-dir (pathname-directory datadir) ) ; (filename (conc(pathname-file datadir) "." (pathname-extension datadir)))) ; (change-directory parent-dir) ; (process-execute "/bin/tar" (list "chfv" "-" filename)) ; ))) ;)))) ; ; ;;; copy in file to dest, validation is done BEFORE calling this ;;; ;(define (sretrieve:cp configdat retriever file comment) ; (let* ((base-dir (configf:lookup configdat "settings" "base-dir")) ; (allowed-sub-paths (configf:lookup configdat "settings" "allowed-sub-paths")) ; (datadir (conc base-dir "/" file)) ; (filename (conc(pathname-file datadir) "." (pathname-extension datadir)))) ; (if (or (not base-dir) ; (not (file-exists? base-dir))) ; (begin ; (debug:print 0 "ERROR: Bad configuration! base-dir " base-dir " not found") ; (exit 1))) ; (print datadir) ; (if (not (file-exists? datadir)) ; (begin ; (debug:print 0 "ERROR: File (" file "), not found at " base-dir "." ) ; (exit 1))) ; (if (directory? datadir) ; (begin ; (debug:print 0 "ERROR: (" file ") is a dirctory!! cp cmd works only on files ." ) ; (exit 1))) ; (if(not (string-match (regexp allowed-sub-paths) file)) ; (begin ; (debug:print 0 "ERROR: Access denied to file (" file ")!! " ) ; (exit 1))) ; ; (sretrieve:db-do ; configdat ; (lambda (db) ; (sretrieve:register-action db "cp" retriever datadir comment))) ; (sretrieve:do-as-calling-user ; ;; (debug:print 0 "ph: "(pathname-directory datadir) "!! " ) ; (change-directory (pathname-directory datadir)) ; ;;(debug:print 0 "ph: /bin/tar" (list "chfv" "-" filename) ) ; (process-execute "/bin/tar" (list "chfv" "-" filename))) ; )) ; ;;; ls in file to dest, validation is done BEFORE calling this ;;; ;(define (sretrieve:ls configdat retriever file comment) ; (let* ((base-dir (configf:lookup configdat "settings" "base-dir")) ; (allowed-sub-paths (configf:lookup configdat "settings" "allowed-sub-paths")) ; (datadir (conc base-dir "/" file)) ; (filename (conc(pathname-file datadir) "." (pathname-extension datadir)))) ; (if (or (not base-dir) ; (not (file-exists? base-dir))) ; (begin ; (debug:print 0 "ERROR: Bad configuration! base-dir " base-dir " not found") ; (exit 1))) ; (print datadir) ; (if (not (file-exists? datadir)) ; (begin ; (debug:print 0 "ERROR: File (" file "), not found at " base-dir "." ) ; (exit 1))) ; (if(not (string-match (regexp allowed-sub-paths) file)) ; (begin ; (debug:print 0 "ERROR: Access denied to file (" file ")!! " ) ; (exit 1))) ; ; (sretrieve:do-as-calling-user ; (lambda () ; (process-execute "/bin/ls" (list "-ls" "-lrt" datadir )) ; )))) (define (sretrieve:validate target-dir targ-mk) (let* ((normal-path (normalize-pathname targ-mk)) (targ-path (conc target-dir "/" normal-path))) (if (string-contains normal-path "..") (begin (debug:print 0 "ERROR: Path " targ-mk " resolved outside target area " target-dir ) (exit 1))) (if (not (string-contains targ-path target-dir)) (begin (debug:print 0 "ERROR: You cannot update data outside " target-dir ".") (exit 1))) (debug:print 0 "Path " targ-mk " is valid.") )) ;(define (sretrieve:backup-move path) ; (let* ((trashdir (conc (pathname-directory path) "/.trash")) ; (trashfile (conc trashdir "/" (current-seconds) "-" (pathname-file path)))) ; (create-directory trashdir #t) ; (if (directory? path) ; (system (conc "mv " path " " trashfile)) ; (file-move path trash-file)))) ; ; ;(define (sretrieve:lst->path pathlst) ; (conc "/" (string-intersperse (map conc pathlst) "/"))) ; ;(define (sretrieve:path->lst path) ; (string-split path "/")) ; ;(define (sretrieve:pathdat-apply-heuristics configdat path) ; (cond ; ((file-exists? path) "found") ; (else (conc path " not installed")))) ;;====================================================================== ;; MISC ;;====================================================================== (define (sretrieve:do-as-calling-user proc) (let ((eid (current-effective-user-id)) (cid (current-user-id))) (if (not (eq? eid cid)) ;; running suid (set! (current-effective-user-id) cid)) ;; (debug:print 0 "running as " (current-effective-user-id)) (proc) (if (not (eq? eid cid)) (set! (current-effective-user-id) eid)))) (define (sretrieve:find name paths) (if (null? paths) #f |
︙ | ︙ | |||
415 416 417 418 419 420 421 | (lambda () (apply print args)))) ;;====================================================================== ;; SHELL ;;====================================================================== | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | > | > > | > > > > > > < < | > > > | > | | > | > | > > > > > > > > > > > | > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | > > | > > > > > > | > > > | < > | > > | | | | | | | | > | | | | | | < < < | | | | | | | | | | < < | | | | | | | > | < < < < < < < | < | < < < < < < < < < < | | | > | > > | | > > | | < > > > > > > > > > | > > > > > | | | | | > | > > > > > > > | | > | > > > > > > > | > > > > > > > | | > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > | | < > | > > > | > > > > > > > | > | > > > > > > > > > > | > > > | > > > | > > > > > > > > | < < > | > > > | > | > | | < < < < < < < < < < < < < < < < < < < < > | | > > > | 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 | (lambda () (apply print args)))) ;;====================================================================== ;; SHELL ;;====================================================================== ;; Create the sqlite db for shell ;(define (sretrieve:shell-db-do path proc) ; (if (not path) ; (begin ; (debug:print 0 "[database]\nlocation /some/path\n\n Is missing from the config file!") ; (exit 1))) ; (if (and path ; (directory? path) ; (file-read-access? path)) ; (let* ((dbpath (conc path "/" *exe-name* ".db")) ; (writeable (file-write-access? dbpath)) ; (dbexists (file-exists? dbpath))) ; (handle-exceptions ; exn ; (begin ; (debug:print 2 "ERROR: problem accessing db " dbpath ; ((condition-property-accessor 'exn 'message) exn)) ; (exit 1)) ; ;;(debug:print 0 "calling proc " proc "db path " dbpath ) ; (call-with-database ; dbpath ; (lambda (db) ; ;;(debug:print 0 "calling proc " proc " on db " db) ; (set-busy-handler! db (busy-timeout 10000)) ;; 10 sec timeout ; (if (not dbexists)(sretrieve:initialize-db db)) ; (proc db))))) ; (debug:print 0 "ERROR: invalid path for storing database: " path))) ;; function to find sheets to which use has access (define (sretrieve:has-permission area) (let ((username (current-user-name))) (cond ((is-admin username) #t) ((is-user "retrieve" username area) #t) ((is-user "publish" username area) #t) ((is-user "writer-admin" username area) #t) ((is-user "read-admin" username area) #t) ((is-user "area-admin" username area) #t) (else #f)))) (define (sretrieve:get-accessable-projects area) (let* ((projects `())) (if (sretrieve:has-permission area) (set! projects (cons area projects)) (begin (sauth:print-error (conc "User cannot access area " area "!!")) (exit 1))) ; (print projects) projects)) (define (sauth-common:shell-ls-cmd base-path-list ext-path top-areas base-path tail-cmd-list) (if (and (null? base-path-list) (equal? ext-path "") ) (print (string-intersperse top-areas " ")) (let* ((resolved-path (sauth-common:resolve-path ext-path base-path-list top-areas ))) ;(print resolved-path) (if (not (equal? resolved-path #f)) (if (null? resolved-path) (print (string-intersperse top-areas " ")) (let* ((target-path (sauth-common:get-target-path base-path-list ext-path top-areas base-path))) ;(print "Resolved path: " target-path) (if (not (equal? target-path #f)) (begin (if (symbolic-link? target-path) (set! target-path (conc target-path "/"))) (if (not (equal? target-path #f)) (begin (cond ((null? tail-cmd-list) (run (pipe (ls "-lrt" ,target-path)))) ((not (equal? (car tail-cmd-list) "|")) (print "ls cmd cannot accept "(string-join tail-cmd-list) " as an argument!!")) (else (run (pipe (ls "-lrt" ,target-path) (begin (system (string-join (cdr tail-cmd-list)))))) )))))))))))) (define (sretrieve:shell-cat-cmd base-pathlist ext-path top-areas base-path tail-cmd-list) (let* ((resolved-path (sauth-common:resolve-path ext-path base-pathlist top-areas )) (data "") ) (if (not (equal? resolved-path #f)) (if (null? resolved-path) (print "Path could not be resolved!!") (let* ((target-path (sauth-common:get-target-path base-pathlist ext-path top-areas base-path))) (if (not (equal? target-path #f)) (if (or (not (file-exists? target-path)) (directory? target-path)) (print "Target path does not exist or is a directory!") (begin (cond ((null? tail-cmd-list) (run (pipe (cat ,target-path)))) ((not (equal? (car tail-cmd-list) "|")) (print "cat cmd cannot accept "(string-join tail-cmd-list) " as an argument!!")) (else (run (pipe (cat ,target-path) (begin (system (string-join (cdr tail-cmd-list)))))))))) ))) (print "Path could not be resolved!!")))) (define (get-options cmd-list split-str) (if (null? cmd-list) (list '() '()) (let loop ((hed (car cmd-list)) (tal (cdr cmd-list)) (res '())) (cond ((equal? hed split-str) (list res tal)) ((null? tal) (list (cons hed res) tal)) (else (loop (car tal)(cdr tal)(cons hed res))))))) (define (sretrieve:shell-grep-cmd base-pathlist ext-path top-areas base-path tail-cmd-list) (let* ((resolved-path (sauth-common:resolve-path ext-path base-pathlist top-areas )) (pattern (car tail-cmd-list)) (pipe-cmd-list (get-options (cdr tail-cmd-list) "|")) (options (string-join (car pipe-cmd-list))) (pipe-cmd (cadr pipe-cmd-list)) (redirect-split (string-split (string-join tail-cmd-list) ">")) ) (if(and ( > (length redirect-split) 2 )) (print "sgrep cmd cannot accept > " (string-join redirect-split) " as an argument!!" ) (if (not (equal? resolved-path #f)) (if (null? resolved-path) (print "Path could not be resolved!!") (let* ((target-path (sauth-common:get-target-path base-pathlist ext-path top-areas base-path)) (restrictions (if (equal? target-path #f) "" (sretrieve:shell-lookup base-path))) (rest-str (string-split (conc " --exclude-dir=" (string-join (string-split restrictions ",") " --exclude-dir=") )))) (if (not (file-exists? target-path)) (print "Target path does not exist!") (begin (cond ((and (null? pipe-cmd) (string-null? options)) (run (pipe (grep ,pattern ,target-path )))) ((and (null? pipe-cmd) (not (string-null? options))) (run (pipe (begin (process-execute "/usr/bin/grep" (append (list options pattern target-path) rest-str)))))) ((and (not (null? pipe-cmd)) (string-null? options)) (run (pipe (grep ,exclude-dir ,pattern ,target-path) (begin (system (string-join pipe-cmd)))))) (else (run (pipe ;(grep ,options ,exclude-dir ,pattern ,target-path) (begin (process-execute "/usr/bin/grep" (append (list options pattern target-path) rest-str))) (begin (system (string-join pipe-cmd))))))) )))) (print "Path could not be resolved!!"))))) (define (sretrieve:shell-less-cmd base-pathlist ext-path top-areas base-path) (let* ((resolved-path (sauth-common:resolve-path ext-path base-pathlist top-areas ))) (if (not (equal? resolved-path #f)) (if (null? resolved-path) (print "Path could not be resolved!!") (let* ((target-path (sauth-common:get-target-path base-pathlist ext-path top-areas base-path))) (if (not (equal? target-path #f)) (if (or (not (file-exists? target-path)) (directory? target-path)) (print "Target path does not exist or is a directory!") (begin ;(sretrieve:shell-db-do ; db-location ; (lambda (db) ; (sretrieve:register-action db "less" (current-user-name) target-path (conc "Executing cmd: less " target-path)))) (setenv "LESSSECURE" "1") (run (pipe (less ,target-path)))))))) (print "Path could not be resolved!!")))) (define (sretrieve:shell-lookup base-path) (let* ((usr (current-user-name)) (value (get-restrictions base-path usr))) value)) (define (sretrieve:load-shell-config fname) (if (file-exists? fname) (read-config fname #f #f) )) (define (is_directory target-path) (let* ((retval #f)) (sretrieve:do-as-calling-user (lambda () ;(print (current-effective-user-id) ) (if (directory? target-path) (set! retval #t)))) ;(print (current-effective-user-id)) retval)) (define (make-exclude-pattern restriction-list ) (if (null? restriction-list) "" (let loop ((hed (car restriction-list)) (tal (cdr restriction-list)) (ret-str "")) (cond ((null? tal) (conc ret-str ".+" hed ".*")) (else (loop (car tal)(cdr tal)(conc ret-str ".+" hed ".*|")))))) ) (define (sretrieve:get-shell-cmd target-path base-path restrictions iport) (if (not (file-exists? target-path)) (sauth:print-error "Target path does not exist!") (begin (if (not (equal? target-path #f)) (begin (if (is_directory target-path) (begin (let* ((tmpfile (conc "/tmp/" (current-user-name) "/my-pipe")) (parent-dir target-path) (last-dir-name (if (pathname-extension target-path) (conc(pathname-file target-path) "." (pathname-extension target-path)) (pathname-file target-path))) (curr-dir (current-directory)) (start-dir (conc (current-directory) "/" last-dir-name)) (execlude (make-exclude-pattern (string-split restrictions ",")))) ; (print tmpfile) (if (file-exists? start-dir) (begin (print last-dir-name " already exist in your work dir. Do you want to over write it? [y|n]") (let* ((inl (read-line iport))) (if (equal? inl "y") (begin (change-directory parent-dir) (create-fifo tmpfile) (process-fork (lambda() (sleep 1) (with-output-to-file tmpfile (lambda () (sretrieve:make_file parent-dir execlude parent-dir))))) (run (pipe (tar "chfv" "-" "-T" ,tmpfile ) (begin (system (conc "cd " start-dir ";tar xUf - " ))))) (change-directory curr-dir) (system (conc "rm " tmpfile)) ) (begin (print "Nothing has been retrieved!! "))))) (begin (sretrieve:do-as-calling-user (lambda () (create-directory start-dir #t))) (change-directory parent-dir) ; (print execlude) (create-fifo tmpfile) (process-fork (lambda() (sleep 1) (with-output-to-file tmpfile (lambda () (sretrieve:make_file parent-dir execlude parent-dir))))) (run (pipe (tar "chfv" "-" "-T" ,tmpfile) (begin (system (conc "cd " start-dir ";tar xUf - " ))))) (change-directory curr-dir) (system (conc "rm " tmpfile)))))) (begin (let*((parent-dir (pathname-directory target-path)) (start-dir (current-directory)) (filename (if (pathname-extension target-path) (conc(pathname-file target-path) "." (pathname-extension target-path)) (pathname-file target-path))) (work-dir-file (conc (current-directory) "/" filename))) (if (file-exists? work-dir-file) (begin (print filename " already exist in your work dir. Do you want to over write it? [y|n]") (let* ((inl (read-line iport))) (if (equal? inl "y") (begin (change-directory parent-dir) (run (pipe (tar "chfv" "-" ,filename) (begin (system (conc "cd " start-dir ";tar xUf - " ))))) (change-directory start-dir)) (begin (print "Nothing has been retrieved!! "))))) (begin (change-directory parent-dir) (run (pipe (tar "chfv" "-" ,filename) (begin (system (conc "cd " start-dir ";tar xUf -"))))) (change-directory start-dir))))))))))) (define (sretrieve:get-shell-cmd-line target-path base-path restrictions iport) (handle-exceptions exn (begin (sauth:print-error (conc "Problem fetching the data. Sauth provieds sudo access to only one unix group. Please ensure you have washed all the remaining groups. System Error: " ((condition-property-accessor 'exn 'message) exn))) (exit 1)) (if (not (file-exists? target-path)) (sauth:print-error "Error:Target path does not exist!") (begin (if (not (equal? target-path #f)) (begin (if (is_directory target-path) (begin (let* ((parent-dir target-path) (last-dir-name (if (pathname-extension target-path) (conc(pathname-file target-path) "." (pathname-extension target-path)) (pathname-file target-path))) (curr-dir (current-directory)) (start-dir (conc (current-directory) "/" last-dir-name)) (execlude (make-exclude-pattern (string-split restrictions ","))) (tmpfile (conc "/tmp/" (current-user-name) "/my-pipe-" (current-process-id)))) (if (file-exists? start-dir) (begin (sauth:print-error (conclast-dir-name " already exist in your work dir.")) (sauth:print-error "Nothing has been retrieved!! ")) (begin ; (sretrieve:do-as-calling-user ; (lambda () (if (not (file-exists? (conc "/tmp/" (current-user-name)))) (create-directory (conc "/tmp/" (current-user-name)) #t)) (change-directory parent-dir) (create-fifo tmpfile) (process-fork (lambda() (sleep 1) (with-output-to-file tmpfile (lambda () (sretrieve:make_file parent-dir execlude parent-dir))))) (process-execute "/bin/tar" (append (list "chfv" "-" "-T" tmpfile) (list "--ignore-failed-read"))) ;(run (pipe ;(tar "chfv" "-" "." ) ;(begin (system (conc "cd " start-dir ";tar xUf - " execlude ))))) (system (conc "rm " tmpfile)) (change-directory curr-dir))))) (begin (let*((parent-dir (pathname-directory target-path)) (start-dir (current-directory)) (filename (if (pathname-extension target-path) (conc(pathname-file target-path) "." (pathname-extension target-path)) (pathname-file target-path))) (work-dir-file (conc (current-directory) "/" filename))) (if (file-exists? work-dir-file) (begin (print filename " already exist in your work dir.") (print "Nothing has been retrieved!! ")) (begin (change-directory parent-dir) (process-execute "/bin/tar" (append (append (list "chfv" "-") (list filename)) (list "--ignore-failed-read"))) ;(run (pipe ; (tar "chfv" "-" ,filename) ; (begin (system (conc "cd " start-dir ";tar xUf -"))))) (change-directory start-dir)))))))))))) (define (sretrieve:make_file path exclude base_path) (find-files path action: (lambda (p res) (cond ((symbolic-link? p) (if (directory?(read-symbolic-link p)) (sretrieve:make_file p exclude base_path) (print (string-substitute (conc base_path "/") "" p "-")))) ((directory? p) ;;do nothing for dirs) ) (else (if (not (string-match (regexp exclude) p )) (print (string-substitute (conc base_path "/") "" p "-")))))))) (define (sretrieve:shell-help) (conc "Usage: " *exe-name* " [action [params ...]] ls [target path] : list contents of target area. The output of the cmd can be piped into other system cmd. eg ls <path> | grep txt cd <target directory> : To change the current directory within the sretrive shell. pwd : Prints the full pathname of the current directory within the sretrive shell. get <file or directory path> : download directory/files into the directory where sretrieve shell cmd was invoked less <file path> : Read input file to allows backward movement in the file as well as forward movement cat <file path> : show the contents of a file. The output of the cmd can be piped into other system cmd. sgrep <search path> <pattern> [options] : Similar to unix grep cmd But with diffrent parameter ordering. The output of the cmd can be piped into other system cmd. Part of the Megatest tool suite. Learn more at http://www.kiatoa.com/fossils/megatest Version: " megatest-fossil-hash) ) ;(define (toplevel-command . args) #f) (define (sretrieve:shell area) ; (print area) (use readline) (let* ((path '()) (prompt "sretrieve> ") (args (argv)) (usr (current-user-name) ) (top-areas (sretrieve:get-accessable-projects area)) (close-port #f) (area-obj (get-obj-by-code area)) (user-obj (get-user usr)) (base-path (if (null? area-obj) "" (caddr (cdr area-obj)))) (iport (make-readline-port prompt))) (if (null? area-obj) (begin (print "Area " area " does not exist") (exit 1))) (let loop ((inl (read-line iport))) ;(print 1) (if (not (or (or (eof-object? inl) (equal? inl "exit")) (port-closed? iport))) (let* ((parts (string-split inl)) (cmd (if (null? parts) #f (car parts)))) ; (print "2") (if (and (not cmd) (not (port-closed? iport))) (loop (read-line)) (case (string->symbol cmd) ((cd) (if (> (length parts) 1) ;; have a parameter (begin (let*((arg (cadr parts)) (resolved-path (sauth-common:resolve-path arg path top-areas)) (target-path (sauth-common:get-target-path path arg top-areas base-path))) (if (not (equal? target-path #f)) (if (or (equal? resolved-path #f) (not (file-exists? target-path))) (print "Invalid argument " arg ".. ") (begin (set! path resolved-path) (sauthorize:do-as-calling-user (lambda () (run-cmd (conc *sauth-path* "/sauthorize") (list "register-log" (conc "\"" inl "\"") (number->string (car user-obj)) (number->string (caddr area-obj)) "cd")))) ))))) (set! path '()))) ((pwd) (if (null? path) (print "/") (print "/" (string-join path "/")))) ((ls) (let* ((thepath (if (> (length parts) 1) ;; have a parameter (cdr parts) `())) (plen (length thepath))) (cond ((null? thepath) (sauth-common:shell-ls-cmd path "" top-areas base-path '()) (sauthorize:do-as-calling-user (lambda () (run-cmd (conc *sauth-path* "/sauthorize") (list "register-log" (conc "\"" inl "\"") (number->string (car user-obj)) (number->string (caddr area-obj)) "ls")))) ) ((< plen 2) (sauth-common:shell-ls-cmd path (car thepath) top-areas base-path '()) (sauthorize:do-as-calling-user (lambda () (run-cmd (conc *sauth-path* "/sauthorize") (list "register-log" (conc "\"" inl "\"") (number->string (car user-obj)) (number->string (caddr area-obj)) "ls"))))) (else (if (equal? (car thepath) "|") (sauth-common:shell-ls-cmd path "" top-areas base-path thepath) (sauth-common:shell-ls-cmd path (car thepath) top-areas base-path (cdr thepath))) (sauthorize:do-as-calling-user (lambda () (run-cmd (conc *sauth-path* "/sauthorize") (list "register-log" (conc "\"" inl "\"") (number->string (car user-obj)) (number->string (caddr area-obj)) "ls")))))))) ((cat) (let* ((thepath (if (> (length parts) 1) ;; have a parameter (cdr parts) `())) (plen (length thepath))) (cond ((null? thepath) (print "Error: Missing argument to cat")) ((< plen 2) (sretrieve:shell-cat-cmd path (car thepath) top-areas base-path '()) (sauthorize:do-as-calling-user (lambda () (run-cmd (conc *sauth-path* "/sauthorize") (list "register-log" (conc "\"" inl "\"") (number->string (car user-obj)) (number->string (caddr area-obj)) "cat"))))) (else (sretrieve:shell-cat-cmd path (car thepath) top-areas base-path (cdr thepath)) (sauthorize:do-as-calling-user (lambda () (run-cmd (conc *sauth-path* "/sauthorize") (list "register-log" (conc "\"" inl "\"") (number->string (car user-obj)) (number->string (caddr area-obj)) "cat")))) )))) ((sgrep) (let* ((thepath (if (> (length parts) 1) ;; have a parameter (cdr parts) `())) (plen (length thepath))) (cond ((null? thepath) (print "Error: Missing arguments to grep!! Useage: grep <search path> <pattern> [options] ")) ((< plen 2) (print "Error: Missing arguments to grep!! Useage: grep <search path> <pattern> [options] ")) (else (sretrieve:shell-grep-cmd path (car thepath) top-areas base-path (cdr thepath)) (sauthorize:do-as-calling-user (lambda () (run-cmd (conc *sauth-path* "/sauthorize") (list "register-log" (conc "\"" inl "\"") (number->string (car user-obj)) (number->string (caddr area-obj)) "grep")))))))) ((less) (let* ((thepath (if (> (length parts) 1) ;; have a parameter (cdr parts) `())) (plen (length thepath))) (cond ((null? thepath) (print "Error: Missing argument to less")) ((< plen 2) (sretrieve:shell-less-cmd path (car thepath) top-areas base-path) (sauthorize:do-as-calling-user (lambda () (run-cmd (conc *sauth-path* "/sauthorize") (list "register-log" (conc "\"" inl "\"") (number->string (car user-obj)) (number->string (caddr area-obj)) "less"))))) (else (print "less cmd takes only one (<file path>) argument!!"))))) ((get) (let* ((thepath (if (> (length parts) 1) ;; have a parameter (cdr parts) `())) (plen (length thepath))) (cond ((null? thepath) (print "Error: Missing argument <path> to get")) ((< plen 2) (let* ((target-path (sauth-common:get-target-path path (car thepath) top-areas base-path)) (restrictions (if (equal? target-path #f) "" (sretrieve:shell-lookup base-path)))) (if (not (equal? target-path #f)) (begin (sretrieve:get-shell-cmd target-path base-path restrictions iport) (sauthorize:do-as-calling-user (lambda () (run-cmd (conc *sauth-path* "/sauthorize") (list "register-log" (conc "\"" inl "\"") (number->string (car user-obj)) (number->string (caddr area-obj)) "get")))))))) (else (print "Error: get cmd takes only one argument "))))) ((exit) (print "got exit")) ((help) (print (sretrieve:shell-help))) (else (print "Got command: " inl)))) (loop (read-line iport))))))) ;;)) ;;====================================================================== ;; MAIN ;;====================================================================== ;;(define *default-log-port* (current-error-port)) ;(define (sretrieve:load-config exe-dir exe-name) ; (let* ((fname (conc exe-dir "/." exe-name ".config"))) ; ;; (ini:property-separator-patt " * *") ; ;; (ini:property-separator #\space) ; (if (file-exists? fname) ; ;; (ini:read-ini fname) ; (read-config fname #f #f) ; (make-hash-table)))) ;; package-type is "megatest", "builds", "kits" etc. ;; ;(define (sretrieve:load-packages configdat exe-dir package-type) ; (push-directory exe-dir) ; (let* ((packages-metadir (configf:lookup configdat "settings" "packages-metadir")) ; (conversion-script (configf:lookup configdat "settings" "conversion-script")) ; (upstream-file (configf:lookup configdat "settings" "upstream-file")) ; (package-config (conc packages-metadir "/" package-type ".config"))) ; (if (file-exists? upstream-file) ; (if (or (not (file-exists? package-config)) ;; if not created call the updater, otherwise call only if upstream newer ; (> (file-modification-time upstream-file)(file-modification-time package-config))) ; (handle-exceptions ; exn ; (debug:print 0 "ERROR: failed to run script " conversion-script " with params " upstream-file " " package-config) ; (let ((pid (process-run conversion-script (list upstream-file package-config)))) ; (process-wait pid))) ; (debug:print 0 "Skipping update of " package-config " from " upstream-file)) ; (debug:print 0 "Skipping update of " package-config " as " upstream-file " not found")) ; (let ((res (if (file-exists? package-config) ; (begin ; (debug:print 0 "Reading package config " package-config) ; (read-config package-config #f #t)) ; (make-hash-table)))) ; (pop-directory) ; res))) (define (toplevel-command . args) #f) (define (sretrieve:process-action action . args) ; (print action) ; (use readline) (case (string->symbol action) ((get) (if (< (length args) 2) (begin (sauth:print-error "Missing arguments; <area> <relative path>" ) (exit 1))) (let* ((remargs (args:get-args args '("-m" ) '() args:arg-hash 0)) (iport (make-readline-port ">")) (area (car args)) (usr (current-user-name)) (area-obj (get-obj-by-code area)) (user-obj (get-user usr)) (top-areas (sretrieve:get-accessable-projects area)) (base-path (if (null? area-obj) "" (caddr (cdr area-obj)))) (sub-path (if (null? remargs) "" (car remargs)))) (if (null? area-obj) (begin (sauth:print-error (conc "Area " area " does not exist")) (exit 1))) (let* ((target-path (sauth-common:get-target-path '() (conc area "/" sub-path) top-areas base-path)) (restrictions (if (equal? target-path #f) "" (sretrieve:shell-lookup base-path)))) (if (not (equal? target-path #f)) (begin (sauthorize:do-as-calling-user (lambda () (run-cmd (conc *sauth-path* "/sauthorize") (list "register-log" (conc "get " area " " sub-path) (number->string (car user-obj)) (number->string (caddr area-obj)) "get")))) (sretrieve:get-shell-cmd-line target-path base-path restrictions iport)))))) ((cp) (if (< (length args) 2) (begin (sauth:print-error "Missing arguments; <area> <relative path>" ) (exit 1))) (let* ((remargs (args:get-args args '("-m" ) '() args:arg-hash 0)) (iport (make-readline-port ">")) (area (car args)) (usr (current-user-name)) (area-obj (get-obj-by-code area)) (user-obj (get-user usr)) (top-areas (sretrieve:get-accessable-projects area)) (base-path (if (null? area-obj) "" (caddr (cdr area-obj)))) (sub-path (if (null? remargs) "" (car remargs)))) ; (print args) (if (null? area-obj) (begin (sauth:print-error (conc "Area " area " does not exist")) (exit 1))) (let* ((target-path (sauth-common:get-target-path '() (conc area "/" sub-path) top-areas base-path)) (restrictions (if (equal? target-path #f) "" (sretrieve:shell-lookup base-path)))) ;(print target-path) (if (not (equal? target-path #f)) (begin (sauthorize:do-as-calling-user (lambda () (run-cmd (conc *sauth-path* "/sauthorize") (list "register-log" (conc "get " area " " sub-path) (number->string (car user-obj)) (number->string (caddr area-obj)) "get")))) (sretrieve:get-shell-cmd-line target-path base-path restrictions iport)))))) ((cat) (if (< (length args) 2) (begin (sauth:print-error "Missing arguments; <area> <relative path>" ) (exit 1))) (let* ((remargs (args:get-args args '("-m" ) '() args:arg-hash 0)) (area (car args)) (usr (current-user-name)) (area-obj (get-obj-by-code area)) (user-obj (get-user usr)) (top-areas (sretrieve:get-accessable-projects area)) (base-path (if (null? area-obj) "" (caddr (cdr area-obj)))) (sub-path (if (null? remargs) "" (car remargs)))) (if (null? area-obj) (begin (sauth:print-error (conc "Area " area " does not exist")) (exit 1))) (let* ((target-path (sauth-common:get-target-path '() (conc area "/" sub-path) top-areas base-path)) (restrictions (if (equal? target-path #f) "" (sretrieve:shell-lookup base-path)))) ;(sauth-common:shell-ls-cmd base-path-list ext-path top-areas base-path tail-cmd-list) (if (not (equal? target-path #f)) (begin (sauthorize:do-as-calling-user (lambda () (run-cmd (conc *sauth-path* "/sauthorize") (list "register-log" (conc "get " area " " sub-path) (number->string (car user-obj)) (number->string (caddr area-obj)) "get")))) (sretrieve:shell-cat-cmd (list area) sub-path top-areas base-path '())))))) ((ls) (cond ((< (length args) 1) (begin (print "ERROR: Missing arguments; <area> ") (exit 1))) ((equal? (length args) 1) (let* ((area (car args)) (usr (current-user-name)) (area-obj (get-obj-by-code area)) (user-obj (get-user usr)) (top-areas (sretrieve:get-accessable-projects area)) (base-path (if (null? area-obj) "" (caddr (cdr area-obj))))) (if (null? area-obj) (begin (print "Area " area " does not exist") (exit 1))) ; (sretrieve:shell-cat-cmd base-pathlist ext-path top-areas base-path tail-cmd-list) (sauth-common:shell-ls-cmd '() area top-areas base-path '()) (sauthorize:do-as-calling-user (lambda () (run-cmd (conc *sauth-path* "/sauthorize") (list "register-log" "ls" (number->string (car user-obj)) (number->string (caddr area-obj)) "ls")))))) ((> (length args) 1) (let* ((remargs (args:get-args args '("-m" ) '() args:arg-hash 0)) (usr (current-user-name)) (user-obj (get-user usr)) (area (car args))) (let* ((area-obj (get-obj-by-code area)) (top-areas (sretrieve:get-accessable-projects area)) (base-path (if (null? area-obj) "" (caddr (cdr area-obj)))) (sub-path (if (null? remargs) area (conc area "/" (car remargs))))) ;(print "sub path " sub-path) (if (null? area-obj) (begin (print "Area " area " does not exist") (exit 1))) (sauth-common:shell-ls-cmd `() sub-path top-areas base-path '()) (sauthorize:do-as-calling-user (lambda () (run-cmd (conc *sauth-path* "/sauthorize") (list "register-log" (conc "ls " sub-path) (number->string (car user-obj)) (number->string (caddr area-obj)) "ls"))))))))) ((shell) (if (< (length args) 1) (begin (print "ERROR: Missing arguments <area>!!" ) (exit 1)) (sretrieve:shell (car args)))) (else (print 0 "Unrecognised command " action)))) (define (main) (let* ((args (argv)) (prog (car args)) (rema (cdr args)) (exe-name (pathname-file (car (argv)))) (exe-dir (or (pathname-directory prog) (sretrieve:find exe-name (string-split (get-environment-variable "PATH") ":")))) ;(configdat (sretrieve:load-config exe-dir exe-name)) ) ;; preserve the exe data in the config file ;(hash-table-set! configdat "exe-info" (list (list "exe-name" exe-name) ; (list "exe-dir" exe-dir))) (cond ;; one-word commands ((eq? (length rema) 1) (case (string->symbol (car rema)) ((help -h -help --h --help) (print sretrieve:help)) (else (print "ERROR: Unrecognised command. Try \"sretrieve help\"")))) ;; multi-word commands ((null? rema)(print sretrieve:help)) ((>= (length rema) 2) (apply sretrieve:process-action (car rema) (cdr rema))) (else (debug:print 0 "ERROR: Unrecognised command. Try \"sretrieve help\""))))) (main) |
Added subrun.scm version [bd1952a98c].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 | ;; Copyright 2006-2016, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. ;; strftime('%m/%d/%Y %H:%M:%S','now','localtime') (use (prefix sqlite3 sqlite3:) srfi-1 posix regex regex-case srfi-69 (srfi 18) posix-extras directory-utils pathname-expand typed-records format call-with-environment-variables) (declare (unit subrun)) ;;(declare (uses runs)) (declare (uses db)) (declare (uses common)) ;;(declare (uses items)) ;;(declare (uses runconfig)) ;;(declare (uses tests)) ;;(declare (uses server)) (declare (uses mt)) ;;(declare (uses archive)) ;; (declare (uses filedb)) ;(include "common_records.scm") ;;(include "key_records.scm") (include "db_records.scm") ;; provides db:test-get-id ;;(include "run_records.scm") ;;(include "test_records.scm") (define (subrun:subrun-test-initialized? test-run-dir) (if (and (common:file-exists? (conc test-run-dir "/subrun-area") ) (common:file-exists? (conc test-run-dir "/testconfig.subrun") )) #t #f)) (define (subrun:launch-dashboard test-run-dir) (if (subrun:subrun-test-initialized? test-run-dir) (let* ((subarea (subrun:get-runarea test-run-dir))) (if (and subarea (common:file-exists? subarea)) (system (conc "cd " subarea ";env -i PATH=$PATH DISPLAY=$DISPLAY HOME=$HOME USER=$USER dashboard &")))))) (define (subrun:subrun-removed? test-run-dir) (if (subrun:subrun-test-initialized? test-run-dir) (let ((flagfile (conc test-run-dir "/subrun.removed"))) (if (common:file-exists? flagfile) #t #f)) #t)) (define (subrun:set-subrun-removed test-run-dir) (let ((flagfile (conc test-run-dir "/subrun.removed"))) (if (and (subrun:subrun-test-initialized? test-run-dir) (not (common:file-exists? flagfile))) (with-output-to-file flagfile (lambda () (print (current-seconds))))))) (define (subrun:unset-subrun-removed test-run-dir) (let ((flagfile (conc test-run-dir "/subrun.removed"))) (if (and (subrun:subrun-test-initialized? test-run-dir) (common:file-exists? flagfile)) (delete-file flagfile)))) (define (subrun:testconfig-defines-subrun? testconfig) (configf:lookup testconfig "subrun" "runwait")) ;; we use runwait as the flag that a subrun is requested (define (subrun:initialize-toprun-test testconfig test-run-dir) (let ((ra (configf:lookup testconfig "subrun" "run-area")) (logpro (configf:lookup testconfig "subrun" "logpro")) (symlink-target (conc test-run-dir "/subrun-area")) ) (if (not ra) ;; when runarea is not set we default to *toppath*. However (let ((fallback-run-area (or *toppath* (conc test-run-dir "/subrun")))) ;; we need to force the setting in the testconfig so it will ;; be preserved in the testconfig.subrun file (configf:set-section-var testconfig "subrun" "run-area" fallback-run-area) (set! ra fallback-run-area))) (configf:set-section-var testconfig "logpro" "subrun" logpro) ;; append the logpro rules to the logpro section as stepname subrun (if (common:file-exists? symlink-target) (delete-file symlink-target)) (create-symbolic-link ra symlink-target) (configf:write-alist testconfig "testconfig.subrun"))) (define (subrun:set-state-status test-run-dir state status new-state-status) (if (and (not (subrun:subrun-removed? test-run-dir)) (subrun:subrun-test-initialized? test-run-dir)) (let* ((action-switches-str (conc "-set-state-status "new-state-status (if state (conc " -state "state) "") (if status (conc " -status "status) ""))) (log-prefix (subrun:sanitize-path (conc "set-state-status="new-state-status (if state (conc ":state="state) "") (if status (conc "+status="status) "")))) (submt-result (subrun:exec-sub-megatest test-run-dir action-switches-str log-prefix))) submt-result))) (define (subrun:remove-subrun test-run-dir keep-records ) (if (and (not (subrun:subrun-removed? test-run-dir)) (subrun:subrun-test-initialized? test-run-dir)) (let* ((action-switches-str (conc "-remove-runs" (if keep-records "-keep-records " "") )) (remove-result (subrun:exec-sub-megatest test-run-dir action-switches-str "remove"))) (if remove-result (begin (subrun:set-subrun-removed test-run-dir) #t) #f)) #t)) (define (subrun:kill-subrun test-run-dir ) (if (and (not (subrun:subrun-removed? test-run-dir)) (subrun:subrun-test-initialized? test-run-dir)) (let* ((action-switches-str (conc "-kill-runs" )) (kill-result (subrun:exec-sub-megatest test-run-dir action-switches-str "kill"))) kill-result) #t)) (define (subrun:launch-cmd test-run-dir #!optional (sub-cmd "-run")) ;; BUG: "-run" should be changed to "-rerun-clean" but current doesn't work (if (subrun:subrun-removed? test-run-dir) (subrun:unset-subrun-removed test-run-dir)) (let* ((log-prefix "run") (switches (subrun:selector+log-switches test-run-dir log-prefix)) (run-wait #t) (cmd (conc "megatest " sub-cmd " " switches" " (if run-wait "-run-wait " "")))) cmd)) (define (subrun:sanitize-path inpath) (let* ((insane-pattern (irregex "[^[a-zA-Z0-9_\\-]"))) (regex#string-substitute insane-pattern "_" inpath #t))) (define (subrun:get-runarea test-run-dir) (if (subrun:subrun-test-initialized? test-run-dir) (let* ((info-alist (subrun:selector+log-alist test-run-dir "foo")) (run-area (if (list? info-alist) (alist-ref "-start-dir" info-alist equal? #f) #f))) run-area) #f)) (define (subrun:selector+log-alist test-run-dir log-prefix) (let* ((switch-def-alist (common:get-param-mapping flavor: 'config)) (subrunfile (conc test-run-dir "/testconfig.subrun" )) (subrundata (with-input-from-file subrunfile read)) (subrunconfig (configf:alist->config subrundata)) (run-area (configf:lookup subrunconfig "subrun" "run-area")) (defvals `(("start-dir" . ,(or run-area ;; default values if not specified in subrun section of tconf (get-environment-variable "MT_RUN_AREA_HOME") "/no/rundir/found")) ("run-name" . ,(or (get-environment-variable "MT_RUNNAME") "NO-RUNNAME")) ("target" . ,(or (get-environment-variable "MT_TARGET") "NO-TARGET")))) (switch-alist-pre (filter-map (lambda (item) (let* ((config-key (car item)) (switch (cdr item)) (defval (alist-ref config-key defvals equal? #f)) (val (or (configf:lookup subrunconfig "subrun" config-key) defval))) (if val (cons switch val) #f))) switch-def-alist)) ;; testpatt may be modified if all three of mode-patt, tag-expr, and testpatt are null (mode-patt (alist-ref "-modepatt" switch-alist-pre equal? #f)) (tag-expr (alist-ref "-tagexpr" switch-alist-pre equal? #f)) (testpatt (alist-ref "-testpatt" switch-alist-pre equal? (if (not (or mode-patt tag-expr)) "%" #f))) ;; testpatt is % if not ;; otherwise specified ;; define compact-stem for logfile (target (alist-ref "-target" switch-alist-pre equal? #f)) ;; want data-structures alist-ref, not alist-lib alist-ref (runname (alist-ref "-runname" switch-alist-pre equal? #f)) (compact-stem (subrun:sanitize-path (conc target "-" runname "-" (or testpatt mode-patt tag-expr "NO-TESTPATT")))) (logfile (conc test-run-dir "/" (if log-prefix (conc (subrun:sanitize-path log-prefix) "-") "") compact-stem ".log")) ;; swap out testpatt with modified test-patt and add -log (switch-alist (cons (cons "-log" logfile) (map (lambda (item) (if (equal? (car item) "-testpatt") (cons "-testpatt" testpatt) item)) switch-alist-pre)))) switch-alist)) ;; note - get precmd from subrun section ;; apply to submegatest commands (define (subrun:get-log-path test-run-dir log-prefix) (let* ((alist (subrun:selector+log-alist test-run-dir log-prefix)) (res (alist-ref "-log" alist equal? #f))) res)) (define (subrun:selector+log-switches test-run-dir log-prefix) (let* ((switch-alist (subrun:selector+log-alist test-run-dir log-prefix)) (res (string-intersperse (apply append (map (lambda (x) (list (car x) (cdr x))) switch-alist)) " "))) res)) (define (subrun:exec-sub-megatest test-run-dir action-switches-str log-prefix) (let* ((selector-switches (subrun:selector+log-switches test-run-dir log-prefix)) (cmd (conc "megatest " selector-switches " " action-switches-str )) (pid #f) (proc (lambda () (debug:print-info 0 *default-log-port* "Running sub megatest command: "cmd) ;;(set! pid (process-run "/usr/bin/xterm" (list )))))) (set! pid (process-run "/bin/bash" (list "-c" cmd)))))) (call-with-environment-variables (list (cons "PATH" (conc (get-environment-variable "PATH") ":."))) (lambda () (common:without-vars proc "^MT_.*"))) (let processloop ((i 0)) (let-values (((pid-val exit-status exit-code)(process-wait pid #t))) (if (eq? pid-val 0) (begin (thread-sleep! 2) (processloop (+ i 1))) (begin (debug:print-info 0 *default-log-port* "sub megatest " action-switches-str " completed with exit code " exit-code) (if (eq? 0 exit-code) (begin #t) (begin #f)))))))) ;; (subrun:exec-sub-megatest "/nfs/pdx/disks/icf_env_disk001/bjbarcla/gwa/issues/mtdev/165/megatest/ext-tests/tests/subrun-usecases/toparea/links/SYSTEM_val/RELEASE_val/go/toptest" "-foo" "foo") |
Modified supplemental.megatest.config from [5180103602] to [bac0ffc91c].
1 2 3 | [tests-paths] nada #{getenv MT_RUN_AREA_HOME}/moretests | > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. [tests-paths] nada #{getenv MT_RUN_AREA_HOME}/moretests |
Modified synchash.scm from [748a7632da] to [6d4566e942].
1 2 3 | ;;====================================================================== ;; Copyright 2006-2012, Matthew Welland. ;; | | | > > > > > | | > | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | ;;====================================================================== ;; Copyright 2006-2012, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. ;; ;;====================================================================== ;;====================================================================== ;; A hash of hashes that can be kept in sync by sending minial deltas ;;====================================================================== (use format) |
︙ | ︙ |
Modified task_records.scm from [9c8b281be4] to [ff61a823b3].
1 2 3 | ;;====================================================================== ;; Copyright 2006-2012, Matthew Welland. ;; | | | > > > > > | | > | > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | ;;====================================================================== ;; Copyright 2006-2012, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. ;;====================================================================== ;; make-vector-record tasks task id action owner state target name test item params creation_time execution_time (define (make-tasks:task)(make-vector 11)) (define-inline (tasks:task-get-id vec) (vector-ref vec 0)) (define-inline (tasks:task-get-action vec) (vector-ref vec 1)) (define-inline (tasks:task-get-owner vec) (vector-ref vec 2)) |
︙ | ︙ |
Modified tasks.scm from [3d363ae696] to [dcc03dba77].
1 2 | ;; Copyright 2006-2012, Matthew Welland. ;; | | | > > > > > | | > | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | ;; Copyright 2006-2012, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. ;; ;; strftime('%m/%d/%Y %H:%M:%S','now','localtime') (use sqlite3 srfi-1 posix regex regex-case srfi-69 dot-locking format) (import (prefix sqlite3 sqlite3:)) (declare (unit tasks)) |
︙ | ︙ | |||
34 35 36 37 38 39 40 | (debug:print-error 0 *default-log-port* "Called tasks:wait-on-journal with path=" path " (not a string)") (let ((fullpath (conc path "-journal"))) (handle-exceptions exn (begin (print-call-chain (current-error-port)) (debug:print 0 *default-log-port* " message: " ((condition-property-accessor 'exn 'message) exn)) | | | | | 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 | (debug:print-error 0 *default-log-port* "Called tasks:wait-on-journal with path=" path " (not a string)") (let ((fullpath (conc path "-journal"))) (handle-exceptions exn (begin (print-call-chain (current-error-port)) (debug:print 0 *default-log-port* " message: " ((condition-property-accessor 'exn 'message) exn)) (debug:print 5 *default-log-port* " exn=" (condition->list exn)) (debug:print 0 *default-log-port* "tasks:wait-on-journal failed. Continuing on, you can ignore this call-chain") #t) ;; if stuff goes wrong just allow it to move on (let loop ((journal-exists (common:file-exists? fullpath)) (count n)) ;; wait ten times ... (if journal-exists (begin (if (and waiting-msg (eq? (modulo n 30) 0)) (debug:print 0 *default-log-port* waiting-msg)) (if (> count 0) (begin (thread-sleep! 1) (loop (common:file-exists? fullpath) (- count 1))) (begin (debug:print 0 *default-log-port* "ERROR: removing the journal file " fullpath ", this is not good. Look for disk full, write access and other issues.") (if remove (system (conc "rm -rf " fullpath))) #f))) #t)))))) |
︙ | ︙ | |||
85 86 87 88 89 90 91 | *task-db* (handle-exceptions exn (if (> numretries 0) (begin (print-call-chain (current-error-port)) (debug:print 0 *default-log-port* " message: " ((condition-property-accessor 'exn 'message) exn)) | | | | | | 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 | *task-db* (handle-exceptions exn (if (> numretries 0) (begin (print-call-chain (current-error-port)) (debug:print 0 *default-log-port* " message: " ((condition-property-accessor 'exn 'message) exn)) (debug:print 5 *default-log-port* " exn=" (condition->list exn)) (thread-sleep! 1) (tasks:open-db numretries (- numretries 1))) (begin (print-call-chain (current-error-port)) (debug:print 0 *default-log-port* " message: " ((condition-property-accessor 'exn 'message) exn)) (debug:print 5 *default-log-port* " exn=" (condition->list exn)))) (let* ((dbpath (db:dbfile-path )) ;; (tasks:get-task-db-path)) (dbfile (conc dbpath "/monitor.db")) (avail (tasks:wait-on-journal dbpath 10)) ;; wait up to about 10 seconds for the journal to go away (exists (common:file-exists? dbpath)) (write-access (file-write-access? dbpath)) (mdb (cond ;; what the hek is *toppath* doing here? ((and (string? *toppath*)(file-write-access? *toppath*)) (sqlite3:open-database dbfile)) ((file-read-access? dbpath) (sqlite3:open-database dbfile)) (else (sqlite3:open-database ":memory:")))) ;; (never-give-up-open-db dbpath)) (handler (sqlite3:make-busy-timeout 36000))) (if (and exists (not write-access)) (set! *db-write-access* write-access)) ;; only unset so other db's also can use this control (sqlite3:set-busy-handler! mdb handler) (db:set-sync mdb) ;; (sqlite3:execute mdb (conc "PRAGMA synchronous = 0;")) ;; (if (or (and (not exists) ;; (file-write-access? *toppath*)) |
︙ | ︙ | |||
181 182 183 184 185 186 187 | (equal? (configf:lookup *configdat* "server" "required") "yes")) ;; no elegance here ... ;; (define (tasks:kill-server hostname pid #!key (kill-switch "")) (debug:print-info 0 *default-log-port* "Attempting to kill server process " pid " on host " hostname) (setenv "TARGETHOST" hostname) | > > > > > | > | > > > > > | | > | 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 | (equal? (configf:lookup *configdat* "server" "required") "yes")) ;; no elegance here ... ;; (define (tasks:kill-server hostname pid #!key (kill-switch "")) (debug:print-info 0 *default-log-port* "Attempting to kill server process " pid " on host " hostname) (setenv "TARGETHOST" hostname) (let* ((logdir (if (directory-exists? "logs") "logs/" "")) (logfile (if logdir (conc "logs/server-"pid"-"hostname".log") #f)) (gzfile (if logfile (conc logfile ".gz")))) (setenv "TARGETHOST_LOGF" (conc logdir "server-kills.log")) (system (conc "nbfake kill "kill-switch" "pid)) (when logfile (thread-sleep! 0.5) (if (common:file-exists? gzfile) (delete-file gzfile)) (system (conc "gzip " logfile)) (unsetenv "TARGETHOST_LOGF") (unsetenv "TARGETHOST")))) ;;====================================================================== ;; M O N I T O R S ;;====================================================================== (define (tasks:remove-monitor-record mdb) (sqlite3:execute mdb "DELETE FROM monitors WHERE pid=? AND hostname=?;" |
︙ | ︙ | |||
256 257 258 259 260 261 262 | (set! res count)) mdb "SELECT count(id) FROM monitors WHERE last_update < (strftime('%s','now') - 300) AND username=?;" (car (user-information (current-user-id)))) res)) ;; | | | 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 | (set! res count)) mdb "SELECT count(id) FROM monitors WHERE last_update < (strftime('%s','now') - 300) AND username=?;" (car (user-information (current-user-id)))) res)) ;; #;(define (tasks:start-monitor db mdb) (if (> (tasks:get-num-alive-monitors mdb) 2) ;; have two running, no need for more (debug:print-info 1 *default-log-port* "Not starting monitor, already have more than two running") (let* ((megatestdb (conc *toppath* "/megatest.db")) (monitordbf (conc (db:dbfile-path #f) "/monitor.db")) (last-db-update 0)) ;; (file-modification-time megatestdb))) (task:register-monitor mdb) (let loop ((count 0) |
︙ | ︙ | |||
420 421 422 423 424 425 426 | ;; remove tasks given by a string of numbers comma separated (define (tasks:remove-queue-entries dbstruct task-ids) (db:with-db dbstruct #f #t (lambda (db) (sqlite3:execute db (conc "DELETE FROM tasks_queue WHERE id IN (" task-ids ");"))))) | | | | | | 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 | ;; remove tasks given by a string of numbers comma separated (define (tasks:remove-queue-entries dbstruct task-ids) (db:with-db dbstruct #f #t (lambda (db) (sqlite3:execute db (conc "DELETE FROM tasks_queue WHERE id IN (" task-ids ");"))))) #;(define (tasks:process-queue dbstruct) (let* ((task (tasks:snag-a-task dbstruct)) (action (if task (tasks:task-get-action task) #f))) (if action (print "tasks:process-queue task: " task)) (if action (case (string->symbol action) ((run) (tasks:start-run dbstruct task)) ((remove) (tasks:remove-runs dbstruct task)) ((lock) (tasks:lock-runs dbstruct task)) ;; ((monitor) (tasks:start-monitor db task)) #;((rollup) (tasks:rollup-runs dbstruct task)) ((updatemeta)(tasks:update-meta dbstruct task)) #;((kill) (tasks:kill-monitors dbstruct task)))))) (define (tasks:tasks->text tasks) (let ((fmtstr "~10a~10a~10a~12a~20a~12a~12a~10a")) (conc (format #f fmtstr "id" "action" "owner" "state" "target" "runname" "testpatts" "params") "\n" (string-intersperse (map (lambda (task) (format #f fmtstr (tasks:task-get-id task) (tasks:task-get-action task) (tasks:task-get-owner task) (tasks:task-get-state task) (tasks:task-get-target task) (tasks:task-get-name task) (tasks:task-get-testpatt task) ;; (tasks:task-get-item task) (tasks:task-get-params task))) tasks) "\n")))) (define (tasks:set-state dbstruct task-id state) (db:with-db dbstruct #f #t |
︙ | ︙ | |||
604 605 606 607 608 609 610 611 612 613 | (pgdb:add-area dbh area-name (or toppath *toppath*))))) (or success (case modifier ((none)(loop (conc (current-user-name) "_" area-name) 'user)) ((user)(loop (conc (substring (common:get-area-path-signature) 0 4) area-name) 'areasig)) (else #f)))))) ;; give up ;; gets mtpg-run-id and syncs the record if different ;; | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | > | | > | > > > > > > > > > | | | | < < | | | > > > > > | > > > | > > > > | | | > > > | | > > > | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > | > > > > | > > > | < | > > > | > > | > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > | > > | > > > > > > > > > > > > > > > > > > > | > > > | | > > > > > > > > | | | > > | > > > > > > > > > | | 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 | (pgdb:add-area dbh area-name (or toppath *toppath*))))) (or success (case modifier ((none)(loop (conc (current-user-name) "_" area-name) 'user)) ((user)(loop (conc (substring (common:get-area-path-signature) 0 4) area-name) 'areasig)) (else #f)))))) ;; give up (define (task:print-runtime run-times saperator) (for-each (lambda (run-time-info) (let* ((run-name (vector-ref run-time-info 0)) (run-time (vector-ref run-time-info 1)) (target (vector-ref run-time-info 2))) (print target saperator run-name saperator run-time ))) run-times)) (define (task:print-runtime-as-json run-times) (let loop ((run-time-info (car run-times)) (rema (cdr run-times)) (str "")) (let* ((run-name (vector-ref run-time-info 0)) (run-time (vector-ref run-time-info 1)) (target (vector-ref run-time-info 2))) ;(print (not (equal? str ""))) (if (not (equal? str "")) (set! str (conc str ","))) (if (null? rema) (print "[" str "{target:" target ",run-name:" run-name ", run-time:" run-time "}]") (loop (car rema) (cdr rema) (conc str "{target:" target ", run-name:" run-name ", run-time:" run-time "}")))))) (define (task:get-run-times) (let* ( (run-patt (if (args:get-arg "-run-patt") (args:get-arg "-run-patt") "%")) (target-patt (if (args:get-arg "-target-patt") (args:get-arg "-target-patt") "%")) (run-times (rmt:get-run-times run-patt target-patt ))) (if (eq? (length run-times) 0) (begin (print "Data not found!!") (exit))) (if (equal? (args:get-arg "-dumpmode") "json") (task:print-runtime-as-json run-times) (if (equal? (args:get-arg "-dumpmode") "csv") (task:print-runtime run-times ",") (task:print-runtime run-times " "))))) (define (task:print-testtime test-times saperator) (for-each (lambda (test-time-info) (let* ((test-name (vector-ref test-time-info 0)) (test-time (vector-ref test-time-info 2)) (test-item (if (eq? (string-length (vector-ref test-time-info 1)) 0) "N/A" (vector-ref test-time-info 1)))) (print test-name saperator test-item saperator test-time ))) test-times)) (define (task:print-testtime-as-json test-times) (let loop ((test-time-info (car test-times)) (rema (cdr test-times)) (str "")) (let* ((test-name (vector-ref test-time-info 0)) (test-time (vector-ref test-time-info 2)) (item (vector-ref test-time-info 1))) ;(print (not (equal? str ""))) (if (not (equal? str "")) (set! str (conc str ","))) (if (null? rema) (print "[" str "{test-name:" test-name ", item-path:" item ", test-time:" test-time "}]") (loop (car rema) (cdr rema) (conc str "{test-name:" test-name ", item-path:" item ", test-time:" test-time "}")))))) (define (task:get-test-times) (let* ((runname (if (args:get-arg "-runname") (args:get-arg "-runname") #f)) (target (if (args:get-arg "-target") (args:get-arg "-target") #f)) (test-times (rmt:get-test-times runname target ))) (if (not runname) (begin (print "Error: Missing argument -runname") (exit))) (if (string-contains runname "%") (begin (print "Error: Invalid runname, '%' not allowed (" runname ") ") (exit))) (if (not target) (begin (print "Error: Missing argument -target") (exit))) (if (string-contains target "%") (begin (print "Error: Invalid target, '%' not allowed (" target ") ") (exit))) (if (eq? (length test-times) 0) (begin (print "Data not found!!") (exit))) (if (equal? (args:get-arg "-dumpmode") "json") (task:print-testtime-as-json test-times) (if (equal? (args:get-arg "-dumpmode") "csv") (task:print-testtime test-times ",") (task:print-testtime test-times " "))))) ;; gets mtpg-run-id and syncs the record if different ;; (define (tasks:run-id->mtpg-run-id dbh cached-info run-id area-info smallest-last-update-time) (let* ((runs-ht (hash-table-ref cached-info 'runs)) (runinf (hash-table-ref/default runs-ht run-id #f)) (area-id (vector-ref area-info 0))) (if runinf runinf ;; already cached (let* ((run-dat (rmt:get-run-info run-id)) ;; NOTE: get-run-info returns a vector < row header > (run-name (rmt:get-run-name-from-id run-id)) (row (db:get-rows run-dat)) ;; yes, this returns a single row (header (db:get-header run-dat)) (state (db:get-value-by-header row header "state")) (status (db:get-value-by-header row header "status")) (owner (db:get-value-by-header row header "owner")) (event-time (db:get-value-by-header row header "event_time")) (comment (db:get-value-by-header row header "comment")) (fail-count (db:get-value-by-header row header "fail_count")) (pass-count (db:get-value-by-header row header "pass_count")) (db-contour (db:get-value-by-header row header "contour")) (contour (if (args:get-arg "-prepend-contour") (if (and db-contour (not (equal? db-contour "")) (string? db-contour )) (begin (debug:print-info 1 *default-log-port* "db-contour") db-contour) (args:get-arg "-contour")))) (run-tag (if (args:get-arg "-run-tag") (args:get-arg "-run-tag") "")) (last-update (db:get-value-by-header row header "last_update")) (keytarg (if (or (args:get-arg "-prepend-contour") (args:get-arg "-prefix-target")) (conc "MT_CONTOUR/MT_AREA/" (string-intersperse (rmt:get-keys) "/")) (string-intersperse (rmt:get-keys) "/"))) ;; e.g. version/iteration/platform (target (if (or (args:get-arg "-prepend-contour") (args:get-arg "-prefix-target")) (conc (or (args:get-arg "-prefix-target") (conc contour "/" (common:get-area-name) "/")) (rmt:get-target run-id)) (rmt:get-target run-id))) ;; e.g. v1.63/a3e1/ubuntu (spec-id (pgdb:get-ttype dbh keytarg)) (publish-time (if (args:get-arg "-cp-eventtime-to-publishtime") event-time (current-seconds))) (new-run-id (pgdb:get-run-id dbh spec-id target run-name area-id))) (if new-run-id (begin ;; let ((run-record (pgdb:get-run-info dbh new-run-id)) (hash-table-set! runs-ht run-id new-run-id) ;; ensure key fields are up to date ;; if last_update == pgdb_last_update do not update smallest-last-update-time (let* ((pgdb-last-update (pgdb:get-run-last-update dbh new-run-id)) (smallest-time (hash-table-ref/default smallest-last-update-time "smallest-time" #f))) (if (and (> last-update pgdb-last-update) (or (not smallest-time) (< last-update smallest-time))) (hash-table-set! smallest-last-update-time "smallest-time" last-update))) (pgdb:refresh-run-info dbh new-run-id state status owner event-time comment fail-count pass-count area-id last-update publish-time) (debug:print-info 0 *default-log-port* "Working on run-id " run-id " pgdb-id " new-run-id ) (if (not (equal? run-tag "")) (task:add-run-tag dbh new-run-id run-tag)) new-run-id) (if (equal? state "deleted") (begin (debug:print-info 1 *default-log-port* "Warning: Run with id " run-id " was created after previous sync and deleted before the sync") #f) (if (handle-exceptions exn (begin (print-call-chain) (print ((condition-property-accessor 'exn 'message) exn)) #f) (pgdb:insert-run dbh spec-id target run-name state status owner event-time comment fail-count pass-count area-id last-update publish-time)) (let* ((smallest-time (hash-table-ref/default smallest-last-update-time "smallest-time" #f))) (if (or (not smallest-time) (< last-update smallest-time)) (hash-table-set! smallest-last-update-time "smallest-time" last-update)) (tasks:run-id->mtpg-run-id dbh cached-info run-id area-info smallest-last-update-time)) #f))))))) (define (task:add-run-tag dbh run-id tag) (let* ((tag-info (pgdb:get-tag-info-by-name dbh tag))) (if (not tag-info) (begin (if (handle-exceptions exn (begin (debug:print-info 1 *default-log-port* ((condition-property-accessor 'exn 'message) exn)) #f) (pgdb:insert-tag dbh tag)) (set! tag-info (pgdb:get-tag-info-by-name dbh tag)) #f))) ;;add to area_tags (handle-exceptions exn (begin (debug:print-info 1 *default-log-port* ((condition-property-accessor 'exn 'message) exn)) #f) (if (not (pgdb:is-run-taged-with-a-tag dbh (vector-ref tag-info 0) run-id)) (pgdb:insert-run-tag dbh (vector-ref tag-info 0) run-id))))) (define (tasks:sync-test-steps dbh cached-info test-step-ids smallest-last-update-time) ; (print "Sync Steps " test-step-ids ) (let ((test-ht (hash-table-ref cached-info 'tests)) (step-ht (hash-table-ref cached-info 'steps))) (for-each (lambda (test-step-id) (let* ((test-step-info (rmt:get-steps-info-by-id test-step-id)) (step-id (tdb:step-get-id test-step-info)) (test-id (tdb:step-get-test_id test-step-info)) (stepname (tdb:step-get-stepname test-step-info)) (state (tdb:step-get-state test-step-info)) (status (tdb:step-get-status test-step-info)) (event_time (tdb:step-get-event_time test-step-info)) (comment (tdb:step-get-comment test-step-info)) (logfile (tdb:step-get-logfile test-step-info)) (last-update (tdb:step-get-last_update test-step-info)) (pgdb-test-id (hash-table-ref/default test-ht test-id #f)) (smallest-time (hash-table-ref/default smallest-last-update-time "smallest-time" #f)) (pgdb-step-id (if pgdb-test-id (pgdb:get-test-step-id dbh pgdb-test-id stepname state) #f))) (if step-id (begin (if pgdb-test-id (begin (if pgdb-step-id (begin (debug:print-info 1 *default-log-port* "Updating existing test-step with test-id: " test-id " and step-id " step-id " pgdb test id: " pgdb-test-id " pgdb step id " pgdb-step-id ) (let* ((pgdb-last-update (pgdb:get-test-step-last-update dbh pgdb-step-id))) (if (and (> last-update pgdb-last-update) (or (not smallest-time) (< last-update smallest-time))) (hash-table-set! smallest-last-update-time "smallest-time" last-update))) (pgdb:update-test-step dbh pgdb-step-id pgdb-test-id stepname state status event_time comment logfile last-update)) (begin (debug:print-info 1 *default-log-port* "Inserting test-step with test-id: " test-id " and step-id " step-id " pgdb test id: " pgdb-test-id) (if (or (not smallest-time) (< last-update smallest-time)) (hash-table-set! smallest-last-update-time "smallest-time" last-update)) (pgdb:insert-test-step dbh pgdb-test-id stepname state status event_time comment logfile last-update ) (set! pgdb-step-id (pgdb:get-test-step-id dbh pgdb-test-id stepname state)))) (hash-table-set! step-ht step-id pgdb-step-id )) (debug:print-info 1 *default-log-port* "Error: Test not cashed"))) (debug:print-info 1 *default-log-port* "Error: Could not get test step info for step id " test-step-id )))) ;; this is a wierd senario need to debug test-step-ids))) (define (tasks:sync-test-gen-data dbh cached-info test-data-ids smallest-last-update-time) (let ((test-ht (hash-table-ref cached-info 'tests)) (data-ht (hash-table-ref cached-info 'data))) (for-each (lambda (test-data-id) (let* ((test-data-info (rmt:get-data-info-by-id test-data-id)) (data-id (db:test-data-get-id test-data-info)) (test-id (db:test-data-get-test_id test-data-info)) (category (db:test-data-get-category test-data-info)) (variable (db:test-data-get-variable test-data-info)) (value (db:test-data-get-value test-data-info)) (expected (db:test-data-get-expected test-data-info)) (tol (db:test-data-get-tol test-data-info)) (units (db:test-data-get-units test-data-info)) (comment (db:test-data-get-comment test-data-info)) (status (db:test-data-get-status test-data-info)) (type (db:test-data-get-type test-data-info)) (last-update (db:test-data-get-last_update test-data-info)) (smallest-time (hash-table-ref/default smallest-last-update-time "smallest-time" #f)) (pgdb-test-id (hash-table-ref/default test-ht test-id #f)) (pgdb-data-id (if pgdb-test-id (pgdb:get-test-data-id dbh pgdb-test-id category variable) #f))) (if data-id (begin (if pgdb-test-id (begin (if pgdb-data-id (begin (debug:print-info 1 *default-log-port* "Updating existing test-data with test-id: " test-id " and data-id " data-id " pgdb test id: " pgdb-test-id " pgdb data id " pgdb-data-id) (let* ((pgdb-last-update (pgdb:get-test-data-last-update dbh pgdb-data-id))) (if (and (> last-update pgdb-last-update) (or (not smallest-time) (< last-update smallest-time))) (hash-table-set! smallest-last-update-time "smallest-time" last-update))) (pgdb:update-test-data dbh pgdb-data-id pgdb-test-id category variable value expected tol units comment status type last-update)) (begin (debug:print-info 1 *default-log-port* "Inserting test-data with test-id: " test-id " and data-id " data-id " pgdb test id: " pgdb-test-id) (if (handle-exceptions exn (begin (print-call-chain) (print ((condition-property-accessor 'exn 'message) exn)) #f) (pgdb:insert-test-data dbh pgdb-test-id category variable value expected tol units comment status type last-update)) ;(tasks:run-id->mtpg-run-id dbh cached-info run-id area-info) (begin ;(pgdb:insert-test-data dbh pgdb-test-id category variable value expected tol units comment status type ) (if (or (not smallest-time) (< last-update smallest-time)) (hash-table-set! smallest-last-update-time "smallest-time" last-update)) (set! pgdb-data-id (pgdb:get-test-data-id dbh pgdb-test-id category variable))) #f))) (hash-table-set! data-ht data-id pgdb-data-id )) (begin (debug:print-info 1 *default-log-port* "Error: Test not in pgdb")))) (debug:print-info 1 *default-log-port* "Error: Could not get test data info for data id " test-data-id )))) ;; this is a wierd senario need to debug test-data-ids))) (define (tasks:sync-tests-data dbh cached-info test-ids area-info smallest-last-update-time) (let ((test-ht (hash-table-ref cached-info 'tests))) (for-each (lambda (test-id) ; (print test-id) (let* ((test-info (rmt:get-test-info-by-id #f test-id)) (run-id (db:test-get-run_id test-info)) ;; look these up in db_records.scm (test-id (db:test-get-id test-info)) (test-name (db:test-get-testname test-info)) (item-path (db:test-get-item-path test-info)) (state (db:test-get-state test-info)) (status (db:test-get-status test-info)) (host (db:test-get-host test-info)) (pid (db:test-get-process_id test-info)) (cpuload (db:test-get-cpuload test-info)) (diskfree (db:test-get-diskfree test-info)) (uname (db:test-get-uname test-info)) (run-dir (db:test-get-rundir test-info)) (log-file (db:test-get-final_logf test-info)) (run-duration (db:test-get-run_duration test-info)) (comment (db:test-get-comment test-info)) (event-time (db:test-get-event_time test-info)) (archived (db:test-get-archived test-info)) (last-update (db:test-get-last_update test-info)) (pgdb-run-id (tasks:run-id->mtpg-run-id dbh cached-info run-id area-info smallest-last-update-time)) (smallest-time (hash-table-ref/default smallest-last-update-time "smallest-time" #f)) (pgdb-test-id (if pgdb-run-id (begin ;(print pgdb-run-id) (pgdb:get-test-id dbh pgdb-run-id test-name item-path)) #f))) ;; "id" "run_id" "testname" "state" "status" "event_time" ;; "host" "cpuload" "diskfree" "uname" "rundir" "item_path" ;; "run_duration" "final_logf" "comment" "shortdir" "attemptnum" "archived" (if pgdb-run-id (begin (if pgdb-test-id ;; have a record (begin ;; let ((key-name (conc run-id "/" test-name "/" item-path))) (debug:print-info 0 *default-log-port* "Updating existing test with run-id: " run-id " and test-id: " test-id " pgdb run id: " pgdb-run-id " pgdb-test-id " pgdb-test-id) (let* ((pgdb-last-update (pgdb:get-test-last-update dbh pgdb-test-id))) (if (and (> last-update pgdb-last-update) (or (not smallest-time) (< last-update smallest-time))) ;;if last-update is same as pgdb-last-update then it is safe to assume the records are identical and we can use a larger last update time. (hash-table-set! smallest-last-update-time "smallest-time" last-update))) (pgdb:update-test dbh pgdb-test-id pgdb-run-id test-name item-path state status host cpuload diskfree uname run-dir log-file run-duration comment event-time archived last-update pid)) (begin (debug:print-info 0 *default-log-port* "Inserting test with run-id: " run-id " and test-id: " test-id " pgdb run id: " pgdb-run-id) (pgdb:insert-test dbh pgdb-run-id test-name item-path state status host cpuload diskfree uname run-dir log-file run-duration comment event-time archived last-update pid) (if (or (not smallest-time) (< last-update smallest-time)) (hash-table-set! smallest-last-update-time "smallest-time" last-update)) (set! pgdb-test-id (pgdb:get-test-id dbh pgdb-run-id test-name item-path)))) (hash-table-set! test-ht test-id pgdb-test-id)) (debug:print-info 1 *default-log-port* "WARNING: Skipping run with run-id:" run-id ". This run was created after privious sync and removed before this sync.")))) test-ids))) (define (task:add-area-tag dbh area-info tag) (let* ((tag-info (pgdb:get-tag-info-by-name dbh tag))) (if (not tag-info) (begin (if (handle-exceptions exn (begin (debug:print-info 1 *default-log-port* ((condition-property-accessor 'exn 'message) exn)) #f) (pgdb:insert-tag dbh tag)) (set! tag-info (pgdb:get-tag-info-by-name dbh tag)) #f))) ;;add to area_tags (handle-exceptions exn (begin (debug:print-info 1 *default-log-port* ((condition-property-accessor 'exn 'message) exn)) #f) (if (not (pgdb:is-area-taged-with-a-tag dbh (vector-ref tag-info 0) (vector-ref area-info 0))) (pgdb:insert-area-tag dbh (vector-ref tag-info 0) (vector-ref area-info 0)))))) (define (tasks:sync-run-data dbh cached-info run-ids area-info smallest-last-update-time) (for-each (lambda (run-id) (debug:print-info 1 *default-log-port* "Check if run with " run-id " needs to be synced" ) (tasks:run-id->mtpg-run-id dbh cached-info run-id area-info smallest-last-update-time)) run-ids)) ;; get runs changed since last sync ;; (define (tasks:sync-test-data dbh cached-info area-info) ;; (let* (( (define (tasks:sync-to-postgres configdat dest) (print "In sync") (let* ((dbh (pgdb:open configdat dbname: dest)) (area-info (pgdb:get-area-by-path dbh *toppath*)) (cached-info (make-hash-table)) (start (current-seconds)) (test-patt (if (args:get-arg "-testpatt") (args:get-arg "-testpatt") "%")) (target (if (args:get-arg "-target") (args:get-arg "-target") #f)) (run-name (if (args:get-arg "-runname") (args:get-arg "-runname") #f))) (if (and target (not run-name)) (begin (print "Error: Provide runname") (exit 1))) (if (and (not target) run-name) (begin (print "Error: Provide target") (exit 1))) ;(print "123") ;(exit 1) (for-each (lambda (dtype) (hash-table-set! cached-info dtype (make-hash-table))) '(runs targets tests steps data)) (hash-table-set! cached-info 'start start) ;; when done we'll set sync times to this (if area-info (let* ((last-sync-time (vector-ref area-info 3)) (smallest-last-update-time (make-hash-table)) (changed (if (and target run-name) (rmt:get-run-record-ids target run-name (rmt:get-keys) test-patt) (rmt:get-changed-record-ids last-sync-time))) (run-ids (alist-ref 'runs changed)) (test-ids (alist-ref 'tests changed)) (test-step-ids (alist-ref 'test_steps changed)) (test-data-ids (alist-ref 'test_data changed)) (run-stat-ids (alist-ref 'run_stats changed)) (area-tag (if (args:get-arg "-area-tag") (args:get-arg "-area-tag") (if (args:get-arg "-area") (args:get-arg "-area") "")))) (if (and (equal? area-tag "") (not (pgdb:is-area-taged dbh (vector-ref area-info 0)))) (set! area-tag *default-area-tag*)) (if (not (equal? area-tag "")) (task:add-area-tag dbh area-info area-tag)) (if (or (not (null? test-ids)) (not (null? run-ids))) (begin (debug:print-info 0 *default-log-port* "syncing runs") (tasks:sync-run-data dbh cached-info run-ids area-info smallest-last-update-time) (debug:print-info 0 *default-log-port* "syncing tests") (tasks:sync-tests-data dbh cached-info test-ids area-info smallest-last-update-time) (debug:print-info 0 *default-log-port* "syncing test steps") (tasks:sync-test-steps dbh cached-info test-step-ids smallest-last-update-time) (debug:print-info 0 *default-log-port* "syncing test data") (tasks:sync-test-gen-data dbh cached-info test-data-ids smallest-last-update-time) (print "----------done---------------"))) (let* ((smallest-time (hash-table-ref/default smallest-last-update-time "smallest-time" #f))) (debug:print-info 0 "smallest-time :" smallest-time " last-sync-time " last-sync-time) (if (not (and target run-name)) (if (or (and smallest-time (> smallest-time last-sync-time)) (and smallest-time (eq? last-sync-time 0))) (pgdb:write-sync-time dbh area-info smallest-time))))) ;;this needs to be changed (if (tasks:set-area dbh configdat) (tasks:sync-to-postgres configdat dest) (begin (debug:print 0 *default-log-port* "ERROR: unable to create an area record") #f))))) |
Added tcmt.scm version [679021e6ef].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 | ;; Copyright 2006-2017, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. ;;====================================================================== ;; ;; Wrapper to enable running Megatest flows under teamcity ;; ;; 1. Run the megatest process and pass it all the needed parameters ;; 2. Every five seconds check for state/status changes and print the info ;; (use srfi-1 posix srfi-69 srfi-18 regex defstruct) (use trace) ;; (trace-call-sites #t) (declare (uses margs)) (declare (uses rmt)) (declare (uses common)) (declare (uses megatest-version)) (include "megatest-fossil-hash.scm") (include "db_records.scm") (define origargs (cdr (argv))) (define remargs (args:get-args (argv) `( "-target" "-reqtarg" "-runname" "-delay" ;; how long to wait for unexpected changes to ) `("-tc-repl" ) args:arg-hash 0)) (defstruct testdat (tc-type #f) (state #f) (status #f) (overall #f) (flowid #f) tctname tname (event-time #f) details comment duration (start-printed #f) (end-printed #f)) ;;====================================================================== ;; GLOBALS ;;====================================================================== ;; Gotta have a global? Stash it in the *global* hash table. ;; (define *global* (make-hash-table)) (define (tcmt:print tdat flush-mode) (let* ((comment (if (testdat-comment tdat) (conc " message='" (testdat-comment tdat) "'") "")) (details (if (testdat-details tdat) (conc " details='" (testdat-details tdat) "'") "")) (flowid (conc " flowId='" (testdat-flowid tdat) "'")) (duration (conc " duration='" (* 1e3 (testdat-duration tdat)) "'")) (tcname (conc " name='" (testdat-tctname tdat) "'")) (state (string->symbol (testdat-state tdat))) (status (string->symbol (testdat-status tdat))) (startp (testdat-start-printed tdat)) (endp (testdat-end-printed tdat)) (etime (testdat-event-time tdat)) (overall (case state ((RUNNING) state) ((COMPLETED) state) (else 'UNK))) (tstmp (conc " timestamp='" (time->string (seconds->local-time etime) "%FT%T.000") "'"))) (case overall ((RUNNING) (if (not startp) (begin (print "##teamcity[testStarted " tcname flowid tstmp "]") (testdat-start-printed-set! tdat #t)))) ((COMPLETED) (if (not startp) ;; start stanza never printed (begin (print "##teamcity[testStarted " tcname flowid tstmp "]") (testdat-start-printed-set! tdat #t))) (if (not endp) (begin (if (not (member status '(PASS WARN SKIP WAIVED))) (print "##teamcity[testFailed " tcname flowid comment details "]")) (print "##teamcity[testFinished" tcname flowid comment details duration "]") (testdat-end-printed-set! tdat #t)))) (else (if flush-mode (begin (if (not startp) (begin (print "##teamcity[testStarted " tcname flowid tstmp "]") (testdat-start-printed-set! tdat #t))) (if (not endp) (begin (print "##teamcity[testFailed " tcname flowid comment details "]") (print "##teamcity[testFinished" tcname flowid comment details duration "]") (testdat-end-printed-set! tdat #t))))))) ;; (print "ERROR: tc-type \"" (testdat-tc-type tdat) "\" not recognised for " tcname))) (flush-output))) ;; ;; returns values: flag newlst ;; (define (remove-duplicate-completed tdats) ;; (let* ((flag #f) ;; (state (testdat-state tdat)) ;; (status (testdat-status tdat)) ;; (event-time (testdat-event-time tdat)) ;; (tname (testdat-tname tdat))) ;; (let loop ((hed (car tdats)) ;; (tal (cdr tdats)) ;; (new '())) ;; (if (and (equal? state "COMPLETED") ;; (equal? tname (testdat-tname hed)) ;; (equal? state (testdat-state hed))) ;; we have a duplicate COMPLETED call ;; (begin ;; (set! flag #t) ;; A changed completed ;; process the queue of tests gathered so far. List includes one entry for every test so far seen ;; the last record for a test is preserved. Items are only removed from the list if over 15 seconds ;; have passed since it happened. This allows for compression of COMPLETED/FAIL followed by some other ;; state/status ;; (define (process-queue data age flush-mode) ;; here we process tqueue and gather those over 15 seconds (configurable?) old (let* ((print-time (- (current-seconds) age)) ;; print stuff over 15 seconds old (tqueue-raw (hash-table-ref/default data 'tqueue '())) (tqueue (reverse (delete-duplicates tqueue-raw ;; REMOVE duplicates by testname and state (lambda (a b) (and (equal? (testdat-tname a)(testdat-tname b)) ;; need oldest to newest (equal? (testdat-state a) (testdat-state b)))))))) ;; "COMPLETED") ;; (equal? (testdat-state b) "COMPLETED"))))))) (if (not (null? tqueue)) (hash-table-set! data 'tqueue (let loop ((hed (car tqueue)) ;; by this point all duplicates by state COMPLETED are removed (tal (cdr tqueue)) (rem '())) (if (> print-time (testdat-event-time hed)) ;; event happened over 15 seconds ago (begin (tcmt:print hed flush-mode) (if (null? tal) rem ;; return rem to be processed in the future (loop (car tal)(cdr tal) rem))) (if (null? tal) (cons hed rem) ;; return rem + hed for future processing (loop (car tal)(cdr tal)(cons hed rem))))))))) ;; ##teamcity[testStarted name='suite.testName'] ;; ##teamcity[testStdOut name='suite.testName' out='text'] ;; ##teamcity[testStdErr name='suite.testName' out='error text'] ;; ##teamcity[testFailed name='suite.testName' message='failure message' details='message and stack trace'] ;; ##teamcity[testFinished name='suite.testName' duration='50'] ;; ;; flush; #f, normal call. #t, last call, print out something for NOT_STARTED, etc. ;; ;;;;;;; (begin ;;;;;;; (case (string->symbol newstat) ;;;;;;; ((UNK) ) ;; do nothing ;;;;;;; ((RUNNING) (print "##teamcity[testStarted name='" tctname "' flowId='" flowid "']")) ;;;;;;; ((PASS SKIP WARN WAIVED) (print "##teamcity[testFinished name='" tctname "' duration='" (* 1e3 duration) "'" cmtstr details " flowId='" flowid "']")) ;;;;;;; (else ;;;;;;; (print "##teamcity[testFailed name='" tctname "' " cmtstr details " flowId='" flowid "']"))) ;;;;;;; (flush-output) ;; (trace rmt:get-tests-for-run) (define (update-queue-since data run-ids last-update tsname target runname flowid flush #!key (delay-flag #t)) ;; (let ((now (current-seconds)) (still-running #f)) ;; (handle-exceptions ;; exn ;; (begin (print-call-chain) (print "Error message: " ((condition-property-accessor 'exn 'message) exn))) (for-each (lambda (run-id) (let* ((tests (rmt:get-tests-for-run run-id "%" '() '() #f #f #f #f #f #f last-update #f))) ;; (print "DEBUG: got tests=" tests) (for-each (lambda (test-rec) (let* ((tqueue (hash-table-ref/default data 'tqueue '())) ;; NOTE: the key is a symbol! This allows keeping disparate info in the one hash, lazy but a quick solution for right now. (is-top (db:test-get-is-toplevel test-rec)) (tname (db:test-get-fullname test-rec)) (testname (db:test-get-testname test-rec)) (itempath (db:test-get-item-path test-rec)) (tctname (if (string=? itempath "") testname (conc testname "." (string-translate itempath "/" ".")))) (state (db:test-get-state test-rec)) (status (db:test-get-status test-rec)) (etime (db:test-get-event_time test-rec)) (duration (or (any->number (db:test-get-run_duration test-rec)) 0)) (comment (db:test-get-comment test-rec)) (logfile (db:test-get-final_logf test-rec)) (hostn (db:test-get-host test-rec)) (pid (db:test-get-process_id test-rec)) (test-cont (> (+ etime duration 40) (current-seconds))) ;; test has not been over for more than 20 seconds (adj-state (if delay-flag (if test-cont (begin (set! still-running #t) "RUNNING") state) state)) (newstat (cond ;; ((or (not delay-flag) ;; (< (+ etime duration) ;; (- (current-seconds) 10))) ;; (print "Skipping as delay hasn't hit") "RUNNING") ((equal? adj-state "RUNNING") (set! still-running #t) "RUNNING") ((equal? adj-state "COMPLETED") status) (flush (conc state "/" status)) (else "UNK"))) (cmtstr (if (and (not flush) comment) comment (if flush (conc "Test ended in state/status=" state "/" status (if (string-match "^\\s*$" comment) ", no Megatest comment found." (conc ", Megatest comment=\"" comment "\""))) ;; special case, we are handling stragglers #f))) (details (if (string-match ".*html$" logfile) (conc *toppath* "/lt/" target "/" runname "/" testname (if (equal? itempath "") "/" (conc "/" itempath "/")) logfile) #f)) (prev-tdat (hash-table-ref/default data tname #f)) (tdat (if is-top #f (let ((new (or prev-tdat (make-testdat)))) ;; recycle the record so we keep track of already printed items (testdat-flowid-set! new (or (testdat-flowid new) (if (eq? pid 0) tctname (conc hostn "-" pid)))) (testdat-tctname-set! new tctname) (testdat-tname-set! new tname) (testdat-state-set! new adj-state) (testdat-status-set! new status) (testdat-comment-set! new cmtstr) (testdat-details-set! new details) (testdat-duration-set! new duration) (testdat-event-time-set! new etime) ;; (current-seconds)) (testdat-overall-set! new newstat) (hash-table-set! data tname new) new)))) (if (not is-top) (hash-table-set! data 'tqueue (cons tdat tqueue))) (hash-table-set! data tname tdat) )) tests))) run-ids) (list now still-running))) (define (monitor pid) (let* ((run-ids '()) (testdats (make-hash-table)) ;; each entry is a list of testdat structs (keys #f) (last-update 0) (target (or (args:get-arg "-target") (args:get-arg "-reqtarg"))) (runname (args:get-arg "-runname")) (tsname #f) (flowid (conc target "/" runname)) (tdelay (string->number (or (args:get-arg "-delay") "15")))) (if (and target runname) (begin (launch:setup) (set! keys (rmt:get-keys)))) (set! tsname (common:get-testsuite-name)) (print "TCMT: for testsuite=" tsname " found runname=" runname ", target=" target ", keys=" keys " and successfully ran launch:setup. Using " flowid " as the flowId.") (let loop () ;;;;;; (handle-exceptions ;;;;;; exn ;;;;;; ;; (print "Process done.") ;;;;;; (begin (print-call-chain) (print "Error message: " ((condition-property-accessor 'exn 'message) exn))) (let-values (((pidres exittype exitstatus) (process-wait pid #t))) (if (and keys (or (not run-ids) (null? run-ids))) (let* ((runs (rmt:get-runs-by-patt keys runname target #f ;; offset #f ;; limit #f ;; fields 0 ;; last-update )) (header (db:get-header runs)) (rows (db:get-rows runs)) (run-ids-in (map (lambda (row) (db:get-value-by-header row header "id")) rows))) (set! run-ids run-ids-in))) ;; (print "TCMT: pidres=" pidres " exittype=" exittype " exitstatus=" exitstatus " run-ids=" run-ids) (if (eq? pidres 0) (begin (if keys (begin (set! last-update (- (car (update-queue-since testdats run-ids last-update tsname target runname flowid #f delay-flag: #t)) 5)) (process-queue testdats tdelay #f))) (thread-sleep! 3) (loop))))) ;; the megatest runner is done - now wait for all processes to be COMPLETED or NO Processes to be RUNNING > 1 minute (let loop () (let* ((new-last-update-info (update-queue-since testdats run-ids last-update tsname target runname flowid #f delay-flag: #t)) (still-running (cadr new-last-update-info)) (new-last-update (- (car new-last-update-info) 5))) (process-queue testdats tdelay #f) (if still-running (begin (print "TCMT: Tests still running, keep watching...") (thread-sleep! 3) (loop))))) ;; (print "TCMT: pidres=" pidres " exittype=" exittype " exitstatus=" exitstatus " run-ids=" run-ids) (print "TCMT: processing any tests that did not formally complete.") (update-queue-since testdats run-ids 0 tsname target runname flowid #t #f delay-flag: #f) ;; call in flush mode (process-queue testdats 0 #t) (print "TCMT: All done.") )) ;;;;; ) ;; (trace print-changes-since) ;; (if (not (eq? pidres 0)) ;; (not exitstatus)) ;; (begin ;; (thread-sleep! 3) ;; (loop)) ;; (print "Process: megatest " (string-intersperse origargs " ") " is done."))))) (if (file-exists? ".tcmtrc") (load ".tcmtrc")) (define (main) (let* ((mt-done #f) (pid #f) (th1 (make-thread (lambda () (print "Running megatest " (string-intersperse origargs " ")) (set! pid (process-run "megatest" origargs))) "Megatest job")) (th2 (make-thread (lambda () (monitor pid)) "Monitor job"))) (thread-start! th1) (thread-sleep! 1) ;; give the process time to get going (thread-start! th2) (thread-join! th2))) (if (args:get-arg "-tc-repl") (repl) (main)) ;; (process-wait) |
Modified tdb.scm from [85b17f8d7b] to [6edff6262d].
1 2 3 | ;;====================================================================== ;; Copyright 2006-2013, Matthew Welland. ;; | | | > > > > > | | > | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | ;;====================================================================== ;; Copyright 2006-2013, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. ;; ;;====================================================================== ;;====================================================================== ;; Database access ;;====================================================================== (require-extension (srfi 18) extras tcp) |
︙ | ︙ | |||
48 49 50 51 52 53 54 | ;; (define (open-test-db work-area) (debug:print-info 11 *default-log-port* "open-test-db " work-area) (if (and work-area (directory? work-area) (file-read-access? work-area)) (let* ((dbpath (conc work-area "/testdat.db")) | | | | | | 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 | ;; (define (open-test-db work-area) (debug:print-info 11 *default-log-port* "open-test-db " work-area) (if (and work-area (directory? work-area) (file-read-access? work-area)) (let* ((dbpath (conc work-area "/testdat.db")) (dbexists (common:file-exists? dbpath)) (work-area-writeable (file-write-access? work-area)) (db (handle-exceptions ;; open the db if area writeable or db pre-existing. open in-mem otherwise. if exception, open in-mem exn (begin (print-call-chain (current-error-port)) (debug:print 2 *default-log-port* "ERROR: problem accessing test db " work-area ", you probably should clean and re-run this test" ((condition-property-accessor 'exn 'message) exn)) (set! dbexists #f) ;; must force re-creation of tables, more tom-foolery (sqlite3:open-database ":memory:")) ;; open an in-memory db to allow readonly access (if (or work-area-writeable dbexists) (sqlite3:open-database dbpath) (sqlite3:open-database ":memory:")))) (tdb-writeable (and (file-write-access? work-area) (file-write-access? dbpath))) (handler (sqlite3:make-busy-timeout (if (args:get-arg "-override-timeout") (string->number (args:get-arg "-override-timeout")) 136000)))) (if (and tdb-writeable *db-write-access*) (sqlite3:set-busy-handler! db handler)) (if (not dbexists) (begin (db:set-sync db) ;; (sqlite3:execute db "PRAGMA synchronous = FULL;") |
︙ | ︙ |
Added telemetry-daemon version [a2b1d26b8f].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 | #!/usr/bin/env python # -*- Mode: Python; -*- ## Tiny Syslog Server in Python. ## ## This is a tiny syslog server that is able to receive UDP based syslog ## entries on a specified port and save them to a file. ## That's it... it does nothing else... import os import sys, os, time, atexit from signal import SIGTERM import logging import logging.handlers import SocketServer import datetime from subprocess import call import argparse import os import socket ## code to determine this host's IP on non-loopback interface if os.name != "nt": import fcntl import struct def get_interface_ip(ifname): s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) return socket.inet_ntoa(fcntl.ioctl(s.fileno(), 0x8915, struct.pack('256s', ifname[:15]))[20:24]) def get_lan_ip(): ip = socket.gethostbyname(socket.gethostname()) if ip.startswith("127.") and os.name != "nt": interfaces = [ "eth0", "eth1", "eth2", "wlan0", "wlan1", "wifi0", "ath0", "ath1", "ppp0", ] for ifname in interfaces: try: ip = get_interface_ip(ifname) break except IOError: pass return ip class Daemon(object): """ A generic daemon class. Usage: subclass the Daemon class and override the run() method """ def __init__(self, pidfile, stdin='/dev/null', stdout='/dev/null', stderr='/dev/null'): self.stdin = stdin self.stdout = stdout self.stderr = stderr self.pidfile = pidfile def daemonize(self): """ do the UNIX double-fork magic, see Stevens' "Advanced Programming in the UNIX Environment" for details (ISBN 0201563177) http://www.erlenstar.demon.co.uk/unix/faq_2.html#SEC16 """ try: pid = os.fork() if pid > 0: # exit first parent sys.exit(0) except OSError, e: sys.stderr.write("fork #1 failed: %d (%s)\n" % (e.errno, e.strerror)) sys.exit(1) # decouple from parent environment os.chdir("/") os.setsid() os.umask(0) # do second fork try: pid = os.fork() if pid > 0: # exit from second parent sys.exit(0) except OSError, e: sys.stderr.write("fork #2 failed: %d (%s)\n" % (e.errno, e.strerror)) sys.exit(1) # redirect standard file descriptors sys.stdout.flush() sys.stderr.flush() si = file(self.stdin, 'r') so = file(self.stdout, 'a+') se = file(self.stderr, 'a+', 0) os.dup2(si.fileno(), sys.stdin.fileno()) os.dup2(so.fileno(), sys.stdout.fileno()) os.dup2(se.fileno(), sys.stderr.fileno()) # write pidfile atexit.register(self.delpid) pid = str(os.getpid()) file(self.pidfile,'w+').write("%s\n" % pid) def delpid(self): os.remove(self.pidfile) def start(self): """ Start the daemon """ # Check for a pidfile to see if the daemon already runs try: pf = file(self.pidfile,'r') pid = int(pf.read().strip()) pf.close() except IOError: pid = None if pid: message = "pidfile %s already exist. Daemon already running?\n" sys.stderr.write(message % self.pidfile) sys.exit(1) # Start the daemon self.daemonize() self.run() def stop(self): """ Stop the daemon """ # Get the pid from the pidfile try: pf = file(self.pidfile,'r') pid = int(pf.read().strip()) pf.close() except IOError: pid = None if not pid: message = "pidfile %s does not exist. Daemon not running?\n" sys.stderr.write(message % self.pidfile) return # not an error in a restart # Try killing the daemon process try: while 1: os.kill(pid, SIGTERM) time.sleep(0.1) except OSError, err: err = str(err) if err.find("No such process") > 0: if os.path.exists(self.pidfile): os.remove(self.pidfile) else: print str(err) sys.exit(1) def restart(self): """ Restart the daemon """ self.stop() self.start() def run(self): """ You should override this method when you subclass Daemon. It will be called after the process has been daemonized by start() or restart(). """ # setup logging module so that the log can be moved aside and will reopen for append def log_setup(logfile): log_handler = logging.handlers.WatchedFileHandler(logfile) formatter = logging.Formatter( '%(message)s','') log_handler.setFormatter(formatter) logger = logging.getLogger() logger.addHandler(log_handler) logger.setLevel(logging.INFO) class SyslogUDPHandler(SocketServer.BaseRequestHandler): def handle(self): data = bytes.decode(self.request[0].strip()) socket = self.request[1] print( "%s : " % self.client_address[0], str(data)) timestamp = datetime.datetime.now().isoformat() logline = timestamp + ":"+self.client_address[0] + ":" + str(data) logging.info(str(logline)) class TelemetryLogDaemon(Daemon): def __init__(self, pidfile, logfile, server_ip, server_port): self.logfile = logfile self.server_ip = server_ip self.server_port = server_port super(TelemetryLogDaemon, self).__init__(pidfile) def run(self): log_setup(self.logfile) server = SocketServer.UDPServer((self.server_ip,int(self.server_port)), SyslogUDPHandler) server.serve_forever(poll_interval=0.5) def main(): default_log_file = os.environ['PWD'] + "/telemetry.log" parser = argparse.ArgumentParser(description = 'telemetry-daemon') actions="start,restart,stop,nodaemon".split(",") parser.add_argument("-a", "--action", required=True, choices=actions, help="manage daemon: start stop or restart") parser.add_argument("-p", "--server-port", default="5929", help="specify alternate udp port number, default is 5929") parser.add_argument("-i", "--server-ip", default=get_lan_ip(), help="specify IP if heuristics to get local host lan ip fails") parser.add_argument("-l", "--log-file", default=default_log_file, help="specify log file to write") parser.add_argument("-z", "--pid-file", default=default_log_file + ".pidfile", help="specify pidfile") opts = parser.parse_args() tld = TelemetryLogDaemon(opts.pid_file, opts.log_file, opts.server_ip, opts.server_port) if opts.action == "start": print "Info: Starting server" print """Example addition to megatest.config to enable telemetry: [telemetry] host %s port %s want-events ALL """ % (opts.server_ip, opts.server_port) tld.start() elif opts.action == "stop": tld.stop() elif opts.action == "restart": print "Info: Restarting server" print """Example addition to megatest.config to enable telemetry: [telemetry] host %s port %s want-events ALL """ % (opts.server_ip, opts.server_port) tld.restart() elif opts.action == "nodaemon": log_setup(opts.log_file) server = SocketServer.UDPServer((opts.server_ip,int(opts.server_port)), SyslogUDPHandler) server.serve_forever(poll_interval=0.5) if __name__ == '__main__': main() |
Modified test_records.scm from [9245906f33] to [6f2c755d88].
1 2 3 4 5 6 7 | ;; make-vector-record tests testqueue testname testconfig waitons priority items (define (make-tests:testqueue)(make-vector 7 #f)) (define-inline (tests:testqueue-get-testname vec) (vector-ref vec 0)) (define-inline (tests:testqueue-get-testconfig vec) (vector-ref vec 1)) (define-inline (tests:testqueue-get-waitons vec) (vector-ref vec 2)) (define-inline (tests:testqueue-get-priority vec) (vector-ref vec 3)) ;; items: #f=no items, list=list of items remaining, proc=need to call to get items | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | ;; Copyright 2006-2017, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. ;; make-vector-record tests testqueue testname testconfig waitons priority items (define (make-tests:testqueue)(make-vector 7 #f)) (define-inline (tests:testqueue-get-testname vec) (vector-ref vec 0)) (define-inline (tests:testqueue-get-testconfig vec) (vector-ref vec 1)) (define-inline (tests:testqueue-get-waitons vec) (vector-ref vec 2)) (define-inline (tests:testqueue-get-priority vec) (vector-ref vec 3)) ;; items: #f=no items, list=list of items remaining, proc=need to call to get items |
︙ | ︙ |
Deleted testhttp/example-client.scm version [57afe37838].
|
| < < < < < < |
Deleted testhttp/example-server.scm version [1efa10faa7].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted testhttp/mockupclient.scm version [fceab37de6].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted testhttp/mockupclientlib.scm version [6a9bd9de5d].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted testhttp/mockupserver.scm version [aa3c5bcdcf].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted testhttp/testclient.scm version [4aba6dc5d5].
|
| < < < < < < < < |
Deleted testhttp/testserver.scm version [02c28bc9cb].
|
| < < < < < < < < < < < < < < < < |
Deleted testnanomsg/basic-req-rep.scm version [1436c827c9].
|
| < < < |
Deleted testnanomsg/mockupclient.scm version [63a8c6685a].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted testnanomsg/mockupclientlib.scm version [3b245ba7a9].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted testnanomsg/mockupserver.scm version [a4d3e5594c].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted testnanomsg/pipeline.scm version [1d4d831eb6].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted testnanomsg/req-rep-client.scm version [62cc97e2a5].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted testnanomsg/req-rep-server.scm version [7ffb9a9d45].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted testnanomsg/req-rep.scm version [d17a548c7a].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted testrpc/client.scm version [eacc9c3c29].
|
| < < < < < < < < |
Deleted testrpc/server.scm version [d4d2e05e92].
|
| < < < < < < < < < < < < < < < |
Modified tests.scm from [92c19920cd] to [52d412173f].
1 2 3 | ;;====================================================================== ;; Copyright 2006-2013, Matthew Welland. ;; | | | > > > > > | | > | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | ;;====================================================================== ;; Copyright 2006-2013, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. ;; ;;====================================================================== ;;====================================================================== ;; Tests ;;====================================================================== (use sqlite3 srfi-1 posix regex regex-case srfi-69 dot-locking tcp directory-utils) |
︙ | ︙ | |||
29 30 31 32 33 34 35 36 37 38 39 40 41 42 | (declare (uses server)) (include "common_records.scm") (include "key_records.scm") (include "db_records.scm") (include "run_records.scm") (include "test_records.scm") ;; Call this one to do all the work and get a standardized list of tests ;; gets paths from configs and finds valid tests ;; returns hash of testname --> fullpath ;; (define (tests:get-all) (let* ((test-search-path (tests:get-tests-search-path *configdat*))) | > > > > > | 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | (declare (uses server)) (include "common_records.scm") (include "key_records.scm") (include "db_records.scm") (include "run_records.scm") (include "test_records.scm") (include "js-path.scm") (define (init-java-script-lib) (set! *java-script-lib* (conc (common:get-install-area) "/share/js/jquery-3.1.0.slim.min.js")) ) ;; Call this one to do all the work and get a standardized list of tests ;; gets paths from configs and finds valid tests ;; returns hash of testname --> fullpath ;; (define (tests:get-all) (let* ((test-search-path (tests:get-tests-search-path *configdat*))) |
︙ | ︙ | |||
59 60 61 62 63 64 65 | (append paths (list (conc *toppath* "/tests")))))) (define (tests:get-valid-tests test-registry tests-paths) (if (null? tests-paths) test-registry (let loop ((hed (car tests-paths)) (tal (cdr tests-paths))) | | | > > > > > > > | 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 | (append paths (list (conc *toppath* "/tests")))))) (define (tests:get-valid-tests test-registry tests-paths) (if (null? tests-paths) test-registry (let loop ((hed (car tests-paths)) (tal (cdr tests-paths))) (if (common:file-exists? hed) (for-each (lambda (test-path) (let* ((tname (last (string-split test-path "/"))) (tconfig (conc test-path "/testconfig"))) (if (and (not (hash-table-ref/default test-registry tname #f)) (common:file-exists? tconfig)) (hash-table-set! test-registry tname test-path)))) (glob (conc hed "/*")))) (if (null? tal) test-registry (loop (car tal)(cdr tal)))))) (define (tests:filter-test-names-not-matched test-names test-patts) (delete-duplicates (filter (lambda (testname) (not (tests:match test-patts testname #f))) test-names))) (define (tests:filter-test-names test-names test-patts) (delete-duplicates (filter (lambda (testname) (tests:match test-patts testname #f)) test-names))) |
︙ | ︙ | |||
144 145 146 147 148 149 150 | (items:get-items-from-config tconfig)) (else #f)))) ;; not iterated ;; returns waitons waitors tconfigdat ;; (define (tests:get-waitons test-name all-tests-registry) | | | | | 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 | (items:get-items-from-config tconfig)) (else #f)))) ;; not iterated ;; returns waitons waitors tconfigdat ;; (define (tests:get-waitons test-name all-tests-registry) (let* ((config (tests:get-testconfig test-name #f all-tests-registry 'return-procs))) ;; assuming no problems with immediate evaluation, this could be simplified ('return-procs -> #t) (let ((instr (if config (configf:lookup config "requirements" "waiton") (begin ;; No config means this is a non-existant test (debug:print-error 0 *default-log-port* "non-existent required test \"" test-name "\"") (exit 1)))) (instr2 (if config (configf:lookup config "requirements" "waitor") ""))) (debug:print-info 8 *default-log-port* "waitons string is " instr ", waitors string is " instr2) (let ((newwaitons (string-split (cond ((procedure? instr) ;; here (let ((res (instr))) (debug:print-info 8 *default-log-port* "waiton procedure results in string " res " for test " test-name) |
︙ | ︙ | |||
203 204 205 206 207 208 209 | ;; ;; [requirements] [requirements] ;; mode itemwait ;; # trim off the cell to determine what to run for genlib ;; itemmap /.* ;; ;; waiting-test is waiting on waiton-test so we need to create a pattern for waiton-test given waiting-test and itemmap | > > > > > > > > | > > | | | | | | | | | | | | | | | > > > > > > > > | > > > > > > > > > | 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 | ;; ;; [requirements] [requirements] ;; mode itemwait ;; # trim off the cell to determine what to run for genlib ;; itemmap /.* ;; ;; waiting-test is waiting on waiton-test so we need to create a pattern for waiton-test given waiting-test and itemmap ;; BB> (tests:extend-test-patts "normal-second/2" "normal-second" "normal-first" '()) ;; observed -> "normal-first/2,normal-first/,normal-second/2,normal-second/" ;; expected -> "normal-first,normal-second/2,normal-second/" ;; testpatt = normal-second/2 ;; waiting-test = normal-second ;; waiton-test = normal-first ;; itemmaps = () (define (tests:extend-test-patts test-patt waiting-test waiton-test itemmaps itemized-waiton) (cond (itemized-waiton (let* ((itemmap (tests:lookup-itemmap itemmaps waiton-test)) (patts (string-split test-patt ",")) (waiting-test-len (+ (string-length waiting-test) 1)) (patts-waiton (map (lambda (x) ;; for each incoming patt that matches the waiting test (let* ((modpatt (if itemmap (db:convert-test-itempath x itemmap) x)) (newpatt (conc waiton-test "/" (substring modpatt waiting-test-len (string-length modpatt))))) ;; (conc waiting-test "/," waiting-test "/" (substring modpatt waiton-test-len (string-length modpatt))))) ;; (print "in map, x=" x ", newpatt=" newpatt) newpatt)) (filter (lambda (x) (eq? (substring-index (conc waiting-test "/") x) 0)) ;; is this patt pertinent to the waiting test patts))) (extended-test-patt (append patts (if (null? patts-waiton) (list (conc waiton-test "/%")) ;; really shouldn't add the waiton forcefully like this patts-waiton))) (extended-test-patt-with-toplevels (fold (lambda (testpatt-item accum ) (let ((my-match (string-match "^([^%\\/]+)\\/.+$" testpatt-item))) (cons testpatt-item (if my-match (cons (conc (cadr my-match) "/") accum) accum)))) '() extended-test-patt))) (string-intersperse (delete-duplicates extended-test-patt-with-toplevels) ","))) (else ;; not waiting on items, waiting on entire waiton test. (let* ((patts (string-split test-patt ",")) (new-patts (if (member waiton-test patts) patts (cons waiton-test patts)))) (string-intersperse (delete-duplicates new-patts) ","))))) ;; tests:glob-like-match (define (tests:glob-like-match patt str) (let ((like (substring-index "%" patt))) (let* ((notpatt (equal? (substring-index "~" patt) 0)) |
︙ | ︙ | |||
303 304 305 306 307 308 309 | (db:test-get-rundir testdat)) ;; ) (prev-rundir ;; (sdb:qry 'passstr (db:test-get-rundir prev-testdat)) ;; ) (waivers (if testconfig (configf:section-vars testconfig "waivers") '())) (waiver-rx (regexp "^(\\S+)\\s+(.*)$")) (diff-rule "diff %file1% %file2%") (logpro-rule "diff %file1% %file2% | logpro %waivername%.logpro %waivername%.html")) | | | | 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 | (db:test-get-rundir testdat)) ;; ) (prev-rundir ;; (sdb:qry 'passstr (db:test-get-rundir prev-testdat)) ;; ) (waivers (if testconfig (configf:section-vars testconfig "waivers") '())) (waiver-rx (regexp "^(\\S+)\\s+(.*)$")) (diff-rule "diff %file1% %file2%") (logpro-rule "diff %file1% %file2% | logpro %waivername%.logpro %waivername%.html")) (if (not (common:file-exists? test-rundir)) (begin (debug:print-error 0 *default-log-port* "test run directory is gone, cannot propagate waiver") #f) (begin (push-directory test-rundir) (let ((result (if (null? waivers) #f (let loop ((hed (car waivers)) (tal (cdr waivers))) (debug:print 0 *default-log-port* "INFO: Applying waiver rule \"" hed "\"") (let* ((waiver (configf:lookup testconfig "waivers" hed)) (wparts (if waiver (string-match waiver-rx waiver) #f)) (waiver-rule (if wparts (cadr wparts) #f)) (waiver-glob (if wparts (caddr wparts) #f)) (logpro-file (if waiver (let ((fname (conc hed ".logpro"))) (if (common:file-exists? fname) fname (begin (debug:print 0 *default-log-port* "INFO: No logpro file " fname " falling back to diff") #f))) #f)) ;; if rule by name of waiver-rule is found in testconfig - use it ;; else if waivername.logpro exists use logpro-rule |
︙ | ︙ | |||
418 419 420 421 422 423 424 | ;; (let ((val (hash-table-ref/default otherdat ":first_warn" #f))) ;; (if val ;; (sqlite3:execute db "UPDATE tests SET first_warn=? WHERE run_id=? AND testname=? AND item_path=?;" val run-id test-name item-path))) (let ((category (hash-table-ref/default otherdat ":category" "")) (variable (hash-table-ref/default otherdat ":variable" "")) (value (hash-table-ref/default otherdat ":value" #f)) | | | | | > > > > > | 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 | ;; (let ((val (hash-table-ref/default otherdat ":first_warn" #f))) ;; (if val ;; (sqlite3:execute db "UPDATE tests SET first_warn=? WHERE run_id=? AND testname=? AND item_path=?;" val run-id test-name item-path))) (let ((category (hash-table-ref/default otherdat ":category" "")) (variable (hash-table-ref/default otherdat ":variable" "")) (value (hash-table-ref/default otherdat ":value" #f)) (expected (hash-table-ref/default otherdat ":expected" "n/a")) (tol (hash-table-ref/default otherdat ":tol" "n/a")) (units (hash-table-ref/default otherdat ":units" "")) (type (hash-table-ref/default otherdat ":type" "")) (dcomment (hash-table-ref/default otherdat ":comment" ""))) (debug:print 4 *default-log-port* "category: " category ", variable: " variable ", value: " value ", expected: " expected ", tol: " tol ", units: " units) (if (and value) ;; require only value; BB was- all three required (let ((dat (conc category "," variable "," value "," expected "," tol "," units "," dcomment ",," ;; extra comma for status type ))) ;; This was run remote, don't think that makes sense. Perhaps not, but that is the easiest path for the moment. (rmt:csv->test-data run-id test-id dat) ;; This was added in check-in a5adfa3f9a. Message was: "...added delay in set-values to allow for delayed write on server start" ;; I'm inserting an arbitrary rmt: call to force/ensure that the server is available to (hopefully) prevent a communication issue. (rmt:get-var "MEGATEST_VERSION") ;; this does NOTHING but ensure the server is reachable. This is almost certainly NOT needed :) ;; BB - commentiong out arbitrary 10 second wait (thread-sleep! 10) ;; add 10 second delay before quit incase rmt needs time to start a server. ))) ;; need to update the top test record if PASS or FAIL and this is a subtest ;;;;;; (if (not (equal? item-path "")) ;;;;;; (rmt:set-state-status-and-roll-up-items run-id test-name item-path state status #f) ;;;;;) (if (or (and (string? comment) (string-match (regexp "\\S+") comment)) |
︙ | ︙ | |||
579 580 581 582 583 584 585 586 | ul.LinkedList { display: block; } /* ul.LinkedList ul { display: none; } */ .HandCursorStyle { cursor: pointer; cursor: hand; } /* For IE */ th {background-color: #8c8c8c;} td.test {background-color: #d9dbdd;} td.PASS {background-color: #347533;} td.FAIL {background-color: #cc2812;} | > > > > > > | < | 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 | ul.LinkedList { display: block; } /* ul.LinkedList ul { display: none; } */ .HandCursorStyle { cursor: pointer; cursor: hand; } /* For IE */ th {background-color: #8c8c8c;} td.test {background-color: #d9dbdd;} td.PASS {background-color: #347533;} td.FAIL {background-color: #cc2812;} td.SKIP{background-color: #FFD733;} td.WARN {background-color: #EA8724;} td.WAIVED {background-color: #838A12;} td.ABORT{background-color: #EA24B7;} .PASS .link, .SKIP .link, .WARN .link,.WAIVED .link,.ABORT .link, .FAIL .link{color: #FFFFFF;} </style> <script type="text/JavaScript"> function filtersome() { $("tr").show(); $(".test").filter( |
︙ | ︙ | |||
667 668 669 670 671 672 673 674 675 676 677 678 679 680 | } } } </script> EOF ) (define (tests:run-record->test-path run numkeys) (append (take (vector->list run) numkeys) (list (vector-ref run (+ 1 numkeys))))) (define (tests:get-rest-data runs header numkeys) (let ((resh (make-hash-table))) | > > > > > > > > > > > > > > > > > > | 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 | } } } </script> EOF ) (define tests:css-jscript-block-dynamic #<<EOF <script src= ./jquery3.1.0.js></script> EOF ) (define (test:js-block javascript-lib) (conc "<script src=" javascript-lib "></script>" )) (define tests:css-jscript-block-static (test:js-block *java-script-lib*)) (define (tests:css-jscript-block-cond dynamic) (if (equal? dynamic #t) tests:css-jscript-block-dynamic tests:css-jscript-block-static)) (define (tests:run-record->test-path run numkeys) (append (take (vector->list run) numkeys) (list (vector-ref run (+ 1 numkeys))))) (define (tests:get-rest-data runs header numkeys) (let ((resh (make-hash-table))) |
︙ | ︙ | |||
707 708 709 710 711 712 713 | (if (not (hash-table-ref/default (hash-table-ref/default resh test-name #f) test-item #f)) (hash-table-set! (hash-table-ref/default resh test-name #f) test-item (make-hash-table))) (hash-table-set! (hash-table-ref/default (hash-table-ref/default resh test-name #f) test-item #f) run-id (list test-status test-html-path)))) test-data))) runs) resh)) | | > | < < < < < | < < < < < < < | | > > | | | | < < < < < < < < < < < | < > | | > < < | < < | > > > > > | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 | (if (not (hash-table-ref/default (hash-table-ref/default resh test-name #f) test-item #f)) (hash-table-set! (hash-table-ref/default resh test-name #f) test-item (make-hash-table))) (hash-table-set! (hash-table-ref/default (hash-table-ref/default resh test-name #f) test-item #f) run-id (list test-status test-html-path)))) test-data))) runs) resh)) ;; tests:genrate dashboard body ;; (define (tests:dashboard-body page pg-size keys numkeys total-runs linktree area-name get-prev-links get-next-links flag run-patt target-patt) (let* ((start (* page pg-size)) ;(runsdat (rmt:get-runs "%" pg-size start (map (lambda (x)(list x "%")) keys))) (runsdat (rmt:get-runs-by-patt keys run-patt target-patt start pg-size #f 0 sort-order: "desc")) ; db:get-runs-by-patt keys runnamepatt targpatt offset limit fields last-update (header (vector-ref runsdat 0)) (runs (vector-ref runsdat 1)) (ctr 0) (test-runs-hash (tests:get-rest-data runs header numkeys)) (test-list (hash-table-keys test-runs-hash))) (s:html tests:css-jscript-block (tests:css-jscript-block-cond flag) (s:title "Summary for " area-name) (s:body 'onload "addEvents();" (get-prev-links page linktree) (get-next-links page linktree total-runs) (s:h1 "Summary for " area-name) (s:h3 "Filter" ) (s:input 'type "text" 'name "testname" 'id "testname" 'length "30" 'onkeyup "filtersome()") ;; top list (s:table 'id "LinkedList1" 'border "1" 'cellspacing 0 (map (lambda (key) (let* ((res (s:tr 'class "something" (s:th key ) (map (lambda (run) (s:th (vector-ref run ctr))) runs)))) (set! ctr (+ ctr 1)) res)) keys) (s:tr (s:th "Run Name") (map (lambda (run) (s:th (db:get-value-by-header run header "runname"))) runs)) (map (lambda (test-name) (let* ((item-hash (hash-table-ref/default test-runs-hash test-name #f)) (item-keys (sort (hash-table-keys item-hash) string<=?))) (map (lambda (item-name) (let* ((res (s:tr 'class item-name (s:td item-name 'class "test" ) (map (lambda (run) (let* ((run-test (hash-table-ref/default item-hash item-name #f)) (run-id (db:get-value-by-header run header "id")) (result (hash-table-ref/default run-test run-id "n/a")) ;(relative-path (get-relative-path)) (status (if (string? result) result (car result))) (link (if (string? result) result (if (equal? flag #t) (s:a (car result) 'href (conc "./test_log?runid=" run-id "&testname=" item-name )) (s:a (car result) 'href (string-substitute (conc linktree "/") "" (cadr result) "-")))))) (s:td link 'class status))) runs)))) res)) item-keys))) test-list)))))) ;; (tests:create-html-tree "test-index.html") ;; (define (tests:create-html-tree outf) (let* ((lockfile (conc outf ".lock")) (runs-to-process '()) (linktree (common:get-linktree)) (area-name (common:get-testsuite-name)) (keys (rmt:get-keys)) (numkeys (length keys)) (run-patt (or (args:get-arg "-run-patt") (args:get-arg "-runname") "%")) (target (or (args:get-arg "-target-patt") (args:get-arg "-target") "%")) (targlist (string-split target "/")) (numtarg (length targlist)) (targtweaked (if (> numkeys numtarg) (append targlist (make-list (- numkeys numtarg) "%")) targlist)) (target-patt (string-join targtweaked "/")) ;(total-runs (rmt:get-num-runs "%")) ;;this needs to be changed to filter by target (total-runs (rmt:get-runs-cnt-by-patt run-patt target-patt keys )) (pg-size 10)) (if (common:simple-file-lock lockfile) (begin ;(print total-runs) (let loop ((page 0)) (let* ((oup (open-output-file (or outf (conc linktree "/page" page ".html")))) (get-prev-links (lambda (page linktree ) (let* ((link (if (not (eq? page 0)) (s:a "<<prev" 'href (conc "page" (- page 1) ".html")) (s:a "" 'href (conc "page" page ".html"))))) link))) (get-next-links (lambda (page linktree total-runs) (let* ((link (if (> total-runs (+ 10 (* page pg-size))) (s:a "next>>" 'href (conc "page" (+ page 1) ".html")) (s:a "" 'href (conc "page" page ".html"))))) link))) ) (print "total runs: " total-runs) (s:output-new oup (tests:dashboard-body page pg-size keys numkeys total-runs linktree area-name get-prev-links get-next-links #f run-patt target-patt)) ;; update this function (close-output-port oup) ; (set! page (+ 1 page)) (if (> total-runs (* (+ 1 page) pg-size)) (loop (+ 1 page))))) (common:simple-file-release-lock lockfile)) #f))) (define (tests:readlines filename) (call-with-input-file filename (lambda (p) (let loop ((line (read-line p)) (result '())) (if (eof-object? line) (reverse result) (loop (read-line p) (cons line result))))))) (define (tests:get-test-log run-id test-name item-name) (let* ((test-data (rmt:get-tests-for-run (string->number run-id) test-name ;; testnamepatt '() ;; states '() ;; statuses #f ;; offset #f ;; num-to-get #f ;; hide/not-hide #f ;; sort-by #f ;; sort-order #f ;; 'shortlist ;; qrytype 0 ;; last update #f)) (path "") (found 0)) (debug:print-info 0 *default-log-port* "found: " found ) (let loop ((hed (car test-data)) (tal (cdr test-data))) (debug:print-info 0 *default-log-port* "item: " (vector-ref hed 11) (vector-ref hed 10) "/" (vector-ref hed 13)) (if (equal? (vector-ref hed 11) item-name) (begin (set! found 1) (set! path (conc (vector-ref hed 10) "/" (vector-ref hed 13))))) (if (and (not (null? tal)) (equal? found 0)) (loop (car tal)(cdr tal)))) (if (equal? path "") "<H2>Data not found</H2>" (string-join (tests:readlines path) "\n")))) (define (tests:dynamic-dboard page) ;(define (tests:create-html-tree o) (let* ( ;(page "1") (linktree (common:get-linktree)) (area-name (common:get-testsuite-name)) (keys (rmt:get-keys)) (numkeys (length keys)) (targtweaked (make-list numkeys "%")) (target-patt (string-join targtweaked "/")) (total-runs (rmt:get-num-runs "%")) (pg-size 10) (pg (if (equal? page #f) 0 (- (string->number page) 1))) (get-prev-links (lambda (pg linktree) (debug:print-info 0 *default-log-port* "val: " (- 1 pg)) (let* ((link (if (not (eq? pg 0)) (s:a "<<prev " 'href (conc "dashboard?page=" pg )) (s:a "" 'href (conc "dashboard?page=" pg))))) link))) (get-next-links (lambda (pg linktree total-runs) (debug:print-info 0 *default-log-port* "val: " pg) (debug:print-info 0 *default-log-port* "val: " total-runs " size" pg-size) (let* ((link (if (> total-runs (+ 10 (* pg pg-size))) (s:a "next>> " 'href (conc "dashboard?page=" (+ pg 2) )) (s:a "" 'href (conc "dashboard?page=" pg ))))) link))) (html-body (tests:dashboard-body pg pg-size keys numkeys total-runs linktree area-name get-prev-links get-next-links #t "%" target-patt))) ;; update tis function html-body)) (define (tests:create-html-summary outf) (let* ((lockfile (conc outf ".lock")) (linktree (common:get-linktree)) (keys (rmt:get-keys)) (area-name (common:get-testsuite-name)) (run-patt (or (args:get-arg "-run-patt") (args:get-arg "-runname") "%")) (target (or (args:get-arg "-target-patt") (args:get-arg "-target") "%")) (targlist (string-split target "/")) (numkeys (length keys)) (numtarg (length targlist)) (targtweaked (if (> numkeys numtarg) (append targlist (make-list (- numkeys numtarg) "%")) targlist)) (target-patt (string-join targtweaked "/"))) (if (common:simple-file-lock lockfile) (begin (let* (;(runsdat1 (rmt:get-runs run-patt #f #f (map (lambda (x)(list x "%")) keys))) (runsdat (rmt:get-runs-by-patt keys run-patt target-patt #f #f #f 0)) (runs (vector-ref runsdat 1)) (header (vector-ref runsdat 0)) (oup (open-output-file (or outf (conc linktree "/targets.html")))) (target-hash (test:create-target-hash runs header (length keys)))) (test:create-target-html target-hash oup area-name linktree) (test:create-run-html runs area-name linktree (length keys) header)) (common:simple-file-release-lock lockfile)) #f))) (define (test:get-test-hash test-data) (let ((resh (make-hash-table))) (map (lambda (test) (let* ((test-name (vector-ref test 2)) (test-html-path (if (file-exists? (conc (vector-ref test 10) "/test-summary.html")) (conc (vector-ref test 10) "/test-summary.html" ) (conc (vector-ref test 10) "/" (vector-ref test 13)))) (test-item (vector-ref test 11)) (test-status (vector-ref test 4))) (if (not (hash-table-ref/default resh test-item #f)) (hash-table-set! resh test-item (make-hash-table))) (hash-table-set! (hash-table-ref/default resh test-item #f) test-name (list test-status test-html-path)))) test-data) resh)) (define (test:get-data->b-keys ordered-data a-keys) (delete-duplicates (sort (apply append (map (lambda (sub-key) (let ((subdat (hash-table-ref ordered-data sub-key))) (hash-table-keys subdat))) a-keys)) string>=?))) (define (test:create-run-html runs area-name linktree numkeys header) (map (lambda (run) (let* ((target (string-join (take (vector->list run) numkeys) "/")) (run-name (db:get-value-by-header run header "runname")) (run-time (seconds->work-week/day-time (db:get-value-by-header run header "event_time"))) (oup (if (file-exists? (conc linktree "/" target "/" run-name)) (open-output-file (conc linktree "/" target "/" run-name "/run.html")) #f)) (run-id (db:get-value-by-header run header "id")) (test-data (rmt:get-tests-for-run run-id "%" ;; testnamepatt '() ;; states '() ;; statuses #f ;; offset #f ;; num-to-get #f ;; hide/not-hide #f ;; sort-by #f ;; sort-order #f ;; 'shortlist ;; qrytype 0 ;; last update #f)) (item-test-hash (test:get-test-hash test-data)) (items (hash-table-keys item-test-hash)) (test-names (test:get-data->b-keys item-test-hash items))) (if oup (begin (s:output-new oup (s:html tests:css-jscript-block (tests:css-jscript-block-cond #f) (s:title "Runs View " run-name) (s:body (s:h1 "Runs View " ) (s:h3 "Target" target) (s:p (s:b "Run name" ) run-name) (s:p (s:b "Run Date" ) run-time) (s:table 'border 1 'cellspacing 0 (s:tr (s:th "Items") (map (lambda (test) (s:th test)) test-names)) (map (lambda (item) (let* ((test-hash (hash-table-ref/default item-test-hash item #f))) (if test-hash (begin (s:tr (s:td 'class "test" item) (map (lambda (test) (let* ((test-details (hash-table-ref/default test-hash test #f)) (status (if test-details (car test-details))) (link (if test-details (string-substitute (conc linktree "/" target "/" run-name "/") "" (cadr test-details) "-")))) (if test-details (s:td 'class status (s:a 'class "link" 'href link status )) (s:td "")))) test-names)))))) (sort items string<=?)))))) (close-output-port oup)) (debug:print-info 0 "Skip: Dirctory structure " linktree "/" target "/" run-name " does not exist. Megatest will not create run.html")))) runs)) (define (test:create-target-hash runs header numkeys) (let ((resh (make-hash-table))) (for-each (lambda (run) (let* ((run-name (db:get-value-by-header run header "runname")) (target (string-join (take (vector->list run) numkeys) "/")) (run-list (hash-table-ref/default resh target #f))) (if (not run-list) (hash-table-set! resh target (list run-name)) (hash-table-set! resh target (cons run-name run-list))))) runs) resh)) (define (test:get-max-run-cnt target-hash targets) (let* ((cnt 0 )) (map (lambda (target) (let* ((runs (hash-table-ref/default target-hash target #f)) (run-length (if runs (length runs) 0))) (if (< cnt run-length) (set! cnt run-length)))) targets) cnt)) (define (test:pad-runs target-hash targets max-row-length) (map (lambda (target) (let loop ((run-list (hash-table-ref/default target-hash target #f))) (if (< (length run-list) max-row-length) (begin (hash-table-set! target-hash target (cons "" run-list)) (loop (hash-table-ref/default target-hash target #f) ))))) targets) target-hash) (define (test:create-target-html target-hash oup area-name linktree) (let* ((targets (hash-table-keys target-hash)) (max-row-length (test:get-max-run-cnt target-hash targets)) (pad-runs-hash (test:pad-runs target-hash targets max-row-length))) (s:output-new oup (s:html tests:css-jscript-block (tests:css-jscript-block-cond #f) (s:title "Target View " area-name) (s:body (s:h1 "Target View " area-name) (s:table 'id "LinkedList1" 'border "1" 'cellspacing 0 (s:tr 'class "something" (s:th "Target") (s:th 'colspan max-row-length "Runs")) (let* ((tbl (map (lambda (target) (s:tr (s:td 'class "test" target) (let* ((runs (hash-table-ref/default target-hash target #f)) (rest-row (map (lambda (run) (if (equal? run "") (s:td run) (if (file-exists?(conc linktree "/" target "/" run )) (begin (s:td (s:a 'href (conc target "/" run "/run.html") run)))))) (reverse runs)))) rest-row))) targets))) tbl))))) (close-output-port oup))) (define (tests:create-html-tree-old outf) (let* ((lockfile (conc outf ".lock")) (runs-to-process '())) (if (common:simple-file-lock lockfile) (let* ((linktree (common:get-linktree)) |
︙ | ︙ | |||
837 838 839 840 841 842 843 | "Runs" (common:htree->html runs-htree '() (lambda (x p) (let* ((targ-path (string-intersperse p "/")) (full-path (conc linktree "/" targ-path)) (run-name (car (reverse p)))) | | | 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 | "Runs" (common:htree->html runs-htree '() (lambda (x p) (let* ((targ-path (string-intersperse p "/")) (full-path (conc linktree "/" targ-path)) (run-name (car (reverse p)))) (if (and (common:file-exists? full-path) (directory? full-path) (file-write-access? full-path)) (s:a run-name 'href (conc targ-path "/run-summary.html")) (begin (debug:print 0 *default-log-port* "INFO: Can't create " targ-path "/run-summary.html") (conc run-name " (Not able to create summary at " targ-path ")"))))))))))) (close-output-port oup) |
︙ | ︙ | |||
876 877 878 879 880 881 882 | (full-name (db:test-make-full-name test-name item-path)) (path-parts (string-split full-name))) path-parts)) test-dats)) (tests-htree (common:list->htree tests-tree-dat)) (html-dir (conc linktree "/" (string-intersperse run-dir "/"))) (html-path (conc html-dir "/run-summary.html")) | | | 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 | (full-name (db:test-make-full-name test-name item-path)) (path-parts (string-split full-name))) path-parts)) test-dats)) (tests-htree (common:list->htree tests-tree-dat)) (html-dir (conc linktree "/" (string-intersperse run-dir "/"))) (html-path (conc html-dir "/run-summary.html")) (oup (if (and (common:file-exists? html-dir) (directory? html-dir) (file-write-access? html-dir)) (open-output-file html-path) #f))) ;; (print "run-dir: " run-dir ", tests-tree-dat: " tests-tree-dat) (if oup (begin |
︙ | ︙ | |||
904 905 906 907 908 909 910 | (let* ((targ-path (string-intersperse p "/")) (test-name (car p)) (item-path ;; (if (> (length p) 2) ;; test-name + run-name (string-intersperse p "/")) (full-targ (conc html-dir "/" targ-path)) (std-file (conc full-targ "/test-summary.html")) (alt-file (conc full-targ "/megatest-rollup-" test-name ".html")) | | | | | 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 | (let* ((targ-path (string-intersperse p "/")) (test-name (car p)) (item-path ;; (if (> (length p) 2) ;; test-name + run-name (string-intersperse p "/")) (full-targ (conc html-dir "/" targ-path)) (std-file (conc full-targ "/test-summary.html")) (alt-file (conc full-targ "/megatest-rollup-" test-name ".html")) (html-file (if (common:file-exists? alt-file) alt-file std-file)) (run-name (car (reverse p)))) (if (and (not (common:file-exists? full-targ)) (directory? full-targ) (file-write-access? full-targ)) (tests:summarize-test run-id (rmt:get-test-id run-id test-name item-path))) (if (common:file-exists? full-targ) (s:a run-name 'href html-file) (begin (debug:print 0 *default-log-port* "ERROR: can't access " full-targ) (conc "No summary for " run-name))))) )))))) (close-output-port oup))))) runs) |
︙ | ︙ | |||
1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 | (if (eq? time-a time-b) (< id-a id-b) ;; (string<? (conc (vector-ref a 2)) ;; (conc (vector-ref b 2))) #f)) (string<? (conc time-a)(conc time-b))))))))) ;; summarize test in to a file test-summary.html in the test directory ;; (define (tests:summarize-test run-id test-id) (let* ((test-dat (rmt:get-test-info-by-id run-id test-id)) (out-dir (db:test-get-rundir test-dat)) (out-file (conc out-dir "/test-summary.html"))) | > > > > > > > > > > > > > > > > > > > | 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 | (if (eq? time-a time-b) (< id-a id-b) ;; (string<? (conc (vector-ref a 2)) ;; (conc (vector-ref b 2))) #f)) (string<? (conc time-a)(conc time-b))))))))) ;; Save test state and status in to a file .final-status in the test directory ;; (define (tests:save-final-status run-id test-id) (let* ((test-dat (rmt:get-test-info-by-id run-id test-id)) (out-dir (db:test-get-rundir test-dat)) (status-file (conc out-dir "/.final-status")) ) ;; first verify we are able to write the output file (if (not (file-write-access? out-dir)) (debug:print 0 *default-log-port* "ERROR: cannot write .final-status to " out-dir) (let* ((outp (open-output-file status-file)) (status (db:test-get-status test-dat)) (state (db:test-get-state test-dat))) (fprintf outp "~S\n" state) (fprintf outp "~S\n" status) (close-output-port outp))))) ;; summarize test in to a file test-summary.html in the test directory ;; (define (tests:summarize-test run-id test-id) (let* ((test-dat (rmt:get-test-info-by-id run-id test-id)) (out-dir (db:test-get-rundir test-dat)) (out-file (conc out-dir "/test-summary.html"))) |
︙ | ︙ | |||
1055 1056 1057 1058 1059 1060 1061 | (oup (open-output-file out-file)) (status (db:test-get-status test-dat)) (color (common:get-color-from-status status)) (logf (db:test-get-final_logf test-dat)) (steps-dat (tests:get-compressed-steps run-id test-id))) ;; (dcommon:get-compressed-steps #f 1 30045) ;; (#("wasting_time" "23:36:13" "23:36:21" "0" "8.0s" "wasting_time.log")) | | | | 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 | (oup (open-output-file out-file)) (status (db:test-get-status test-dat)) (color (common:get-color-from-status status)) (logf (db:test-get-final_logf test-dat)) (steps-dat (tests:get-compressed-steps run-id test-id))) ;; (dcommon:get-compressed-steps #f 1 30045) ;; (#("wasting_time" "23:36:13" "23:36:21" "0" "8.0s" "wasting_time.log")) (s:output-new oup (s:html (s:title "Summary for " full-name) (s:body (s:h2 "Summary for " full-name) (s:table 'cellspacing "0" 'border "1" (s:tr (s:td "run id") (s:td (db:test-get-run_id test-dat)) (s:td "test id") (s:td (db:test-get-id test-dat))) (s:tr (s:td "testname") (s:td test-name) (s:td "itempath") (s:td item-path)) (s:tr (s:td "state") (s:td (db:test-get-state test-dat)) (s:td "status") (s:td (s:a 'href logf (s:font 'color color status)))) (s:tr (s:td "TestDate") (s:td (seconds->work-week/day-time (db:test-get-event_time test-dat))) (s:td "Duration") (s:td (seconds->hr-min-sec (db:test-get-run_duration test-dat))))) (s:h3 "Log files") (s:table 'cellspacing "0" 'border "1" (s:tr (s:td "Final log")(s:td (s:a 'href logf logf)))) (s:table 'cellspacing "0" 'border "1" (s:tr (s:td "Step Name")(s:td "Start")(s:td "End")(s:td "Status")(s:td "Duration")(s:td "Log File")) (map (lambda (step-dat) (s:tr (s:td (tdb:steps-table-get-stepname step-dat)) |
︙ | ︙ | |||
1127 1128 1129 1130 1131 1132 1133 | ;;====================================================================== ;; Gather data from test/task specifications ;;====================================================================== ;; (define (tests:get-valid-tests testsdir test-patts) ;; #!key (test-names '())) ;; (let ((tests (glob (conc testsdir "/tests/*")))) ;; " (string-translate patt "%" "*"))))) | | | | | | > | | | 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 | ;;====================================================================== ;; Gather data from test/task specifications ;;====================================================================== ;; (define (tests:get-valid-tests testsdir test-patts) ;; #!key (test-names '())) ;; (let ((tests (glob (conc testsdir "/tests/*")))) ;; " (string-translate patt "%" "*"))))) ;; (set! tests (filter (lambda (test)(common:file-exists? (conc test "/testconfig"))) tests)) ;; (delete-duplicates ;; (filter (lambda (testname) ;; (tests:match test-patts testname #f)) ;; (map (lambda (testp) ;; (last (string-split testp "/"))) ;; tests))))) (define (tests:get-test-path-from-environment) (if (and (getenv "MT_LINKTREE") (getenv "MT_TARGET") (getenv "MT_RUNNAME") (getenv "MT_TEST_NAME") (getenv "MT_ITEMPATH")) (conc (getenv "MT_LINKTREE") "/" (getenv "MT_TARGET") "/" (getenv "MT_RUNNAME") "/" (getenv "MT_TEST_NAME") (if (and (getenv "MT_ITEMPATH") (not (string=? "" (getenv "MT_ITEMPATH")))) (conc "/" (getenv "MT_ITEMPATH")) "")) #f)) ;; if .testconfig exists in test directory read and return it ;; else if have cached copy in *testconfigs* return it IFF there is a section "have fulldata" ;; else read the testconfig file ;; if have path to test directory save the config as .testconfig and return it ;; (define (tests:get-testconfig test-name item-path test-registry system-allowed #!key (force-create #f)(allow-write-cache #t)(wait-a-minute #f)) (let* ((use-cache (common:use-cache?)) (cache-path (tests:get-test-path-from-environment)) (cache-file (and cache-path (conc cache-path "/.testconfig"))) (cache-exists (and cache-file (not force-create) ;; if force-create then pretend there is no cache to read (common:file-exists? cache-file))) (cached-dat (if (and (not force-create) cache-exists use-cache) (handle-exceptions exn #f ;; any issues, just give up with the cached version and re-read (configf:read-alist cache-file)) |
︙ | ︙ | |||
1183 1184 1185 1186 1187 1188 1189 1190 1191 | (if (and dat ;; have a locally cached version (hash-table-ref/default dat "have fulldata" #f)) ;; marked as good data? dat ;; no cached data available (let* ((treg (or test-registry (tests:get-all))) (test-path (or (hash-table-ref/default treg test-name #f) (conc *toppath* "/tests/" test-name))) (test-configf (conc test-path "/testconfig")) | > > > > > > > > > > > | > > > > > > > > > > > > > | > | | 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 | (if (and dat ;; have a locally cached version (hash-table-ref/default dat "have fulldata" #f)) ;; marked as good data? dat ;; no cached data available (let* ((treg (or test-registry (tests:get-all))) (test-path (or (hash-table-ref/default treg test-name #f) (let* ((local-tcdir (conc (getenv "MT_LINKTREE") "/" (getenv "MT_TARGET") "/" (getenv "MT_RUNNAME") "/" test-name "/" item-path)) (local-tcfg (conc local-tcdir "/testconfig"))) (if (common:file-exists? local-tcfg) local-tcdir #f)) (conc *toppath* "/tests/" test-name))) (test-configf (conc test-path "/testconfig")) (testexists (let loopa ((tries-left 30)) (cond ( (and (common:file-exists? test-configf)(file-read-access? test-configf)) #t) ( (common:file-exists? test-configf) (debug:print 0 *default-log-port* "WARNING: Cannot read testconfig file: "test-configf) #f) ( (and wait-a-minute (> tries-left 0)) (thread-sleep! 10) (debug:print 0 *default-log-port* "WARNING: testconfig file does not exist: "test-configf" will retry in 10 seconds. Tries left: "tries-left) ;; BB: this fires (loopa (sub1 tries-left))) (else (debug:print 0 *default-log-port* "WARNING: testconfig file does not exist: "test-configf) ;; BB: this fires #f)))) (tcfg (if testexists (read-config test-configf #f system-allowed environ-patt: (if system-allowed "pre-launch-env-vars" #f)) #f))) (if (and tcfg cache-file) (hash-table-set! tcfg "have fulldata" #t)) ;; mark this as fully read data (if tcfg (hash-table-set! *testconfigs* test-full-name tcfg)) (if (and testexists cache-file (file-write-access? cache-path) allow-write-cache) (let ((tpath (conc cache-path "/.testconfig"))) (debug:print-info 1 *default-log-port* "Caching testconfig for " test-name " in " tpath) (if (and tcfg (not (common:in-running-test?))) (configf:write-alist tcfg tpath)))) tcfg)))))) ;; sort tests by priority and waiton ;; Move test specific stuff to a test unit FIXME one of these days (define (tests:sort-by-priority-and-waiton test-records) (if (eq? (hash-table-size test-records) 0) |
︙ | ︙ | |||
1230 1231 1232 1233 1234 1235 1236 | (lambda (a b) (let* ((a-record (hash-table-ref test-records a)) (b-record (hash-table-ref test-records b)) (a-waitons (or (tests:testqueue-get-waitons a-record) '())) (b-waitons (or (tests:testqueue-get-waitons b-record) '())) (a-config (tests:testqueue-get-testconfig a-record)) (b-config (tests:testqueue-get-testconfig b-record)) | | | | 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 | (lambda (a b) (let* ((a-record (hash-table-ref test-records a)) (b-record (hash-table-ref test-records b)) (a-waitons (or (tests:testqueue-get-waitons a-record) '())) (b-waitons (or (tests:testqueue-get-waitons b-record) '())) (a-config (tests:testqueue-get-testconfig a-record)) (b-config (tests:testqueue-get-testconfig b-record)) (a-raw-pri (configf:lookup a-config "requirements" "priority")) (b-raw-pri (configf:lookup b-config "requirements" "priority")) (a-priority (mungepriority a-raw-pri)) (b-priority (mungepriority b-raw-pri))) (tests:testqueue-set-priority! a-record a-priority) (tests:testqueue-set-priority! b-record b-priority) ;; (debug:print 0 *default-log-port* "a=" a ", b=" b ", a-waitons=" a-waitons ", b-waitons=" b-waitons) (cond ;; is |
︙ | ︙ | |||
1354 1355 1356 1357 1358 1359 1360 | ;; read data from tmp file or create if not exists ;; if exists regen in background ;; (define (tests:lazy-dot testrecords outtype sizex sizey) (let ((dfile (conc "/tmp/." (current-user-name) "-" (server:mk-signature) ".dot")) (fname (conc "/tmp/." (current-user-name) "-" (server:mk-signature) ".dotdat"))) (tests:write-dot-file testrecords dfile sizex sizey) | | | 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 | ;; read data from tmp file or create if not exists ;; if exists regen in background ;; (define (tests:lazy-dot testrecords outtype sizex sizey) (let ((dfile (conc "/tmp/." (current-user-name) "-" (server:mk-signature) ".dot")) (fname (conc "/tmp/." (current-user-name) "-" (server:mk-signature) ".dotdat"))) (tests:write-dot-file testrecords dfile sizex sizey) (if (common:file-exists? fname) (let ((res (with-input-from-file fname (lambda () (read-lines))))) (system (conc "env -i PATH=$PATH dot -T " outtype " < " dfile " > " fname "&")) res) (begin (system (conc "env -i PATH=$PATH dot -T " outtype " < " dfile " > " fname)) |
︙ | ︙ | |||
1425 1426 1427 1428 1429 1430 1431 | (if (not (null? test-names)) (let loop ((hed (car test-names)) (tal (cdr test-names))) ;; 'return-procs tells the config reader to prep running system but return a proc (debug:print-info 4 *default-log-port* "hed=" hed " at top of loop") ;; don't know item-path at this time, let the testconfig get the top level testconfig (let* ((config (tests:get-testconfig hed #f all-tests-registry 'return-procs)) (waitons (let ((instr (if config | | | 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 | (if (not (null? test-names)) (let loop ((hed (car test-names)) (tal (cdr test-names))) ;; 'return-procs tells the config reader to prep running system but return a proc (debug:print-info 4 *default-log-port* "hed=" hed " at top of loop") ;; don't know item-path at this time, let the testconfig get the top level testconfig (let* ((config (tests:get-testconfig hed #f all-tests-registry 'return-procs)) (waitons (let ((instr (if config (configf:lookup config "requirements" "waiton") (begin ;; No config means this is a non-existant test (debug:print-error 0 *default-log-port* "non-existent required test \"" hed "\", grep through your testconfigs to find and remove or create the test. Discarding and continuing.") "")))) (debug:print-info 8 *default-log-port* "waitons string is " instr) (string-split (cond ((procedure? instr) (let ((res (instr))) |
︙ | ︙ | |||
1458 1459 1460 1461 1462 1463 1464 | ;; (items (items:get-items-from-config config))) (if (not (hash-table-ref/default test-records hed #f)) (hash-table-set! test-records hed (vector hed ;; 0 config ;; 1 waitons ;; 2 | | | 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 | ;; (items (items:get-items-from-config config))) (if (not (hash-table-ref/default test-records hed #f)) (hash-table-set! test-records hed (vector hed ;; 0 config ;; 1 waitons ;; 2 (configf:lookup config "requirements" "priority") ;; priority 3 (let ((items (hash-table-ref/default config "items" #f)) ;; items 4 (itemstable (hash-table-ref/default config "itemstable" #f))) ;; if either items or items table is a proc return it so test running ;; process can know to call items:get-items-from-config ;; if either is a list and none is a proc go ahead and call get-items ;; otherwise return #f - this is not an iterated test (cond |
︙ | ︙ | |||
1540 1541 1542 1543 1544 1545 1546 | (let* ((cpuload (get-cpu-load)) (diskfree (get-df (current-directory))) (uname (get-uname "-srvpio")) (hostname (get-host-name))) (tests:update-central-meta-info run-id test-id cpuload diskfree minutes uname hostname))) ;; (define (tests:set-partial-meta-info test-id run-id minutes work-area) | | | | 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 | (let* ((cpuload (get-cpu-load)) (diskfree (get-df (current-directory))) (uname (get-uname "-srvpio")) (hostname (get-host-name))) (tests:update-central-meta-info run-id test-id cpuload diskfree minutes uname hostname))) ;; (define (tests:set-partial-meta-info test-id run-id minutes work-area) #;(define (tests:set-partial-meta-info test-id run-id minutes work-area remtries) (let* ((cpuload (get-cpu-load)) (diskfree (get-df (current-directory))) (remtries 10)) (handle-exceptions exn (if (> remtries 0) (begin (print-call-chain (current-error-port)) (debug:print-info 0 *default-log-port* "WARNING: failed to set meta info. Will try " remtries " more times") (set! remtries (- remtries 1)) (thread-sleep! 10) (tests:set-full-meta-info db test-id run-id minutes work-area (- remtries 1))) (let ((err-status ((condition-property-accessor 'sqlite3 'status #f) exn))) (debug:print-error 0 *default-log-port* "tried for over a minute to update meta info and failed. Giving up") (debug:print 0 *default-log-port* "EXCEPTION: database probably overloaded or unreadable.") (debug:print 0 *default-log-port* " message: " ((condition-property-accessor 'exn 'message) exn)) (debug:print 5 *default-log-port* "exn=" (condition->list exn)) (debug:print 0 *default-log-port* " status: " ((condition-property-accessor 'sqlite3 'status) exn)) (print-call-chain (current-error-port)))) (tests:update-testdat-meta-info db test-id work-area cpuload diskfree minutes) ))) ;;====================================================================== ;; A R C H I V I N G |
︙ | ︙ |
Modified tests/Makefile from [3cbc059672] to [66f2b4083e].
1 2 3 4 5 6 7 8 9 10 11 12 | # # run some tests BINPATH = $(shell readlink -m $(PWD)/../bin) MEGATEST = $(BINPATH)/megatest DASHBOARD = $(BINPATH)/dashboard PATH := $(BINPATH):$(PATH) RUNNAME := $(shell date +w%V.%u.%H.%M) IPADDR := "-" RUNID := 1 SERVER = DEBUG = 1 | > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. # # run some tests BINPATH = $(shell readlink -m $(PWD)/../bin) LSBR = $(shell lsb_release -sr) MEGATEST = $(BINPATH)/megatest MTEST = $(BINPATH)/.$(LSBR)/mtest DASHBOARD = $(BINPATH)/dashboard PATH := $(BINPATH):$(PATH) RUNNAME := $(shell date +w%V.%u.%H.%M) IPADDR := "-" RUNID := 1 SERVER = DEBUG = 1 |
︙ | ︙ | |||
20 21 22 23 24 25 26 | # The NEWTARGET causes some tests to fail. Do not use until this is fixed. NEWTARGET = "$(OS)/$(FS)/$(VER)" TARGET = "ubuntu/nfs/none" all : build unit test4 # test1 test2 test3 test4 test5 test6 test7 test8 test9 | | > > > | | 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 | # The NEWTARGET causes some tests to fail. Do not use until this is fixed. NEWTARGET = "$(OS)/$(FS)/$(VER)" TARGET = "ubuntu/nfs/none" all : build unit test4 # test1 test2 test3 test4 test5 test6 test7 test8 test9 unit : all-rmt.log all-api.log # basicserver.log runs.log misc.log tests.log # inter dependencies on the unit tests, I wish these could be "suggestions" all-rmt.log : all-api.log rel : cd release;dashboard -rows 25 & ## basicserver.log : unittests/basicserver.scm ## script -c "./rununittest.sh basicserver $(DEBUG)" basicserver.log %.log : build unittests/%.scm $(MTEST) script -c "./rununittest.sh $* $(DEBUG)" $*.log if logpro unit.logpro $*.html < $*.log > /dev/null;then echo ALLPASS;else echo ALLFAIL;mv $*.log $*.log.FAIL;fi server : cd fullrun;$(MEGATEST) -server - -debug $(DEBUG) -run-id $(RUNID) stopserver : |
︙ | ︙ | |||
85 86 87 88 89 90 91 | cd fullrun;sleep 0;$(MEGATEST) -preclean -runtests % -target ubuntu/nfs/sleep1 :runname $(RUNNAME)_ae -debug $(DEBUG) $(LOGGING) > ae.log 2> ae.log & cd fullrun;sleep 0;$(MEGATEST) -preclean -runtests % -target ubuntu/nfs/sleep10 :runname $(RUNNAME)_ab -debug $(DEBUG) $(LOGGING) > ab.log 2> ab.log & cd fullrun;sleep 5;$(MEGATEST) -preclean -runtests % -target ubuntu/nfs/sleep60 :runname $(RUNNAME)_ac -debug $(DEBUG) $(LOGGING) > ac.log 2> ac.log & cd fullrun;sleep 8;$(MEGATEST) -preclean -runtests % -target ubuntu/nfs/sleep240 :runname $(RUNNAME)_ad -debug $(DEBUG) $(LOGGING) > ad.log 2> ad.log & # cd fullrun;sleep 0;$(MEGATEST) -preclean -runtests % -target $(TARGET) :runname $(RUNNAME)_af -debug $(DEBUG) $(LOGGING) > af.log 2> af.log & # MUST ADD THIS BACK IN ASAP!!!! | | | 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 | cd fullrun;sleep 0;$(MEGATEST) -preclean -runtests % -target ubuntu/nfs/sleep1 :runname $(RUNNAME)_ae -debug $(DEBUG) $(LOGGING) > ae.log 2> ae.log & cd fullrun;sleep 0;$(MEGATEST) -preclean -runtests % -target ubuntu/nfs/sleep10 :runname $(RUNNAME)_ab -debug $(DEBUG) $(LOGGING) > ab.log 2> ab.log & cd fullrun;sleep 5;$(MEGATEST) -preclean -runtests % -target ubuntu/nfs/sleep60 :runname $(RUNNAME)_ac -debug $(DEBUG) $(LOGGING) > ac.log 2> ac.log & cd fullrun;sleep 8;$(MEGATEST) -preclean -runtests % -target ubuntu/nfs/sleep240 :runname $(RUNNAME)_ad -debug $(DEBUG) $(LOGGING) > ad.log 2> ad.log & # cd fullrun;sleep 0;$(MEGATEST) -preclean -runtests % -target $(TARGET) :runname $(RUNNAME)_af -debug $(DEBUG) $(LOGGING) > af.log 2> af.log & # MUST ADD THIS BACK IN ASAP!!!! # cd fullrun;sleep 10;$(MEGATEST) -run-wait -target $(TARGET) :runname % -testpatt % :state RUNNING,LAUNCHED,NOT_STARTED,REMOTEHOSTSTART;echo ALL DONE test6: fullprep cd fullrun;$(MEGATEST) -preclean -runtests runfirst -testpatt %/1 -reqtarg ubuntu/nfs/none :runname $(RUNNAME)_itempatt -v cd fullrun;$(MEGATEST) -preclean -runtests runfirst -testpatt %blahha% -reqtarg ubuntu/nfs/none :runname $(RUNNAME)_itempatt -debug 10 cd fullrun;$(MEGATEST) -rollup :runname newrun -target ubuntu/nfs/none -debug 10 test7: |
︙ | ︙ | |||
171 172 173 174 175 176 177 | mkdir -p mintest/runs mintest/links cd mintest;$(MEGATEST) -stop-server 0 cd mintest;$(MEGATEST) -server - -debug $(DEBUG) > server.log 2> server.log & sleep 3 cd mintest;$(DASHBOARD) -rows 18 & cleanprep : ../*.scm Makefile */*.config build | | | 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 | mkdir -p mintest/runs mintest/links cd mintest;$(MEGATEST) -stop-server 0 cd mintest;$(MEGATEST) -server - -debug $(DEBUG) > server.log 2> server.log & sleep 3 cd mintest;$(DASHBOARD) -rows 18 & cleanprep : ../*.scm Makefile */*.config build mkdir -p fullrun/tmp/mt_runs fullrun/tmp/mt_links /tmp/$(USER)/adisk1 fullrun/logs rm -f */logging.db touch cleanprep fullprep : cleanprep cd fullrun;$(MEGATEST) -remove-runs :runname $(RUNNAME)% -target %/%/% -testpatt %/% cd fullrun;$(BINPATH)/dashboard -rows 15 & |
︙ | ︙ |
Modified tests/dep-tests/common.testconfig from [382c89b27d] to [f50c774530].
1 2 3 4 5 6 7 | [ezsteps] delay sleep $SPEED;echo "Delayed $SPEED seconds" # lookup table for waitons # [std] genlib setup | > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. [ezsteps] delay sleep $SPEED;echo "Delayed $SPEED seconds" # lookup table for waitons # [std] genlib setup |
︙ | ︙ |
Modified tests/dep-tests/common_itemstable.testconfig from [64419eaa4a] to [e6e486536d].
1 2 3 4 | [itemstable] VIEW layout layout layout schematic schematic schematic CELL ntran ptran diode ntran ptran diode | > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. [itemstable] VIEW layout layout layout schematic schematic schematic CELL ntran ptran diode ntran ptran diode |
Modified tests/dep-tests/megatest.config from [b96d033fe9] to [45b6e2e343].
1 2 3 4 5 6 7 | [fields] # this field changes the dep tree DEPS TEXT # this field changes the test run time; 0 .. N or random SPEED TEXT | > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. [fields] # this field changes the dep tree DEPS TEXT # this field changes the test run time; 0 .. N or random SPEED TEXT |
︙ | ︙ |
Modified tests/dep-tests/runconfigs.config from [9ccccd23c7] to [8722e0acae].
1 2 3 4 5 6 7 | [default] # [DEPS/SPEED] [simple/0] [std/0] | > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. [default] # [DEPS/SPEED] [simple/0] [std/0] |
︙ | ︙ |
Modified tests/dep-tests/tests/aggregate/testconfig from [fa95f0ff55] to [cea7be458c].
1 2 3 4 | [include #{getenv MT_RUN_AREA_HOME}/common.testconfig] [requirements] waiton #{get #{getenv DEPS} aggregate} | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. [include #{getenv MT_RUN_AREA_HOME}/common.testconfig] [requirements] waiton #{get #{getenv DEPS} aggregate} |
Modified tests/dep-tests/tests/genlib/testconfig from [5997267de8] to [2b0c33f7e4].
1 2 3 4 5 6 7 | [include #{getenv MT_RUN_AREA_HOME}/common.testconfig] [itemstable] VIEWTYPE layout schematic [requirements] waiton #{get #{getenv DEPS} genlib} | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. [include #{getenv MT_RUN_AREA_HOME}/common.testconfig] [itemstable] VIEWTYPE layout schematic [requirements] waiton #{get #{getenv DEPS} genlib} |
︙ | ︙ |
Modified tests/dep-tests/tests/results/testconfig from [33e68a628c] to [b9a7a9ba39].
1 2 3 4 5 | [include #{getenv MT_RUN_AREA_HOME}/common.testconfig] [requirements] waiton #{get #{getenv DEPS} results} | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. [include #{getenv MT_RUN_AREA_HOME}/common.testconfig] [requirements] waiton #{get #{getenv DEPS} results} |
Modified tests/dep-tests/tests/setup/testconfig from [c2dea9e96c] to [188ca8ccb8].
1 2 | [include #{getenv MT_RUN_AREA_HOME}/common.testconfig] | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. [include #{getenv MT_RUN_AREA_HOME}/common.testconfig] |
Modified tests/dep-tests/tests/test1/testconfig from [d6e3a28a40] to [b529b552a6].
1 2 3 4 5 6 7 | [include #{getenv MT_RUN_AREA_HOME}/common.testconfig] [include #{getenv MT_RUN_AREA_HOME}/common_itemstable.testconfig] [requirements] waiton #{get #{getenv DEPS} test1} | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. [include #{getenv MT_RUN_AREA_HOME}/common.testconfig] [include #{getenv MT_RUN_AREA_HOME}/common_itemstable.testconfig] [requirements] waiton #{get #{getenv DEPS} test1} |
︙ | ︙ |
Modified tests/dep-tests/tests/test2/testconfig from [536ee9f06b] to [a1a9431bfa].
1 2 3 4 5 6 7 | [include #{getenv MT_RUN_AREA_HOME}/common.testconfig] [include #{getenv MT_RUN_AREA_HOME}/common_itemstable.testconfig] [requirements] waiton #{get #{getenv DEPS} test2} | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. [include #{getenv MT_RUN_AREA_HOME}/common.testconfig] [include #{getenv MT_RUN_AREA_HOME}/common_itemstable.testconfig] [requirements] waiton #{get #{getenv DEPS} test2} |
Modified tests/dynamic-waiton-example/common.testconfig from [c4b44c24a4] to [76f4fe8556].
1 2 3 4 5 6 7 | [ezsteps] delay sleep $SPEED;echo "Delayed $SPEED seconds" [requirements] #{getenv WAITON_#{getenv MT_TEST_NAME}} [test_meta] | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. [ezsteps] delay sleep $SPEED;echo "Delayed $SPEED seconds" [requirements] #{getenv WAITON_#{getenv MT_TEST_NAME}} [test_meta] |
︙ | ︙ |
Modified tests/dynamic-waiton-example/common_itemstable.testconfig from [64419eaa4a] to [ff0dd73743].
1 2 3 4 | [itemstable] VIEW layout layout layout schematic schematic schematic CELL ntran ptran diode ntran ptran diode | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. [itemstable] VIEW layout layout layout schematic schematic schematic CELL ntran ptran diode ntran ptran diode |
Modified tests/dynamic-waiton-example/megatest.config from [b96d033fe9] to [6547eaf1dc].
1 2 3 4 5 6 7 | [fields] # this field changes the dep tree DEPS TEXT # this field changes the test run time; 0 .. N or random SPEED TEXT | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. [fields] # this field changes the dep tree DEPS TEXT # this field changes the test run time; 0 .. N or random SPEED TEXT |
︙ | ︙ |
Modified tests/dynamic-waiton-example/runconfigs.config from [81e449a935] to [fc3c92bc21].
1 2 3 4 5 6 7 | [default] WAITON_setup WAITON_genlib waiton setup WAITON_test1 waiton genlib WAITON_aggregate waiton test1 WAITON_test2 waiton aggregate | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. [default] WAITON_setup WAITON_genlib waiton setup WAITON_test1 waiton genlib WAITON_aggregate waiton test1 WAITON_test2 waiton aggregate |
︙ | ︙ |
Modified tests/dynamic-waiton-example/tests/aggregate/testconfig from [c2dea9e96c] to [188ca8ccb8].
1 2 | [include #{getenv MT_RUN_AREA_HOME}/common.testconfig] | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. [include #{getenv MT_RUN_AREA_HOME}/common.testconfig] |
Modified tests/dynamic-waiton-example/tests/genlib/testconfig from [e2cba0fe56] to [4b1e277b66].
1 2 3 4 5 | [include #{getenv MT_RUN_AREA_HOME}/common.testconfig] [itemstable] VIEWTYPE layout schematic | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. [include #{getenv MT_RUN_AREA_HOME}/common.testconfig] [itemstable] VIEWTYPE layout schematic |
Modified tests/dynamic-waiton-example/tests/results/testconfig from [c2dea9e96c] to [188ca8ccb8].
1 2 | [include #{getenv MT_RUN_AREA_HOME}/common.testconfig] | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. [include #{getenv MT_RUN_AREA_HOME}/common.testconfig] |
Modified tests/dynamic-waiton-example/tests/setup/testconfig from [c2dea9e96c] to [188ca8ccb8].
1 2 | [include #{getenv MT_RUN_AREA_HOME}/common.testconfig] | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. [include #{getenv MT_RUN_AREA_HOME}/common.testconfig] |
Modified tests/dynamic-waiton-example/tests/test1/testconfig from [a1ac7fb924] to [51e580b121].
1 2 3 | [include #{getenv MT_RUN_AREA_HOME}/common.testconfig] [include #{getenv MT_RUN_AREA_HOME}/common_itemstable.testconfig] | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. [include #{getenv MT_RUN_AREA_HOME}/common.testconfig] [include #{getenv MT_RUN_AREA_HOME}/common_itemstable.testconfig] |
Modified tests/dynamic-waiton-example/tests/test2/testconfig from [a1ac7fb924] to [51e580b121].
1 2 3 | [include #{getenv MT_RUN_AREA_HOME}/common.testconfig] [include #{getenv MT_RUN_AREA_HOME}/common_itemstable.testconfig] | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. [include #{getenv MT_RUN_AREA_HOME}/common.testconfig] [include #{getenv MT_RUN_AREA_HOME}/common_itemstable.testconfig] |
Modified tests/fdktestqa/fdk.config from [1449c69529] to [d3876c421e].
1 2 3 4 5 6 7 | [fields] SYSTEM TEXT RELEASE TEXT [setup] # Adjust max_concurrent_jobs to limit how much you load your machines # max_concurrent_jobs 150 | > > > > > > > > > > > > > > > > > | < < > | > < | < < < < < < < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. [fields] SYSTEM TEXT RELEASE TEXT [setup] # Adjust max_concurrent_jobs to limit how much you load your machines # max_concurrent_jobs 150 max_concurrent_jobs 3000 # This is your link path, you can move it but it is generally better to keep it stable linktree #{shell readlink -f #{getenv MT_RUN_AREA_HOME}/../simplelinks} [include testqa/configs/megatest.abc.config] [jobtools] maxload 4 # launcher smartlauncher --cores 1 --memory 1 launcher nbjob run --target pdx_soft --class 'SLES11&&1C&&1G' --qslot /icf/fdk/soft # launcher bsub -q priority -o $MT_TEST_RUN_DIR/openlava.log [server] # timeout 0.01 # homehost xena # homehost 143.182.225.38 # force server # server-query-threshold 0 |
Modified tests/fdktestqa/testqa/Makefile from [f65c4da07e] to [66f3d73e38].
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | BINDIR = $(PWD)/../../../bin PATH := $(BINDIR):$(PATH) MEGATEST = $(BINDIR)/megatest DASHBOARD = $(BINDIR)/dashboard NEWDASHBOARD = $(BINDIR)/newdashboard RUNNAME = a NUMTESTS = 20 all : $(MEGATEST) -remove-runs -target a/b -runname c -testpatt %/% $(MEGATEST) -run -testpatt % -target a/b -runname c bigbig : for tn in a b c d;do \ | > > > > > > > > > > > > > > > > > > | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. BINDIR = $(PWD)/../../../bin PATH := $(BINDIR):$(PATH) MEGATEST = $(BINDIR)/megatest DASHBOARD = $(BINDIR)/dashboard NEWDASHBOARD = $(BINDIR)/newdashboard RUNNAME = a NUMTESTS = 20 SUBTARG = b all : $(MEGATEST) -remove-runs -target a/b -runname c -testpatt %/% $(MEGATEST) -run -testpatt % -target a/b -runname c bigbig : for tn in a b c d;do \ (NUMTESTS=1000 $(MEGATEST) -run -testpatt % -target a/$(SUBTARG) -runname $$tn & ) ; \ done waitonpatt : megatest -remove-runs -runname waitonpatt -target a/$(SUBTARG) -testpatt % NUMTESTS=15 megatest -run -target a/b -runname waitonpatt -testpatt bigrun3/%8 waitonall : megatest -remove-runs -runname waitonall -target a/b -testpatt % NUMTESTS=20 megatest -run -target a/b -runname waitonall -testpatt alltop bigrun : |
︙ | ︙ |
Modified tests/fdktestqa/testqa/README from [a5a438bd7b] to [a17713c60f].
1 | set NUMTESTS to set the number of tests that will be run. A small number (say 20) illustrates itemwait well. | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. set NUMTESTS to set the number of tests that will be run. A small number (say 20) illustrates itemwait well. |
Modified tests/fdktestqa/testqa/configs/megatest.abc.config from [a1a8a77b6d] to [c1fd66d97e].
1 2 3 4 5 6 7 | # Valid values for state and status for steps, NB// It is not recommended you use this [validvalues] state start end completed # Job tools are more advanced ways to control how your jobs are launched [jobtools] # useshell yes | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. # Valid values for state and status for steps, NB// It is not recommended you use this [validvalues] state start end completed # Job tools are more advanced ways to control how your jobs are launched [jobtools] # useshell yes |
︙ | ︙ |
Modified tests/fdktestqa/testqa/configs/megatest.def.config from [11f50463c8] to [982421a250].
1 2 3 4 5 6 7 | # You can override environment variables for all your tests here [env-override] EXAMPLE_VAR example value # As you run more tests you may need to add additional disks, the names are arbitrary but must be unique [disks] disk0 #{scheme (create-directory (nice-path "#{getenv MT_RUN_AREA_HOME}/../simpleruns") #t)} | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. # You can override environment variables for all your tests here [env-override] EXAMPLE_VAR example value # As you run more tests you may need to add additional disks, the names are arbitrary but must be unique [disks] disk0 #{scheme (create-directory (nice-path "#{getenv MT_RUN_AREA_HOME}/../simpleruns") #t)} |
︙ | ︙ |
Modified tests/fdktestqa/testqa/local.config.example from [3de7bfdb32] to [eb39bb3b99].
1 2 3 4 5 6 7 | [host-types] general #MTLOWESTLOAD xena zeus [jobtools] launcher nbfake maxload 1.5 flexi-launcher yes | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. [host-types] general #MTLOWESTLOAD xena zeus [jobtools] launcher nbfake maxload 1.5 flexi-launcher yes |
︙ | ︙ |
Modified tests/fdktestqa/testqa/megatest.config from [d32541500d] to [4fbbebd6d8].
1 2 3 4 5 6 | [setup] testcopycmd cp --remove-destination -rlv TEST_SRC_PATH/. TEST_TARG_PATH/. >> TEST_TARG_PATH/mt_launch.log 2>> TEST_TARG_PATH/mt_launch.log # launchwait no launch-delay 0 [server] | > > > > > > > > > > > > > > > > > > > > > | > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. [setup] testcopycmd cp --remove-destination -rlv TEST_SRC_PATH/. TEST_TARG_PATH/. >> TEST_TARG_PATH/mt_launch.log 2>> TEST_TARG_PATH/mt_launch.log # launchwait no # launch-delay 0.1 launch-delay 0 [jobtools] maxhomehostload 4 [server] # runtime 180 # timeout is in hours, this is how long the server will stay alive when not being used. # timeout 0.1 # All these are overridden in ../fdk.config # [jobtools] # launcher nbfake # launcher bsub -q priority -o $MT_TEST_RUN_DIR/openlava.log [include ../fdk.config] |
︙ | ︙ |
Modified tests/fdktestqa/testqa/runconfigs.config from [346ed47154] to [6d8e5dc4ac].
1 2 3 4 5 6 | [default] ALLTESTS see this variable # Your variables here are grouped by targets [SYSTEM/RELEASE] [SYSTEM_val/RELEASE_val] ANOTHERVAR only defined if target is SYSTEM_val/RELEASE_val | > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. [include local.runconfigs] [default] ALLTESTS see this variable # Your variables here are grouped by targets [SYSTEM/RELEASE] [SYSTEM_val/RELEASE_val] ANOTHERVAR only defined if target is SYSTEM_val/RELEASE_val |
Modified tests/fdktestqa/testqa/runsuite.sh from [b83309f619] to [c108c24f2d].
1 2 3 4 5 6 7 8 9 | #!/bin/bash # (cd ../../..;make && make install) || exit 1 # export PATH=$PWD/../../../bin:$PATH for i in a b c d e f;do # g h i j k l m n o p q r s t u v w x y z;do viewscreen megatest -run -testpatt % -target a/b -runname w$(date +%U.%u.%H)$i done | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | #!/bin/bash # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. # (cd ../../..;make && make install) || exit 1 # export PATH=$PWD/../../../bin:$PATH for i in a b c d e f;do # g h i j k l m n o p q r s t u v w x y z;do viewscreen megatest -run -testpatt % -target a/b -runname w$(date +%U.%u.%H)$i done |
︙ | ︙ |
Modified tests/fdktestqa/testqa/tests/alltop/testconfig from [50bb71fe35] to [0e44634228].
1 2 3 4 5 6 7 | # Add additional steps here. Format is "stepname script" [vars] step1var step1.sh [ezsteps] step1 megatest -list-runs $MT_RUNNAME -target $MT_TARGET -itempatt % | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. # Add additional steps here. Format is "stepname script" [vars] step1var step1.sh [ezsteps] step1 megatest -list-runs $MT_RUNNAME -target $MT_TARGET -itempatt % |
︙ | ︙ |
Modified tests/fdktestqa/testqa/tests/bigrun/step1.sh from [e700391a61] to [e301928d0a].
1 2 3 | #!/bin/bash if [ $NUMBER -lt 10 ];then sleep 20 | > > > > > > > > > > > > > > > > > | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | #!/bin/bash # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. if [ $NUMBER -lt 10 ];then sleep 20 sleep `echo 4 \* $NUMBER | bc` else sleep 130 fi if [[ $RANDOM -lt 10000 ]];then exit 1 else |
︙ | ︙ |
Modified tests/fdktestqa/testqa/tests/bigrun/testconfig from [679e59d899] to [a7919d4cda].
1 2 3 4 5 6 7 | # Add additional steps here. Format is "stepname script" [vars] step1var step1.sh [ezsteps] step1 #{get vars step1var} | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. # Add additional steps here. Format is "stepname script" [vars] step1var step1.sh [ezsteps] step1 #{get vars step1var} |
︙ | ︙ |
Modified tests/fdktestqa/testqa/tests/bigrun2/step1.sh from [f90152c7af] to [01419025f6].
1 2 3 4 5 6 7 8 9 | #!/bin/sh # prev_test=`$MT_MEGATEST -test-paths -target $MT_TARGET :runname $MT_RUNNAME -testpatt bigrun/$NUMBER` # if [ -e $prev_test/testconfig ]; then # exit 0 # else # exit 1 # fi exit 0 | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | #!/bin/sh # prev_test=`$MT_MEGATEST -test-paths -target $MT_TARGET :runname $MT_RUNNAME -testpatt bigrun/$NUMBER` # if [ -e $prev_test/testconfig ]; then # exit 0 # else # exit 1 # fi # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. exit 0 |
Modified tests/fdktestqa/testqa/tests/bigrun2/testconfig from [ccc63b9335] to [95837d9aee].
1 2 3 4 5 6 7 8 9 10 11 12 13 | # Add additional steps here. Format is "stepname script" [ezsteps] step1 step1.sh # Test requirements are specified here [requirements] waiton bigrun priority 0 mode itemwait itemmap .*/ # Iteration for your tests are controlled by the items section [items] | > > > > > > > > > > > > > > > > > | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. # Add additional steps here. Format is "stepname script" [ezsteps] step1 step1.sh # Test requirements are specified here [requirements] waiton bigrun priority 0 mode itemwait itemmap .*/ # Iteration for your tests are controlled by the items section [items] NUMBER #{scheme (string-intersperse (map (lambda (x)(conc (if (getenv "USEBLAH") "blah/" "") x)) \ (map number->string (sort (let loop ((a 0)(res '())) \ (if (<= a (or (any->number (get-environment-variable "NUMTESTS")) 2500)) \ (loop (+ a 1)(cons a res)) res)) <))) " ")} # test_meta is a section for storing additional data on your test [test_meta] |
︙ | ︙ |
Modified tests/fdktestqa/testqa/tests/bigrun3/step1.sh from [f90152c7af] to [01419025f6].
1 2 3 4 5 6 7 8 9 | #!/bin/sh # prev_test=`$MT_MEGATEST -test-paths -target $MT_TARGET :runname $MT_RUNNAME -testpatt bigrun/$NUMBER` # if [ -e $prev_test/testconfig ]; then # exit 0 # else # exit 1 # fi exit 0 | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | #!/bin/sh # prev_test=`$MT_MEGATEST -test-paths -target $MT_TARGET :runname $MT_RUNNAME -testpatt bigrun/$NUMBER` # if [ -e $prev_test/testconfig ]; then # exit 0 # else # exit 1 # fi # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. exit 0 |
Modified tests/fdktestqa/testqa/tests/bigrun3/testconfig from [d62ae5987e] to [55a756af09].
1 2 3 4 5 6 7 | # Add additional steps here. Format is "stepname script" [ezsteps] step1 step1.sh # Test requirements are specified here [requirements] waiton bigrun2 | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. # Add additional steps here. Format is "stepname script" [ezsteps] step1 step1.sh # Test requirements are specified here [requirements] waiton bigrun2 |
︙ | ︙ |
Modified tests/fixpath.csh from [b1cf12b595] to [f926c6fd4b].
1 | setenv PATH `readlink -f ../bin`:$PATH | > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. setenv PATH `readlink -f ../bin`:$PATH |
Modified tests/fixpath.sh from [3f102b87f3] to [b6d0bf2956].
1 | export PATH=$(readlink -f ../bin):$PATH | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. export PATH=$(readlink -f ../bin):$PATH |
Deleted tests/fslsync/megatest.config version [6aa39fa6b6].
|
| < < < < < < < < < < < < < < < < < < < < |
Deleted tests/fslsync/runconfigs.config version [ba5882eb76].
|
| < < < < < |
Deleted tests/fslsync/sites.dat.template version [7e1f28d5f7].
|
| < |
Deleted tests/fslsync/tests/setup/mkdirs.logpro version [e453c6e331].
|
| < < < < < < < < |
Deleted tests/fslsync/tests/setup/mkdirs.sh version [5b853fc39d].
|
| < < < < < < < < < < < |
Deleted tests/fslsync/tests/setup/seedcache.logpro version [e453c6e331].
|
| < < < < < < < < |
Deleted tests/fslsync/tests/setup/seedcache.sh version [a18d5e99f5].
|
| < < < < < < |
Deleted tests/fslsync/tests/setup/testconfig version [3c9aac8422].
|
| < < < < < < < < < < < < < < < < < < < < < |
Deleted tests/fslsync/tests/sync/fsync.logpro version [e453c6e331].
|
| < < < < < < < < |
Deleted tests/fslsync/tests/sync/fsync.sh version [bf21db2120].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted tests/fslsync/tests/sync/rsync.logpro version [e453c6e331].
|
| < < < < < < < < |
Deleted tests/fslsync/tests/sync/rsync.sh version [035d9817f0].
|
| < < < < < < < < < < < |
Deleted tests/fslsync/tests/sync/testconfig version [518d98790f].
|
| < < < < < < < < < < < < < < < < < < < < < < |
Deleted tests/fullrun/afs.config version [d8bf445723].
|
| < |
Deleted tests/fullrun/common_runconfigs.config version [bf3b671e75].
|
| < < < < < < < < < < < < < < < < < |
Deleted tests/fullrun/configs/mt_include_1.config version [4c90d470ad].
|
| < < < < < < < < < < < < < < < < < < < < < < < |
Deleted tests/fullrun/configs/mt_include_2.config version [e3be724bae].
|
| < < |
Deleted tests/fullrun/ez_pass_linked/testconfig version [55e83172e9].
|
| < < < < < < < < < < < < < |
Deleted tests/fullrun/megatest.config version [55e292f1b8].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted tests/fullrun/multi-dboard-load-all.scm version [929c778374].
|
| < < < < < < < < < < < < < |
Deleted tests/fullrun/multi-dboard.sh version [b641343611].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted tests/fullrun/nfs.config version [417e40a368].
|
| < |
Deleted tests/fullrun/run-each-proc.sh version [2d922bdae6].
|
| < < < < < < < < < < < < < < < |
Deleted tests/fullrun/runconfigs.config version [cf88798291].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted tests/fullrun/tests/all_toplevel/calcresults.logpro version [7bd9c74d1a].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted tests/fullrun/tests/all_toplevel/testconfig version [5a83007156].
|
| < < < < < < < < < < < < < |
Deleted tests/fullrun/tests/blocktestxz/main.sh version [c5c5020d12].
|
| < < < < < < |
Deleted tests/fullrun/tests/blocktestxz/testconfig version [689bce3544].
|
| < < < < < < < < < < < < < < < < < < < < < < |
Deleted tests/fullrun/tests/db_sync/calcresults.logpro version [2b1b84e89b].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted tests/fullrun/tests/db_sync/dbdelta.scm version [5e038e3a3e].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted tests/fullrun/tests/db_sync/getdbdir.scm version [2bb1c2296a].
|
| < |
Deleted tests/fullrun/tests/db_sync/showdiff.logpro version [95bed654bf].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted tests/fullrun/tests/db_sync/testconfig version [f92575e768].
|
| < < < < < < < < < < < < < |
Deleted tests/fullrun/tests/dynamic_waiton/testconfig version [7a5b999ddf].
|
| < < < < < < < < < < < < < < < < < < < < < |
Deleted tests/fullrun/tests/exit_0/main.sh version [0536bc3eb1].
|
| < < < < < < < < < < |
Deleted tests/fullrun/tests/exit_0/testconfig version [63e30e301e].
|
| < < < < < < < < < < < < < < < < < |
Deleted tests/fullrun/tests/exit_1/main.sh version [c5651ffc6c].
|
| < < < < < < < < < < |
Deleted tests/fullrun/tests/exit_1/testconfig version [b41a76aacb].
|
| < < < < < < < < < < < < < |
Deleted tests/fullrun/tests/ez_exit2_fail/testconfig version [f01baecf74].
|
| < < < < < < < < < < < < < < < |
Deleted tests/fullrun/tests/ez_fail/testconfig version [d90c6719c8].
|
| < < < < < < < < < < < < < < < < < < < |
Deleted tests/fullrun/tests/ez_fail_quick/testconfig version [99e2edd3f4].
|
| < < < < < < < < < < < < < < < < < < |
Deleted tests/fullrun/tests/ez_pass/testconfig version [495009f510].
|
| < < < < < < < < < < < < < < < |
Deleted tests/fullrun/tests/ez_pass_linked version [43cc02393a].
|
| < |
Deleted tests/fullrun/tests/ezlog_fail/example.logpro version [e50a47bd5d].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted tests/fullrun/tests/ezlog_fail/lookithome.logpro version [1d9c0ef873].
|
| < < < < < < < < < < |
Deleted tests/fullrun/tests/ezlog_fail/lookittmp.logpro version [961ab4aef4].
|
| < < < < < < |
Deleted tests/fullrun/tests/ezlog_fail/testconfig version [da8d5b9ba5].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted tests/fullrun/tests/ezlog_fail/waiver_1.logpro version [f9358fd909].
|
| < |
Deleted tests/fullrun/tests/ezlog_fail_then_pass/firststep.logpro version [1d9c0ef873].
|
| < < < < < < < < < < |
Deleted tests/fullrun/tests/ezlog_fail_then_pass/main.sh version [e978ba6f87].
|
| < < < < < < < < < < < < < < < < < < |
Deleted tests/fullrun/tests/ezlog_fail_then_pass/testconfig version [4d4490bc7d].
|
| < < < < < < < < < < < < < |
Deleted tests/fullrun/tests/ezlog_pass/example.logpro version [e50a47bd5d].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted tests/fullrun/tests/ezlog_pass/lookittmp.logpro version [1d9c0ef873].
|
| < < < < < < < < < < |
Deleted tests/fullrun/tests/ezlog_pass/testconfig version [13eb33bb90].
|
| < < < < < < < < < < < < < |
Deleted tests/fullrun/tests/ezlog_warn/lookithome.logpro version [b2a6575abf].
|
| < < < < < < < < < < < |
Deleted tests/fullrun/tests/ezlog_warn/lookittmp.logpro version [5323023529].
|
| < < < < < < < < < < < < |
Deleted tests/fullrun/tests/ezlog_warn/testconfig version [bb1f94c96f].
|
| < < < < < < < < < < < < < |
Deleted tests/fullrun/tests/lineitem_fail/main.sh version [b8aaccbe35].
|
| < < < < < < < < < < < < < < < < < < < < < < < |
Deleted tests/fullrun/tests/lineitem_fail/testconfig version [475b97c77b].
|
| < < < < < < < < < < |
Deleted tests/fullrun/tests/lineitem_pass/main.sh version [c43fd19ef0].
|
| < < < < < < < < < < < < < < < < < < < < < < |
Deleted tests/fullrun/tests/lineitem_pass/testconfig version [475b97c77b].
|
| < < < < < < < < < < |
Deleted tests/fullrun/tests/logpro_required_fail/testconfig version [ec159a2f12].
|
| < < < < < < < < < < < < < < < < < < < < < < < |
Deleted tests/fullrun/tests/manual_example/results/results.csv version [5aae106e5b].
|
| < |
Deleted tests/fullrun/tests/manual_example/runsetupxterm.sh version [de48b1c9d6].
|
| < < < < < < < < < < < < < |
Deleted tests/fullrun/tests/manual_example/setupremote.sh version [4f3f90bb14].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted tests/fullrun/tests/manual_example/testconfig version [f5375aa3ae].
|
| < < < < < < < < < < < < < |
Deleted tests/fullrun/tests/neverrun/testconfig version [88f71844f4].
|
| < < < < |
Deleted tests/fullrun/tests/no_items/testconfig version [ee0c082186].
|
| < < < < < < < < < < < < < < < |
Deleted tests/fullrun/tests/priority_1/main.sh version [0536bc3eb1].
|
| < < < < < < < < < < |
Deleted tests/fullrun/tests/priority_1/testconfig version [9d6a3629ba].
|
| < < < < < < < < < < < < < < < < < |
Deleted tests/fullrun/tests/priority_10/main.sh version [0536bc3eb1].
|
| < < < < < < < < < < |
Deleted tests/fullrun/tests/priority_10/testconfig version [393387936a].
|
| < < < < < < < < < < < < < |
Deleted tests/fullrun/tests/priority_10_waiton_1/main.sh version [0536bc3eb1].
|
| < < < < < < < < < < |
Deleted tests/fullrun/tests/priority_10_waiton_1/testconfig version [b7686d9e51].
|
| < < < < < < < < < < < < < < |
Deleted tests/fullrun/tests/priority_2/main.sh version [8c8c341150].
|
| < < < < < < < < < < |
Deleted tests/fullrun/tests/priority_2/testconfig version [7fc8d055ec].
|
| < < < < < < < < < < < < < < < < |
Deleted tests/fullrun/tests/priority_3/README version [f710a809a4].
|
| < < < |
Deleted tests/fullrun/tests/priority_3/main.sh version [416f9ddbf9].
|
| < < < < < < < < < < < < < < < < < < < < |
Deleted tests/fullrun/tests/priority_3/testconfig version [392fa56879].
|
| < < < < < < < < < < < < < < < |
Deleted tests/fullrun/tests/priority_4/main.sh version [0536bc3eb1].
|
| < < < < < < < < < < |
Deleted tests/fullrun/tests/priority_4/testconfig version [0f3ea908bb].
|
| < < < < < < < < < < < < < < |
Deleted tests/fullrun/tests/priority_5/main.sh version [0536bc3eb1].
|
| < < < < < < < < < < |
Deleted tests/fullrun/tests/priority_5/testconfig version [ce686fcc38].
|
| < < < < < < < < < < < < < < < < |
Deleted tests/fullrun/tests/priority_6/main.sh version [0536bc3eb1].
|
| < < < < < < < < < < |
Deleted tests/fullrun/tests/priority_6/testconfig version [b12d3ed5db].
|
| < < < < < < < < < < < < < |
Deleted tests/fullrun/tests/priority_7/main.sh version [0536bc3eb1].
|
| < < < < < < < < < < |
Deleted tests/fullrun/tests/priority_7/testconfig version [0be8a52e91].
|
| < < < < < < < < < < < < < < < < < |
Deleted tests/fullrun/tests/priority_8/main.sh version [12267f0508].
|
| < < < < < < < < < < < < < < |
Deleted tests/fullrun/tests/priority_8/testconfig version [cce675c747].
|
| < < < < < < < < < < < < < |
Deleted tests/fullrun/tests/priority_9/main.sh version [0536bc3eb1].
|
| < < < < < < < < < < |
Deleted tests/fullrun/tests/priority_9/testconfig version [b41a76aacb].
|
| < < < < < < < < < < < < < |
Deleted tests/fullrun/tests/runfirst/main.sh version [2f5036b48c].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted tests/fullrun/tests/runfirst/testconfig version [784a9af124].
|
| < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted tests/fullrun/tests/runfirst/wasting_time.logpro version [1c532ab9c9].
|
| < < < < < < < < < < < < < < < |
Deleted tests/fullrun/tests/singletest/main.sh version [d41b458021].
|
| < < < < < < < < < |
Deleted tests/fullrun/tests/singletest/testconfig version [e1b002dc2e].
|
| < < < < < < < < < < < < < |
Deleted tests/fullrun/tests/singletest/wasting_time.logpro version [1c532ab9c9].
|
| < < < < < < < < < < < < < < < |
Deleted tests/fullrun/tests/singletest2/main.sh version [54d3e4ef49].
|
| < < < < < < < < < |
Deleted tests/fullrun/tests/singletest2/testconfig version [2527ed7627].
|
| < < < < < < < < < < < < < < |
Deleted tests/fullrun/tests/singletest2/wasting_time.logpro version [1c532ab9c9].
|
| < < < < < < < < < < < < < < < |
Deleted tests/fullrun/tests/special/testconfig version [32232b309f].
|
| < < < < < < < < |
Deleted tests/fullrun/tests/sqlitespeed/runscript.rb version [630bce8730].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted tests/fullrun/tests/sqlitespeed/testconfig version [e539689c49].
|
| < < < < < < < < < < < < < < < |
Deleted tests/fullrun/tests/test_mt_vars/altvarnotset.logpro version [3d9297acb6].
|
| < |
Deleted tests/fullrun/tests/test_mt_vars/altvarnotset.sh version [e1b639c562].
|
| < < < |
Deleted tests/fullrun/tests/test_mt_vars/bogousnotset.logpro version [3d9297acb6].
|
| < |
Deleted tests/fullrun/tests/test_mt_vars/bogousnotset.sh version [25167b86d9].
|
| < < < |
Deleted tests/fullrun/tests/test_mt_vars/currentisblah.logpro version [3d9297acb6].
|
| < |
Deleted tests/fullrun/tests/test_mt_vars/currentisblah.sh version [e891695e2f].
|
| < < < |
Deleted tests/fullrun/tests/test_mt_vars/empty_var.logpro version [3d9297acb6].
|
| < |
Deleted tests/fullrun/tests/test_mt_vars/empty_var.sh version [df128ce23e].
|
| < < < < < < |
Deleted tests/fullrun/tests/test_mt_vars/eval_vars.sh version [786761600e].
|
| < < < < < < < |
Deleted tests/fullrun/tests/test_mt_vars/lookithome.logpro version [3d9297acb6].
|
| < |
Deleted tests/fullrun/tests/test_mt_vars/lookittmp.logpro version [3d9297acb6].
|
| < |
Deleted tests/fullrun/tests/test_mt_vars/test-path-file.sh version [a550b15ff7].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted tests/fullrun/tests/test_mt_vars/test-path.logpro version [3d9297acb6].
|
| < |
Deleted tests/fullrun/tests/test_mt_vars/testconfig version [cd1b423cdc].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted tests/fullrun/tests/test_mt_vars/vackyvar.logpro version [3d9297acb6].
|
| < |
Deleted tests/fullrun/tests/test_mt_vars/vackyvar.sh version [48a1b07c71].
|
| < < < |
Deleted tests/fullrun/tests/test_mt_vars/varwithdollar.logpro version [3d9297acb6].
|
| < |
Deleted tests/fullrun/tests/testxz/testconfig version [b0661b0db5].
|
| < < < < < < < < < < < < < < < |
Deleted tests/fullrun/tests/wait_no_items1/testconfig version [8560a2beaf].
|
| < < < < < < < < < < < < < < < < < |
Deleted tests/fullrun/tests/wait_no_items2/testconfig version [329ea91261].
|
| < < < < < < < < < < < < < < < < < |
Deleted tests/fullrun/tests/wait_no_items3/testconfig version [ac0d16af73].
|
| < < < < < < < < < < < < < < < < < |
Deleted tests/fullrun/tests/wait_no_items4/testconfig version [ea8006f831].
|
| < < < < < < < < < < < < < < < < < |
Deleted tests/installall/config/megatest.config.dat version [736a5da885].
|
| < |
Deleted tests/installall/config/runconfigs.config.dat version [3b8f260acb].
|
| < |
Deleted tests/installall/config/sheet-names.cfg version [ab2c4d6c15].
|
| < < |
Deleted tests/installall/config/sxml/_sheets.sxml version [8edcebe32d].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted tests/installall/config/sxml/_workbook.sxml version [96ffb7f9d5].
|
| < |
Deleted tests/installall/config/sxml/megatest.config.sxml version [20b51cabfc].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted tests/installall/config/sxml/runconfigs.config.sxml version [6fbe8f45dc].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted tests/installall/configs/chicken-4.8.0.4.config version [bef028dfb3].
|
| < |
Deleted tests/installall/configs/chicken-4.8.1.config version [3328179afb].
|
| < |
Deleted tests/installall/megatest.config version [a67193d07e].
|
| < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted tests/installall/runconfigs.config version [7b227fbb06].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted tests/installall/tests/canvas-draw/install.logpro version [da3117435b].
|
| < < < < < < < < |
Deleted tests/installall/tests/canvas-draw/install.sh version [161268d5b1].
|
| < < < < < |
Deleted tests/installall/tests/canvas-draw/testconfig version [2a7615e9f3].
|
| < < < < < < < < < < < < < < < < < < |
Deleted tests/installall/tests/chicken/compile.logpro version [4b1b41a7d0].
|
| < < < < < < < < < < |
Deleted tests/installall/tests/chicken/compile.sh version [272db8604a].
|
| < < < < < < < < |
Deleted tests/installall/tests/chicken/download.logpro version [c8aac76d70].
|
| < < < < < < < < < < < |
Deleted tests/installall/tests/chicken/download.sh version [ba9f4a1774].
|
| < < < < < < < < < < < < < < < < < < < |
Deleted tests/installall/tests/chicken/install.logpro version [2d69c0d10e].
|
| < < < < < < < < < < < |
Deleted tests/installall/tests/chicken/install.sh version [47d124f75d].
|
| < < < < < < < < < < < |
Deleted tests/installall/tests/chicken/testconfig version [7dac45e334].
|
| < < < < < < < < < < < < < < < < < < < < < < |
Deleted tests/installall/tests/eggs/install.logpro version [ce3aad56c4].
|
| < < < < < < < < < |
Deleted tests/installall/tests/eggs/install.sh version [b7bf4a2122].
|
| < < < < < < < < |
Deleted tests/installall/tests/eggs/testconfig version [db11309e75].
|
| < < < < < < < < < < < < < < < < < < < < |
Deleted tests/installall/tests/ffcall/compile.logpro version [dafe0ca4b9].
|
| < < < < < < < < |
Deleted tests/installall/tests/ffcall/compile.sh version [b1f9ee8d88].
|
| < < < < < < < < < |
Deleted tests/installall/tests/ffcall/download.logpro version [a65f247e38].
|
| < < < < < < < < |
Deleted tests/installall/tests/ffcall/download.sh version [4f613a1743].
|
| < < < < < < < < < < < < < |
Deleted tests/installall/tests/ffcall/install.logpro version [dafe0ca4b9].
|
| < < < < < < < < |
Deleted tests/installall/tests/ffcall/install.sh version [c40130a331].
|
| < < < < < < < < |
Deleted tests/installall/tests/ffcall/testconfig version [042dbec27d].
|
| < < < < < < < < < < < < < < < < < < < < |
Deleted tests/installall/tests/iup/install.logpro version [c5d9baa323].
|
| < < < < < < < < < |
Deleted tests/installall/tests/iup/install.sh version [57d94ee07e].
|
| < < < < < < < < < < < < |
Deleted tests/installall/tests/iup/testconfig version [5db24fdb23].
|
| < < < < < < < < < < < < < < < < < < |
Deleted tests/installall/tests/iupbinlib/compile.logpro version [da3117435b].
|
| < < < < < < < < |
Deleted tests/installall/tests/iupbinlib/compile.sh version [161268d5b1].
|
| < < < < < |
Deleted tests/installall/tests/iupbinlib/download.logpro version [5b3da735d6].
|
| < < < < < < < < |
Deleted tests/installall/tests/iupbinlib/download.sh version [f2ee3d4aa3].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted tests/installall/tests/iupbinlib/install.logpro version [da3117435b].
|
| < < < < < < < < |
Deleted tests/installall/tests/iupbinlib/install.sh version [f8d37254ad].
|
| < < < < |
Deleted tests/installall/tests/iupbinlib/testconfig version [f1c92a67e2].
|
| < < < < < < < < < < < < < < < < < < |
Deleted tests/installall/tests/iupbinlib/untar.logpro version [da3117435b].
|
| < < < < < < < < |
Deleted tests/installall/tests/iupbinlib/untar.sh version [f8d37254ad].
|
| < < < < |
Deleted tests/installall/tests/iupsrclib/cd.logpro version [de3fb33d93].
|
| < < < |
Deleted tests/installall/tests/iupsrclib/compile.logpro version [b41da09609].
|
| < < < < < < < < < < < < |
Deleted tests/installall/tests/iupsrclib/compile.sh version [f015809a0b].
|
| < < < < < < < < < < < < < < < < < |
Deleted tests/installall/tests/iupsrclib/download.logpro version [df3583cb3b].
|
| < < < < < < < < < < < < < |
Deleted tests/installall/tests/iupsrclib/download.sh version [ad6ad0c176].
|
| < < < < < < < < < < < < < < |
Deleted tests/installall/tests/iupsrclib/im.logpro version [5f1496c62a].
|
| < |
Deleted tests/installall/tests/iupsrclib/install.logpro version [da3117435b].
|
| < < < < < < < < |
Deleted tests/installall/tests/iupsrclib/install.sh version [f3584b2f09].
|
| < < < < < < < < < < < < < < < < < < < < < < |
Deleted tests/installall/tests/iupsrclib/iup.logpro version [d60fae9ebf].
|
| < < < |
Deleted tests/installall/tests/iupsrclib/lua.logpro version [5f1496c62a].
|
| < |
Deleted tests/installall/tests/iupsrclib/testconfig version [1d7cd86274].
|
| < < < < < < < < < < < < < < < < < < < < < < |
Deleted tests/installall/tests/iupsrclib/untar.logpro version [da3117435b].
|
| < < < < < < < < |
Deleted tests/installall/tests/iupsrclib/untar.sh version [f8d37254ad].
|
| < < < < |
Deleted tests/installall/tests/mmisc/clone.logpro version [c92957c5fd].
|
| < < < < < < < < |
Deleted tests/installall/tests/mmisc/clone.sh version [a61e06ec47].
|
| < < < < < < < < < < < |
Deleted tests/installall/tests/mmisc/install.logpro version [1f5310e869].
|
| < < < < < < < < < |
Deleted tests/installall/tests/mmisc/install.sh version [6fa1a37e4b].
|
| < < < < < < < < < < < < < < < < |
Deleted tests/installall/tests/mmisc/testconfig version [e2a1711886].
|
| < < < < < < < < < < < < < < < < < < < < < |
Deleted tests/installall/tests/opensrc/clone.logpro version [c7d0c07345].
|
| < < < < < < < < |
Deleted tests/installall/tests/opensrc/clone.sh version [3a6c7e5a01].
|
| < < < < < < < < < < < < < < < < < < < < < < |
Deleted tests/installall/tests/opensrc/install.logpro version [78dae7a202].
|
| < < < < < < < < < |
Deleted tests/installall/tests/opensrc/install.sh version [0a2e83707c].
|
| < < < < < < |
Deleted tests/installall/tests/opensrc/testconfig version [f020005b2c].
|
| < < < < < < < < < < < < < < < < < < < < |
Deleted tests/installall/tests/setup/setup.logpro version [ce8667656b].
|
| < < < < < < < < < < |
Deleted tests/installall/tests/setup/setup.sh version [70b95f9196].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted tests/installall/tests/setup/testconfig version [27705aefdb].
|
| < < < < < < < < < < < < < < < < < < |
Deleted tests/installall/tests/sqlite3/compile.logpro version [1d01bbbbd5].
|
| < < < < < < < < < |
Deleted tests/installall/tests/sqlite3/compile.sh version [e12d00dc21].
|
| < < < < < < < < < < |
Deleted tests/installall/tests/sqlite3/download.logpro version [39413dc315].
|
| < < < < < < < < |
Deleted tests/installall/tests/sqlite3/download.sh version [f2f624d46c].
|
| < < < < < < < < < < < < < < |
Deleted tests/installall/tests/sqlite3/install.logpro version [dafe0ca4b9].
|
| < < < < < < < < |
Deleted tests/installall/tests/sqlite3/install.sh version [c5cbfd9758].
|
| < < < < < < < < < |
Deleted tests/installall/tests/sqlite3/installegg.logpro version [739280ede6].
|
| < < < < < < < < < |
Deleted tests/installall/tests/sqlite3/installegg.sh version [c022c1b5fd].
|
| < < < < < < < |
Deleted tests/installall/tests/sqlite3/testconfig version [a8be7a5282].
|
| < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted tests/installall/tests/tougheggs/install.logpro version [ce3aad56c4].
|
| < < < < < < < < < |
Deleted tests/installall/tests/tougheggs/install.sh version [7f9ea04779].
|
| < < < < < < < < < |
Deleted tests/installall/tests/tougheggs/testconfig version [e1e673d39f].
|
| < < < < < < < < < < < < < < < < < < < |
Deleted tests/installall/tests/zmq/install.logpro version [da3117435b].
|
| < < < < < < < < |
Deleted tests/installall/tests/zmq/install.sh version [f8d37254ad].
|
| < < < < |
Deleted tests/installall/tests/zmq/testconfig version [61b477c9b8].
|
| < < < < < < < < < < < < < < < < < < |
Deleted tests/installall/tests/zmqlib/compile.logpro version [da3117435b].
|
| < < < < < < < < |
Deleted tests/installall/tests/zmqlib/compile.sh version [f8d37254ad].
|
| < < < < |
Deleted tests/installall/tests/zmqlib/download.logpro version [da3117435b].
|
| < < < < < < < < |
Deleted tests/installall/tests/zmqlib/download.sh version [f8d37254ad].
|
| < < < < |
Deleted tests/installall/tests/zmqlib/install.logpro version [da3117435b].
|
| < < < < < < < < |
Deleted tests/installall/tests/zmqlib/install.sh version [161268d5b1].
|
| < < < < < |
Deleted tests/installall/tests/zmqlib/testconfig version [fcfbb2efb3].
|
| < < < < < < < < < < < < < < < < < < < < < |
Deleted tests/installall/tests/zmqlib/untar.logpro version [da3117435b].
|
| < < < < < < < < |
Deleted tests/installall/tests/zmqlib/untar.sh version [f8d37254ad].
|
| < < < < |
Modified tests/manual.sh from [e3ceda48a0] to [ef26951c46].
1 | (cd ..;make install) && `realpath ../bin/megatest` -runtests manual_example :sysname ubuntu :fsname afs :datapath none :runname testing -setvars TARGETDISPLAY=:0,TARGETHOST=localhost,TARGETDIR=/tmp/blah,TARGETUSER=matt | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. (cd ..;make install) && `realpath ../bin/megatest` -runtests manual_example :sysname ubuntu :fsname afs :datapath none :runname testing -setvars TARGETDISPLAY=:0,TARGETHOST=localhost,TARGETDIR=/tmp/blah,TARGETUSER=matt |
Modified tests/mintest/megatest.config from [74b434d2c6] to [bfa94e44af].
1 2 3 4 5 6 7 | [fields] X TEXT [setup] max_concurrent_jobs 50 linktree #{getenv MT_RUN_AREA_HOME}/linktree transport http | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. [fields] X TEXT [setup] max_concurrent_jobs 50 linktree #{getenv MT_RUN_AREA_HOME}/linktree transport http |
︙ | ︙ |
Modified tests/mintest/runconfigs.config from [40b4b21352] to [65063ec46e].
1 2 3 4 5 6 | [default] ALLTESTS see this variable # Your variables here are grouped by targets [SYSTEM/RELEASE] [a] ANOTHERVAR only defined if target is "a" | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. [default] ALLTESTS see this variable # Your variables here are grouped by targets [SYSTEM/RELEASE] [a] ANOTHERVAR only defined if target is "a" |
Modified tests/mintest/tests/a/testconfig from [facb7c910d] to [7f9803b9fe].
1 2 3 4 5 6 | # Add steps here. Format is "stepname script" [ezsteps] step1 echo SUCCESS [requirements] waiton b | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. # Add steps here. Format is "stepname script" [ezsteps] step1 echo SUCCESS [requirements] waiton b |
Modified tests/mintest/tests/a1/testconfig from [9ca81e5ed7] to [9b27e8d12f].
1 2 3 4 5 6 | # Add steps here. Format is "stepname script" [ezsteps] step1 echo SUCCESS [requirements] waiton b1 | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. # Add steps here. Format is "stepname script" [ezsteps] step1 echo SUCCESS [requirements] waiton b1 |
Modified tests/mintest/tests/b/testconfig from [6534ef153f] to [ff99d23b03].
1 2 3 4 5 6 | # Add steps here. Format is "stepname script" [ezsteps] step1 echo SUCCESS [requirements] waiton c | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. # Add steps here. Format is "stepname script" [ezsteps] step1 echo SUCCESS [requirements] waiton c |
Modified tests/mintest/tests/b1/testconfig from [4b7d232216] to [53af536646].
1 2 3 4 5 6 | # Add steps here. Format is "stepname script" [ezsteps] step1 echo SUCCESS [requirements] waiton c1 | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. # Add steps here. Format is "stepname script" [ezsteps] step1 echo SUCCESS [requirements] waiton c1 |
Modified tests/mintest/tests/c/testconfig from [edfeef7824] to [2597af7971].
1 2 3 4 5 6 | # Add steps here. Format is "stepname script" [ezsteps] step1 echo SUCCESS [requirements] waiton d | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. # Add steps here. Format is "stepname script" [ezsteps] step1 echo SUCCESS [requirements] waiton d |
Modified tests/mintest/tests/c1/testconfig from [7cc87abb7f] to [044a1dedf3].
1 2 3 4 5 6 | # Add steps here. Format is "stepname script" [ezsteps] step1 echo SUCCESS [requirements] waiton d1fail | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. # Add steps here. Format is "stepname script" [ezsteps] step1 echo SUCCESS [requirements] waiton d1fail |
Modified tests/mintest/tests/d/testconfig from [7572bd1520] to [ecbd4a6752].
1 2 3 4 5 6 | # Add steps here. Format is "stepname script" [ezsteps] step1 echo SUCCESS [requirements] waiton e | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. # Add steps here. Format is "stepname script" [ezsteps] step1 echo SUCCESS [requirements] waiton e |
Modified tests/mintest/tests/d1fail/testconfig from [896a37e3bb] to [501505a8e3].
1 2 3 4 5 6 7 | # Add steps here. Format is "stepname script" [ezsteps] step1 echo SUCCESS step2 exit 123 [requirements] waiton e1 | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. # Add steps here. Format is "stepname script" [ezsteps] step1 echo SUCCESS step2 exit 123 [requirements] waiton e1 |
Modified tests/mintest/tests/e/testconfig from [8e71a3916a] to [6f374d7742].
1 2 3 4 | # Add steps here. Format is "stepname script" [ezsteps] step1 echo SUCCESS | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. # Add steps here. Format is "stepname script" [ezsteps] step1 echo SUCCESS |
Modified tests/mintest/tests/e1/testconfig from [8e71a3916a] to [6f374d7742].
1 2 3 4 | # Add steps here. Format is "stepname script" [ezsteps] step1 echo SUCCESS | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. # Add steps here. Format is "stepname script" [ezsteps] step1 echo SUCCESS |
Modified tests/mintest/tests/f/testconfig from [8af865d5b6] to [cec92de58d].
1 2 3 4 5 6 | # Add steps here. Format is "stepname script" [ezsteps] step1 echo SUCCESS [requirements] waiton | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. # Add steps here. Format is "stepname script" [ezsteps] step1 echo SUCCESS [requirements] waiton |
Modified tests/mintest/tests/g/testconfig from [1fecef7a7b] to [f6fe1d7a40].
1 2 3 4 5 6 7 | # Add steps here. Format is "stepname script" [ezsteps] step1 echo SUCCESS [requirements] waiton b | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. # Add steps here. Format is "stepname script" [ezsteps] step1 echo SUCCESS [requirements] waiton b |
︙ | ︙ |
Modified tests/mintest/tests/h/testconfig from [facb7c910d] to [7f9803b9fe].
1 2 3 4 5 6 | # Add steps here. Format is "stepname script" [ezsteps] step1 echo SUCCESS [requirements] waiton b | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. # Add steps here. Format is "stepname script" [ezsteps] step1 echo SUCCESS [requirements] waiton b |
Modified tests/mintest/tests/i/testconfig from [facb7c910d] to [7f9803b9fe].
1 2 3 4 5 6 | # Add steps here. Format is "stepname script" [ezsteps] step1 echo SUCCESS [requirements] waiton b | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. # Add steps here. Format is "stepname script" [ezsteps] step1 echo SUCCESS [requirements] waiton b |
Modified tests/mintest/tests/j/testconfig from [facb7c910d] to [7f9803b9fe].
1 2 3 4 5 6 | # Add steps here. Format is "stepname script" [ezsteps] step1 echo SUCCESS [requirements] waiton b | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. # Add steps here. Format is "stepname script" [ezsteps] step1 echo SUCCESS [requirements] waiton b |
Modified tests/mintest/tests/k/testconfig from [facb7c910d] to [7f9803b9fe].
1 2 3 4 5 6 | # Add steps here. Format is "stepname script" [ezsteps] step1 echo SUCCESS [requirements] waiton b | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. # Add steps here. Format is "stepname script" [ezsteps] step1 echo SUCCESS [requirements] waiton b |
Modified tests/mintest/tests/l/testconfig from [facb7c910d] to [7f9803b9fe].
1 2 3 4 5 6 | # Add steps here. Format is "stepname script" [ezsteps] step1 echo SUCCESS [requirements] waiton b | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. # Add steps here. Format is "stepname script" [ezsteps] step1 echo SUCCESS [requirements] waiton b |
Modified tests/ods-test.scm from [08da0f4575] to [f68e94146b].
1 2 3 4 5 6 7 | (load "ods.scm") (ods:list->ods "testing" "testing.ods" '((Sheet1 ("Row 1,A" "Row 1,B") ("Row 2,A" "Row 2,B")) | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | ;; Copyright 2006-2017, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. (load "ods.scm") (ods:list->ods "testing" "testing.ods" '((Sheet1 ("Row 1,A" "Row 1,B") ("Row 2,A" "Row 2,B")) |
︙ | ︙ |
Modified tests/release/Makefile from [0d13fa9945] to [e28fe0e602].
|
| > | > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. dashboard : compile dashboard -rows 24 & compile : runs cd ../..;make -j install |
︙ | ︙ |
Modified tests/release/megatest.config from [0bf84b11be] to [c6158602fc].
1 2 3 4 5 6 7 | [fields] release TEXT iteration TEXT [setup] linktree #{getenv MT_RUN_AREA_HOME}/links max_concurrent_jobs 100 | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. [fields] release TEXT iteration TEXT [setup] linktree #{getenv MT_RUN_AREA_HOME}/links max_concurrent_jobs 100 |
︙ | ︙ |
Modified tests/release/runconfigs.config from [45021e9fc7] to [c80019f31a].
1 2 3 4 5 6 7 | [default] MTRUNNER #{shell readlink -f #{getenv MT_RUN_AREA_HOME}/../../utils/mtrunner} MTTESTDIR #{shell readlink -f #{getenv MT_RUN_AREA_HOME}/..} MTPATH #{shell readlink -f #{getenv MT_RUN_AREA_HOME}/../../bin} [v1.60/15] | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. [default] MTRUNNER #{shell readlink -f #{getenv MT_RUN_AREA_HOME}/../../utils/mtrunner} MTTESTDIR #{shell readlink -f #{getenv MT_RUN_AREA_HOME}/..} MTPATH #{shell readlink -f #{getenv MT_RUN_AREA_HOME}/../../bin} [v1.60/15] |
︙ | ︙ |
Modified tests/release/tests/dependencies/simpleresults.logpro from [cdf9db5b94] to [10433d6999].
1 2 | ;; (c) 2006,2007,2008,2009 Matthew Welland matt@kiatoa.com ;; | > > > > > > > > > > > > > > > > | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | ;; (c) 2006,2007,2008,2009 Matthew Welland matt@kiatoa.com ;; ;; Copyright 2006-2017, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. (define logbody "LogFileBody") (define pass-specs '( ;; testname num-expected max-runtime ("setup" 1 20) ("test1/layout/ptran" 1 20) ("test1/schematic/ptran" 1 20) |
︙ | ︙ |
Modified tests/release/tests/dependencies/testconfig from [0654f78c14] to [5568843566].
1 2 3 4 5 6 7 | # test2 from the tests/Makefile [var] tname itemwait [ezsteps] | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. # test2 from the tests/Makefile [var] tname itemwait [ezsteps] |
︙ | ︙ |
Modified tests/release/tests/fullrun/results.logpro from [7bd9c74d1a] to [2bceb45ec2].
1 2 | ;; (c) 2006,2007,2008,2009 Matthew Welland matt@kiatoa.com ;; | > > > > > > > > > > > > > > > > | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | ;; (c) 2006,2007,2008,2009 Matthew Welland matt@kiatoa.com ;; ;; Copyright 2006-2017, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. (define logbody "LogFileBody") (define pass-specs '( ;; testname num-expected max-runtime ("exit_0" 1 20) ("ezlog_fail_then_pass" 1 20) ("ezlog_pass" 1 20) |
︙ | ︙ |
Modified tests/release/tests/fullrun/testconfig from [be4bd3c0d9] to [f11cba09ca].
1 2 3 4 5 6 7 | [ezsteps] cleantop $MTRUNNER $MTTESTDIR/fullrun $MTPATH megatest -remove-runs -target ubuntu/nfs/none -runname release_toplevel -testpatt % runall $MTRUNNER $MTTESTDIR/fullrun $MTPATH megatest -run -testpatt % -target ubuntu/nfs/none -runname release_toplevel -runwait runtop $MTRUNNER $MTTESTDIR/fullrun $MTPATH megatest -run -testpatt all_toplevel -target ubuntu/nfs/none -runname release_toplevel -rerun FAIL -preclean -runwait results $MTRUNNER $MTTESTDIR/fullrun $MTPATH megatest -list-runs release_toplevel -target ubuntu/nfs/none -runname release_toplevel [requirements] | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. [ezsteps] cleantop $MTRUNNER $MTTESTDIR/fullrun $MTPATH megatest -remove-runs -target ubuntu/nfs/none -runname release_toplevel -testpatt % runall $MTRUNNER $MTTESTDIR/fullrun $MTPATH megatest -run -testpatt % -target ubuntu/nfs/none -runname release_toplevel -runwait runtop $MTRUNNER $MTTESTDIR/fullrun $MTPATH megatest -run -testpatt all_toplevel -target ubuntu/nfs/none -runname release_toplevel -rerun FAIL -preclean -runwait results $MTRUNNER $MTTESTDIR/fullrun $MTPATH megatest -list-runs release_toplevel -target ubuntu/nfs/none -runname release_toplevel [requirements] |
︙ | ︙ |
Modified tests/release/tests/itemwait/testconfig from [c976040a3b] to [8c53dc00df].
1 2 3 4 5 6 7 | # test2 from the tests/Makefile [var] tname itemwait [pre-launch-env-vars] NUMTESTS 20 | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. # test2 from the tests/Makefile [var] tname itemwait [pre-launch-env-vars] NUMTESTS 20 |
︙ | ︙ |
Modified tests/release/tests/itemwait/watchrun.sh from [3cd7d57805] to [ecbe7ec9af].
1 2 3 4 5 6 7 8 9 | #!/bin/bash runname=$1 pass=no alldone=no while [[ $alldone == no ]];do sleep 5 $MTRUNNER $MTTESTDIR/fdktestqa/testqa $MTPATH megatest -list-runs $runname > list-runs.log | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | #!/bin/bash # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. runname=$1 pass=no alldone=no while [[ $alldone == no ]];do sleep 5 $MTRUNNER $MTTESTDIR/fdktestqa/testqa $MTPATH megatest -list-runs $runname > list-runs.log |
︙ | ︙ |
Modified tests/release/tests/rollup/firstres.logpro from [aa9c55c1c8] to [9ce53a76ff].
1 2 | ;; (c) 2006,2007,2008,2009 Matthew Welland matt@kiatoa.com ;; | > > > > > > > > > > > > | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | ;; (c) 2006,2007,2008,2009 Matthew Welland matt@kiatoa.com ;; ;; Copyright 2006-2017, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. (define logbody "LogFileBody") (define pass-specs '( ;; testname num-expected max-runtime ;; ("exit_0" 1 20) ;; ("ezlog_fail_then_pass" 1 20) ;; ("ezlog_pass" 1 20) |
︙ | ︙ |
Modified tests/release/tests/rollup/results.logpro from [ed47d73b48] to [bf04c0af0d].
1 2 | ;; (c) 2006,2007,2008,2009 Matthew Welland matt@kiatoa.com ;; | > > > > > > > > > > > > | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | ;; (c) 2006,2007,2008,2009 Matthew Welland matt@kiatoa.com ;; ;; Copyright 2006-2017, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. (define logbody "LogFileBody") (define pass-specs '( ;; testname num-expected max-runtime ;; ("exit_0" 1 20) ;; ("ezlog_fail_then_pass" 1 20) ;; ("ezlog_pass" 1 20) |
︙ | ︙ |
Modified tests/release/tests/rollup/testconfig from [3a08af0f00] to [a13b971060].
1 2 3 4 5 6 7 | # test2 from the tests/Makefile [var] tname rollup [ezsteps] | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. # test2 from the tests/Makefile [var] tname rollup [ezsteps] |
︙ | ︙ |
Modified tests/release/tests/test2/results.logpro from [0604885ee3] to [650b30db37].
1 2 | ;; (c) 2006,2007,2008,2009 Matthew Welland matt@kiatoa.com ;; | > > > > > > > > > > > > | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | ;; (c) 2006,2007,2008,2009 Matthew Welland matt@kiatoa.com ;; ;; Copyright 2006-2017, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. (define logbody "LogFileBody") (define pass-specs '( ;; testname num-expected max-runtime ;; ("exit_0" 1 20) ;; ("ezlog_fail_then_pass" 1 20) ;; ("ezlog_pass" 1 20) |
︙ | ︙ |
Modified tests/release/tests/test2/results_a.logpro from [0604885ee3] to [3218ee6258].
1 2 | ;; (c) 2006,2007,2008,2009 Matthew Welland matt@kiatoa.com ;; | > > > > > > > > > > > > > > > > | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | ;; (c) 2006,2007,2008,2009 Matthew Welland matt@kiatoa.com ;; ;; Copyright 2006-2017, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. (define logbody "LogFileBody") (define pass-specs '( ;; testname num-expected max-runtime ;; ("exit_0" 1 20) ;; ("ezlog_fail_then_pass" 1 20) ;; ("ezlog_pass" 1 20) |
︙ | ︙ |
Modified tests/release/tests/test2/results_b.logpro from [0604885ee3] to [650b30db37].
1 2 | ;; (c) 2006,2007,2008,2009 Matthew Welland matt@kiatoa.com ;; | > > > > > > > > > > > > | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | ;; (c) 2006,2007,2008,2009 Matthew Welland matt@kiatoa.com ;; ;; Copyright 2006-2017, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. (define logbody "LogFileBody") (define pass-specs '( ;; testname num-expected max-runtime ;; ("exit_0" 1 20) ;; ("ezlog_fail_then_pass" 1 20) ;; ("ezlog_pass" 1 20) |
︙ | ︙ |
Modified tests/release/tests/test2/testconfig from [94d7901019] to [a8933c23f2].
1 2 3 4 5 6 7 | # test2 from the tests/Makefile [var] tname test2 mtpath #{shell readlink -f ../../bin} [ezsteps] | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. # test2 from the tests/Makefile [var] tname test2 mtpath #{shell readlink -f ../../bin} [ezsteps] |
︙ | ︙ |
Modified tests/release/tests/testpatt/cleanres.logpro from [8613c2bd62] to [0587880d95].
1 2 | ;; (c) 2006,2007,2008,2009 Matthew Welland matt@kiatoa.com ;; | > > > > > > > > > > > > | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | ;; (c) 2006,2007,2008,2009 Matthew Welland matt@kiatoa.com ;; ;; Copyright 2006-2017, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. (define logbody "LogFileBody") (define pass-specs '( ;; testname num-expected max-runtime ;; ("exit_0" 1 20) ;; ("ezlog_fail_then_pass" 1 20) ;; ("ezlog_pass" 1 20) |
︙ | ︙ |
Modified tests/release/tests/testpatt/results.logpro from [0604885ee3] to [3218ee6258].
1 2 | ;; (c) 2006,2007,2008,2009 Matthew Welland matt@kiatoa.com ;; | > > > > > > > > > > > > > > > > | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | ;; (c) 2006,2007,2008,2009 Matthew Welland matt@kiatoa.com ;; ;; Copyright 2006-2017, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. (define logbody "LogFileBody") (define pass-specs '( ;; testname num-expected max-runtime ;; ("exit_0" 1 20) ;; ("ezlog_fail_then_pass" 1 20) ;; ("ezlog_pass" 1 20) |
︙ | ︙ |
Modified tests/release/tests/testpatt/testconfig from [ddc5455f74] to [7c37f4c0bf].
1 2 3 4 5 6 7 | [ezsteps] clean $MTRUNNER $MTTESTDIR/fullrun $MTPATH megatest -remove-runs -testpatt % -target ubuntu/nfs/none -runname release_testpatt cleanres $MTRUNNER $MTTESTDIR/fullrun $MTPATH megatest -list-runs release_testpatt -target ubuntu/nfs/none runitems $MTRUNNER $MTTESTDIR/fullrun $MTPATH megatest -run -testpatt runfirst/%2 -target ubuntu/nfs/none -runname release_testpatt results $MTRUNNER $MTTESTDIR/fullrun $MTPATH megatest -list-runs release_testpatt -target ubuntu/nfs/none | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. [ezsteps] clean $MTRUNNER $MTTESTDIR/fullrun $MTPATH megatest -remove-runs -testpatt % -target ubuntu/nfs/none -runname release_testpatt cleanres $MTRUNNER $MTTESTDIR/fullrun $MTPATH megatest -list-runs release_testpatt -target ubuntu/nfs/none runitems $MTRUNNER $MTTESTDIR/fullrun $MTPATH megatest -run -testpatt runfirst/%2 -target ubuntu/nfs/none -runname release_testpatt results $MTRUNNER $MTTESTDIR/fullrun $MTPATH megatest -list-runs release_testpatt -target ubuntu/nfs/none |
︙ | ︙ |
Modified tests/release/tests/testpatt_envvar/results.logpro from [71808ef31b] to [93e40d6742].
1 2 | ;; (c) 2006,2007,2008,2009 Matthew Welland matt@kiatoa.com ;; | > > > > > > > > > > > > > > > > | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | ;; (c) 2006,2007,2008,2009 Matthew Welland matt@kiatoa.com ;; ;; Copyright 2006-2017, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. (define logbody "LogFileBody") (define pass-specs '( ;; testname num-expected max-runtime ("exit_0" 1 20) ("ezlog_fail_then_pass" 1 20) ("ezlog_pass" 1 20) |
︙ | ︙ |
Modified tests/release/tests/testpatt_envvar/testconfig from [ee5022af6d] to [6e650aba26].
1 2 3 4 5 6 7 | [var] targ -target ubuntu/nfs/all_toplevel tp -testpatt % [ezsteps] cleantop $MTRUNNER $MTTESTDIR/fullrun $MTPATH megatest -remove-runs #{get var tp} #{get var targ} -runname release_toplevel runall $MTRUNNER $MTTESTDIR/fullrun $MTPATH megatest -run #{get var tp} #{get var targ} -runname release_toplevel -runwait | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. [var] targ -target ubuntu/nfs/all_toplevel tp -testpatt % [ezsteps] cleantop $MTRUNNER $MTTESTDIR/fullrun $MTPATH megatest -remove-runs #{get var tp} #{get var targ} -runname release_toplevel runall $MTRUNNER $MTTESTDIR/fullrun $MTPATH megatest -run #{get var tp} #{get var targ} -runname release_toplevel -runwait |
︙ | ︙ |
Modified tests/release/tests/toprun/results.logpro from [7bd9c74d1a] to [2bceb45ec2].
1 2 | ;; (c) 2006,2007,2008,2009 Matthew Welland matt@kiatoa.com ;; | > > > > > > > > > > > > > > > > | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | ;; (c) 2006,2007,2008,2009 Matthew Welland matt@kiatoa.com ;; ;; Copyright 2006-2017, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. (define logbody "LogFileBody") (define pass-specs '( ;; testname num-expected max-runtime ("exit_0" 1 20) ("ezlog_fail_then_pass" 1 20) ("ezlog_pass" 1 20) |
︙ | ︙ |
Modified tests/release/tests/toprun/testconfig from [e70d05999a] to [667806e54d].
1 2 3 4 5 6 7 | [misc] rname release_toprun rdir $MTTESTDIR/fullrun [ezsteps] cleantop $MTRUNNER #{get misc rdir} $MTPATH megatest -remove-runs -testpatt % -target ubuntu/nfs/none -runname #{get misc rname} -testpatt % runall $MTRUNNER #{get misc rdir} $MTPATH megatest -run -testpatt % -target ubuntu/nfs/none -runname #{get misc rname} -runwait | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. [misc] rname release_toprun rdir $MTTESTDIR/fullrun [ezsteps] cleantop $MTRUNNER #{get misc rdir} $MTPATH megatest -remove-runs -testpatt % -target ubuntu/nfs/none -runname #{get misc rname} -testpatt % runall $MTRUNNER #{get misc rdir} $MTPATH megatest -run -testpatt % -target ubuntu/nfs/none -runname #{get misc rname} -runwait |
︙ | ︙ |
Modified tests/resources/ruby/librunscript.rb from [a529a5a104] to [fecc66e6e2].
1 2 3 4 5 6 7 8 9 | # This is the library of stuff for megatest def run_and_record(stepname, cmd, checks) system "megatest -step #{stepname} :state start :status n/a" system cmd exitcode=$? if exitcode==0 exitcode='pass' else | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | # This is the library of stuff for megatest # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. def run_and_record(stepname, cmd, checks) system "megatest -step #{stepname} :state start :status n/a" system cmd exitcode=$? if exitcode==0 exitcode='pass' else |
︙ | ︙ |
Modified tests/rununittest.sh from [3301b831f3] to [1c340ef384].
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | #!/bin/bash # Usage: rununittest.sh testname debuglevel # banner $1 # put megatest on path from correct location mtbindir=$(readlink -f ../bin) export PATH="${mtbindir}:$PATH" # Clean setup # dbdir=$(echo /tmp/$USER/megatest_localdb/simplerun/.[a-zA-Z]*/) echo "dbdir=$dbdir" | > > > > > > > > > > > > > > > > > | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | #!/bin/bash # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. # Usage: rununittest.sh testname debuglevel # banner $1 # put megatest on path from correct location mtbindir=$(readlink -f ../bin) export PATH="${mtbindir}:$PATH" # Clean setup # dbdir=$(echo /tmp/$USER/megatest_localdb/simplerun/.[a-zA-Z]*/) echo "dbdir=$dbdir" rm -f simplerun/megatest.db simplerun/monitor.db simplerun/db/monitor.db rm -rf simplelinks/ simpleruns/ simplerun/db/ $dbdir mkdir -p simplelinks simpleruns (cd simplerun;cp ../../*_records.scm .;perl -pi.bak -e 's/define-inline/define/' *_records.scm) (cd simplerun;cp ../../altdb.scm .) # Run the test $1 is the unit test to run cd simplerun;echo '(load "../tests.scm")' | ../../bin/megatest -repl -debug $2 $1 |
Modified tests/simplerun/megatest.config from [4850198caf] to [373cc8c0cf].
1 2 3 4 5 6 7 | [fields] SYSTEM TEXT RELEASE TEXT [setup] # Adjust max_concurrent_jobs to limit how much you load your machines max_concurrent_jobs 50 | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. [fields] SYSTEM TEXT RELEASE TEXT [setup] # Adjust max_concurrent_jobs to limit how much you load your machines max_concurrent_jobs 50 |
︙ | ︙ |
Modified tests/simplerun/runconfigs.config from [346ed47154] to [cd9421e89b].
1 2 3 4 5 6 | [default] ALLTESTS see this variable # Your variables here are grouped by targets [SYSTEM/RELEASE] [SYSTEM_val/RELEASE_val] ANOTHERVAR only defined if target is SYSTEM_val/RELEASE_val | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. [default] ALLTESTS see this variable # Your variables here are grouped by targets [SYSTEM/RELEASE] [SYSTEM_val/RELEASE_val] ANOTHERVAR only defined if target is SYSTEM_val/RELEASE_val |
Modified tests/simplerun/test.config from [5ec648d029] to [5d045ee29c].
1 2 3 4 5 6 7 | [section1] 1 ./blah [section2] # A comment | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. [section1] 1 ./blah [section2] # A comment |
︙ | ︙ |
Modified tests/simplerun/tests/test1/step1.logpro from [3a7d1def42] to [b272b25505].
1 2 3 4 5 6 7 | ;; You should have at least one expect:required. This ensures that your process ran ;; (expect:required in "LogFileBody" > 0 "Put description here" #/put pattern here/) ;; You may need ignores to suppress false error or warning hits from the later expects ;; NOTE: Order is important here! (expect:ignore in "LogFileBody" < 99 "Ignore the word error in comments" #/^\/\/.*error/) (expect:warning in "LogFileBody" = 0 "Any warning" #/warn/) | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | ;; Copyright 2006-2017, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. ;; You should have at least one expect:required. This ensures that your process ran ;; (expect:required in "LogFileBody" > 0 "Put description here" #/put pattern here/) ;; You may need ignores to suppress false error or warning hits from the later expects ;; NOTE: Order is important here! (expect:ignore in "LogFileBody" < 99 "Ignore the word error in comments" #/^\/\/.*error/) (expect:warning in "LogFileBody" = 0 "Any warning" #/warn/) |
︙ | ︙ |
Modified tests/simplerun/tests/test1/step1.sh from [c71fbc7484] to [b36e5b3e1b].
1 2 3 4 5 | #!/usr/bin/env bash # Run your step here echo Got here! | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | #!/usr/bin/env bash # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. # Run your step here echo Got here! |
Modified tests/simplerun/tests/test1/step2.logpro from [3a7d1def42] to [b272b25505].
1 2 3 4 5 6 7 | ;; You should have at least one expect:required. This ensures that your process ran ;; (expect:required in "LogFileBody" > 0 "Put description here" #/put pattern here/) ;; You may need ignores to suppress false error or warning hits from the later expects ;; NOTE: Order is important here! (expect:ignore in "LogFileBody" < 99 "Ignore the word error in comments" #/^\/\/.*error/) (expect:warning in "LogFileBody" = 0 "Any warning" #/warn/) | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | ;; Copyright 2006-2017, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. ;; You should have at least one expect:required. This ensures that your process ran ;; (expect:required in "LogFileBody" > 0 "Put description here" #/put pattern here/) ;; You may need ignores to suppress false error or warning hits from the later expects ;; NOTE: Order is important here! (expect:ignore in "LogFileBody" < 99 "Ignore the word error in comments" #/^\/\/.*error/) (expect:warning in "LogFileBody" = 0 "Any warning" #/warn/) |
︙ | ︙ |
Modified tests/simplerun/tests/test1/step2.sh from [97ecbea6c6] to [8cc537c8e5].
1 2 3 4 5 6 | #!/usr/bin/env bash # Run your step here echo Got here eh! | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | #!/usr/bin/env bash # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. # Run your step here echo Got here eh! |
Modified tests/simplerun/tests/test1/testconfig from [57935abc84] to [db2c27ffef].
1 2 3 4 5 6 7 | # Add additional steps here. Format is "stepname script" [ezsteps] step1 step1.sh step2 step2.sh # Test requirements are specified here [requirements] | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. # Add additional steps here. Format is "stepname script" [ezsteps] step1 step1.sh step2 step2.sh # Test requirements are specified here [requirements] |
︙ | ︙ |
Modified tests/simplerun/tests/test2/step1.logpro from [3a7d1def42] to [b272b25505].
1 2 3 4 5 6 7 | ;; You should have at least one expect:required. This ensures that your process ran ;; (expect:required in "LogFileBody" > 0 "Put description here" #/put pattern here/) ;; You may need ignores to suppress false error or warning hits from the later expects ;; NOTE: Order is important here! (expect:ignore in "LogFileBody" < 99 "Ignore the word error in comments" #/^\/\/.*error/) (expect:warning in "LogFileBody" = 0 "Any warning" #/warn/) | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | ;; Copyright 2006-2017, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. ;; You should have at least one expect:required. This ensures that your process ran ;; (expect:required in "LogFileBody" > 0 "Put description here" #/put pattern here/) ;; You may need ignores to suppress false error or warning hits from the later expects ;; NOTE: Order is important here! (expect:ignore in "LogFileBody" < 99 "Ignore the word error in comments" #/^\/\/.*error/) (expect:warning in "LogFileBody" = 0 "Any warning" #/warn/) |
︙ | ︙ |
Modified tests/simplerun/tests/test2/step1.sh from [67f9a133dc] to [de871e9b2f].
1 2 3 | #!/usr/bin/env bash # Run your step here | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | #!/usr/bin/env bash # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. # Run your step here |
Modified tests/simplerun/tests/test2/step2.logpro from [3a7d1def42] to [b272b25505].
1 2 3 4 5 6 7 | ;; You should have at least one expect:required. This ensures that your process ran ;; (expect:required in "LogFileBody" > 0 "Put description here" #/put pattern here/) ;; You may need ignores to suppress false error or warning hits from the later expects ;; NOTE: Order is important here! (expect:ignore in "LogFileBody" < 99 "Ignore the word error in comments" #/^\/\/.*error/) (expect:warning in "LogFileBody" = 0 "Any warning" #/warn/) | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | ;; Copyright 2006-2017, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. ;; You should have at least one expect:required. This ensures that your process ran ;; (expect:required in "LogFileBody" > 0 "Put description here" #/put pattern here/) ;; You may need ignores to suppress false error or warning hits from the later expects ;; NOTE: Order is important here! (expect:ignore in "LogFileBody" < 99 "Ignore the word error in comments" #/^\/\/.*error/) (expect:warning in "LogFileBody" = 0 "Any warning" #/warn/) |
︙ | ︙ |
Modified tests/simplerun/tests/test2/step2.sh from [67f9a133dc] to [de871e9b2f].
1 2 3 | #!/usr/bin/env bash # Run your step here | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | #!/usr/bin/env bash # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. # Run your step here |
Modified tests/simplerun/tests/test2/testconfig from [e076c692d8] to [3b265ede54].
1 2 3 4 5 6 7 | # Add additional steps here. Format is "stepname script" [ezsteps] step1 step1.sh step2 step2.sh # Test requirements are specified here [requirements] | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. # Add additional steps here. Format is "stepname script" [ezsteps] step1 step1.sh step2 step2.sh # Test requirements are specified here [requirements] |
︙ | ︙ |
Modified tests/speedtest/megatest.config from [7467c22f06] to [f875c4ef8a].
1 2 3 4 5 6 7 | [fields] sysname TEXT fsname TEXT datapath TEXT [setup] transport #{scheme (if (getenv "USEHTTP") "http" "fs")} | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. [fields] sysname TEXT fsname TEXT datapath TEXT [setup] transport #{scheme (if (getenv "USEHTTP") "http" "fs")} |
︙ | ︙ |
Modified tests/speedtest/runconfigs.config from [0df59726be] to [9bc28c2391].
1 2 3 | [default] SOMEVAR This should show up in SOMEVAR3 | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. [default] SOMEVAR This should show up in SOMEVAR3 |
Modified tests/speedtest/tests/speedtest/main.sh from [a0890e7c55] to [fbb8189cfc].
1 2 3 4 5 6 7 8 | #!/bin/bash # a bunch of steps in 2 second increments for i in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17;do $MT_MEGATEST -step step$i :state start :status running -setlog results$i.html sleep $TEST_DELAY $MT_MEGATEST -step step$i :state end :status 0 done | > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | #!/bin/bash # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. # a bunch of steps in 2 second increments for i in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17;do $MT_MEGATEST -step step$i :state start :status running -setlog results$i.html sleep $TEST_DELAY $MT_MEGATEST -step step$i :state end :status 0 done |
︙ | ︙ |
Modified tests/speedtest/tests/speedtest/testconfig from [b5ced43bad] to [f427c7d038].
1 2 3 4 5 6 7 | [setup] runscript main.sh [requirements] priority 1 [items] | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. [setup] runscript main.sh [requirements] priority 1 [items] |
︙ | ︙ |
Deleted tests/stats.txt version [2a209bca81].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Modified tests/supportfiles/ruby/librunscript.rb from [a529a5a104] to [06bc8ea310].
1 2 3 4 5 6 7 | # This is the library of stuff for megatest def run_and_record(stepname, cmd, checks) system "megatest -step #{stepname} :state start :status n/a" system cmd exitcode=$? if exitcode==0 | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. # This is the library of stuff for megatest def run_and_record(stepname, cmd, checks) system "megatest -step #{stepname} :state start :status n/a" system cmd exitcode=$? if exitcode==0 |
︙ | ︙ |
Modified tests/test7.logpro from [4938e4fafc] to [871f6796f4].
1 2 3 4 5 6 7 | ;; You should have at least one expect:required. This ensures that your process ran (expect:required in "LogFileBody" > 0 "All tests launched" #/INFO:.*All tests launched/) ;; You may need ignores to suppress false error or warning hits from the later expects ;; NOTE: Order is important here! (expect:ignore in "LogFileBody" < 99 "Ignore the word error in comments" #/^\/\/.*error/) (expect:warning in "LogFileBody" = 0 "Any warning" #/warn/) | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | ;; Copyright 2006-2017, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. ;; You should have at least one expect:required. This ensures that your process ran (expect:required in "LogFileBody" > 0 "All tests launched" #/INFO:.*All tests launched/) ;; You may need ignores to suppress false error or warning hits from the later expects ;; NOTE: Order is important here! (expect:ignore in "LogFileBody" < 99 "Ignore the word error in comments" #/^\/\/.*error/) (expect:warning in "LogFileBody" = 0 "Any warning" #/warn/) |
︙ | ︙ |
Modified tests/tests.scm from [63be015a8f] to [b91fa9e96d].
1 2 | ;; Copyright 2006-2012, Matthew Welland. ;; | | | > > > > > | | > | | > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | ;; Copyright 2006-2012, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. ;; ;; strftime('%m/%d/%Y %H:%M:%S','now','localtime') (require-extension test) (require-extension regex) (require-extension srfi-18) (require-extension posix) (import posix) (import srfi-18) ;; (require-extension zmq) ;; (import zmq) (define test-work-dir (current-directory)) ;; given list of lists ;; ( ( msg expected param1 param2 ...) ;; ( ... ) ) ;; apply test to all ;; (define (test-batch proc pname inlst #!key (post-proc #f)) (for-each (lambda (spec) (let ((msg (conc pname " " (car spec))) (result (cadr spec)) (params (cddr spec))) (if post-proc (test msg result (post-proc (apply proc params))) (test msg result (apply proc params))))) inlst)) ;; read in all the _record files (let ((files (glob "*_records.scm"))) (for-each (lambda (file) (print "Loading " file) (load file)) |
︙ | ︙ |
Modified tests/unit.logpro from [e61bf35efe] to [776e0584bb].
1 2 3 4 5 6 7 | ;; Ignore initial errors (trigger "ScriptStart" #/^Script started/) (trigger "TestStart" #/^megatest> \(/) (section "startup" "ScriptStart" "TestStart") (expect:ignore in "startup" >= 0 "Ignore startup errors" #/error/i) | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | ;; Copyright 2006-2017, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. ;; Ignore initial errors (trigger "ScriptStart" #/^Script started/) (trigger "TestStart" #/^megatest> \(/) (section "startup" "ScriptStart" "TestStart") (expect:ignore in "startup" >= 0 "Ignore startup errors" #/error/i) |
︙ | ︙ |
Added tests/unittests/all-api.scm version [60bcb491ab].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 | ;;====================================================================== ;; A L L - A P I ;;====================================================================== ;; Copyright 2006-2017, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. ;; Run like this: ;; ;; Update the following line. make unit from parent directory. ;; ./rununittest.sh all-api 1 ;; Definitions: ;; NTN - no test needed ;; DEP - function is deprecated, no point in testing ;; NED - function nested under others, no test needed. ;; DEF - deferred ;; Issues: ;; 1. Most of the API calls accept a string or symbol for the function name, but at least one requires a symbol. ;; Should we decide one way or the other, symbol or string, (seems symbol is best) and enforce that in the API? Current code: ;; (cmd (if (symbol? cmd-in) ;; cmd-in ;; (string->symbol cmd-in))) ;; Just accept symbol ;; In the refactor, change execute-requests to only accept a symbol. ;; 2. Some functions return <unspecified> in element 1 of the vector. What to do about this? Fix them to return a measurable value? ;; Or is there a way to make test accept <unspecified>? - No. ;; This is why I had to use vector-ref and look at one value or the other. ;; Look at why functions are returning unspecified. ;; The last function they call returns nothing. ;; 3. Some API functions call non-existent db functions. ;; Delete these API functions after checking that they are not called? ;; Comment them out and give a date to delete. (in the refactor branch?) ;; 4. get-tests-times: no such query supported in api.scm, but it is in the list of read-only queries. Remove it? Or implement it if it's in db.scm? (define my-dbstruct (db:setup #t)) (define toppath (current-directory)) (define keypatts '(("SYSTEM" "ubuntu")("RELEASE" "v1.234")) ) (define keys (db:get-keys my-dbstruct)) (test #f #t (vector-ref (api:execute-requests my-dbstruct (vector 'start-server (list *toppath* ))) 0)) (test #f '() (vector-ref (api:execute-requests my-dbstruct (vector 'get-key-val-pairs (list 0 ))) 1)) (test #f #t (vector-ref (api:execute-requests my-dbstruct (vector 'set-var (list "LAST_UPDATE" 1234567))) 0)) (test #f 1234567 (vector-ref (api:execute-requests my-dbstruct (vector 'get-var (list "LAST_UPDATE" ))) 1)) (test #f #t (vector-ref (api:execute-requests my-dbstruct (vector 'del-var (list "LAST_UPDATE" ))) 0)) (test #f '("SYSTEM" "RELEASE") (vector-ref (api:execute-requests my-dbstruct (vector 'get-keys (list ))) 1)) (test #f '() (vector-ref (api:execute-requests my-dbstruct (vector 'get-key-vals (list 1 ))) 1)) (test #f 0 (vector-ref (api:execute-requests my-dbstruct (vector 'test-toplevel-num-items (list 1 "foo"))) 1)) (test #f #t (vector-ref (api:execute-requests my-dbstruct (vector 'get-test-info-by-id (list 1 1))) 0)) (test #f #t (vector-ref (api:execute-requests my-dbstruct (vector 'get-steps-info-by-id (list 1))) 0)) (test #f #t (vector-ref (api:execute-requests my-dbstruct (vector 'get-data-info-by-id (list 1))) 0)) (test #f '(#t "successful login") (vector-ref (api:execute-requests my-dbstruct (vector 'login (list toppath megatest-version "Fred"))) 1)) (test #f '(-1 . 0) (vector-ref (api:execute-requests my-dbstruct (vector 'get-latest-host-load (list "localhost"))) 1)) (test #f #t (vector-ref (api:execute-requests my-dbstruct (vector 'get-changed-record-ids (list 0))) 0)) (test #f #t (vector-ref (api:execute-requests my-dbstruct (vector 'get-run-record-ids (list "%" 1 keys "%/%"))) 0)) (test #f #t (vector-ref (api:execute-requests my-dbstruct (vector 'get-not-completed-cnt (list 1))) 0)) (test #f #t (vector-ref (api:execute-requests my-dbstruct (vector 'get-tests-tags (list ))) 0)) (test #f '("SYSTEM" "RELEASE") (vector-ref (api:execute-requests my-dbstruct (vector 'get-keys-write (list ))) 1)) (test #f (vector '("SYSTEM" "RELEASE") '())(vector-ref (api:execute-requests my-dbstruct (vector 'get-targets (list 1 ))) 1)) (test #f "" (vector-ref (api:execute-requests my-dbstruct (vector 'get-target (list 1 ))) 1)) (test #f #t (vector-ref (api:execute-requests my-dbstruct (vector 'general-call (list 'register-test 1 1 "foo" ""))) 0)) (test #f 1 (vector-ref (api:execute-requests my-dbstruct (vector 'get-test-id (list 1 "foo" ""))) 1)) (test #f "/tmp/badname" (vector-ref (api:execute-requests my-dbstruct (vector 'test-get-rundir-from-test-id (list 1 1))) 1)) (test #f #t (vector-ref (api:execute-requests my-dbstruct (vector 'set-tests-state-status (list 1 '("foo") "COMPLETED" "PASS" "NOT_STARTED" "PASS"))) 0)) (test #f #t (vector-ref (api:execute-requests my-dbstruct (vector 'test-set-state-status-by-id (list 1 1 "COMPLETED" "PASS" "Just testing!"))) 0)) (test #f #t (vector-ref (api:execute-requests my-dbstruct (vector 'get-tests-for-run (list 1 "%" '() '() #f #f #f #f #f #f 0 #f))) 0)) (test #f #t (vector-ref (api:execute-requests my-dbstruct (vector 'get-tests-for-run-mindata (list 1 "%" '("COMPLETED") '("PASS") #f ))) 0)) (test #f #t (vector-ref (api:execute-requests my-dbstruct (vector 'delete-test-records (list 1 2 ))) 0)) (test #f #t (vector-ref (api:execute-requests my-dbstruct (vector 'test-set-state-status (list 1 1 "COMPLETED" "FAIL" "Another message" ))) 0)) (test #f '() (vector-ref (api:execute-requests my-dbstruct (vector 'get-matching-previous-test-run-records (list 1 "foo" ""))) 1)) (test #f '("/tmp/badname" "logs/final.log") (vector-ref (api:execute-requests my-dbstruct (vector 'test-get-logfile-info (list 1 "foo"))) 1)) (test #f #t (vector-ref (api:execute-requests my-dbstruct (vector 'test-get-records-for-index-file (list 1 "foo"))) 0)) (test #f #t (vector-ref (api:execute-requests my-dbstruct (vector 'get-testinfo-state-status (list 1 1))) 0)) (test #f #t (vector-ref (api:execute-requests my-dbstruct (vector 'general-call (list 'test-set-log 1 "/tmp/another/logfile/eh" 1))) 0)) (test #f #t (vector-ref (api:execute-requests my-dbstruct (vector 'test-set-archive-block-id (list 1 1 123))) 0)) (test #f #t (vector-ref (api:execute-requests my-dbstruct (vector 'test-set-top-process-pid (list 1 1 123))) 0)) (test #f 123 (vector-ref (api:execute-requests my-dbstruct (vector 'test-get-top-process-pid (list 1 1))) 1)) (test #f #t (vector-ref (api:execute-requests my-dbstruct (vector 'get-run-ids-matching-target (list keys "%/%" #f "%" "%" "%" "%"))) 0)) (test #f #t (vector-ref (api:execute-requests my-dbstruct (vector 'test-get-paths-matching-keynames-target-new (list 1 keys "%/%" #f "%" "%" "%" "%"))) 0)) (test #f '() (vector-ref (api:execute-requests my-dbstruct (vector 'get-prereqs-not-met (list 1 '() "foo" "" '(normal) '()))) 1)) (test #f 0 (vector-ref (api:execute-requests my-dbstruct (vector 'get-count-tests-running-for-run-id (list 1))) 1)) (test #f 0 (vector-ref (api:execute-requests my-dbstruct (vector 'get-count-tests-running (list 1))) 1)) (test #f 0 (vector-ref (api:execute-requests my-dbstruct (vector 'get-count-tests-running-for-testname (list 1 "foo"))) 1)) (test #f 0 (vector-ref (api:execute-requests my-dbstruct (vector 'get-count-tests-running-in-jobgroup (list 1 "nada"))) 1)) (test #f #t (vector-ref (api:execute-requests my-dbstruct (vector 'set-state-status-and-roll-up-items (list 1 "foo" "" "COMPLETED" "FAIL" "Just yet another message"))) 0)) (test #f #t (vector-ref (api:execute-requests my-dbstruct (vector 'set-state-status-and-roll-up-run (list 1 "COMPLETED" "FAIL"))) 0)) (test #f #t (vector-ref (api:execute-requests my-dbstruct (vector 'top-test-set-per-pf-counts (list 1 "foo"))) 0)) (test #f #t (vector-ref (api:execute-requests my-dbstruct (vector 'get-raw-run-stats (list 1))) 0)) (test #f #t (vector-ref (api:execute-requests my-dbstruct (vector 'get-run-info (list 1))) 0)) (test #f 0 (vector-ref (api:execute-requests my-dbstruct (vector 'get-num-runs (list "%"))) 1)) (test #f 0 (vector-ref (api:execute-requests my-dbstruct (vector 'get-runs-cnt-by-patt (list "%" "%/%" keys))) 1)) (test #f #t (vector-ref (api:execute-requests my-dbstruct (vector 'register-run (list '(("SYSTEM" "ubuntu")("RELEASE" "v1.234")) "bar" "NEW" "JUSTFINE" "bobafett" "quick" ))) 0)) (test #f #(#t "bar") (api:execute-requests my-dbstruct (vector 'get-run-name-from-id '(1)))) (test #f #t (vector-ref (api:execute-requests my-dbstruct (vector 'delete-run (list 2))) 0)) ;; delete a non-existant run (test #f #t (vector-ref (api:execute-requests my-dbstruct (vector 'update-run-stats (list 1 '()))) 0)) (test #f #t (vector-ref (api:execute-requests my-dbstruct (vector 'get-main-run-stats (list 1 ))) 0)) (test #f #t (vector-ref (api:execute-requests my-dbstruct (vector 'delete-old-deleted-test-records '())) 0)) (test #f #t (vector-ref (api:execute-requests my-dbstruct (vector 'get-runs (list "%" 10 0 keypatts))) 0)) (test #f #t (vector-ref (api:execute-requests my-dbstruct (vector 'simple-get-runs (list "%" 10 0 keypatts))) 0)) (test #f #(#t (1))(api:execute-requests my-dbstruct (vector 'get-all-run-ids '()))) (test #f #(#t ()) (api:execute-requests my-dbstruct (vector 'get-prev-run-ids '(1)))) (test #f #(#t "JUSTFINE") (api:execute-requests my-dbstruct (vector 'get-run-status '(1)))) (test #f #(#t "NEW") (api:execute-requests my-dbstruct (vector 'get-run-state '(1)))) (test #f #(#t (("Totals" "UNKNOWN" 1) ("bar" "UNKNOWN" 1))) (api:execute-requests my-dbstruct (vector 'get-run-stats '()))) (test #f #(#t ()) (api:execute-requests my-dbstruct (vector 'get-run-times '(1 1 )))) (test #f #t (vector-ref (api:execute-requests my-dbstruct (vector 'lock/unlock-run '(1 #t #f "mikey"))) 0)) (test #f #t (vector-ref (api:execute-requests my-dbstruct (vector 'set-run-status '(1 "NOTFINE" "A message"))) 0)) (test #f #t (vector-ref (api:execute-requests my-dbstruct (vector 'set-run-state-status '(1 "NOTFINE" "AMESS"))) 0)) (test #f #t (vector-ref (api:execute-requests my-dbstruct (vector 'update-run-event_time '(1))) 0)) (test #f #t (vector-ref (api:execute-requests my-dbstruct (vector 'get-runs-by-patt (list keys "%" "%/%" #f #f #f #f "ASC"))) 0)) (test #f #t (vector-ref (api:execute-requests my-dbstruct (vector 'get-steps-data (list 1 1))) 0)) (test #f #t (vector-ref (api:execute-requests my-dbstruct (vector 'get-steps-for-test (list 1 1))) 0)) (test #f #t (vector-ref (api:execute-requests my-dbstruct (vector 'delete-steps-for-test! (list 1 1))) 0)) (test #f #t (vector-ref (api:execute-requests my-dbstruct (vector 'teststep-set-status! (list 1 1 "step1" "COMPLETED" "PASS" "force pass" "/tmp/logfile"))) 0)) (test #f #t (vector-ref (api:execute-requests my-dbstruct (vector 'test-data-rollup (list 1 1 "COMPLETED"))) 0)) (test #f #t (vector-ref (api:execute-requests my-dbstruct (vector 'csv->test-data (list 1 1 "some,data"))) 0)) (test #f #t (vector-ref (api:execute-requests my-dbstruct (vector 'read-test-data (list 1 1 "%"))) 0)) (test #f #t (vector-ref (api:execute-requests my-dbstruct (vector 'read-test-data* (list 1 1 "%" "%"))) 0)) (test #f #t (vector-ref (api:execute-requests my-dbstruct (vector 'tasks-add (list "run" "Fred" "%" "foo" "%/%" #f))) 0)) (test #f #t (vector-ref (api:execute-requests my-dbstruct (vector 'tasks-set-state-given-param-key (list "mykey" "COMPLETED"))) 0)) (test #f #t (vector-ref (api:execute-requests my-dbstruct (vector 'tasks-get-last (list "%" "foo"))) 0)) (test #f #t (vector-ref (api:execute-requests my-dbstruct (vector 'find-task-queue-records (list "%" "myrun" "%/%" "RUNNING" "run"))) 0)) (test #f #t (vector-ref (api:execute-requests my-dbstruct (vector 'testmeta-add-record (list "foo"))) 0)) (test #f #t (vector-ref (api:execute-requests my-dbstruct (vector 'testmeta-update-field (list "foo" "description" "junk"))) 0)) (test #f #t (vector-ref (api:execute-requests my-dbstruct (vector 'testmeta-get-record (list "foo"))) 0)) (test #f #t (vector-ref (api:execute-requests my-dbstruct (vector 'have-incompletes? (list 1 12000))) 0)) (test #f #t (vector-ref (api:execute-requests my-dbstruct (vector 'mark-incomplete (list 1 12000))) 0)) (test #f #t (vector-ref (api:execute-requests my-dbstruct (vector 'no-sync-set (list "field1" "value1"))) 0)) (test #f "value1" (vector-ref (api:execute-requests my-dbstruct (vector 'no-sync-get/default (list "field1" #f))) 1)) (test #f #t (vector-ref (api:execute-requests my-dbstruct (vector 'no-sync-del! (list "field1"))) 0)) (test #f #t (vector-ref (api:execute-requests my-dbstruct (vector 'no-sync-get-lock (list "mykey"))) 0)) (test #f 1 (vector-ref (api:execute-requests my-dbstruct (vector 'archive-register-disk (list "mydisk" "/usr/mydisk" 10000000))) 1)) (test #f #t (vector-ref (api:execute-requests my-dbstruct (vector 'archive-register-block-name (list 1 "/usr/mydisk/myblock"))) 0)) (test #f #t (vector-ref (api:execute-requests my-dbstruct (vector 'test-get-archive-block-info (list 1 ))) 0)) (test #f #t (vector-ref (api:execute-requests my-dbstruct (vector 'ping (list ))) 0)) (test #f #t (vector-ref (api:execute-requests my-dbstruct (vector 'kill-server (list ))) 0)) ;; api.scm calls db:get-previous-test-run-record, which does not exist. ;;(test #f '() (vector-ref (api:execute-requests my-dbstruct (vector "get-previous-test-run-record" (list 1 ))) 1)) ;; no such query supported in api.scm, but it is is the list of read-only queries. ;;(test #f #t (vector-ref (api:execute-requests my-dbstruct (vector 'get-tests-times (list ))) 0)) ;; api.scm calls db:get-tests-for-runs-mindata, which does not exist. ;;(test #f #t (vector-ref (api:execute-requests my-dbstruct (vector 'get-tests-for-runs-mindata (list 1 "%" '("COMPLETED") '("PASS") #f ))) 0)) ;;This api function calls db:archive-allocate-testsuite/area-to-block, which does not exist. ;;(test #f #t (vector-ref (api:execute-requests my-dbstruct (vector 'archive-allocate-testsuite/area-to-block (list 1 "/usr/mydisk/myblock"))) 0)) ;;debug this: ERROR: parameter last-update for db:sync-tables must be a pair or a number, received: (0 . last_update) ;;(test #f #t (vector-ref (api:execute-requests my-dbstruct (vector 'sync-inmem->db (list 1))) 0)) ;;debug this. Error: bad argument count - received 0 but expected 5: #<procedure (db:get-runs dbstruct3787 runpatt3788 count3789 offset3790 keypatts3... ;;(test #f #t (vector-ref (api:execute-requests my-dbstruct (vector 'synchash-get (list 1 (db:get-runs) "foo" 1 (list "%" 10 0 keypatts)))) 0)) ;;debug this. Call of non-procedure ;;(test #f #t (vector-ref (api:execute-requests my-dbstruct (vector 'sdb-qry (list "sdb-db"))) 0)) |
Modified tests/unittests/all-rmt.scm from [091111a6e5] to [3c7b17d5c4].
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | ;;====================================================================== ;; A L L - R M T ;;====================================================================== ;; Run like this: ;; ;; ./rununittest.sh all-rmt 1 ;; Definitions: ;; NTN - no test needed ;; DEP - function is deprecated, no point in testing ;; NED - function nested under others, no test needed. ;; DEF - deferred (print "start dir: " (current-directory)) (define toppath (current-directory)) | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 | ;;====================================================================== ;; A L L - R M T ;;====================================================================== ;; Copyright 2006-2017, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. ;; Run like this: ;; ;; ./rununittest.sh all-rmt 1 ;; Definitions: ;; NTN - no test needed ;; DEP - function is deprecated, no point in testing ;; NED - function nested under others, no test needed. ;; DEF - deferred (print "start dir: " (current-directory)) (define toppath (current-directory)) (test #f #f (server:check-if-running toppath)) ;; these are used by server:start-and-wait (test #f #t (list? (server:get-list toppath))) (test #f '() (server:get-best '())) (test #f #t (common:simple-file-lock-and-wait "test.lock" expire-time: 15)) (test #f "test.lock" (common:simple-file-release-lock "test.lock")) (test #f #t (server:get-best-guess-address (get-host-name))) (test #f #t (string? (common:get-homehost))) ;; clean out any old running servers ;; (let ((servers (server:get-list toppath))) (print "Known servers: " servers) (if (not (null? servers)) (begin (for-each (lambda (server) (let ((pid (list-ref server 4))) (thread-start! (make-thread (lambda () (print "Attempting to kill server: " server) (print "Attempting to kill pid " pid) (system (conc "kill " pid)) (thread-sleep! 2) (system (conc "kill -9 " pid))) (conc pid))))) servers) (thread-sleep! 2)))) ;; let's start up a server the mechanical way (system "nbfake megatest -server -") (thread-sleep! 2) ;; (test #f #t (string? (server:start-and-wait *toppath*))) (test "setup for run" #t (begin (launch:setup) (string? (getenv "MT_RUN_AREA_HOME")))) (test #f #t (client:setup-http toppath)) (test #f #t (vector? (client:setup toppath))) (test #f #t (vector? (rmt:get-connection-info toppath))) ;; TODO: push areapath down. (test #f #t (string? (server:check-if-running "."))) ;; DEF (test #f #f (rmt:send-receive-no-auto-client-setup *runremote* 'get-keys #f '())) ;; DEF (rmt:kill-server run-id) ;; DEF (rmt:start-server run-id) (test #f '(#t "successful login")(rmt:login #f)) ;; DEF (rmt:login-no-auto-client-setup connection-info) (test #f #t (pair? (rmt:get-latest-host-load (get-host-name)))) ;; get-latest-host-load does a lookup in the db, it won't return a useful value unless ;; a test ran recently on host (test-batch rmt:get-latest-host-load "rmt:get-latest-host-load" (list (list "localhost" #t (get-host-name)) (list "not-a-host" #t "not-a-host" )) post-proc: pair?) (test #f #t (list? (rmt:get-changed-record-ids 0))) (test #f #f (begin (runs:update-all-test_meta #f) #f)) (test #f '("test1" "test2")(sort (alist-ref "tagtwo" (rmt:get-tests-tags) equal?) string<=)) (test #f '() (rmt:get-key-val-pairs 0)) (test #f '("SYSTEM" "RELEASE") (rmt:get-keys)) (test #f '("SYSTEM" "RELEASE") (rmt:get-keys-write)) ;; dummy query to force server start (test #f '() (rmt:get-key-vals 1)) (test #f (vector '("SYSTEM" "RELEASE") '()) (rmt:get-targets)) (test #f "" (rmt:get-target 1)) (test #f #t (rmt:register-test 1 "foo" "")) (test #f 1 (rmt:get-test-id 1 "foo" "")) (test #f "foo" (vector-ref (rmt:get-test-info-by-id 1 1) 2)) (test #f "/tmp/badname" (rmt:test-get-rundir-from-test-id 1 1)) ;; (test #f '(1) (db:set-tests-state-status *db* 1 '("foo") "COMPLETED" "PASS" "NOT_STARTED" "PASS")) ;; trust that this was tested in all-api (test #f '(1) (rmt:set-tests-state-status 1 '("foo") "COMPLETED" "PASS" "NOT_STARTED" "PASS")) (test #f #t (mt:test-set-state-status-by-id 1 1 "COMPLETED" "PASS" "Just testing!")) (test #f #t (list? (rmt:get-tests-for-run 1 "%" '() '() #f #f #f #f #f #f 0 #f))) (test #f #t (list? (rmt:get-tests-for-runs-mindata '(1) "%" '() '() #f))) (test #f #f (begin (rmt:delete-test-records 1 2) #f)) (test #f #t (begin (rmt:test-set-state-status 1 1 "COMPLETED" "FAIL" "Another message") #t)) (test #f 0 (rmt:test-toplevel-num-items 1 "foo")) |
︙ | ︙ | |||
80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 | (test #f #t (vector? (rmt:get-runs "%" 10 0 keypatts))) (test #f '(1)(rmt:get-all-run-ids)) (test #f '()(rmt:get-prev-run-ids 1)) (test #f #t (begin (rmt:lock/unlock-run 1 #t #f "mikey") #t)) (test #f "JUSTFINE" (rmt:get-run-status 1)) (test #f #t (begin (rmt:set-run-status 1 "NOTFINE" msg: "A message") #t)) (test #f #t (begin (rmt:update-run-event_time 1) #t)) ;; (rmt:get-runs-by-patt keys runnamepatt targpatt offset limit fields last-runs-update) ;; fields of #f uses default ;; (rmt:find-and-mark-incomplete run-id ovr-deadtime) ;; (rmt:get-main-run-stats run-id) ;; (rmt:get-var varname) ;; (rmt:set-var varname value) ;; (rmt:find-and-mark-incomplete-all-runs #!key (ovr-deadtime #f)) ;; (rmt:get-previous-test-run-record run-id test-name item-path) ;; (rmt:get-run-stats) | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 | (test #f #t (vector? (rmt:get-runs "%" 10 0 keypatts))) (test #f '(1)(rmt:get-all-run-ids)) (test #f '()(rmt:get-prev-run-ids 1)) (test #f #t (begin (rmt:lock/unlock-run 1 #t #f "mikey") #t)) (test #f "JUSTFINE" (rmt:get-run-status 1)) (test #f #t (begin (rmt:set-run-status 1 "NOTFINE" msg: "A message") #t)) (test #f #t (begin (rmt:update-run-event_time 1) #t)) ;; (rmt:get-runs-by-patt keys runnamepatt targpatt offset limit fields last-runs-update) ;; fields of #f uses default ;; (let ((keys (rmt:get-keys)) (rnp "%") ;; run name patt (tpt "%/%")) ;; target patt (test-batch rmt:get-runs-by-patt "rmt:get-runs-by-patt" (list (list "t=0" #t keys rnp tpt #f #f #f 0) (list "t=current" #f keys rnp tpt #f #f #f (+ 100 (current-seconds))) ;; should be no records from the future ) post-proc: (lambda (res) ;; (print "rmt:get-runs-by-patt returned: " res) (and (vector? res) (let ((rows (vector-ref res 1))) (> (length rows) 0)))))) (test #f '(("Totals" "UNKNOWN" 1) ("bar" "UNKNOWN" 1)) (begin (rmt:get-run-stats))) (test #f #t (begin (rmt:set-run-state-status 1 "COMPLETE" "PASS") #t)) (test #f '"COMPLETE" (rmt:get-run-state 1)) (test #f '"PASS" (rmt:get-run-status 1)) (test #f #t (begin (rmt:set-var "foo" "bar")#t)) (test #f "bar" (rmt:get-var "foo")) (test #f #t (begin (rmt:print-db-stats) #t)) (test #f #t (begin (rmt:del-var "foo") #t)) (test #f #f (rmt:get-var "foo")) (test #f (vector #f #f #f #f #f #f #f #f #f #f #f #f) (rmt:get-data-info-by-id 1)) (test #f '() (rmt:get-key-vals 1)) (test #f "ubuntu/v1.234" (rmt:get-target 1)) (print (rmt:get-run-info 1)) (test #f '((runs) (tests) (test_steps) (test_data)) (rmt:get-run-record-ids "ubuntu/v1.234" 1 '("fail_count") "bar")) ;; (rmt:find-and-mark-incomplete run-id ovr-deadtime) ;; (rmt:get-main-run-stats run-id) ;; (rmt:get-var varname) ;; (rmt:set-var varname value) ;; (rmt:find-and-mark-incomplete-all-runs #!key (ovr-deadtime #f)) ;; (rmt:get-previous-test-run-record run-id test-name item-path) ;; (rmt:get-run-stats) |
︙ | ︙ |
Modified tests/unittests/basicserver.scm from [723ba8b37f] to [6dbaa79db6].
1 2 3 4 5 6 7 8 9 10 | ;;====================================================================== ;; S E R V E R ;;====================================================================== ;; Run like this: ;; ;; ./rununittest.sh server 1;(cd simplerun;megatest -stop-server 0) (delete-file* "logs/1.log") (define run-id 1) | > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | ;;====================================================================== ;; S E R V E R ;;====================================================================== ;; Copyright 2006-2017, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. ;; Run like this: ;; ;; ./rununittest.sh server 1;(cd simplerun;megatest -stop-server 0) (delete-file* "logs/1.log") (define run-id 1) |
︙ | ︙ |
Modified tests/unittests/configfiles.scm from [b89134d61a] to [cd320b1e94].
1 2 3 4 5 6 7 8 9 10 | ;;====================================================================== ;; C O N F I G F I L E S ;;====================================================================== (define conffile #f) (test "Read a config" #t (hash-table? (read-config "test.config" #f #f))) (test "Read a config that doesn't exist" #t (hash-table? (read-config "nada.config" #f #f))) (set! conffile (read-config "test.config" #f #f)) (test "Get available diskspace" #t (number? (get-df "./"))) | > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | ;;====================================================================== ;; C O N F I G F I L E S ;;====================================================================== ;; Copyright 2006-2017, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. (define conffile #f) (test "Read a config" #t (hash-table? (read-config "test.config" #f #f))) (test "Read a config that doesn't exist" #t (hash-table? (read-config "nada.config" #f #f))) (set! conffile (read-config "test.config" #f #f)) (test "Get available diskspace" #t (number? (get-df "./"))) |
︙ | ︙ |
Modified tests/unittests/cron.scm from [700c4402ed] to [b4dd05b232].
1 2 3 4 5 6 7 | (use test) ;; S M H MD MTH YR WD (define ref-time (vector 58 39 21 18 1 117 6 48 #f 25200)) (for-each | > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | ;; Copyright 2006-2017, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. (use test) ;; S M H MD MTH YR WD (define ref-time (vector 58 39 21 18 1 117 6 48 #f 25200)) (for-each |
︙ | ︙ |
Modified tests/unittests/dbrdbstruct.scm from [174e159a1e] to [7415eb1acc].
1 2 3 4 5 6 7 8 9 10 | ;;====================================================================== ;; S E R V E R ;;====================================================================== ;; Run like this: ;; ;; (cd ..;make && make install) && ./rununittest.sh server 1;(cd simplerun;megatest -stop-server 0) (test #f #t (vector? (make-dbr:dbstruct "/tmp"))) | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | ;;====================================================================== ;; S E R V E R ;;====================================================================== ;; Copyright 2006-2017, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. ;; Run like this: ;; ;; (cd ..;make && make install) && ./rununittest.sh server 1;(cd simplerun;megatest -stop-server 0) (test #f #t (vector? (make-dbr:dbstruct "/tmp"))) |
︙ | ︙ |
Modified tests/unittests/inmemdb.scm from [be345ba03b] to [76d3d329f0].
1 2 3 4 5 6 7 8 9 10 | ;;====================================================================== ;; S E R V E R ;;====================================================================== ;; Run like this: ;; ;; (cd ..;make && make install) && ./rununittest.sh server 1;(cd simplerun;megatest -stop-server 0) (set! *transport-type* 'http) | > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | ;;====================================================================== ;; S E R V E R ;;====================================================================== ;; Copyright 2006-2017, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. ;; Run like this: ;; ;; (cd ..;make && make install) && ./rununittest.sh server 1;(cd simplerun;megatest -stop-server 0) (set! *transport-type* 'http) |
︙ | ︙ |
Modified tests/unittests/misc.scm from [dd44f991b6] to [13ac5e1e6e].
1 2 3 4 5 6 7 | (use sqlite3) ;;====================================================================== ;; P R O C E S S E S ;;====================================================================== (test "process:cmd-run-with-stderr->list" '("No such file or directory") | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | ;; Copyright 2006-2017, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. (use sqlite3) ;;====================================================================== ;; P R O C E S S E S ;;====================================================================== (test "process:cmd-run-with-stderr->list" '("No such file or directory") |
︙ | ︙ |
Modified tests/unittests/runs.scm from [fb0f09ae17] to [ba97d94f7e].
1 2 3 4 5 6 7 | (define keys (rmt:get-keys)) (test #f #t (and (server:kind-run *toppath*) #t)) (test "get all legal tests" (list "test1" "test2") (sort (hash-table-keys (tests:get-all)) string<=?)) (test "register-run" #t (number? | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | ;; Copyright 2006-2017, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. (define keys (rmt:get-keys)) (test #f #t (and (server:kind-run *toppath*) #t)) (test "get all legal tests" (list "test1" "test2") (sort (hash-table-keys (tests:get-all)) string<=?)) (test "register-run" #t (number? |
︙ | ︙ |
Modified tests/unittests/server.scm from [d45af24828] to [a6d42b3a64].
1 2 3 4 5 6 7 8 9 10 | ;;====================================================================== ;; S E R V E R ;;====================================================================== ;; Run like this: ;; ;; (cd ..;make && make install) && ./rununittest.sh server 1;(cd simplerun;megatest -stop-server 0) (delete-file* "logs/1.log") (define run-id 1) | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | ;;====================================================================== ;; S E R V E R ;;====================================================================== ;; Copyright 2006-2017, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. ;; Run like this: ;; ;; (cd ..;make && make install) && ./rununittest.sh server 1;(cd simplerun;megatest -stop-server 0) (delete-file* "logs/1.log") (define run-id 1) |
︙ | ︙ |
Modified tests/unittests/tests.scm from [eb49f922eb] to [bafe78c58c].
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | ;; ;;====================================================================== ;; ;; itemwait, itemmatch ;; ;; (db:compare-itempaths ref-item-path item-path itemmap) ;; ;; ;; prereqs-not-met ;; ;; (rmt:get-prereqs-not-met run-id waitons item-path mode: testmode itemmap: itemmap)) ;; ;; (fails (runs:calc-fails prereqs-not-met)) ;; (prereq-fails (runs:calc-prereq-fail prereqs-not-met)) ;; (non-completed (runs:calc-not-completed prereqs-not-met)) ;; (runnables (runs:calc-runnable prereqs-not-met))) ;; ;; ;; | > > > > > > > > > > > > > > > > > < > | | > > | | | | | | | | < | < > > > | | | | | < > | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 | ;; ;;====================================================================== ;; Copyright 2006-2017, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. ;; ;; itemwait, itemmatch ;; ;; (db:compare-itempaths ref-item-path item-path itemmap) ;; ;; ;; prereqs-not-met ;; ;; (rmt:get-prereqs-not-met run-id waitons item-path mode: testmode itemmap: itemmap)) ;; ;; (fails (runs:calc-fails prereqs-not-met)) ;; (prereq-fails (runs:calc-prereq-fail prereqs-not-met)) ;; (non-completed (runs:calc-not-completed prereqs-not-met)) ;; (runnables (runs:calc-runnable prereqs-not-met))) ;; ;; ;; (define user (current-user-name)) (define runname "mytestrun") (define keys (rmt:get-keys)) (define runinfo #f) (define keyvals '(("SYSTEM" "abc")("RELEASE" "def"))) (define header (list "SYSTEM" "RELEASE" "id" "runname" "state" "status" "owner" "event_time")) (define contour #f) (define run-id 1) (define new-comment #f) ;; Create a run (test #f 1 (rmt:register-run keyvals runname "new" "n/a" user contour)) (test #f #t (rmt:general-call 'register-test run-id run-id "test-one" "")) (test #f #t (rmt:general-call 'register-test run-id run-id "test-two" "")) (test #f #t (rmt:general-call 'register-test run-id run-id "test-three" "")) (test #f #t (rmt:general-call 'register-test run-id run-id "test-four" "")) ;; (define (rmt:test-set-state-status-by-id run-id test-id newstate newstatus newcomment) (rmt:test-set-state-status-by-id run-id (rmt:get-test-id run-id "test-one" "") "COMPLETED" "FAIL" new-comment) (rmt:test-set-state-status-by-id run-id (rmt:get-test-id run-id "test-two" "") "COMPLETED" "PASS" new-comment) (rmt:test-set-state-status-by-id run-id (rmt:get-test-id run-id "test-three" "") "RUNNING" "n/a" new-comment) (rmt:test-set-state-status-by-id run-id (rmt:get-test-id run-id "test-four" "") "COMPLETED" "WARN" new-comment) (test "MODE=not in" '() (filter (lambda (y) (equal? y "FAIL")) ;; any FAIL in the output list? (map (lambda (x)(vector-ref x 4)) (rmt:get-tests-for-run run-id "%/%" '() '("FAIL") #f #f #t 'event_time "DESC" 'shortlist 0 'dashboard)))) (test "MODE=in" '("FAIL") (map (lambda (x)(vector-ref x 4)) (rmt:get-tests-for-run run-id "%/%" '() '("FAIL") #f #f #f 'event_time "DESC" 'shortlist 0 'dashboard))) (set! *verbosity* 1) ;; (set! *verbosity* 8) (test "MODE=in, state in RUNNING" '("RUNNING") (map (lambda (x)(vector-ref x 3)) (rmt:get-tests-for-run run-id "%/%" '("RUNNING") '() #f #f #f 'event_time "DESC" 'shortlist 0 'dashboard))) (set! *verbosity* 1) ;; (set! *verbosity* 8) ;;(define (rmt:get-tests-for-run run-id testpatt states statuses offset limit not-in sort-by sort-order qryvals last-update mode) (test "MODE=in, state in RUNNING and status IN WARN" '(("COMPLETED" . "WARN") ("RUNNING" . "n/a") ) (map (lambda (x) (cons (vector-ref x 3)(vector-ref x 4))) (rmt:get-tests-for-run run-id "%/%" '("RUNNING") '("WARN") #f #f #f 'event_time "DESC" 'shortlist 0 'dashboard))) (set! *verbosity* 1) (set! *verbosity* 8) (test "MODE=not in, state in RUNNING and status IN WARN" '(("COMPLETED" . "PASS") ("COMPLETED" . "FAIL")) (map (lambda (x) (cons (vector-ref x 3)(vector-ref x 4))) (rmt:get-tests-for-run run-id "%/%" '("RUNNING") '("WARN") #f #f #t 'event_time "DESC" 'shortlist 0 'dashboard))) (set! *verbosity* 1) (exit) |
Modified tests/vectors-vs-records.scm from [e4ff5d5a7e] to [ebf01cc3f7].
1 2 3 4 5 6 7 | (use srfi-9) (define numtodo (string->number (caddr (argv)))) ;; using vectors (define testvalvec (vector 0 1 2 3 4 5)) (define-inline (testing:get-first vec )(vector-ref vec 0)) | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | ;; Copyright 2006-2017, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. ;; (use srfi-9) (define numtodo (string->number (caddr (argv)))) ;; using vectors (define testvalvec (vector 0 1 2 3 4 5)) (define-inline (testing:get-first vec )(vector-ref vec 0)) |
︙ | ︙ |
Modified tests/watch-monitor.sh from [b68f1ca512] to [264f0c8557].
1 2 3 4 5 6 7 8 9 | #!/bin/bash if [ -e fullrun/db/monitor.db ];then sqlite3 fullrun/db/monitor.db << EOF .header on .mode column select * from servers order by start_time desc; .q EOF | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | #!/bin/bash # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. if [ -e fullrun/db/monitor.db ];then sqlite3 fullrun/db/monitor.db << EOF .header on .mode column select * from servers order by start_time desc; .q EOF |
︙ | ︙ |
Deleted testzmq/hwclient.scm version [2bca7d9a69].
|
| < < < < < < < < < < < < < < < < |
Deleted testzmq/hwserver.scm version [d8d9994146].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted testzmq/hwtest.sh version [aa5368d04d].
|
| < < < < < < < < < < < < < < |
Deleted testzmq/mockupclient.scm version [63a8c6685a].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted testzmq/mockupclientlib.scm version [1577031d21].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted testzmq/mockupserver.scm version [f130435054].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted testzmq/random.scm version [7090f9f44f].
|
| < < < < < < < < |
Deleted testzmq/testmockup.sh version [8905872c25].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Added trackback.scm version [b547b4460b].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | ;; Copyright 2006-2017, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. (include "codescanlib.scm") ;; show call paths for named procedure (define (traceback-proc in-procname) (letrec* ((all-scm-files (glob "*.scm")) (xref (get-xref all-scm-files)) (have (alist-ref (string->symbol in-procname) xref eq? #f)) (lookup (lambda (path procname depth) (let* ((upcone-temp (filter (lambda (x) (eq? procname (car x))) xref)) (upcone-temp2 (cond ((null? upcone-temp) '()) (else (cdar upcone-temp)))) (upcone (filter (lambda (x) (not (eq? x procname))) upcone-temp2)) (uppath (cons procname path)) (updepth (add1 depth))) (if (null? upcone) (print uppath) (for-each (lambda (x) (if (not (member procname path)) (lookup uppath x updepth) )) upcone)))))) (if have (lookup '() (string->symbol in-procname) 0) (print "no such func - "in-procname)))) (if (eq? 1 (length (command-line-arguments))) (traceback-proc (car (command-line-arguments))) (print "Usage: trackback <procedure name>")) (exit 0) |
Modified tree.scm from [be6fd73bd7] to [ffabd357b5].
1 2 3 | ;;====================================================================== ;; Copyright 2006-2013, Matthew Welland. ;; | | | > > > > > | | > | > > > | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | ;;====================================================================== ;; Copyright 2006-2013, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. ;; ;;====================================================================== (use format) (require-library iup) (import (prefix iup iup:)) (use canvas-draw) (use sqlite3 srfi-1 posix regex regex-case srfi-69) (import (prefix sqlite3 sqlite3:)) (declare (unit tree)) (declare (uses margs)) (declare (uses launch)) (declare (uses megatest-version)) (declare (uses gutils)) (declare (uses db)) (declare (uses server)) ;; (declare (uses synchash)) (declare (uses dcommon)) (include "common_records.scm") (include "db_records.scm") (include "key_records.scm") ;;====================================================================== |
︙ | ︙ | |||
67 68 69 70 71 72 73 | ;; top is the top node name zeroeth node VALUE=0 (define (tree:add-node obj top nodelst #!key (userdata #f)) (let ((curr-top (iup:attribute obj "TITLE0"))) (if (or (not (string? curr-top)) (string-null? curr-top) (string-match "^\\s*$" curr-top)) | | > > > | 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 | ;; top is the top node name zeroeth node VALUE=0 (define (tree:add-node obj top nodelst #!key (userdata #f)) (let ((curr-top (iup:attribute obj "TITLE0"))) (if (or (not (string? curr-top)) (string-null? curr-top) (string-match "^\\s*$" curr-top)) (iup:attribute-set! obj "ADDBRANCH0" top)) (cond ((not (equal? top (iup:attribute obj "TITLE0"))) (print "ERROR: top name " top " doesn't match " (iup:attribute obj "TITLE0"))) ((null? nodelst)) (else (let loop ((hed (car nodelst)) (tal (cdr nodelst)) |
︙ | ︙ |
Deleted txtdb/metadat.scm version [af09f06325].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted txtdb/nada3/First_Sheet.dat version [b680ed8dff].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted txtdb/nada3/RunsToDo.dat version [3e0737c065].
|
| < < < < < < < < < < < < < < < |
Deleted txtdb/nada3/RunsToLock.dat version [5d15c8e35d].
|
| < < < < < < < < < < < < |
Deleted txtdb/nada3/Second-sheet.dat version [6499ddd193].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted txtdb/nada3/Sheet3.dat version [2e8bf819e7].
|
| < < < < < < < < |
Deleted txtdb/nada3/sheet-names.cfg version [380375514f].
|
| < < < < |
Deleted txtdb/nada3/sxml/First_Sheet.sxml version [4c684f65f1].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted txtdb/nada3/sxml/RunsToDo.sxml version [670e476878].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted txtdb/nada3/sxml/RunsToLock.sxml version [fedfcd13be].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted txtdb/nada3/sxml/Second-sheet.sxml version [f87c23eec3].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted txtdb/nada3/sxml/Sheet3.sxml version [fc57fa497e].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted txtdb/nada3/sxml/_sheets.sxml version [fd8e08bb55].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted txtdb/nada3/sxml/_workbook.sxml version [96ffb7f9d5].
|
| < |
Deleted txtdb/testdata.sxml version [0efca32b7e].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Modified utils/Makefile.git.installall from [307e7d57f5] to [a36c19bd4e].
1 2 | # Copyright 2013-2015 Matthew Welland. | | > > > | < > > > | | | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | # Copyright 2013-2015 Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. help : @echo You may need to do the following setup first: @echo @echo sudo apt-get install libreadline-dev @echo sudo apt-get install libwebkitgtk-dev libfreetype6-dev libx11-dev libxpm-dev libxmu-dev \ libxft-dev libgtk2.0-dev libgl1-mesa-dev libglu1-mesa-dev libpangox-1.0-dev bison \ |
︙ | ︙ | |||
45 46 47 48 49 50 51 | endif # Set this on the command line of your make call if needed: make PROXY=host.com:1234 PROXY= # http://code.call-cc.org/dev-snapshots/2015/06/07/chicken-4.10.0rc1.tar.gz # http://code.call-cc.org/releases/4.10.0/chicken-4.10.0.tar.gz # Select version of chicken, sqlite3 etc | | | 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 | endif # Set this on the command line of your make call if needed: make PROXY=host.com:1234 PROXY= # http://code.call-cc.org/dev-snapshots/2015/06/07/chicken-4.10.0rc1.tar.gz # http://code.call-cc.org/releases/4.10.0/chicken-4.10.0.tar.gz # Select version of chicken, sqlite3 etc CHICKEN_VERSION=4.12.0rc2 SQLITE3_VERSION=3090200 # http://www.sqlite.org/2014/sqlite-autoconf-3080500.tar.gz # http://www.sqlite.org/2015/sqlite-autoconf-3081101.tar.gz # Override IUPBRANCH to use other than trunk IUPBRANCH=trunk IUPCONFIG=ubuntu-15.04.inc # iup-3.15 |
︙ | ︙ | |||
172 173 174 175 176 177 178 179 180 181 182 183 184 185 | fossil clone https://www.kiatoa.com/fossils/chicken-core chicken-scheme.fossil mkdir -p chicken-core cd chicken-core; pwd cd chicken-core; fossil open ../chicken-scheme.fossil cd chicken-core; fossil up 337f5be # wget http://code.call-cc.org/dev-snapshots/2015/08/29/chicken-4.10.1.tar.gz # git clone git://code.call-cc.org/chicken-core # git clone http://code.call-cc.org/git/chicken-core.git $(PRODCHICKEN)/bin/chicken : wget http://code.call-cc.org/dev-snapshots/2015/08/29/chicken-4.10.1.tar.gz tar -xzvf chicken-4.10.1.tar.gz cd chicken-4.10.1/; make PLATFORM=linux PREFIX=$(PRODCHICKEN) | > > > | 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 | fossil clone https://www.kiatoa.com/fossils/chicken-core chicken-scheme.fossil mkdir -p chicken-core cd chicken-core; pwd cd chicken-core; fossil open ../chicken-scheme.fossil cd chicken-core; fossil up 337f5be # wget http://code.call-cc.org/dev-snapshots/2015/08/29/chicken-4.10.1.tar.gz chicken-4.12.0rc2.tar.gz : wget https://code.call-cc.org/dev-snapshots/2017/02/06/chicken-4.12.0rc2.tar.gz # git clone git://code.call-cc.org/chicken-core # git clone http://code.call-cc.org/git/chicken-core.git $(PRODCHICKEN)/bin/chicken : wget http://code.call-cc.org/dev-snapshots/2015/08/29/chicken-4.10.1.tar.gz tar -xzvf chicken-4.10.1.tar.gz cd chicken-4.10.1/; make PLATFORM=linux PREFIX=$(PRODCHICKEN) |
︙ | ︙ |
Modified utils/Makefile.installall from [aefb91939e] to [98a3761faa].
1 2 3 | # Copyright 2013-2015 Matthew Welland. # | > > > | < > > > | | | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | # Copyright 2013-2015 Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. help : @echo You may need to do the following setup first: @echo @echo sudo apt-get install libreadline-dev @echo sudo apt-get install libwebkitgtk-dev libfreetype6-dev libx11-dev libxpm-dev libxmu-dev \ libxft-dev libgtk2.0-dev libgl1-mesa-dev libglu1-mesa-dev libpangox-1.0-dev bison \ |
︙ | ︙ | |||
43 44 45 46 47 48 49 | # Set this on the command line of your make call if needed: make PROXY=host.com:1234 PROXY= # http://code.call-cc.org/dev-snapshots/2015/06/07/chicken-4.10.0rc1.tar.gz # http://code.call-cc.org/releases/4.10.0/chicken-4.10.0.tar.gz # Select version of chicken, sqlite3 etc # CHICKEN_VERSION=4.10.0 | | | | 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 | # Set this on the command line of your make call if needed: make PROXY=host.com:1234 PROXY= # http://code.call-cc.org/dev-snapshots/2015/06/07/chicken-4.10.0rc1.tar.gz # http://code.call-cc.org/releases/4.10.0/chicken-4.10.0.tar.gz # Select version of chicken, sqlite3 etc # CHICKEN_VERSION=4.10.0 CHICKEN_VERSION=4.11.0 SQLITE3_VERSION=3090200 # http://www.sqlite.org/2014/sqlite-autoconf-3080500.tar.gz # http://www.sqlite.org/2015/sqlite-autoconf-3081101.tar.gz # Override IUPBRANCH to use other than trunk IUPBRANCH=trunk IUPCONFIG=ubuntu-15.04.inc # iup-3.15 # Eggs to install (straightforward ones) EGGS=matchable readline apropos base64 regex-literals format regex-case test coops trace csv \ dot-locking posix-utils posix-extras hostinfo tcp-server rpc csv-xml fmt \ json md5 awful http-client spiffy uri-common intarweb spiffy-request-vars pathname-expand \ spiffy-directory-listing ssax sxml-serializer sxml-modifications sql-de-lite \ srfi-19 refdb ini-file sparse-vectors z3 call-with-environment-variables hahn linenoise \ crypt parley # # Derived variables |
︙ | ︙ | |||
95 96 97 98 99 100 101 | ifeq ($(ISARCHX86_64),) ARCHSIZE= else ARCHSIZE=64_ endif CSCLIBS=$(shell echo $(LD_LIBRARY_PATH) | sed 's/:/ -L/g') | | | 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 | ifeq ($(ISARCHX86_64),) ARCHSIZE= else ARCHSIZE=64_ endif CSCLIBS=$(shell echo $(LD_LIBRARY_PATH) | sed 's/:/ -L/g') CSC_OPTIONS="-I$(PREFIX)/include -L$(CSCLIBS) -C -fPIC" # CSC_OPTIONS=-I $(PREFIX)/include -L $(CSCLIBS) nogui : base mutils #all : nogui libiup $(PREFIX)/lib/sqlite3.so all : nogui libiup |
︙ | ︙ | |||
135 136 137 138 139 140 141 | $(EGGFLAGS) : # $(CHICKEN_INSTALL) mkdir -p eggflags touch $(EGGFLAGS) # some setup stuff # | | > | < < < < < < < < < | | < < < > | | > > | 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 | $(EGGFLAGS) : # $(CHICKEN_INSTALL) mkdir -p eggflags touch $(EGGFLAGS) # some setup stuff # #$(PREFIX)/setup-chicken4x.sh : $(EGGFLAGS) $(PREFIX)/setup-chicken4x.sh : mkdir -p $(PREFIX) (echo 'export PATH=$(PREFIX)/bin:$$PATH' > $(PREFIX)/setup-chicken4x.sh) (echo "export LD_LIBRARY_PATH=$(LD_LIBRARY_PATH)" >> $(PREFIX)/setup-chicken4x.sh) $(PREFIX)/setup-chicken4x.csh : $(EGGFLAGS) mkdir -p $(PREFIX) (echo "setenv PATH $(PREFIX):'$$'PATH" > $(PREFIX)/setup-chicken4x.csh) (echo "setenv LD_LIBRARY_PATH $(LD_LIBRARY_PATH)" >> $(PREFIX)/setup-chicken4x.csh) # NOTE: the touch chicken-core/chicken.scm compensates for the time stamp from the tar file chicken-core/chicken.scm : chicken-$(CHICKEN_VERSION).tar.gz tar xzf chicken-$(CHICKEN_VERSION).tar.gz ln -sf chicken-$(CHICKEN_VERSION) chicken-core if [[ -e chicken-core/chicken.scm ]];then touch chicken-core/chicken.scm;fi chicken-4.11.0.tar.gz : wget http://code.call-cc.org/releases/4.11.0/chicken-4.11.0.tar.gz # git clone git://code.call-cc.org/chicken-core # git clone http://code.call-cc.org/git/chicken-core.git $(CHICKEN_INSTALL) : chicken-core/chicken.scm $(PREFIX)/setup-chicken4x.sh $(PREFIX)/setup-chicken4x.csh pwd; env; which make cd chicken-core; make PLATFORM=linux PREFIX=$(PREFIX) cd chicken-core; make PLATFORM=linux PREFIX=$(PREFIX) install #cd chicken-core;env -i PATH=${PATH} LD_LIBRARY_PATH=${LD_LIBRARY_PATH} make PLATFORM=linux PREFIX=$(PREFIX) #cd chicken-core;env -i PATH=${PATH} LD_LIBRARY_PATH=${LD_LIBRARY_PATH} make PLATFORM=linux PREFIX=$(PREFIX) install #====================================================================== # S Q L I T E 3 #====================================================================== # https://www.sqlite.org/2015/sqlite-autoconf-3090200.tar.gz sqlite-autoconf-$(SQLITE3_VERSION).tar.gz : wget http://www.sqlite.org/2015/sqlite-autoconf-$(SQLITE3_VERSION).tar.gz |
︙ | ︙ | |||
233 234 235 236 237 238 239 | $(PREFIX)/lib/chicken/8/dbi.so : opensrc/dbi/dbi.scm cd opensrc/dbi;chicken-install $(PREFIX)/lib/chicken/8/margs.so : opensrc/margs/margs.scm cd opensrc/margs;chicken-install opensrc/histstore/hs : opensrc/histstore/histstore.scm chkn eggs $(CHICKEN_EGG_DIR)/sqlite3.so | > | | | 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 | $(PREFIX)/lib/chicken/8/dbi.so : opensrc/dbi/dbi.scm cd opensrc/dbi;chicken-install $(PREFIX)/lib/chicken/8/margs.so : opensrc/margs/margs.scm cd opensrc/margs;chicken-install opensrc/histstore/hs : opensrc/histstore/histstore.scm chkn eggs $(CHICKEN_EGG_DIR)/sqlite3.so env | grep CSC cd opensrc/histstore; $(PREFIX)/bin/csc histstore.scm -o hs $(PREFIX)/bin/hs : opensrc/histstore/hs cp -f opensrc/histstore/hs $(PREFIX)/bin/hs # stml stml.fossil : fossil clone http://www.kiatoa.com/fossils/stml stml.fossil # open touches the .fossil :( stml/requirements.scm.template : stml.fossil mkdir -p stml cd stml;if [ -e .fslckout ];then fossil update; else fossil open ../stml.fossil;fi stml/requirements.scm : stml/requirements.scm.template cp stml/install.cfg.template stml/install.cfg cp stml/requirements.scm.template stml/requirements.scm $(PREFIX)/lib/chicken/8/stml.so : stml/requirements.scm cd stml; make #====================================================================== # F F C A L L (Used by IUP) #====================================================================== ffcall.fossil : fossil clone http://www.kiatoa.com/fossils/ffcall ffcall.fossil |
︙ | ︙ | |||
278 279 280 281 282 283 284 | # I U P #====================================================================== iuplib.fossil : fossil clone http://www.kiatoa.com/fossils/iuplib iuplib.fossil cd-5.9_Linux26g4_64_lib.tar.gz : | | > > > > | | > > > | > > > | > > > | | | | | | 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 | # I U P #====================================================================== iuplib.fossil : fossil clone http://www.kiatoa.com/fossils/iuplib iuplib.fossil cd-5.9_Linux26g4_64_lib.tar.gz : wget --no-check-certificate -c http://sourceforge.net/projects/canvasdraw/files/5.9/Linux%20Libraries/cd-5.9_Linux26g4_64_lib.tar.gz/download mv download cd-5.9_Linux26g4_64_lib.tar.gz cd-5.10_Linux26g4_64_lib.tar.gz : cp /p/fdk/gwa/jmoon18/cd-5.10_Linux26g4_64_lib.tar.gz cd-5.10_Linux26g4_64_lib.tar.gz iup-3.17_Linux26g4_64_lib.tar.gz : cp /p/fdk/gwa/jmoon18/iup-3.17_Linux26g4_64_lib.tar.gz iup-3.17_Linux26g4_64_lib.tar.gz # wget --no-check-certificate -c http://sourceforge.net/projects/iup/files/3.17/Linux%20Libraries/iup-3.17_Linux26g4_64_lib.tar.gz/download # mv download iup-3.17_Linux26g4_64_lib.tar.gz iup-3.19.1_Linux26g4_64_lib.tar.gz : cp /p/fdk/gwa/jmoon18/iup-3.19.1_Linux26g4_64_lib.tar.gz iup-3.19.1_Linux26g4_64_lib.tar.gz im-3.10_Linux26g4_64_lib.tar.gz : wget --no-check-certificate -c http://sourceforge.net/projects/imtoolkit/files/3.10/Linux%20Libraries/im-3.10_Linux26g4_64_lib.tar.gz/download mv download im-3.10_Linux26g4_64_lib.tar.gz im-3.11_Linux26g4_64_lib.tar.gz : cp /p/fdk/gwa/jmoon18/im-3.11_Linux26g4_64_lib.tar.gz im-3.11_Linux26g4_64_lib.tar.gz lua-5.3.2_Linux26g4_64_lib.tar.gz : wget --no-check-certificate -c http://sourceforge.net/projects/luabinaries/files/5.3.2/Linux%20Libraries/lua-5.3.2_Linux26g4_64_lib.tar.gz/download mv download lua-5.3.2_Linux26g4_64_lib.tar.gz lua-5.3.3_Linux26g4_64_lib.tar.gz : cp /p/fdk/gwa/jmoon18/lua-5.3.3_Linux26g4_64_lib.tar.gz lua-5.3.3_Linux26g4_64_lib.tar.gz iup/installall.sh : $(PREFIX)/lib/libiup.so \ cd-5.10_Linux26g4_64_lib.tar.gz \ iup-3.17_Linux26g4_64_lib.tar.gz \ im-3.11_Linux26g4_64_lib.tar.gz \ lua-5.3.3_Linux26g4_64_lib.tar.gz # iuplib.fossil mkdir -p iup pwd tar -xzvf cd-5.10_Linux26g4_64_lib.tar.gz -C iup/ tar -xzvf im-3.11_Linux26g4_64_lib.tar.gz -C iup/ tar -xzvf iup-3.17_Linux26g4_64_lib.tar.gz -C iup/ mkdir -p $(PREFIX)/include/ $(PREFIX)/lib/ cp iup/include/* $(PREFIX)/include/ cp iup/*.so $(PREFIX)/lib/ cp iup/*.a $(PREFIX)/lib/ # cd iup && if [ -e makeall.sh ];then fossil update $(IUPBRANCH); else fossil open ../iuplib.fossil;fossil update $(IUPBRANCH); fi |
︙ | ︙ | |||
329 330 331 332 333 334 335 | # -feature disable-iup-web $(CHICKEN_EGG_DIR)/canvas-draw.so : $(PREFIX)/lib/libiup.so $(PREFIX)/lib/libavcall.a CSC_OPTIONS=$(CSC_OPTIONS) $(CHICKEN_INSTALL) $(PROX) -D no-library-checks canvas-draw clean : | | | 343 344 345 346 347 348 349 350 | # -feature disable-iup-web $(CHICKEN_EGG_DIR)/canvas-draw.so : $(PREFIX)/lib/libiup.so $(PREFIX)/lib/libavcall.a CSC_OPTIONS=$(CSC_OPTIONS) $(CHICKEN_INSTALL) $(PROX) -D no-library-checks canvas-draw clean : rm -rf chicken-4.11.0 eggflags ffcall sqlite-autoconf-$(SQLITE3_VERSION) |
Modified utils/Makefile.latest.installall from [e858ad0d21] to [dc72026b09].
1 2 3 | # Copyright 2013-2015 Matthew Welland. # | > > > | < > > > | | > > > > | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | # Copyright 2013-2015 Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. help : @echo You may need to do the following setup first: @echo @echo sudo apt-get install libreadline-dev @echo sudo apt-get install libwebkitgtk-dev libfreetype6-dev libx11-dev libxpm-dev libxmu-dev \ libxft-dev libgtk2.0-dev libgl1-mesa-dev libglu1-mesa-dev libpangox-1.0-dev bison \ |
︙ | ︙ |
Added utils/checkPreReqs version [15cea0fad4].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | #!/bin/bash # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. SYSTEM_TYPE=$(lsb_release -irs |tr ' ' '_' |tr '\n' '-')$(uname -i) file=`/bin/mktemp` case $SYSTEM_TYPE in Ubuntu-17.04-x86_64-std) apt list --installed | cut -d/ -f 1 > $file ;; Ubuntu-16.04-x86_64) apt list --installed | cut -d/ -f 1 > $file ;; Ubuntu-16.04-i686) apt list --installed | cut -d/ -f 1 > $file ;; SUSE_LINUX_11-x86_64) rpm -qa > $file ;; CentOS_5.11-x86_64-std) rpm -qa > $file ;; esac for package in libmysqlclient-dev libsqlite3-dev sqlite3 postgresql libreadline-dev libwebkitgtk-dev libpangox-1.0-0 zlib1g-dev libfreetype6 cmake libssl-dev uuid-dev libmotif3 mysql-client; do grep --silent $package $file if [ "$?" != "0" ]; then echo "sudo apt install $package" fi done rm $file |
Modified utils/cleanup-links-dir.sh from [2e6a90f3c8] to [13fadb51d1].
1 2 3 4 5 6 7 8 9 | #!/usr/bin/env bash export LINKSDIR=$1 export RUNSDIR=$2 if [ "x$LINKSDIR" == "x" ];then echo Usage: cleanup-links-dir /links/dir/path /runs/dir/path exit fi | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | #!/usr/bin/env bash # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. export LINKSDIR=$1 export RUNSDIR=$2 if [ "x$LINKSDIR" == "x" ];then echo Usage: cleanup-links-dir /links/dir/path /runs/dir/path exit fi |
︙ | ︙ |
Added utils/cleanup-pkts.sh version [3ade713f98].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | #!/bin/bash # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. pushd $1 for x in *.pkt;do if grep 'T configf' $x > /dev/null;then rm $x else echo skip $x fi done |
Modified utils/deploy.sh from [614579fd81] to [5264c6b65f].
1 2 3 4 5 6 7 8 9 | #!/bin/bash set -x if [[ $DEPLOYTARG == "" ]] ; then echo Installing into deploytarg export DEPLOYTARG=$PWD/deploytarg fi | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | #!/bin/bash # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. set -x if [[ $DEPLOYTARG == "" ]] ; then echo Installing into deploytarg export DEPLOYTARG=$PWD/deploytarg fi |
︙ | ︙ |
Added utils/editwiki version [fef348f67d].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 | #!/bin/bash # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. wikiname=$1 FOSSILBIN=fossil if [ x"$wikiname" == "x" ];then echo "Usage: viwiki wikipagename" exit fi $FOSSILBIN sync # wikitmpfile=`mktemp /tmp/${USER}_wikiedit.XXXXXXX` wikitmpfile=${wikiname}.in if ! $FOSSILBIN wiki export "$wikiname" 2> /dev/null 1> $wikitmpfile ;then cat /dev/null > $wikitmpfile wikipagestate='new' else wikipagestate='existing' fi # make a backup copy of the extracted file to diff detect if changed cp $wikitmpfile ${wikitmpfile}.orig if [[ x"$EDITOR" == "x" ]];then # || [[ x"$VISUAL" == "x" ]];then EDITOR="gvim -f" fi echo $EDITOR | grep -q -e gvim isGvim=$? echo $EDITOR | grep -q -e 'gvim.*-f' hasF=$? if [[ $isGvim == 0 && $hasF != 0 ]]; then EDITOR="$EDITOR -f" fi $EDITOR $wikitmpfile if ! diff -q $wikitmpfile ${wikitmpfile}.orig;then echo "Saving changes to $wikitmpfile to wiki" if [ $wikipagestate == 'new' ];then $FOSSILBIN wiki create "$wikiname" $wikitmpfile else $FOSSILBIN wiki commit "$wikiname" $wikitmpfile fi else echo "Not saving, no changes to $wikitmpfile." fi $FOSSILBIN sync # NOTE// We *keep* the wikitmpfile but remove the orig copy rm -f ${wikitmpfile}.orig |
Modified utils/example-launch-dispatcher.scm from [2ae1f52553] to [c3c6f2b8ec].
1 2 3 4 5 6 7 | (let ((target (assoc ;; Put the variable name here, note: only *one* ' ;; 'TARGET_OS 'MANYITEMS (read (open-input-string (get-environment-variable "MT_ITEM_INFO")))))) (case (if target target 'var-undef) | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | ;; Copyright 2006-2017, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. ;; (let ((target (assoc ;; Put the variable name here, note: only *one* ' ;; 'TARGET_OS 'MANYITEMS (read (open-input-string (get-environment-variable "MT_ITEM_INFO")))))) (case (if target target 'var-undef) |
︙ | ︙ |
Modified utils/find-unused-globals.sh from [54735d591a] to [56c8cd797e].
1 2 3 4 5 6 7 8 9 | #!/bin/bash echo "Finding unused globals:" for var in $(egrep '^\s*\(define\s+\*' *.scm|awk '{print $2}'|sort -u);do if ! $(egrep -v '^\s*\(define' *scm| grep "$var" > /dev/null);then echo "$var not used"; fi; done | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | #!/bin/bash # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. echo "Finding unused globals:" for var in $(egrep '^\s*\(define\s+\*' *.scm|awk '{print $2}'|sort -u);do if ! $(egrep -v '^\s*\(define' *scm| grep "$var" > /dev/null);then echo "$var not used"; fi; done |
︙ | ︙ |
Modified utils/fslrept.scm from [a7525c0b51] to [5aaf37f778].
1 2 3 4 5 6 7 | (use json fmt posix) ;; abstract out the alist-ref a bit and re-order the params ;; (define-inline (aref dat key) (alist-ref key dat equal?)) | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | ;; Copyright 2006-2017, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. ;; (use json fmt posix) ;; abstract out the alist-ref a bit and re-order the params ;; (define-inline (aref dat key) (alist-ref key dat equal?)) |
︙ | ︙ |
Added utils/gen-build-info.sh version [338b067888].
> > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | echo "Data gathered on $(date)" echo echo "Megatest code node: $(fossil status | grep checkout: | awk '{print $2}')" echo echo "Host: $HOSTNAME" echo echo "Which csi: $(which csi)" echo echo "Version info from csc -version:" csc -version echo echo "Eggs info from chicken-status:" chicken-status echo echo "Host info from lsb_release -a:" lsb_release -a |
Modified utils/homehost_check.sh from [a5c58a17c8] to [d9e559ad21].
1 2 3 4 5 6 7 8 9 | #! /bin/bash #exits 1 when current host is not homehost. if [[ ! -e .homehost ]]; then exit 0 fi homehostname=$( host `cat .homehost` | awk '{print $NF}' | sed 's/\.$//' ) | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | #! /bin/bash # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. #exits 1 when current host is not homehost. if [[ ! -e .homehost ]]; then exit 0 fi homehostname=$( host `cat .homehost` | awk '{print $NF}' | sed 's/\.$//' ) |
︙ | ︙ |
Modified utils/installall.logpro from [8a1c71a14c] to [d90d1e784b].
1 2 | ;; (c) 2006,2007,2008,2009 Matthew Welland matt@kiatoa.com ;; | > > > > > > > > > > > > | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | ;; (c) 2006,2007,2008,2009 Matthew Welland matt@kiatoa.com ;; ;; Copyright 2006-2017, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. ;; first ensure your run at least started ;; (trigger "Body" #/^.*$/) ;; anything starts the body ;; (trigger "EndBody" #/This had better never match/) (section "Body" "Body" "EndBody") |
︙ | ︙ |
Modified utils/installall.sh from [5277c0ad22] to [f674f29713].
1 2 3 4 5 6 7 8 9 | #! /usr/bin/env bash # This file installs prerequisites for megatest (chicken, eggs, etc.) # Before running this script, set PREFIX environment variable # to chicken install target area. /opt/chicken is a typical value # set -x # Copyright 2007-2014, Matthew Welland. # | > > > | < > > > | | > > > > | > > > > > > | | | | | | > > | | > > > > > > > > > > > > > > > > | | | | | > > > > > > > > | | | > > | | | > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 | #! /usr/bin/env bash # This file installs prerequisites for megatest (chicken, eggs, etc.) # Before running this script, set PREFIX environment variable # to chicken install target area. /opt/chicken is a typical value # set -x # Copyright 2007-2014, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. # echo OPTION=$OPTION # BKM for ubuntu 17.04: # sudo dpkg -i libpng12-0_1.2.54-1ubuntu1_amd64.deb # sudo dpkg -i libpng12-0_1.2.54-1ubuntu1_amd64.deb if [[ $OPTION == "" ]]; then export OPTION=std fi echo You may need to do the following first: echo sudo apt install libreadline-dev echo sudo apt install libwebkitgtk-dev echo sudo apt install libpangox-1.0-0 zlib1g-dev libfreetype6-dev cmake echo sudo apt install libssl-dev uuid-dev echo sudo apt install libmotif3 -OR- set KTYPE=26g4 echo sudo apt install cmake curl ruby wget echo echo Set OPTION to std, currently OPTION=$OPTION echo echo Additionally, if you want mysql-client, you will need to make sure echo mysql_config is in your path echo for postgres to install dbi libpq-dev echo echo You are using PREFIX=$PREFIX echo You are using proxy="$proxy" echo echo "Set additional_libpath to help find gtk or other libraries, don't forget a leading :" SYSTEM_TYPE=$(lsb_release -irs |tr ' ' '_' |tr '\n' '-')$(uname -i)-$OPTION CHICKEN_VERSION=4.10.0 CHICKEN_BASEVER=4.10.0 # Set up variables # case $SYSTEM_TYPE in Ubuntu-17.10-x86_64-std) KTYPE=32 CDVER=5.11.1 IUPVER=3.22 IMVER=3.12 # CHICKEN_VERSION=4.12.0 # CHICKEN_BASEVER=4.12.0 ;; Ubuntu-17.04-x86_64-std) KTYPE=32 CDVER=5.11.1 IUPVER=3.22 IMVER=3.12 # CHICKEN_VERSION=4.12.0 # CHICKEN_BASEVER=4.12.0 ;; Ubuntu-16.04-x86_64-std) KTYPE=32 CDVER=5.11.1 IUPVER=3.22 IMVER=3.12 # CHICKEN_VERSION=4.12.0 # CHICKEN_BASEVER=4.12.0 ;; Ubuntu-16.04-x86_64-new) KTYPE=32 CDVER=5.11.1 IUPVER=3.22 IMVER=3.12 CHICKEN_VERSION=4.13.0 CHICKEN_BASEVER=4.13.0 ;; Ubuntu-16.04-i686-std) KTYPE=32 CDVER=5.11.1 IUPVER=3.22 IMVER=3.12 # CHICKEN_VERSION=4.12.0 # CHICKEN_BASEVER=4.12.0 ;; SUSE_LINUX_11-x86_64-std) KTYPE=26g4 CDVER=5.11.1 IUPVER=3.22 IMVER=3.12 ;; CentOS_5.11-x86_64-std) KTYPE=24g3 CDVER=5.4.1 IUPVER=3.5 IMVER=3.6.3 ;; esac echo SYSTEM_TYPE=$SYSTEM_TYPE echo KTYPE=$KTYPE echo CDVER=$CDVER echo IUPVER=$IUPVER echo IMVER=$IMVER echo CHICKEN_VERSION=$CHICKEN_VERSION echo CHICKEN_BASEVER=$CHICKEN_BASEVER # NOTES: # # Centos with security setup may need to do commands such as following as root: # # NB// fix the paths first # # for a in /localdisk/chicken/4.8.0/lib/*.so;do chcon -t textrel_shlib_t $a; done |
︙ | ︙ | |||
99 100 101 102 103 104 105 106 107 108 109 110 111 112 | sleep 5 if [[ $proxy == "" ]]; then echo 'Please set the environment variable "proxy" to host.com:port (e.g. foo.com:1234) to use a proxy' echo PROX="" else export http_proxy=http://$proxy export PROX="-proxy $proxy" fi if [[ $KTYPE == "" ]]; then echo 'Using KTYPE=26' export KTYPE=26g4 else | > | 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 | sleep 5 if [[ $proxy == "" ]]; then echo 'Please set the environment variable "proxy" to host.com:port (e.g. foo.com:1234) to use a proxy' echo PROX="" else export http_proxy=http://$proxy export https_proxy=http://$proxy export PROX="-proxy $proxy" fi if [[ $KTYPE == "" ]]; then echo 'Using KTYPE=26' export KTYPE=26g4 else |
︙ | ︙ | |||
151 152 153 154 155 156 157 | cd chicken-${CHICKEN_VERSION} # make PLATFORM=linux PREFIX=$PREFIX spotless make PLATFORM=linux PREFIX=$PREFIX make PLATFORM=linux PREFIX=$PREFIX install cd $BUILDHOME fi cd $BUILDHOME | > | | > | | | | | | | | > | | | > > > > > > > > > > > > > | | | | > > | > | | > < < < < < < < < < < < < < < < < < | > | > > > > | | < < > | 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 | cd chicken-${CHICKEN_VERSION} # make PLATFORM=linux PREFIX=$PREFIX spotless make PLATFORM=linux PREFIX=$PREFIX make PLATFORM=linux PREFIX=$PREFIX install cd $BUILDHOME fi cd $BUILDHOME #if [[ ! -e 1.0.0.tar.gz ]];then # wget --no-check-certificate https://github.com/nanomsg/nanomsg/archive/1.0.0.tar.gz # mv 1.0.0 1.0.0.tar.gz #fi if ! [[ -e $PREFIX/lib/libnanomsg.so ]]; then wget --no-check-certificate https://github.com/nanomsg/nanomsg/archive/1.0.0.tar.gz mv 1.0.0 1.0.0.tar.gz tar xf 1.0.0.tar.gz cd nanomsg-1.0.0 ./configure --prefix=$PREFIX make make install CSC_OPTIONS="-I$PREFIX/include -L$PREFIX/lib" $CHICKEN_INSTALL $PROX nanomsg fi cd $BUILDHOME export SQLITE3_VERSION=3090200 if ! [[ -e $PREFIX/bin/sqlite3 ]]; then echo Install sqlite3 sqlite3_tgz=sqlite-autoconf-$SQLITE3_VERSION.tar.gz if ! [[ -e tgz/$sqlite3_tgz ]]; then wget http://www.sqlite.org/2015/$sqlite3_tgz mv $sqlite3_tgz tgz fi if ! [[ -e $PREFIX/bin/sqlite3 ]] ; then if [[ -e tgz/sqlite-autoconf-$SQLITE3_VERSION.tar.gz ]]; then tar xfz tgz/sqlite-autoconf-$SQLITE3_VERSION.tar.gz (cd sqlite-autoconf-$SQLITE3_VERSION;./configure --prefix=$PREFIX;make;make install) fi fi fi if ! [[ -e $PREFIX/bin/pg_config ]]; then echo Install Postgresql pgsql_tgz=postgresql-9.6.4.tar.gz if ! [[ -e tgz/$pgsql_tgz ]]; then wget -c https://ftp.postgresql.org/pub/source/v9.6.4/$pgsql_tgz mv $pgsql_tgz tgz fi if ! [[ -e $PREFIX/bin/pg_config ]]; then if [[ -e tgz/$pgsql_tgz ]]; then tar xfz tgz/$pgsql_tgz (cd postgresql-9.6.4; ./configure --prefix=$PREFIX --with-openssl; make; make install) fi fi fi cd $BUILDHOME for egg in "sqlite3" sql-de-lite nanomsg do echo "Installing $egg" CSC_OPTIONS="-I$PREFIX/include -L$PREFIX/lib -L$PREFIX/lib64" $CHICKEN_INSTALL $PROX -keep-installed $egg #CSC_OPTIONS="-I$PREFIX/include -L$PREFIX/lib -L$PREFIX/lib64" $CHICKEN_INSTALL $PROX $egg if [ $? -ne 0 ]; then echo "$egg failed to install" exit 1 fi done # Some eggs are quoted since they are reserved to Bash # for f in matchable readline apropos base64 regex-literals format "regex-case" "test" coops trace csv dot-locking posix-utils posix-extras directory-utils hostinfo tcp rpc csv-xml fmt json md5; do # $CHICKEN_INSTALL $PROX -keep-installed matchable readline apropos base64 regex-literals format "regex-case" "test" coops trace csv dot-locking posix-utils posix-extras directory-utils hostinfo tcp rpc csv-xml fmt json md5 awful http-client spiffy uri-common intarweb http-client spiffy-request-vars md5 message-digest http-client spiffy-directory-listing for egg in matchable readline apropos base64 regex-literals format "regex-case" "test" \ coops trace csv dot-locking posix-utils posix-extras directory-utils hostinfo \ tcp rpc csv-xml fmt json md5 awful http-client:0.7.1 spiffy uri-common intarweb http-client \ spiffy-request-vars s md5 message-digest spiffy-directory-listing ssax sxml-serializer \ sxml-modifications z3 call-with-environment-variables \ pathname-expand typed-records \ logpro \ simple-exceptions numbers crypt parley srfi-42 \ alist-lib ansi-escape-sequences args basic-sequences bindings chicken-doc chicken-doc-cmd \ cock condition-utils debug define-record-and-printer easyffi easyffi-base \ expand-full ezxdisp filepath foof-loop ini-file irc lalr lazy-seq \ locale locale-builtin locale-categories locale-components locale-current locale-posix \ locale-timezone loops low-level-macros procedural-macros refdb rfc3339 scsh-process \ sexp-diff sha1 shell slice srfi-101 srfi-19 srfi-19-core srfi-19-date srfi-19-io \ srfi-19-period srfi-19-support srfi-19-time srfi-19-timezone srfi-29 srfi-37 srfi-78 syslog \ udp uuid uuid-lib zlib postgresql do echo "Installing $egg" $CHICKEN_INSTALL $PROX -keep-installed $egg #$CHICKEN_INSTALL $PROX $egg if [ $? -ne 0 ]; then echo "$egg failed to install" exit 1 fi done if [[ ! -e $PREFIX/lib/chicken/7/mysql-client.so ]];then if [[ -e `which mysql_config` ]]; then $CHICKEN_INSTALL $PROX mysql-client fi fi cd $BUILDHOME cd `$PREFIX/bin/csi -p '(chicken-home)'` curl http://3e8.org/pub/chicken-doc/chicken-doc-repo.tgz | tar zx cd $BUILDHOME # $CHICKEN_INSTALL $PROX sqlite3 cd $BUILDHOME if [[ `uname -a | grep x86_64` == "" ]]; then export ARCHSIZE='' else export ARCHSIZE=64_ fi # export files="cd-5.4.1_Linux${KTYPE}_lib.tar.gz im-3.6.3_Linux${KTYPE}_lib.tar.gz iup-3.5_Linux${KTYPE}_lib.tar.gz" if [[ x$USEOLDIUP == "x" ]];then export files="cd/cd-${CDVER}_Linux${KTYPE}_${ARCHSIZE}lib.tar.gz im/im-${IMVER}_Linux${KTYPE}_${ARCHSIZE}lib.tar.gz iup/iup-${IUPVER}_Linux${KTYPE}_${ARCHSIZE}lib.tar.gz" else echo WARNING: Using old IUP libraries export files="cd/cd-5.4.1_Linux${KTYPE}_${ARCHSIZE}lib.tar.gz im/im-3.6.3_Linux${KTYPE}_${ARCHSIZE}lib.tar.gz iup/iup-3.5_Linux${KTYPE}_${ARCHSIZE}lib.tar.gz" fi echo $files mkdir -p $PREFIX/iuplib mkdir -p iup/ for a in $files ; do targfile=$(echo $a | cut -d'/' -f2) if ! [[ -e tgz/$a ]] ; then echo wget -c -O tgz/$a http://www.kiatoa.com/matt/chicken-build/$a wget -c http://www.kiatoa.com/matt/chicken-build/$a mv $targfile tgz/ fi if ! [[ -e tgz/$targfile ]] ; then echo "ERROR: Failed to get http://www.kiatoa.com/matt/chicken-build/$a, please report this to matt@kiatoa.com" exit 1 fi echo Untarring tgz/$targfile into $BUILDHOME/lib tar -xzf tgz/$targfile -C iup/ done cp iup/include/* $PREFIX/include/ cp iup/*.so $PREFIX/lib/ cp iup/*.a $PREFIX/lib/ cp iup/ftgl/lib/*/* $PREFIX/lib/ cd $BUILDHOME # ffcall obtained from: # cvs -z3 -d:pserver:anonymous@cvs.savannah.gnu.org:/sources/libffcall co ffcall |
︙ | ︙ | |||
317 318 319 320 321 322 323 324 325 326 | cp -f hs $PREFIX/bin/hs cd ../mutils $PREFIX/bin/chicken-install cd ../dbi $PREFIX/bin/chicken-install cd ../margs $PREFIX/bin/chicken-install fi cd $BUILDHOME | > > | | 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 | cp -f hs $PREFIX/bin/hs cd ../mutils $PREFIX/bin/chicken-install cd ../dbi $PREFIX/bin/chicken-install cd ../margs $PREFIX/bin/chicken-install cd ../pkts $PREFIX/bin/chicken-install fi cd $BUILDHOME if [[ ! -e $PREFIX/bin/stmlrun ]] ; then #fossil clone http://www.kiatoa.com/fossils/stml stml.fossil wget -c -O stml.tar.gz 'http://www.kiatoa.com/fossils/stml/tarball?name=stml&uuid=trunk' tar -xzf stml.tar.gz cd stml #fossil open ../stml.fossil cp install.cfg.template install.cfg echo "TARGDIR=$PREFIX/bin" > install.cfg |
︙ | ︙ | |||
344 345 346 347 348 349 350 | export CSCLIBS=`echo $LD_LIBRARY_PATH | sed 's/:/ -L/g'` IUPEGGVER='iup' if [[ $IUPVER == "3.5" ]]; then IUPEGGVER='iup:1.2.1' fi #CSC_OPTIONS="-I$PREFIX/include -L$CSCLIBS" $CHICKEN_INSTALL $PROX -D no-library-checks -feature disable-iup-web iup | | > | | > > > | 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 | export CSCLIBS=`echo $LD_LIBRARY_PATH | sed 's/:/ -L/g'` IUPEGGVER='iup' if [[ $IUPVER == "3.5" ]]; then IUPEGGVER='iup:1.2.1' fi #CSC_OPTIONS="-I$PREFIX/include -L$CSCLIBS" $CHICKEN_INSTALL $PROX -D no-library-checks -feature disable-iup-web iup CSC_OPTIONS="-I$PREFIX/include -L$PREFIX/lib" $CHICKEN_INSTALL $PROX -D no-library-checks -feature disable-iup-web -feature disable-iup-pplot $IUPEGGVER # CSC_OPTIONS="-I$PREFIX/include -L$CSCLIBS" $CHICKEN_INSTALL $PROX -D no-library-checks -feature disable-iup-web -deploy -prefix $DEPLOYTARG iup # iup:1.0.2 CSC_OPTIONS="-I$PREFIX/include -L$PREFIX/lib" $CHICKEN_INSTALL $PROX -D no-library-checks canvas-draw # CSC_OPTIONS="-I$PREFIX/include -L$CSCLIBS" $CHICKEN_INSTALL $PROX -D no-library-checks -deploy -prefix $DEPLOYTARG canvas-draw cd $BUILDHOME # install ducttape if [[ -e ../ducttape ]];then cd ../ducttape $CHICKEN_INSTALL else echo "ducttape egg not found at ../ducttape. You will need to cd into the ducttape directory in the megatest distribution and run \"chicken-install\"" fi cd $BUILDHOME echo You may need to add $LD_LIBRARY_PATH to your LD_LIBRARY_PATH variable, a setup-chicken4x.sh echo file can be found in the current directory which should work for setting up to run chicken4x echo Testing iup $PREFIX/bin/csi -b -eval '(use iup)(print "Success")' |
Modified utils/installck.sh from [7eb094e9b0] to [2992cfb0b8].
1 2 3 4 5 6 7 8 9 | #!/bin/bash myhome=$(dirname $0) if [[ $proxy == "" ]]; then echo 'Please set the environment variable "proxy" to host.com:port (e.g. foo.com:1234) to use a proxy' echo PROX="" else export http_proxy=http://$proxy | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | #!/bin/bash # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. myhome=$(dirname $0) if [[ $proxy == "" ]]; then echo 'Please set the environment variable "proxy" to host.com:port (e.g. foo.com:1234) to use a proxy' echo PROX="" else export http_proxy=http://$proxy |
︙ | ︙ |
Modified utils/loadrunner from [ba6e3962e1] to [b74a707821].
1 2 3 4 5 6 7 8 9 | #!/bin/bash LOADRUNNER=$0 # load=`uptime|awk '{print $10}'|cut -d, -f1` load=$(uptime|perl -pe 's/.*: (\d+.\d+),.*/$1/') load2=$(uptime|perl -pe 's/.*: (\d+.\d+), (\d+.\d+),.*/$2/') # echo "load2=$load2, load=$load" | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | #!/bin/bash # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. LOADRUNNER=$0 # load=`uptime|awk '{print $10}'|cut -d, -f1` load=$(uptime|perl -pe 's/.*: (\d+.\d+),.*/$1/') load2=$(uptime|perl -pe 's/.*: (\d+.\d+), (\d+.\d+),.*/$2/') # echo "load2=$load2, load=$load" |
︙ | ︙ |
Modified utils/loadrunner.scm.notfinished from [a8651ba3f3] to [110a1f3c3c].
1 2 3 | ;; Copyright 2006-2013, Matthew Welland. ;; | | | > > > > > | | > | > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | ;; Copyright 2006-2013, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. (use ssax) (use sxml-serializer) (use sxml-modifications) (use regex) (use srfi-69) (use regex-case) |
︙ | ︙ |
Modified utils/lock-stats.sh from [84d255afaf] to [f04d649bde].
1 2 3 4 5 6 7 8 9 | #!/bin/bash while IFS=': ' read x x x x p x x i x; do if ! [[ ${i}x == "x" ]];then if ! $(echo $i|grep EOF >/dev/null);then fname=$(find -L "/proc/$p/fd" -maxdepth 1 -inum "$i" -exec readlink {} \; -quit) if $(echo $fname | grep megatest.db > /dev/null) || \ $(echo $fname | egrep '.db/\d+.db' > /dev/null);then echo $fname | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | #!/bin/bash # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. while IFS=': ' read x x x x p x x i x; do if ! [[ ${i}x == "x" ]];then if ! $(echo $i|grep EOF >/dev/null);then fname=$(find -L "/proc/$p/fd" -maxdepth 1 -inum "$i" -exec readlink {} \; -quit) if $(echo $fname | grep megatest.db > /dev/null) || \ $(echo $fname | egrep '.db/\d+.db' > /dev/null);then echo $fname |
︙ | ︙ |
Added utils/memproblem.scm version [e8b2f8fd7a].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 | ;; Copyright 2006-2017, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. ;; ;; Run like this: ((adjust the "30" number to a value that fills memory on the machine you are using) ;; script -c "free -g ; utils/memproblem 30 -:hm128G" memclean.log ;; Fill the cache with something like this: ;; find /path/to/lots/of/files/ -type f -exec cat {} > /dev/null \; (use posix numbers srfi-4) (define num-iter (or (if (> (length (argv)) 2) (string->number (cadr (argv))) #f) 43)) ;; Gigs memory to try to allocate ;; (print "Allocating up to " memsize "G memory. Note that due to the usage of the heap this will actually use up to " (* 2 memsize) "G") (define (get-free) (let ((indat (with-input-from-pipe "free" read-lines))) (map string->number (cdr (string-split (cadr indat)))))) (define-inline (cached dat)(list-ref dat 5)) (define-inline (used dat)(list-ref dat 1)) (define-inline (free dat)(list-ref dat 2)) (define-inline (k->G val)(/ val 1e6)) (define-inline (G->k val)(* val 1e6)) (define start-time (current-milliseconds)) (let loop ((n 0) (dat (get-free)) (stuff '())) (let ((bigvec (make-u32vector 200000000)) (startt (current-milliseconds))) (print "Value at 100: " (u32vector-ref bigvec 100) " ms to access: " (- (current-milliseconds) startt)) (u32vector-set! bigvec (random 190000000) 111) (print n " Elapsed time: " (/ (- (current-milliseconds) start-time) 1000) " s " "Cached: " (k->G (cached dat)) " G " "Used: " (k->G (used dat)) " G ") (if (< n num-iter) (loop (+ n 1)(get-free) (cons bigvec stuff))))) (exit) |
Modified utils/mk_wrapper from [9bb7f8caf7] to [e11fc37257].
1 2 3 4 5 6 7 | #!/bin/bash prefix=$1 cmd=$2 target=$3 if [ "$LD_LIBRARY_PATH" != "" ];then | > > > > > > > > > > > > > > > > > > > > > > > > > > < > > > > > > < < < < < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | #!/bin/bash # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. prefix=$1 cmd=$2 target=$3 cfgfile="$prefix/bin/.$(lsb_release -sr)/cfg.sh" # we wish to create a var in cfg.sh for finding sqlite3 executable chicken_bin_dir=$(dirname $(which csi)) if [[ -e $chicken_bin_dir/sqlite3 ]];then sqlite3_exe=$chicken_bin_dir/sqlite3 else sqlite3_exe=$(which sqlite3) fi if [ "$LD_LIBRARY_PATH" != "" ];then echo "INFO: Using LD_LIBRARY_PATH=$LD_LIBRARY_PATH" >&2 ( cat << __EOF if [ -z \$MT_ORIG_ENV ]; then export MT_ORIG_ENV=\$( $prefix/bin/serialize-env ) fi if [ "\$LD_LIBRARY_PATH" != "" ];then export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:\$LD_LIBRARY_PATH else export LD_LIBRARY_PATH=$LD_LIBRARY_PATH fi export MT_SQLITE3_EXE=$sqlite3_exe __EOF ) > $cfgfile echo else echo "INFO: LD_LIBRARY_PATH not set" >&2 fi echo "#!/bin/bash" > $target if [[ $cmd =~ dboard ]]; then cat >> $target <<'EOF' # # disable if not running on homehost # if [[ -e .homehost ]]; then |
︙ | ︙ | |||
55 56 57 58 59 60 61 62 | exit 1 fi fi EOF fi echo "lsbr=\$(lsb_release -sr)" >> $target | > > > > > > > > > > > | | 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 | exit 1 fi fi EOF fi cat >> $target << EOF if [[ \$(ulimit -a | grep 'open files' | awk '{print \$4}') -gt 10000 ]];then ulimit -n 10000;fi EOF # echo "#!/bin/bash" > $target # echo "exec $prefix/bin/.\$(lsb_release -sr)/$cmd \"\$@\"" >> $target echo "lsbr=\$(lsb_release -sr)" >> $target if [ "$LD_LIBRARY_PATH" != "" ];then echo "source $prefix/bin/.\$lsbr/cfg.sh" >> $target fi # echo "if [[ -e \$lsbr ]];then source \$lsbr;fi" >> $target echo "exec $prefix/bin/.\$lsbr/$cmd \"\$@\"" >> $target |
Modified utils/mt_ezstep from [6865452478] to [c3b3a9d270].
1 2 | #!/bin/bash | | | < | > | | > > > > > > > > > > | | | < < | | < > > > > > > > > > > > > < < < < < < < < < | > | < < < < | < < | < | < | > | > | < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 | #!/bin/bash # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. usage="mt_ezstep stepname command [args ...]" # Purpose: This is for the [ezsteps] secton in your testconfig file. # DO NOT USE IN YOUR SCRIPTS! # # Call like this: # mt_ezstep stepname prevstepname command .... # if [[ "x$1" == "x" ]];then echo "Usage: $usage" exit fi # Since the user may not have . on the path and since we are likely to want to # run test scripts in the current directory add the current dir to the path export PATH=$PATH:$PWD testrundir=$1; shift stepname=$1;shift command=$* allstatus=99 runstatus=99 logpropstatus=99 # prev_env=".ezsteps/${prevstepname}.sh" # echo "prev_env=$prev_env" # if [[ -e "${prev_env}" ]];then # source $prev_env # fi # source the environment from the previous step if it exists cd $testrundir #if [[ "$MT_CMDINFO" == "" ]];then if [[ -e megatest.sh ]];then source megatest.sh else echo "ERROR: $0 should be run within a megatest test environment" echo "Usage: $usage" exit fi #fi # if a logpro file exists then use it otherwise just run the command, nb// was using 2>&1 if [[ -e ${stepname}.logpro ]];then eval $command 2>&1 ${stepname}.log runstatus=$? logpro ${stepname}.logpro ${stepname}.html &> /dev/null < ${stepname}.log logprostatus=$? if [[ $runstatus == 0 ]]; then exitstatus=$logprostatus else exitstatus=$runstatus fi else eval $command &> ${stepname}.log exitstatus=$? fi exit $exitstatus |
Modified utils/mt_laststep from [b984c38ecb] to [fae58533b9].
1 2 3 4 5 6 7 8 9 | #!/bin/bash if [ $MT_CMDINFO == "" ];then echo "ERROR: $0 should be run within a megatest test environment" exit fi # Purpose: run a step, record start and end with exit codes, if sucessful # update test status with PASS, else update with FAIL | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | #!/bin/bash # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. if [ $MT_CMDINFO == "" ];then echo "ERROR: $0 should be run within a megatest test environment" exit fi # Purpose: run a step, record start and end with exit codes, if sucessful # update test status with PASS, else update with FAIL |
︙ | ︙ |
Modified utils/mt_runstep from [35ded54591] to [effc903bf9].
1 2 3 4 5 6 7 8 9 | #!/bin/bash # Purpose: run a step, record start and end with exit codes # # Call like this: # mt_runstep stepname command .... # # This expects that you have a logpro file named stepname.logpro and must be run # inside a test environment (click on xterm button on a test control panel | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | #!/bin/bash # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. # Purpose: run a step, record start and end with exit codes # # Call like this: # mt_runstep stepname command .... # # This expects that you have a logpro file named stepname.logpro and must be run # inside a test environment (click on xterm button on a test control panel |
︙ | ︙ |
Modified utils/mt_xterm from [40d98efdc8] to [868b69899e].
1 2 3 4 5 6 7 8 9 | #!/bin/bash MT_TMPDISPLAY=$DISPLAY if [ -e megatest.sh ];then source megatest.sh fi export DISPLAY=$MT_TMPDISPLAY if [ x"$MT_XTERM_CMD" == "x" ];then | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | #!/bin/bash # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. MT_TMPDISPLAY=$DISPLAY if [ -e megatest.sh ];then source megatest.sh fi export DISPLAY=$MT_TMPDISPLAY if [ x"$MT_XTERM_CMD" == "x" ];then |
︙ | ︙ |
Modified utils/mtgetfile from [071134089a] to [003893808f].
1 2 3 4 5 6 7 8 9 | #!/bin/bash fullparams="$@" function findfile () { megatest $fullparams -repl <<EOF (let* ((numargs (length remargs)) (path (if (> numargs 0)(car remargs) #f)) (scriptn (if (> numargs 1)(cadr remargs) #f)) | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | #!/bin/bash # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. fullparams="$@" function findfile () { megatest $fullparams -repl <<EOF (let* ((numargs (length remargs)) (path (if (> numargs 0)(car remargs) #f)) (scriptn (if (> numargs 1)(cadr remargs) #f)) |
︙ | ︙ |
Added utils/mtrept.sh version [4ab1fc4a2b].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 | #!/bin/bash # # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. # Rollup counts of calls to Megatest from a logging dat file # # Usage: mtrept.sh file [host] if [[ "$2"x != "x" ]];then host_name_grep="grep $2 | " else host_name_grep="" fi if [[ "$1"x == "x" ]];then datfile=/p/fdk/gwa/$USER/.logger/all.dat else datfile=$1 fi datcopy=/tmp/$USER/all.$PID.dat if [[ -e $datfile ]];then cp $datfile $datcopy list_runs=$(grep list-runs $datcopy |$host_name_grep wc -l) show_config=$(grep show-config $datcopy |$host_name_grep wc -l) list_targets=$(grep list-targets $datcopy |$host_name_grep wc -l) mt_run=$(grep ' -run ' $datcopy |$host_name_grep wc -l) execute=$(grep ' -execute' $datcopy|$host_name_grep wc -l) server=$(grep ' -server' $datcopy|$host_name_grep wc -l) sync_to=$(grep ' -sync-to' $datcopy|$host_name_grep wc -l) step=$(grep ' -step' $datcopy|$host_name_grep wc -l) state_status=$(grep ' -set-state-status' $datcopy|$host_name_grep wc -l) test_status=$(grep ' -test-status' $datcopy|$host_name_grep wc -l) other=$(egrep -v ' -(list-runs|show-config|list-targets|run|execute|server|sync-to|step|set-state-status|test-status)' $datcopy |$host_name_grep wc -l) start_time=$(head -1 $datcopy|awk '{print $1}') end_time=$(tail -1 $datcopy | awk '{print $1}') minutes=$(echo "($end_time-$start_time)/60.0" | bc) hours=$(echo "($minutes/60)"|bc) total_calls=$(cat $datcopy |$host_name_grep wc -l) if [[ $hours -gt 2 ]];then echo "Over $hours hour period we have;" else echo "Over $minutes minutes we have;" fi echo " list-runs: $list_runs" echo " show-config: $show_config" echo " list-targets: $list_targets" echo " execute: $execute" echo " run: $mt_run" echo " server: $server" echo " step: $step" echo " test-status: $test_status" echo " sync-to: $sync_to" echo " state-status: $state_status" echo " other: $other" echo " total: $total_calls" else echo "Could not find input file $datfile" fi |
Modified utils/mtrunner from [ee53d3f91b] to [68e483031e].
1 2 3 4 5 6 7 8 9 10 11 12 13 | #! /bin/bash # Run megatest from within megatest # Usage: mtrunner testsuite_dir megatest_bin_dir command args .... for var in $(env | egrep "^MT_"|cut -d= -f1);do unset ${var} done cd $1 shift export PATH="$1:$PATH" shift | > > > > > > > > > > > > > > > > > | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | #! /bin/bash # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. # Run megatest from within megatest # Usage: mtrunner testsuite_dir megatest_bin_dir command args .... for var in $(env | egrep "^MT_"|cut -d= -f1);do unset ${var} done cd $1 shift export PATH="$1:$PATH" shift exec "$@" |
Modified utils/mtrunscript from [e78e46f29a] to [1a61a1f2c4].
1 2 3 | #!/usr/bin/env bash # Copyright 2012, Matthew Welland. | | > > > | < > > | > | | | | < > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | #!/usr/bin/env bash # Copyright 2012, Matthew Welland. # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. # set -e # set -u # set -x # Usage: mtrunscript scriptname params # |
︙ | ︙ |
Modified utils/mtutils.csh from [23f4997ab4] to [6bd5da1b2e].
1 2 3 4 5 6 7 8 9 10 | # Better to use the mt_* snippet scripts in utils # To use the snippets set PREFIX then install with "make installall" alias mt_runstep 'set argv=(\!*); \ set stepname = $1;shift; \ megatest -runstep $stepname -logpro ${stepname}.logpro "$*" || exit $?' alias mt_laststep 'set argv=(\!*);set stepname = $1;shift; \ megatest -runstep $stepname -logpro ${stepname}.logpro "$*" ; \ set exitstatus = $? ; \ | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | # Better to use the mt_* snippet scripts in utils # To use the snippets set PREFIX then install with "make installall" # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. alias mt_runstep 'set argv=(\!*); \ set stepname = $1;shift; \ megatest -runstep $stepname -logpro ${stepname}.logpro "$*" || exit $?' alias mt_laststep 'set argv=(\!*);set stepname = $1;shift; \ megatest -runstep $stepname -logpro ${stepname}.logpro "$*" ; \ set exitstatus = $? ; \ |
︙ | ︙ |
Modified utils/nbfake from [bfff85f08b] to [c26c7b18f9].
1 2 3 4 5 6 7 8 | #!/bin/bash ############################################################################### # # nbfake - capture command output in a logfile # # nbfake behavior can be changed by setting the following env vars: # NBFAKE_HOST SSH to $NBFAKE_HOST and run command # NBFAKE_LOG Logfile for nbfake output | > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | #!/bin/bash # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. ############################################################################### # # nbfake - capture command output in a logfile # # nbfake behavior can be changed by setting the following env vars: # NBFAKE_HOST SSH to $NBFAKE_HOST and run command # NBFAKE_LOG Logfile for nbfake output |
︙ | ︙ |
Modified utils/nbfind from [03c58ee4f1] to [845fc2490b].
1 2 3 4 5 6 7 8 9 | #!/bin/bash # load=`uptime|awk '{print $10}'|cut -d, -f1` load=`uptime|perl -pe 's/.*: (\d+.\d+),.*/$1/'` if which cpucheck > /dev/null;then numcpu=`cpucheck|tail -1|awk '{print $6}'` else numcpu=`lscpu|grep "CPU.s.:"|awk '{print $2}'` fi | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | #!/bin/bash # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. # load=`uptime|awk '{print $10}'|cut -d, -f1` load=`uptime|perl -pe 's/.*: (\d+.\d+),.*/$1/'` if which cpucheck > /dev/null;then numcpu=`cpucheck|tail -1|awk '{print $6}'` else numcpu=`lscpu|grep "CPU.s.:"|awk '{print $2}'` fi |
︙ | ︙ |
Modified utils/plot-code.scm from [2b66df6bfd] to [2b6e0cd992].
1 2 3 4 5 6 7 8 | #!/mfs/pkgs/chicken/4.8.0.5/bin/csi -nbq ;; Coming soon (right?) Usage: plot-code file1.scm,file2.scm "fun1,fun2,x*" *.scm > plot.dot ;; Usage: plot-code file1.scm,file2.scm *.scm > plot.dot ;; dot -Tpdf plot.dot > plot.pdf ;; first param is comma separated list of files to include in the map, use - to do all ;; second param is list of regexs for functions to include in the map ;; third param is list of files to scan | > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | #!/mfs/pkgs/chicken/4.8.0.5/bin/csi -nbq ;; Copyright 2006-2017, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. ;; ;; Coming soon (right?) Usage: plot-code file1.scm,file2.scm "fun1,fun2,x*" *.scm > plot.dot ;; Usage: plot-code file1.scm,file2.scm *.scm > plot.dot ;; dot -Tpdf plot.dot > plot.pdf ;; first param is comma separated list of files to include in the map, use - to do all ;; second param is list of regexs for functions to include in the map ;; third param is list of files to scan |
︙ | ︙ |
Modified utils/remrun from [836fc55fdd] to [7a107135c8].
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | #!/bin/bash ############################################################################### # # remrun - same behavior as nbfake but first param is a hosthane # (capture command output in a logfile) # # remrun behavior can be changed by setting the following env var: # NBFAKE_LOG Logfile for nbfake output # ############################################################################### if [[ -z "$@" ]]; then cat <<__EOF remrun usage: remrun hostname <command to run> | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | #!/bin/bash ############################################################################### # # remrun - same behavior as nbfake but first param is a hosthane # (capture command output in a logfile) # # remrun behavior can be changed by setting the following env var: # NBFAKE_LOG Logfile for nbfake output # ############################################################################### # # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. if [[ -z "$@" ]]; then cat <<__EOF remrun usage: remrun hostname <command to run> |
︙ | ︙ |
Modified utils/revtagfsl.scm from [48b6acfe19] to [387217d7c0].
1 2 3 | ;; Copyright 2006-2013, Matthew Welland. ;; | | | > > > > > | | > | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | ;; Copyright 2006-2013, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. ;; (use json regex posix) (use srfi-69) ;; Add tags with node nums: trunk(12) (define fname #f) |
︙ | ︙ |
Added utils/run2mock.scm version [19fe62ea8b].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 | #!/p/foundry/env/pkgs/chicken/4.10.1_v1.63/bin/csi -s ; -*- Mode: Scheme; -*- ;; Copyright 2006-2017, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. ;; (use ducttape-lib) (use posix-extras pathname-expand regex matchable) (use ini-file) ;; plugs a hole in posix-extras in latter chicken versions (define ##sys#expand-home-path pathname-expand) (define (realpath x) (resolve-pathname (pathname-expand (or x "/dev/null")) )) ;; resolve fullpath to this script (define (get-this-script-fullpath #!key (argv (argv))) (let* ((this-script (cond ((and (> (length argv) 2) (string-match "^(.*/csi|csi)$" (car argv)) (string-match "^-(s|ss|sx|script)$" (cadr argv))) (caddr argv)) (else (car argv)))) (fullpath (realpath this-script))) fullpath)) (define *this-script-fullpath* (get-this-script-fullpath)) (define *this-script-dir* (pathname-directory *this-script-fullpath*)) (define *this-script-name* (pathname-strip-directory *this-script-fullpath*)) (define (false-on-exception thunk) (handle-exceptions exn #f (thunk) )) (define (safe-file-exists? path-string) (false-on-exception (lambda () (file-exists? path-string)))) (define (crude-config-transformer infile outfile keep-sections-list append-text #!key (filter-patt #f)) (let* ((inlines (with-input-from-file infile read-lines)) (keep-lines (let loop ((lines-left inlines) (lines-out '()) (current-section #f) (section-lines-accumulator '())) (let* ((this-line (if (not (null? lines-left)) (car lines-left) "")) (section-match (string-match "^\\s*\\[([^\\]]+)\\].*" this-line))) (cond ((null? lines-left) (if (member current-section keep-sections-list) (append lines-out (reverse section-lines-accumulator)) lines-out)) (section-match (let* ((next-lines-left (cdr lines-left)) (next-lines-out (if (member current-section keep-sections-list) (append lines-out (reverse section-lines-accumulator)) lines-out)) (next-current-section (cadr section-match)) (next-section-lines-accumulator (list this-line))) (loop next-lines-left next-lines-out next-current-section next-section-lines-accumulator))) (else (let* ((next-lines-left (cdr lines-left)) (next-lines-out lines-out) (next-current-section current-section) (next-section-lines-accumulator (cond ((and filter-patt (string-match (conc "^.*"filter-patt".*$") this-line)) section-lines-accumulator) (else (cons this-line section-lines-accumulator))))) (loop next-lines-left next-lines-out next-current-section next-section-lines-accumulator)))))))) (with-output-to-file outfile (lambda () (print (string-join keep-lines "\n")) (print) (print append-text) (print))))) (define (testconfig-transformer infile outfile) (crude-config-transformer infile outfile '("meta" "items" "requirements" "test_meta") (conc " [ezsteps] alwayspass /bin/true "))) (let* ((mtexe "/p/foundry/env/pkgs/megatest/1.64/31/bin/megatest") (faux-mtra "/p/fdk/gwa/bjbarcla/issues/mtdev/ch/cap/faux") (src-mtra "/nfs/pdx/disks/icf_fdk_asic_gwa002/asicfdkqa/fossil/megatestqa/afdkqa") (target "p1275/5/ADF_r0.7_s/9p27t_tp0") (run "ww38.4") (src-mtdb (conc src-mtra "/megatest.db")) (extra-src-testdirs '("/p/fdk/gwa/asicfdkqa/fossil/ext/afdkqa_ext/trunk/tests")) (mtconf (with-input-from-pipe (conc "cd "src-mtra" && "mtexe" -show-config -target "target) read)) (runconf (with-input-from-pipe (conc "cd "src-mtra" && "mtexe" -show-runconfig -dumpmode sexp -target "target) read)) (testdir-alist (alist-ref "tests-paths" mtconf equal?)) (testdirs (filter safe-file-exists? (append extra-src-testdirs (list (conc src-mtra "/tests")) (if (and testdir-alist (not (null? testdir-alist))) (map cadr testdir-alist) '())))) (tconfigfiles (apply append (map (lambda (src-testdir) (with-input-from-pipe (conc "ls -1 "src-testdir"/*/testconfig") read-lines)) testdirs))) (tconf-alist (filter identity (map (lambda (tcfile) (let* ((m (string-match "^.*/([^/]+)/testconfig$" tcfile))) (if (not (null? m)) (cons (cadr m) tcfile) #f))) tconfigfiles)))) ; (pp mtconf) ; (pp (list 'FOO testdir-alist)) (exit 1) ;; make megatest area (when (not (file-exists? src-mtdb)) (ierr "Source does not exist. Aborting. [src-mtdb]") (exit 1)) (when (file-exists? faux-mtra) (system (conc "cd "faux-mtra" && rm -rf $(/p/foundry/env/bin/mttmpdir)")) (system (conc "rm -rf "faux-mtra))) (system (conc "mkdir -p "faux-mtra)) (system (conc "mkdir -p "faux-mtra"/links")) (system (conc "mkdir -p "faux-mtra"/disk0")) (system (conc "cd "src-mtra" && "mtexe" -show-config -target "target" -dumpmode ini > "faux-mtra"/megatest.config.in")) (crude-config-transformer (conc faux-mtra"/megatest.config.in") (conc faux-mtra"/megatest.config") '("fields" "server" "env-override" "dashboard" "validvalues") (conc "[setup] linktree "faux-mtra"/links max_concurrent_jobs 1000 launch-delay 5 use-wal 1 " ;; emacs has trouble if a string has [ at the beginning of line, so breaking it up. "[disks] disk0 "faux-mtra"/disk0") filter-patt: "MT_LINKTREE" ) (system (conc "cd "src-mtra" && "mtexe" -show-runconfig -target "target" -dumpmode ini > "faux-mtra"/runconfigs.config")) (system (conc "mkdir -p "faux-mtra"/tests")) (for-each (lambda (tpair) (pp tpair) (let* ((testname (car tpair)) (src-tconfigfile (cdr tpair)) (destdir (conc faux-mtra"/tests/"testname))) (do-or-die (conc "mkdir -p "destdir)) (do-or-die (conc "cp "src-tconfigfile" "destdir"/testconfig.in")) (testconfig-transformer (conc destdir"/testconfig.in") (conc destdir"/testconfig")) (print "processed test "testname))) tconf-alist) ) |
Modified utils/runner from [229dc9c405] to [429ba71354].
1 2 3 4 5 6 7 8 9 | #!/usr/bin/perl -w $starthr=`date +%k`; $hrsper = 1; $nexthr=$starthr + $hrsper; $ltr='a'; while (1) { | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | #!/usr/bin/perl -w # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. $starthr=`date +%k`; $hrsper = 1; $nexthr=$starthr + $hrsper; $ltr='a'; while (1) { |
︙ | ︙ |
Deleted utils/trace/trace.import.scm version [937dcb55c1].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted utils/trace/trace.meta version [9714181a62].
|
| < < < < < < < < < < |
Deleted utils/trace/trace.scm version [dc3560e035].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted utils/trace/trace.setup version [d222d610b4].
|
| < < < < < < < < < |
Modified utils/triage.rb from [1b394ae2b3] to [54791236c4].
1 2 3 4 5 6 7 8 9 | #!/usr/bin/env ruby #dir = "." #if ARGV.length == 1 # dir = ARGV[0] #end #puts dir #exit 1 | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | #!/usr/bin/env ruby # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. #dir = "." #if ARGV.length == 1 # dir = ARGV[0] #end #puts dir #exit 1 |
︙ | ︙ |
Modified utils/unlock_db.sh from [c92810209b] to [c822e4d964].
1 2 3 4 5 6 7 8 9 | #!/bin/bash ## Enh : # 1. if /tmp/repo exists, delte it or name it something else # 2. compare the repo is successfully created ## Usage : # unlock_db.sh <database-name/complete path> | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | #!/bin/bash # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. ## Enh : # 1. if /tmp/repo exists, delte it or name it something else # 2. compare the repo is successfully created ## Usage : # unlock_db.sh <database-name/complete path> |
︙ | ︙ |
Modified utils/viewscreen from [df19e653be] to [fe2bbf9f4f].
1 2 3 4 5 6 7 8 9 | #!/bin/bash if ! type screen &> /dev/null;then xterm -geometry 180x20 -e "$*;echo Press any key to continue;bash -c 'read -n 1 -s'" & exit fi if [[ $(screen -list | egrep 'Attached|Detached'|awk '{print $1}') == "" ]];then # echo "No screen found for displaying to. Run \"screen\" in an xterm" | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | #!/bin/bash # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. if ! type screen &> /dev/null;then xterm -geometry 180x20 -e "$*;echo Press any key to continue;bash -c 'read -n 1 -s'" & exit fi if [[ $(screen -list | egrep 'Attached|Detached'|awk '{print $1}') == "" ]];then # echo "No screen found for displaying to. Run \"screen\" in an xterm" |
︙ | ︙ |
Added utils/watch-close-wait.sh version [d54fe2c8d0].
> > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. psline=$(ps -F -u $USER | grep "mtest" |grep " -run " | egrep " -(target|reqtarg) "| head -1) id=$(echo $psline|awk '{print $2}') echo "Watching process for command line: $psline" echo " with PID=$id" while true;do echo "CLOSE_WAIT: $(lsof -n | grep CLOSE_WAIT | grep $id | wc -l) ALL OPEN: $(lsof -n |grep $id|wc -l) ALL CLOSE_WAIT: $(netstat -ap 2> /dev/null| grep -i close_wait| wc -l)" sleep 1 done |
Added utils/whodunit.scm version [dae56f8cd6].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 | ;; Copyright 2006-2017, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. ;; (use posix srfi-69) (define *numsamples* (or (and (> (length (argv)) 1) (string->number (cadr (argv)))) 3)) (define (topdata) (with-input-from-pipe (conc "top -b -n " *numsamples* " -d 0.1") read-lines)) (define (cleanup-data topdat)list (let loop ((hed (car topdat)) (tal (cdr topdat)) (res '())) (let* ((line-list (string-split hed)) (nums (map (lambda (indat)(or (string->number indat) indat)) line-list)) (not-data (or (null? nums) (not (number? (car nums))))) (new-res (if not-data res (cons nums res)))) (if (null? tal) new-res (loop (car tal)(cdr tal) new-res))))) (print "Getting " *numsamples* " samples of cpu usage data.") (define data (cleanup-data (topdata))) (define pidhash (make-hash-table)) (define userhash (make-hash-table)) ;; sum up and normalize the (for-each (lambda (indat) (let ((pid (car indat)) (usr (cadr indat)) (cpu (list-ref indat 8))) (hash-table-set! userhash usr (+ cpu (hash-table-ref/default userhash usr 0))))) data) (for-each (lambda (usr) (print usr (if (< (string-length usr) 8) "\t\t" "\t") (inexact->exact (round (/ (hash-table-ref userhash usr) *numsamples*))))) (sort (hash-table-keys userhash) (lambda (a b) (> (hash-table-ref userhash a) (hash-table-ref userhash b))))) |
Deleted utils/wip/mtest-dbstop.scm version [f84335871c].
|
| < < < < < < < < < < < < |
Deleted utils/wip/mtest-diag.scm version [7f6edef793].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted utils/wip/mtest-nbstop.scm version [7b4c78c86f].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted utils/wip/mtest-reaper.scm version [b3b10d5f69].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted utils/wip/mtest-repair-lib.scm version [c317aec679].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted utils/wip/mtest-repair.scm version [abac938a88].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Modified vg-test.scm from [3a58c56b03] to [ee1267e1a2].
1 2 3 4 5 6 7 | (use canvas-draw iup foof-loop) (import canvas-draw-iup) (load "vg.scm") (define numtorun 1000) ;; (if (> (length (argv)) 1) | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | ;; Copyright 2006-2017, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. ;; (use canvas-draw iup foof-loop) (import canvas-draw-iup) (load "vg.scm") (define numtorun 1000) ;; (if (> (length (argv)) 1) |
︙ | ︙ |
Modified vg.scm from [2067ad836c] to [48b3b2908c].
1 2 3 | ;; ;; Copyright 2016 Matthew Welland. ;; | | | > > > > > | | > | > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | ;; ;; Copyright 2016 Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. ;; strftime('%m/%d/%Y %H:%M:%S','now','localtime') (use typed-records srfi-1) (declare (unit vg)) (use canvas-draw iup) |
︙ | ︙ | |||
553 554 555 556 557 558 559 | (prev-foreground-color (canvas-foreground cnv))) ;; (if fill-color ;; (begin ;; (canvas-foreground-set! cnv fill-color) ;; (canvas-box! cnv llx ulx lly uly))) ;; docs are all over the place on this one.;; w h) (if line-color (canvas-foreground-set! cnv line-color) | | | 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 | (prev-foreground-color (canvas-foreground cnv))) ;; (if fill-color ;; (begin ;; (canvas-foreground-set! cnv fill-color) ;; (canvas-box! cnv llx ulx lly uly))) ;; docs are all over the place on this one.;; w h) (if line-color (canvas-foreground-set! cnv line-color) #;(if fill-color (canvas-foreground-set! cnv prev-foreground-color))) (canvas-line! cnv llx ulx lly uly) (canvas-foreground-set! cnv prev-foreground-color) (if text (let* ((prev-font (canvas-font cnv)) (font-changed (and font (not (equal? font prev-font))))) (if font-changed (canvas-font-set! cnv font)) |
︙ | ︙ |
Modified vg_records.scm from [c48b950cb7] to [67dafc9ef0].
1 2 3 4 5 6 7 8 9 | ;; Created by records.sh. DO NOT EDIT THIS FILE. Edit records.sh instead ;; Generated using make-vector-record -safe vg lib comps (use simple-exceptions) (define vg:lib-exn (make-exception "wrong record type, expected vg:lib." 'assert)) (define (pmake-vg:lib . params)(let ((v (if (null? params)(make-vector 2)(apply vector 'vg:lib params)))) v)) (define (make-vg:lib #!key (comps #f) ) | > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | ;; Created by records.sh. DO NOT EDIT THIS FILE. Edit records.sh instead ;; Generated using make-vector-record -safe vg lib comps ;; Copyright 2006-2017, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. ;; (use simple-exceptions) (define vg:lib-exn (make-exception "wrong record type, expected vg:lib." 'assert)) (define (pmake-vg:lib . params)(let ((v (if (null? params)(make-vector 2)(apply vector 'vg:lib params)))) v)) (define (make-vg:lib #!key (comps #f) ) |
︙ | ︙ |
Modified widgets.scm from [3d56925ea9] to [dcc875399e].
1 2 3 4 5 6 7 | (require-library srfi-4 iup) (import srfi-4 iup iup-pplot iup-glcanvas) ;; iup-web (define (popup dlg . args) (apply show dlg #:modal? 'yes args) (destroy! dlg)) | > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | ;; Copyright 2006-2017, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. (require-library srfi-4 iup) (import srfi-4 iup iup-pplot iup-glcanvas) ;; iup-web (define (popup dlg . args) (apply show dlg #:modal? 'yes args) (destroy! dlg)) |
︙ | ︙ |
Added wrappers/cfg.sh version [b56bcbd346].
> > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. if [ -z $MT_ORIG_ENV ]; then export MT_ORIG_ENV=$( PREFIX/bin/serialize-env ) fi if [ "$LD_LIBRARY_PATH" != "" ];then export LD_LIBRARY_PATH=PREFIX:PREFIX/lib:PREFIX/lib64:$LD_LIBRARY_PATH else export LD_LIBRARY_PATH=PREFIX:PREFIX/lib:PREFIX/lib64 fi |
Added wrappers/dashboard version [9ebc005d67].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | #!/bin/bash # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. # # disable if not running on homehost # if [[ -e .homehost ]]; then # homehostname=$( host `cat .homehost` | awk '{print $NF}' | sed 's/\.$//' ) # hostname=$( hostname -f ) # # if [[ ! ($homehostname == $hostname) ]]; then # echo "ERROR: this host ($hostname) is not the homehost ($homehostname) for this megatest run area. Cannot start dashboard." # echo " Please log into homehost before launching dashboard." # exit 1 # fi # fi # check that $DISPLAY is set if [[ -z $DISPLAY ]]; then echo 'ERROR: $DISPLAY environment variable is not set; megatest dashboard requires X display address to be set in $DISPLAY.' exit 1 fi # check that $DISPLAY is proper if [[ -x $(which xdpyinfo 2>/dev/null) ]]; then if ! xdpyinfo -display "$DISPLAY" &>/dev/null; then echo 'ERROR: megatest dashboard cannot open display "'$DISPLAY'". Please check $DISPLAY environment variable.' exit 1 fi fi if [[ $(ulimit -a | grep 'open files' | awk '{print $4}') -gt 10000 ]];then ulimit -n 10000;fi lsbr=$(lsb_release -sr) source PREFIX/ARCHSTR/cfg.sh exec PREFIX/dboard "$@" |
Added wrappers/megatest version [b2fbc4db18].
> > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | #!/bin/bash # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. if [[ $(ulimit -a | grep 'open files' | awk '{print $4}') -gt 20000 ]];then ulimit -n 20000;fi lsbr=$(lsb_release -sr) source PREFIX/ARCHSTR/cfg.sh exec PREFIX/mtest "$@" |