Changes In Branch v1.65 Through [3acb83c0e6] Excluding Merge-Ins
This is equivalent to a diff from ade6384a7b to 3acb83c0e6
2020-12-15
| ||
13:29 | Modified to install .so files only on sles12 check-in: 4b250051d9 user: mmgraham tags: v1.65, v1.6579 | |
11:37 | Added path to .so libraries to LD_LIBRARY_PATH in cfg.sh check-in: 3acb83c0e6 user: mmgraham tags: v1.65 | |
2020-12-14
| ||
12:02 | Added installation of the .so files, changed their location check-in: 204c375230 user: mmgraham 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>. |
Added DONE version [b7b86aa11f].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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/>. NOTE: This file gets copied occasionally into the wiki as "Roadmap DONE". Do not make changes in the wiki, they will be lost! DONE ==== WW14 . Streamline compilation - DONE, all non-official egg modules are now bundled. WW15 . syscheck; touch file in home, tmp, runs, links and start xterm [DONE] WW16 . archiving improvements/extentions [DONE] .. -get-data, -put-data [DONE] .. use MT_ vars if defined and no switch present [DONE] .. fix archive "first run" bug [DONE] .. areas path1 path2 ... -> search path for archives [NOT NEEDED - use -start-dir] .. -propagate -> move archive data forward when it is found in older bundles [NOT NEEDED - simply repost the data] |
Modified Makefile from [a8eded8e26] to [3b78bc7f1e].
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 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 | # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more 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 \ 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 = adjutant.scm mutils.scm mttop.scm # ftail.scm rmtmod.scm commonmod.scm removed # MSRCFILES = ducttape-lib.scm pkts.scm stml2.scm cookie.scm mutils.scm \ # mtargs.scm commonmod.scm dbmod.scm adjutant.scm ulex.scm \ # rmtmod.scm apimod.scm 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)) # compiled import files MOIMPFILES = $(MSRCFILES:%.scm=%.import.o) %.import.o : %.import.scm csc $(CSCOPTS) -unit $*.import -c $*.import.scm -o $*.import.o # I'm not sure the cp is a good idea, changed a lot of things and it may not have been necessary... # mofiles/%.o %.import.scm : %.scm megatest-fossil-hash.scm # @[ -e mofiles ] || mkdir -p mofiles # csc $(CSCOPTS) -I mofiles -I $* -J -c $< -o $*.o # cp $*.o mofiles/$*.o # @touch $*.import.scm # ensure it is touched after the .o is made 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) $(MOIMPFILES) megatest-version.scm csc $(CSCOPTS) $(OFILES) $(MOFILES) $(MOIMPFILES) megatest.o -o mtest showmtesthash: @echo $(MTESTHASH) dboard : $(OFILES) $(GOFILES) dashboard.scm $(MOFILES) $(MOIMPFILES) megatest-version.scm megatest-fossil-hash.scm csc $(CSCOPTS) $(OFILES) dashboard.scm $(GOFILES) $(MOFILES) $(MOIMPFILES) -o dboard mtut: $(OFILES) $(MOFILES) megatest-fossil-hash.scm mtut.scm megatest-version.scm csc $(CSCOPTS) $(OFILES) $(MOFILES) mtut.scm -o mtut include makefile.inc include chicken.makefile 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 \ ods.o \ portlogger.o \ process.o \ rmt.o \ runconfig.o \ runs.o \ server.o \ tasks.o \ tdb.o \ tests.o \ subrun.o \ ezsteps.o # mofiles/rmtmod.o \ # mofiles/commonmod.o \ tcmt : $(TCMTOBJS) tcmt.scm megatest-version.scm csc $(CSCOPTS) $(TCMTOBJS) $(MOFILES) $(MOIMPFILES) 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 # Special dependencies for the includes $(MOFILE) $(MOIMPFILES) : megatest-fossil-hash.scm # common.o : mofiles/commonmod.o megatest-fossil-hash.scm # commonmod.o dashboard.o megatest.o tcmt.o apimod.o : megatest-fossil-hash.scm 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 megatest-fossil-hash.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 megatest-version.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 megatest-version.scm common_records.scm : altdb.scm # mofiles/stml2.o : mofiles/cookie.o # configf.o : mofiles/commonmod.o vg.o dashboard.o : vg_records.scm megatest-version.scm dcommon.o : run_records.scm mofiles/stml2.o : mofiles/cookie.o # # special include based modules # mofiles/pkts.o : pkts/pkts.scm # mofiles/stml2.o : cookie.o # # mofiles/mtargs.o : mtargs/mtargs.scm # # mofiles/mtconfigf.o : mtconfigf/mtconfigf.scm # mofiles/ulex.o : ulex/ulex.scm # mofiles/mutils.o : mutils/mutils.scm # mofiles/cookie.o : stml2/cookie.scm # mofiles/stml2.o : stml2/stml2.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/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 $@ | | < < < < | 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 | $(INSTALL) $< $@ chmod a+x $@ $(PREFIX)/bin/nbfind : utils/nbfind $(INSTALL) $< $@ chmod a+x $@ $(PREFIX)/bin/mtrunner : utils/mtrunner $(INSTALL) $< $@ chmod a+x $@ deploytarg/nbfake : utils/nbfake $(INSTALL) $< $@ chmod a+x $@ deploytarg/viewscreen : utils/viewscreen $(INSTALL) $< $@ chmod a+x $@ |
︙ | ︙ | |||
187 188 189 190 191 192 193 194 195 | # 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 \ | > > > > > > > > > > | > > > > > > | > > | > > > > > > > > > > > > < < < < < < < < < < < < < < | | | | | > | < < | > | > > < < > | | > > > > > > > > > > > > > > > > > > > > | 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 | # 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 $(PREFIX)/bin/.$(ARCHSTR)/lib/libpangox-1.0.so : lib/libpangox-1.0.so $(INSTALL) lib/libpangox-1.0.so $(PREFIX)/bin/.$(ARCHSTR)/lib/libpangox-1.0.so $(PREFIX)/bin/.$(ARCHSTR)/lib/libpangox-1.0.so.0 : lib/libpangox-1.0.so.0 $(INSTALL) lib/libpangox-1.0.so.0 $(PREFIX)/bin/.$(ARCHSTR)/lib/libpangox-1.0.so.0 $(PREFIX)/bin/.$(ARCHSTR)/lib/libxcb-xlib.so.0 : lib/libxcb-xlib.so.0 $(INSTALL) lib/libxcb-xlib.so.0 $(PREFIX)/bin/.$(ARCHSTR)/lib/libxcb-xlib.so.0 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)/lib/libpangox-1.0.so \ $(PREFIX)/bin/.$(ARCHSTR)/lib/libpangox-1.0.so.0 \ $(PREFIX)/bin/.$(ARCHSTR)/lib/libxcb-xlib.so.0 # $(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 readline-fix.scm serialize-env dboard *.o \ megatest-fossil-hash.* altdb.scm mofiles/*.o \ mofiles/*.o vg.o cookie.o dashboard-main.o \ ducttape-lib.o ftail.o mutils.o pkts.o rmtmod.o stml2.o \ tcmt.o *.import.scm *.import.o 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 #====================================================================== # Deploy section (not complete yet) #====================================================================== $(DEPLOYHELPERS) : utils/mt_* $(INSTALL) $< $@ chmod a+X $@ deploytarg/apropos.so : Makefile chicken-install -p deploytarg -deploy -keep-installed $(EGGS) deploy : deploytarg/mtest deploytarg/dboard $(DEPLOYHELPERS) deploytarg/nbfake deploytarg/remrun deploytarg/viewsceen deploytarg/nbfind deploytarg/apropos.so # puts deployed megatest in directory "megatest" deploytarg/mtest : $(OFILES) megatest.o deploytarg/apropos.so csc -deploy $(CSCOPTS) $(OFILES) megatest.scm -o deploytarg mv deploytarg/deploytarg deploytarg/mtest deploytarg/dboard : $(OFILES) $(GOFILES) dashboard.scm deploytarg/apropos.so csc -deploy $(OFILES) $(GOFILES) dashboard.scm -o deploytarg mv deploytarg/deploytarg deploytarg/dboard datashare-testing/sd : datashare.scm $(OFILES) csc $(CSCOPTS) datashare.scm $(OFILES) -o datashare-testing/sd datashare-testing/sdat: sharedat.scm $(OFILES) csc $(CSCOPTS) sharedat.scm $(OFILES) -o datashare-testing/sdat 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) megatest-version.scm csc $(CSCOPTS) spublish.scm margs.o process.o common.o -o datashare-testing/spublish datashare-testing/sretrieve : sretrieve.scm $(OFILES) megatest-version.scm csc $(CSCOPTS) sretrieve.scm margs.o process.o common.o -o datashare-testing/sretrieve datashare-testing/sauthorize : sauthorize.scm $(OFILES) megatest-version.scm csc $(CSCOPTS) sauthorize.scm 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 readline-fix.scm : if [[ $(shell chicken-status | grep readline | awk '{print $4}' | cut -d. -f1) -gt 3 ]];then \ echo "(define *use-new-readline* #f)" > readline-fix.scm; \ else \ echo "(define *use-new-readline* #t)" > readline-fix.scm;\ fi 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 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 mt.o ods.o portlogger.o process.o rmt.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 mt.o ods.o portlogger.o process.o rmt.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 [0b75f67e74].
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 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/>. (server:writable-watchdog-bruteforce dbstruct) (server:writable-watchdog-deltasync dbstruct) ===================================================================== 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 | > > > > | 161 162 163 164 165 166 167 168 169 170 171 | 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 [0885dee1e5].
|
| > | > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | # Copyright 2006-2020, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more 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 ==== WW38 . Add test_rundat to no-sync ==> correction, put in <testdir>/.meta/test-run.dat . Add STATE/STATUS transitions to .meta/test-run.dat or similar . Swizzle update-test-rundat to operate on no-sync . Swizzle update-run-duration, -uname-host and cpuload-diskfree to no-sync . On state/status change update tests table with duration WW15 . fill newview matrix with data, filter pipeline gui elements . improve [script], especially indent handling WW16 . split db into megatest.db (runs etc.) db/<something>.db . release basic newview implementation WW18 . release split db implementation . mtutil calls from dashboard (for remote control) . logs browser (esp. for surfacing mtutil related activities) WW19 . break command line into sections; all, run control, queries, utilities etc. . pull in ftfplan (not integrated, just code pulled in) WW20 . ./configure => ubuntu, sles11, sles12, rh7 . Add output flushing in teamcity support . Switch to using simple runs query everywhere . Add end_time to runs and add a rollup call that sets state, status and end_time Future . Switch to scsh-process pipeline management for job execution/control . Use call-with-environment-variables more. 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 |
Added adjutant.scm version [d6c67b1549].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 2017, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more 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 adjutant)) (module adjutant * (import scheme chicken data-structures extras files) (import (prefix sqlite3 sqlite3:) posix typed-records srfi-18 srfi-69 md5 message-digest matchable regex srfi-1) (define (adjutant-run host-type rmt:no-sync-take-job) (print "Running the adjutant!") (let loop ((wait-count 0)) (if (< wait-count 10) ;; 6 x 10 seconds = one minute (let* ((dat (rmt:no-sync-take-job host-type))) (match dat ((id ht vars exekey cmdline state event-time last-update) (system cmdline) (loop 0)) (else (thread-sleep! 10) (loop (+ wait-count 1))))) (print "I'm bored. Exiting.")))) ) |
Modified api.scm from [9ab20f89e3] to [2de2a631a2].
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 | ;;====================================================================== ;; 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-tests-for-run-state-status 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 drop-all-triggers create-all-triggers update-tesdata-on-repilcate-db ;; TESTMETA testmeta-add-record testmeta-update-field ;; TASKS tasks-add tasks-set-state-given-param-key )) ;; These are called by the server on recipt of /api calls ;; - keep it simple, only return the actual result of the call, i.e. no meta info here ;; ;; - returns #( flag result ) ;; (define (api:execute-requests dbstruct dat) (handle-exceptions exn (let ((call-chain (get-call-chain))) (debug:print 0 *default-log-port* "WARNING: api:execute-requests received an exception from peer, dat=" dat ", exn=" exn) (print-call-chain (current-error-port)) (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 (common:safe-vector-ref dat 0 'nocmd)) (cmd (if (symbol? cmd-in) cmd-in (string->symbol cmd-in))) (params (common:safe-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 ;;=============================================== ((nocmd) '(#f "All broken!")) ((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)) ((inc-var) (apply db:inc-var dbstruct params)) ((dec-var) (apply db:dec-var dbstruct params)) ((del-var) (apply db:del-var dbstruct params)) ((add-var) (apply db:add-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)) ((create-all-triggers) (db:create-all-triggers dbstruct)) ((drop-all-triggers) (db:drop-all-triggers dbstruct)) ;; 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)) ((no-sync-add-job) (apply db:no-sync-add-job *no-sync-db* params)) ((no-sync-take-job) (apply db:no-sync-take-job *no-sync-db* params)) ((no-sync-job-records-clean) (apply db:no-sync-job-records-clean *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)) ((get-keys) (db:get-keys dbstruct)) |
︙ | ︙ | |||
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)) | | > | > > > > > > > > > > > > | > > > > > | > > > > | | | | 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 | ((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)) ((update-tesdata-on-repilcate-db) (apply db:update-tesdata-on-repilcate-db dbstruct params)) ((get-tests-for-run) (apply db:get-tests-for-run dbstruct params)) ((get-tests-for-run-state-status) (apply db:get-tests-for-run-state-status 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 ;; (define (api:process-request dbstruct $) ;; the $ is the request vars proc (set! *api-process-request-count* (+ *api-process-request-count* 1)) (let* ((cmd ($ 'cmd)) (paramsj ($ 'params)) (params (db:string->obj paramsj transport: 'http)) ;; incoming data from the POST (or is it a GET?) (resdat (api:execute-requests dbstruct (vector cmd params))) ;; process the request, resdat = #( flag result ) (success (common:safe-vector-ref resdat 0 #f)) (res (common:safe-vector-ref resdat 1 #f))) ;; (vector flag payload), get the payload, ignore the flag (why?) (if (not success) (debug:print 0 *default-log-port* "ERROR: success flag is #f for " cmd " with params " params)) (if (> *api-process-request-count* *max-api-process-requests*) (set! *max-api-process-requests* *api-process-request-count*)) (set! *api-process-request-count* (- *api-process-request-count* 1)) ;; This can be here but needs controls to ensure it doesn't run more than every 4 seconds ;; (rmt:dat->json-str |
︙ | ︙ |
Added apimod.scm version [0c866deee4].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 2017, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more 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 apimod)) (declare (uses commonmod)) (declare (uses ulex)) (module apimod * (import scheme chicken data-structures extras) (import (prefix sqlite3 sqlite3:) posix typed-records srfi-18) (import commonmod) (import (prefix ulex ulex:)) (define (api:execute-requests params) #f) ) |
Modified archive.scm from [7dd47285c1] to [e54df630d3].
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 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 | (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. exn=" exn) (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 ) #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)) (target (string-intersperse (map cadr (rmt:get-key-val-pairs run-id)) "/")) (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))) (src-archive-linktree (rmt:get-var "src-archive-linktree")) (print-prefix "Running: ") ;; change to #f to turn off printing (preclean-spec (configf:get-section *configdat* "archive-preclean"))) (if (or (not src-archive-linktree) (not (equal? src-archive-linktree linktree))) (rmt:set-var "src-archive-linktree" linktree)) ;; (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)) (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 2 *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) "-"(string-substitute "/" "-" target " ")) (conc "--strip-path=" (conc test-base target "/" )) ;; 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 2 *default-log-port* "Init bup in " archive-dir) ;; (mutex-lock! bup-mutex) (let-values (((pid-val exit-status exit-code) (run-n-wait bup-exe params: bup-init-params print-cmd: print-prefix))) (if (not (eq? exit-code 0)) (begin (debug:print-error 0 *default-log-port* "There was an error initializing bup. Archive failed.") (exit 1)))) ;; (mutex-unlock! bup-mutex) )) (debug:print-info 2 *default-log-port* "Indexing data to be archived") ;; (mutex-lock! bup-mutex) (let-values (((pid-val exit-status exit-code) (run-n-wait bup-exe params: bup-index-params print-cmd: print-prefix))) (if (not (eq? exit-code 0)) (begin (debug:print-error 0 *default-log-port* "There was an error Indexing bup. Archive failed.") (exit 1)))) (debug:print-info 2 *default-log-port* "Archiving data with bup") (let-values (((pid-val exit-status exit-code) (run-n-wait bup-exe params: bup-save-params print-cmd: print-prefix))) (if (not (eq? exit-code 0)) (begin (debug:print-error 0 *default-log-port* "There was an archiving data with bup. Archive failed.") (exit 1)))))) ((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:megatest-db target-patt run-patt) (let* ((blockid-cache (make-hash-table)) (tsname (common:get-testsuite-name)) (min-space (string->number (or (configf:lookup *configdat* "archive" "minspace") "1000"))) (bup-exe (or (configf:lookup *configdat* "archive" "bup") "bup")) (compress (or (configf:lookup *configdat* "archive" "compress") "9")) (archiver (let ((s (configf:lookup *configdat* "archive" "archiver"))) (if s (string->symbol s) 'bup))) (rsync-exe (or (configf:lookup *configdat* "archive" "rsync") "rsync")) (print-prefix "Running: ") (archive-info (archive:allocate-new-archive-block blockid-cache *toppath* tsname min-space target-patt run-patt "megatest-db")) (archive-dir (if archive-info (cdr archive-info) #f)) (archive-id (if archive-info (car archive-info) -1)) (home-host (common:get-homehost)) (archive-time (seconds->std-time-str (current-seconds))) (archive-staging-db (conc *toppath* "/.db-snapshot/archive_" archive-time)) (tmp-db-path (conc (common:get-db-tmp-area) "/megatest.db")) (dbfile (conc archive-staging-db "/megatest.db"))) (create-directory archive-staging-db #t) (let-values (((pid-val exit-status exit-code) (run-n-wait rsync-exe params: (list "-v" (conc (car home-host) ":"tmp-db-path) archive-staging-db) print-cmd: print-prefix))) (if (eq? exit-code 0) (case archiver ((bup) ;; Archive using bup (let* ((bup-init-params (list "-d" archive-dir "init")) (bup-index-params (list "-d" archive-dir "index" archive-staging-db)) (bup-save-params (list "-d" archive-dir "save" ;; (conc "--strip-path=" linktree) (conc "-" compress) ;; or (conc "--compress=" compress) "-n" (conc tsname "-megatest-db" ) (conc "--strip-path=" archive-staging-db ) ;; if we push to the directory do we need this? dbfile))) (if (not (common:file-exists? (conc archive-dir "/HEAD"))) (begin ;; replace this with jobrunner stuff enventually (debug:print-info 2 *default-log-port* "Init bup in " archive-dir) (let-values (((pid-val exit-status exit-code)(run-n-wait bup-exe params: bup-init-params print-cmd: print-prefix))) (if (not (eq? exit-code 0)) (begin (debug:print-error 0 *default-log-port* "There was an error initializing bup. Archive failed.") (exit 1)))))) (debug:print-info 2 *default-log-port* "Indexing data to be archived") (let-values (((pid-val exit-status exit-code) (run-n-wait bup-exe params: bup-index-params print-cmd: print-prefix))) (if (not (eq? exit-code 0)) (begin (debug:print-error 0 *default-log-port* "There was an error Indexing bup. Archive failed.") (exit 1)))) (debug:print-info 2 *default-log-port* "Archiving data with bup") (let-values (((pid-val exit-status exit-code) (run-n-wait bup-exe params: bup-save-params print-cmd: print-prefix))) (if (not (eq? exit-code 0)) (begin (debug:print-error 0 *default-log-port* "There was an error archiving data with bup. Archive failed.") (exit 1)) (debug:print-info 2 *default-log-port* "To restore megatest.db run megatest -archive replicacte-db -source archive-dir -time-stamp <ts>. Current timestamp: " (seconds->std-time-str (current-seconds))))))) (else (debug:print-info 0 *default-log-port* "No support for databse archiving with " archiver))) (debug:print-error 0 *default-log-port* "There was an error rsyncing tmp database"))))) (define (archive:restore-db archive-path ts) (let* ((bup-exe (or (configf:lookup *configdat* "archive" "bup") "bup")) (archive-internal-path (conc (common:get-testsuite-name) "-megatest-db/" ts "/megatest.db" )) (bup-restore-params (list "-d" archive-path "restore" "-C" *toppath* archive-internal-path))) (debug:print-info 0 *default-log-port* "Restoring archived data to " *toppath* " from archive in " archive-path " ... " archive-internal-path) (run-n-wait bup-exe params: bup-restore-params print-cmd: #f)) (db:multi-db-sync (db:setup #f) 'killservers ;'dejunk ;'adj-testids 'old2new ) (debug:print-info 1 *default-log-port* "dropping trigerrs to update linktree") (rmt:drop-all-triggers) (let* ((linktree (common:get-linktree)) ;; (configf:lookup *configdat* "setup" "linktree"))) (src-archive-linktree (rmt:get-var "src-archive-linktree"))) (if (not (equal? src-archive-linktree linktree)) (rmt:update-tesdata-on-repilcate-db src-archive-linktree linktree)) (debug:print-info 1 *default-log-port* "creating triggers after updating linktree") (rmt:create-all-triggers) )) (define (archive:ls->list bup-exe archive-dir internal-path) (let ((cmd (conc bup-exe " -d " archive-dir " ls -l " internal-path "| awk '{print $6}' | sort")) (res '())) (handle-exceptions exn #f ;; anything goes wrong - assume the process in NOT running. (with-input-from-pipe cmd (lambda () (let* ((inl (read-lines))) (reverse inl))))))) (define (time-string->seconds tstr ds-flag) (let* ((atime (string->time tstr "%Y-%m-%d-%H%M%S"))) (vector-set! atime 8 ds-flag) (local-time->seconds atime))) (define (seconds->std-time-str sec) (time->string (seconds->local-time sec) "%Y-%m-%d-%H%M%S")) (define (archive:get-timestamp-dir bup-exe archive-dir testsuite-name target test-partial-path test-last-update) (print (seconds->std-time-str test-last-update)) (let* ((internal-path (conc testsuite-name "-" target)) (ts-list (archive:ls->list bup-exe archive-dir internal-path)) (ds-flag (vector-ref (seconds->local-time) 8))) (let loop ((hed (car ts-list)) (tail (cdr ts-list))) (if (and (null? tail) (equal? hed "latest")) #f (if (and (not (null? tail)) (equal? hed "latest")) (loop (car tail) (cdr tail)) (let* ((archive-seconds (time-string->seconds hed ds-flag))) (if (< (abs (- archive-seconds test-last-update)) 120) (let* ((test-list (archive:ls->list bup-exe archive-dir (conc internal-path "/" hed "/" test-partial-path)))) (if (> (length test-list) 0) hed (if (not (null? tail)) (loop (car tail) (cdr tail)) #f))) (if (null? tail) #f (loop (car tail) (cdr tail)))))))))) (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"))) |
︙ | ︙ | |||
226 227 228 229 230 231 232 | (test-id (db:test-get-id test-dat)) (run-id (db:test-get-run_id test-dat)) (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))) | | | > > | | > > > > > < | < < < > | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | (test-id (db:test-get-id test-dat)) (run-id (db:test-get-run_id test-dat)) (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 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)) (test-last-update (db:test-get-last_update 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-timestamp-dir (if archive-path (archive:get-timestamp-dir bup-exe archive-path (common:get-testsuite-name) (string-substitute "/" "-" target " ") test-partial-path test-last-update) #f)) (archive-internal-path (conc (common:get-testsuite-name) "-" (string-substitute "/" "-" target " ") "/" archive-timestamp-dir "/" 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 (not archive-timestamp-dir) (debug:print-error 0 *default-log-port* "Archive not found for testsuite" (common:get-testsuite-name) " run/test/itempath" test-partial-path) (begin ;; 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 (not toplevel/children)) (begin ;; CREATE WORK AREA ;; test-src-path == #f ==> don't copy in data from tests directory ;; itemdat == string ==> use directly (create-work-area run-id run-name keyvals test-id #f best-disk test-name item-path) ;; #!key (remtries 2)) ;; 1. Get the block id from the test info ;; 2. Get the block data given the block id ;; 3. Construct the paths etc. for the following command: ;; bup -d /tmp/matt/adisk1/2015_q1/fullrun_e1a40/ restore -C /tmp/seeme fullrun-30/latest/ubuntu/nfs/none/w02.1.20.54_b/ ;; DO BUP RESTORE (let* ((new-test-dat (rmt:get-test-info-by-id run-id test-id)) (new-test-path (if (vector? new-test-dat ) (db:test-get-rundir new-test-dat) (begin (debug:print-error 0 *default-log-port* "unable to get data for run-id=" run-id ", test-id=" test-id) (exit 1)))) ;; new-test-path won't work - must use best-disk instead? Nope, new-test-path but tack on /.. (bup-restore-params (list "-d" archive-path "restore" "-C" (conc new-test-path "/..") archive-internal-path))) (debug:print-info 0 *default-log-port* "Restoring archived data to " new-test-physical-path " from archive in " archive-path " ... " archive-internal-path) (debug:print-info 0 *default-log-port* bup-exe " " (string-join bup-restore-params " ")) ;; (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 [b49201d65c].
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].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Added chicken.makefile version [b07a513938].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | # Copyright 2006-2017, Matthew Welland. # # This file is part of Megatest. # # Megatest is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Megatest is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Megatest. If not, see <http://www.gnu.org/licenses/>. #====================================================================== # Chicken build #====================================================================== # CHICKEN_BIN_DIR=$(shell dirname $(shell which csi)) # if have csi on path use that, else use default # CSIPATH=$(shell which csi) # CKPATH=$(shell dirname $(shell dirname $(CSIPATH))) CHICKEN_PREFIX=$(or $(CKPATH),$(PREFIX)/bin/.$(ARCHSTR)) whatever : @echo "CHICKEN_PREFIX=$(CHICKEN_PREFIX)" tgz-$(USER)/postgresql-9.6.4.tar.gz : mkdir -p tgz-$(USER) wget -c https://ftp.postgresql.org/pub/source/v9.6.4/postgresql-9.6.4.tar.gz mv postgresql-9.6.4.tar.gz tgz-$(USER)/ tgz-$(USER)/sqlite-autoconf-3090200.tar.gz : mkdir -p tgz-$(USER) curl http://www.sqlite.org/2015/sqlite-autoconf-3090200.tar.gz > tgz-$(USER)/sqlite-autoconf-3090200.tar.gz tgz-$(USER)/nanomsg-1.0.0.tar.gz : wget --no-check-certificate https://github.com/nanomsg/nanomsg/archive/1.0.0.tar.gz mv 1.0.0.tar.gz tgz-$(USER)/nanomsg-1.0.0.tar.gz tgz-$(USER)/chicken-4.13.0.tar.gz : mkdir -p tgz-$(USER) curl https://code.call-cc.org/releases/4.13.0/chicken-4.13.0.tar.gz > tgz-$(USER)/chicken-4.13.0.tar.gz tgz-$(USER)/ffcall.tar.gz : wget -c -O tgz-$(USER)/ffcall.tar.gz 'http://www.kiatoa.com/fossils/ffcall/tarball?name=ffcall&uuid=trunk' $(CHICKEN_PREFIX)/bin/pg_config : tgz-$(USER)/postgresql-9.6.4.tar.gz mkdir -p build-$(USER)/ tar xfz tgz-$(USER)/postgresql-9.6.4.tar.gz -C build-$(USER) cd build-$(USER)/postgresql-9.6.4; ./configure --prefix=$(CHICKEN_PREFIX) --with-openssl; make; make install build-$(USER)/sqlite-autoconf-3090200/configure : tgz-$(USER)/sqlite-autoconf-3090200.tar.gz mkdir -p build-$(USER); cd build-$(USER); tar xf ../tgz-$(USER)/sqlite-autoconf-3090200.tar.gz $(CHICKEN_PREFIX)/lib/libnanomsg.so : tgz-$(USER)/nanomsg-1.0.0.tar.gz cd tgz-$(USER); tar -xzvf nanomsg-1.0.0.tar.gz cd tgz-$(USER)/nanomsg-1.0.0; mkdir build-$(USER); cd build-$(USER); cd tgz-$(USER)/nanomsg-1.0.0/build-$(USER); cmake ../ -DCMAKE_INSTALL_PREFIX=$(CHICKEN_PREFIX) cd tgz-$(USER)/nanomsg-1.0.0/build-$(USER); make; make install $(CHICKEN_PREFIX)/chicken-4.13.0/LICENSE : tgz-$(USER)/chicken-4.13.0.tar.gz mkdir -p build-$(USER)/eggs-installed cd build-$(USER);tar xf ../tgz-$(USER)/chicken-4.13.0.tar.gz if [[ -e $(CHICKEN_PREFIX)/chicken-4.13.0/LICENSE ]];then touch $(CHICKEN_PREFIX)/chicken-4.13.0/LICENSE;fi tgz-$(USER)/opensrc.fossil : cd tgz-$(USER); fossil clone http://www.kiatoa.com/fossils/opensrc opensrc.fossil mkdir tgz-$(USER)/opensrc cd tgz-$(USER)/opensrc; fossil open --nested ../opensrc.fossil; fossil up; fossil uv sync $(CHICKEN_PREFIX)/lib/libiupweb.so : tgz-$(USER)/opensrc.fossil cd tgz-$(USER)/opensrc; fossil unversioned cat libs/cd/cd-5.10_Linux26g4_64_lib.tar.gz > ../cd.tgz cd tgz-$(USER)/opensrc; fossil unversioned cat libs/im/im-3.11_Linux26g4_64_lib.tar.gz > ../im.tgz cd tgz-$(USER)/opensrc; fossil unversioned cat libs/iup/iup-3.19.1_Linux26g4_64_lib.tar.gz > ../iup.tgz cd tgz-$(USER); tar -xzf cd.tgz; cd tgz-$(USER); tar -xzf im.tgz; cd tgz-$(USER); tar -xzf iup.tgz; cp tgz-$(USER)/include/* $(CHICKEN_PREFIX)/include/ cp tgz-$(USER)/*.so $(CHICKEN_PREFIX)/lib/ cp tgz-$(USER)/*.a $(CHICKEN_PREFIX)/lib/ cp tgz-$(USER)/ftgl/lib/*/* $(CHICKEN_PREFIX)/lib/ EGGS=srfi-69 srfi-42 sqlite3 iup canvas-draw typed-records md5 regex-case base64 \ format dot-locking csv-xml z3 udp hostinfo directory-utils stack dbi crypt sha1 \ posix-extras pathname-expand csv call-with-environment-variables s11n spiffy \ uri-common intarweb http-client spiffy-request-vars spiffy-directory-listing \ ansi-escape-sequences test slice rfc3339 uuid-lib filepath srfi-19 sparse-vectors \ sql-de-lite fmt readline apropos json simple-exceptions rpc trace logpro refdb postgresql nanomsg EGGSTARG=$(addsuffix .done,$(addprefix build-$(USER)/eggs-installed/,$(EGGS))) EGGSTARG2=$(addsuffix .done, $(EGGS)) $(CHICKEN_PREFIX)/lib/libcallback.a : tgz-$(USER)/ffcall.tar.gz cd tgz-$(USER); tar -xzvf ffcall.tar.gz cd tgz-$(USER)/ffcall; ./configure --prefix=$(CHICKEN_PREFIX) --enable-shared cd tgz-$(USER)/ffcall; make CC="gcc -fPIC"; make install $(CHICKEN_PREFIX)/bin/sqlite3 : build-$(USER)/sqlite-autoconf-3090200/configure cd build-$(USER)/sqlite-autoconf-3090200; ./configure --prefix=$(CHICKEN_PREFIX); make; make install $(CHICKEN_PREFIX)/bin/csi : $(SQLITE3_DEP) $(CHICKEN_PREFIX)/lib/libiupweb.so $(CHICKEN_PREFIX)/chicken-4.13.0/LICENSE cd build-$(USER)/chicken-4.13.0;make PLATFORM=linux PREFIX=$(CHICKEN_PREFIX) cd build-$(USER)/chicken-4.13.0;make PLATFORM=linux PREFIX=$(CHICKEN_PREFIX) install ALL_CKBIN=chicken chicken-bind chicken-bug chicken-dump \ chicken-install chicken-profile chicken-sqlite3 chicken-status \ chicken-uninstall csc csi feathers nanocat sqlite3 vacuumdb logpro \ refdb CKBIN_WRAPPERS=$(addprefix $(PREFIX)/bin/,$(ALL_CKBIN)) $(PREFIX)/bin/% : $(CHICKEN_PREFIX)/bin/% $(CHICKEN_PREFIX)/bin/csi utils/mk_wrapper_tool $(PREFIX) $* $(PREFIX)/bin/$* chmod a+x $(PREFIX)/bin/$* $(PREFIX)/bin : mkdir -p $(PREFIX)/bin $(CHICKEN_PREFIX)/bin # For the future - binwrappers chicken : $(PREFIX)/bin $(CHICKEN_PREFIX)/bin/csi postgresql.done nanomsg.done iup.done canvas-draw.done sqlite3.done sql-de-lite.done dbi.done $(EGGSTARG2) @echo "Fake target to build prefix chicken" binwrappers : $(CKBIN_WRAPPERS) # make the dep a dummy if not requiring our own build of postgres ifeq ($(BUILD_POSTGRES),yes) PG_DEP=$(CHICKEN_PREFIX)/bin/pg_config else PG_DEP=$(CHICKEN_PREFIX)/bin/csi endif postgresql.done : $(PG_DEP) CSC_OPTIONS="-I$(CHICKEN_PREFIX)/include -L$(CHICKEN_PREFIX)/lib -L$(CHICKEN_PREFIX)/lib64" $(CHICKEN_PREFIX)/bin/chicken-install postgresql > postgresql.done ifeq ($(BUILD_NANOMSG),yes) NMSG_DEP=$(CHICKEN_PREFIX)/lib/libnanomsg.so else NMSG_DEP=$(CHICKEN_PREFIX)/bin/csi endif nanomsg.done : $(NMSG_DEP) CSC_OPTIONS="-I$(CHICKEN_PREFIX)/include -L$(CHICKEN_PREFIX)/lib -L$(CHICKEN_PREFIX)/lib64" $(CHICKEN_PREFIX)/bin/chicken-install nanomsg > nanomsg.done iup.done : $(CHICKEN_PREFIX)/lib/libcallback.a CSC_OPTIONS="-I$(CHICKEN_PREFIX)/include -L$(CHICKEN_PREFIX)/lib" $(CHICKEN_PREFIX)/bin/chicken-install -D no-library-checks -feature disable-iup-web -feature disable-iup-pplot -feature disable-iup-matrixex iup > iup.done canvas-draw.done : CSC_OPTIONS="-I$(CHICKEN_PREFIX)/include -L$(CHICKEN_PREFIX)/lib" $(CHICKEN_PREFIX)/bin/chicken-install -D no-library-checks canvas-draw > canvas-draw.done # make the dep a dummy if not requiring our own build of postgres ifeq ($(BUILD_SQLITE3),yes) SQLITE3_DEP=$(CHICKEN_PREFIX)/bin/sqlite3 else SQLITE3_DEP=$(CHICKEN_PREFIX)/bin/csi endif sqlite3.done : $(SQLITE3_DEP) CSC_OPTIONS="-I$(CHICKEN_PREFIX)/include -L$(CHICKEN_PREFIX)/lib" $(CHICKEN_PREFIX)/bin/chicken-install sqlite3 > sqlite3.done sql-de-lite.done : CSC_OPTIONS="-I$(CHICKEN_PREFIX)/include -L$(CHICKEN_PREFIX)/lib" $(CHICKEN_PREFIX)/bin/chicken-install sql-de-lite > sql-de-lite.done dbi.done : postgresql.done sqlite3.done sql-de-lite.done CSC_OPTIONS="-I$(CHICKEN_PREFIX)/include -L$(CHICKEN_PREFIX)/lib" $(CHICKEN_PREFIX)/bin/chicken-install dbi > dbi.done %.done : $(CHICKEN_PREFIX)/bin/chicken-install $* > $*.done build-$(USER)/eggs-installed/%.done : $(CHICKEN_PREFIX)/bin/csi $(EGGS) $(CHICKEN_PREFIX)/bin/chicken-install $* > build-$(USER)/eggs-installed/$*.done build-clean : rm -rf build-$(USER) bin |
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 [6aec6a8542].
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 | ;;====================================================================== ;; 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", exn=" exn) (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. (substring-index "." key)) ;; periods are not allowed in 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 ", exn=" exn) (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 | > > | 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 | ;; 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)) | > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | 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 | (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*)) ;; when called from a wrapper I need sometimes to find the calling ;; wrapper, this is for dashboard to find the correct megatest. ;; (define (common:find-local-megatest #!optional (progname "megatest")) (let ((res (filter file-exists? (map (lambda (updir) (let* ((lm (car (argv))) (dir (pathname-directory lm)) (exe (pathname-strip-directory lm))) (conc (if dir (conc dir "/") "") (case (string->symbol exe) ((dboard) (conc updir progname)) ((mtest) (conc updir progname)) ((dashboard) progname) (else exe))))) '("../../" "../"))))) (if (null? res) (begin (debug:print 0 *current-log-port* "Failed to find this executable! Using what can be found on the path") progname) (car res)))) (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) | > > > > > | > > > > > > > > > > | | > < | > > | > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | | | > | > > > | | > > > > | | > | < | | | | | | > > | > > > > > > > > > > | | | > | < | > > | | > > > > > > > > > > > > > > > > > > > > > > > | | | | | | | | | | | | | 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 | (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)) (define (common:safe-vector-ref vec indx default) (if (vector? vec) (handle-exceptions exn (begin (debug:print-info 0 *default-log-port* "remote data issue: exn=" exn) default) (vector-ref vec indx)) default)) ;; 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. exn=" exn) (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)) (file-old (> file-age (* 48 60 60))) (file-big (> (file-size fullname) 200000))) (hash-table-set! all-files file mod-time) (if (or (and (string-match "^.*.log" file) file-old file-big) (and (string-match "^server-.*.log" file) file-old)) (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 (and (> file-age (* (string->number (or (configf:lookup *configdat* "setup" "log-expire-days") "30")) 24 3600)) (file-exists? fullname)) ;; just in case it was gzipped - will get it next time (handle-exceptions exn #f (if (directory? fullname) (begin (debug:print-info 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-info 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 ", exn=" exn) (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. exn=" exn) (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 402 403 404 405 406 407 408 409 410 411 412 413 414 | (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 (hash-table-set! *common:denoise* key currtime) #t) #f))) (define (common:get-megatest-exe) (or (getenv "MT_MEGATEST") "megatest")) (define (common:read-encoded-string instr) (handle-exceptions exn (handle-exceptions exn (begin | > > > | | | | > | | | | > > | | | | 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 | (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 (hash-table-set! *common:denoise* key currtime) #t) #f))) (define (common:get-megatest-exe) (or (getenv "MT_MEGATEST") "megatest")) (define (common:read-encoded-string instr) (handle-exceptions exn (handle-exceptions exn (begin (debug:print-error 0 *default-log-port* "received bad encoded string \"" instr "\", message: " ((condition-property-accessor 'exn 'message) exn) ", exn=" exn) (print-call-chain (current-error-port)) #f) (read (open-input-string (base64:base64-decode instr)))) (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 ;;====================================================================== | > | > | > > > > > > > > > > | < | | | > > | > > | | > > > > | > > > > > > | 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 | #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)))) |
︙ | ︙ | |||
580 581 582 583 584 585 586 | (let ((res (assoc key lst))) (if res (cadr res)(if (null? default) #f (car default))))) (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") | | | > > | > > > > > > > > > > > > > > > > > > > > > > > > > | | > > > > > > > | | > > > > | | > | | < < < < < < < < < < < < < > > > > > > < < | > | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < > | | | | | | | | | > > > > > | > > > > > | | > > | | | | | 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 | (let ((res (assoc key lst))) (if res (cadr res)(if (null? default) #f (car default))))) (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") (pathname-file (or (if (string? *toppath* ) (pathname-file *toppath*) #f) (common:get-topath #f))) "please-set-setup-area-name")) ;; (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* ", exn=" exn) (exit 1)) (let* ((tsname (common:get-testsuite-name)) (dbpath (common:get-create-writeable-dir (list (conc "/tmp/" (current-user-name) "/megatest_localdb/" tsname "/" (string-translate *toppath* "/" ".")) (conc "/tmp/" (current-process-id) ;; just in case we have an issue with the dir by own user name "/megatest_localdb/" tsname (string-translate *toppath* "/" ".")) )))) (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") "delta-sync"))) ;; "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) | | | > > > > > > > > > > > | 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 | ) ) 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) | | | | > > > | | 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 | (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. exn=" exn) #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 "\"") | | > > > > > > > > > > > > | 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 | ;; 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)) | | > > > > > > > > > > | | > | > > > > > > > > > > > > > > > | | > | | < > > | > | > > > > | | 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 | (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 (begin (debug:print 0 *default-log-port* "Failed to identify access to " path-string ", exn=" 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 | > > > > > > > > > > | 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 | 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*) | > | > > | > | | 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 | ;; 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) ", exn=" 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?) | | > | > | > > > > > > > > | < < < < < < < | 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 | (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 1307 1308 1309 | (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 ;; (define (common:lazy-modification-time fpath) (handle-exceptions exn | > > > > > > > > > > > > > > > > > > > > > > > > > | > | > > > | | | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | | | | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | > | | | | | | | | > > | | | | | | | | | | | | | | | | | | > | > > > | 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 | (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 ;; (define (common:lazy-modification-time fpath) (handle-exceptions exn (begin (debug:print 0 *default-log-port* "Failed to get modifcation time for " fpath ", treating it as zero. exn=" exn) 0) (if (file-exists? fpath) (file-modification-time fpath) 0))) ;; find timestamp of newest file associated with a sqlite db file (define (common:lazy-sqlite-db-modification-time fpath) (let* ((glob-list (handle-exceptions exn (begin (debug:print 0 *default-log-port* "Failed to glob " fpath "*, exn=" exn) `(,(conc "/no/such/file, message: " ((condition-property-accessor 'exn 'message) exn)))) (glob (conc fpath "*")))) (file-list (if (eq? 0 (length glob-list)) '("/no/such/file") glob-list))) (apply max (map common:lazy-modification-time file-list)))) ;; return a nice clean pathname made absolute (define (common:nice-path dir) (let ((match (string-match "^(~[^\\/]*)(\\/.*|)$" dir))) (if match ;; using ~ for home? (common:nice-path (conc (common:read-link-f (cadr match)) "/" (caddr match))) (normalize-pathname (if (absolute-pathname? dir) dir (conc (current-directory) "/" dir)))))) ;; make "nice-path" available in config files and the repl (define nice-path common:nice-path) (define (common:read-link-f path) (handle-exceptions exn (begin (debug:print-error 0 *default-log-port* "command \"/bin/readlink -f " path "\" failed. exn=" exn) path) ;; just give up (with-input-from-pipe (conc "/bin/readlink -f " path) (lambda () (read-line))))) ;; returns *effective load* (not normalized) ;; (define (common:get-intercept onemin fivemin) (if (< onemin fivemin) ;; load is decreasing, just use the onemin load onemin (let* ((load-change (- onemin fivemin)) (tchange (- 300 60))) (max (+ onemin (* 60 (/ load-change tchange))) 0)))) ;; calculate a delay number based on a droop curve ;; inputs are: ;; - load-in, load as from uptime, NOT normalized ;; - numcpus, number of cpus, ideally use the real cpus, not threads ;; (define (common:get-delay load-in numcpus) (let* ((ratio (/ load-in numcpus)) (new-option (configf:lookup *configdat* "load" "new-load-method")) (paramstr (or (configf:lookup *configdat* "load" "exp-params") "15 12 1281453987.9543 0.75")) ;; 5 4 10 1")) (paramlst (map string->number (string-split paramstr)))) (if new-option (begin (cond ((and (>= ratio 0) (< ratio .5)) 0) ((and (>= ratio 0.5) (<= ratio .9)) (* ratio (/ 5 .9))) ((and (> ratio .9) (<= ratio 1.1)) (+ 5 (* (- ratio .9) (/ 55 .2)))) ((> ratio 1.1) 60))) (match paramlst ((r1 r2 s1 s2) (debug:print 3 *default-log-port* "Using params r1=" r1 " r2=" r2 " s1=" s1 " s2=" s2) (min (max (/ (expt r1 (* r2 s2 ratio)) s1) 0) 30)) (else (debug:print 0 *default-log-port* "BAD exp-params, should be \"r1 r2 s1 s2\" but got " paramstr) 30))))) (define (common:print-delay-table) (let loop ((x 0)) (print x "," (common:get-delay x 1)) (if (< x 2) (loop (+ x 0.1))))) (define (get-cpu-load #!key (remote-host #f)) (car (common:get-cpu-load remote-host))) ;; (let* ((load-res (process:cmd-run->list "uptime")) ;; (load-rx (regexp "load average:\\s+(\\d+)")) ;; (cpu-load #f)) ;; (for-each (lambda (l) ;; (let ((match (string-search load-rx l))) ;; (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")) (delfile (lambda () (debug:print-info 1 *default-log-port* " removing bad file " fullpath ", exn=" exn) (delete-file* fullpath) #f))) (if (and (file-exists? fullpath) (file-read-access? fullpath)) (handle-exceptions exn (begin (debug:print 0 *default-log-port* "failed to get cached info from " fullpath ", exn=" exn) #f) (debug:print 2 *default-log-port* "reading file " fullpath) (let ((real-age (- (current-seconds) (handle-exceptions exn (begin (debug:print 1 *default-log-port* "Failed to read mod time on file " fullpath ", using 0, exn=" exn) 0) (file-change-time fullpath))))) (if (< real-age age) (handle-exceptions exn (delfile) (let* ((res (with-input-from-file fullpath read))) (if (eof-object? res) (begin (delfile) #f) res))) (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 (begin (debug:print 0 *default-log-path* "failed to write file " fullpath ", exn=" exn) #f) (with-output-to-file fullpath (lambda ()(pp dat))))) #f)) (define (common:raw-get-remote-host-load remote-host) (handle-exceptions exn (begin (debug:print 0 *default-log-port* "failed to ssh to " remote-host " and get loadavg. exn=" exn) #f) ;; more specific handling of errors needed (with-input-from-pipe (conc "ssh " remote-host " cat /proc/loadavg") (lambda ()(list (read)(read)(read)))))) ;; get cpu load by reading from /proc/loadavg, return all three values ;; (define (common:get-cpu-load remote-host) (handle-exceptions exn (begin (debug:print 0 *default-log-port* "failed to ssh or read loadavg from host " remote-host ", exn=" 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))))))) (match result ((l1 l2 l3) (if (and (number? l1) (number? l2) (number? l3)) (begin (common:write-cached-info actual-hostname "cpu-load" result) result) '(-1 -1 -1))) ;; -1 is bad result (else '(-2 -2 -2)))))))) ;; 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))) | > > > | > > > > > | | | | > > > > > > > > | > > > > > > > > > > > > | > | | | < < < < < < | | < | < < | < > | > > > > > | | | | > > > > > > > > > | > > | < | < < < < < < < | < < < < < > > > > > | | | | > | > | | | | | | | | | > > > > > > | > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | (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 maxnormload 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 maxnormload msg hh))) (define *numcpus-cache* (make-hash-table)) (define (common:get-num-cpus remote-host) (let* ((actual-host (or remote-host (get-host-name)))) ;; hosts had better not be changing the number of cpus too often! (or (hash-table-ref/default *numcpus-cache* actual-host #f) (let* ((numcpus (or (common:get-cached-info actual-host "num-cpus" age: (+ 2592000 (random 3600))) (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)))) (hash-table-set! *numcpus-cache* actual-host numcpus) numcpus)))) ;; wait for normalized cpu load to drop below maxload ;; (define (common:wait-for-normalized-load maxnormload msg remote-host #!optional (rem-tries 5)) (let ((num-cpus (common:get-num-cpus remote-host))) (if num-cpus (common:wait-for-cpuload maxnormload 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 maxnormload msg remote-host (- rem-tries 1)) #f))))) ;; DO NOT CALL THIS DIRECTLY. It is called from common:wait-for-normalized-load ;; count - count down to zero, at some point we'd give up if the load never drops ;; num-tries - count down to zero number tries to get numcpus ;; (define (common:wait-for-cpuload maxnormload numcpus-in #!key (count 1000) (msg #f)(remote-host #f)(num-tries 5)) (let* ((loadavg (common:get-cpu-load remote-host)) ;; not possible to have zero. If we get 1, it's possible that we got the previous default, and we should check again (numcpus (if (<= 1 numcpus-in) (common:get-num-cpus remote-host) numcpus-in)) (first (car loadavg)) (next (cadr loadavg)) (adjmaxload (* maxnormload (max 1 numcpus))) ;; possible bug ;; where numcpus ;; (or could be ;; maxload) is ;; zero, crude ;; fallback is to ;; at least use 1 ;; effective load accounts for load jumps, this should elminate all the first-next-avg, adjwait, load-jump-limit ;; etc. (effective-load (common:get-intercept first next)) (recommended-delay (common:get-delay effective-load numcpus)) (effective-host (or remote-host "localhost")) (normalized-effective-load (/ effective-load numcpus)) (will-wait (> normalized-effective-load maxnormload))) (if (> recommended-delay 0) (let* ((actual-delay (min recommended-delay 30))) (if (common:low-noise-print 30 (conc (round actual-delay) "-safe-load")) (debug:print-info 0 *default-log-port* "Load control, delaying " actual-delay " seconds to maintain safe load. current normalized effective load is " normalized-effective-load".")) (thread-sleep! actual-delay))) (cond ;; bad data, try again to get the data ((not will-wait) (if (common:low-noise-print 30 (conc (round normalized-effective-load) "-load-acceptable-" effective-host)) (debug:print 0 *default-log-port* "Effective load on " effective-host " is acceptable at " effective-load " continuing."))) ((and (< first 0) ;; this indicates the loadavg data is bad - machine may not be reachable (> num-tries 0)) (debug:print 0 *default-log-port* "WARNING: received bad data from get-cpu-load " first ", we'll sleep 10s and try " num-tries " more times.") (thread-sleep! 10) (common:wait-for-cpuload maxnormload numcpus-in count: count remote-host: remote-host num-tries: (- num-tries 1))) ;; need to wait for load to drop ((and will-wait ;; (> first adjmaxload) (> count 0)) (debug:print-info 0 *default-log-port* "Delaying 15" ;; adjwait " seconds due to normalized effective load " normalized-effective-load ;; first " exceeding max of " adjmaxload " on server " (or remote-host (get-host-name)) " (normalized load-limit: " maxnormload ") " (if msg msg "")) (thread-sleep! 15) ;; adjwait) (common:wait-for-cpuload maxnormload numcpus count: (- count 1) msg: msg remote-host: remote-host) ;; put the message here to indicate came out of waiting (debug:print-info 1 *default-log-port* "On host: " effective-host ", effective load: " effective-load ", numcpus: " numcpus ", normalized effective load: " normalized-effective-load )) ;; overloaded and count expired (i.e. went to zero) (else (if (> num-tries 0) ;; should be "num-tries-left". (if (common:low-noise-print 30 (conc (round effective-load) "-load-acceptable-" effective-host)) (debug:print 0 *default-log-port* "Load on " effective-host " is acceptable at effective normalized load of " effective-normalized-load " continuing.")) (debug:print 0 *default-log-port* "Load on " effective-host ", " first" could not be retrieved. Giving up and continuing.")))))) ;; 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)(num-tries 5)) ;; (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)) ;; (adjmaxload (* maxload (max 1 numcpus))) ;; possible bug where ;; ;; numcpus (or could be ;; ;; maxload) is zero, ;; ;; crude fallback is to ;; ;; at least use 1 ;; (loadjmp (- first (if (> next (* numcpus 0.7)) ;; could do something with average of first and next? ;; 0 ;; next))) ;; we will force a conservative calculation any time next is large. ;; (first-next-avg (/ (+ first next) 2)) ;; ;; add some randomness to the time to break any alignment ;; ;; where netbatch dumps many jobs to machines simultaneously ;; (adjwait (min (+ 300 (random 10)) (abs (* (+ (random 10) ;; (/ (- 1000 count) 10) ;; waitdelay) ;; (- first adjmaxload) )))) ;; (load-jump-limit (configf:lookup-number *configdat* "setup" "load-jump-limit")) ;; ;; effective load accounts for load jumps, this should elminate all the first-next-avg, adjwait, load-jump-limit ;; ;; etc. ;; (effective-load (common:get-intercept first next)) ;; (effective-host (or remote-host "localhost")) ;; (normalized-effective-load (/ effective-load numcpus)) ;; (will-wait (> normalized-effective-load maxload))) ;; ;; ;; let's let the user know once in a long while that load checking ;; ;; is happening but not constantly report it ;; #;(if (common:low-noise-print 30 (conc "cpuload" (or remote-host "localhost"))) ;; (> (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 ", adjmaxload: " adjmaxload ", loadjmp: " loadjmp)) ;; ;; (debug:print-info 1 *default-log-port* ;; "On host: " effective-host ;; ", effective load: " effective-load ;; ", numcpus: " numcpus ;; ", normalized effective load: " normalized-effective-load ;; ) ;; ;; (cond ;; ;; bad data, try again to get the data ;; ((and (< first 0) ;; this indicates the loadavg data is bad - machine may not be reachable ;; (> num-tries 0)) ;; (debug:print 0 *default-log-port* "WARNING: received bad data from get-cpu-load " first ", we'll sleep 10s and try " num-tries " more times.") ;; (thread-sleep! 10) ;; (common:wait-for-cpuload maxload-in numcpus-in waitdelay ;; count: count remote-host: remote-host force-maxload: force-maxload num-tries: (- num-tries 1))) ;; ;; need to wait for load to drop ;; ((and will-wait ;; (> first adjmaxload) ;; (> count 0)) ;; (debug:print-info 0 *default-log-port* ;; "Delaying " 15 ;; adjwait ;; " seconds due to normalized effective load " normalized-effective-load ;; first ;; " exceeding max of " adjmaxload ;; " on server " (or remote-host (get-host-name)) ;; " (normalized load-limit: " maxload ") " (if msg msg "")) ;; (thread-sleep! 15) ;; adjwait) ;; (common:wait-for-cpuload maxload numcpus waitdelay count: (- count 1) msg: msg remote-host: remote-host)) ;; ((and (> loadjmp (cond ;; (load-jump-limit load-jump-limit) ;; ((> numcpus 8)(/ numcpus 2)) ;; ((> numcpus 4)(/ numcpus 1.2)) ;; (else 0.5))) ;; (> count 0)) ;; (debug:print-info 0 *default-log-port* "waiting " adjwait " seconds due to possible load jump " loadjmp ". " ;; (if msg msg "")) ;; (thread-sleep! adjwait) ;; (common:wait-for-cpuload maxload numcpus waitdelay count: (- count 1) msg: msg remote-host: remote-host)) ;; (else ;; (if (> num-tries 0) ;; (if (common:low-noise-print 30 (conc (round first) "-load-acceptable-" (or remote-host "localhost"))) ;; (debug:print 0 *default-log-port* "Load on " (or remote-host "localhost") " is acceptable at " first " continuing.")) ;; (debug:print 0 *default-log-port* "Load on " (or remote-host "localhost") ", "first" could not be retrieved. Giving up and continuing.")))))) ;; (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") | > > > > > > > > > > > > > > > > > > > > > > > > > | | 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 | (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) | | | > > > > | > > > > > > > > > > > > > > > > > > | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > | 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 | (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") ("rerun" . "-rerun") ("setvars" . "-setvars") ("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)) | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | > | | | | | | | > > > | | 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 | (proc (proc))) (hash-table-for-each vars (lambda (var val) (setenv var val))) vars)) (define (common:propogate-mt-vars-to-subrun proc propogate-vars) (let ((vars (make-hash-table)) (var-patt "^MT_.*")) (for-each (lambda (vardat) ;; each env var ;(for-each ;(lambda (var-patt) (if (string-match var-patt (car vardat)) (let ((var (car vardat)) (val (cdr vardat))) (hash-table-set! vars var val) (if (member var propogate-vars) (begin (print var " " (string-substitute "MT_" "PARENT_" var)) (setenv (string-substitute "MT_" "PARENT_" var) val))) (unsetenv var)))) ; var-patts)) (get-environment-variables)) (cond ((string? proc)(system proc)) (proc (proc))) (hash-table-for-each vars (lambda (var val) (if (member var propogate-vars) (unsetenv (string-substitute "MT_" "PARENT_" var))) (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))) "/")) | > > > > > > | > > > > > > > | > | | | | | > > > > | > > > > > > > > | | | | < < < < < < < < < < < < | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | > > > > > > > > > > | > | > > > | | | > | > > | > > > > > > > > > > > > | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | (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] ;; C/M/A lets megatest know this launcher provides C cores, M bytes memory for architecture A ;; 2/2G/arm smart -cores 2 -memory 2G -arch arm ;; 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 ;; ;; NOTE: host-rules is ONLY used for MTLOWESTLOAD ;; ;; [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 2/2G/arm ;; % nbgeneral ;; ;; [jobtools] ;; # if defined and not "no" flexi-launcher will bypass "launcher" unless no match. ;; flexi-launcher yes ;; launcher nbfake ;; mode adjutant|normal (default is normal) ;; ;; ;; mode is 'normal (i.e. directly use launcher) or 'adjutant (i.e. use adjutant) ;; (define (common:get-launcher configdat testname itempath mode) (let ((fallback-launcher (configf:lookup configdat "jobtools" "launcher"))) (if (and (configf:lookup configdat "jobtools" "flexi-launcher") ;; overrides launcher (not (equal? (configf:lookup configdat "jobtools" "flexi-launcher") "no"))) (let* ((launchers (hash-table-ref/default configdat "launchers" '()))) (if (null? launchers) fallback-launcher (let loop ((hed (car launchers)) (tal (cdr launchers))) (let ((patt (car hed)) (host-type (cadr hed))) (if (tests:match patt testname itempath) ;; have a launcher match for this test (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))) ;; find the actual launcher from the host-types table ;; if we are in adjutant mode then we want to return both host-type and launcher (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))))) (case mode ((adjutant) (list host-type launcher)) (else 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 ", exn=" exn) ;; 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 (begin (debug:print 0 *default-log-port* "joining threads failed. exn=" 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 [80f9e14f2d].
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: |
︙ | ︙ | |||
28 29 30 31 32 33 34 35 36 37 38 39 40 41 | ((_ (name arg ...) body ...) (define-syntax name (syntax-rules () ((name arg ...) (begin body ...))))))) ;; (define-syntax common:handle-exceptions ;; (syntax-rules () ;; ((_ exn-in errstmt ...)(handle-exceptions exn-in errstmt ...)))) (define-syntax common:debug-handle-exceptions (syntax-rules () ((_ debug exn errstmt body ...) (if debug (begin body ...) (handle-exceptions exn errstmt body ...))))) | > | 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | ((_ (name arg ...) body ...) (define-syntax name (syntax-rules () ((name arg ...) (begin body ...))))))) ;; (define-syntax common:handle-exceptions ;; (syntax-rules () ;; ((_ exn-in errstmt ...)(handle-exceptions exn-in errstmt ...)))) ;; this works, why didn't I use it more? (define-syntax common:debug-handle-exceptions (syntax-rules () ((_ debug exn errstmt body ...) (if debug (begin body ...) (handle-exceptions exn errstmt body ...))))) |
︙ | ︙ | |||
112 113 114 115 116 117 118 119 120 121 122 123 | (not (null? (lset-intersection! eq? *verbosity* n)))) ((and (number? *verbosity*) (list? n)) (member *verbosity* n)))) (define (debug:setup) (let ((debugstr (or (args:get-arg "-debug") (getenv "MT_DEBUG_MODE")))) (set! *verbosity* (debug:calc-verbosity debugstr)) (debug:check-verbosity *verbosity* debugstr) ;; if we were handed a bad verbosity rule then we will override it with 1 and continue (if (not *verbosity*)(set! *verbosity* 1)) | > > | | | 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 | (not (null? (lset-intersection! eq? *verbosity* n)))) ((and (number? *verbosity*) (list? n)) (member *verbosity* n)))) (define (debug:setup) (let ((debugstr (or (args:get-arg "-debug") (args:get-arg "-debug-noprop") (getenv "MT_DEBUG_MODE")))) (set! *verbosity* (debug:calc-verbosity debugstr)) (debug:check-verbosity *verbosity* debugstr) ;; if we were handed a bad verbosity rule then we will override it with 1 and continue (if (not *verbosity*)(set! *verbosity* 1)) (if (and (not (args:get-arg "-debug-noprop")) (or (args:get-arg "-debug") (not (getenv "MT_DEBUG_MODE")))) (setenv "MT_DEBUG_MODE" (if (list? *verbosity*) (string-intersperse (map conc *verbosity*) ",") (conc *verbosity*)))))) (define (debug:print n e . params) (if (debug:debug-mode n) (with-output-to-port (or e (current-error-port)) |
︙ | ︙ | |||
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) | > > | | | | | | 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 | (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 [9423abd515].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | ;;====================================================================== ;; 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 files) (import (prefix sqlite3 sqlite3:) posix typed-records srfi-18 srfi-69 md5 message-digest regex srfi-1) ;;====================================================================== ;; CONTENTS ;; ;; config file utils ;; misc conversion, data manipulation functions ;; testsuite and area utilites ;; ;;====================================================================== (include "megatest-version.scm") (include "megatest-fossil-hash.scm") (define (get-full-version) (conc megatest-version "-" megatest-fossil-hash)) (define (version-signature) (conc megatest-version "-" (substring megatest-fossil-hash 0 4))) ;;====================================================================== ;; config file utils ;;====================================================================== (define (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)) ;; returns var key1=val1; key2=val2 ... as alist (define (get-key-list cfgdat section var) ;; convert string a=1; b=2; c=a silly thing; d= (let ((valstr (lookup cfgdat section var))) (if valstr (val->alist valstr) '()))) ;; should it return empty list or #f to indicate not set? (define (get-section cfgdat section) (hash-table-ref/default cfgdat section '())) ;;====================================================================== ;; misc conversion, data manipulation functions ;;====================================================================== ;; if it looks like a number -> convert it to a number, else return it ;; (define (lazy-convert inval) (let* ((as-num (if (string? inval)(string->number inval) #f))) (or as-num inval))) ;; to '((a . 1)(b . 2)(c . "a silly thing")(d . "")) ;; (define (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 (lazy-convert inval) inval)))) (else f)))) (filter (lambda (x) (not (string-match "^\\s*" x))) val-list)) '()))) ;;====================================================================== ;; testsuite and area utilites ;;====================================================================== (define (get-testsuite-name toppath configdat) (or (lookup configdat "setup" "area-name") (lookup configdat "setup" "testsuite") (get-environment-variable "MT_TESTSUITE_NAME") (if (string? toppath) (pathname-file toppath) #f))) (define (get-area-path-signature toppath #!optional (short #f)) (let ((res (message-digest-string (md5-primitive) toppath))) (if short (substring res 0 4) res))) (define (get-area-name configdat toppath #!optional (short #f)) ;; look up my area name in areas table (future) ;; generate auto name (conc (get-area-path-signature toppath short) "-" (get-testsuite-name toppath configdat))) ;; need generic find-record-with-var-nmatching-val ;; (define (path->area-record cfgdat path) (let* ((areadat (get-cfg-areas cfgdat)) (all (filter (lambda (x) (let* ((keyvals (cdr x)) (pth (alist-ref 'path keyvals))) (equal? path pth))) areadat))) (if (null? all) #f (car all)))) ;; return first match ;; given a config return an alist of alists ;; area-name => data ;; (define (get-cfg-areas cfgdat) (let ((adat (get-section cfgdat "areas"))) (map (lambda (entry) `(,(car entry) . ,(val->alist (cadr entry)))) adat))) ;; (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 [83ecc5b24c].
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 | ;;====================================================================== ;; 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, exn=" exn) #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 (debug:print 0 *default-log-port* "WARNING: failed to process config input \"" l "\", exn=" exn) (debug:print 0 *default-log-port* " message: " ((condition-property-accessor 'exn 'message) exn)) ;; (print "exn=" (condition->list exn)) (set! result (conc "#{( " cmdtype ") " cmd "}, full expansion: " fullcmd))) (if (or allow-system (not (member cmdtype '("system" "shell" "sh")))) (with-input-from-string fullcmd (lambda () |
︙ | ︙ | |||
170 171 172 173 174 175 176 | ;; (not (eq? allow-processing 'return-string))) ((#t #f) (configf:process-line inl ht allow-processing)) ((return-string) inl) (else (configf:process-line inl ht allow-processing))))) | | | | > > > > > > > > > > > > > > > > | 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 | ;; (not (eq? allow-processing 'return-string))) ((#t #f) (configf:process-line inl ht allow-processing)) ((return-string) inl) (else (configf:process-line inl ht allow-processing))))) (if (and (string? res) ;; must set to "no" to force NOT trimming trailing spaces (not (equal? (hash-table-ref/default settings "trim-trailing-spaces" "yes") "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 564 565 566 567 | (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 (begin (debug:print '(2 9) *default-log-port* "glob of " full-conf " gave no match. , exn=" 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) | | | 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 | (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 | | | | | 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 | (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) | | | | | 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 | ;; 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 '())) |
︙ | ︙ | |||
656 657 658 659 660 661 662 | adat) ht)) ;; if (define (configf:read-alist fname) (handle-exceptions exn | > > | | > | | | | | | | | | | | | | > > | | | | | < | | < < < | | 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 | adat) ht)) ;; if (define (configf:read-alist fname) (handle-exceptions exn (begin (debug:print-info 0 *default-log-port* "unable to read alist " fname ". exn=" 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 (begin (debug:print 0 *default-log-port* "deleting " fname " failed, exn=" 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))) |
︙ | ︙ |
Added configure version [5bc39a4917].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | #!/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/>. # Configure the build if [[ "$1"x == "x" ]];then PREFIX=$PWD else PREFIX=$1 fi #====================================================================== # Configure stuff needed for eggs #====================================================================== function configure_dependencies () { #====================================================================== # libnanomsg #====================================================================== if [[ ! $(ls /usr/lib/*/libnanomsg*) ]];then echo "libnanomsg build needed." echo "BUILD_NANOMSG=yes" >> makefile.inc fi #====================================================================== # postgresql libraries #====================================================================== if [[ ! $(ls /usr/lib/*/libpq.*) ]];then echo "Postgresql build needed." echo "BUILD_POSTGRES=yes" >> makefile.inc fi if [[ ! $(ls /usr/lib/*/libsqlite3.*) ]];then echo "Sqlite3 build needed." echo "BUILD_SQLITE3=yes" >> makefile.inc fi } #====================================================================== # Initialize makefile.inc #====================================================================== echo "" > makefile.inc #====================================================================== # Do we need Chicken? #====================================================================== if [[ -e /usr/bin/sw_vers ]]; then ARCHSTR=$(/usr/bin/sw_vers -productVersion) else ARCHSTR=$(lsb_release -sr) fi echo "CKPATH=$PREFIX/.$ARCHSTR" >> makefile.inc CHICKEN_PREFIX=$PREFIX/bin/.$ARCHSTR if [[ ! $(type csi) ]];then echo "Chicken build needed." echo "BUILD_CHICKEN=yes" >> makefile.inc configure_dependencies echo "include chicken.makefile" >> makefile.inc else echo "CSIPATH=$(which csi)" >> makefile.inc CSIPATH=$(which csi) echo "CKPATH=$(dirname $(dirname $CSIPATH))" >> makefile.inc fi # Make setup scripts echo "#!/bin/bash" > setup.sh echo "export PATH=$CHICKEN_PREFIX/bin:\$PATH" >> setup.sh echo "export LD_LIBRARY_PATH=$CHICKEN_PREFIX/lib" >> setup.sh echo 'exec "$@"' >> setup.sh chmod a+x setup.sh echo "setenv PATH $CHICKEN_PREFIX/bin:\$PATH" > setup.csh echo "setenv LD_LIBRARY_PATH $CHICKEN_PREFIX/lib" >> setup.csh echo "All done creating makefile.inc, feel free to edit it!" echo "run \"setup.sh bash\" or source setup.csh to get PATH and LD_LIBRARY_PATH adjusted" |
Added cookie.scm version [93f6026f72].
> > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | ;;====================================================================== ;; Copyright 2019, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more 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 cookie)) (include "stml2/cookie.scm") |
Deleted daemon.scm version [1e273ea0bb].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Added dashboard-context-menu.scm version [48947370a7].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | ;;====================================================================== ;; 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* ((dboardexe (common:find-local-megatest "dashboard")) (cmd (conc dboardexe " -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, exn=" exn) (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 [237d160a6c].
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 581 582 583 584 585 586 587 | ;; 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 (begin (debug:print 0 *default-log-port* "failed to set up environment for " runconfigf ", exn=" 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! (begin (debug:print 0 *default-log-port* "testconfig load using " item-path " failed, trying " (db:test-get-item-path testdat) ", exn=" exn) (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 (begin (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) ", exn=" exn) #f) (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"))) | | | | 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 | (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) | | > | | 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 | 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" | | | | | > | | < | | | | > > > > > | | 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 | (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)))))))))) | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | (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 [627ca6b765].
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 mt)) (include "common_records.scm") (include "db_records.scm") (include "run_records.scm") (include "task_records.scm") (include "megatest-version.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 170 | "-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 "-:p" ;; ignore the built in chicken profiling switch ) 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) | | > > | | 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 | ;; 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? | > > | 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 | (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)))) | | | 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 | (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) |
︙ | ︙ | |||
382 383 384 385 386 387 388 389 390 391 392 393 394 395 | ((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)) ;; register dboard:rundat with BBpp ;; this is used by BBpp (Brandon's pretty printer) to convert dboard:rundat into a composition of lists that pp will handle (hash-table-set! *BBpp_custom_expanders_list* RUNDAT: (cons dboard:rundat? (lambda (tabdat-item) (filter | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | ((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)) ;; for the new runs view lets build up a few new record types and then consolidate later ;; ;; this is a two level deep pipeline for the incoming data: ;; sql query data ==> filters ==> data for display ;; (defstruct dboard:rdat ;; view related items (runnum 0) ;; which column we are processing, index into runsbynum, we sweep across all these runs then start over (leftcol 0) ;; number of the leftmost visible column (toprow 0) ;; topmost visible row (numcols 24) ;; number of columns visible (numrows 20) ;; number of rows visible ;; data from sql db (keys (rmt:get-keys)) ;; to be removed when targets handling is refactored (runs (make-sparse-vector)) ;; id => runrec (runsbynum (make-vector 100 #f)) ;; vector num => runrec (targ-runid (make-hash-table)) ;; area/target/runname => run-id ;; not sure this will be needed (tests (make-hash-table)) ;; test[/itempath] => list of test rec ;; run sql filters (targ-sql-filt "%") (runname-sql-filt "%") (run-state-sql-filt "%") (run-status-sql-filt "%") ;; test sql filter (testname-sql-filt "%") (itempath-sql-filt "%") (test-state-sql-filt "%") (test-status-sql-filt "%") ;; other sql related fields (last-updates (make-sparse-vector 0)) ;; run-id -> timestamp of the last update from sql db, set to zero on any field changes ;; filtered data (cols (make-sparse-vector)) ;; columnnum => run-id (tests (make-hash-table)) ;; test[/itempath] => (vector columnnum => test rec) ;; various (prev-run-ids '()) ;; push previously looked at runs on this (view-changed #f) ;; widgets (runs-tree #f) ;; ) (define (dboard:rdat-push-run-id rdat run-id) (dboard:rdat-prev-run-ids-set! rdat (cons run-id (dboard:rdat-prev-run-ids rdat)))) (defstruct dboard:runrec id target ;; a/b/c... tdef ;; for future use ) (defstruct dboard:testrec id runid testname ;; test[/itempath] state status start-time duration ) ;; register dboard:rundat with BBpp ;; this is used by BBpp (Brandon's pretty printer) to convert dboard:rundat into a composition of lists that pp will handle (hash-table-set! *BBpp_custom_expanders_list* RUNDAT: (cons dboard:rundat? (lambda (tabdat-item) (filter |
︙ | ︙ | |||
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) | < | | 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 | 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)) | | < | < | | 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 | ;; 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)) | < | < | | 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 | ;; 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 | > | > > > > > > > > | | 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 | (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"))) | | | 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 | 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))) | > | 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 | "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 ;; | > > | | | | > | | > > > | > | | > > > > | > | | | | | | | | > > > > > | | > | > > > | > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | #: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)))) ;; (dboard:tabdat-view-changed-set! tabdat #t) ;; ?? ;; done below when run-id is a number (dboard:tabdat-target-set! tabdat (cdr run-path)) ;; (print ;; "run-path: ;; " ;; run-path) (iup:attribute-set! txtbox "VALUE" (string-intersperse (cdr run-path) "/")) (dashboard:update-run-command tabdat) (dboard:tabdat-layout-update-ok-set! tabdat #f) (if (number? run-id) (begin ;; capture last two in tabdat. (dboard:tabdat-prev-run-id-set! tabdat (dboard:tabdat-curr-run-id tabdat)) (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 txtbox tb )))) ;; browse runs as a tree. Used in both "Runs" tab and ;; in the runs control panel. ;; ;; THIS IS THE NEW ONE ;; (define (dboard:runs-tree-new-browser commondat rdat) (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:rdat-targ-sql-filt-set! rdat (string-split b "/"))) #;(dashboard:update-run-command tabdat)) "command-testname-selector tb action")) ;; #:value (dboard:test-patt->lines ;; This seems like it was wrong, BUG in code where it was copied from? ;; (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 (new-tree-path->run-id rdat (cdr run-path)))) ;; (dboard:tabdat-view-changed-set! tabdat #t) ;; ?? ;; done below when run-id is a number (dboard:rdat-targ-sql-filt-set! rdat (cdr run-path)) ;; (print ;; "run-path: ;; " ;; run-path) (iup:attribute-set! txtbox "VALUE" (string-intersperse (cdr run-path) "/")) #;(dashboard:update-run-command tabdat) #;(dboard:tabdat-layout-update-ok-set! tabdat #f) (if (number? run-id) (begin ;; capture last two in tabdat. (dboard:rdat-push-run-id rdat run-id) (dboard:rdat-view-changed-set! rdat #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:rdat-runs-tree-set! rdat tb) (iup:detachbox (iup:vbox txtbox tb )))) ;;====================================================================== ;; 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 | | | 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 | (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" | | | | 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 | ))) 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)) | > > > > > | | | | | | | | | | | | < > | | | | | | | | | | | | < | | > > | 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 | ;; 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 (new-tree-path->run-id rdat path) (if (not (null? path)) (hash-table-ref/default (dboard:rdat-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) |
︙ | ︙ | |||
1680 1681 1682 1683 1684 1685 1686 | ;; userdata: (conc "run-id: " run-id)))) (hash-table-set! (dboard:tabdat-path-run-ids tabdat) run-path run-id) ;; (set! colnum (+ colnum 1)) )))) run-ids))) (define (dashboard:tests-ht->tests-dat tests-ht) | > > > > > > > > > > > | | | | | | | | > > > > > > > > | | | | | | 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 | ;; userdata: (conc "run-id: " run-id)))) (hash-table-set! (dboard:tabdat-path-run-ids tabdat) run-path run-id) ;; (set! colnum (+ colnum 1)) )))) run-ids))) (define (dashboard:tests-ht->tests-dat tests-ht) (let ((oldest-item (make-hash-table))) ;; ;; populate the oldest-item table (for-each (lambda (tdat) (let ((tname (db:test-get-testname tdat)) (etime (db:test-get-event_time tdat))) (if (hash-table-exists? oldest-item tname) (if (< (hash-table-ref oldest-item tname) etime) (hash-table-set! oldest-item tname etime)) (hash-table-set! oldest-item tname etime)))) (hash-table-values tests-ht)) (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 (equal? a-test-name b-test-name) (> a-event-time b-event-time) (> (hash-table-ref oldest-item a-test-name) (hash-table-ref oldest-item b-test-name))))))))) ;; (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)) | < | < < | | 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 | 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)) |
︙ | ︙ | |||
1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 | (if (> max-col (string->number (iup:attribute run-matrix "NUMCOL"))) (iup:attribute-set! run-matrix "NUMCOL" max-col )) (let ((effective-max-row (if (< max-row max-visible) max-visible max-row))) (if (> effective-max-row (string->number (iup:attribute run-matrix "NUMLIN"))) (iup:attribute-set! run-matrix "NUMLIN" effective-max-row ))) ;; Row labels (for-each (lambda (ind) (let* ((name (car ind)) (num (cadr ind)) (key (conc num ":0"))) (if (not (equal? (iup:attribute run-matrix key) name)) | > > | 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 | (if (> max-col (string->number (iup:attribute run-matrix "NUMCOL"))) (iup:attribute-set! run-matrix "NUMCOL" max-col )) (let ((effective-max-row (if (< max-row max-visible) max-visible max-row))) (if (> effective-max-row (string->number (iup:attribute run-matrix "NUMLIN"))) (iup:attribute-set! run-matrix "NUMLIN" effective-max-row ))) (iup:attribute-set! run-matrix "WIDTHDEF" 16) ;; Row labels (for-each (lambda (ind) (let* ((name (car ind)) (num (cadr ind)) (key (conc num ":0"))) (if (not (equal? (iup:attribute run-matrix key) name)) |
︙ | ︙ | |||
1833 1834 1835 1836 1837 1838 1839 | (begin (set! changed #t) (iup:attribute-set! run-matrix key (cadr value)) (iup:attribute-set! run-matrix (conc "BGCOLOR" key) (car value)))))) matrix-content) ;; Col labels - do after setting Cell contents so they are accounted for in the size calc. | | | | | | 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 | (begin (set! changed #t) (iup:attribute-set! run-matrix key (cadr value)) (iup:attribute-set! run-matrix (conc "BGCOLOR" key) (car value)))))) matrix-content) ;; Col labels - do after setting Cell contents so they are accounted for in the size calc. (for-each (lambda (ind) (let* ((name (car ind)) (num (cadr ind)) (key (conc "0:" num))) (if (not (equal? (iup:attribute run-matrix key) name)) (begin (set! changed #t) (iup:attribute-set! run-matrix key name) ;; (list->string (intersperse (string->list name) #\newline))) ;; name) #;(if (<= num max-col) (iup:attribute-set! run-matrix "FITTOTEXT" (conc "C" num))))))) col-indices) (if (and (eq? pass-num 0) changed) (loop 1 #t)) ;; force second pass due to column labels changing ;; (debug:print 0 *default-log-port* "runs-summary-updater, changed: " changed " pass-num: " pass-num) ;; (print "runs-summary-updater, changed: " changed " pass-num: " pass-num) (if changed (iup:attribute-set! run-matrix "REDRAW" "ALL"))))))))) ;;====================================================================== ;; S U M M A R Y ;;====================================================================== ;; ;; 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)) | | | | | | 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 | (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) ", exn=" exn) (debug:print 0 *default-log-port* "ERROR: failed to load " source ", try loading in the repl: megatest -repl") (set! success #f)) (load source)) (begin (debug:print 0 *default-log-port* "ERROR: cannot find file to load: \"" source "\" for user view " view-name))) ;; now run the user supplied definition for the tab view (if success (handle-exceptions exn (begin (print-call-chain) (debug:print 0 *default-log-port* " message: " ((condition-property-accessor 'exn 'message) exn) ", exn=" exn) (debug:print 0 *default-log-port* "ERROR: failed call procedure " viewgen ", with; tab-num=" tab-num ", view-name=" view-name ", and views-cfgdat and megatest configdat as parameters. To debug try loading in the repl: megatest -repl") (set! success #f)) (print "Adding tab " view-name " with proc " viewgen) ;; (iup:child-add! tabs (set! result-child ((eval (string->symbol viewgen)) commondat tabs tab-num view-name views-cfgdat *configdat*)))) ;; and finally set the updater (if success (dboard:commondat-add-updater commondat (lambda () (handle-exceptions exn (begin (print-call-chain) (debug:print 0 *default-log-port* " message: " ((condition-property-accessor 'exn 'message) exn) ", exn=" exn) (debug:print 0 *default-log-port* "ERROR: failed call procedure \"" updater "\", with; tabnum=" tab-num ", view-name=" view-name ", and views-cfgdat and megatest configdat as parameters. To debug try loading in the repl: megatest -repl") (set! success #f)) (debug:print 4 *default-log-port* "Running updater for tab " view-name " with proc " updater " and tab-num: " tab-num) ((eval (string->symbol updater)) commondat tabs tab-num view-name views-cfgdat *configdat*))) tab-num: tab-num)) |
︙ | ︙ | |||
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 | | > | | 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 | ;; 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))) | | | | | | 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 | 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 | > > > > > > > > > > > > > > > > > > | 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 | 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") | > > > > > > > > > > | 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 | (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) | | | | | | | | | 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 | #: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 ))) | < < < < < | | | | | | | | | | | < < | | | | | | | | | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | | | | | | | | | | < < < > > > | | | | | | | | | > > > > > | | > > | | | | | > > | > > > | < < < < < | | | | | | < > | | | | < < > | | | | | < > | | | < | > | | | < < < < < | < | > > > | | < | | | < < | | | < < < < < > | < | < | > > > > > > > > > > > > > | < > | < < < < < < < > > > | | < < < < | < | | | | | | | < | > | | | | | | | | > > > > | | < < < < | < | < < | < | < < | | > > | | < | < > | | > | > | | | > | < | < > > | < < < < < < < < < < < < < > > | > | 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 | (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)) ;; make-simple-run procedure (target3772 id3773 runname3774 state3775 status3776 owner3777 event_time3778) ;; rmt:simple-get-runs procedure (runpatt1001 count1002 offset1003 target1004) ;; simple-run-event_time procedure (x3834) ;; simple-run-event_time-set! procedure (x3830 val3831) ;; simple-run-id procedure (x3794) ;; simple-run-id-set! procedure (x3790 val3791) ;; simple-run-owner procedure (x3826) ;; simple-run-owner-set! procedure (x3822 val3823) ;; simple-run-runname procedure (x3802) ;; simple-run-runname-set! procedure (x3798 val3799) ;; simple-run-state procedure (x3810) ;; simple-run-state-set! procedure (x3806 val3807) ;; simple-run-status procedure (x3818) ;; simple-run-status-set! procedure (x3814 val3815) ;; simple-run-target procedure (x3786) ;; simple-run-target-set! procedure (x3782 val3783) ;; simple-run? procedure (x3780) ;;====================================================================== ;; Extracting the data to display for runs ;; ;; This needs to be re-entrant such that it does one column per call ;; on the zeroeth call update runs data ;; on each subsequent call update one run (configurable - could do two, three ... or update until tdelta exceeded ;; on last run reset to zeroeth ;; ;; 1. select with run filters; area, target, runname, runstate, runstatus, starttime, duration ;; - put this information into two data structures: ;; a. hash of area/target/runname => runstruct #< ordernun, id, area, target, runname, state, ;; status, starttime, duration, non-deleted testcount> ;; ordernum reflects order as received from sql query ;; b. sparsevec of id => runstruct ;; 2. for each run in runshash ordered by ordernum do: ;; retrieve data since last update for that run ;; if there is a deleted test - retrieve full data ;; if there are non-deleted tests register this run in the columns sparsevec ;; if this is the zeroeth column regenerate the rows sparsevec ;; if this column is in the visible zone update visible cells ;; ;; Other factors: ;; 1. left index handling: ;; - add test/itempaths to left index as discovered, re-order and ;; update row -> test/itempath mapping on each read run ;;====================================================================== ;; runs is <vec header runs> ;; get ALL runs info ;; update rdat-targ-run-id ;; update rdat-runs ;; (define (dashboard:update-runs-data rdat) (let* ((tb (dboard:rdat-runs-tree rdat)) (targ-sql-filt (dboard:rdat-targ-sql-filt rdat)) (runname-sql-filt (dboard:rdat-runname-sql-filt rdat)) (state-sql-filt (dboard:rdat-run-state-sql-filt rdat)) (status-sql-filt (dboard:rdat-run-status-sql-filt rdat)) ;; Use (db:get-value-by-header (db:get-header runinfo)(db:get-rows runinfo)) (data (rmt:simple-get-runs runname-sql-filt #f #f targ-sql-filt #f)) (numruns (length data))) ;; store in the runsbynum vector (dboard:rdat-runsbynum-set! rdat (list->vector data)) ;; update runs id => runrec ;; update targ-runid target/runname => run-id (for-each (lambda (runrec) (let* ((run-id (simple-run-id runrec)) (full-targ-runname (conc (simple-run-target runrec) "/" (simple-run-runname runrec)))) (debug:print 0 *default-log-port* "Update run " run-id) (sparse-vector-set! (dboard:rdat-runs rdat) run-id runrec) (hash-table-set! (dboard:rdat-targ-runid rdat) full-targ-runname run-id) )) data) numruns)) ;; NOTE: runnum is NOT the run-id, it is a pointer into the runsbynum vector ;; (define (dashboard:update-run-data runnum rdat) (let* ((curr-time (current-seconds)) (runrec (vector-ref (dboard:rdat-runsbynum rdat) runnum)) (run-id (simple-run-id runrec)) (last-update (sparse-vector-ref (dboard:rdat-last-updates rdat) run-id)) ;; filters (testname-sql-filt (dboard:rdat-testname-sql-filt rdat)) ;; (itempath-sql-filt (dboard:rdat-itempath-sql-filt rdat)) (test-state-sql-filt (dboard:rdat-test-state-sql-filt rdat)) ;; not used yet (test-status-sql-filt (dboard:rdat-test-status-sql-filt rdat)) ;; not used yet (tests (rmt:get-tests-for-run-state-status run-id testname-sql-filt last-update ;; last-update ))) (sparse-vector-set! (dboard:rdat-last-updates rdat) run-id (- curr-time 1)) (debug:print 0 *default-log-port* "Got " (length tests) " tests for run-id " run-id " testname-sql-filt " testname-sql-filt " and last-update " last-update) (length tests))) (define (new-runs-updater commondat rdat) (let* ((runnum (dboard:rdat-runnum rdat)) (start-time (current-milliseconds)) (tot-runs #f)) (if (eq? runnum 0)(dashboard:update-runs-data rdat)) (set! tot-runs (vector-length (dboard:rdat-runsbynum rdat))) (let loop ((rn runnum)) (if (and (< (- (current-milliseconds) start-time) 250) (< rn tot-runs)) (let* ((newrn (if (>= runnum (vector-length (dboard:rdat-runsbynum rdat))) 0 ;; start over (+ rn 1)))) ;; (+ runnum 1))) (dashboard:update-run-data rn rdat) (dboard:rdat-runnum-set! rdat newrn) (if (> newrn 0) (loop newrn))))) (if (>= (dboard:rdat-runnum rdat) tot-runs) (dboard:rdat-runnum-set! rdat 0)) ;; (dboard:rdat-runnum-set! rdat rn))) ;; not needed as it is set above ;; (dboard:rdat-last-update-set! rdat (- (current-seconds) 10)) ;; (tree:add-node tb "Runs" (string-split full-targ-runname "/")) '())) (define (dboard:runs-new-matrix commondat rdat) (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* ((cell (conc row ":" col))) #f)) )) (define (make-runs-view commondat rdat tab-num) ;; register an updater (dboard:commondat-add-updater commondat (lambda () (new-runs-updater commondat rdat)) tab-num: tab-num) (iup:vbox (iup:split #:orientation "VERTICAL" ;; "HORIZONTAL" #:value 100 (dboard:runs-tree-new-browser commondat rdat) (dboard:runs-new-matrix commondat rdat) ))) (define (make-dashboard-buttons commondat) ;; runs-sum-dat new-view-dat) (let* ((stats-dat (dboard:tabdat-make-data)) (runs-dat (dboard:tabdat-make-data)) (runs2-dat (make-dboard:rdat)) ;; (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)) (nruns (dboard:tabdat-numruns runs-dat)) (ntests (dboard:tabdat-num-tests runs-dat)) (keynames (dboard:tabdat-dbkeys runs-dat)) (nkeys (length keynames)) |
︙ | ︙ | |||
2496 2497 2498 2499 2500 2501 2502 | (btn-height (dboard:tabdat-runs-btn-height runs-dat)) (btn-fontsz (dboard:tabdat-runs-btn-fontsz runs-dat)) (cell-width (dboard:tabdat-runs-cell-width runs-dat))) ;; controls (along bottom) ;; (set! controls (dboard:make-controls commondat runs-dat)) ;; create the left most column for the run key names and the test names | | > | | | | > > > > | > > > > | | > > > > > > | | | | | > > > > > | | > > | | | | | > | > > > | | | | | | | | | > | | | | | | | | | 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 | (btn-height (dboard:tabdat-runs-btn-height runs-dat)) (btn-fontsz (dboard:tabdat-runs-btn-fontsz runs-dat)) (cell-width (dboard:tabdat-runs-cell-width runs-dat))) ;; controls (along bottom) ;; (set! controls (dboard:make-controls commondat runs-dat)) ;; create the left most column for the run key names and the test names (set! lftlst (list (iup:hbox (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 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 '())) (cond ((>= testnum ntests) ;; now lftlst will be an hbox with the test keys and the test name labels (set! lftlst (append lftlst (list (iup:hbox #:expand "HORIZONTAL" (iup:valuator #:valuechanged_cb (lambda (obj) (let ((val (string->number (iup:attribute obj "VALUE"))) (oldmax (string->number (iup:attribute obj "MAX"))) (newmax (* 10 (length (dboard:tabdat-all-test-names runs-dat))))) (dboard:commondat-please-update-set! commondat #t) (dboard:tabdat-start-test-offset-set! runs-dat (inexact->exact (round (/ val 10)))) (debug:print 6 *default-log-port* "(dboard:tabdat-start-test-offset runs-dat) " (dboard:tabdat-start-test-offset runs-dat) " val: " val " newmax: " newmax " oldmax: " oldmax) (if (< val 10) (iup:attribute-set! obj "MAX" newmax)) )) #:expand "VERTICAL" #:orientation "VERTICAL" #:min 0 #:step 0.01) (apply iup:vbox (reverse res))))))) (else (let ((labl (iup:button "" ;; the testname labels #:flat "YES" #:alignment "ALEFT" ; #:image img1 ; #:impress img2 #:size (conc cell-width btn-height) #:expand "HORIZONTAL" #:fontsize btn-fontsz #:action (lambda (obj) (mark-for-update runs-dat) (toggle-hide testnum (dboard:commondat-uidat commondat)))))) (vector-set! lftcol testnum labl) (loop (+ testnum 1)(cons labl res)))))) ;; These are the headers for each row (let loop ((runnum 0) (keynum 0) (keyvec (make-vector nkeys)) (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)))) | | | < < | | > > | > > | > | | | > | | | > < > > | 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 | "%" 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 (let ((tab-num tab-start-num) (result '())) (for-each (lambda (view-name) (debug:print 0 *default-log-port* "Adding view " view-name) (let* ((cfgtype (configf:lookup views-cfgdat view-name "type"))) ;; what type of view? (if (not (string? cfgtype)) (debug:print-info 0 *default-log-port* "WARNING: view \"" view-name "\" is missing needed sections. " "Please consult the documenation and update ~/.mtviews.config or " *toppath* "/.mtviews.config") (case (string->symbol cfgtype) ;; user supplied source for a tab ;; ((external) ;; was tabs (let ((tab-content (dboard:add-external-tab commondat view-name views-cfgdat #f tab-num))) (set! additional-tabnames (cons (cons tab-num view-name) additional-tabnames)) (set! tab-num (+ tab-num 1)) (set! result (append result (list tab-content))))))))) (sort (hash-table-keys views-cfgdat) (lambda (a b) (let ((order-a (or (any->number (configf:lookup views-cfgdat a "order")) 999)) (order-b (or (any->number (configf:lookup views-cfgdat b "order")) 999))) (> order-a order-b))))) 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 ;; (make-runs-view commondat runs2-dat 2) (dashboard:runs-summary commondat onerun-dat tab-num: 2) (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" "Runs2") (iup:attribute-set! tabs "TABTITLE2" "Run Summary") (iup:attribute-set! tabs "TABTITLE3" "Run Control") (iup:attribute-set! tabs "TABTITLE4" "Run Times") ;; (iup:attribute-set! tabs "TABTITLE3" "New View") ;; (iup:attribute-set! tabs "TABTITLE4" "Run Control") ;; set the tab names for user added tabs (for-each (lambda (tab-info) (iup:attribute-set! tabs (conc "TABTITLE" (car tab-info)) (cdr tab-info))) additional-tabnames) (iup:attribute-set! tabs "BGCOLOR" "190 190 190") ;; make the iup tabs object available (for changing color for example) (dboard:commondat-hide-not-hide-tabs-set! commondat tabs) ;; now set up the tabdat lookup (dboard:common-set-tabdat! commondat 0 stats-dat) (dboard:common-set-tabdat! commondat 1 runs-dat) ;;(dboard:common-set-tabdat! commondat 2 runs2-dat) (dboard:common-set-tabdat! commondat 2 onerun-dat) (dboard:common-set-tabdat! commondat 3 runcontrols-dat) (dboard:common-set-tabdat! commondat 4 runtimes-dat) (iup:vbox tabs ;; controls |
︙ | ︙ | |||
2747 2748 2749 2750 2751 2752 2753 | ;; Force creation of the db in case it isn't already there. ;; (tasks:open-db) (define (dashboard:get-youngest-run-db-mod-time dbdir) (handle-exceptions exn (begin | | > | | 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 | ;; Force creation of the db in case it isn't already there. ;; (tasks:open-db) (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 ", exn=" exn) (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 (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)) | < < | | 3198 3199 3200 3201 3202 3203 3204 3205 3206 3207 3208 3209 3210 3211 3212 | (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)) |
︙ | ︙ | |||
3453 3454 3455 3456 3457 3458 3459 | fres)))) (define (dashboard:runs-tab-updater commondat tab-num) (debug:catch-and-dump (lambda () (let* ((tabdat (dboard:common-get-tabdat commondat tab-num: tab-num)) (dbkeys (dboard:tabdat-dbkeys tabdat))) | < < < < < < < < | | | 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 | fres)))) (define (dashboard:runs-tab-updater commondat tab-num) (debug:catch-and-dump (lambda () (let* ((tabdat (dboard:common-get-tabdat commondat tab-num: tab-num)) (dbkeys (dboard:tabdat-dbkeys tabdat))) (dashboard:do-update-rundat tabdat) (let ((uidat (dboard:commondat-uidat commondat))) (update-buttons tabdat uidat (dboard:tabdat-numruns tabdat) (dboard:tabdat-num-tests tabdat))) )) "dashboard:runs-tab-updater")) ;;====================================================================== ;; 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) |
︙ | ︙ | |||
3504 3505 3506 3507 3508 3509 3510 3511 3512 3513 3514 | (dboard:commondat-uidat-set! commondat (make-dashboard-buttons commondat)) (dboard:commondat-curr-tab-num-set! commondat 0) (dboard:commondat-add-updater commondat (lambda () (dashboard:runs-tab-updater commondat 1)) tab-num: 1) (iup:callback-set! *tim* "ACTION_CB" (lambda (time-obj) (let ((update-is-running #f)) | > > > > > > | | | | | | | | | | | | | 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 | (dboard:commondat-uidat-set! commondat (make-dashboard-buttons commondat)) (dboard:commondat-curr-tab-num-set! commondat 0) (dboard:commondat-add-updater commondat (lambda () (dashboard:runs-tab-updater commondat 1)) tab-num: 1) ;; may not want this alive (manually merged it from v1.66) (dboard:commondat-add-updater commondat (lambda () (dashboard:runs-tab-updater commondat 1)) tab-num: 2) (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 [999bf6a3c9].
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 |
︙ | ︙ | |||
28 29 30 31 32 33 34 | (declare (uses mt)) (include "common_records.scm") (include "db_records.scm") (include "key_records.scm") (include "run_records.scm") | < > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | (declare (uses mt)) (include "common_records.scm") (include "db_records.scm") (include "key_records.scm") (include "run_records.scm") (define *number-of-writes* 0) (define *number-non-write-queries* 0) ;;====================================================================== ;; R E C O R D S ;;====================================================================== ;; each db entry is a pair ( db . dbfilepath ) ;; I propose this record evolves into the area record ;; (defstruct dbr:dbstruct (tmpdb #f) (dbstack #f) ;; stack for tmp db handles, do not initialize with a stack (mtdb #f) (refndb #f) (homehost #f) ;; not used yet (on-homehost #f) ;; not used yet (read-only #f) (stmt-cache (make-hash-table)) ) ;; goal is to converge on one struct for an area but for now it is too confusing ;; record for keeping state,status and count for doing roll-ups in ;; iterated tests ;; (defstruct dbr:counts (state #f) (status #f) (count 0)) ;;====================================================================== ;; alist-of-alists ;;====================================================================== ;; ;; (define (db:aa-set! dat key1 key2 val) ;; (let loop (( ;;====================================================================== ;; hash of hashs ;;====================================================================== (define (db:hoh-set! dat key1 key2 val) (let* ((subhash (hash-table-ref/default dat key1 #f))) (if subhash (hash-table-set! subhash key2 val) (begin (hash-table-set! dat key1 (make-hash-table)) (db:hoh-set! dat key1 key2 val))))) (define (db:hoh-get dat key1 key2) (let* ((subhash (hash-table-ref/default dat key1 #f))) (and subhash (hash-table-ref/default subhash key2 #f)))) (define (db:get-cache-stmth dbstruct db stmt) (let* ((stmt-cache (dbr:dbstruct-stmt-cache dbstruct)) (stmth (db:hoh-get stmt-cache db stmt))) (or stmth (let* ((newstmth (sqlite3:prepare db stmt))) (db:hoh-set! stmt-cache db stmt newstmth) newstmth)))) ;;====================================================================== ;; SQLITE3 HELPERS ;;====================================================================== (define (db:general-sqlite-error-dump exn stmt . params) (let ((err-status ((condition-property-accessor 'sqlite3 'status #f) exn))) ;; RADT ... how does this work? |
︙ | ︙ | |||
79 80 81 82 83 84 85 | (handle-exceptions exn (let ((err-status ((condition-property-accessor 'sqlite3 'status #f) exn))) ;; check for (exn sqlite3) ((condition-property-accessor 'exn 'message) exn) (if (eq? err-status 'done) default (begin | | | 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 | (handle-exceptions exn (let ((err-status ((condition-property-accessor 'sqlite3 'status #f) exn))) ;; check for (exn sqlite3) ((condition-property-accessor 'exn 'message) exn) (if (eq? err-status 'done) default (begin (debug:print-error 0 *default-log-port* " query " stmt " failed, params: " params ", error: " ((condition-property-accessor 'exn 'message) exn) ", exn=" exn) (print-call-chain (current-error-port)) default))) (apply sqlite3:first-result db stmt params))) ;; Get/open a database ;; if run-id => get run specific db ;; if #f => get main db |
︙ | ︙ | |||
111 112 113 114 115 116 117 | dbdat)) (define (db:dbdat-get-path dbdat) (if (pair? dbdat) (cdr dbdat) #f)) | < < < < < | < < < < | < < > > > > > | | | | | | | > | | < < < < < | | | | | | > > > > > > > > > > > | | 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 | dbdat)) (define (db:dbdat-get-path dbdat) (if (pair? dbdat) (cdr dbdat) #f)) (define-inline (db:generic-error-printout exn . message) (print-call-chain (current-error-port)) (apply debug:print-error 0 *default-log-port* message) (debug:print-error 0 *default-log-port* " params: " params ", error: " ((condition-property-accessor 'exn 'message) exn) ", arguments: " ((condition-property-accessor 'exn 'arguments) exn) ", location: " ((condition-property-accessor 'exn 'location) exn) )) ;; (db:with-db dbstruct run-id sqlite3:exec "select blah fgrom blaz;") ;; r/w is a flag to indicate if the db is modified by this query #t = yes, #f = no ;; (define (db:with-db dbstruct run-id r/w proc . params) (let* ((have-struct (dbr:dbstruct? dbstruct)) (dbdat (if have-struct (db:get-db dbstruct) #f)) (db (if have-struct (db:dbdat-get-db dbdat) dbstruct)) (fname (db:dbdat-get-path dbdat)) (use-mutex (> *api-process-request-count* 25))) ;; was 25 (if (and use-mutex (common:low-noise-print 120 "over-50-parallel-api-requests")) (debug:print-info 0 *default-log-port* *api-process-request-count* " parallel api requests being processed in process " (current-process-id) ", throttling access")) (if (common:low-noise-print 600 (conc "parallel-api-requests" *max-api-process-requests*)) (debug:print-info 2 *default-log-port* "Parallel api request count: " *api-process-request-count* " max parallel requests: " *max-api-process-requests*)) (condition-case (begin (if use-mutex (mutex-lock! *db-with-db-mutex*)) (let ((res (apply proc db params))) (if use-mutex (mutex-unlock! *db-with-db-mutex*)) ;; (if (vector? dbstruct)(db:done-with dbstruct run-id r/w)) (if dbdat (stack-push! (dbr:dbstruct-dbstack dbstruct) dbdat)) res)) (exn (io-error) (db:generic-error-printout exn "ERROR: i/o error with " fname ". Check permissions, disk space etc. and try again.")) (exn (corrupt) (db:generic-error-printout exn "ERROR: database " fname " is corrupt. Repair it to proceed.")) (exn (busy) (db:generic-error-printout exn "ERROR: database " fname " is locked. Try copying to another location, remove original and copy back.")) (exn (permission)(db:generic-error-printout exn "ERROR: database " fname " has some permissions problem.")) (exn () (db:generic-error-printout exn "ERROR: Unknown error with database " fname " message: " ((condition-property-accessor 'exn 'message) exn)))))) ;;====================================================================== ;; K E E P F I L E D B I N dbstruct ;;====================================================================== ;; (define (db:get-filedb dbstruct run-id) ;; (let ((db (vector-ref dbstruct 2))) ;; (if db |
︙ | ︙ | |||
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. ;; | < | < < < < < < < | | | | | | > > > > | > > > > > > > | | | > | > > | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | > | | | | | > > | | > > > | > > > > > | < | | | > | > > > > > > > > > > > > > > > > | < | > > > | | 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 | ;; (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) (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 | (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 | > > > > > > > > > > > > > > > > > | | | | | > < | | | | 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 | (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 stmt-cache #!key (try-num 3)) (if (<= try-num 0) #f (handle-exceptions exn (begin (print "Attempt to safely close sqlite3 db failed. Trying again. exn=" exn) (thread-sleep! 3) (sqlite3:interrupt! db) (db:safely-close-sqlite3-db db stmtcache try-num: (- try-num 1))) (if (sqlite3:database? db) (let* ((stmts (and stmt-cache (hash-table-ref/default stmt-cache db #f)))) (if stmts (map sqlite3:finalize! (hash-table-values stmts))) (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) ", note - exn=" 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))) (stmt-cache (dbr:dbstruct-stmt-cache dbstruct))) (map (lambda (db) (db:safely-close-sqlite3-db db stmt-cache)) tdbs) (db:safely-close-sqlite3-db mdb stmt-cache) ;; (if (sqlite3:database? mdb) (sqlite3:finalize! mdb)) (db:safely-close-sqlite3-db rdb stmt-cache))))) ;; (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) | | > | > | > | > > > > > > > > > > > > > > > > | 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 | '("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 "archive_disks" '("id" #f) '("archive_area_name" #f) '("disk_path" #f) '("last_df" #f) '("last_df_time" #f) '("creation_time" #f)) (list "archive_blocks" '("id" #f) '("archive_disk_id" #f) '("disk_path" #f) '("last_du" #f) '("last_du_time" #f) '("creation_time" #f)) (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)) | | | 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 | (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)))) |
︙ | ︙ | |||
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 | ;; ;; NOPE: apply this same approach to all db files ;; (else ;; ((equal? fname "megatest.db") ;; this file can be regenerated if needed (handle-exceptions exn (begin ;; (db:move-and-recreate-db dbdat) (if (> numtries 0) (db:repair-db dbdat numtries: (- numtries 1)) #f) (debug:print 0 *default-log-port* "FATAL: file " dbpath " was found corrupted, an attempt to fix has been made but you must start over.") (debug:print 0 *default-log-port* " check the following:\n" " 1. full directories, look in ~/ /tmp and " dbdir "\n" " 2. write access to " dbdir "\n\n" " if the automatic recovery failed you may be able to recover data by doing \"" (if (member fname '("megatest.db" "monitor.db")) "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;"))) | > > > | | | 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 | ;; ;; NOPE: apply this same approach to all db files ;; (else ;; ((equal? fname "megatest.db") ;; this file can be regenerated if needed (handle-exceptions exn (begin (print "Problems trying to repair the db, exn=" exn) ;; (db:move-and-recreate-db dbdat) (if (> numtries 0) (db:repair-db dbdat numtries: (- numtries 1)) #f) (debug:print 0 *default-log-port* "FATAL: file " dbpath " was found corrupted, an attempt to fix has been made but you must start over.") (debug:print 0 *default-log-port* " check the following:\n" " 1. full directories, look in ~/ /tmp and " dbdir "\n" " 2. write access to " dbdir "\n\n" " if the automatic recovery failed you may be able to recover data by doing \"" (if (member fname '("megatest.db" "monitor.db")) "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) | | | > | > > > > | | | > | | > > > > > > > | > > > > | | | | > > > | 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 | (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) (field-names (map car fields)) (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")) | | > > > > > > | > > > > > > | > > | 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 | ;; 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)) (drp-trigger (if (member "last_update" field-names) (db:drop-trigger db tablename) #f)) (is-trigger-dropped (if (member "last_update" field-names) (db:is-trigger-dropped db tablename) #f)) (stmth (sqlite3:prepare db full-ins))) ;; (db:delay-if-busy targdb) ;; NO WAITING (if (member "last_update" field-names) (debug:print-info 3 *default-log-port* "is-trigger-dropped: " is-trigger-dropped)) (for-each (lambda (fromdat-lst) (sqlite3:with-transaction db (lambda () (for-each ;; (lambda (fromrow) |
︙ | ︙ | |||
746 747 748 749 750 751 752 | (if (and same (< i (- num-fields 1))) (loop (+ i 1)))) (if (not same) (begin (apply sqlite3:execute stmth (vector->list fromrow)) (hash-table-set! numrecs tablename (+ 1 (hash-table-ref/default numrecs tablename 0))))))) | | < | > > | 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 | (if (and same (< i (- num-fields 1))) (loop (+ i 1)))) (if (not same) (begin (apply sqlite3:execute stmth (vector->list fromrow)) (hash-table-set! numrecs tablename (+ 1 (hash-table-ref/default numrecs tablename 0))))))) fromdat-lst)))) fromdats) (sqlite3:finalize! stmth) (if (member "last_update" field-names) (db:create-trigger db tablename)))) (append (list todb) slave-dbs)))) tbls) (let* ((runtime (- (current-milliseconds) start-time)) (should-print (or (debug:debug-mode 12) (common:low-noise-print 120 "db sync" (> runtime 500))))) ;; low and high sync times treated as separate. (if should-print (debug:print 3 *default-log-port* "INFO: db sync, total run time " runtime " ms")) (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; | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | 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)) | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | > > > > | | | | | | | | > > > > | | | < | | | | < < < < < < < | | | < | | | < < < < < < < < < < | | | | | | | | | > > > | | < | | | | | | | | < < < < | < < | | > | < < < | < < < < | | > > | < | | | | | | < > | < | > > > < < < < < < < < < < < < < < < | < < | < | > > | > | > | | < > | < < | < < > > > > | > > > | | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | > > > > > | | | | | | | > | | | | | | | > | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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 | ;; 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:trigger-list (list (list "update_runs_trigger" "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;" ) (list "update_run_stats_trigger" "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;" ) (list "update_tests_trigger" "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;" ) (list "update_teststeps_trigger" "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;" ) (list "update_test_data_trigger" "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;" ))) (define (db:create-all-triggers dbstruct) (db:with-db dbstruct #f #f (lambda (db) (db:create-triggers db)))) (define (db:create-triggers db) (for-each (lambda (key) (sqlite3:execute db (cadr key))) db:trigger-list)) (define (db:drop-all-triggers dbstruct) (db:with-db dbstruct #f #f (lambda (db) (db:drop-triggers db)))) (define (db:is-trigger-dropped db tbl-name) (let* ((trigger-name (if (equal? tbl-name "test_steps") "update_teststeps_trigger" (conc "update_" tbl-name "_trigger"))) (res #f)) (sqlite3:for-each-row (lambda (name) (if (equal? name trigger-name) (set! res #t))) db "SELECT name FROM sqlite_master WHERE type = 'trigger' ;" ))) (define (db:drop-triggers db) (for-each (lambda (key) (sqlite3:execute db (conc "drop trigger if exists " (car key)))) db:trigger-list)) (define (db:drop-trigger db tbl-name) (let* ((trigger-name (if (equal? tbl-name "test_steps") "update_teststeps_trigger" (conc "update_" tbl-name "_trigger")))) (for-each (lambda (key) (if (equal? (car key) trigger-name) (sqlite3:execute db (conc "drop trigger if exists " trigger-name)))) db:trigger-list))) (define (db:create-trigger db tbl-name) (let* ((trigger-name (if (equal? tbl-name "test_steps") "update_teststeps_trigger" (conc "update_" tbl-name "_trigger")))) (for-each (lambda (key) (if (equal? (car key) trigger-name) (sqlite3:execute db (cadr key)))) db:trigger-list))) (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 "));")) ;; All triggers created at once in end ;;(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')))") ;; All triggers created at once in end ;; (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('%s','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('%s','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('%s','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));") | | > > > > > > | | | | | | | | > | | | | | | | | > | | | | | | | | > | | 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 | 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 ;; All triggers created at once in end ;;(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);") ;; All triggers created at once in end ;;(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);") ;; All triggers created at once in end ;;(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:create-triggers db) 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 | > | 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 | 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 | < | | < | > > | 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 | (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) | | | | 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 | ;;====================================================================== ;; 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) | | | 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 | (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 ;; |
︙ | ︙ | |||
1536 1537 1538 1539 1540 1541 1542 | (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.") (if (and (null? incompleted) (null? oldlaunched) (null? toplevels)) #f #t))))) | > > > > > > > > > > > | > > > > > > > > > > > > > > > > | | > > > | | > > | > > > > > | | | > > > > | | | > > > > > > > > > > > > > | | | | | | | | | > | | | | | | > | > > > > > | > > > > > > > > > > | > | > > > | | | | | | | | | | > > > | < < > | | > > | | < < < < < < < | | | | > | > | | > | | | < < | > > | | | < | > | | | | | | | | > | > > > > > > | > | | | | | | > > > > > > > > | 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 | (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.") (if (and (null? incompleted) (null? oldlaunched) (null? toplevels)) #f #t))))) (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) ))) ;; check duration against test-run.dat file if it exists and update the value in ;; the db if necessary ;; (define (db:adjust-run-duration dbstruct test-id run-dir event-time run-duration) (let* ((datf (conc run-dir ".mt_data/test-run.dat")) (modt (if (and (file-exists? datf) (file-read-access? datf)) (file-modification-time datf) #f)) ;; (+ event-time run-duration)))) (alt-run-duration (if modt (- modt event-time) #f))) (if (and alt-run-duration (> alt-run-duration run-duration)) (begin (debug:print 0 *default-log-port* "Test " test-id " run duration mismatch. Setting to " alt-run-duration) (db:with-db dbstruct #f #f (lambda (db) (sqlite3:execute db "UPDATE tests SET run_duration=? WHERE id=?;" alt-run-duration test-id) #t))) #f))) ;; #f = we did NOT adjust the time ;; 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) (let* ((stmth1 (db:get-cache-stmth dbstruct 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');")) (stmth2 (db:get-cache-stmth dbstruct 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');")) (stmth3 (db:get-cache-stmth dbstruct db "SELECT id,rundir,uname,testname,item_path FROM tests WHERE run_id=? AND (strftime('%s','now') - event_time) > 86400 AND state IN ('LAUNCHED');"))) ;; 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 (not (db:adjust-run-duration dbstruct test-id run-dir 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))))) stmth1 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 (not (db:adjust-run-duration dbstruct test-id run-dir 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)))))) stmth2 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))))) stmth3 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-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 (and (not (eq? pid 0)) ;; 0 is default in re-used field "attemptnum" where pid stored. (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."))))))) ;; call end of eud of run detection for posthook - from merge, is it needed? ;; (launch:end-of-run-check run-id) all-ids) ;;call end of eud of run detection for posthook (launch:end-of-run-check run-id) ))))))) ;; BUG: Probably broken - does not explicitly use run-id in the query ;; (define (db:top-test-set-per-pf-counts dbstruct run-id test-name) (db:general-call dbstruct 'top-test-set-per-pf-counts (list test-name test-name test-name test-name test-name test-name test-name test-name test-name test-name test-name test-name test-name test-name test-name test-name test-name))) ;; Clean out old junk and vacuum the database ;; ;; Ultimately do something like this: ;; ;; 1. Look at test records either deleted or part of deleted run: ;; a. If test dir exists, set the the test to state='UNKNOWN', Set the run to 'unknown' ;; 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) |
︙ | ︙ | |||
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 | "SELECT val FROM metadat WHERE var=?;" var) ;; convert to number if can (if (string? res) (let ((valnum (string->number res))) (if valnum (set! res valnum)))) res)))) ;; This was part of db:get-var. It was used to estimate the load on ;; the database files. ;; ;; scale by 10, average with current value. ;; (set! *global-delta* (/ (+ *global-delta* (* (- (current-milliseconds) start-ms) ;; (if throttle throttle 0.01))) ;; 2)) ;; (if (> (abs (- *last-global-delta-printed* *global-delta*)) 0.08) ;; don't print all the time, only if it changes a bit ;; (begin ;; (debug:print-info 4 *default-log-port* "launch throttle factor=" *global-delta*) ;; (set! *last-global-delta-printed* *global-delta*))) (define (db:set-var dbstruct var val) (db:with-db dbstruct #f #t (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? | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | "SELECT val FROM metadat WHERE var=?;" var) ;; convert to number if can (if (string? res) (let ((valnum (string->number res))) (if valnum (set! res valnum)))) res)))) (define (db:inc-var dbstruct var) (db:with-db dbstruct #f #t (lambda (db) (sqlite3:execute db "UPDATE metadat SET val=val+1 WHERE var=?;" var)))) (define (db:dec-var dbstruct var) (db:with-db dbstruct #f #t (lambda (db) (sqlite3:execute db "UPDATE metadat SET val=val-1 WHERE var=?;" var)))) ;; This was part of db:get-var. It was used to estimate the load on ;; the database files. ;; ;; scale by 10, average with current value. ;; (set! *global-delta* (/ (+ *global-delta* (* (- (current-milliseconds) start-ms) ;; (if throttle throttle 0.01))) ;; 2)) ;; (if (> (abs (- *last-global-delta-printed* *global-delta*)) 0.08) ;; don't print all the time, only if it changes a bit ;; (begin ;; (debug:print-info 4 *default-log-port* "launch throttle factor=" *global-delta*) ;; (set! *last-global-delta-printed* *global-delta*))) (define (db:set-var dbstruct var val) (db:with-db dbstruct #f #t (lambda (db) (sqlite3:execute db "INSERT OR REPLACE INTO metadat (var,val) VALUES (?,?);" var val)))) (define (db:add-var dbstruct var val) (db:with-db dbstruct #f #t (lambda (db) (sqlite3:execute db "UPDATE metadat SET val=val+? WHERE var=?;" val var)))) (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 "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;"))) ;; MOVE THIS TABLE CREATION TO THE (begin above in about six months (it is Sep 2020 right now). (sqlite3:execute db "CREATE TABLE IF NOT EXISTS jobs_queue (id INTEGER PRIMARY KEY, host_type TEXT, cores INTEGER, memory TEXT, vars TEXT, exekey TEXT, cmdline TEXT, state TEXT, event_time INTEGER, last_update INTEGER);") ;; not sure I'll use this next one. I prefer if tests simply append to a file: ;; last-update-seconds cpuload tmpspace rundirspace (sqlite3:execute db "CREATE TABLE IF NOT EXISTS test_extra_data (id INTEGER PRIMARY KEY, run_id INTEGER, test_id INTEGER, last_seen_running INTEGER);") (sqlite3:execute db "PRAGMA synchronous = 0;") db)) (define (db:no-sync-add-job db-in host-type vars-list exekey cmdline) (sqlite3:execute (db:no-sync-db db-in) "INSERT INTO jobs_queue (host_type,vars,exekey,cmdline,state,event_time,last_update) VALUES (?,?,?,?,?,?,?);" host-type (with-output-to-string (lambda () (write vars-list))) exekey cmdline "waiting" (current-seconds)(current-seconds))) ;; find next job (waiting longest) that matches host-type - future, we'll find jobs that fit if no exact match (define (db:no-sync-take-job db-in host-type) (let* ((db (db:no-sync-db db-in)) (stmt1 "SELECT id,host_type,vars,exekey,cmdline,state,event_time,last_update FROM jobs_queue WHERE host_type=? AND state != 'taken' ORDER BY event_time ASC;") (stmt1h (sqlite3:prepare db stmt1)) (stmt2 "UPDATE jobs_queue SET state='taken',last_update=? WHERE id=?;") (stmt2h (sqlite3:prepare db stmt2)) (res (sqlite3:with-transaction db (lambda () (let* ((matching-jobs (sqlite3:fold-row (lambda (res . row) ;; id host-type vars exekey state event-time last-update) (cons row res)) '() stmt1h host-type))) (if (null? matching-jobs) #f (let ((choosen-one (let loop ((tal matching-jobs) (res #f)) ;; put bestest one in here (if (null? tal) res (let ((curr (car tal)) (rem (cdr tal))) curr) ;; here we will compare with res, if better candidate the loop with curr else loop with res )))) (if choosen-one ;; we need to mark it as taken (sqlite3:execute stmt2h (current-seconds) (car choosen-one))) choosen-one))))))) (sqlite3:finalize! stmt1h) ;; it'd be nice to cache these and finalize on exit. (sqlite3:finalize! stmt2h) res)) ;; clean out old jobs in queue, i.e. taken and event_time > 24 hrs ago ;; (define (db:no-sync-job-records-clean db) (sqlite3:execute (db:no-sync-db db) "DELETE FROM jobs_queue WHERE state='taken' AND event_time < ?;" (- (current-seconds)(* 24 3600)))) ;; 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-in var default) (let ((db (db:no-sync-db db-in)) (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 stmt-cache) (db:safely-close-sqlite3-db db stmt-cache)) ;; 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))) (debug:print-info 2 *default-log-port* "db:no-sync-get-lock keyname=" keyname ", lock-time=" lock-time ", exn=" exn) (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? |
︙ | ︙ | |||
1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 | (lambda (key) (set! res (cons key res))) db "SELECT fieldname FROM keys ORDER BY id DESC;"))) (set! *db-keys* res) 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)) | > > > > | | | > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > | 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 | (lambda (key) (set! res (cons key res))) db "SELECT fieldname FROM keys ORDER BY id DESC;"))) (set! *db-keys* res) res))) ;; extract index number given a header/data structure (define (db:get-index-by-header header field) (list-index (lambda (x)(equal? x field)) header)) ;; 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 ", exn=" exn) #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)) | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | (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 last-update) (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' " (if (number? last-update) (conc " AND last_update >= " last-update) "") " 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 | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | (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 ;; | | | 2779 2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 | ;; 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 " ") " ") | | > > | 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 | (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)) | | > | | 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 | ;; 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) | | > > > > > > > > > > > > > > > > > > > > > > | | | | 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 | 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 |
︙ | ︙ | |||
2486 2487 2488 2489 2490 2491 2492 | " "))) (if sort-order sort-order " ") (if limit (conc " LIMIT " limit) " ") (if offset (conc " OFFSET " offset) " ") ";" ))) (debug:print-info 8 *default-log-port* "db:get-tests-for-run run-id=" run-id ", qry=" qry) | | | > > | > | | < > > | | | | | | | > > > > > > > > | > > > | | | > > > > > > > > > > > > > > > > > > > > | | | | > | | | 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 | " "))) (if sort-order sort-order " ") (if limit (conc " LIMIT " limit) " ") (if offset (conc " OFFSET " offset) " ") ";" ))) (debug:print-info 8 *default-log-port* "db:get-tests-for-run run-id=" run-id ", qry=" qry) (let* ((res (db:with-db dbstruct run-id #f (lambda (db) ;; (let* ((stmth (db:get-cache-stmth dbstruct db qry))) ;; due to use of last-update we can't efficiently cache this query (reverse (sqlite3:fold-row (lambda (res . row) ;; id run-id testname state status event-time host cpuload ;; diskfree uname rundir item-path run-duration final-logf comment) (cons (list->vector row) res)) '() db qry ;; stmth (or run-id 1) ;; 1 > 0 , for the case where we are seeking tests matching criteral for all runs )))))) (case qryvals ((shortlist)(map db:test-short-record->norm res)) ((#f) res) (else res))))) (define (db:test-short-record->norm inrec) ;; "id,run_id,testname,item_path,state,status" ;; "id,run_id,testname,state,status,event_time,host,cpuload,diskfree,uname,rundir,item_path,run_duration,final_logf,comment (vector (vector-ref inrec 0) ;; id (vector-ref inrec 1) ;; run_id (vector-ref inrec 2) ;; testname (vector-ref inrec 4) ;; state (vector-ref inrec 5) ;; status -1 "" -1 -1 "" "-" (vector-ref inrec 3) ;; item-path -1 "-" "-")) ;; ;; 1. cache tests-match-qry ;; 2. compile qry and store in hash ;; 3. convert for-each-row to fold ;; (define (db:get-tests-for-run-state-status dbstruct run-id testpatt) (db:with-db dbstruct run-id #f (lambda (db) (let* ((res '()) (stmt-cache (dbr:dbstruct-stmt-cache dbstruct)) (stmth (let* ((sh (db:hoh-get stmt-cache db testpatt))) (or sh (let* ((tests-match-qry (tests:match->sqlqry testpatt)) (qry (conc "SELECT id,testname,item_path,state,status FROM tests WHERE run_id=? " (if tests-match-qry (conc " AND (" tests-match-qry ") ") ""))) (newsh (sqlite3:prepare db qry))) (debug:print-info 8 *default-log-port* "db:get-tests-for-run qry=" qry) (db:hoh-set! stmt-cache db testpatt newsh) newsh))))) (reverse (sqlite3:fold-row (lambda (res id testname item-path state status) ;; id,run_id,testname,state,status,event_time,host,cpuload,diskfree,uname,rundir,item_path,run_duration,final_logf,comment (cons (vector id run-id testname state status -1 "" -1 -1 "" "-" item-path -1 "-" "-") res)) '() stmth run-id)))))) (define (db:get-tests-for-run-state-status dbstruct run-id testpatt #!optional (last-update 0)) (let* ((res '()) (tests-match-qry (tests:match->sqlqry testpatt)) (qry (conc "SELECT id,testname,item_path,state,status,event_time,run_duration FROM tests WHERE run_id=? " " AND last_update > ? " (if tests-match-qry (conc " AND (" tests-match-qry ") ") "") ))) (debug:print-info 8 *default-log-port* "db:get-tests-for-run qry=" qry) (db:with-db dbstruct run-id #f (lambda (db) (sqlite3:fold-row (lambda (res id testname item-path state status event-time run-duration) ;; id,run_id,testname,state,status,event_time,host,cpuload,diskfree,uname,rundir,item_path,run_duration,final_logf,comment (cons (vector id run-id testname state status event-time "" -1 -1 "" "-" item-path run-duration "-" "-") res)) '() db qry run-id (or last-update 0)))))) (define (db:get-testinfo-state-status dbstruct run-id test-id) (let ((res #f)) (db:with-db dbstruct run-id #f (lambda (db) (sqlite3:for-each-row (lambda (run-id testname item-path state status) |
︙ | ︙ | |||
2576 2577 2578 2579 2580 2581 2582 | (db:with-db dbstruct #f #f (lambda (db) (sqlite3:execute db "UPDATE tests SET state='DELETED',status='n/a',comment='' WHERE id=?;" test-id)))) ;; (define (db:delete-old-deleted-test-records dbstruct) | | > | | 3213 3214 3215 3216 3217 3218 3219 3220 3221 3222 3223 3224 3225 3226 3227 3228 3229 | (db:with-db dbstruct #f #f (lambda (db) (sqlite3:execute db "UPDATE tests SET state='DELETED',status='n/a',comment='' WHERE id=?;" test-id)))) ;; (define (db:delete-old-deleted-test-records dbstruct) (let ((targtime (- (current-seconds) (or (configf:lookup-number *configdat* "setup" "keep-deleted-records") (* 30 24 60 60))))) ;; one month in the past (db:with-db dbstruct 0 #t (lambda (db) (sqlite3:with-transaction db |
︙ | ︙ | |||
2653 2654 2655 2656 2657 2658 2659 | (if newcomment (sqlite3:execute db "UPDATE tests SET comment=? WHERE id=?;" newcomment ;; (sdb:qry 'getid newcomment) test-id)))))) (mt:process-triggers dbstruct run-id test-id newstate newstatus)) ;; NEW BEHAVIOR: Count tests running in all runs! ;; (define (db:get-count-tests-running dbstruct run-id) | > | | | | | > | < < < < < < | > | | | | | > | > > | < > | > > | > > > > | > > > | > > > | 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 | (if newcomment (sqlite3:execute db "UPDATE tests SET comment=? WHERE id=?;" newcomment ;; (sdb:qry 'getid newcomment) test-id)))))) (mt:process-triggers dbstruct run-id test-id newstate newstatus)) ;; NEW BEHAVIOR: Count tests running in all runs! ;; (define (db:get-count-tests-running dbstruct run-id) (let* ((qry "SELECT count(id) FROM tests WHERE state in ('RUNNING','LAUNCHED','REMOTEHOSTSTART') AND NOT (uname = 'n/a' AND item_path = '');")) (db:with-db dbstruct run-id #f (lambda (db) (let* ((stmth (db:get-cache-stmth dbstruct db qry))) (sqlite3:first-result stmth)))))) ;; NEW BEHAVIOR: Count tests running in only one run! ;; (define (db:get-count-tests-actually-running dbstruct run-id) (db:with-db dbstruct 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) (let* ((qry "SELECT count(id) FROM tests WHERE state in ('RUNNING','LAUNCHED','REMOTEHOSTSTART') AND run_id=?;")) (db:with-db dbstruct run-id #f (lambda (db) (let* ((stmth (db:get-cache-stmth dbstruct db qry))) (sqlite3:fold-row (lambda (res val) val) 0 stmth run-id)))))) ;; (sqlite3:first-result stmth 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) (let* ((stmt "SELECT count(id) FROM tests WHERE state in ('RUNNING','LAUNCHED','REMOTEHOSTSTART') AND run_id=? AND NOT (uname = 'n/a' AND item_path = '') AND testname=?;") (stmth (db:get-cache-stmth dbstruct db stmt))) (sqlite3:fold-row (lambda (res val) val) 0 stmth run-id testname))))) (define (db:get-not-completed-cnt dbstruct run-id) (db:with-db dbstruct run-id #f (lambda (db) (let* ((stmt "SELECT count(id) FROM tests WHERE state not in ('COMPLETED', 'DELETED') AND run_id=?;")) (sqlite3:fold-row (lambda (res val) val) 0 (db:get-cache-stmth dbstruct db stmt) 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 |
︙ | ︙ | |||
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" | | > > > > > > | 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 | 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)) (tal (cdr fields)) (indx 0)) (if (equal? fieldname hed) indx (if (null? tal) #f (loop (car tal)(cdr tal)(+ indx 1))))))) (define db:test-record-qry-selector (string-intersperse db:test-record-fields ",")) (define (db:update-tesdata-on-repilcate-db dbstruct old-lt new-lt) (db:with-db dbstruct #f #f (lambda (db) (sqlite3:execute db "UPDATE tests SET rundir= replace(rundir,?,?), shortdir=replace(shortdir,?,?);" old-lt new-lt old-lt new-lt)))) ;; NOTE: Use db:test-get* to access records ;; NOTE: This needs rundir decoding? Decide, decode here or where used? For the moment decode where used. (define (db:get-all-tests-info-by-run-id dbstruct run-id) (let* ((res '())) (db:with-db dbstruct #f #f |
︙ | ︙ | |||
2886 2887 2888 2889 2890 2891 2892 | (let* ((run-ids (db:get-all-run-ids mtdb))) (for-each (lambda (run-id) (let ((testrecs (db:get-all-tests-info-by-run-id mtdb run-id))) (db:prep-megatest.db-adj-test-ids (db:dbdat-get-db mtdb) run-id testrecs))) run-ids))) | | | | | 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 | (let* ((run-ids (db:get-all-run-ids mtdb))) (for-each (lambda (run-id) (let ((testrecs (db:get-all-tests-info-by-run-id mtdb run-id))) (db:prep-megatest.db-adj-test-ids (db:dbdat-get-db mtdb) run-id testrecs))) run-ids))) ;; Get test data using test_id, run-id is not used - but it will be! ;; (define (db:get-test-info-by-id dbstruct run-id test-id) (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 ""))))) | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | #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) (let* ((stmt "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; (db:with-db dbstruct #f #f (lambda (db) (let* ((stmth (db:get-cache-stmth dbstruct db stmt)) (res (sqlite3:fold-row (lambda (res id test-id category variable value expected tol units comment status type last-update) (vector id test-id category variable value expected tol units comment status type last-update)) (vector #f #f #f #f #f #f #f #f #f #f #f #f) stmth 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")) | | | | 3811 3812 3813 3814 3815 3816 3817 3818 3819 3820 3821 3822 3823 3824 3825 3826 | 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 | > > > > > > > > > > > > > > > | 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 | (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 "")) | > > | > | | < | | > > > | < > | < | | < < < < < < < < < < < < < < < < < < | < < < < < < < < < < | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > | | | | | | | > | | > > > > > > > > > > > > > > > > > > > > > | 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 | ;; 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* ;; ;; NOTE: This is called within a transaction ;; (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=?;") | | | 4271 4272 4273 4274 4275 4276 4277 4278 4279 4280 4281 4282 4283 4284 4285 | (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)) | | | 4423 4424 4425 4426 4427 4428 4429 4430 4431 4432 4433 4434 4435 4436 4437 | (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 | > | | | | | | | | 4446 4447 4448 4449 4450 4451 4452 4453 4454 4455 4456 4457 4458 4459 4460 4461 4462 4463 4464 4465 4466 4467 | ;; 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) |
︙ | ︙ | |||
3714 3715 3716 3717 3718 3719 3720 | (if dbdat (let* ((dbpath (db:dbdat-get-path dbdat)) (db (db:dbdat-get-db dbdat)) ;; we'll return this so (db:delay--if-busy can be called inline (dbfj (conc dbpath "-journal"))) (if (handle-exceptions exn (begin | | | | 4560 4561 4562 4563 4564 4565 4566 4567 4568 4569 4570 4571 4572 4573 4574 4575 4576 4577 | (if dbdat (let* ((dbpath (db:dbdat-get-path dbdat)) (db (db:dbdat-get-db dbdat)) ;; we'll return this so (db:delay--if-busy can be called inline (dbfj (conc dbpath "-journal"))) (if (handle-exceptions exn (begin (debug:print-info 0 *default-log-port* "WARNING: failed to test for existance of " dbfj ", exn=" exn) (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") | | | 4627 4628 4629 4630 4631 4632 4633 4634 4635 4636 4637 4638 4639 4640 4641 | (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) | > > > > > > > > > | > > > > | > > > > > > > > | 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 | (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 ", exn=" exn) 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)) '() | > > > > > > > > > > > > > > | | > > | > > > | | > > | | < | | | > > > | | | | | | > > > > | > > > > | | | > | | | > < < | > | | > | | | | | > > | > > > > > > > > > | > > > > > > > > > > > > > > | | | | > > > > > > > > > > > > > > > > > > > > > > > > | | | | | | 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 | ;; (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 "/" | | | | 5030 5031 5032 5033 5034 5035 5036 5037 5038 5039 5040 5041 5042 5043 5044 5045 | (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" "%")) "%") | > | 5078 5079 5080 5081 5082 5083 5084 5085 5086 5087 5088 5089 5090 | (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)) |
︙ | ︙ |
Added dbmod.scm version [2029a02dc3].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | ;;====================================================================== ;; 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 dbmod)) (module dbmod * (import scheme chicken data-structures extras) (import (prefix sqlite3 sqlite3:) posix typed-records srfi-18) (define (just-testing) (print "JUST TESTING")) ;; (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)) ) |
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 [a84560491e].
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 gutils)) (declare (uses db)) ;; (declare (uses synchash)) (include "megatest-version.scm") (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) |
︙ | ︙ | |||
536 537 538 539 540 541 542 543 544 545 | ;; (iup:attribute-set! general-matrix "2:0" "Area") ;; (iup:attribute-set! general-matrix "2:1" *toppath*) ;; Megatest version (iup:attribute-set! general-matrix "2:0" "Version") (iup:attribute-set! general-matrix "2:1" (conc megatest-version "-" (substring megatest-fossil-hash 0 4))) general-matrix)) (define (dcommon:run-stats commondat tabdat #!key (tab-num #f)) (let* ((stats-matrix (iup:matrix expand: "YES")) | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 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 | ;; (iup:attribute-set! general-matrix "2:0" "Area") ;; (iup:attribute-set! general-matrix "2:1" *toppath*) ;; Megatest version (iup:attribute-set! general-matrix "2:0" "Version") (iup:attribute-set! general-matrix "2:1" (conc megatest-version "-" (substring megatest-fossil-hash 0 4))) general-matrix)) (define (dcommon:stats-updater commondat tabdat stats-matrix) (if (and (iup:ihandle? stats-matrix) (dashboard:database-changed? commondat tabdat context-key: 'run-stats)) (let* ((changed #f) (run-stats (rmt:get-run-stats)) (indices (common:sparse-list-generate-index run-stats)) ;; proc: set-cell)) (row-indices (car indices)) (col-indices (cadr indices)) (max-row (if (null? row-indices) 1 (common:max (map cadr row-indices)))) (max-col (if (null? col-indices) 1 (common:max (map cadr col-indices)))) (max-visible (max (- (dboard:tabdat-num-tests tabdat) 15) 3)) (max-col-vis (if (> max-col 10) 10 max-col)) (numrows 1) (numcols 1)) (iup:attribute-set! stats-matrix "CLEARVALUE" "CONTENTS") (iup:attribute-set! stats-matrix "NUMCOL" max-col ) (iup:attribute-set! stats-matrix "NUMLIN" (if (< max-row max-visible) max-visible max-row)) ;; min of 20 (iup:attribute-set! stats-matrix "NUMCOL_VISIBLE" max-col-vis) (iup:attribute-set! stats-matrix "NUMLIN_VISIBLE" (if (> max-row max-visible) max-visible max-row)) ;;(print "row-indices: " row-indices " col-indices: " col-indices) ;; Row labels (for-each (lambda (ind) (let* ((name (car ind)) (num (cadr ind)) (key (conc num ":0"))) (if (not (equal? (iup:attribute stats-matrix key) name)) (begin (set! changed #t) (iup:attribute-set! stats-matrix key name))))) row-indices) ;; Col labels (for-each (lambda (ind) (let* ((name (car ind)) (num (cadr ind)) (key (conc "0:" num))) (if (not (equal? (iup:attribute stats-matrix key) name)) (begin (set! changed #t) (iup:attribute-set! stats-matrix key name))))) col-indices) ;; Cell contents (for-each (lambda (entry) (let* ((row-name (car entry)) (col-name (cadr entry)) (value (caddr entry)) (row-num (cadr (assoc row-name row-indices))) (col-num (cadr (assoc col-name col-indices))) (key (conc row-num ":" col-num))) (if (not (equal? (iup:attribute stats-matrix key) value)) (begin (set! changed #t) (iup:attribute-set! stats-matrix key value))))) run-stats) (if changed (iup:attribute-set! stats-matrix "REDRAW" "ALL"))))) (define (dcommon:run-stats commondat tabdat #!key (tab-num #f)) (let* ((stats-matrix (iup:matrix expand: "YES")) (stats-updater (lambda () (dcommon:stats-updater commondat tabdat stats-matrix)))) ;; (dboard:commondat-please-update-set! commondat #t) ;; force redraw on first pass ;; (mark-for-update tabdat) ;; (stats-updater) (dboard:commondat-add-updater commondat stats-updater tab-num: tab-num) ;; (set! dashboard:update-summary-tab updater) (iup:attribute-set! stats-matrix "WIDTHDEF" "40") (iup:vbox |
︙ | ︙ | |||
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"))) | | | 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 | (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))))) |
︙ | ︙ | |||
869 870 871 872 873 874 875 | (define (dcommon:y->canvas y scalef yoffset) (+ yoffset (* y scalef))) ;; sizex, sizey - canvas size ;; originx, originy - canvas origin ;; | | | < | | 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 | (define (dcommon:y->canvas y scalef yoffset) (+ yoffset (* y scalef))) ;; sizex, sizey - canvas size ;; originx, originy - canvas origin ;; (define (dcommon:initial-draw-tests cnv xadj yadj sizex sizey sizexmm sizeymm originx originy tests-draw-state sorted-testnames test-records) (let* ((dot-data (tests:lazy-dot test-records "plain" sizex sizey 'munged)) (xoffset (dcommon:get-xoffset tests-draw-state sizex xadj)) (yoffset (dcommon:get-yoffset tests-draw-state sizey yadj)) (no-dot (configf:lookup *configdat* "setup" "nodot")) (boxh 15) (boxw 10) (margin 5) (tests-info (hash-table-ref tests-draw-state 'tests-info)) |
︙ | ︙ | |||
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)))) | | | > > | | > > | 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 | (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))) | | | | | | | | | | | | | | | | | | | > | 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 | ;; #: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)) )) | | | 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 | (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 ;;====================================================================== | | | | > > > > > > > > > > | > | > > > > > > > > | > > > | | 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 | (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)))) | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | ;;====================================================================== (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 ", exn=" exn) (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 [55192787b7].
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 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 | // Copyright 2006-2017, Matthew Welland. // // This file is part of Megatest. // // Megatest is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Megatest is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more 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. Megatest. In the v1.66 and beyond assistance to create the build system is built into the Makefile. .Installation steps (overview) ------------------------------------- ./configure make chicken setup.sh make -j install ------------------------------------- Or install the needed build system manually: . Chicken scheme from http://call-cc.org . IUP from http://webserver2.tecgraf.puc-rio.br/iup/ . CD from http://webserver2.tecgraf.puc-rio.br/cd/ . IM from https://webserver2.tecgraf.puc-rio.br/im/ . ffcall from http://webserver2.tecgraf.puc-rio.br/iup/ . Nanomsg from https://nanomsg.org/ (NOTE: Plan is to eliminate nanomsg dependency). . Needed eggs (look at the eggs lists in the Makefile) Then follow these steps: .Installation steps (self-built chicken scheme build system) ------------------------------------- ./configure make -j install ------------------------------------- |
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,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 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 O3OCiMh372NjS0/nPXuhsdFCYweHJJhbPq0wkqsU2GvHsu/8hB/DFn/x+ztGxwW6z2W3XDp+btPJ Wv7zjQoWLx8def+MoUm2bB/je1uPPH2lhYjunZr81v2Z9q1aP8e2e29df1Zmwv9WT+xwuhm7eHTQ p9laItLpmq5+Xx1vbwpqmxUzdrhsaGIIOXWtDrns7PWcy1uPV/L9JFjiuyBdtnpG+jB7zzy++6uV XzcQUYY8+tPfTA+2b7Vn++HHcpo7fkyO9V2mFPNHXVRrdrHYrq6o8NNvy9/Nb6zQWYmYjNjA1WNj FrVN2HXqn5Ljz4zI2nn5zQKdRSScmSL7688mJTtOn+0UeaqztlFhwR/vThuaICWimIxhf7hLc+yT aiKyWkzKEm1KmrTqSr19Tb8NPxoeKRERSRcvGfLRhfOnLRyR4dSVitFxGfamu/jnfTeOqS2dHI6m Rldseyl46o50eYKUiFIyxz5VUP+LbC0R3WgyedJDHDzpWqy5/j+f3yjoxsB57bUrTx+t71FKDA1o +6sKNNftx/XEzKRxGVFEFJk69LczVceyFESk0pp1RKd7288dPPkF6ar91QXVJvteIpbeNcyfiHzC ly5I+u+lK3lERNbGOj116PYAAANIr9f3aH2O44iIIYZhBJ6OsheerDhoTzZYNz0+rX3uoGDij1KW R/j/bGz0rgdH/27ucMcbDSX5a545umhf+eFqAz8S0qgz7b1cd8/m4y/sOe/ygFir6c3Xv7xnV9kx hdFKRMSdK1Ev356778T17lRVX1fxwiuH5uy4vqNE32jhiMhoshwuUC3ffnbNO6caPB7MPpVXteKT ymKdlYhqGw1W8nW52o0LiqP2FntgevwUe7zuIPCRLpmfNNI23MjtulqvIUofFZlGRERWi+7C6TYj yAVFDXy8HCELHWUPUotPn737xbO/z1VX6KxkS5BVP7Dj0sOuj5R94/OLG3K0jRaOiLtYbvrJlCh+ gLesQlvUJkXB+H2+7cexw8PS49zmWrPm+rdf//KeXWWOz7e20fDGt+Wz/vHN8XN8/f1GDw7hV87O 19bYN2ysVHxpP+8qq2iqaB0+VJ0p5Uti5ieHu+y4o4ZFRNj3/1nb3JjS09X2jsqszIju9G7oloP/ OzZze6GjnzTqTDtya+55/cSHx/L5IlISQ/j2ySvUVraO5CmO5tl6rtWiLzqvsC9vvlZlWz5HHtox Xj+ddTxm3dEtrUetHL5ud8y63XtO8KcTLcf3HJ+w+eJf7J8mEZdX3fTb/YUznjniJnXK/Nx/zm8q 0BmJrBbrVbXV31XgYuBovEycIfPzI//0ca2XHfx92p/JVyia+R3HxwbFJ9o+NbFUNmWQrZNn1zbx L1QFV+/fXszHi0KR7+hI14MCgTJxvMs37GR+Qk96yOzEwN5t6NS12O8OXOYHzifJQzqpLWuuf/ez 0gILRyS8V96Duw8GsP2lg4NiXb5hF+Av9PGgn09KDPT4F6TL9g9JjvBxsbiVQCzpfAUAgJstICAg MTExpduCg/lBj77IZb9R3WwfWxLPHOliIgWBT/zmZxe8tHb69AmpwRLb94dBfWPjO9cOuR4H4l7/ 6vo/sy51jCsrqrVvucj7tD7/VZmiw9IO1G/+5/zrrpJBibhD56s2fHC2Zyc+HZwta3bcOxgfIZ0+ zXVed165I4HXd/HIJJcfQGhiysp0W1RZcL2xWm0MTUxYIeeXcJ8UKZwap/bgJdtuF42W8dOkqAou r91RVuZidIo7dL7q5dYEWQfLsTJHyzCrpkVPnxlvTzIxHS+odKxnUJfvto1idh74Gj/bkesySddo avnpe5eu1rUQUVKGjD8PUaqay+wnBsrSxkKn1a+X2vIBai7UZttibvHY0XEu9xozOm6RPUY5cqHB 6cyGvVDUYL+yIZns5qPhndn//cPZ6o4jplaL5bef5H17QUFEg8ZEzba1jyHviq33qQpU53WOpmUv KGw1N6hrDhTyWQaiOSmuZrLp1Jn93//UzW0PterGFe98X1DXsVebjtmTNIQi4a+mxrQ/LyQiovSp E/Y9v/DY84tubJ03xGm0Xt3k2Jst6FHZlwQGipxi/9DBEbbWLle0tDt1GDJIevg3M9YmuB7jjBia sDSeDzfZF7/Ov17dRGQpPJP7oi1bQ3TfsDjyoIdsWBjnYdeqvXZ5w5f1RBQcEvK3u6Pd/6Fkvztw +Y0KExEtnZrws8E9uN9xANtf4BNzf6bt1vYt39w4V1RPxNbkXX35G/70n/nZyOhgD/r5Y3cle/gL 0o32F4xJk9lPDJR7j1wzE7Voavfuv5FHRETjh4fJ3Y8pAAD8gLAsx1o9fZSS5nKlLeNRKBKFdvvv 45ljJfttgSuzYmL8uRcW1mxdcvZXjiRO7o2j5RddJb4LRb7/XDGifOvyq0+NmmvP+Kyta64o1hBJ n3p68amVjtMG331PzKnZupzPisn/Os+RaTo1I5LPnb3427GPJNq+0g7lVH37fSV5Ji0x4vsXFtZs Xf79s3cmup7DQVOscOQ/+ES5veXRLzXWkcdsrivTEAXOGhnG/3ziQkOpfaRccbnmSxV/5iO6S84P 1Bm/+Lqcv5osFPm+vWpM+dblJS9M/VOGrcAPTlQXukjxZJ64O7Vky7KarT/+x4pxAoq9b0Io/8an V1Uq+0o3LigvEhGRUOSf6SZuJiLF5bxn7ZmyUzOiv39hYc3WJV+tSkwUMURkteh3niggotDEmLm2 uM10rtT2vV5U7nxPIndGYbvOXlau5aOJDHlInNuL3RF3jbCNQfK5Mfxr1lzxyQXb+cO8CeHJ7md/ M6ivv2jPnXWkF3//cNpUW2ezbDldYiAS+Ay6J4OfUYM7Ws7XiypKNWVORZ2obOR/N6quNPCNJpFI UjrMY0O2+3fnPGFrCkqMj7iydXnN1uXLpic41yc4RLLz5+PKty4veeGO/94h4yvUqG3855Grrq4Q CV9bMap86/LKfy596C4XCVru6Ouuv/q17YjSUkKS4gKdk3bCg32DXW1lZjlHHdITQj9YNerYH+YM G9zJHb3SXyxOmS0VEVFBmWraXw/FrNs38/0Sfqz6mUWpM0ZHkwc9ZMjQOE+6FmtWvLarpIyISLhl ydAoIePuMKouXPyVPbL83YqxbtfrtpvV/n4/WpD+4CA/ImrUNs/f/HXMuj1jX792TGslYlZNTVwx O5U86OfysXJPfkG62f7y6SPfmBHmR0RkfXrf1YR1uwf//tunLzUTUWK0dNOPx3rNpDcAAB6xslar 1ephyM5ZWdtQblyMf7fnI6z+6LRtSGj88Ji//3xSTKiYSBQ3bNimB1L4Waj5xPeOWz44M3H5rHQf orAE+RMz7UkQxFmtneebNh+7qOK/raMiw7Y8Ol2eICUSRCan/O4Xw+yjQda3z5V7dseV6Jl7MuK7 mIG+tcUS4wNcfvvyhALHt5SFH2MbPCZ6ki3kbc2NKShsqLWVJh0+IoKIDOrynZdsFwx+Ozd10bQh PkT+obGrf5pm31x/+nx5u91FyKQ/v3e0v1Msm54u46NLp9wYY06Bbfh5+uhwufsk0fx8FV8riST4 lUenxoeKiURDp014aabtrCPrgqqGiEg6aYjtNO9ASYOBiEj1fWmbMeNvi7UqIqLmcyW2S/93Dw7t pN3S5GH2oLg1N6bwZNUJe9LwoiGdjJhSyXnFaXvS8Nafjx+aICUSxI8e+de7o/kQ+fSlhhK1kUiQ kWSrhT31gi2obHIu6mJ+Y5WZJadIcXxGSE9ves0/U22vj+jt+8bOmjjYh8g/NPyu5ZNfHWtrus/O 1HY8Bxs7PGrxLHlP0wL0dRX/+M9V+7w6wqemDw7tYQmytBHvPXXXnGld7zpq6PA3HxnmOPG2Ez67 SL66dYbHXvcQT7oW++WuS+/VWYjowTuS757g9tSUNVe+8HFpLRGR6O37Rro5S++Bm9n+AZFJz/1m 4mMJ7fP31sxI+tOKcfZgt9f93JNfkO62P5H/3J/M/HBO+1n8kxNkHzw4HjM8AsAtw2plLVZ2AOY+ Vl5T5tovj94/bJDzQEjU0PRHh9v+zn5TrO2QpcuMi2nNBA6RuE4W74g11x+1XXilpaPDBzl9swZE pjxkH04+e03bjQSbTvgluhpD7StiafJPR/Mj5Y7cGOWRy7ZrEStHRfJNoy5rtieEiEbFypw2j7pr sC3IPlLRvmnTkwPbZWxEj0j8iX2cks+NMagr91zjgx7B/UNj3Xcd4w2lfTKQ5MBop9YeHB/MH4BS pass1hBRWmoYf+LFf383VtYdr+bvDgy+UyYiorKK5lq10enSue+stE6+wp2r7ciNaT3TiJCFjpvU WRJ1ncrWTyJkkhh70jARxaZK5baXhoK8OiIaPCZyrO1Y+NQLxfGCFiISigJWZfgTkdViqLiqJKo9 ls8P8DM/Tu3sbMGV1ignPjZ02Gjn9Bb/GZnRfNNZLS15eXXttpweF9zTp5fp6yr+8Z/zb9svRi2d mtBptOSpghNnZr1yqcM8j9a/ZOWtfP2kY6KkXveQXm9YfCrniWwtEUVFhj1276hO+vlnO67u1VqJ 6ME7kmaMdpl81AM3uf1rr11e8IcTb5Sb2i3f9m3p3L8fK7ZnW/W6n/d6w263P7Hm+k2vHFp+tL7d 8tJy1R2vHD94+kbvWwcAwJtYrazVau2zp5+WVegbibozjXSzymCPKX0To0PavukXJLb9iXa+1Gvn EyPrTW6iuqTJcSviMFn7i8ViP9s4n9XCeTKde+ej5h113mKOwXgikSyID7UF44aGS3KadfbcGEl+ 1f46PiumddZCQ5PJdh2aLCv//a3LwlvMLEvk/F04NrzjNWTp3aOkWypqiejTq6qHFpHyQi0/bYVE Ejh8XCfjxXqFPQ47d6U6ed1uV+twJpOViGJGR02VlHzwD+y/AAAgAElEQVSqY/nvb06r5fNQxyTI 7rawX6ma+RDZz2q7dB4hC0zsYgL11mrzuTERqS32M43WdH93HEnDSlXDWHc1N1uJSCyNmS/PP1do IDLlV9WnWPX8iah8cPC9yeyOvBYiy9lK5Qh/7ltb5pI4Y3hPozptqdKWEZEUGxDR9j1ff5H9M+PY DleZUqXtfrO6oK+7/uSWS1m220uYRRPjX74/s/9O6DVl1369u4J/ksPskbGbH5gYKaFrJ8+t3lVe ZuH4Kcn/tnyMwIMe0rsN9XXX//Z5ZSMRkei1e4cNcj9wXnDiwlNnGqkbkaXzTFMO7Z7ieZPbnzVX PvdB0SUTR0RpibJtD4xPiZVUXLjy5MfF2VprmUK9/pNzH62bGuBBP+/dht1vf35qeX6ueqHI772f jZqdmWjUVP/ngwvP5+msFtPDO64eHhw1DGPtAPDDx7JWhvV0xhhpWqxjqNtSX6xxtY765Vf2/+qt b77JzqvTeMNUvwPLucWMZRfcPZqw+eINx3QWPpGJtusACeOi+TQefr4FR1ZMhlw6JLEHIVq10tCd B9UMHhbO38NXVtFUUal2jFXfNVqW5GkOgEmh4ofWoufYcl4tp8vrivkva2LmJESkxfNnQNx3VfWO GTOmpod0ef+mo9p8bswN+5kGke+C4YmeVZuIqFTLj3wHjh1sywU7fKOhsryRPxG9e3DokLhgPrw+ Xq6tqmrkY7VOU/AHWGN10a82X3TEi4/fmbL55xOdzuFap+bQGSwuf4d9BD27kz3/Yt0l2+0Wgc+t mRwpEfGpUy9Ot52P7f5eWWVbt9c9pDcb1hbU2wf+LSv/fSJm3e6YdbuHOwXcj+08E7Nu94tZl68U qfgSa+saMp/Yw69pn+2UiHRT1u2OWffZ6W48E+rmt3/p6arPbIfp++K9Y1Jig/gEsOfusl0nPHul odA2o06v+3lvNux++7PmivftN8w8Nid5TmaiwJYBmMqP7lst+m/O3ehJqwAAeCmrlbNaWU9H2dPi g+kM/5fdeKqwevyQ9rmXmrKaAyUtBdSy93LdrMzG/62eyM/vVkFEZCpTaNs+dbK5ttE2QMvPMtYn +BnN+D/6V1XqZdRmZhtNk+3SsEQi4ptD7Nsuv9amSdXi6Q2qbVrMsvtqxYzRUR2/azVl5bvsmTyJ 8YFR9lBP4BO/dHTe59laIvazorLEclvWBD+9A0/kJ5QQ6YiIfD95bNrUob1/gGZoYsIK+fXnCw1E hpOXirNtY9Wi+4Z1PkGfT7C/7Zgmj43/ZO2kToMJwejUMGFOs5XoyxKlspnfhV9KsiyO9BlUnUf0 XYnKyvLxvWBxaudz0/HVHrQkpfjF60YiOnKhPqbJyneptBRpelePOJX42X4j4mPDD/zxjohOV05N kyUeUpYRnc3THGattsOJlsWMJn5892J+40F7esqP08N7dBGGiGyxWoWJiG5U65VEzvXRa432hACB o9q9oK+7/sTrl/k4SSjy/ddPRsybMrjtRyaICvHj+5SywdREZD8mTYnSNulTQrR/jx4eW1Vvu90i LsY/1On0z3HJS6ez2OeT6nUP6fuu1R8GpP2V6hZ7QlKbm+Cd5pdkDTrbFZ5e9/NebOi4071L6pLG UvukWM7XlMRSP8ed+42mzianBwD4oeiTUfbWeyKJaOuJig7zzbUcPlJWYHttS4CWpYam2Df539Uq 56kVa69d/689VJ0SH9TzEKcNq9WWWSPwCZlgz2/ee6G+ymlicn3d9Q8u2ALfESmBfEjklCXPGlpa cz3LaprbJd72gnOL7c0u7zipPGuu/9dHxfZGY342JtI56B49MpIfBztyQfFuhYmIhKKASWNaT0Ii UkPsY8ymnBvuRvG7KXD2KNvMJK99XcmPVUdFhqR3kbIfONR+h8KlAm15VxPeDxoeNoqIiPIKVTts 2cZB8XGBwXFhmTIRERWXqXfYjzR1THdyS0JmDrNFITpd01v2m3GXZIR3eTNfQozt676iuqmiq4f1 ytIiZ8hERKTTNW45p3OqoWxish8RWS3NW3L40zPfscm9yHUWJEYG2OujuXrB+VaLllOXlHywKRSJ k1J7eWLGmuv/+Z+rfLwYHCLZ9+jUBe3jRSKiSJnYXo3WZjGoVaeqbL8dU6O6ffM5EREJ7HOAVNbo lK33zrLNehcxVq97SD90rd6QpY04vXV5Tdt/fFbMQLW/093txvLLjisDpDe4eJ5Xr/t5v/6CCISM Y0znfF3r85v0dQY8ZBsAbjEsy3o+YwyJpSlP3R3hmG9u0eavD53Mb9RZiNi60uubX//6N+dsCR5p ieGTJ8UTkcAn/ucTbdH42Ss1T79/ukZjILJUXr26/oPr/Fi4UOS/LLOzybPd1ifI1z4SabpaoWTJ olY2E0nvGRPGV7K2ruGJf50oLFfzNXSen+GRsQn8FyM/UE1ERJZnDudVaAys2ZB75NQT3zSQx5xb jMj62M6LL+/JqVQ2ExFrNhScufDLv2c75qNMjJctuzPdefPoEYMWRPLfghY+Yhs/VJrklHEhlias HGmL814+VLT7eF6LmWXNhtwj2dOf2v/izlO552+0dPu5UUmjo8aLGOfdLRgR1uVXq2O2GZ2u8f9s rU0N5SXPvbL//i1f7Tl4gT9ee4Vj5svb3Co5JiFQRkQUNTtd4rx8/NCQTnNbnSowMXps+2X+d01O 6XJDpxMq47r3v7+QV8sStWhq3/vX4fmvfPlhVk5xab1T27WvoXxwYISPwPkZQLb1IoOSuhrgd30g oyLtD9WyPPLxueNnSsxELZr6I7u/22D/zVo8MaqT2Xs6ZfxsRy7f2YQiv/cemDB+aPvJN3jOzfLq F1fqdBazTv3ZvmL7bDbiKcM7v/DSnj01hawW/fMf5/B/Aa6dzPnjKVtyXYY8yHEW0use0osNk6dP rOkQXl95It2RUPXGyok1W5c/tWjEstXzOq65b67jQojk1NblNVsXT+rscx+w9o+zp6YQWf5y8DL/ 97DiwqW/HLPdxyyR+A9qrXmv+3mPN+x++0uHREyW2a4JvPdN+RHbr0b1ex8XX7KtKxgd3ftrjAAA 3oNhiGGoD24/nbhgwpa6bx/LaSSiRq3uFzsu047L7dYRivz+vnCY/c+nYMZdKXOvXDyktRJxu85U 7DpT0XZ15om7E8f0JDnbQRzoE0LEjxr95bPLf/ns8pDEyKyNM0fdmfHYRTX/7ZidVzcz72i7DRdM jJtln58hIlU6QnSD/zosKFNO+P3nvahJJ5xbjMi66avSTV+5mNEyOETy+uIRUe2D1IgFY6XbWlNm mZ8OG9R2bhC/OybFRl0qriWyWky/3nXl17uuON7bcqJqywnFfx4Uze3eZBRiafJPRxeeznFE2N1K B48ekfab4VVPX9GTi9ZuOVbQMLKw6ePfTLePeQdOSQ+lQscQMjMnwRZOpCaECLNbpxRZLI/o5iwo YmnC8uEF55yeXT9pZNjgbsS1YmnyE9NvnP66gYjKFJofvd7m/t1zJdrg7xq+fG6OYzq/Yalhkmyt 45FRjgko45NDE0nhSMC9e5i0d0O4oYnpz8ypW35IaSVq1OpWvp9L7+c6rxAcEvzkvBG9O/NWFRS+ ZM8GtlqMS9/4uuM6/F2SYmnyIxOvn87WEtGxS9WjfrvPeZ2lU2NG9vCZNenTE5ceqeWnWzl2qXrs peq27wsfnxDvdJGt1z2k77tWHxrA9o8ZPfhRedXzhS1EVFCmmvliu7+HzCMzY5xPAnrdz/vzFyRq 5dTwHVkKK5HVYvxZh1+NtMTw8RMGJtkJAKCPMQKB0OPEGCIi8l+2esbOOyPcBURR0sBPHpow2WkA KSAy5dWHhs6VujxhYNbPTf3NghG9q4p0yKD58W0mfzSaWQuRwCf8178Y87jrZxMyiyYmvLoq0/Gd LZYm/25OeMd89pGDw5bGdndmyU75L1s946O5UVEi148IIaIhg8I+f3y6y1G39FGR9tQXkkiCOs5a OGj0qPd/PMhNWpHwmUXynkweJxg3NNwxUNaddHAiIvJf8eORjsdUtZMYLX1zVaZzjkp8cqjTeUDr zCoRycFyp+Wj5d1/dKjfpIwwp0+w44mNO4IZ9479x0jXAVBwiOTDB8Y6T789aEzE+NYPUTQpIZJ/ JUuTjZE4VhPMTuz17J+CyYsmfujmlytKGrLv8SlDentX6+VLdWVdr2Wrxt0rxj6TIen4RlpixJ9X jO3p3xGBT9yfH5DPdvMX4LfzUhdPSXJe1Ose0g9dq88MYPsThTy4ajj/KKUOmEUT43/V9i9wr/t5 v/6CjJmb+a7tUUrtRUlD3v7FBIyxA8CtQSAgAdOzaQY64T9r2axzT03YOjtyvNR286ZQJBw/OGTr koxvn7ln0oj2Yyhhg9O3PTMna0ni0sEBwSKGiIIlvqvGxRx9ctZvF43y4MZT6bqfj/7jiGBHmdNj bNNGBkTG//7/5h5dlfJQWlCUL0NEfr6ie9LCsx6d+NbPJwa3GcwWTF404/B9ibOj+bvhmIzYoDeW ZOx+YnS86xtTe8F/5qIZ3z03/YO5sffE+gfbv9Wigv2Wjoj89KEJx/5wpzzWdX5qaGLCCvvl/tmj whJc5IoIRs2ecuLJUc+Ok8ZLhI6SV42LOfrkjEdan1PTLUmTBt1l/3LtTjo4LyAy/s/r78haknBP rJj/ThWKhCNjg95YkvHl07PbPeVElhY9J9IWvTnfbhscF323/QTM/iTIblfbntJDbk5s3BH4SB94 9K6jq1JW2XsmETNEFvDs3JQTf7y73UmUwCd6/lDbsQhF4vhhjrwIx3QlJJEEpnuUJ+0/a9ms758c 9cIkWUYw30q2DvntM3OGuukk3aA5W6Lrei07gU/4I4/ffXhF6y9FvDTghQXyrPUzOlwI6paoocPf +/2sXQsGOXoI//t4+MlZ6xe0v27Q6x7SH12rjwxw+wdEJv3td3d/sSLJ8RdYKBKOHyzdvXr8W23m q+H33st+3s+/IP5zf3LHd48P/92IEPsfOluzfPvMnDRM7wgAtwpGwDBChuE8moscAAAAAAC61tjY yDAMy3b3lkIiSn+9ZkzZOyIfj5+wDQAAAAAA/YXjOI5FyA4AAAAA4LU44jiE7AAAAAAAXorjWI7j +mCSRwAAAAAA6A8sxzFIjAEAAAAA8Focy7II2QEAAAAAvJaVYzkWuewAAAAAAN4Ko+wAAAAAAD8A CNkBAAAAALyUUCgUCgQI2QEAAAAAvJRQKBAKhQjZAQAAAAC8lFAoEAoxyg4AAAAA4K34iB0hOwAA AACAl2IERAzh6acAAAAAAF5KyAgYhsEoOwAAAACAl2IYBiE7AAAAAID3YhhiCIkxAAAAAADeymq1 MhyHUXYAAAAAAC9ltVo4lsUoOwAAAACAl2ItViIGITsAAAAAgJeyWq3EIGQHAAAAAPBWFouZIw4h OwAAAACAl7JYLBxmjAEAAAAA8FoYZQcAAAAA8Gr8KDsmeQQAAAAA8F4ch5AdAAAAAMC7IWQHAAAA APBqCNkBAAAAALwaQnYAAAAAAC/FMAJG4NmjlNRqdV/VBgAAAADAy0ml0pu8R4FAIGSEHoXsN7/S AAAAAAC3EYGAEQiQGAMAAAAA4KUEjECAkB0AAAAAwHsxDDEMQnYAAAAAAO+Fp58CAAAAAHgvjhiE 7AAAAAAA3s6jGWMAAAAAAKD/sBxHLIeQHQAAAADAS1lZK0eePUoJAAAAAAD6j5VlOWIRsgMAAAAA eCmLlRNwVoTsAAAAAABeimVZDrefAgAAAAB4LZZjGRa57AAAAAAA3oplOWKQyw4AAAAA4K1YjiUO o+wAAAAAAN6K44gjDk8/BQAAAADwWgxhXnYAAAAAAO/FMESEUXYAAAAAAK+FkB0AAAAAwItxHEcI 2QEAAAAAvBZHHIeQHQAAAADAa3EcR5gxBgAAAADAa3EcSxxG2QEAAAAAvBdHDEbZAQAAAAC8FkcY ZQcAAAAA8F4McUQsQnYAAAAAAG+FUXYAAAAAAG/GEDGY5BEAAAAAwGsxDDEMJxroagAAAAAAgGsC BqPsAAAAAABejGGIqI9G2Zt0JnWz0WxmDSZLnxQIAAAAADCwfEQCsZ8oOMA3NMhvoOqgyL3GkMDT kN3KclXK5iadqU/qBAAAAADgJcwW1mwxNelMKq0hKTZYKGBufh3E4hCGEXiaGIN4HQAAAABubQaT pULRNIAV8Chk1zQZEa8DAAAAwC1PZzBrmowDtXePQvZGPeJ1AAAAALgtDGDo61HIbjDiZlMAAAAA uC3oW8wDtWuPQnazhe2regAAAAAAeDMryw3UrjEvOwAAAACAV0PIDgAAAADg1RCyAwAAAAB4tb55 +qk7DEP+QotIwAoFA5b6AwAAAADQCZZjLKygxSJkuQF4WFJ39GPIzjAU7GsyWIVGi4+V9dLjBwAA AIDbnIDhfIRssK+p0eTrnVF7P4bsASKLySo0WoT9twsAAAAAAA+xHMOHrP4iq87cv0kovdOPuewi AWu0IlceAAAAAH4ATFahj8A60LVwrR9DagHDeeeVBQAAAACAdjiOGG8NXTEKDgAAAADg1RCyAwAA AAB4NYTsAAAAAABeDSE7AAAAAIBXQ8gOAAAAAODVELIDAAAAAHg1hOwAAAAAAF4NITsAAAAAgFdD yA4AAAAA4NUQsgMAAAAAeDWE7AAAAAAAXg0hOwAAAACAV/O6kN3YqPvqTPWPs8qG774xfPeNuZ9X fHqxXmfhbn5F3j5cPu9wdVP31r52rpqvcId/5deqjW1LM759uPzR7Fp+Q5266cPj1XX9dRQ9xZ38 rnLknoqyRkt31q7Nr7UfYN/QVKqW7nFZIHftXPW9rj6OhhvK2Xsqa1z3kKZHd5dfqTTcwpsAAADA 7UA00BVow9io/cNxzSEjNyZU9H/hQiLuq3rzHwubdynNW2dFh4qYga5g55ilUT6DO1QyWCwgYt1t U1ba9KLSelc/16ybmpXqrdUWlqVPCjUbMsNv8t4bKlRPnW8uZDt+yuy1i7Vrrpukwb4dt6qoNw0K F8naNrtJp/3DscY5SeJYCVNSr917TTk+LvhHQ0NuvU0AAADgduBdIXt+YfMhI20ZIb0z3RaRPEjs pRzFqlJjdmHjfG8PU5ifDJENjfVz+d4j9yQ8cpOr03PXy1quC0WbE5k/VhoeGM1F3qxzJKvReOlq w4ZSYx1LRG122lTf+NmVxn8oLSyR1MWmxtMq67yYgHaxvK8kaP0Iy4GSll066+lq8+/iA8alBN2K mwAAAMBtwbtC9nojSyQYnu4cmgvSMwLGlJpONhrn2xdpatTvXGn+SGM1Eo0J9dk4JHh4siOIsVy5 WP9KuemcgWWJIv0Ea+MClo0N9yMiMr59uPZ8oO9PGOuGKnOIn+g/M6ISQ31qS+vfKW7Z57o0UhTW PVVk+EbPBvkIHk9wFNVTxrcP135Goo/viXWOtr7Krnii2kpEd+6+MS3W/19Tozo9Otf17011XGEt zTsrLSviJJMTBYNKG78r0C4eFkpERNyNvLpnio3nDCwJmLHBor8MD0uO8XdVgunSJdUz5aZiMxfk I3ggRvzAuIggW9zfWSEFV1UPXDcNCfL55yDhT/JNzu22I1fzeiP784SAoRbjm83t96hv0B9ppOdG BHSoiyAyxt9aqFsY4XOmgY2UBgT5CW69TQAAAOA24V3f/QmBIiL29OUGq9NCX0noB8uT/j4pkv+x urBu6SlttlXwzwzJhxkByVbrT3IavsrXEhERd/5s7U8KDQlSn/8OD3xP7j9aRC9cb957qcFR2imF 4RUNvT1c8oc4P1moT2V+7b05zccM9IJc8p7cX2ywrDqnzrPnUlc2m356xTArRrxzuGSBmF643nz0 mrYPj3dorOT5aBGRYOvwwA2xAV0dnYv692h3tfm1w3ffePucyuW7JdeaDpqZRYnBgREha6KEW8p0 aiIiqsqvu+9KS1iQz/bhgduHiK0tlsWn6it11g4FGP97vPZnpaY5MeKdwwOfiRF9Uqn/+bEajYXr shChgPl9iuR/c2IjfNqP60vFwg/HyTZMjBS7qnN9jbHeXxjt6sqGqkZ/Q+izcVrMq/HCC/V68624 CQAAANwmvGuUPWVY6J8b6v+Q3/hcUdM8mc9cmW9ypCQ60t/pxKJlZ3FLQrj4zalREhFDRKOHW8Z9 U/O3kuax6SFS0h+qtc6N9f/j1Cg+u2DkEK32kPqbJvNK+/YsK3xjWlRSMH/gLW+XGPwlPrvvjuUT iEcka9Yd1R6pacyIDSYilmX+NT58TFIAEaUlaEsOqT9VGX5EIX11ohOTHJamNhBxaRnhUV0fXcf6 96GWzypN46P8EiN8iWh8jJ/uQsvVouZpqYH5KpM0yPcvs2L4ax+bg5WrzuuLKnRx6cHO21deU29S s9szZZnJgUQ0gigzSrn8rI7PaOq8kLTRMWlERNRhGN1vxcxB7uvMFWksU8N9w1y9F5kU/vckIqIx 42PH3JqbAAAAwO3Cu0J2gch/xR2Dpt9QHy5r+Uht3ldnorzmIB/BX+VBs4ZKhUTaSt0RHTctlEqK WoeKWQFTp7PWVBulsZKnF0icC/SViCcECk5aOBMRH8QnBAtl9ni3WaE/oePuSxE7bvjzCw7dtpTP BjESUVyQz+CkAOeiPtNbdURuUonZFdk17Q5o19Qod9ntHXV1dO3r31NR6VFX0l2/VVfUtEtHr6YG 8q0UmRq0oqjl3erm8amB4X6CymrzJzl1i+XS8GCf8OSIL5M7FsBdU5n9RAKzwXA5zzGrCRdG9Lna MJ9CuldIT+mPKa2z012k6NwemwAAAMCtz2DQMiTwrpCdiIgEMUmyB5PoQSJ9o76qsvmDcsMTV7W/ NrBrx8oMzdZKoo+qDB9Vtd+srtk8lPyIiLVY1fW6WrWxpNFyWGX+RsfGEWu0h+zO9I2WEqIh7e/3 c6oK06PMIRczxgSLe1BAV0fXZ2nrHUWmRp5JdV7gv2FeIv8qXR7083rN5lL95lJ9pJ/gx1F+ixKC 49rnsptK9VyLhX3oSvuB8iE6a3N3C+kZ5XXdMavwsSGBt+cmAAAAcDvI+vQ9Pz+xF4bsrQKCA1KH BjwjNw4+XruptOXesbblW0bI7kx3OdLNFVxS/LLIWMeSn5BJ9hXcHeEjYE1FbsrnWPeTL/ZGZzPG dJ/7o+uz6c97xC84+Ldzg9ZUac/XtHxQY/5XecvWcsOWEaF3prefwCch2Lfd/bWtul1I91U2mId0 mBLx9tkEAAAAbh9edPtps6Lhx3tuvHhW2W65QOQ3RCJgWY4j8hELwonONrl+oEyzUv10gVEeLv52 fnzu0sRPFsQ/PDEkxv0eJaGiIUTF+jZTlGz7snz9CcWAPLGm86MbUEzYoNA7M2PeW5iQfUfIHT70 VpVe32YFUbSYKW+0ql3cltr9QnrE+H2DdZ7Uz+0lklt8EwAAALiNeFHIHhjtP9mf2VHeklPS5Dz4 3VTb8GGtVS4VSYjCkgIXSph9VcbK1sdzWr48UTn508oyjVmnMhcSLY0MCAsQ8u/Vleq+bHH75NTA 6IDpEuZjhUFlf96kprJpj5ZNk/i4nJ+kv3V+dANRIyJqee+rilVHaxz5LpJQ32gX12aE4yJ8BGTd n692fHaayvp5u2+8lqvsdiE9wE+JOCq845SIt8UmAAAAcFvxqsQY/zUjA7PPND2Yq4q8olkaLgok uq6zHNRYzQLBR+mhgURE/vcNFn9yuWXx0ernUvwHCbmvao3vN1gfSwmKD/XRm31GClqeztOYTcYE X8pXmTbVWkhI7uNvW2kPfFn1hwQ/P6v1r9cNaj/RwrRQIovbjfqUn4ghYj89Wzs7PCA1OaiTo/M8 MaY2v/bOyy2PpwQ9MlbW7Y38J4YJNxUbn/yq6sEoXwlxR2qMO1voDbkkgKjJab1YechjlaZ/ljTn NZnXRPmodObXy41qP9GPU6VEok4K6Z2OUyI2Vavuy25KsE9vf2tvAgAAALcVrwrZKTRO9oHE9+u8 ph0qy7+rjCxRkI9gSYx4zbCwGKktayAuPepTv/p3ilv+XKgzEsWJhZuHhcwaKhUQBUaEbR7LvpKn f7pQxz+v573xMlW15tEqq1ZnDZK42KOjtF/n6cwC5p5wv7fHRERJhDctZI9LkvxCYX7zRssXauuH yUGdHN1AyRgTvVtU9/cbpl/m6ViiIRLRh+PCRg5un7IuEPmvnR2VnqvaVGP6qdLoJ2Tukvm9NVIW EyzqfiHd1tmUiLfBJgAAAHB7YTjObd5Il66WuH4oD08qNqoNnt6LCQAAAABwc3QZvg4b3P1UhfYa GxsZhmHZHsx+kv56ze5Z9X5+PZmCEAAAAAAAbj6E7AAAAAAAXg0hOwAAAACAV0PIDgAAAADg1RCy AwAAAAB4NYTsAAAAAABeDSE7AAAAAIBXQ8gOAAAAAODVELIDAAAAAHg1hOwAAAAAAF4NITsAAAAA gFdDyA4AAAAA4NUQsgMAAAAAeLV+DNlZjhEwXP+VDwAAAADQVxiGOG8NXfsxZLewAh8h23/lAwAA AAD0FV+h1cJ5aQZKP1ZLbxEFiCx+Imv/7QIAAAAAwEMMQ75Cq1hobbGIBrourvVjtTiONEa/AJHF 38/IMP23HwAAAACA3uM4snKCJpMPy3lpzNq/ZxIcRzqzqL/3AgAAAABwC/PSfB0AAAAAAOAhZAcA AAAA8GoI2QEAAAAAvBpCdgAAAAAAr4aQHQAAAADAqyFkBwAAAADwagjZAQAAAAC8GkJ2AAAAAACv hpAdAAAAAMCrIWQHAAAAAPBqCNkBAAAAALwaQnYAAAAAAK+GkB0AAAAAwKshZAcAAAAA8GoI2QEA AAAAvJpooCsAAAAAAACuqVQNfn5+CNkBAAAAALxUVFSkWCxGYgwAAAAAgFdDyA4AAAAA4NUQsgMA AAAAeDWE7AAAAAAAXg0hOwAAAACAV0PIDgAAAKtI9KMAACAASURBVADg1TwK2X1EiPgBAAAA4LYg FDADtWuPYm6Jv09f1QMAAAAAwJuJfQfsiUYehezBAb59VQ8AAAAAAG8W4P/DDNmDJL4SMQbaAQAA AOAWJxH7yEL8B2rvniajx0cHIWoHAAAAgFuYROwzKDJwAHPZPR3eFwqYpNhgldbQpDMZTBYry/VJ tQAAAAAABpZQwIh9RUES39AgvwGM18nzkJ0nCxHLQsR9UhQAAAAAADjDLI0AAAAAAF4NITsAAAAA gFdDyA4AAAAA4NUQsgMAAAAAeDWE7AAAAAAAXg0hOwAAAACAV0PIDgAAAADg1RCyAwAAAAB4NYTs AAAAAABeDSE7AAAAAIBXQ8gOAAAAAODVELIDAAAAAHg1hOwAAAAAAF4NITsAAAAAgFdDyA4AAAAA 4NUQsgMAAAAAeDWE7AAAAAAAXg0hOwAAAACAV0PIDgAAAADg1UQDXQGAHwCDwdDS0tLS0sKyrMVi YVl2oGvUlwQCgUgk8vHxEYlEEolELBb3SbG3dqPBTdBPPRMA4IcIITuAWyzLNjU1NTU1EZFEIgkL C+NjCIHglro8xbIsy7JGo9FkMtXX11ssFqlUGhIS0uvSbodGg5vAw57JcVy/Vg+6iWGYga4CwK0A ITuAawaDob6+XiAQREZG+vr6DnR1+pFAIOCjaolEIpVKTSaTVqstLy+XyWQSiaRHRd0+jQY3Qa97 JsdxDTrzn/YVnyhSX6lqumkVhnbiw8TTUsOeu3dISoQ/AncADyFkB3BBq9U2NTVJpdKexqy3AF9f 34iICJPJpFAoTCaTVCrt5oa3c6PBTdDNnslxXKmqJe21U9FhwYGxgeMGh93keoKD0Ww50dQif+3k sdUTZqaEIGoH8ASDS4cA7SiVSrPZHBkZKRLd1ue0LMsqFAoiio2N7XJlNBrcNJ33TI7jhrx0Wicg zi9A1WK1sviOGzBCASPzF/qajb4Wa/HGSQjZARobGxmG6dHNXemv1+yboxGLxfhyBWhDq9UajcbY 2FjkXgsEgtjY2OrqapVKJZPJOlkTjQY3Uyc9k+M4juPK1bqw8LC6RstA1RB4VitXZ7aE+flWNdTx 44OI2gF6DSE7QCudTtfU1ITQ01l0dHRlZaVYLHaX7oJGgwHhrmdyHGexWjRGIsxR5B20RpZjWY7j EK8DeAIhO4ANy7JqtTo8PByhpzN+RLOystJlyI5Gg4HirmdyHEdWMpmQD+MtrFaOrJjAB8BTCNkB bJqamnx8fDD3c0cikcjf31+tVne84Q+NBgPIbc9kiawDVCdwCVc8ADyGkB3ARqvVRkZGDnQtvFRE RER5eXnHkB2NBgPLdc9kESN6GXwcAB5DyA5ARGQymQQCAUaL3eFnyDYYDM5N9INotCKlPjUiYKBr Af3FZc9EyN73LEYS+fV+c3wcAB5D+ikAEZFOp+vJbOKqtS/lMm3/rc3ry/oc/CyX+UzV+nPedeal 3PEn9Y4FRSevMturinpcsGptb6saFBSk0+mcl/Sq0a4fbLNQv2l7x4UuNuxVnfWbtueuKui8ENXa l65uUvai8D7ZvA/1/pP9oevYM20he3f/aakst/Wf1tjDzQfkn5FqcttUuyyXamr7dBdaKssjk21f meGBnhYIAJ7BKDsAEZHJZAoMDOzRJmsWjXs3w/5D3nUm6+rQ8GHrI/qmPqkyMRUaiohSiYjoYKFm TXroNlULET9grP+80JApl6b2zd66xd/fv6GhwXlJzxtNnBmh2ZtH8xztplTvJHFmX1WxN2Tvbuxs /sp+3hz6QMeeSdZu57JbakkhObDr4Xn2BUUH9sk/CSFpSJ/Wsc8FbvrHw09Gt12muDz+T005QR6M hbcRc+Cj8QWvFK6vDtz0j4cXXL4k/8KDwnBrAYDHELIDEBGZzWY/Pw++6jJiXv0ub2eBfn0Ebdpe SnLxhmwNkfjV1cPWR+g3bc/bwA/ERkQXrh6USnTws9z5lMQttkV77X4kotS00MxsR8iuz1eJhy4M XbNdc3CxbB4RUcs1pXjlQlv43rH8TpfbKavGb1fkpLfZbyd8fX1NJpPzkl402kp56IZC1bsZtj0W FWhGyUMvKg1tqmRfuc1JkYs6d36A9neVeYwqiVtMRESqqvEv8eXzHw0Rqda+pBi6etj6CCo6eVWe zdfE8W4rNx8ZOTZ3VR/9pu151yaPezfDVvNRi8a9m0FFJ6/KC0PbVFhZNX67ZuVUvtsQpSdxcg2T ZX+9WNZu70Unr8pV0S4+OBcH6LJiXe/R7YZt97f2JcXQRaE7s/idhh7YmDLP+ZOyr+f0UarWvnRj G1/DqeIN2WTfpMt9udWxZ3b79lMjBcUX/nNE0c5c5jS/JPzAliVczHfMNv7r0Uh1V4gv2zeOIqOI +Ci/gUICSFtPRCQZQv4aqre/loYQaamymsLDqL6SL5PiEm07tNSSorJ1/+HjSMzvpYT8+QIDKDqD RK7228HB/+bOz3X8FLDpDyN2LMmWH7YfmssSmvJIy1+s43dERFqqLLbXhMhQRvXUWmGrkWrKiRtJ hutUH0LSEFcldANG2QE8hsQYACKiHj2KzJ1RMj6GNmwoFBduHMdttMXrO+UZ3MZx3MZxhXKNfHtV EdE8eSjla+zZIKq9+bRG3jb8ipCujNDs5fMclOqdFLowwn9o6xLDRRKn28PEjuW7X25njyC7Ga+7 1JtGSwtd03rg+s8LxUvTHO+p1vJV2jiO2zjuQDpty2qbMNOmzl0dIAWsX53xagRlTs1wHOO2bMOz tsINGz5vu37edXm2+MDGcdzGcdwi8Ybt7XN1uvrIXNYnYKFcvK1QRURUb6AI8UWVnoiKVC6vkBg2 qEK5jeO4RaGUf4MpDOU2juNWR2fmKzYp2+1d/3mhoX2HcXuA+k3b8zbIkmytKlM4NVRne+xGC9sL ybLttHCqYb4tx8ndR6la+9KNi1MzuI3juNWhO/mzBbet54FupmqYuE2PjaCv8uafciysn/8/LY0d uymJiDWSonbT5oe5PQ9zex7mNsdnKmqJJYrPKNyzcNPymbblvxFSpuO1P5mI2JgDexZuGikv5Bfu mbi6osyWahIQb1/4MLfn4QMj+eWBmzYt3LRsOrfnYW7P8k1JRlLUbnrNvtprybb9tvvHEXHOS/Tr v1CkjonNZO0171iCvixzyb32vd+7KYDfe8yBPQ8fmGIvZ8oUbs+U1Y5UFk666Z9Lnoyh1IVLuI0p bkpAYgzAzYCQHYCIyGKxiEQeXHTKq9mgFA8Nt/3UGpDl1WxQhj47zXb7Y+q05FdJ8VIeUUboGrLH 33mabRS6tN1wMgWky4iP8KjeQHJpKgUslNtjvgJNTnrovE7Kd7fcRrV2u4KmZrQfw+6UQCBoF6P3 qtFkS9OdTkVkofOc3np3Y+uw+jx5aNsN29a5iwN0bc0i2xjwPHkoKQ1ug8KMFM4xWty6sNOPzE19 UmViUhmKiIpUhlEycY6qhUifr3Kc3bWtHh+FZ4SucbyOEI8iw7X6tntXqncqO3YYNweoVO9Uhh6w n7TMW5y0RtnaUJ3tsdst7Nhp6rRoeyXdfJR5mm0R0Tv4MiMG7Zhqv2G0V5+mQ8eeaUuM6fJfTNSC mOb9Ofo2C7OLmXVX1pcSGblNm5c8WV/GrMtl1uWuqR9xdnN8po4fvw95clAzsy6X+VBFY2dyE5uZ dbnMSxVFY4duirGv8KuIF9flMutyxx+TbtubuVpHZE058PKIog9zbQVeonm/mrLaal9/nHn8ulxm 3ZX1ecZNm5csuJrHrzb+avLZ1+z7df5H9osJtn9aajIR40dWIp2bEqZMObuwec26XGZdLvOh9cmX 71zdsSjWqQGJyKpf/5dLm2uo6NAl5s16tyV05x8AeAaJMQC9tC0rd1uW46c2qRSOgKxIZSAyzH8p 13nDTJWeSLY0/cb8QtW7GbKDhRpKT2ofIBLNk4fOL2whCjhYqBklTyGi1LRQ+lxdNC2gSGUbZHVX fhG52y9f8xtE4lfTBmYelVQZf+IRUFSgIVkykaHt+47ECSJqjdrb1dl9w/b2oDJiXv0ujy/QRUIO Uecfmdv6TAtdk6UpIiIVDZWLM78zFBFdcx1wt57ytX3dfu9FBZqc9OiOHca1ekNOhNhpRN9/aATt VOkpvIs9druFnTe0F25bp/1HWaQykCzUUZlUmbiH++q2bg7rDgpMpeYrpe7ejVoQq1zzXD3/0/Y3 ipf9a8Szk0/NryUiOniunliik3UHfyoj/nVpcxHFpw0iqiYiOvhe8XaWiChnV/XB2UOWTa7cnls/ /9F6Ii1VFxPR9uMR20b6OupZdFGbw7+eLH8ytnzNoyf45TmvlW/+15JnJ5+an9shCa0pl1qzbNIO bE0o+iovh3VfgtCPqIkqc4mIjhJz0lWLOf9P9oF8x4tOSugcRtkBPIaQHYDIPlDXo0d4ugnsOnCT mDtPHkpZmoOLaW8+rVnkKjslXJxpWyF0KZ+KHSEepdQU8antjjjJVflFJ93tt8VWc7rOfF61sCcZ wx31otGo9cSDPi+klQsDiNT2d2wRXubUDG5aAOVdZ1rPiFzVuYcZz10JWL963Ho+ST0rd1uWi3T2 Lj4yN/UZGqHIV+pJJU7PEI/K0hQp6WKEeGPP6zdvSnTmds3Bxf75hYY1k2/KPa+9b+HOPsq+3pcr XPdiRIGQyESmdt+ERrL4kYhoUGBqTfOl1nL0BTW0IC6QaoioqaDcsQvn145dOy+0b3i2nmqKidIO fO6421XRGrJX6PnXmXHBREHbsh62n+0QERUlS+msntqa9+uHuV87/Xy5jPlY31kJuxSb52bwyw/+ 89/zjwRQhD0Z3Tk0J6fDYdu+Pum+hM7hyacAHkNiDAARkUgkslgsfV5sqkzsNgGDT3U4abjoIiuG iPh0dkN+nuFi6yipbGm6Zu9JPrW9s/I7269t7zGvkmLVyfZBQCc6psH0stEipCtJ83le61HY5Gm2 RUQXbhx3dpqbsVWnOnd9gL01b/E4bmPGqxGGnQUdGsf9R+a+PgEL5XStQL2TxKnkPzTCkF/Apzn1 HH97w0m3WTGuhYsz21Ss5ZrSdVpOO91uYcO1+g6Fu/koHWlCvCKVoYf7cs1FglY3s6urzEUUODym 7ayOZi4zOJdaiARC4qxObxmJI2J8bNEn5xTOch1CW2LJ0mHDltADnz/MfT4z9UgeszaXeVfRWlXO qdoMQ9XF49fmMk7/5B/pO+ayH3zX9u6ay0RUvuap3K5K0K//vW39eb9+mPt84Sb+2J0brd1rrl3e vJsSkMsO0P8QsgMQuUyH7RMZMa9GaOY77qXLu860TuMt2zhVvC1bYctKdyEgXWbY+Z3GOcJLlYkv FjotcVd+Z/u1Fb5+cmhOdmn35xRnWbZdYNTbRgtYKKcNWQoXkasjblNWjc/SEBny3dW56wPsobzr rdPDK9U7leKVLhKH3H9k7uuTKhNvy+YPNiBdRjsLNd2JmF0JWCjvvMO4EiFdGaGZb5/j/+BnN7ZF RG/sTsTf7RZ23CXcpnCXH2WbE0XVS9n2nCjPPs2OPbO72dXXtfsVIQsya6nR2JoRHhS847WHD9xB VGEuivUd2aC1vdWgT4ulomp9a+pIx0Rwx2sKSZOWtd9weuy8quLxv8iV79CTqZaaTERWMrUvJKfa TLG+I+tqbZvry6gqz7aam1z27Zty11xK2HYgc3WDtrMS9GVUVcavz/wse3NVyILpUrL6EBEZ+cM0 kt7U2oCth0PEOYrqWAJy2QFuBiTGABAR+fn5GY3GfniQZ8D61Rm0PU/+koKI2qW8p6aFZmYrRrma +oM3Tx46P0uzZnJrhJeaFkrZilGtS9yV39l+bTJSDhTmzu92ekxLS0u7KR173WipaaGZ2Zr2MTFf H1tCc+iBjUl7X7pxrZ4oosM6n1ctXD2o6wOkgIVy8YZsp0keO9Fm77Rm0TiXU+y7/8jcN3hG6Jos DckCiChVRjn5oc/25K7f7u29E7aKMS/dIOpR/kk3uhAREa1JJ1u7OQp3+1EGrF+ddO2lPCabiMSv Tg2lQv4KUnf35VLHntkaaHZBv/6t2gXPLink9snf5k8R0g4cHpF6sUx+nIi0+xUZ254u3f7HXCJa /deH5ylqxx8nSuywC1ev5z05ZfU9WdudN5zhT4NMI6tzc4hIPrvwyQQi7fBBRFVtCzmu2DwvY9u/ tJd+8V0OEd0zn1sfvvkvV9Z3zLl32u/2V8qW/Tdx21Ol21/Qui0h/k5urXbNPYe2E5F88oJBxv3/ 1pM1oEBBT44XUlYuUfymF6YQKdoejg8xRMbrpA6hBS5L6EZLY5QdwGMMxyHFDIBMJlN1dXVSUtJA V8R7VVdXh4SEOD/uFI12symrxm83PNtxNpsBo1r70g3q5k0dHeVdZ74Te57C7twzOY6zWq0+9x0l /+4/1Sz8wIeJrY9S+iJP/j9HTlTAplcybE8sUtSO/7/KHCJKjit8PnT/n/gYOvzAh9EFra8T6Z3c +d8EHPgwg85p540NabMh0er/G7dtNF+yds1PNcvs6296JSPt89z535CL/ZJx8586xusdNyGaOYR7 KIQulDGv1LsrwakCdPAdx+aOFjBufkez4CHxiz8t3u50aJn3Dz/7Iz++ZDcldKVFaf54jlAoZBim exsA3JoaGxsZhunRBer012v2zdGIxWKE7AA25eXlsbGxHk31eOuyWCyVlZUJCQntbjZFo91MRSev rqJkt7n+A6CHIXvedSbL8KrTk6d2yjM8PJx2PdMWsv+4RyF7nws4sDOD3syd3/0JVW55LUrzJwjZ AXoZsn84VSH288MXLYBNSEiISqWKinL9oMHbnFqtDgkJ6Tg5DBrtJuEfJhoRXbjae+L1nstIKVRd lW/P3UBERJlTPY3XyV3P9Ib7Hbs5a81tAk0B4AGJv1gsFiNkB7AJCQnRarUmk8nX13eg6+JdDAaD TqdLSEjo+BYa7SaJGHR246CBrkRHsnc39my6ydRpw7hpfbZ7tz1zgEP2ACIiIeJUJ2gKAI8hZAdo JZPJFApFXFxcT+cav4WxLFtfXy+VSt21CRoNBkRnPXOAR7jr5y+r73qt2woycAE8hpAdoJVEIjEY DAqFIjY2dqDr4hVYllUqlf7+/iEhIe7WQaPBzddFz8Ssgt4GHweAxxCyA7Qhk8mUSmV1dTUCUD4q IiKpVNr5mmg0uJm67pkI2b0NPg4AjyFkB2gvIiJCpVKVl5dHR0fftinaBoOhrq5OIpF0khLjDI0G N0d3eqbIV2SxWokR3uS6gRscg6w5AI8hZAdwQSaTicVihULh7+8vlUpvq0kMLRaLVqvV6XQhISGd 5MN0dDs3GtwE3eyZ/8/e3Ye1cd15w/9J5tUvcdwkbu0AAhkcx6V1d8PjLiaGLLZZkjQkMUmdFzl4 o238XNp91tRJusHrDSG3L7y98eOb3mnUkl3SuAZn3ZR4H2WzprKjew0GNm7S1K1DQgAZScQkThps Y4PAYub5Y/QykmY0kpDQSPp+Li5fZnTm6MyZn9BPZ84cKRSKnG8sGrFdZ5RI2WVByUzfcksmlncE mCO8pwIIW7Ro0aJFiy5fvmy1WjMyMjIzMzMzM1NSUhIvE2Vcrl27du3aNYZhli5dGt7tpMnTaTAP wotMhULR+T8KVz9kpJSFlLF83loLAthZun6JaOrAD76LlB1gjvBVSgDSrl27NjMzMzU15XA4HA5H rJsTYUqXzMzMJUuWpKSkRGTtl8TuNJgH4UUm921KFy9P6VrffeeDkaszWF8wZhZnpN6Wtey1v71z zcob8T1KAIRvPwUAAOCwLMuyrHuEHu9xMaRQKNyfuxQKBVJ2gLmk7LhaDQAAiYPLCxcsWKBUKrn0 PdYtSl4KF3KdFwAIG1J2AABIKO7sEGmiHOAsAEQEUnYAAEhAyBQBIJFgqVQAAAAAAFlDyg4AAAAA IGtI2QEAAAAAZA0pOwAAAACArCFlBwAAAACQNaTsAAAAAACyhpQdAAAAAEDWkLIDAAAAAMgaUnYA AAAAAFlDyg4AAAAAIGtI2QEAAAAAZA0pOwAAAACArCFlBwAAAACQNaTsAAAAAACyhpQdAAAAAEDW kLIDAAAAAMhayhz3ZxhmfHx8ampqZmYmIg0CAAAAAIhHKSkpmZmZy5YtS0mZa47tW/NcdmYY5sLY Z//nk0v/8YfPuwa+jFSbQFLPM3eUHHg/1q2QkaTtkKQ98PmB7o0XOFMQBoQNRFz2TYsqv/V17Z05 10ZHs7KyIpu1z2lizPjE5Ntnx140fIx8HQAAAACSme1P1/7lv8wV/2+PIm3R+Ph4ZCufU8r+3/02 08dfXZ2ejVRrAAAAAADi15Wp6/r/sly7di2y1c4pZb95kXLwi8lINQUAAAAAIN79+/ujDMNEts45 pey3LE4du4y7TgEAAAAAnK5MXY94nVjkEQAAAABA1pCyAwAAAADIGlJ2AAAAAABZQ8oOAAAAACBr SNkBAAAAAGQNKTsAAAAAgKwhZQcAAAAAkDWk7AAAAAAAsoaUHQAAklBem/7hMf2dj86xGtW6Hv3D Y7o86Y2QCBA2EDMpsW4AAABAXHpU9/DBwqA2ArghbCA8SNkBACChqdb1/MNqtfOXsd26068LlVr3 0N2d5Yu5/7/T9oamN/Duyxpe2PzUcjJfvKpevthVVHAjxCeEDcgMJsYAAEACy2vzZE5EtOLgC+vW +RV6VPewO/Eiok2ah3seWia1+9VXfvxGiXHCuybBjRB3EDYgOxhlBwCAxKW6IY+ILn5S+cLZs6Jl 1v1dIb/MsoYXNj9V/s1Hf336ddHdx+tfOE5EdKvkRohDCBuQH6TsAACQuCxXzhOpl6/u1K8mIuEZ DrcuURORpwxnyRpVcLtD4kHYgPxgYgwAACSw85off2L2/LrioP7uBtW87Q5xCmEDsoNRdgAASGiW syU65/SER3UPHyxcvOpWIguvwKcTZlqhFpsFIbk7JCSEDcgMUnYAAEhcXgt3cMbe7vUuYzn703Or DxZ6z3DgUrFgdofEg7AB+cHEGAAASFyWsyVeUxSuvvJjgVnFr+vf2H2O97t76DS43SHRIGxAfjDK DgAACY03RYHnvEZ3nv/76/o3hJMq4d1dek+v8B89FdwI8QVhAzKDUXYAAAAAAFlDyg4AAAAAIGtI 2QEAAAAAZA0pOwAAAACArCFlBwAAAACQNaTsAAAAAACyhpQdAAAAAEDWkLIDAAAAAMgaUnYAAAAA AFmL3refLmt4YfNTy4mIzKaTJb8e57aue+juzvLFRO7v9fUU83LuvRX6835b/Sr3KpbXpi/a5Fty bLeO+5ZgwUevvvLj4/WWAHXGI+EufaftDU2vQCe80/aGxvl1a9yj7h4j2nDnmGaFd5lgn47OjbxT mBuww70awwsSv2Y4n4K/JSTz3CGB6xQq4/6Oa/HWhhWWsT/woF6AtK7nH1arvTohQIVBvmZ5+3pq lqwwJDJ5ob23Qn9JvB989gr7YAFgrh7VPXzv7wO8xgX5vyFC8or2KPtV80VSF+asc/66bGvh4gjU qsrZzL0JFd76qETRFQdfWLdOokyodSaUTZqHex5aJvCAal2PdBoRrg13jnnnNOryzWO6vEg/TTii 0SFedarW9fjkc8tXd+rvblCF1dzIiU4kBP0CDIPoa9Y7Y16+ulMGoRXFF5pYP6jW9eh9svzFT/3D w20bwnoWAJiDR3UPHyyMdSMgzkVvlN3p/MWr6sIla4nOEhHduGo5mc+NUeEKtfPx8foX3qgnIpXY SJuAdf/XSjXRO+fGNhWuuHcDve71Psf/MJrXpi/atNz97D7DmcHXGY8CfCj3Hd5Tl3/z0V/7FM5r +4fV6qDSCLEzmNemzxXp8GUNFSuIN7LuvPZSuKZBdT5qQ4Dz1iGB61zW8Ner1eQ1IPqo7uGDhYuf +ut1b75w9mxYr4hgWxJsI/nmcOBBvgADf1YJ4zWruiHPs2Nem75oU+Gtj9L516UqDEvMX2i07qG7 hfrBP9KcI+6bKtat641gD8gedxHj3CevLF/91HLizku/63ovr+f5VyT8r/L5b4eEJ3rqPfMFBEJo bHcbHdSs4O3lqWeT5uGx77ivjF195xxtKlzsvPx1q/NqGxHhghgIivpc9uHfXzDTinu5cZ0Nt24i On9xYm5VckP1Y2+/PWEm2vSdiIyfRaPOeNB7evc5IvcJclrW8ELRpiiNr5NrUPDiJzrXdKmzv/7v Vy7SO20y+AsVjQ7h1+k69kreBIbX9SdfuUi0fOXWGA60xyQS5kTqNbt89bMbiOi8RvfGipinWVHs XpF+EIi08fpffGKmsd2R/MQSPwpXu3KvFQf1D7vzrU2aOx8l8ptBtOKgPvB2SHiip/5RnSd+SOAC 2oqDnsx7xcFAl/gWb+LmHVy88KYlr82zFxEtfuqvo3Z9EuJW1EfZ6dMr54nyVi4jGl+3cgnR2Nu/ pb8rn0OF3FvRuU9ft1xac3H1U/zxMyLuz/FBfvlzn3oeXb66U7/a85B7pEqiznjk3Q/iM6H7L14l 8pqttOahv3COB3wnj3rnNq1fsMNvXaImMp+z8vKG8foX3gjU/giIZYd46rx1iZqILl7xzpnGP75I tHzxqluJIv+hZZ4PPKwXYABhvGYt1pMXVz+1nDZpHh7TkO/IaBhtCCTWLzSxfhCMNMvZEl2YzxP/ xnbrTr/OXaPwuuVgyRoVEXGTi5yh8qju4YPcJYtPRbbL7hMsRJpKLCTW/V0h/+/GsoYXNj/lfQHN eQGZu7yz/IZ1dL7+hTc+1j18sND9+dyV4vP+Ymh03jfm8a9PAhDRvKwYc/7tc9x09mVbCxfTxYn+ uVXnvBr++/NE42+eu+o3cOXlnbY3grlpL6Q6E92Kp8rplR+/9w4RFRZh2msSd0gEDjzIF2AYAr5m x+tfeGP3Ofev8hwZjUxcBfu3a8OdY/qH8m1BVAAAIABJREFUXT8y7I3o4z46Wq6cJyIae7uXiC4N X3Q9yo0jmD7ksq7X9W+s0L2h6RXfDgkvYEjQ8tWdzlcTNxLPffDjXD3523Eiot5P35F4jquvvO1/ 3/zDYwJ3yQMQzccoOze8VLhkLTeR3WQ9SzlzqMx5A6tr/IzId4yK+0zsvP+MG9337C0ytVqqzngU 7JzLtct9bgh2TqFbZ1qzqXzxXKe9Cnb4pxNmWqEuzFn363H+MimrjPz3QrG5pGGLZYd46uSOffkN 67yGT5atWU5EV4c/DbHeoMzzgYfxAgwo3Nfs6/o3XifXzG/ijYzO31x2L9F5oYn3g3CkARGR2MiR evmNXuEqtR0SXlinfuLjMC6Wuq7/AAQwH+uyn/3tBTOtuFd36yb3p8+wuddG4BNY4+W85sefmInU 5Zulh6+CrTMRbbjzYCG5xpw4zj833PxyWr5aL7jMxVxwA128mtc99BdPLadNmtivmhKVDuHXabGe vOi7hsmjus1PLeemM0biEMIT4QMP5QUYhoCv2XUP3T2mf9i5AJHl7E/P+ZWcf1F6oQXoB3ekcSv2 9J5eoXtjhe7kKxf9ygNxn6V9Q6jnoWWi2yHhBQ6Ji59U6t5Y4fmZ641Y3OUys+nkCt0bK378iXnu 7YdENB+j7FyKtqlwBdHYxxapBSICcoe1e6F30cmFlrM608rO8sWbNHc+2usaBvOZxkr0TtsbTSuD rjNB+M42dl/78zZebxx7SrNCXf4XDb8N9++RUIdres9r2m4d06xQl28e49/VcO7jGN1+Go0OEatz vP4Xn2z+h9XqwqIxfRHv8auv/GL+bwqMZiQE/QLUfCrwkNl0suTXorsEfs2e/e0Fc7lPD/NyZeGY DO6gQhP1F1rAv4euSPM7Xq+7C4DjvP+Bf8rGfvrrcSIS2w4JTjQkxn96bvXBwjBviXGvGOOz/eyF CaLFvu+JAN7m59tPz7/NDXTN9a3CeRX4/AXPX8z+i1dJZI0X5/CVxC3bodWZeN5pe6NE7B2o98NX LhLR4qfujXRX9J5eoXuPP8/PbDopk2+wikaHeNVpOVviM9h58ZPKOQ/SzF3EDzy4F2AYpF6zlrMl XsNUV1/5caxXjIlKXAXRDzr+nH4iGtuti9bdBXHO5/4Hd8yIbYeEJ3rqX9d7v6yCy9dff9v1R2n5 DQJLwTgXlSIiMptOVpqS/J46EKZgWTbsnc1mc8mB9yPYGghSzzN3oOf5krZDkvbA5we6N17gTEEY EDYQVT3P3KFW+96hcOXKFYVCwTBM8PWseWns2OZLGRkZ8zPKDgAAAAAAYZqXueyhEr11Gt8HFiM4 Iz6StkOS9sDnB7oXAABEyDJlt5wt0WFdMjnBGfGRtB2StAc+P9C9AAAgAhNjAAAAAABkDSk7AAAA AICsIWUHAAAAAJA1pOwAAAAAALKGlB0AAAAAQNaQsgMAAAAAyBpSdgAAAAAAWUPKDgAAAAAga0jZ AQAAAABkTcGybNg7m83mCDYFAAAAACAxqNVqny1XrlxRKBQMwwRfyZqXxo5tvpSRkZEyx9Zk3PiN OdYAYbBf+gw9z5e0HZK0Bz4/0L3xwn7pswMfH4h1KyBaFCybcp1Jm3akzjhSp2dTZ66nzsymzThS px1pM7Mp0460mdnUGQdXIIX3UOq0I23GkTLjSJueTZ1xpM7Mpk07UmacD1k+GVx1eFWsDw4S1vD2 4chWiIkxAAAAAACyhpQdAAAAAEDWkLIDAAAAAMgaUnYAAAAAAFlDyg4AAAAAIGtI2QEAAAAAZG2u izwCAAAklPC/rQSig/X6YV0/AEkFKTsAAAAREbE0y6Z+eW3t5PRNM44lsW4NCFlAlEmUSUT0wOhL sW6NR6pyiXppzdL0by1OVcW6LUnKZKuMdROiCyk7AAAAEUvXadH49YeW37J0UWZGRlpqrBsEgfSP WFmbXIbaF6auvPv2jluW3ojIiZX+EStZEny6N1J2AAAAIqI/2SuWLVnMpqWP2R3MlCPWzYFAGEYm 6ToRUXHeS0sXLUHkxJCs4iFKkLIDAEDSY4kl1jGbqUxLG7dfD3KnKfNHU+b+yQ/fuz7+BWOfjGoD 45QyY2Hqslsy1GuX3FGavjKSM0YYholgbXPCUqbyZkROMJIiHqImDlL2UZs1Kzsn1q0AAICExhLL sNdmWTaI2RaMfXL8ZMflns55aFdcY+yT02OW6THL5Z7jS0sqb/re9kjVHMxpmicsEatA5AQjKeIh amSesls7dJrusrbmbbFuSEKxdug0tu1dtcXuLT3NFXUm5/8r9xr3rCeivsaqet+/KeUN/L2IbO21 WtPG1tbq7Cg3OTKCO/BEwz9GUmvbmrfl+G/nuM6vtUOnOTTEf6SgxnOWe5or6ogfCbb2Wm2Lect+ w7MlQbfK8xS8Jvk601S674R/A2RFrHsD9yGR19ERhdZ7EBUsyzIMM+2YlSw5M2b5or3ZMf7lPLQq kVzu6Zx4v+sWTW1G3u1zr01Wo6qInDAkcDxEicxTdog4ZyZR7tnS01xRN6JtM2zLIaLRo1pdReNe 4571xXsMxj3uQmeaSved3/lQsXdV+1vMVLBxvpo+N0EfeMxaGAW29lptS25Dl8F54nqaKzRVVk92 6PUZrK+xql6b7UorfR/Sltp8PrCRq05tS25DV7PAQ2KsHTrNobz9Bn0J16RaEsjazzSVHslpMxhz XA1ozJbb2Qm1e3l9eKapdB/tNxi5ktYOnaaqCVl77LEMw0q98TP2yT91vCKcdTnsE1POqRGpmUsy Unw2OrcxM5PXpr3SuwXpixamKUOpireTYEl+gz1P53kewY3+xzozeW16VrBWkQKSjbFPftHWnPWP PxOuLxSSZ2o+xU/khFKVp5BIkMy5QKLGQ5REM2Xnxt5cv3nevdzb83fq9Y9niRZ2DVMNud8F3QNa BTUN5d31lse4t3CxJ0pSPc0Vr2Y3lHfXc33iGTweParVtQ5SfmV5Pm/4vO+UiSr3uhKmrG1Plre+ arPRev6IZl/jvhOVe42uk+WsraE7r1I9NBzlw4mA8A88vlk79reQto33ciipbag01b/a8UiJwIh1 saYmX9Pda632v6hVvEevHdYdbn+o2CsGBEbcxVqia6CyVYdaO4kKavaVdw8V1NSVuJtUdbh7dJt3 zbb2IycKNra68vjiPQZjMIc8n0LtXn4f9vSeKKhpdSfoOdXbKw/VnzrzbIm8PpMkhPcb3l++fHng Ml9NfbXuh+uIiCGWkbq8fsl0bGbMKvAAMzN5z8sDjWXcb6f2rP1/OhemEX+jc1vhc52/fMzrM6r1 yBNbD/ZLVKUkx30vD/yPMq+dzgmX5FeVv/v4r3Zwk4Ytr1Xf22zJSBHc6Hs8DvvEqmeMHTtUXS8U 7f4PgQP2KyDSbN9+sk9+ceQnNz369wJVhoKJ2vr5Cy8vvOO9O5YuXRq42NTUVM+f99gX2UnmkRNe VeSw5+0+3sFFieW179/3v81+Hw7mWoAoHuJBPqK3HI5z7M1g7DIYu/ZuIVN94xmv7W011HLgqFW8 cE61vq0mn9TaNsOzJUTWDl3diLbNYOwyGJ+01btzdLEnSmaDh+otjxm7DMYuvXZ4X4W7Q8r3GrsM eo1XOlG8x8AfvLSNjPjWZu043KnWarySCVv7gVPlzzwSL6vPhnfgcc7W3T1UsHGD9+h18R6DMdAM k9wc4TkqWRvK1UOmd238bdYOXTD5Omfw0CmV3thlMLZWz1rM+eXfdbchS6UeslzwKT7qXUaGQu9e Xh9mZ+cPHvq3Hu8dZXYNIVEsX778LSnuwgzDMgFN9r9/tU/k42Phc52NZdYjTxQVFT3RZilrPP7M GqI1zxxvLLO0PVFUVPTi6bLG40/fxlD/wa1FRUVFRUV//u3vv2Yhop7XvFIlkaqIuX9LGVF3A7dz 0daD/WIlvao6sENFPS8WFWkOW1Q7On72oNhGLw77xD0vDzizLSFCBSQb4zL10e8m+98P3NVBiGKK tmnTJsmw2bVrl7u8rCMnvKoc973csUN1+sWioqIXT6t2ND19m88o9twLuMg/HmQieil7Sa3R816+ /k7X+vZ9p0xUuaGYiHKq9V2uq+Eihfn62g4NVT7mKv+QtkDiiZJbeYPz7T9r25Pl1Nnbx/3/camc wNqxv8W85UmvnMOr593FTBvrfAZc5SvMA493oxYzrcoO/oj62g4NFWSLndTs3FwatI16Npxp8pmr LUFdtpGre9Tqf2Vm2Ob1YcBZ5sJRbVVFaVVFaVWF/D6Hh9q9xO/DnGr9/vITdc6j07WPSu4L80Iy KZgZs4ju3H9wqzOPpnODFiJV3m1Eq3NVRJahfiIynOwi1V13e7JYR8Huph0qOv3iLkMwVdGaVSoi y/AfJiYmJibsjgAlfasq2vWmfWJqloistmGxjV4e0LuHaoUJFZBsDM/UR7+bc4omo4kQso6c8Kp6 YEsZUddJg9BeESrAk2DxECXRXnS+p5l7T3LdyDhqHaZ81crgCvP57Ji1oVwd9L7Jh594ZWfn04hV 6GKcL9cMY68JtQJD7KNHG7rL6hMouxU88KRgqi915cSlVfXDwd/iaaov7b0ztItaYuP3ooZajlA9 d/XM0ED7ZJi1z0lJLXdoxv3lQy26itKqph7pnSDKWCn2jz+QrsVhz8tTORNhhYKI2FkHETlmWSJV 7mpnKWbme7odKrIeecU3VxKpiinIVRGpdnQMDAwMDLx8z+QMI1JSwNaWgY4d9Fr1lsY/SGzkKBdY jzxRpDksmmcGLCDRGCIi+8AHkr0tSbT2eSfryAmrKr8xa89ekSrAl2DxECXRm8vunHeu5m7v62us qo9U4QjuCy629lptC7nuxeRt7+4eKthYl8MveeBU+TP6RFl2U+zAE0CWSk0mv9n51lFbTpZrSwg3 fthGRqhgo+ujoJqbw128v/xE3b6mspA+7WTlrPLbJjRcnb/zGfdJKdbU5Gt6+/asl89tKkF0ry/v PnQpqTV21draa7Uik+BhHjGzs7Ozgdb9kF5Cm5mZvOfljh0q6nnxYD8R2axEZZvvmfhVR/UW/qg0 c9vTPygjOu07HUG8qsLbcl0Tjtf+8M1fNh5/+vyDLw0qBUoKMOwqMlQ1v9cxkPdP33n6eEqAja6H thLRmi2ixyleQLoxTu6u3vnt7Afzv+7z6LGhz1v+YPPbifc8Ac/UPJN15IRVVWGBxMTXuRfwkUjx ECVRG2XvO2XK36k3dvksBJGVs4r8562KFA6046jFHPS+yYc/gcFmG5Ia4OxrrNKaNrYK9aHflOLR XpOZGxSsKK3Stphp8JC2tLkvgo2fRwEOPAFkb9yYP9jd632BxdZ9IKzzNdpr4keCK6JKahsq6URd aBX6TF4ftZj9rrwJpfUyE3r3evqwr9F3qo/fvCOICelxvOnAiZfDnrf7eGMZWY88wU006D+49cUe KmscGBhozLVYnCOeRLTm7rtURKdNBs+uExzn6LlQVa45D/3HT1lIddc9a4Wf1LcqJ8PJLqKyLQ94 tdizUWQv/sFJFBBsjAjWPunu1J+ftR4b+pz/6LGhz39+1hpHo6pyj5zQqzo35HsBRaGIRAGxDkys eIiSaE6Mcb8r29pr6zud01WLy9xTq0ePaj3XggUL8xVravI79znL9zTzJ8BI7pt83NMVzjTVmfJ9 Fmf0ZmuvFZ8RceZ0J+Xl8ocFs7a1OucqGLsMrTvVVFDTGp9L9AQ88ISQU123k1o1tUfdaWVPs7bF vGV/yOerr1HXOli+XejuheI9em1BaPd8Z2/c6P1adk9z51WrqaGWX7tz3762Q0PcPTDyEWL38vuQ +2vGm8I+evRV100+EEsMK3ETofKGmwLs7Rzb5C+9wcxMtj95W+F3ioqKvvMvIyqyOm/l4Ga5dL/j yWq3tgxwOp8rFKzKYXdnZcwsQ0QKpVL4SflV8fZyzLJEpFR6VeXZ6NUAIZIFBBsjQrn0Jn7H6j8Y eXPwM+6hNwc/038wIj1zWU4pmqwjJ7yqlErymk5jtQ5HooCIBIuHKInaxJjiPXu3lO6r4BLryr3G /b0VdbZRouyS2tadtdrSKuf2koCFc75bVnCo1bnIY7W+jXSaqgoiovItlXQi8BNF68jiQvkW2ldR SuS9kqaQ0V6TmQbN2tJD/N158yXUOYnZlZIHngiyH2825jZXaKpanRvUQU8BMtWX8r5oqaCmtUt0 IZRt9TWnNPsqKOhV7XP4r2X+Vylxa7E3b8vhynToSl3z3GT5RVdS3SvehznV+q7splJdRYvzwfyd emPc3M+dwLi3/gAFUrLzZy+KXA1xFOw+3lhGltd+2PDuBBG3Ava3n+v85WM5p/bc9lRH9ZYysh75 DZdGcbeSWngpjGFXkSFgVVtbBp4vsbxWXbH/XOFf3aXi6hIsya+Kt1f15jKiHpNBZCPx9hJkkCog 2BiRLGPB8lt9uvrl353nBkr1H4wEfBqnwGdqnsk6csKriqp6nr/TOZ1ms2uv/jkXEJFg8RAlirlc SjCbzRk3fiOCrQlBX2NVffApQqKxX/pMvOeDXCo7oQTskESWtAc+P9C98cJ+6bMDHx8QfMj2Mxt/ GUdBJZtL1v1wHcMwf7Ddnb7s5gAlmYufXjv8P4Ufq/rJe8973dTR82LRLgOt3f2mcwFs/sBn1U/e e76EKxBOVe66REry8fbyPCi40Q9XKugCQTTGLfP+v0nJ/5bwY8GZHv/ykS9eSXcwqdOOtJnZ1BlH 2rQjdcaRMjObNuNwbpx2pM04UmYcadOzqTOO1JnZtGlHyozzIcsng6sOC8zBW3h54Y+W/qi+XuLG uLfeeuv73d+3L7ITQ8Vf//f4iJzgqyIS2S2iBVwiEg99nz8Q9UVVQjG8fVitVvtsvHLlikKhCOkD xpqXxo5tvpSRkYGUPS4hZfeRtKlV0h74/ED3xouIpezWyrSAiRcR2Q2tjqE/htlQICKilG+uz/ir x+ZYycz4l498+S9ySdmXH0PkhC1S8dB38cHETtmj+e2nAJA8vL+EmKcgoW8YgIQyyzCzUm+lKVse mb34KXvlq/lpUuJRpGemlN4v2c+S5l5DBCFywpaQ8RAlcZuyy/ELzGWipNbYFes2QPLJfrzZ+His GwEwJyzLspJv/KnpqffuuP72L9gr4/PSqMSSnpmyZRulpkv3sxRZrRCCyAlTgsZDlMRtyg4AACDl q6mvSjZLfG9A2g1p3H8Ylg1q3YmbV6TW7HGcPMp89N7cW5g8FLeuSr23htIzI7K4R1RXCJmcnLxw wXc9ah+XL1/mNwaRE6o4igeZQMoOAAAJa93udUGVY4mCWPeDT1n+sCJvLWP+kP3UTBMYNxWRnklp GYqbVypvv0OR902GiCI0gSF6K4RML5xu/ay19flWyZIzK2bcjUHkBCUO40E+kLIDAAAQEbGhJF5E RKrbFarbxb8fBjxYorlPfvCqMGop2mzq7J+y/xRqYxA5IYmjeJAPpOwAAABERMoUJTM7q1DKadUJ ECGrucuKBQpETmzJKh6iBCk7AAAAKRSKjHTH1LSd0tJj3RaQNsvMxroJHg7FpZTpdERODMkqHqIE KTsAAAAR0W1f/+1//36NMiMzVWqNbYg5WQ2qDl6qz2MaEDkxJKt4iBKk7AAAkPQUpCBFWsrUhnV/ HB1TX/7yKkupsW4TBLLkxq+RPdaN4CjJznw+RM+qmZqMi/kpyoWxblAyWnLj12gy1o2IMqTsAAAA REQKpSIl1ZGb/Ql7K8tSEozaxQkFy6ZcZ9zfYJoycz3t+mz6hJwmQijoOjsxMP1TYgmBEwMKootE iX4/L1J2AAAAIgUpWIVCqWBZlvs31g0CJwXLKhlSLmCUC5TKBeyCBUrlLKtQMAqFQi5JmoJIQcQk ftYoa4l+9y9SdgAAACJy5lsKUhCRfLJBULCsUklKpVKpZJQKvli3zEeip4wQW0jZAQAAeOSWCAK5 hrEVRApSuH4Akgo+EgIAAAAAyBpSdgAAAAAAWUPKDgAAAAAga0jZAQAAAABkDSk7AAAAAICsIWUH AAAAAJA1pOwAAAAAALKGlB0AAAAAQNbm9J3MZrM5gk0BAAAAAEgMarXaZ8uVK1cUCgXDMMFXsual sWObL2VkZMz1208zbvzGHGuAMNgvfYae50vaDknaA58f6N54Yb/02YGPD8S6FTBPFCybOjObZr+e bnek2a+nTzvS7NfTph3p9utpdke63ZE2fd356PT19ClH2rSnWLrdkcZttzssA5+sOrwq1kcDCWt4 +3BkK8TEGAAAAAAAWUPKDgAAAAAga0jZAQAAAABkDSk7AAAAAICsIWUHAAAAAJA1pOwAAAAAALI2 10UeAQAAEkr431YC84J1/QAkE6TsAAAARETE0iyb+uW1tZPTN804lsS6NSBhA7XFugkeqcol6qU1 S9O/tThVFeu2JCmTrTLWTYgupOwAAABELF2nRePXH1p+y9JFmRkZaamxbhAE0j9iZS/N5QvcI2lh 6sq7b++4ZemNiJxY6R+xkiXBp3sjZQcAACAi+pO9YtmSxWxa+pjdwUw5Yt0cCIRhZJKuExEV5720 dNESRE4MMYx8wiFakLIDAEDSY4kl1jGbqUxLG7dfD3KnKfNHU+b+yQ/fuz7+BWOfjGoD45QyY2Hq slsy1GuX3FGavjKSM0YYholgbXPCUqbyZkROMJIiHqImDlL2UZs1Kzsn1q0AAICExhLLsNdm2WAm WzD2yfGTHZd7OuehXXGNsU9Oj1mmxyyXe44vLam86XvbI1WzXObEEHcvrAKRE4ykiIeokXnKbu3Q abrL2pq3xbohCcXaodPYtnfVFru39DRX1Jmc/6/ca9yznoj6Gqvqff+mlDfw9yKytddqTRtbW6uz o9zkyPA/cGuHTnNoiIiItuw3PFsSq5ZFE//kklrb1rwtx387x3V+ed3iVFDjOcs9zRV1xI8EW3ut tsUcWgd6noLXJF9nmkr3nfBvgKyIdW/gPiTyOroEDr94wrIswzDTjlnJkjNjli/amx3jX85DqxLJ 5Z7Oife7btHUZuTdPvfaZDWqisgJQwLHQ5TIPGWHiHNmEuWeLT3NFXUj2jbDthwiGj2q1VU07jXu WV+8x2Dc4y50pql03/mdDxV7V7W/xUwFG+er6XPjf+B0pklzKG+/QV/CPVp7VDR3jFe29lptS25D l8F54nqaKzRVVk926PUZrK+xql6b7UorfR/Sltp8PrCRq05tS25DV7PAQ2KsHTp3z/c0V2hqSaDn zzSVHslpMxhzXA1ozOY+TMpHqN3L68MzTaX7aL/ByJW0dug0VU3I2mOPZRhW6o2fsU/+qeMVwayL mZm8Ns3lbQvSFy1Mc94J57BPTF332+oqnpq5JMP/nVikKsG9xOoPWJVnJxJugVQLBQuIN9u1g33y i7bmrH/8mXB9oZA8U/NJ9pETTlW8uoTP5twLJGo8REk07621tddWlFa5fpr7/Lbr2kcDFXbmWOZW TVVTDxER9TQ7C2g7+tprKxrPBH6iJNXT7OwfrkNcvUQ0elRbVaE5RJXl+bzifadMVPmYK2HK2vZk OQ3bbN5V9jXuO1G5V/94Fm/b6NGG7rxKdfSOI3KED9zWfuREQc0jXJKU892yAvOp7lHhCuKUtWN/ C2nbeHl2SW1DJZ14tcMmVLxYU5M/2N1rFXpoj15bYDrc7tc/fiPuYi3RaTuONjpfvGe6u4fcPV9S 21Ap0PO29iMnCjZucOXxxXsMcsvXQ+5efh/29Hpij4hyqrdX0olTZ4T2gzn68OcfSv580v4JV5gh lmElfi6Zjs2MCb1MmJn83ccHnI7vzrM7uK2T97zs2Zo/48wrHPaJvN3HBwYG9A8EW5XgXmL1B6zK a6eBl++Z9N1LsoWCBUSb7d0i++QXR34i2c/SP1FbmD3Vnnp71+2SPysHVnoOStaRE1ZV5LDnuesS iKxIFCCKh3iQj+il7M6xN4Oxy2Ds2ruFTPVc7uje3lZDLQeOWsUL51Tr22rySa1tMzzLjYPWjWjb DMYug/FJW32LWeKJktngoXrLY8Yug7FLrx3e58nay/cauwx6jdf8Ap9kyDYy4lubteNwp1qr8UqY bO0HTpU/80i8rD4rdODZjzcb3RMVrO+eGlSXbcwS2jle2bq7h3hZL6d4j8EYaIZJbo7wdYasDeXq IdO7XsmotUMXTL7OGTx0SqU3dhmMrdWzFnN++XfdbchSqYcsF3yKj3qXkaHQu5fXh9nZ+YOH/q3H e0e5fSZJEDewN5wynAr8M/X5FFeYYVgmoMn+96/2GYWfqfC5AztU1PNiUZHmsEW1o+NnDxIRc9vT xxvLTr9YVFT0Yg+pdhx4rpCIHPaJe14e6Ngh9hdUsCrBvYTrl6qq8LnOxjLrkSeKioqeaLOUNR5/ Zo1PC6RaKFhAuNkCpj763WT/+4G7OghRS9mnU7eVbut/pz/Az8nDJ9Om0ty7yDpywqvKcd/LHTtU 3F6nVTuanr6NiXQBF5nHg3xEb2JMSa2xy/3L+jsriZu12XfKRJV7i4kop1rfVR24MF9f26Ghyr16 7g2y5CFtgak16H2TT3mD8+0/a9uT5a11vX171hdT1rbHpVJSa8f+FvOW/c38nMOr593FTBvrWrOo PdINj4qAB+6ac5y/U59gs2JGLWZa9VjwWW9f26GhghqxnsrOzaVB2yiRq8IzTb4TjQJzfyIatQ4T +bxLDNtstJ7XVK7MhaNaXesgEXlusZCPULuX+H2YU63fb6uoq+L+WOXv1OslX5swH7h3/gAFZsYs oo/1H9xadJDIYZ9YNUtEVtswEa25+y4Vdf1L+8QEtT9526+c8w8e0A+8UBrgaQSrEtxLuH6pqpwb iYjODVqISvNuI/qEv5tUCwULCDdb2NRHv0tbvS7QM0gJfKbmmawjJ7yqHthSRtR10kBEhpNdz79w 191rXhr8JKIFeBIsHqIk2ovOu6b5f7OtAAAgAElEQVSyuG5kHLUOU75qZXCF+Xx2zNpQ7j0lI9C+ yacg2/P+n52dTyNWoYtxvlwzjL0m1AoMsY8ebeguq5flvYBhyKnWdxmMXYbtFl1F0l2fMdV7ZpRV 1Q8Hf4unqb60987QLmqJjd+LGmo5QvXc1TNDA+1LtLNTUssdmnF/+VCLrqLUNf0PYomVYv/4A6k6 trYMdOyg16q3NP6BiCnIVZFF9ZTPFBTlAuuRJ4o0h8WzOP+qBPcSqV+yKheHPS9PJZRcS7YwQAGR 5/JmH/hAsrcliVc/3+QcOeFV5TdmrcpdHeECfAkWD1ESzYkxFaVVFa6pLA2Bv0U2pMIR3BdcbO21 FZrusjbfG+D8r/5zU2ISbECauJncnb2JdCNElkrtf1sCWUd5W8pdM8oM3JSVAPm6bWSE91FQrW2r Lab1z+4vp859IeaaWTmr/LatyvZ/6vydnjCT4dkJont9efehS0mtscvQulMtNgke5hEzKyGIJbQN u4qKXrTt6Bh4+T4HFRaoiFTU9URRUdGLp8k1BcWwa+vBfunmeFUluJdI/ZJVcUc7M3nPyx07VNTz ml9rJFsYoIDQcwlx9+rffHPl2/f/mc/P33xzpcS5mJVeoWXeyDlywquqsEBi4uvcC/hIpHiIkqil 7H2nTPk79cYun4UgsnJWkf+8VZHCgXYctZiD3jf5DNp4N/bahqQGOPsaq7Smja1Cfeg3pXi012Tm BgUrSqu0LWYaPKSNz1t++xqrvAZubbYh8cLxKHvjRv/bSW3dB8I6X6O9Jn4kuCKKu+GyLrQKfSav j1rMflfehNJ6mQm9ez196Bt7vDkzEFPS43jTQX3rjeFkF1HZlgeof9hKRJahftdG8YFGh32C4z1Q 7q5KkHD9QVXlsOftPt5YRtYjT+wyBGiAZAsD94AY1j7p7tSfn7UeG/qc/+ixoc9/ftYaR6Oqco6c 8Ko6N+Q7/K5QRKKAiASLhyiJ5sQY97uyrb22vpObrkrFZeXkHC0bPar1XAsWLMxXrKnJd4/n9TTz J8BI7pt83NMVzjTVmfJ9Fmf0ZmuvFZ8RceZ0J+Xl8ocFs7a1esZlW3eqqaCmNcgbEGXGZ+C275RE R8WfnOq6ndSqqT3qTit7mrUt5i37Qz5ffY261sHy7ULzrbmFUEK65zt740bv17LAjb/Fmhpq+bXn 7LQdGqrcIK+zE2L38vuQ+2vGWzJr9OirJpLbASYjhpW4iVB5w02iOzvs7qzJMcsSkVJJNGy1ErGz Dq+Ngra2OCcudD5XKFiVIMH6patyDbBbjzzhHmrl7yXZwuB7QIRy6U38jtV/MPLm4GfcQ28Ofqb/ YCSIuw1llKLJOnLCq0qpJK+9rNbhSBQQkWDxECVRu/20eM/eLaX7KrjEunKvcX9vRZ1tlCi7pLZ1 Z622tMq5vSRg4ZzvlhUcanUudVytbyOdpqqCiKh8i+s2U9F9o3VkcaF8C+2rKCWSvrNttNdkpkGz tvQQf3feMiDqnETtypxqfVuHrrSqnogS9BbA7MebjbnNFZoq573apHYtwC/JVF/K+6KlgprWLtGF ULbV15zS7KugoO8QzeG/lvlfpcStxd68Lcf37Mjw9lOS7l7xPsyp1ndlN5XqKlqcD+bv1BsTLvzi EPfWH6BASnb+7EWRqyFbWwaeL7G8Vl2x/1z15jKiHpOBiH5z2vr4Y5vvmfhVB2+jEMOuIkPgqoT0 C9YvVZWjYPfxxjKyvPbDhncniLil2fkNkGxhCD0gbMHyW326+uXfnecGSvUfjAR8GieGYWhBMAXn g7wjJ6yqqKrn+TvL3HtZj/ymn6h/zgVERCYeEp1iLpcSzGZzxo3fiGBrQtDXWFUffIqQaOyXPhPv +SCXyk4oATskkSXtgc8PdG+8sF/67MDHBwQfsv3M9tZbbwXevWRzybofrmMY5g+2u9OX3RygJHPx 02uH/6fYo2t3v/nLx5zfLvxi0S5X6lL1k/eeLyEi4o9pu4vzS0pWJbiXWP3iVbn3cBFuRMAWChYQ b7avzPv/JiX/W+KPS5se//Iv099In3ZkzDjS7NfTph3p9utpdke63ZE2fT3Nfp37T/qUI23akWa/ ns79a3ekcdvtDsvAJ6sOC8zBW3h54Y+W/qi+vj7As1+4cKHkb0tGvjNCRMRQ8df/Xd6RE05VvLqE QysCBVwiEg99nz8Q9UVVQjG8fVit9v32mitXrigUipA+YKx5aezY5ksZGRlI2eMSUnYfSZtaJe2B zw90b7yIWMpurUwLmHgRkd3Q6hj6Y5gNBSIiSvnm+oy/emyOlcyMf/mXGb+WS8q+/BgiJ2yRioe+ iw8mdsoevXXZASCZ2Nprte4vOOMrCH7tSIDYmmWYWam30pQtj8xe/JS98tX8NCnxKNIzU0rvl+xn SXOvIYIQOWFLyHiIkrhN2Yv3GES+RyzpeX23FMA8yX682fh4rBsBMCcsy7KSb/yp6an37rj+9i/Y K+Pz0qjEkp6ZsmUbpaZL97MUWa0QgsgJU4LGQ5TEbcoOAAAg5eLFi/fdd1+QhRmWDWrdiZtXpNbs cZw8ynz03pwal2QUt65KvbeG0jMjsrhHVFcIeeedd957L9DJnZ2dpXSvxiByQhVH8SATSNkBACBh 3VF/h2SZbMomliiIdT/4lOUPK/LWMuYP2U/NNIFxUxHpmZSWobh5pfL2OxR532SIKEITGKK3Qsjk 0snuTd2hNgaRE5Q4jAf5QMoOAABARMSGkngREaluV6huF/9+GPBgieY++cGrQjmlaIicUCV2PEQJ UnYAAAAiImWKkpmdVQT4BiCQDVnNXVYsUCByYktW8RAlSNkBAABIoVBkpDumpu2Uli5dGmJtlpmN dRM8HIpLKdPpiJwYklU8RAlSdgAAACKi277+2//+/RplRmaq1BrbEHOyGlQdvFSfxzQgcmJIVvEQ JUjZAQAg6SlIQYq0lKkN6/44Oqa+/OVVllJj3SYIZMmNX4t1E1yUZGc+H6Jn1UxNxsX8FOXCWDco GS258Ws0GetGRBlSdgAAACIihVKRkurIzf6EvZVlKQlG7eKTgmXTrjNp0w7FTKyb4qag6+zEwPRP iSUETgwoiC4SJfr9vEjZAQAAiBSkYBUKpYJlWe7fWDcIhClYVjHLKpUKhUKhkEmWpiBSEDGJnzXK WqLf/YuUHQAAgIic+ZaCFEQkm2QQfClYVqlkFQqF7PLjRE8ZIbaQsgMAAPDILREEfwqcJkg6+EgI AAAAACBrSNkBAAAAAGQNKTsAAAAAgKwhZQcAAAAAkDWk7AAAAAAAsoaUHQAAAABA1pCyAwAAAADI GlJ2AAAAAABZm9N3MpvN5gg2BQAAAAAgMajVap8tV65cUSgUDMMEX8mal8aObb6UkZEx128/zbjx G3OsAcJgv/QZep4vaTskaQ98fqB744X90merDq+KdSsgzgxvH0bYQPQMbx+ObIWYGAMAAAAAIGtI 2QEAAAAAZA0pOwAAAACArCFlBwAAAACQNaTsAAAAAACyhpQdAAAAAEDWkLIDAAAAAMjaXNdlBwAA SBipyiXqpTVL07+1OFUV67YkKZOtMtZNCAciJ+biNHKCh5QdAACAiGhh6sq7b++4ZemNizIzMtJS Y92cZNQ/YiVL/M0AQOTEXJxGTkiQsgMAABARFee9tHTREjYtfczuYKYcsW5OMmIYNtZNCAciJ+bi NHJCgpQdAACAiKVM5c3KtLRx+/Ug95gyfzRl7p/88L3r418w9smotk5WlBkLU5fdkqFeu+SO0vSV kZwHwjBMBGubJ4icoCFy5iIOUvZRmzUrOyfWrQAAgITGErGKa7Msy0oP1zH2yfGTHZd7OuehXTLE 2CenxyzTY5bLPceXllTe9L3tkao5mM6XHURO0BA5cyHzlN3aodN0l7U1b4t1QxKKtUOnsW3vqi12 b+lprqgzOf9fude4Zz0R9TVW1fv+TSlv4O9FZGuv1Zo2trZWZ0e5yXMldIAe/h2SSPjHTmptW/O2 HP/tHNf5tXboNIeG+I8U1HjOck9zRR3xI8HWXqttMW/Zb3i2JOhWeZ6C1ySeYMLPu7YYnUGx7g3c h0REZ5pK951w/RJa70G0MAwz7ZiVLDYzZvmivdkx/uU8NEn+Lvd0TrzfdYumNiPv9rnXFqdjpYic MCByQiXzlB0izplJlHu29DRX1I1o2wzbcoho9KhWV9G417hnffEeg3GPu9CZptJ953c+VOxd1f4W MxVsnK+mh0vkAJ2P+ndIArG112pbchu6DM4T19NcoamyerJDryS4r7GqXpvtSit9H9KW2oQz5p5m bUtuQ1dzCOmytUOnOZS336Av4ZpUS35Zu3T4edcWkzMYavfy+vBMU+k+2m8wciWtHTpNVROy9thj GYaVeuNn7JN/6nhFPOtiZiavTc+mZi7JSHH9wn94QfqiDLL7b1yY5n/fXISq8uwZ8HnmUICxT37R 1pz1jz/z2zNkkv0vT4gcRM48iGbKzo29uX7zvHu5t+fv1OsfzxIt7BqmGnK/C7oHtApqGsq76y2P cYmX2BMlqZ7milezG8q767k+8Qwqjx7V6loHKb+yPJ83ftl3ykSVe10JU9a2J8tbX7XZaD1/4Lyv cd+Jyr1G18ly1tbQnVepHhqO8uHMmfgBCndI4rB27G8hbRvv5VBS21Bpqn+145ESgQsjxZqafE13 r7Xa/6JW8R69dlh3uP2hYq8YEBhxF2uJroHKVh1q7SQqqNlX3j1UUFNX4m5S1eHu0W0+NfMIhR8n pmcw1O7l92FP74mCmlZ3gp5Tvb3yUP2pM8+WrPfbD+Yo9/e5kmUcaY7RtaNExBDLSF1ev2Q6NjNm FavJPrHqGWPHDlXXC0W7/4Oo8LnOXz7m9XHUeuSJvbTPf+PWg/3Rqcphz9t9vGOHiojI8tr37/vf Zp/Eae4FiLjc68hPbnr070V6JlgMxX56Q9pk2spPVkoWu/q1q1/mOPNvRA4iZx5EL2X3Gns701S6 r75xg3HPes92a4dOc+DoxuZtOWKFq/Vt5JwYk0Nk7dC5x0p7mivqzFQZ8ImS2eCh+lV7jV3rfQeV y/caW9eTtUPXaXOXLd5jMPJ2tY2MEHnnG9aOw51qbZtXl9raD5wqf6aODpyQfcoe6ACFOiRh2Lq7 hwo21vmPXgfaKTcnh0jgTSVrQ7m61fSu7fEsT3BYO3TB5OucwUOnyvXGriwi6ms8lF/+jLueLJV6 yHKBSCRlFwo/j9idwdC7l9eH2dn5g4f+rafaPawudV4gbLdP3/6v//qvgctUPlLpTNkZNvDldfvH H1ztEztVDvvEPS8PNJbxNvUf3Fp0kIiImVH//Vu/2qHqee1gfz8JbIxWVY77Xu7YoTr9YlGtoar5 veebnv7Ngy8NKiNawGXqo99N9r+fsebPRLsvCHJY9yPlesr3V39/165dAcpcvHjxwYYHPSk7IgeR E33RW8GypNboeS9ff6drffu+Uyaq3FBMRDnV+i7X1XCRwnx9bYeGKh9zlX9IWyDxRMmtvMH5oSVr 25Pl1Nnbx/3/calPMtaO/S3mLU96jRF69by7mGljnfiwqHx5HWAQHRLPRi1mWpUd/G0GfW2Hhgqy xU5qdm4uDdpGPRvONPnM1ZagLtvI1T1q9f+YN2wTy7gFws8jlmcw1O4lfh/mVOv3l5+oq6ooraoo rdK1j0ruC+FasGDBSinuwoyUmTGL+FM9oPdOlXgcBbubdqjo9Iu7DBIbI13VA1vKiLpOGojIcLKL VHfdvSbSBXimPvqdZB9KEq19Hi1cuDBwzCxfvpxfHpGDyJkH0V50vqeZe09y3Uk2ah2mfJXIBSff wnw+O2ZtKFcHvW/y4Sde2dn5NGIVuxjH55ph7DWhlhvj1PATo9GjDd1l9bK/5dSf4AEmNVN9qTNr rCitqh+uCfpOYlN9ae+dXXu3kKm+8Uxwz5WbE8a6TwLhlyhKao1dBmOXwbi/fKhFV1Fa1dQT6yYB sVLsH38gvrdygfXIE0Waw365GTPzPd0OFVmPvGKQ2BjxqvxGHlW5qyNcgM8+8IFkH0oSrV3GEDmI nHkQzYkxFXUmIjU3laWvsao+UoUjuC+42NprtS3kukeTt93v6j83JUYfb8tuih1gAstSqcnke1sC WUdtOe7JLSHc+GEbGaGCja6PgmpuDnfx/vITdfuaykL6FJSVs8pvm8hwteDkE5kIont9efehS0mt savW1l6rFZkED/OImZ2dnQ207kfAJbQNu7YS0Zotfjvd9vQPyohOe808ENwY+aoKCySWvp57AR/u Dtz57ewH87/u8+ixoc9b/hBoFhsTsP9lC5ETRgEfyRk5IYnaKHvfKVP+Tr2xy2chiKycVTRkuRBc 4UA7jlrMQe+bfPgTGGy2IakBzr7GKq1pY6tQH45azPnl3+WlEaO9JjM3KFhRWqVtMdPgIW1pc18E Gx8FAQ4wgWVv3Jg/2N3rfYHF1n0grPM12mviR4IrokpqGyrpRF1oFbomr7uqtpjFrrz5hZ+MhN69 nj7sa6yq8L464TfvCGJCehxvOoxvvVlz910qotMmQ8CNDvsEZ3JG/AJ/yFWdG/IdblUoIlFABGuf dHfVz89ajw19zn/02NDnPz9rTcixUkROsAVEJG3khCSaE2Pc78q29tr6Tud01eIy99Tq0aNaz7Vg wcJ8xZqa/M59zvI9zfwJMJL7Jh/3dIUzTXWmfLHV8YiI6zTRGRFnTndSXi5/WDBrW6vBeUG/y9C6 U00FNa3yXqIn4AEmtJzqup3Uqqk96k4re5q1LeYt+0M+X32NutbB8u1Cdy8U79FrC4KfHkPEJbte r2X3NHcf/uEnJyF2L78Pub9mvCnso0dfdd3kA7HEsGzgybLKG24KvdKCXBVR9zuGwBu3tgxwOp8r jGBVSiURsbMOInLMskRW63AkCohQLr2J3136D0beHPyMe+jNwc/0H4xIz0eOz8QLkYPImQdRmxhT vGfvltJ9FVxiXbnXuL+3os42SpRdUtu6s1ZbWuXcXhKwcM53ywoOtToXeeQWkKmqICIq31JJJwI/ UbSOLC6Ub6F9FaVE3itpChntNZlp0KwtPcTfnTdfQp0T310peYCJLPvxZmNuc4WmqtW5QR301CBT fSnvi5YKalq7xD7zZG2rrzml2VdBft9RJSaH/1rmf5XSmabSIzlea7T7h59/mZiR6l7xPsyp1ndl N5XqKlqcD+bv1AutYgnzjHvrD1AgJTt/9mKIV0PWrFIRWSzDEhsNu4oEpibPvaqqnufvLNt8z8Sv Oqo3l5H1yG/6ifrnXEDEguW3+nTgy787zw1/6j8YkTo8orj9QhxEDiJnHkRxXfb1z3YZnuX9auxy /i/78Wbj40EWztrWavCsEp1Tre+q5v7b12g6IbFvUrtzj+HZPSKP5VTrPV3k3cO+1j/bFSgJEzqV chP4AInIp0MSTkmtsatWZLvILrwXWlA7Bi5PQj0svItPvAmGn9DGGJ5Bse6V7BPfP1wgB9KJ19r1 0+//V8A6lAsURLTAcwl7zSoVUY/ZO1sR3BiVqgy7nsh/85eNAwONRNYjT/jPWp57AY+Utev9O/Cn 75sFCwuK08QLkYPImQeKucz+MZvNGTd+I4KtCUFfY1V98KN6icZ+6TPxng/y220SSsAOSWRJe+Dz A90bL+yXPlt12P+2ZiKi7733vbfeeivw7t8u/fYfN/2RGCpefixt2c0Sz2VodQz9McyGJrSUb67P +KvH5ljJzPiXfRcfjPpqdkRENLx9WDBsFl5e+KOlP6qvD7SWxYULF0r+tmTkOyNEhMiZo7iLnCAN bx9Wq9U+G69cuaJQKEL6gLHmpbFjmy9lZGRE89tPASB5eH8JMU9BUt5IAHFplmFmpd5KU7Y8Mnvx U/bKV/PTpHihSM9MKb1fsvckzb2GmEDkhC3JIyckcZuy48sCRQWY8AAQNfEwSwogMJZlWck3/tT0 1Ht3XH/7F+yV8XlpVDxIz0zZso1S06V7T0qcrvuByAlT0kdOSOI2ZQcAAJBy+fLlhoaGIAszLBvU uhM3r0it2eM4eZT56L05NS4hKG5dlXpvDaVnRmTJDpms+/H73/8+cNhMTnot2ojICUNCRk5UIWUH AICE9W7xu+9OvitRyPVVYJI3EfIpyx9W5K1lzB+yn5ppIsnGTdMzKS1DcfNK5e13KPK+yRBRhKYl yOEmwqklU/+5+j//c/I/Axdj1nqaisgJVkJHTrQhZQcAgIQ1s3Am+MJsKIkXEZHqdoXqdvHvh0l8 LNHcpzR4VSiDxItVsiGFDSFyQpeQkRNtSNkBAACIiBQLFMzsrEIpp1UnkkyczkhG5MRcnEZOSJCy AwAAEBE5FJdSptMpLT3WDUles8xsrJsQDkROzMVp5IQEKTsAAAAR0eCl+jymQZmRmSq1xjZESZwO lSJyYi5OIyckSNkBAACIlGRnPh+iZ9VMTcbF/BTlwlg3KBktufFrNCldTF4QOTIQl5ETIqTsAAAA RESkoOvsxMD0T4klSoJBO9lREF0kise7MhE5sRW/kRMKpOwAAABERKQgUhAxif/eL2vxeA8nIkcO 4jFyQoGUHQAAgCfR3/ghWhA5EE2ILwAAAAAAWUPKDgAAAAAga0jZAQAAAABkDSk7AAAAAICsIWUH AAAAAJA1pOwAAAAAALKGlB0AAAAAQNaQsgMAAAAAyBpSdgAAAAAAWZvrt5/aL30WkXZAqNDzPpK2 Q5L2wOcHujdeDG8fjnUTIP4gbCCOzDVlz7jxGxFpB4TEfukz9Dxf0nZI0h74/ED3xgv7pc8OfHwg 1q0AWUhxzC6cmF40Mb1owr7win3RVfuiK9OLJuzcFue/V+yLrk7b+gdWHV4V6/ZCwor4B0JMjAEA AAAAkDWk7AAAAAAAsoaUHQAAAABA1pCyAwAAAADIGlJ2AAAAAABZQ8oOAAAAACBrc13kEQAAIKGw sW5AklPEugEAsoSUHQAAgIiIWJplU7+8tnZy+qYZx5JYtyZJ3fb1/y8es/ZU5RL10pql6d9anKqK dVuSlMlWGesmRBdSdgAAACKWrtOi8esPLb9l6aLMjIy01Fg3KBn1j1hZllWQIr6y9oWpK+++veOW pTcicmKlf8RKlgSf7o2UHQAAgIjoT/aKZUsWs2npY3YHM+WIdXOSEcOwLMsqFHGVsBMV5720dNES RE4MMUziT2hDyg4AAEmPJZZYx2ymMi1t3H49yJ2mzB9NmfsnP3zv+vgXjH0yqg2UFWXGwtRlt2So 1y65ozR9ZSTngTAME8Ha5glLmcqbETnBQOTMRRyk7KM2a1Z2TqxbAQAACY0llmGvzbIsKz1cx9gn x092XO7pnId2yRBjn5wes0yPWS73HF9aUnnT97ZHquZgOl92WCJWgcgJBiJnLmSesls7dJrusrbm bbFuSEKxdug0tu1dtcXuLT3NFXUm5/8r9xr3rCeivsaqet+/KeUN/L2IbO21WtPG1tbq7Cg3ea6s HTrNoSEiItqy3/Bsif+j3h2SSPgnl9TatuZtOf7bOa7zy+sup4Iaz1nuaa6oI34k2NprtS1mgY4N wPMUvCbxBBN+3rXF6AyKdW/gPiQiOtNUuu+E65fQeg+igmVZhmGmHbOSJWfGLF+0NzvGv5yHVsnf 5Z7Oife7btHUZuTdPvfa4nSsFJETBkROqGSeskPEOTOJcs+WnuaKuhFtm2FbDhGNHtXqKhr3Gves L95jMO5xFzrTVLrv/M6Hir2r2t9ipoKN89X0sJ1p0hzK22/Ql3CHX3uUnyP6d0gCsbXXaltyG7oM zhPX01yhqbJ6skOvJLivsapem+1KK30f0pbahDPmnmZtS25DV3MI6bK1Q+c+Iz3NFZpa8svapcPP u7aYnMFQu5fXh2eaSvfRfoORK2nt0GmqmpC1xx7LMKzUGz9jn/xTxyviWRczM3ltejY1c0lGiusX /sML0hdlkN1/48I0//vmvKoiIiKHfWLquuAuDvvE1HXhesR3CvhcgjUIV8LYJ79oa876x58JVh0S yf6XJzlHTvhVefYM+DxzKIDICUk07621tddWlFa5fpr7/Lbr2kcDFXa+E5tbNVVNPURE1NPsLKDt 6GuvrWg8E/iJklRPs7N/uA5x9RLR6FFtVYXmEFWW5/OK950yUeVjroQpa9uT5TRss3lX2de470Tl Xv3jWbxto0cbuvMq1dE7jkixtR85UVDzCJcM5Xy3rMB8qpsLPOEOSRzWjv0tpG3j5dkltQ2VdOLV DptQ8WJNTf5gd69V6KE9em2B6TDvBevkN+Iu1hKdtuNoo/PFe6a7e8h9RkpqGyrdZ0SYUPhxYnoG Q+1efh/29HpikohyqrdX0olTZ4T2gzn68oMvJX+++vArrjBDLMNK/FwyHZsZE3qZEBE57BN5u48P DAzoHyAiosLnOge8dT5XKLhRsioiZmbynpdduxzfnT/jSVGYme+9PDAwcPzZtQL18HfKswvdGun/ XN4P3/eyRGO53OvITyR7T/pHBqvip8yk3GS7SfJn8VeL3bvIOXLCrcph56rxD7eIFSBKrMiJtuiN snuNvZ1pKt1X37jBuGe9Z7u1Q6c5cHRj87YcscLV+jZyTozJIbJ26NyDwT3NFXVmqgz4RMls8FD9 qr3GrvX8UXMiovK9xtb1ZO3QdXqSiuI9BiNvV9vICJH3PBdrx+FOtbbNq0tt7QdOlT9TRwdODEfv MCIj+/Fm4+OuX6zvnhpUl9W7kj+hDkkYtu7uoYKNdf6j14F2ys3JIRJ4U8naUK5uNb1rezzLExzW Dl0w+Tpn8NCpcr2xK4uI+hoP5Zc/464nS6Ueslwg8s/Inc/iH34esTuDoXcvrw+zs/MHD/1bT7V7 WF3qvEDYvvo/X+3atStwmX/+yT9/be3XiIhh2MCX1+0ff3C1T+xUOewT97w80FjG29R/cGvRQSIi Zkb992/9aoeq57WD/f0ksFZ08v4AACAASURBVFGyKmJue/p4Y9npF4tqDVU/ee/5HQeeM23l9mNm 8nf/oIwEMffrG8uou6Hoh2/d97/eq+/Qn//z3W97DdYJPZdPFVvKiKtCtAwR0dRHv5vsfz9jzZ8F LCVBDut+pE2lPUAP3H///QHKXL58+Z86/unq165yv8o5csKsynHfyx07VFy8Nb/3fNPTv3nwpUFl RAu4JEzkRFv0UvaSWmOX+5f1d1YSN2uz75SJKvcWE1FOtb6rOnBhvr62Q0OVe/XcG2TJQ9oCU2vQ +yaf8gbnh5asbU+Wt9b19u1ZX0xZ2wTGKb1ZO/a3mLfsb+bn7F497y5m2ljXmkXtkW549LjmFufv 1HsuKUh2SDwbtZhp1WPB32bQ13ZoqKBGrEeyc3Np0Dbq+Tx3pim06Sjqso1c3aPWYSKfhQKGbTZa L9hUgfDziOUZDLV7id+HOdX6/baKuiruj1X+Tr3QNQSIiMzMzPvuuy9wmX/+yT9z/2EYJnDiNTNm EX/wAf3AC6XCDzkKdjftUNHpF3cZJDaKV7Xm7rtU1PUv7RMT1P7kbb9yT2FhZvJ3N+1QWC0k9DIp LFARWc4PENHAeQttVBUUEnnlZgGa7XziVSoiy/AfJiYmiESmzjhNffS7tNXrAlUmRSYzkrOzswOH zYULF/6p45/cv8o6csKr6oEtZURdJw1EZDjZ9fwLd9295qXBTyJagCdhIieqor3ovGsqi+tOslHr MOWrVgZXmM9nx6wN5d5TMgLtm3wKsj3v/9nZ+TRiFbsYx+eaYew1oZYb49TwxzhHjzZ0l9XL/pZT HznV+i6Dscuw3aLjTRZKcqZ6z4yyqvrhmqDvJDbVl/be2bV3C5nqg+3M3Jww1n0SCL9EUVJr7DIY uwzG/eVDLbqKUtf0P4glVor94w/E91YusB55okhz2C83Y2a+p9uhIuuRVwwSGwNUxRTkqsiieso5 z+DleyZnGHIn7Ed+cUq4Uf3mUSKVKndiYiJXpSIaNfsMy4o3m//EpNrR4fW8wuwDH0j2oSTR2mVM zpETXlV+Y9aq3NURLsCXtJETkmhOjKmoMxGpuaksfY1V9ZEqHMF9wcXWXqttIddNqLztflf/uSkx IqOecaBYU5Ov4S47JLgslZpMfqPX1lFbjntyi/gaLH5sIyNUsNH1UVDNzeEu3l9+om5fU1lI901m 5azy27YqW/CjguDkE5kIont9efehS0mtsavW1l6rfbXjkZJ4+yScaJjZ2dnZQOt+BFxC27BrKxGt 2eK3021P/6CM6LTXzAPBjYGqKixQEamo64mi5v6q5veebzz+zEh187n83U07VKdfrB7ME34RMr/+ wW32nw80Dgw0EnXtue3//g/fuwDFmu1+4ttyiaxHnth6sH/tD9/8ZePxp8+LzG8gIiJ3B+78dvaD +V/3efTY0Octfwg0i40J2P+yJefICa+qwgKJRdPnXsBHckZOSKI2yt53ypS/U2/s8lkIIitnFQ1Z LgRXONCOoxZz0Psmn0Eb78Ze25DUAGdfY5XWtLFVqA9HLeb88u/y0ojRXpOZGxSsKK3Stphp8JBW 3rf89jVWeQ2r22xD4oUTSfbGjf63k9q6D4R1vkZ7TfxIcEUUd8NlXWgVuiavu6q2mMWuvPmFn4yE 3r2ePvSNSd6cGYgp6XG86TC+9WbN3XepiE6bDAE3OuwTHJFR7P5hKxFZhvqJyHCyi0iVu5q57emm HSrLa/+rfWJqlohodmrC7uBX5bjt6eMDjaq2J4qKip5oUzUOHH9mjfRzeRXoP7i1qIibNd9//JSF VHfd43+Tq6sD7ZPurvr5Weuxoc/5jx4b+vznZ60JOVYq58gJr6pzQ74D9QpFJAqISNrICUk0J8a4 35Vt7bX1ndx0VSouK6fO3j4ibrUH97VgwcJ8xZqa/M597qVj+BNgJPdNPu7pCmea6kz5YqvjERHX aaIzIs6c7qS8XP6wYNa2VoPzgn6XoXWnmgpqWuW9onmxpibfGXJEzs94gTokceRU1+2kVk3tUXda 2dOsbTFv2R/y+epr1LUOlm8Xmm/NLYQS9PQYIi7Z9Xotu6e5+/APPzkJsXv5fcj9NeMtmTV69FUT VW5IirCUNYZlmYCUN9wUeqUFuSqi7ncMgTdubQm4IgvRsNVKxM46iMgxyxKRUll431+65qx07HD+ r2Urv6r7v/eXKiLL4DkiOjdoIVL9/+zdfVBb570v+t+SeXXikjRO0joIgSzqlzhp7w7jDiFAjxK0 yUtJatKSa8vBJ9p7+w575lo7L51CvcPFw8BMyfioJ7Vaeoa21ODZ7lTxvsrpNpVdzbUw5pTjxG2T krARCkgkfsmLsalBYLTW/UMvLL0uCUloSfp+hsnEaz3P0rMe/ST99OhZzyrbFsVj8QusOH3ZIOti iYiRhM0cJEX38LtLf2n6rckr7l1vTV7RX5qO3L0sy7LpmXiJOnLWdiiJhPzizW6fSkSBMLI2cmKS tIkxlW2H62o6Ve7Euv6wqfuCqtUxSySt0vYd1GpqGjzbqyIWLvlmbXl/n2epY/cCMg0qIiJlnfcy 07B1k3VmaUFZR52qGiLhK9tmL5htNGnT1PTzq/PmS8hL0r0rSxr1A4aWGs+Mqay61E+6T2cq1anU DZ5rtb3zx6Jgbq/h3WipvLnPEm7ORnFTe/M5daeKDke7UlMJ/7XMv5XSWE/NiRK/NdqDwy+4TMoI dW/4Pixp1FukPTUtql7PTsVBvSlrwlLE3B/9EQrkSBWuazH+GuK+enNmSmCj8VBFiKnJPOO/P2/f t/eJp+Z/Y2h8opZoxGwcNxrdy34QbT9kGNhPx9WNP/6QyLh6qJ2k2bdXVlY2P//+rjIZkd0xRTQu 9Fj8xuzpnXi9auZXjaru93f9/bdkZD/x+1AzMoiIaMN9DwR04LF3P3IPf+ovTUd8SI/I/S9aoo6c NR6qYeT1x2p98eZ+2sfjLhBG1kZOTJJ4K6Xdr1mMr/H+6VvXxW/RPYHCxU19xtVbn/IWmRntMp8R qJvVHmszvtYWZl9Jo361i/x7ONDu1yyRkrBQT6Uo8ZcnCr13HRuzzqq0Jos2zPYwVSJ3V3DFyOUp VA+HrhIQbyHDL9TGFD6D4bpXsE8C37hADIQTr527l975/yIeQ7KBIaINqwPR27fKiEYCrvoMuVHg UONH9xyRXXTPSrefeNF/iY+gh/Wr9Lph4gAR0ciRipAzoMPXJzIeelHx1q8PuI/gntMetsU5O3cH d+BP3rGFrRAkTRMvcUfO2g7lfuJ98Rb8tMdfYFXWRk5McPdTAAAAIvJMSY6wn7l3S47ioRXre+GL +FbB9go5CBrNyGjwoSJUCy4b72NFt48n58HdG7buindKcZpObxB55KztUIJPfPwFiCjLIycWSNkB IBEcg1pNb6ghkfLo144ESC0Xy7qExupy6l5wXfuYu/nF+jQpXTD5hTk1zwr2nqD4j5ASiJw1y/LI iUnapuy4WWBYESY8ACRN2sySAgiL4zhO8IM/Nz/36QO3f/dL7ub1dWlUOsgvzKlrotx84d4Tkqbr fiBy1ijrIycmaZuyAwAACFlcXHz77bejLMxyXFTrTmz+am5z28rZk+wHF+NqXEZgHtia+3Qz5Rcm ZMkOkaz74XA4IofNjRs3+P9E5KxBRkZOUiFlBwCAjFXSXHJq7lTkMtv/63b3/wheRMgnUX6XKdvJ 2v7KfWyj+SwbN80vpLwCZvMWyY5HmLIHWSJK0LQEMVxE6LzTOZgzODg8GLmYa8fqvXsQOdHK6MhJ NqTsAACQsQruKYiqHEdExMWSeBERyXYwsh3h7w+T+Tii+Kc0+B1QBIkXu4F13uGMqQoiJ1YZGTnJ hpQdAACAiEiSI2Fdrgi3CoJkS9MZycwGBpGTWmkaOTFByg4AAEAMwxTkrywuOSkvP9VtyV4u1iVc SHxWmLmcpXxETgqlaeTEBCk7AAAAEdG2+//3//rTdklBYe7dm1PdliyVpkOlk3PtZWwHIieF0jRy YoKUHQAAsh5DDDF5OYuPfv292cvyG5/9jaPcVLcpG22668upbkLsJORkr1rpNTnbXHBNkSPZmOoG ZaNNd32ZFlLdiCRDyg4AAEBExEiYnNyVUul/cg9wHGXBqJ3IMMQwEoZh0vCyTIZuc/MTSz8hjhA4 KcAQXSNKw8CJCVJ2AAAAIoYYjmEkDMdx7v+mukHZiGEYhmHSL/diiBgiNvOzRlHL9Kt/kbIDAAAQ kSffcieMaTnWmxnSt+MzPWWE1ELKDgAAwJO+KSMAZC58JQQAAAAAEDWk7AAAAAAAooaUHQAAAABA 1JCyAwAAAACIGlJ2AAAAAABRQ8oOAAAAACBqSNkBAAAAAEQNKTsAAAAAgKjFdU9mm82WwKYAAAAA AGQGuVwesOXmzZsMw7AsG/1Btr95+dQTcwUFBfHe/bTgrq/EeQRYA+fcFfQ8X9Z2SNae+PpA96YL 59yVNz58I9WtAHFhOCpYWCr6YrHoi1tfun6r6IuFos8Xir64VXR9oeiLW0VfLHz8/odbj29NdTMh Y03tn0rsATExBgAAAABA1JCyAwAAAACIGlJ2AAAAAABRQ8oOAAAAACBqSNkBAAAAAEQNKTsAAAAA gKjFu8gjAABARln73UogaZhUNwAg1ZCyAwAAEBERRy4u97NbOxeW7lle2ZTq1sCqbff/vyLP2nMl m+RFzUX5D92ZK0t1W7KU2VGf6iYkF1J2AAAAIo5u0x3Xbz9/371FdxQWFOTlprpB4DE+bec4jiFG tFn7xtwtT+4w3Ft0FyInVcan7TST4dO9kbIDAAAQEX3uVN296U4uL/+yc4VdXEl1c8CDZTmO4xhG rAk7UWXZm0V3bELkpBDLZv6ENqTsAACQ9TjiiFtxFUry8q47b0dZadH2waJtfOGvF29f/5R1LiS1 geInKdiYe/e9BfKdmx6pyd+SyMkhLMsm8GiJx1GhZDMiJxrZGySJkAYp+6zDXiwtSXUrAAAgo3HE sdwtF8dxwsN1rHPh+lnDjZGhdWhXumCdC0uXZ5Yuz9wYOV1UVX/PM/sTdeRonpFU4og4BpETjewN kkQQecpuN7Soh2sHdE2pbkhGsRta1I79Fm2lb8uITtVq9vx//WFT224iGu1qaA98T1F2WLSVRI5B rabX5tuqOKjX7ytOerPjEeoEMx//rD08zyDZDS3qfit/T3lzX1+jdLUidfAixP2M13UbX6uK+tFX H0KuGdA1hfrWHVUgify58+tk3plG7mEiorGems4z3n/E1reQFBzHsSy7tOISLLl8eebTQd3K9c/W oVVp6sbI0Pw7lnvV2oKyHfEfTfwDqIicNci2IImfyFN2SDhPJqFc3TKiU7VOawaMTSVENHtS06Lq Omxq213ZZjS1+QqN9dR0fnTweXcONzsTY/aWWmFOMNXNWh9KfuY92tXQrpF6E8fAXZoaB3/LqhGd pre0w6ILsSscu6FF3V/WbdRXEY3oVGothcrahQNJ3M+dY1Cr6S3tsBg9PTOiU6kb7KtnFKGHx3pq OqnbaHKXtBta1A09afSaylgcy3JCH/ysc+Fzw88jZV0rzvnF2xvy79iYJyEiYpcXbi25iIhWt7nL EBFRbuGmguBP4tVKoWt5NvKKefBK+zco7N4wjxW6RbzWrh41dEXWufDpgK74hz8NebiYCD4pKSee yEnkoULWSmiBrAqS+CXz2lrHoFZV0+D9040GbW8ZnI1U2JNc2vrUDT0jREQ0ovMU0BhGB7WqrrHI D5SlRnSe/nF3iLeXiGZPahpU6n6qVyp4xUfPmal+rzedKm56SUlTDof/IUe7Os/UH/aOgI6dH1I+ lj65RTQnmCUq1c2KyeEL9lC72vSacvNx3kvSI2jEPTS7oUVjONnleXmODQ9by5tfcAdJlbaj3nZu OOjIUQSSqJ87u6G7lzQDvJ6p0nbU05lfGEK20K+HRy6c8fUPEZU07q+nM+fGQtWDOL3T8Y7jp47I f38++md3YZY4lhP4mzOfWr4c6kXkwS4/c2xiYuL0azuJiGjFWfby6Qm30y8rllkiYpcXnjrm2TZx 7KmF5cBcg11W+CpNnH65zLniPtRqLc/GXT8YmvA39INdgcda4FdTBD5Y6McKsOKcd5+G/jnfpm8f i/Sw7mM7Fz498WPBLhX+W9+l8jfe2Fj9h+pnLj4T+e/x4ccLbhV4zlQkkZPIQ4WqleACRGkbJCmR vJTdMzJnNFmMJsvhOjK3u3NH3/aBZup946Q9fOGSRv1As4LkmgHja1VEdkNL67RmwGiyGE0vOdp9 v6eHe6BsNtnfPrPXZDGaLHrNVOdq1q48bLIY9Wopv2xlm5E/bOmYng48mt1wfEiuUXvL2B0flU8f 935HaglO8kRG+ASzS2lJ6CtDih9Vyq3mP/qlm3ZDSzT5uttk/zmZ3mQxmvoaXTM2hfKbvjgrlsmt M58Elo8ikMT83DmGh63l1Y/6d2Zlm9HkN/uFj9fDUqlisv/fRvwriubXg8xy3333vS3EV5hlOTai hfF3/jZqivBw7LLi5X+sXf33yrePGQ7Izh+pqKg4cl52oOeVbSzR9ldPd9XODLxYUVFx5Hxt1+lX tgXkMrt+8MYBGY0cqahQH5+RHTD89DtExD6r76ql4Y6KioqOYdkBg/5ZlsaP7qmoqKioqPi7h7/3 qxkiGvnV0XH/Bm175XRXrbsBIyQ78EZgbh3ysfysOOefOjZhOOB3rSD7bF0tuVtTUVFRsSfgYX0W P3h3YfydyL0ahfXOxh5//HHBsDl06JCvvFgiJ4GHClkrsQW80jRI1l/yUvYqrWn1k373Y9717UfP man+0UoiKmnUW7y/lYcpzDc60G/1jbdVPa8pF3ig7Kbs8Hz8Fze9pKShC6Pu/98nlBPYDd29trqX /HIOv54nIofDOkm17u9OFmMrvSH+rH1VqBPMHqMD/dZyabjLDqSlpTTp4D2XYz0Bs7EFyGur3cee tU8F7QweHY81kET23M3O2GirNKbGrPZwSaO+W3mmNW2+92YNwaRg+fJMxPrLipd7DjD21ULP1dUS Wc4aich41kKybz25nehrpTKiGeu430Y+dyZ+6C3n/KKLiOyOKSLaVS4jmvlogogmPpohkpWvJt8r 5S/3HJDR+SOHjAFN2v7kt2RkGRqcn58ffGnbrm8E5dYhH8vPc/qJrtrAjdu3yohmpv4yPz8/Px9y ZN5n8YN3487GxD7nQSyRk8BDhayV2AI82RAk8Uv2ovPeqSzeCxln7VOkkG2JrjBfQMXiR5XyqOtm H35aJpUqaNoe4cc4H+/8Y78JtQFD7OT+jrQ6L1laWmrt/W16TEYKeYIZzty+OmesoX0q4ArIyBUv PBbbz1bhxu/DiCmQMu+5q9K6v6uYupXW3hZVjXf6H6QSJ8T54aXwtT250olfnlvdFDjwJyv9GhHD EBHnWiGiFRfn2RjCnt4JwwH6VWNd11+IaNw2SySTlc7Pz5fKZESzNm/yzS4/03JARvYTPw9M2Ikt L5XRjOyfBOdS+D+WH8kG+4kXK9TH+TknW14qI5IdMAhN0SAi58QlwY4VFPbo4iCayEnYoULXSmgB vmwIkvgl7/JTz0IKcvelY6NdDe2JKpzAuuDlGNRqesl7nR9v+/Cwtby6NUIqJpUqSCyziyMId4KZ ThnttBb3tJPyau+XPbl7lnZlt/JMa2dPbUy5cnHJ1qBtggPS4QNJnM9dsUxOZoeDdvudl33WUVIc 7kz9e9irSmuyaB2DWs0vDC9UieU3hGzFulwuV6R1PyIsoe3OlWTnjzROlvleLbvKQ608PeWwE9U+ 8dT8bwyNdUHj16uMhyqMDbqLhomyf/3GK6clv/3Hbc6fTXRNTHQRWdq2/V//03M9H7vtlX+sJTof OCfG1wAZWV6s0I036C6+3nX61enG//6fQo+V479rDxFtr/M77rZSIvuJF/ccHd/5L2/9uuv0Kx99 583JsIOAvl49+LD0O4r7A/aesl7t/UukjxE24pMiBiKJnAQeKnSthBYIkPFBEr+kjbKPnjMrDur5 o2hE5P4sD57VGqZwpIqzM7ao62Yf/vQGh8MqNPw52tWgMVf3herDWf9Jye7CKv6wq8MRYa6FSEQ4 QfCavWDmP9femHFfUtka21XdAZPXZ2dswb+tRRlIon3upNXVwdfyOobf0IS9An61hwPPPcSsJEgJ 4XG8pXCJF7vtlZ4Dsplf/bdB9wQTci3OO1fGrYHTIRiGaPzoniMjVNs1MTHRVToz49644px38x+w Np61ENXWPUfstldOT3TJBl6sqKh4cUDWNXH6Vc80g+1PfktGdN7sG2LnHer9KTvx5z+4RzqFHitc gVXjR/d4J7CPnz43Q7JvPbUzbK86F3z997M/209Zr/L3nrJe/dmf7ek+gCqOyHGWJy4I3w9ZK/4C 4TowC4IkfsmcGOP7zHYMatuHPJNZK2t9U6tnT2pWfwsOWZivUt2sGOr0LR3DnwAjWDf7+CYzjPW0 mhXexRlDcgxqw8+XGDs/RGWlfnlUpbpZ4XkGidxfmfxzerGJeILgMdrV0jep3B9qfX33UicxXdUt ra72f7X6prnzDhtFIIn6uStpbD1IfWrtSV/WPqLT9NrqukP/rMHvYfe7GW8K++zJX3gv8oFUYjmB iwglX7onTNVd3/4v3pkihgOe/+vdQxIJ+U0/sNuniNjlhcGXtu36RkVFxTf+x7TMvXFP7+riKytO X7a84uKISCKhXc/8FxnRzOT7RPT+5AyRrGybu9HlpTKi4T+sTorhH2rKbvdrAEkkwo/lVyDk6fJq sS6WiBhJ2HRCUnQPvw/1l6bfmrzi3vXW5BX9pWnhScqiz8bEETlv/NcEBmHIWvEXCCMbgiR+SZsY U9l2uK6mU+VOrOsPm7ovqFods0TSKm3fQa2mpsGzvSpi4ZJv1pb393mWOm7UD1CLukFFRKSsq6cz kR8oWWeWFpR11KmqIRK+z9HsBbONJm2amn5+dd5sCnlJQFeWNOq7dSr3M5gG91ESPMGsZW6v4d1o qby5zxJ2qZOm9uZz6k4VRb0megn/1cq/ldJYT82JEvc/wwaSr4zYnzvpPp2pVKdSN/R5Nsj9Z++E 7+GSRr1F2lPTour17FQc1JtE/TrKEu6P/ggFcqQK17WQv4aMH91TcdT9v9sPGQb203F1448/JKKR 1x/zTD94opbsJ34/TrTrB0O/3ltyrm3bPxka67wbxw9V+JLuPb0Tr1fN/KpR1f1+4xO1RCNmI43v PG/ft1dWVjY///6uMtnqhaLuC0FneNmQkXco2nnevm+vrwE0YjYSkcBj+RUIiVdr199/S+Y5h9A2 3PdAQK8ee/cj95io/tJ0xIfxiPykiIFYIocOH07YoRpC1Iq/QBjZECTxY+L5KcFmsxXc9ZUEtiYG o10N7dEnEJnGOXclfM9HuZB2RonYIZksa098faB704Vz7sobH74Rcpfjpw7+Mo4hVT1R9fV/+TrL sn9xPJl/9+YIJdlrH986/iOB1ux8+a1f76UTL3oWZ9n58lu/3ltC5J37HW5b8DHcX/9GjlR414Fp +PHF1z1TlFe3Nvz44utVvELBfNVCP1joxwpdarUAr1aYc/AqfPYfchQPhd0dhaXrnz0sPS2RSCj8 zIpgDEcFC0tFXywWfXHrS9dvFX2xUPT5QtEXt4quLxR9cavoi4WP3/9w6/HgC29o442N3y/6fnu7 wIVxb7/99veGv+e8w0ksVd7/7yKJnEQeKoYwXWsBr4QEyejV55K+qEospvZPyeXygI03b95kGCam Lxjb37x86om5goICpOxpCSl7gKxNrbL2xNcHujddJCxlt9fnRUy8iMhp7FuxvrfGhmafnAd3F/z9 3jgPsnz9s4dLhkSdst93CpGzZokKktFr38nslD15K8YAQGZxDGo1vluY8ZWLdbo5QGxcLOsS+ijN qXvBde1j7uYX69OktMbkF+bUPCvYpYLiP0KyIXLWLHuCJH5pm7JXthkj3Ucsm1VpTZZUtwEykXSf zrQv1Y0ASCKO4zjBD/7c/NynD9z+3S+5m9fXpVFpK78wp66JcvOFu1SI+BcDQeSsUTYFSfzSNmUH AAAQ8sXiF1VPCNxVIO9Lee7/YTkuqnUnNn81t7lt5exJ9oOL8bcwIzEPbM19upnyCxOyjsf6Lway sLDwySeB61EHuHHjhu//ETlrkO5Bsv6QsgMAQMb6+stfj6ocRxTFuh98EuV3mbKdrO2v3Mc2mse4 KVF+IeUVMJu3SHY8wpQ9yBJRguYqrPNiIEsbl/qu9PW93idYcvmry+7/QeREK1OCJCWQsgMAABAR cbEkXkREsh2MbEcsl0RmBY4o/nkOfgdc32zMlev6XPp5TFUQObFK9yBJCaTsAAAARESSHAnrckW4 KxCkhPinKTMbGEROaok/SOKHlB0AAIAYhinIX1lcclJefqrbAn5crCvVTRCwwszlLOUjclJI/EES P6TsAAAARETb7v/f/+tP2yUFhblCa2zDehL/+OnkXHsZ24HISSHxB0n8kLIDAEDWY4ghJi9n8dGv vzd7WX7js79xlJvqNoHHpru+nOomRCQhJ3vVSq/J2eaCa4ocycZUNygbbbrry7SQ6kYkGVJ2AAAA IiJGwuTkrpRK/5N7gOMoC0bt0gFDDCNhGEbc12oydJubn1j6CXGEwEkBhugaxXRz3HSElB0AAICI IYZjGAnDcZz7v6luEHgwDMMwjKgTMoaIIWIzP2sUtUy/+hcpOwAAABF58i13bij2Yd1skxbPRqan jJBaSNkBAAB40iI7BIAsg6+EAAAAAACihpQdAAAAAEDUkLIDAAAAAIgaUnYAAAAAAFFDyg4AAAAA IGpI2QEAAAAARA0pOwAAAACAqCFlBwAAAAAQtbjuyWyz2RLYFAAAAACAzCCXywO23Lx5k2EYlmWj P8j2Ny+femKuoKAgway8bAAAIABJREFU3rufFtz1lTiPAGvgnLuCnufL2g7J2hNfH+jedOGcuxL8 0QgQmc1m23p8a6pbARlrav9UYg+IiTEAAAAAAKKGlB0AAAAAQNSQsgMAAAAAiBpSdgAAAAAAUUPK DgAAAAAgakjZAQAAAABEDSk7AAAAAICoxbsuOwAAAECWy5Vskhc1F+U/dGeuLNVtyVJmR32qm5Bc SNkBAAAA1m5j7pYndxjuLbrrjsKCgrzcVDcnG41P22kmw+eOIGUHAAAAWLvKsjeL7tjE5eVfdq6w iyupbk42Ylku1U1IOqTsAAAAAGvFUaFksyQv77rzdpQ1Fm0fLNrGF/568fb1T1nnQlJbJyqSgo25 d99bIN+56ZGa/C2JnEHEsmwCjyZOaZCyzzrsxdKSVLcCAAAAIAhHxDG3XBzHCQ/0ss6F62cNN0aG 1qFdIsQ6F5Yuzyxdnrkxcrqoqv6eZ/Yn6sjRdH66E3nKbje0qIdrB3RNqW5IRrEbWtSO/RZtpW/L iE7Vavb8f/1hU9tuIhrtamgPfE9Rdli0lUSOQa2m1+bbqjio1+8rTnqz45B2DU4M/tPq4XkGyW5o Ufdb+XvKm/v6GqWrFamDFyHuDqzrNr5WFfWjrz6EXDOgawr61h0hwMKehTc4RcSvk3lnGrmHiYjG emo6z3j/EVvfAoC4sCy7tOISLLZ8eebTQd3K9c/WoUnid2NkaP4dy71qbUHZjviPhlF2yDyeTEK5 umVEp2qd1gwYm0qIaPakpkXVddjUtruyzWhq8xUa66np/Ojg8+50anYmxuwt1dKuwYnjlwSPdjW0 a6TexDFwl6bGESJjJqIRnaa3tMOiC7ErHLuhRd1f1m3UVxGN6FRqLQVl7RECjP/QIYMz+oYklWNQ q+kt7bAYPc0e0anUDfbVSIvQw2M9NZ3UbTS5S9oNLeqGniwNUYAMwLEsJ5Qyss6Fzw0/D52vrzjn Fz2TanILNxW4UzN2eeHWkouIaEP+HRvzJAElVwsm61AhayW0AOtc+HRAV/zDnwY/eKwE+z8DJPPa WsegVlXT4P3TjQZtbxmcjVTYk1za+tQNPSNERDSi8xTQGEYHtaquscgPlKVGdJ7+cXeIt5eIZk9q GlTqfqpXKnjFR8+ZqX6vN50qbnpJSVMOh/8hR7s6z9Qf9o5Mj50fUj6WTrlF2jU4WSrVzYrJ4Qv2 ULva9Jpy83HeS9IjaMQ9NLuhRWM42eV5eY4ND1vLm19w93mVtqPedm446Mg8/gHG2x5FcKaM3dDd S5oBXs9UaTvq6cwvDCFb6NfDIxfO+PqHiEoa99fTmXNjoeoBwDrLdebusOwQ/NsyscVXhSWO5QT+ 5synli+HevtllxeeOjbhdeyphWWWiFacZS+f9mw7/bJimQ0s6S2YpEOFrJXgAkTurP3EjwV7T/iP Mn9iTPJSds/InNFkMZosh+vI3O7OHX3bB5qp942T9vCFSxr1A80KkmsGjK9VEdkNLa3TmgGjyWI0 veRo981zCPdA2Wyyv31mr8liNFn0mqnO1axdedhkMerVUn7ZyjYjf9jSMT0deDS74fiQXKP2lrE7 PiqfPu79jtQSnOSJTdo1OLlKS0JfGVL8qFJuNf/RL920G1qiydfdJvvPyfQmi9HU1+iasSmU3/TF WbFMbp35JGzFgADjEQ7O1HEMD1vLqx8N/unAb/YLH6+HpVLFZP+/jfhXFM2vBwDZLXcpt6mmafwP 4xH+zh4/m7eY56vCshwb0cL4O38bNYV+vF0/GOqqtZ94saKi4sWBmdqu069uJ1r59jHDAdn5IxUV FUfOyw70vLKNJdr+6umu2pmBFysqKo6cr+06/co2NmmHClkrsQW8Fj94d2H8ncgdGAWk7GtXpTWt ftLvfsy7vv3oOTPVP1pJRCWNeov3t/IwhflGB/qtvvG2quc15QIPlN2UHZ6P/+Kml5Q0dGHU/f/7 hHICu6G711b3kl/O4dfzRORwWCep1v3dyWJspTfEngSnXYOTZnSg31ouDTeLX1paSpMOXteM9QTM xhYgr612H3vWPhW0M/zoeGCAhRMqOFNodsZGW6UxNWa1h0sa9d3KM634GgmQGQTTyeXLM2Erjx/d U1Gx5+g4Eb0/OUMkK9tG9FxdLZHlrJGIjGctJPvWk9uJvlYqI5qxjvttTNKhQtZKbAGexQ/ejTtl z/yJMcmey+536Ri5P8sVyi3RFeYLqFj8qFLex38BRKqbffhpmVSqoGG7nSqjSInc84/9JtS6R0AH eLl+ldZkWf2XtLTU2vrb0X3RDcSmRNo1OJHM7TW8K1ADr4CMXJE6LIepprO969HoBoDDjd9HFBxg YYqFCM60VqU1WbRE7veuFlUvrkAFSF8cJ7BcjPPDS8JHWXGWlcmI7I4pYssC9slKv0bEMETEuVaI clZcnGfjfyblUEFj1okvwOecuPQl7kDofdHBijHx8OTQcvelY6NdDe2JKpzAuuDlGNRqesl7nR9v +/Cwtby6NUIqJpUqSCyzi6OSdg2OS6g1WMJwTE9TebX3y57cPUu7slt5prWzpzambLK4ZGvQtjAD 0sIBFj44U6tYJiezw0G7/c7LPusoKQ73pci/h72qtCaL1jGo1fzC8EKVWH5DAIBYsC6XyxVpxRjh xdfZ5YWnjhkOyGjkyNFx2qUKtWb5lMNOVPvEU/O/MTTW1Sb1ULvKBRZNj79AAF8HHnxY+h3F/QF7 T1mv9v4l0kc3G7H/M0PSJsaMnjMrDupNloBlIopLtlLwrNYwhSNVnJ2xRV03+/CnNzgcVqHhz9Gu Bo25ui9UH876T0p2F1bxrxZwOCLMtRCDtGtwisxeMPOfa2/MuC+pbI3tqu6AyeuzMzaFLPRva8EB FiBCcKaWtLo6+Fpex/AbmrBXwK/2cGBMhpiVBABphBO0FDllX3GWvXy6q5bsJ148ZCSicWvgRBqG IRo/uufICNV2TUxMdJXOzLg3rjjn3TyXkCbmUO+HrBV/gXAd6FzwddXP/mw/Zb3K33vKevVnf7YL 9nGkDs4IyVwxxveZ7RjUtg95JrNW1vqmVs+e1HiXgglTmK9S3awY6vQtHcNf0VmwbvbxXYM71tNq VgSvncfjGNS2T4WbLzF2fojKSv3y20p1s8LzDBK5vzJFTLlSLu0anBKjXS19k8r9oZardy91EtNV 3dLqav9Xq2+ae4AQAcYXMThTraSx9SD1qbUnfVn7iE7Ta6vrDv2zBr+H3e9mvCnssyd/4b3IBwDS D8sJXH4q+dI9EWp7RsXtJ150z0MnIomEPBNXaMXFEdntU0Ts8sLgS9t2faOiouIb/2Na5t64p9ez KMvQD3Yl8FAha8VfIAxJ0T387tJfmn5r8op711uTV/SXpoVnsmdByp60iTGVbYfrajpV7sS6/rCp +4Kq1TFLJK3S9h3UamoaPNurIhYu+WZteX+fZ6njRv0AtagbVEREyrp6OhP5gZJ1ZmlBWUedqhoi 4dsGzV4w22jSpqnp51fnzaaQlwR0ZUmjvluncj+DaXFborRr8DoJmuZuCbvUSVN78zl1p4qiXhO9 hP9q5d9Kaayn5kSJ3xrtQQG2WkYwOFNMuk9nKtWp1A19ng1y/9k74Xu4pFFvkfbUtKh6PTsVB/Um hCVAuhK8/DFHqnBdC/M72kr5y6e7amnmV//S8cd5Ivcy6UbzyOuPeSauPFFL9hO/Hyfa9YOhX+8t Ode27Z8MjXXejeOHKoxJOBQ1hKgVf4EwNtz3QEAHHnv3I/fAuf7SdISO9cmGy0+ZeH5KsNlsBXd9 JYGticFoV0N79AlEpnHOXQnf81EupJ1RInZIJsvaE18f6N504Zy7IpfLU90KSDM2m23r8eALb2jj jY3fL/p+e3ukC+M++eSTqn+umv7GNBERS5X3/3v+3ZsjlGevfXzr+I9C72v48cXX/S4WGjlScchI tPPlt369t4SIaHXMPNS25BwqmhLxF/AqfPYfchQPhd0dhaXrn41efS6pc0diNbV/Kvh96ebNmwzD xPQFY/ubl089MVdQEOp2VwAAAAAQLaG51My9W3IUD61Y3wuxz8gfmeYZP7qn4mgU25JzqGhKxF+A iIhyHty9YeuueCejY2IMAICHY1Cr8d3CjC+GtSMBADKPi2VdQuOmOXUvuK59zN38Yn2alC6Y/MKc mmcFe09Q/EcQv7RN2SvbjGHuI5b1/JchB0gU6T6daV+qGwEAIDocx3GCKWNufu7TB27/7pfczevr 0qh0kF+YU9dEufnCvSckG1aMSduUHQAAACAJ/vCHP1y8eDFCAZfLRfmr/2Q5LqoVSzZ/Nbe5beXs SfaDSAfPEswDW3Ofbqb8woQs9oIVYwAAAACyyELRwvDjwzFVEVwxhk+i/C5TtpO1/ZX72EbzWTbi nl9IeQXM5i2SHY8wZQ+yRJSgCS3ZsGIMUnYAAACAteNiSdmJiGQ7GNmO8HcWynwcUfyTYfwOiJQd AAAAACJgNjCsy8VIxLTEYJbBXHYAAAAAiGSFmctZyqe8fOGikBwu1pXqJiQdUnYAAACAtZucay9j OyQFhbkRb6gEyZMFg+xI2QEAAADWTEJO9qqVXpOzzQXXFDmSjaluUDbadNeXaSHVjUgypOwAAAAA cWDoNjc/sfQT4oiyYLhXdBiia0SZfj0vUnYAAACAODBEDBGb+VmjqGX61b9I2QEAAADilukpI6QW 4gsAAAAAQNSQsgMAAAAAiBpSdgAAAAAAUUPKDgAAAAAgakjZAQAAAABEDSk7AAAAAICoIWUHAAAA ABA1pOwAAAAAAKKGlB0AAAAAQNTivfupc+5KQtoBsULPB8jaDsnaE18f6N50YbPZUt0ESD9T+6dS 3QSAaMWbshfc9ZWEtANi4py7gp7ny9oOydoTXx/o3nThnLuy9fjWVLcC0szU/imEDSRPwr8QYmIM AAAAAICoIWUHAAAAABA1pOwAAAAAAKKGlB0AAAAAQNSQsgMAAAAAiBpSdgAAAAAAUUPKDgAAAAAg avGuyw4AAJAxciWb5EXNRfkP3ZkrS3VbMorZUZ/qJiQXIidJMj5yooeUHQAAgIhoY+6WJ3cY7i26 647CgoK83FQ3J3OMT9tpJpN/10fkJEnGR05MkLIDAAAQEVWWvVl0xyYuL/+yc4VdXEl1czIHy3Kp bkJyIXKSJOMjJyZI2QEAAIg4KpRsluTlXXfejrLGou2DRdv4wl8v3r7+KetcSGrr1oGkYGPu3fcW yHdueqQmf0siZ3ewLJvAo4kOIgeRsy6QsgMAABBxRBxzy8VxnPDAHutcuH7WcGNkaB3atW5Y58LS 5ZmlyzM3Rk4XVdXf88z+RB05mi5NY4gcRM66QMqeheyGFrVjv0Vb6dsyolO1mj3/X3/Y1LZ7jdtF LvoTzyT8cyS5ZkDXVBK83U3Z4e4cu6FF3W/l7ylv7utrlK4ekDp43egY1Gp6bXXdxteqom7V6kPw mhS+5bEdPBVGuxraKUNDKIuwLLu04hIstnx55tNB3cr1z9ahSalyY2Ro/h3LvWptQdmO+I+W8WOl iBwfRE7yIGXPNp5USbm6ZUSnap3WDBibSoho9qSmRdV12NS2O+btIhf9iWcQx6BW01vaYTF60usR nUrdYF9Nf5X8zHu0q6FdI/Wm5oG7NDUO/pZVIzpNb2mHRRdiVzh2Q4u6v6zbqK9yN0lLwVm73dDS avZk6nZDi7qhR/RZO6Q/jmU5oRSBdS58bvh5+KyLXV64teTKLdxUkMPfQES0If+OjXmhL6SLvVby C7DOhU8HdMU//GmYM42BYK+mO0ROwJkicpIhmVfhOga1qpoG759u1L11RKfSGEZ9u7rGPKXthhaN 4WRXg6qmQaUxONwlazz/HB3U+kqGPiz4hOthmj2paVCp+6leqeAVHz1npvq93oSpuOklJU05HLFv F7HYTjxz2A3dvaQZ4OXZVdqOejrzC0PI06xUNysmhy/YQ+1q02vKzccHZwN3BI24h2sJ/9U9Njxs LW9+ocrXJNu54cAjjw70W+sPe3L0ksbWg/JwzU4l3nuUX7fZDS3e96gWXqfhvSsVSv9UKvhXPF7s LswSx3ICf3PmU8uXQ71MiIhWnPNlL5+emJjQP+fb4t4wMTExcfplxXKoBGQNtdahAJE79zrxY8E+ Ef6jdJrekLeQF03YbLZv9lVB5ATIzshJtuSl7J6xN6PJYjRZDteRud2XO072t8/sNVmMJoteM9Wp 4m0/J9ObLEZTX6PUbmhpndYMGE0Wo+klR3uvTfiw4BOuh5WHTRajXi3ll61sM/KHlh3T02vbLmqx nHjGcAwPW8urH/Ufva5sM5p8U1xCKC0JOUeFih9Vyq3mP/olzXZDSzT5uhvv1e2asSmU3/S1oVgm t8584l961j5FCtkW37+lpaU06Qj6xpBS/u9RfUO87er+sm7Pe1RZb4sna8d7V2rsWNoxcmwk8t/d l+92F2ZZjo1oYfydv42awjzUinP+qWMThgP8q+9Wvn3McEB2/khFRcWR87IDPa9sC0xw1lRrHQp4 LX7w7sL4O5G7JQrplHjl3M753te+FzlmTrWfuvOLO31VEDnBsjByki15KXuV1rT6Wb77Mb+V8JUd nlSpuOklJQ1d8I42yWurPWMdowP9Vt8IaNXzmvJoDgs+IXu4uGmf0KwPu6G711b3UlBKF+t2cYnj xNPZ7IyNtkqjP6PRgX5rubQ4zN6gpHmsJ2C+uwDfq3vWPhW0M/D3jeKSrcTP40X4hcr/PUrb4X0v cgwPr/4+QLtf61Zae387SnjvSpUNGzZsEeIrLJg+LF+eCf9Qz+knumoDt9XVElnOGonIeNZCsm89 uT0RtdahAM/iB+/GnXil2fSGjRs3Ro6Z++67j18ekRNSFkZOUiV7eXrvD8ft/Iuj+WmBVKqgabvn pyLfCF/AGFvxo0q58GHBJ2wPR+QdHQycMRzr9rSTMScSM3P76jyNhvYp3jWmwhUvPBbbUHG48fvQ KmuVNNTZM+L+19i/+X5nE4vA3wGKZZ73qNkZG3974AsQ712ixglxfngpfG3JBvuJFyvUx3m5WdAQ oaz0awmotQ4F+JwTlwR7RlDYo2cERE5IiJzESt7lp57VHuTuy/tGuxraxXzYrOcY1Gp6yXst5tq3 p52MOZFgxTI5mR0O2u2XhdtnHSXF3i3KaKe1uMe5y72/gpHcPUW+slt5prWzpzambzvFJVuDtgX/ GlClNXWTqrXhjLudA80fqUU3lT02eO9KA6zL5XJFWvcj4hLaxkN7iGh7HW/TrnLBNarXUmsdCgTw dcvBh6XfUdwfsPeU9WrvXyK9QNmIvZoBEDnhIHISKGkp++g5s+KgXr8v1M/sk45ZIs8ntMNhpdL9 JUR+w8C+n8U91WdnbMKHBZ+QPRzeaFdD+1RznyVwhDXW7WknY04kJGl1taJ3+IK9kf9txDH8hqa3 NPpM3Wv2gtmmUL7q7SjvkHmVtqPe3N6qeyyWA3onr6++uv2GpX2qtCaL1tPsQa21fm+MbU6qsO9R AWfnewGODuC9S/wER/W4pdjuejNunSHyS3EYhmjFOb94myjsghyCtd5PUoEwOOeCr1t+9mc7EfFz r1PWq+6NEWT8WCkiJyRETmIlc2KMbyqqY1DbPsSfrur7MX2sp9WsOPh88CdxpbpZ4ftZfETH/xE5 /GHBR7iHfRyD2pAzImLdnnYy5kTCKmlsPUh9au1J3qwMTa+trjvWfJ1Gu1r6JpX7Q6Wb7sVkYrqS Ulpd7f/qXr2IxccxqPWsHEXepW/U4lp/M9x7lN/Z+b8A8d4leiwncBGh5Ev3xHZEiYSIONcKEa24 OCK7fYpoT69nvY2hH+xaW60kFQh3EkX38DtBf2n6rckr7l1vTV7RX5oWno+c6YkXIid0cxA5CZW0 UfbKtsN1NZ0q98dY/WFT9wVVq2/oV1lHnaoaIqKww04ljfoBalE3qNzl6+mM8GHBJ4oe9pi9YLbR pE1T08+v3mF53h7b9pizwFQLd+JpdyKRSPfpTKU6lbqhz7NBHvUUIHN7De9GS+URfosobmpvPqfu VEV/IyG/Vzf/VkpjPTUnSgZ0TSUk3afrmGnwPjvhb7eUQvyzKG/W1FNf8HbeCxDvXenAnSREKJAj VbiuxbJ0kdE88vpjtU88Nf8bQ+MTtWQ/8ftxovFDFcY4azUkpUAYG+57IKBbjr37kXv4U39pOppu iNyrGQCRExIiJ7GYeH50sNlsBXd9JcZKUS7k7A93FvTnnLsSvufX1MNpLmKHZLKsPfH1ge5NF865 K1uPB18jQUT0zMVn3n777cjVH655+L3H3yOWKu//9/y7N0coyV77+NbxH0U82M6X3/r13pKRIxWH jPwNRET2Ey/uORo6v4m91joU8Cp89h9yFA+F3R2FpeufjV59LukLXsRoav9UyLDZeGPj94u+394e 6XKTTz75pOqfq6a/MU1EiJxwMjVyojS1f0oulwdsvHnzJsMwMX0V2f7m5VNPzBUUFODupwAAAETk mZIcYT9z75YcxUMr1vfCFxk/uqfiaMQNiam1DgWIiCjnwd0btu6Kd0pxxk9vQOQEQeQkHFJ2AEgE x6BWE3IpxvKMvmAAMoqLZV1Co185dS+4rn3M3fxifZqUWkx+YU7Ns4J9Iij+I4gcIicAIicZ1j9l r9KaLDFXqmwzhrtrGARaUw8DxEm6T2fal+pGAMSF4zhOMEXIzc99+sDt3/2Su3l9XRqVOvmFOXVN lJsv3CdCMn7dD0SOH0ROcmCUHQAAMtaNGzc6OjqiLMxyXFQrVGz+am5z28rZk+wHF+NqnIgxD2zN fbqZ8gsTsmRH2q378ac//Sly2Cws+C3aiMjxyfLISSqk7AAAkLH+WPnHPy78UaCQ91Zggut+8EmU 32XKdrK2v3If22g+I8ZN8wspr4DZvEWy4xGm7EGWiBI0LSG91v1Y3LT4H1/7j/9Y+I/IxdidqyeF yEHkrAOk7AAAkLGWNy5HX5iLJfEiIpLtYGQ7wt9JJl1xRPFPafA7YFolXpyEiylsCJHjleWRk2xI 2QEAAIiImA0M63IxkvRcUk7EMn5GMiInSTI+cmKClB0AAICIaIWZy1nKp7z8VDck07hYV6qbkFyI nCTJ+MiJCVJ2AAAAIqLJufYytkNSUJgb8bY4EKuMHypF5CRJxkdOTJCyAwAAEEnIyV610mtytrng miJHsjHVDcocm+76Mi0IF0tXiJykyfDIiRFSdgAAACIiYug2Nz+x9BPiiDC8lygM0TWizLvWkg+R kwzZEDmxQMoOAABAREQMEUPEIktIgsy+MhORkzyZHTmxQMoOAADAgxQB1gaRA8mE+AIAAAAAEDWk 7AAAAAAAooaUHQAAAABA1JCyAwAAAACIGlJ2AAAAAABRQ8oOAAAAACBqSNkBAAAAAEQNKTsAAAAA gKghZQcAAAAAELV4737qnLuSkHZArNDzAbK2Q7L2xNcHujddTO2fSnUTIP0gbCCNxJuyF9z1lYS0 A2LinLuCnufL2g7J2hNfH+jedOGcu7L1+NZUtwLSzNT+KYQNJE/CvxBiYgwAAAAAgKghZQcAAAAA EDWk7AAAAAAAooaUHQAAAABA1JCyAwAAAACIGlJ2AAAAAABRQ8oOAAAAACBq8a7LDgAAkDFyJZvk Rc1F+Q/dmStLdVsyitlRn+omJBciJ0kyPnKih5QdAACAiGhj7pYndxjuLbrrjsKCgrzcVDcnc4xP 22kmk3/XR+QkScZHTkyQsgMAABARVZa9WXTHJi4v/7JzhV1cSXVzMgfLcqluQnIhcpIk4yMnJkjZ AQAAiDgqlGyW5OVdd96Ossai7YNF2/jCXy/evv4p61xIauvWgaRgY+7d9xbId256pCZ/SyJnd7As m8CjiQ4iB5GzLpCyAwAAEHFEHHPLxXGc8MAe61y4ftZwY2RoHdq1bljnwtLlmaXLMzdGThdV1d/z zP5EHTmaLk1jiBxEzrpAyp6F7IYWtWO/RVvp2zKiU7WaPf9ff9jUtpuIRrsa2gPfU5Qd/FpEjkGt xlzd19coTXKTEyO6E880/HMkuWZA11QSvN3N+/zaDS3qfit/T3nz6rM8olO1Ej8SHINaTa+trtv4 WlXUrVp9CF6TAo311HSeCW6AKI12NbRThoZQFmFZdmnFJVhs+fLMp4O6leufrUOTUuXGyND8O5Z7 1dqCsh3xHy3jx0oROT6InORByp5tPKmScnXLiE7VOq0ZMDaVENHsSU2LquuwqW13ZZvR1OYrNNZT 0/nRwecr/Q/V3Wuj8ur1anp8oj7xlLUwCRyDWk1vaYfF6HniRnQqdYN9Nbf2+w422tXQrpF6M+PA XZoaR8AXNvIeU9Nb2mHRhdgVjt3Qou4v6zbqq9xN0lKIrH2sp+ZEyYDRVOJtQJc0w54dEB+OZTmh FIF1Lnxu+Hn4rItdXri15Mot3FSQw99ARLQh/46NeaEvpIu9VvILsM6FTwd0xT/8aZgzjYFgr6Y7 RE7AmSJykiGZV+E6BrWqmgbvn27UvXVEp9IYRn27usY8pe2GFo3hZFeDqqZBpTE43CVrPP8cHdT6 SoY+LPiE62GaPalpUKn7qV6p4BUfPWem+r3ehKm46SUlTTkc/occ7eo8U39Yv6+Yt232ZMdwWb08 eeeROGs/8fRmN3T3kmaAl2dXaTvq6cwvDCFPs1LdrJgcvmAPtatNryk3Hx+cDdwRNOIeriX8V/fY 8LC1vPmFKl+TbOeGA4/sGDxxprz6UW8eX9lmFGO+znuP8us2u6HF+x7Vwus0vHelwj2OewT/7r58 t7swSxzLCfzNmU8tXw71MiEiWnHOl718emJiQv+cb4t7w8TExMTplxXLoRKQNdRahwJE7tzrxI8F +0T4j9JpekPOck40YXPnF3f6qiByAmRn5CRb8kbZ/cbexnpqOtu7HvV86E72t289bLLsDhzanOw/ p9SbLMVERHbaJ1fDAAAgAElEQVRDi28EdESnarVRvdBhwSdcDysPm/p2k93QMrSas1W2GU28qo7p aSL/CQh2w/EhuWbAr5Mdg2+cU77aSm+cmUreaSTO2k48zTmGh63l1a3+o9cBZx2ktKSEKMSHSvGj Snmf+Y+OfcWrfWQ3tESTr7vxXt2jXf0K5au+4xTL5NaZT4j4XwhpdsbGLyNGge9R5HmP4v+GQGM9 NS0tpNfvK8Z7V4p8Y/obhw4dilzmhz0/vP7V60TEslzkH+KdH17622i4l9CKc/6pYxNdtX7bvn3M cEB2/kiF1tigu/h6zyu//86bk5K4a61DAa/FD95dGH+nYPv/EaFbBKXXuh95i3nP0XPPPvtshDI3 btz4V8O//u3Lf3P/E5ETLAsjJ9mSN8pepTWtfpbvfsxvJXxlh+eDqrjpJSUNXfCONslrqz0f26MD /VbfCGjV85ryaA4LPiF7uLhpn1B+YDd099rqXvKbNOz3XPiKmatb/QbdxWyNJ57uZmdstFUa/RmN DvRby6XhnlRpaSlNOniD4WM9AfPdBfhe3bP24K95gb9vuMt8clLTEPRjkVj4v0dpO7zvRY7hYWv9 Ye/Uo92vdSutvb8dJbx3pUphYeG3hfgKs0KWL8+Ef6jn9AH5ExE9V1dLZDlrJCLjWQvJvvXk9kTU WocCPIsfvCvYM4LC95sYSaXSyDGjVCr55RE5IWVh5CRVspen9/5w7HchIz8tkEoVNG33jOqVlnjy wln7FClkW7yFih9V+k/ACHlY8AnbwxF5Rwf9LiJ0D7Gr+Snv7MmO4dr2DMpuQ554VjC3r87TaGif iv4ST3N7zYXHLIfryNwebTLte3VHy9p7gtqNJovRZDF2UKfIsvaA9ygqlnneo2ZnbPztgS9AvHeJ GifE+eGl8LUlG+wnXqxQH+flZkFDhLLSryWg1joU4HNOXBLsGUFhj54REDkhIXISK5kTY1StZiK5 +4fj0a6GdjEfNus5BrWaXvJei8nbHjS5wj0lRh9j+iVa4U48AxTL5GR2OGi3XxZun3WU+Ca3BC4B FIFjeprKvb+Ckdw9Rb6yW3mmtbOnNqZvO8UlW4O2hfo1QHHwVd+TUqluVqgvjLbtjuEiV7HBe1ca YF0ulyvSuh8Rl9A2HtpDRNvreJt2lQuuUb2WWutQIICvWw4+LP2O4v6AvaesV3v/EulKIDZir2YA RE44iJwEStoo++g5s+Kg3mQJtXwb/+d1h8MaYvituGQrWWc+8f17dsYmfFjwEe5hP6NdDRpzdV+o Xp2dsSmU3+SlU7MXzDZrb4t7pFDTa6PJfk3aXkgX4cQzgLS6OvhyUsfwG2t6vmYvmPmR4I0o9/Ws rbEd0Dt53XvogGFpotBpvbiEfY8KODvfCxDvXelAeMRvKba73oxbA6dDMAzRinPebSH0pXuCtd5P UoEwOOeCrwN+9mf7KetV/t5T1qs/+7M9y8dKETkhIXISK5kTY3yfW45BbfsQf7qq78f0sZ5WsyJg 6UAicg+qDXX2jBAR0YiO/yNy+MOCj3AP+zgGteFnRIydH6KyUv705uKmPs9cBZPF2HdQTuXNfVGP 1IpKxBPPCCWNrQepT609yZuVoem11XXH/HyNdrX0TSr3h7p6wb2YTNTTY4jc3yX8Xt2rF7GsHlbd TO4p4O4GDPRb6x8VVZiFe4/yOzv/FyDeu0SP5bjI02olX7ontiNKJETEuVaIaMXFEdntU0R7ej3r bQz9YNfaaiWpQLiTKLqH3wn6S9NvTV5x73pr8or+0rTwfORMT7wQOaGbg8hJqKRNjKlsO1xX06ly f4zVHzZ1X1C1OmY9S3Io66hTVUNEpDio14e8irGkUT9ALeoGlbt8PZ0RPiz4RNHDHrMXzDaatGlq +vnVefMl5CWZ2bmCJ54JpPt0plKdSt3Q59kgj3oKkLm9hnejpfLmPku47zbFTe3N59SdquhvJOT3 6ubfSsm9FruuqcRdxtBS4509IsIbXfHPorxZU099wdt5L0C8d6UDd5IQoUCOVOG6FrTYaQRG88jr j9U+8dT8bwyNT9SS/cTvx4nGD1UY46zVkJQCYWy474GAbjn27kfu4U/9pelouiFyr2YARE5IiJzE YuL50cFmsxXc9ZUYK0W5kLM/3FnQn3PuSvieX1MPp7mIHZLJsvbE1we6N104565sPR56MtUzF595 ++23I1d/uObh9x5/j1iqvP/f8+/eHKEke+3jW8d/FPFgO19+69d7S0aOVBwy8jcQEdlPvLjnaOj8 JvZa61DAq/DZf8hRPBR2dxSWrn82evW5pC94EaOp/VMhw2bjjY3fL/p+e3uky00++eSTqn+umv7G NBEhcsLJ1MiJ0tT+Kbk88O41N2/eZBgmpq8i29+8fOqJuYKCAtz9FAAAgIg8U5Ij7Gfu3ZKjeGjF +l74IuNH91QcjbghMbXWoQAREeU8uHvD1l3xTinO+OkNiJwgiJyEQ8oOAIngGNRqem0hdpRn9AUD kFFcLOsSGv3KqXvBde1j7uYX69Ok1GLyC3NqnhXsE0HxH0HkEDkBEDnJsP4pe5XWZIm5ktAtG4Fn TT0MECfpPp1pX6obARAXjuM4wRQhNz/36QO3f/dL7ub1dWlU6uQX5tQ1UW6+cJ8Iyfh1PxA5fhA5 yYFRdgAAyFiLi4uCc9l9WI6LaoWKzV/NbW5bOXuS/eBiXI0TMeaBrblPN1N+YUKW7Ei7dT8cDkfk sLlx4wb/n4gcnyyPnKRCyg4AABlr5O9GRoZHIpfhKj1pgeC6H3wS5XeZsp2s7a/cxzaaz4hx0/xC yitgNm+R7HiEKXuQJaIETUtIr3U/nHc6B3MGB4cHIxdz7Vi9yw8iB5GzDpCyAwBAxnLe4Yy+MBdL 4kVEJNvByHaEv5NMuuKI4p/S4HfAtEq82A1sTGFDiByvLI+cZEPKDgAAQETEbGBYl4uRpOeSciKW 8TOSETlJkvGRExOk7AAAAEREK8xczlI+5eWnuiGZxsW6hAulM0ROkmR85MQEKTsAAAAR0eRcexnb ISkozI14WxyIVcYPlSJykiTjIycmSNkBAACIJORkr1rpNTnbXHBNkSPZmOoGZY5Nd32ZFlLdiORB 5CRNhkdOjJCyAwAAEBERQ7e5+YmlnxBHhOG9RGGIrhFl3rWWfIicZMiGyIkFUnYAAAAiImKIGCIW WUISZPaVmYic5MnsyIkFUnYAAAAepAiwNogcSCbEFwAAAACAqCFlBwAAAAAQNaTsAAAAAACihpQd AAAAAEDUkLIDAAAAAIgaUnYAAAAAAFFDyg4AAAAAIGpI2QEAAAAARA0pOwAAAACAqMV791Pn3JWE tANihZ4PkLUdkrUnvj7Qveliav9UqpsA6QdhA2kk3pS94K6vJKQdEBPn3BX0PF/WdkjWnvj6QPem C+fcla3Ht6a6FZBmpvZPIWwgeRL+hRATYwAAAAAARA0pOwAAAACAqCFlBwAAAAAQNaTsAAAAAACi hpQdAAAAAEDUkLIDAAAAAIgaUnYAAAAAAFGLd112AACAjJEr2SQvai7Kf+jOXFmq25JRzI76VDch uRA5SZLxkRM9pOwAAABERBtztzy5w3Bv0V13FBYU5OWmujmZY3zaTjOZ/Ls+IidJMj5yYoKUHQAA gIiosuzNojs2cXn5l50r7OJKqpuTOViWS3UTkguRkyQZHzkxQcoOAABAxFGhZLMkL++683aUNRZt Hyzaxhf+evH29U9Z50JSW7cOJAUbc+++t0C+c9MjNflbEjm7g2XZBB5NdBA5iJx1gZQdAACAiCPi mFsujuOEB/ZY58L1s4YbI0Pr0K51wzoXli7PLF2euTFyuqiq/p5n9ifqyNF0aRpD5CBy1gVS9ixk N7SoHfst2krflhGdqtXs+f/6w6a23UQ02tXQHvieouzg1yJyDGo15uq+vkZpkpucGMEnbje0qPut RERU1218rSpVLUsm/pNLcs2ArqkkeLub9/nldYtHefPqszyiU7USPxIcg1pNry22Dlx9CF6TAo31 1HSeCW6AKI12NbST57UDaYtl2aUVl2Cx5csznw7qVq5/tg5NSpUbI0Pz71juVWsLynbEf7SMHytF 5PggcpIHKXu28aRKytUtIzpV67RmwNhUQkSzJzUtqq7DprbdlW1GU5uv0FhPTedHB5+v9D9Ud6+N yqvXq+nxCT5xGutR95d1G/VV7r3ak2Fzx3TlGNRqeks7LEbPEzeiU6kb7Ku5td93sNGuhnaN1JsZ B+7S1DgCvrCR95ia3tIOiy7ErnDshhZfz4/oVGothej5sZ6aEyUDRlOJtwFdUiTEkGQcy3JCKQLr XPjc8PPwWRe7vHBryZVbuKkgh7+BiGhD/h0b80JfSBd7reQXYJ0Lnw7oin/40zBnGgPBXk13iJyA M0XkJEMyU3b32Jv3X94MYESn+oW0Qznc7t7lHdMlu6Glg2q39vcNeUfUfKOA5c0dyuH2mb3ukqEP Cz7hephmT2pa+iZJUa9U8IbPR8+Zqf6wN2EqbnpJ2fcLh4N280c0R7s6z9QfNu0r5m2bPdkxXFYv t04l+XQSIPSJOwZPnClv7nMnryXfrC3vPzc82+R3jmnObujuJc0A7wVSpe2oN7f/wvBCVYgR60p1 s0I9fMHe2BS8q02vmWo5Pvh8ZUD/BI24h2sJ/9XdqRy2lje3Vvma1HA8qOcdgyfOlFf3efP4yjaj KZpTXme89yjNVt523s8UioN6vffU8N6VCrv/Y/d9990XuczMjZn3Hn+PiFjiWKEf4ufMp5Yv28Ps XHHOb33VZDggs/w/FS//T/eWspdPGw7IiIhmfvW9b/93W3CGs4Za61CAyJ17nfjxPf/n/x25TwSx lE7TGzbe2PjIxUeKiooiF1tcXBz5uxHnHU5C5ASdT3ZGTrIlb+Ecz9ib0WQxmiyH68jc3jXm2TXZ 3z6z12Qxmix6zVSnirf9nExvshhNfY1Su6GldVozYDRZjKaXHO2+z7kIhwWfcD2sPGyyGPVqv2yt ss3IH7x0TE8HHs1uOD4k16j9Bjgdg2+cU776QrqsPhvqxKX7dCbfXAv7H89NymurMyhfJ3IMD1vL qx/1H72ubDOaIs0wKS0J/TtD8aNKudX8Rwd/m93QEk2+7sZ7dbtmbArlN31tKJbJrTOfBBSf9S8j Rv7vUX1DvO3q/rJuz3tUWW9Ly+AsEd67UuW+++57W4ivMMtybEQL4+/8bTTc18cV5/xTxyY8uYx3 27ePGQ7Izh+pqKg4cl52oOeVbYGDhmuqtQ4FvBY/eHdh/J3I3RKFNEu8Hn/8ccGwOXTokK88IidY dkZOUiUvZa/SmlY/y3c/5rcSvrLDkyMWN72kpKELo57tqznT6EC/tX6vZ+i36nlNeTSHBZ+QPVzc tE9oXoHd0N1rq3vJL6Xzey58xczVrWkzIB3xxO2GlpoGlbqfDr6aYbNiZmdstFUafdY7OtBvLZeG e1KlpaU06Zhd3TDWEzDfXYDv1T1rD/5lZsrh92XAU+aTk5oGVU2DqqZBJb7s1v89StvhfS9yDA9b 6w97px7tfq1bae397SjhvSstCKYPy5dnwtd+Tj/RVRu4ra6WyHLWSETGsxaSfevJ7YmotQ4FeBY/ eDfuxCvDpzcgckJC5CRWspenH9G5P3H9LmTkpwVSqYKm7Z6finwjfLP2KVLItngLFT+qlAsfFnzC 9nBE3tFBv4sIQwyxz57sGK5tF/W1gDEoadRbjCaLcf9MiwjzwiQzt9d4c+Kahvap6C/xNLfXXHgs tqHicOP3YVl7T1C7e0za2EGdInt2At6jqFjmeY+anbHxtwe+APHeJWqcEOeHl8LXlmywn3ixQn2c l5sFDRHKSr+WgFrrUIDPOXFJsGcEhT16RkDkhITISazkzWX3zPKUu69rHO1qaBfzYbOeY1Cr6SXv Rai87cPD1vLq1hJ+yTfOKV/VZ9aANHlmcl8YbdudMdOLi2VyMgdelkD2WUdJsXdLDNOpHdPTVO6b OSR3T5Gv7Faeae3sqY1psZ3ikq1B20L9GqDg/e6RCc8O3rvSAOtyuVyR1v2IuIS28dAeItpex9u0 q1xw9uBaaq1DgQC+bjn4sPQ7ivsD9p6yXu39iyOo0io2Yq9mAEROOIicBEraKPvoObPioN5kCbUE B//ndYfDGmL4rbhkK/Gnt87O2IQPCz7CPexntKtBY67uC9WrQVOKZy+YbdbeFvdIoabXRpP9mhrd aGC9NDDa5T/dwuGIZZpHGpBWVysmhy/4/8DiGH5jTc/X7AUzPxK8EVWl7ainM62xHTBg8nrgsDRR 6LReXMK+RwVOzfe+APHelQ6ER/yWYrvrzbg1cDoEwxCtOOfdFpZD/uovWOv9JBUIg3Mu+DrgZ3+2 n7Je5e89Zb36sz/bs3ysFJETEiInsZI5Mcb3ueUY1LYP8aer+n5MH+tpNSsClg4kIveg2lBnzwgR EY3o+D8ihz8s+Aj3sI9jUBt+RsTY+SEqK+VPby5u6vPMVTBZjH0H5VTe3JeeC19UqpsVq9dRuDOq SB2VfkoaWw9Sn1p7kjcrQ9Nrq+uO+fka7Wrpm1TuD3X1QmWbXlMe25WU0upq/1d3iAt/K9XN5J4C 7m7AQL+1/lFRPTvh3qP8zs7/BYj3LtFjOYGLCCVfuie2I0okRMS5VohoxcUR2e1TRHt6J9yGfrBr bbWSVCDcSRTdw+8E/aXptyavuHe9NXlFf2laeD5ypideiJzQzUHkJFTSJsZUth2uq+lUuT/G6g+b ui+oWh2zRO4ln+uoU1VD5L8Cmp+SRv0AtagbVO7y9XRG+LDgE0UPe8xeMNto0qap6edX582XkJdk aueWNOoHDC01nvkJQh2VlqT7dKZSnUrd0OfZIA+e+xSGub2Gd6Ol8uY+S7hp7sVN7c3n1J2q6G8k 5Pfq5t9Kyb0Wu66pJPDZ4a1VKhr8syhv1tRTX/B2XlzhvSsduJOECAVypArXtdkIBQIZzSOvP1b7 xFPzvzE0PlFL9hO/HycaP1RhjLNWQ1IKhLHhvgcCuuXYux+5hz/1l6aj6YbIvZoBEDkhIXISi4nn RwebzVZw11dirBTlQs7+cGdBf865K+F7fk09nOYidkgmy9oTXx/o3nThnLuy9XjoyVTPXHyGv4xj SA/XPPze4+8RS5X3/3v+3ZsjlGSvfXzr+I8iHmzny2/9em/JyJGKQ0b+BiIi+4kX9xwNnd/EXmsd CngVPvsPOYqHwu6OwtL1z0avPpf0BS9iNLV/KmTYbLyx8ftF329vF7jc5O233/7e8PecdzgROeFk auREaWr/lFwuD9h48+ZNhmFi+iqy/c3Lp56YKygowN1PAQAAiMgzJTnCfubeLTmKh1as74UvMn50 T8XRiBsSU2sdChARUc6Duzds3RXvlOKMn96AyAmCyEk4pOwAkAj+t/bkKY9+7UiA1HKxrEto9Cun 7gXXtY+5m1+sT5NSi8kvzKl5VrBPBMV/BJFD5ARA5CTD+qfsVVqTJeZKIr1duTitqYcB4iTdpzPt S3UjAOLCcRwnmCLk5uc+feD2737J3by+Lo1KnfzCnLomys0X7hMhGb/uByLHDyInOTDKDgAAGWvm xszDNQ9HLrNcsOz+H5bjolqhYvNXc5vbVs6eZD+4GH8LxYl5YGvu082UX5iQJTvSbt2PhYWFTz75 JHKZGzdu+P4fkeOT5ZGTVEjZAQAgY733eITZw4EE1/3gkyi/y5TtZG1/5T620XxGjJvmF1JeAbN5 i2THI0zZgywRJWhaQnqt+7G0canvSl/f632CJZe/6v2yh8hB5CQfUnYAAAAiIi6WxIuISLaDke0I fyeZdMURxT+lwe+AaZV4uXJdn0s/j6kKIsctyyMn2ZCyAwAAEBExGxjW5WIk6bmknIhl/IxkRE6S ZHzkxAQpOwAAABHRCjOXs5RPefmpbsj/3979x7Rx330A/9hgMLR5Qtek65Py05iu6drmkRZloxQy sWLRrqVdsz1UiRld/UiRmNRafdrpgSd6PKoIpCdVxbqVjUmsYoFImeZmcrWVOZmlmBKrqG2Wp8/o gzAe2G5D0j0LSZ4Sk+C75w//4M72+Wzw2efz+yX+SM7fu3zvex9fPnzv+/2e0gSZYK6rIC1EjkQU HzlpQcoOAABARDS/Yqlj+tXaMk3S1+JAuhTfVYrIkYjiIyctSNkBAACI1BRgLrnpFR3Trb2sL1aX 57pCyrGt4ku0mutKSAeRIxmFR06akLIDAAAQEZGKbrHX59Z+RiwRuvcyRUV0mUh5cy25EDlSKITI SQdSdgAAACIiUhGpiBhkCRJQ9sxMRI50lB056UDKDgAAwIEUATYHkQNSQnwBAAAAAMgaUnYAAAAA AFlDyg4AAAAAIGtI2QEAAAAAZA0pOwAAAACArCFlBwAAAACQNaTsAAAAAACyhpQdAAAAAEDWkLID AAAAAMjaVt9+GlhZzkg9IF1o+RgF2yAFe+LZgebNFwtdC7muAuQfhA3kka2m7NqKuzNSD0hLYGUZ Lc9VsA1SsCeeHWjefBFYWa4/Xp/rWkCeWehaQNiAdDL+CyEGxgAAAAAAyBpSdgAAAAAAWUPKDgAA AAAga0jZAQAAAABkDSk7AAAAAICsIWUHAAAAAJA1pOwAAAAAALK21XXZAQAAFEOj3qbb3r299MHb NTW5rouiOHztua6CtBA5ElF85KQOKTsAAAARUblm12O7rTu3V9xWptWWaHJdHeWYXfTSkpKf6yNy JKL4yEkLUnYAAAAiosa6n26/bRtbUnoxsM7cWM91dZSDYdhcV0FaiByJKD5y0oKUHQAAgIilMvUO dUnJlcCtFPe44fnkhmd29S8f3LryORNYlbR2WaDWlmvu2KnV3b/tay2luzI5uoNhmAweTXYQOYic rEDKDgAAQMQSsaovgizLinfsMYHVK2esV6cns1CvrGECq2sXl9YuLl2dfnd7U/udT3Rl6sipNGke Q+QgcrICKXsB8lp7jL4up7kxumV6yNDrCP+5/Yi9bx8RuQY6LLH3lNZ+7l5EvgmzydE8OnqgSuIq b1WiE9wQ3yBKwj130pnGhzqr47eHRK6v19pjHHNzP2no3rjK00OGXuJGgm/CbBrxtA3aXmlKuVYb /wSnShyphB//aDm+gq6BDgvFhRbkGYZh1taDosVuXlz6fGJo/crfslClXLk6PXn9Q+dOo1lbt3vr R1N8XykiJwqRIx2k7IUmnCq1bmyZHjL0LprGbZ3VROQ/aeoxDByx9+1r7LPZ+6KFZo61HP3r4e82 8g81OOKhhuZsVX2zBE4w/Gl8gyiIb8JsGqntd9rCF256yGDs8G7k1rwk2DXQYTFVRVLz2I9MLb7E GfP0kGmktt85lEa67LX2GMfqBm3DTaEqmSkuaxcPP/7RlHoFIbtYhmHFUgQmsPq/1l8KZ13MzdUv 1oKasm3aYu4GIqKi0tvKSxJPpEt/L+kLMIHVz8eHKv/95wJnmgbRVs13iJyYM0XkSEHKWbi+CbOh pSPyM+QKbZ0eMpisruhHAzPh0l5rj8l6cqDD0NJhMFl9oZIt4b+6JszRkokPC1FCLUz+k6YOg3GM 2lv1nOKusw5qPxhJmCo7n2+lBZ+Pf0jXwNHT7UeGD1VytvlP9k/VteukO49MET7BxA2iHF7r4AiZ xjl5dpO5v51O/8rqS1S80ditn5865030Ud+wqcFxfMIf+0Fcj7tQTbjf7pmpKXdD97NN0Sp5zk7F HZkjUfiF5PoKcu5RvGbzWnsi96geTqPh3pULu527RX/0M+EAYohlWJGfFcepmxcTfU2IiNYD1+te endubm746eiW0Ia5ubm5d1/S30yUgGxirywUIArlXid+Itom4j+UT8MbNAFNKmGza25XdBdETozC jBypSZeyh/vebHanze480kYOSzR3nB+zLB20O21257Bp4aiBs/1szbDdabOPHqjyWnt6F03jNrvT Zn/eZxnxiB8WooRauPWI3WkbNvKGsTT22bhP832Li7FH81qPT+pMRt4Tf9/Ea2dbX342H1afTXaC iRpEMXxTU+6G5ofje6+TDWSqrY4bo0JERJUPt+rcjvd5ub7X2pNKvh7C+XYHlzz61q9H61BZo3Mv fSa4Y6Lw25DDK8i/R41OcrYbx+oGw/eoupGecNaOe1du1JfXz/5pNvlP2fWyUGGGYZmkVmc//D+X XeCfWg9cf/zNOetz3Pvi+pNvWp+ree/VvXv3vvpezXPH/vUrsQnOpvbKQoGIG598tDr7YfJmSUE+ JV6aNU1nS2fymDlz/EzJjZLoLoiceAUYOVKTLmVvMts3/i/f9whvJfzW/nAKVdn5fCtNnov0Nun2 N4c70lzjY+5oz2jTd00NqRwWohK2cGXnIbGBtl7r4Iin7XleSse7FtFijubeBL2essc7wRQaJJ/5 lzxUX5V6MusaH3M3VAld1KraWpr3cTrDZ47FjHcXEf12+70LcR/GPdjh1Som/Dbk8gry71Hm/si9 yDc15W4/Ehl6tO+VwVb3yG9dhHtXXhBNH25eXBLe++nhuYH9sdva9hM5z9iIyHbGSTXffOy+TOyV hQIcNz75aMuJl8KHNyByEkLkZJbUy9NHHhzzZpJx04KqKj0tesOPiqI9fH7vAulros+cKh9u5Q/A SHhYiBJs4aQivYO8SYQJ+jj9J/un9ltkP+U0XsITLGgOy8Y4jQ7LQnfKM4kdlpZzj6TXVSzUf59U 8i72XIq5R1FlTfge5V/ycLfHfgFx75I1Vkzgf84L760u8p74/l7jcU5uFtdFWFN7bwb2ykIBrsDc edGWESV4dEVA5CSEyMks6aafhtej0IWm/bkGOixyPmzB802YTSMUmaPJ2T415W5o7q3mlnztbOvL w5tIv3JK6AQVrLJGRw6fj/bxsnCv31ddGdkivAZLHN/iIjVEnoKRLjREvnGw9XTv0WP70/otqLK6 Pm6bwKmFaugAABYiSURBVNOA+PDLY7h35QEmGAwGk637kXQJbduLzxDRfW2cTQ80iI4e3MxeWSgQ I9oshx+q+o7+yzGfnnJfGvkvoSdlRERM0lZVAESOEEROBknWy+4669AfHrY7Eyzfxnu87vO5E3S/ VVbXE3d4q3/JI35YiBJvYR7XQIfJ0TyaqFX9/GHHRP5zDo97pCfUU2ga8dD8mEn2E+mSnKCCVTU3 x08n9U29tqnr5T/n4EZCJKJC81l70ztgzOD12G5p7r8aG37yIXiPih2aH/kC4t6VD8R7/NbSe+vN rDt2OIRKRbQeuB6ymnjqnuhe/y1RAQFsYDXaAL+44D3lvsT99JT70i8ueAu8rxSRkxAiJ7OkHBgT /X/LN2G2THKHq0Yfps8c63XoE63d1mjs1k8ePTZNRETTQ9yHyMKHhSjxFo7yTZiFR0TMvDdJdbXc 4c2VnaOh+XM2u9M2elhHDd2j8l7RPOkJKlr1gd7DNGo0n+SMyjCNeNoG075eroGe0fnWrkSzF0KL yaQ1k7KquZn/7d6YxMIXH34yInSP4p0d/wuIe5fsMazIJEL1P9yZ3hHVaiJig+tEtB5kibzeBaJn RsLrbUz+2wOb20uiAkInsf1ObiMMn198e3459NHb88vD5xfFxyMrPfFC5CSuDiInoyQbGNPYd6St 5agh9N9Y+xH74DlDr89PFFryuY2OGlqIiPSHhxOt3UZUfWB4nHqMHYZQ+XY6LX5YiEqhhcP85xwe mveYWsa4u3PGS+iq87txRU9QyaoODdlrhwzGjtHwBl3KQ4MclhbOi5YaukedQr/zVHZaus8ajxpS f5EQ79vNfZXSzLGWE9W8Ndrjwy++TI5wz6Kh29ROo/HbOV9A3LvyQShJSFKguEofvJxsSdJYNsf0 fzyy/9HHr//GeuDR/eQ98cdZotkX99q2uFeHJAUEFN11T0yzvPnRX0Pdn8PnF1NphuStqgCInIQQ OZml2spDB4/Ho624O82dUlzImQ9vFuQLrCwLt/ymWjjPJW0QJSvYE88ONG++CKws1x+PnyNBRPTE B0+88847yXd/qOWhj7/1MTHU+OXfld6xI0lJ5vKnXxz/z6QHu/+lt399sHr61b0v2rgbiIi8J77/ zOuJ85v098pCgYiyp/6lWP+g4McpWLvyN9elpyVf8CJNC10LCcOm/Gr5j7b/yGJJNt3ks88+a/ph 0+I/LRIRIkeIUiMnRQtdCzpd7Ntrrl27plKp0vpV5L6fXjz16IpWq8XbTwEAAIgoPCQ5yeeqnbuK 9Q+uuz8WLjL7+jN7X0+6ITN7ZaEAEREVf3VfUf0DWx1SrPjhDYicOIicjEPKDgCZ4Jswm6KvPONq KMiJBJCXggwTFOv9Km57Nnj5U/ba37NTpdxSlZYVtzwl2iaitn4EmUPkxEDkSCH7KXuT2e5Me6fG PpvQW8Mg1qZaGGCLqg4N2Q/luhIAW8KyLCuaImhKNd9+7tbv32KvXclKpXKntKy4rZM0peJtIkbx 634gcngQOdJALzsAACjW5cuXn3zyyRQLMyyb0goVO/5R0923fuYk88kHW6qcjKnuqdd8u5tKyzKy ZEferfvxpz/96YMPkl3cYDBIpRt/ReREFXjkSAopOwAAKNbM42ksQCq67geXuvV7qrr7Gc9f2E89 dF0R/aalZVSiVe3Ypd79NVXdVxkiytCwhPxa92N1++rUt6bS2gWRg8jJAqTsAAAARERsOokXEVHN blXNbuE3yeQrlmjrQxp4B1R64oXICUHkSAopOwAAABGRqkjFBIMqdX4uKSdjih+RjMiRiOIjJy1I 2QEAAIiI1lUrxWulVFIqXhTSEWSCua6CtBA5ElF85KQFKTsAAAAR0fyKpY7pV2vLNElfiwPpUnxX KSJHIoqPnLQgZQcAACBSU4C55KZXdEy39rK+WF2e6wopx7aKL9FqrishHUSOZBQeOWlCyg4AAEBE RCq6xV6fW/sZsUTo3ssUFdFlIuXNteRC5EihECInHUjZAQAAiIhIRaQiYpAlSEDZMzMROdJRduSk Ayk7AAAAB1IE2BxEDkgJ8QUAAAAAIGtI2QEAAAAAZA0pOwAAAACArCFlBwAAAACQNaTsAAAAAACy hpQdAAAAAEDWkLIDAAAAAMgaUnYAAAAAAFlDyg4AAAAAIGtbfftpYGU5I/WAdKHlYxRsgxTsiWcH mjdfLHQt5LoKkH8QNpBHtpqyayvuzkg9IC2BlWW0PFfBNkjBnnh2oHnzRWBluf54fa5rAXlmoWsB YQPSyfgvhBgYAwAAAAAga0jZAQAAAABkDSk7AAAAAICsIWUHAAAAAJA1pOwAAAAAALKGlB0AAAAA QNaQsgMAAAAAyNpW12UHAABQDI16m2579/bSB2/X1OS6Lori8LXnugrSQuRIRPGRkzqk7AAAAERE 5Zpdj+227txecVuZVluiyXV1lGN20UtLSn6uj8iRiOIjJy1I2QEAAIiIGut+uv22bWxJ6cXAOnNj PdfVUQ6GYXNdBWkhciSi+MhJC1J2AAAAIpbK1DvUJSVXArdS3OOG55MbntnVv3xw68rnTGBV0tpl gVpbrrljp1Z3/7avtZTuyuToDoZhMng02UHkIHKyAik7AAAAEUvEqr4Isiwr3rHHBFavnLFenZ7M Qr2yhgmsrl1cWru4dHX63e1N7Xc+0ZWpI6fSpHkMkYPIyQqk7AXIa+0x+rqc5sbolukhQ68j/Of2 I/a+fUTkGuiwxN5TWvu5exH5JswmR/Po6IEqiau8VV5rj3HMTUREbYO2V5riP+U3iJJwLy7pTOND ndXx20Mi15fTXGEN3RtXeXrI0EvcSPBNmE0jngQNm8TGP8GpEkcq4cc/Wo6voGugw0Lh7w7kLYZh 1taDosVuXlz6fGJo/crfslClXLk6PXn9Q+dOo1lbt3vrR1N8XykiJwqRIx2k7IUmnCq1bmyZHjL0 LprGbZ3VROQ/aeoxDByx9+1r7LPZ+6KFZo61HP3r4e828g81OOKhhuZsVX3TZo4Zx+oGbcNNodM3 n+TmiPENoiC+CbNppLbfaQtfuOkhg7HDu5Fb85Jg10CHxVQVSc1jPzK1+BJnzNNDppHafudQGumy 19oTvSLTQwajmeKydvHw4x9NqVcQsotlGFYsRWACq/9r/aVw1sXcXP1iLagp26Yt5m4gIioqva28 JPFEuvT3kr4AE1j9fHyo8t9/LnCmaRBt1XyHyIk5U0SOFKScheubMBtaOiI/Q67Q1ukhg8nqin40 MBMu7bX2mKwnBzoMLR0Gk9UXKtkS/qtrwhwtmfiwECXUwuQ/aeowGMeovVXPKe4666D2g5GEqbLz +VZa8Pn4h3QNHD3dfmT4UCVnm/9k/1Rdu06688gU38SJ0w3dz4aS1Oqv72/wnJ3yE5FQgyiH1zo4 QqZxTp7dZO5vp9O/svoSFW80duvnp855E33UN2xqcByf8Md+ENfjLlQT7rd7ZmrKHb0iTeb+9ugV SSxR+IXk+gpy7lG8ZvNaeyL3qB5Oo+HelQu1f64V/amcDQcXQyzDivysOE7dvJjoa0JEtB64XvfS u3Nzc8NPR7eENszNzc29+5L+ZqIEZBN7ZaEAUSj3OvET0TYR/6F8Gt5QslqSStjs8O6I7oLIiVGY kSM16VL2cN+bze602Z1H2shhieaO82OWpYN2p83uHDYtHDVwtp+tGbY7bfbRA1Vea0/vomncZnfa 7M/7LCMe8cNClFALtx6xO23DRt4wlsY+G/dpvm9xMfZoXuvxSZ3JyHvi75t47Wzry8/mw+qzVYeG 7NFBHd73z87r9jdHkr9EDaIYvqkpd0Pzw/G918kGMtVWx41RISKiyodbdW7H+7xc32vtSSVfD+F8 u4NLHn3r16N1qKzRuZc+E9wxUfhtyOEV5N+jRic5241jdYPhe1TdSE84a8e9Kzd2r+2efnM6+c8d F+8IFWYYlklqdfbD/3PZBf6p9cD1x9+csz7HvS+uP/mm9bma917du3fvq+/VPHfsX78Sm+Bsaq8s FIi48clHq7MfJm+WFORT4lV8q/if7/3n5DFzynLq9r/fHt0FkROvACNHatKl7E1m+8b/5fse4a2E 39ofzhErO59vpclzkd6mjVzKNT7mjnb9Nn3X1JDKYSEqYQtXdh4SG2jrtQ6OeNqe56V0vGsRLeZo 7k3Q6yljoY5P4xgdfnnjkYJog+Qz/5KH6qtST2Zd42Puhiqhi1pVW0vzPk5n+MyxmPHuIqLfbr93 Ie7DuAc7vFrFhN+GXF5B/j3K3B+5F/mmptztRyJDj/a9MtjqHvmti3DvypWioqJdYqKFRdOHmxeX hP+pp4fnBvbHbmvbT+Q8YyMi2xkn1XzzsfsysVcWCnDc+OSjLSdeeTa8oby8PHnM3HXXXdzyiJyE CjByJCX18vSRB8e8mWTctKCqSk+L3vCjomgPn9+7QPqa6H208uFW/gCMhIeFKMEWTirSO8ibRJig j9N/sn9qv0X2U05jVB8YdtrsTlvXUo8BvZthDsvGOI0Oy0J3yjOJHZaWc4+k11Us1H+fVPIu9lyK uUdRZU34HuVf8nC3x34Bce+SNVZM4H/OC++tLvKe+P5e43FObhbXRVhTe28G9spCAa7A3HnRlhEl eHRFQOQkhMjJLOmmn4bXo9CF5jW6Bjoscj5swfNNmE0jFJmEytk+NeVuaO6t5pZ87Wzry8ObSL/k odHYrTeec/XtU+b6MByVNTpy+Hy0j5eFe/2+6srIFuE1WOL4FhepITqiSBcaIt842Hq69+ix/ems FUOV1fVx2wSeBsSHXx7DvSsPMMFgMJhs3Y+kS2jbXnyGiO5r42x6oEF09OBm9spCgRjRZjn8UNV3 9F+O+fSU+9LIfwk9KSMiYpK2qgIgcoQgcjJIsl5211mH/vCw3Zlg+Tbe43Wfz52g+62yup64w1v9 Sx7xw0KUeAvzuAY6TI7m0USt6ucPOybyn3N43CM9oZ5C04iH5sdM8p5I5xro4HWr+3zpDOfIY1XN zfHTSX1Tr23qevnPObiREImo0HzW3vQOGDN4PbZbmvuvxoaffAjeo2KH5ke+gLh35QPxHr+19N56 M+uOHQ6hUhGtB66HrCaeuie6139LVEAAG1iNNsAvLnhPuS9xPz3lvvSLC94C7ytF5CSEyMksKQfG RP/f8k2YLZPc4arRh+kzx3od+kRrtzUau/WTR49NExHR9BD3IbLwYSFKvIWjfBNm4RERM+9NUl0t d3hzZedoaP6cze60jR7WUUP3qLxXNG80dus35kuEMqdkDaIc1Qd6D9Oo0XySMyrDNOJpG0z7erkG ekbnW7sSzV4ILSaT1kzKquZm/rebMyGYJz78ZEToHsU7O/4XEPcu2WNYkUmE6n+4M70jqtVExAbX iWg9yBJ5vQtEz4yE19uY/LcHNreXRAWETmL7ndxGGD6/+Pb8cuijt+eXh88vio9HVnrihchJXB1E TkZJNjCmse9IW8tRQ+i/sfYj9sFzhl6fnyi05HMbHTW0EBHpDw8nWruNqPrA8Dj1GDsMofLtdFr8 sBCVQguH+c85PDTvMbWMcXfnjJfQVed741YfGB639rSExyGINYiiVB0astcOGYwdo+ENuvixTwIc lhbOi5YaukedQsPcKzst3WeNRw2pv0iI9+3mvkpp5ljLiWreGu3x4RdfJke4Z9HQbWqn0fjtnHjD vSsfhJKEJAWKq/TBy8mWJI1lc0z/xyP7H338+m+sBx7dT94Tf5wlmn1xr22Le3VIUkBA0V33xDTL mx/9NdT9OXx+MZVmSN6qCoDISQiRk1mqrTx08Hg82oq709wpxYWc+fBmQb7AyrJwy2+qhfNc0gZR soI98exA8+aLwMpy/fH4ORJERE988MQ777yTfPeHWh76+FsfE0ONX/5d6R07kpRkLn/6xfH/THqw +196+9cHq6df3fuijbuBiMh74vvPvJ44v0l/rywUiCh76l+K9Q8KfpyCtSt/c116WvIFL9K00LWQ MGzKr5b/aPuPLJZk000+++yzph82Lf7TIhEhcoQoNXJStNC1oNPFvr3m2rVrKpUqrV9F7vvpxVOP rmi1Wrz9FAAAgIjCQ5KTfK7auatY/+C6+2PhIrOvP7P39aQbMrNXFgoQEVHxV/cV1T+w1SHFih/e gMiJg8jJOKTsAJAJvgmzKfrKM66G1NeOBMitIMMExXq/itueDV7+lL329+xUKbdUpWXFLU+Jtomo rR9B5hA5MRA5Ush+yt5ktjvT3qmxzyb01jCItakWBtiiqkND9kO5rgTAlrAsy4qmCJpSzbefu/X7 t9hrV7JSqdwpLStu6yRNqXibiFH8uh+IHB5EjjTQyw4AAIp19erV/v7+FAszLJvSChU7/lHT3bd+ 5iTzyQdbqpyMqe6p13y7m0rLMrJkR96t+/HnP/85edisrvIWbUTkRBV45EgKKTsAACjW+43vv7/6 vkihyKvARNf94FK3fk9Vdz/j+Qv7qYeuK6LftLSMSrSqHbvUu7+mqvsqQ0QZGpaQX+t+3Nh24w/3 /uEPq39IXoy5f+OkEDmInCxAyg4AAIp1s/xm6oXZdBIvIqKa3aqa3cJvkslXLNHWhzTwDphXiRer ZtMKG0LkRBR45EgNKTsAAAARkapIxQSDKnV+LiknY4ofkYzIkYjiIyctSNkBAACIiNZVK8VrpVRS muuKKE2QCea6CtJC5EhE8ZGTFqTsAAAARETzK5Y6pl+tLdMkfS0OpEvxXaWIHIkoPnLSgpQdAACA SE0B5pKbXtEx3drL+mJ1ea4rpBzbKr5Eq+LF8hUiRzIKj5w0IWUHAAAgIiIV3WKvz639jFgidO9l ioroMpHy5lpyIXKkUAiRkw6k7AAAAEREpCJSETHIEiSg7JmZiBzpKDty0oGUHQAAgAMpAmwOIgek hPgCAAAAAJA1pOwAAAAAALKGlB0AAAAAQNaQsgMAAAAASG7btm2b3hcpOwAAAACArCFlBwAAAACQ NaTsAAAAAACyhpQdAAAAAEDWkLIDAAAAAGTbyspKzJa1tbW1tbWEhbf69tPAyvIWjwCbg5aPUbAN UrAnnh1o3nyx0LWQ6ypA/kHYQG698cYbTz311J49e0J/XVtbO3XqlE6n27dvH7cYy7Isy241ZddW 3L3FI8AmBFaW0fJcBdsgBXvi2YHmzReBleX64/W5rgXkmYWuBYQNSCfFXwhPnDhx48aNb3zjG6E/ X7hwQafTJSyJgTEAAAAAANn2wgsvhHrWL1y48MYbb1y4cGHPnj3RTvcYSNkBAAAAALKtoqLixz/+ cXFx8VtvveXxeHQ63Q9+8IPS0tKYYiqVSqVSIWUHAAAAAMiBiooKk8m0Y8eOPXv2vPDCC0lKbnUs OwAAAAAAbI5Opzt48OA999wjVCDUy46UHQAAAAAgZ4SmnIZgYAwAAAAAgKyp1Wqk7AAAAAAA8oWB MQAAADwa9bZ77/jhbZq62zU1ua6Lojh87bmugrQQORJRfOSkQq1WFxUVIWUHAAAgIirX7Hpst3Xn 9orbyrTaEk2uq6Mcs4teWlLystKIHIkoPnJSVFRUpFar/x80LPqzaLLNywAAAABJRU5ErkJggg== " 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 [cce838ed12].
︙ | ︙ | |||
769 770 771 772 773 774 775 | </script> </head> <body class="book"> <div id="header"> <h1>The Megatest Users Manual</h1> <span id="author">Matt Welland</span><br> <span id="email" class="monospaced"><<a href="mailto:matt@kiatoa.com">matt@kiatoa.com</a>></span><br> | | | > > > > > > > > > > > > > > > > > > > > | | | | | | > > > > | | | | | | | < | | > | > > > > > > > > > > > > | < < < < < < < < < < < | > | | | > > > > | > > > > | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > | | | > > > > > > > > > > | > > > < > > > > > | > > > > > > > > > > > > > > > > > > > > > < < > < > > > > > > > > > > > > > > > > > > > > > > > > > > > > | < > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | < > > > > > > | > > > > > > | | > > > > | < > > > > > > > > > > > > | > > > > > | > > > > > > > > > > > > > > > > > > > > > | < > > > > > > > | > > > > > > > > > > > > > > > > > > > | > > > > > | > > > > > > > > > > > | | > > > > > > > > > > > > > | > > > > > > | < > > > > > > > > > > | > < > > > > > > > > > > > | > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | < > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > < < < > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | | 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 | </script> </head> <body class="book"> <div id="header"> <h1>The Megatest Users Manual</h1> <span id="author">Matt Welland</span><br> <span id="email" class="monospaced"><<a href="mailto:matt@kiatoa.com">matt@kiatoa.com</a>></span><br> <span id="revnumber">version 1.5,</span> <span id="revdate">June 2020</span> <div id="toc"> <div id="toctitle">Table of Contents</div> <noscript><p><b>JavaScript must be enabled in your browser to display the table of contents.</b></p></noscript> </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-2020, 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 integration 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="_road_map">Road Map</h2> <div class="sectionbody"> </div> </div> <div class="sect1"> <h2 id="_todo_road_map">TODO / Road Map</h2> <div class="sectionbody"> <div class="paragraph"><p>Note: This road-map is a wish list and not a formal plan. Items are in rough priority but are subject to change. Development is driven by user requests, developer "itch" and bug reports. Please contact <a href="mailto:matt@kiatoa.com">matt@kiatoa.com</a> with requests or bug reports. Requests from inside Intel generally take priority.</p></div> <div class="paragraph"><p>Dashboard and runs</p></div> <div class="olist arabic"><ol class="arabic"> <li> <p> Multi-area dashboard view </p> </li> </ol></div> <div class="paragraph"><p>Tests Support</p></div> <div class="olist arabic"><ol class="arabic"> <li> <p> Add variable $MT_RUNPATH = $MT_LINKTREE/$MT_TARGET/$MT_RUNNAME </p> </li> <li> <p> Improve [script], especially indent handling </p> </li> </ol></div> <div class="paragraph"><p>Scalability</p></div> <div class="olist arabic"><ol class="arabic"> <li> <p> Overflow database methodology - combine the best of the v1.63 multi-db approach and the current db-in-tmp approach (currently slowness can be seen when number of tests in a db goes over 50-100k, with the overflow db it will be able to handle 1000’s of runs with 50-100k tests per run). High priority - goal is to complete this by 20Q3. </p> </li> </ol></div> <div class="paragraph"><p>Mtutils/CI</p></div> <div class="olist arabic"><ol class="arabic"> <li> <p> Enable mtutil calls from dashboard (for remote control) </p> </li> <li> <p> Logs browser (esp. for surfacing mtutil related activities) </p> </li> <li> <p> Embed ftfplan for distributed automation, completed activities trigger QA runs which trigger deployment etc. </p> </li> <li> <p> Jenkins junit XML support [DONE] </p> </li> <li> <p> Add output flushing in teamcity support </p> </li> </ol></div> <div class="paragraph"><p>Build system</p></div> <div class="olist arabic"><ol class="arabic"> <li> <p> ./configure ⇒ ubuntu, sles11, sles12, rh7 [WIP] </p> </li> <li> <p> Switch to using simple runs query everywhere </p> </li> <li> <p> Add end_time to runs and add a rollup call that sets state, status and end_time </p> </li> </ol></div> <div class="paragraph"><p>Code refactoring/quality/performance</p></div> <div class="olist arabic"><ol class="arabic"> <li> <p> Switch to scsh-process pipeline management for job execution/control </p> </li> <li> <p> Use call-with-environment-variables where possible. </p> </li> </ol></div> <div class="paragraph"><p>Migration to inmem db and or overflow db</p></div> <div class="olist arabic"><ol class="arabic"> <li> <p> Re-work the dbstruct data structure? </p> <div class="olist loweralpha"><ol class="loweralpha"> <li> <p> [ run-id.db inmemdb last-mod last-read last-sync inuse ] </p> </li> </ol></div> </li> </ol></div> <div class="paragraph"><p>Some ideas for Megatest 2.0</p></div> <div class="olist arabic"><ol class="arabic"> <li> <p> Aggressive 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 (example is incomplete). </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="paragraph"><p>Add ability to move runs to other Areas (overlaps with overflow db system)</p></div> <div class="olist arabic"><ol class="arabic"> <li> <p> allow shrinking megatest.db data by moving runs to an alternate Megatest area with same keys. </p> </li> <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>Eliminate ties to homehost (part of overflow db system)</p></div> <div class="olist arabic"><ol class="arabic"> <li> <p> Server creates captain pkt </p> </li> <li> <p> Create a lock in the db </p> </li> <li> <p> Relinquish db when done </p> </li> </ol></div> <div class="paragraph"><p>Tasks - better management of run manager processes etc.</p></div> <div class="olist arabic"><ol class="arabic"> <li> <p> adjutant queries tasks table for next action <span class="red">[Migrate into mtutil]</span> </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> <li> <p> adjutant (server/task dispatch/execution manager) </p> </li> </ol></div> <div class="paragraph"><p>Stale propagation</p></div> <div class="olist arabic"><ol class="arabic"> <li> <p> Mark dependent tests for clean/rerun -rerun-downstream </p> </li> <li> <p> On run start check for defunct tests in RUNNING, LAUNCHED or REMOTEHOSTSTART and correct or notify </p> </li> <li> <p> Fix: refresh of gui sometimes fails on last item (race condition?) </p> </li> </ol></div> <div class="paragraph"><p>Bin list</p></div> <div class="olist arabic"><ol class="arabic"> <li> <p> Rerun step and or subsequent steps from gui [DONE?] </p> </li> <li> <p> Refresh test area files from gui </p> </li> <li> <p> Clean and re-run button </p> </li> <li> <p> Clean up STATE and STATUS handling. </p> <div class="olist loweralpha"><ol class="loweralpha"> <li> <p> Dashboard and Test control panel are reverse order - choose and fix </p> </li> <li> <p> Move seldom used states and status to drop down selector </p> </li> </ol></div> </li> <li> <p> Access test control panel when clicking on Run Summary tests </p> </li> <li> <p> Feature: -generate-index-tree </p> </li> <li> <p> Change specifing of state and status to use STATE1/STATUS1,STATE2/STATUS2 </p> </li> <li> <p> rest api available for use with Perl, Ruby etc. scripts </p> </li> <li> <p> megatest.config setup entries for: </p> <div class="olist loweralpha"><ol class="loweralpha"> <li> <p> run launching (e.g. /bin/sh %CMD% > /dev/null) </p> </li> <li> <p> browser "konqueror %FNAME% </p> </li> </ol></div> </li> <li> <p> refdb: Add export of csv, json and sexp </p> </li> <li> <p> Convert to using call-with-environment-variables where possible. Should allow handling of parallel runs in same process. </p> </li> <li> <p> Re-work text interface wizards. Several bugs on record. Possibly convert to gui based. </p> </li> <li> <p> Add to testconfig requirements section; launchlimiter scriptname, calls scriptname to check if ok to launch test </p> </li> <li> <p> Refactor Run Summary view, currently very clumsy </p> </li> <li> <p> Add option to show steps in Run Summary view </p> </li> <li> <p> Refactor guis for resizeablity </p> </li> <li> <p> Add filters to Run Summary view and Run Control view </p> </li> <li> <p> Add to megatest.config or testconfig; rerunok STATE/STATUS,STATE/STATUS… </p> </li> <li> <p> Launch gates for diskspace; /path/one>1G,/path/two>200M,/tmp>5G,#{scheme <strong>toppath</strong>}>1G </p> </li> <li> <p> Tool tips </p> </li> <li> <p> Filters on Run Summary, Summary and Run Control panel </p> </li> <li> <p> Built in log viewer (partially implemented) </p> </li> <li> <p> Refactor the test control panel Help and documentation </p> </li> <li> <p> Complete the user manual (I’ve been working on this lately). </p> </li> <li> <p> Online help in the gui Streamlined install </p> </li> <li> <p> Deployed or static build </p> </li> <li> <p> Added option to compile IUP (needed for VMs) </p> </li> <li> <p> Server side run launching </p> </li> <li> <p> Wizards for creating tests, regression areas (current ones are text only and limited). </p> </li> <li> <p> Fully functional built in web service (currently you can browse runs but it is very simplistic). </p> </li> <li> <p> Gui panels for editing megatest.config and runconfigs.config </p> </li> <li> <p> Fully isolated tests (no use of NFS to see regression area files) </p> </li> <li> <p> Windows version </p> </li> </ol></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 class="paragraph"><p>Megatest. In the v1.66 and beyond assistance to create the build system is built into the Makefile.</p></div> <div class="listingblock"> <div class="title">Installation steps (overview)</div> <div class="content monospaced"> <pre>./configure make chicken setup.sh make -j install</pre> </div></div> <div class="paragraph"><p>Or install the needed build system manually:</p></div> <div class="olist arabic"><ol class="arabic"> <li> <p> Chicken scheme from <a href="http://call-cc.org">http://call-cc.org</a> </p> </li> <li> <p> IUP from <a href="http://webserver2.tecgraf.puc-rio.br/iup/">http://webserver2.tecgraf.puc-rio.br/iup/</a> </p> </li> <li> <p> CD from <a href="http://webserver2.tecgraf.puc-rio.br/cd/">http://webserver2.tecgraf.puc-rio.br/cd/</a> </p> </li> <li> <p> IM from <a href="https://webserver2.tecgraf.puc-rio.br/im/">https://webserver2.tecgraf.puc-rio.br/im/</a> </p> </li> <li> <p> ffcall from <a href="http://webserver2.tecgraf.puc-rio.br/iup/">http://webserver2.tecgraf.puc-rio.br/iup/</a> </p> </li> <li> <p> Nanomsg from <a href="https://nanomsg.org/">https://nanomsg.org/</a> (NOTE: Plan is to eliminate nanomsg dependency). </p> </li> <li> <p> Needed eggs (look at the eggs lists in the Makefile) </p> </li> </ol></div> <div class="paragraph"><p>Then follow these steps:</p></div> <div class="listingblock"> <div class="title">Installation steps (self-built chicken scheme build system)</div> <div class="content monospaced"> <pre>./configure make -j install</pre> </div></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 | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | <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] | > > > > > > > > > > > > > > > > | 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 | <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%; "> | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | 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 | </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 | | | | | | > > > > > > > > > > > > > > > > > > > > > | | | | > > > > > > > > | > > > > | | | | < | 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 | <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="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">As of Megatest version v1.6548 trim-trailing-spaces defaults to yes.</td> </tr></table> </div> <div class="listingblock"> <div class="content monospaced"> <pre>[configf:settings trim-trailing-spaces no] # |<== next line padded with spaces to here DEFAULT_INDENT [configf:settings trim-trailing-spaces no]</pre> </div></div> <div class="paragraph"><p>The variable DEFAULT_INDENT would be a string of 3 spaces</p></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> |
︙ | ︙ | |||
1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 | <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] # this will automatically kill the test if it runs for more than 1h 2m and 3s runtimelim 1h 2m 3s</pre> </div></div> </div> </div> </div> <div class="sect2"> <h3 id="_tests_browser_view">Tests browser view</h3> <div class="paragraph"><p>The tests browser (see the Run Control tab on the dashboard) has two views for displaying the tests.</p></div> <div class="olist arabic"><ol class="arabic"> | > > > > > > > > > > > > > > > > > > > > > > > > | 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 | <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] # this will automatically kill the test if it runs for more than 1h 2m and 3s runtimelim 1h 2m 3s</pre> </div></div> </div> <div class="sect4"> <h5 id="_post_run_hook">Post Run Hook</h5> <div class="paragraph"><p>This runs script to-run.sh after all tests have been completed. It is not necessary to use -run-wait as each test will check for other running tests on completion and if there are none it will call the post run hook.</p></div> <div class="paragraph"><p>Note that the output from the script call will be placed in a log file in the logs directory with a file name derived by replacing / with _ in post-hook-<target>-<runname>.log.</p></div> <div class="listingblock"> <div class="content monospaced"> <pre>[runs] post-hook /path/to/script/to-run.sh</pre> </div></div> </div> </div> </div> <div class="sect2"> <h3 id="_tests_browser_view">Tests browser view</h3> <div class="paragraph"><p>The tests browser (see the Run Control tab on the dashboard) has two views for displaying the tests.</p></div> <div class="olist arabic"><ol class="arabic"> |
︙ | ︙ | |||
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%; "> | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | < < < < < < | 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 | <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> | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | > > > > > > > > > > > > > > > > > > > > > > > > > | | | 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 | <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 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">Dynamic waiton lists must be capable of being calculated at the beginning of a run. This is because Megatest walks the tree of waitons to create the list of tests to execute.</td> </tr></table> </div> <div class="listingblock"> <div class="title">This works</div> <div class="content monospaced"> <pre>waiton [system somescript.sh]</pre> </div></div> <div class="listingblock"> <div class="title">This does NOT work (the full context for the test is not available so #{shell …} is NOT enabled to evaluate.</div> <div class="content monospaced"> <pre>waiton #{shell somescript.sh}</pre> </div></div> <div class="listingblock"> <div class="title">This does NOT work</div> <div class="content monospaced"> <pre>waiton [system somescript_that_depends_on_a_prior_test.sh]</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> | < | 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 | "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] | > | > | | > > > | > > > | < > > > > > > > > | | > > > > > > > > > > > > > > | > > | | | > | > | | > > | | > > | < < < < < < < | | < < < < < < < < < < < < < < < < | > | | < | < < | | | > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > | | | | | | | | | | > > > > > > > > > > > > > > > > | | | | | | > > > | > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > | > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | </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 or if the test/itempath is listed under the matching target in the waivers roll forward file (see below for file spec) 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 # if PASS or WARN result from logpro then WAIVER state is set # [waivers] # logpro_file rulename input_glob waiver_1 logpro lookittmp.log [waiver_rules] # 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 class="sect3"> <h4 id="_waiver_roll_forward_files">Waiver roll-forward files</h4> <div class="paragraph"><p>To transfer waivers from one Megatest area to another it is possible to dump waivers into a file and reference that file in another area.</p></div> <div class="listingblock"> <div class="title">Dumping the waivers</div> <div class="content monospaced"> <pre>megatest -list-waivers -runname %-a > mywaivers.dat</pre> </div></div> <div class="listingblock"> <div class="title">Referencing the saved waivers</div> <div class="content monospaced"> <pre># In megatest.config, all files listed will be loaded - recomended to use # variables to select directorys to minimize what gets loaded. [setup] waivers-dirs /path/to/waiver/files /another/path/to/waiver/files</pre> </div></div> <div class="listingblock"> <div class="title">Waiver files format</div> <div class="content monospaced"> <pre>[the/target/here] # comments are fine testname1/itempath A comment about why it was waived testname2 A comment for a non-itemized test</pre> </div></div> </div> </div> <div class="sect2"> <h3 id="_ezsteps">Ezsteps</h3> <div class="paragraph"><p>Ezsteps is the recommended way to implement tests and automation in Megatest.</p></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">Each ezstep must be a single line. Use the [scripts] mechanism to create multiline scripts (see example below).</td> </tr></table> </div> <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="sect3"> <h4 id="_automatic_environment_propagation_with_ezsteps">Automatic environment propagation with Ezsteps</h4> <div class="paragraph"><p>Turn on ezpropvars and environment variables will be propagated from step to step. Use this to source script files that modify the envionment where the modifications are needed in subsequent steps.</p></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">aliases and variables with strange whitespace or characters will not propagate correctly. Put in a ticket on the <a href="http://www.kiatoa.com/fossils/megatest">http://www.kiatoa.com/fossils/megatest</a> site if you need support for a specific strange character combination.</td> </tr></table> </div> <div class="listingblock"> <div class="title">Turn on auto propagate for bash</div> <div class="content monospaced"> <pre>[setup] ezpropvars sh</pre> </div></div> <div class="listingblock"> <div class="title">Write your ezsteps. The loadenv.csh step will use /bin/csh as its shell, other steps will use bash.</div> <div class="content monospaced"> <pre>[ezsteps] loadenv.csh source $REF/ourenviron.csh compile make install make install</pre> </div></div> <div class="paragraph"><p>Bash and csh are supported. You can override the shell binary location from the default /bin/bash and /bin/csh if needed.</p></div> <div class="listingblock"> <div class="title">Turn on auto propagate for csh</div> <div class="content monospaced"> <pre>[setup] ezpropvars csh /bin/csh</pre> </div></div> <div class="listingblock"> <div class="title">Example of auto propagation using extensions</div> <div class="content monospaced"> <pre>[ezsteps] step1.sh export SOMEVAR=$(ps -def | wc -l);ls /tmp # The next step will get the value of $SOMEVAR from step1.sh step2.sh echo $SOMEVAR</pre> </div></div> <div class="listingblock"> <div class="title">Example of multi-line script</div> <div class="content monospaced"> <pre>[scripts] tarresults tar cfvz $DEST/srcdir1.tar.gz srcdir1 tar cfvz $DEST/srcdir2.tar.gz srcdir2 [setup] ezpropvars sh [ezsteps] step1 DEST=/tmp/targz;source tarresults</pre> </div></div> <div class="paragraph"><p>The above example will result in files; tarresults and ez_step1 being created in the test dir.</p></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"> | | | > > < < | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | 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 | # 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> |
︙ | ︙ | |||
2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 | <td class="tableblock halign-left valign-top" ><p class="tableblock monospaced"></p></td> <td class="tableblock halign-left valign-top" ><p class="tableblock monospaced">( key1 key2 … )</p></td> <td class="tableblock halign-left valign-top" ><p class="tableblock monospaced"></p></td> </tr> </tbody> </table> </div> </div> <div class="sect1"> <h2 id="_megatest_internals">Megatest Internals</h2> <div class="sectionbody"> <div class="imageblock graphviz"> <div class="content"> <img src="server.png" alt="server.png"> </div> </div> </div> </div> <div class="sect1"> | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | | 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 | <td class="tableblock halign-left valign-top" ><p class="tableblock monospaced"></p></td> <td class="tableblock halign-left valign-top" ><p class="tableblock monospaced">( key1 key2 … )</p></td> <td class="tableblock halign-left valign-top" ><p class="tableblock monospaced"></p></td> </tr> </tbody> </table> </div> </div> <div class="sect1"> <h2 id="_test_plan">Test Plan</h2> <div class="sectionbody"> <div class="sect2"> <h3 id="_tests">Tests</h3> <div class="paragraph"><p>itemwait|33</p></div> <div class="paragraph"><p>rerun-downstream-item|20</p></div> <div class="paragraph"><p>rerunclean|20</p></div> <div class="paragraph"><p>fullrun|18</p></div> <div class="paragraph"><p>goodtests|18</p></div> <div class="paragraph"><p>kill-rerun|17</p></div> <div class="paragraph"><p>items-runconfigvars|16</p></div> <div class="paragraph"><p>ro_test|16</p></div> <div class="paragraph"><p>runconfig-tests|16</p></div> <div class="paragraph"><p>env-pollution|13</p></div> <div class="paragraph"><p>itemmap|11</p></div> <div class="paragraph"><p>testpatt_envvar|10</p></div> <div class="paragraph"><p>toprun|10</p></div> <div class="paragraph"><p>chained-waiton|8</p></div> <div class="paragraph"><p>skip-on-fileexists|8</p></div> <div class="paragraph"><p>killrun_preqfail|7</p></div> <div class="paragraph"><p>subrun|6</p></div> <div class="paragraph"><p>dependencies|5</p></div> <div class="paragraph"><p>itemwait-simple|4</p></div> <div class="paragraph"><p>rollup|4</p></div> <div class="paragraph"><p>end-of-run|3</p></div> <div class="paragraph"><p>killrun|3</p></div> <div class="paragraph"><p>listener|3</p></div> <div class="paragraph"><p>test2|3</p></div> <div class="paragraph"><p>testpatt|3</p></div> <div class="paragraph"><p>env-pollution-usecacheno|2</p></div> <div class="paragraph"><p>set-values|2 envvars|1 listruns-tests|1 subrun-usecases|1</p></div> </div> </div> </div> <div class="sect1"> <h2 id="_megatest_internals">Megatest Internals</h2> <div class="sectionbody"> <div class="imageblock graphviz"> <div class="content"> <img src="server.png" alt="server.png"> </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.5<br> Last updated 2020-10-13 21:24:33 PDT </div> </div> </body> </html> |
Modified docs/manual/megatest_manual.txt from [c82fa9e963] to [cb5cc67576].
1 2 3 | The Megatest Users Manual ========================= Matt 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 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 | The Megatest Users Manual ========================= Matt Welland <matt@kiatoa.com> v1.5, June 2020 :doctype: book [preface] Preface ------- This book is organised as three sub-books; getting started, writing tests and reference. .License ---------------------------- Copyright 2006-2020, 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 integration 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::plan.txt[] include::installation.txt[] include::getting_started.txt[] include::study_plan.txt[] // :leveloffset: 0 include::writing_tests.txt[] include::howto.txt[] include::reference.txt[] include::testplan.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] | | | | 177 178 179 180 181 182 183 184 185 186 187 188 189 | // // [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 [84407a87ee].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | 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-2020, Matthew Welland. TODO / Road Map --------------- Note: This road-map is a wish list and not a formal plan. Items are in rough priority but are subject to change. Development is driven by user requests, developer "itch" and bug reports. Please contact matt@kiatoa.com with requests or bug reports. Requests from inside Intel generally take priority. Dashboard and runs . Multi-area dashboard view Tests Support . Add variable $MT_RUNPATH = $MT_LINKTREE/$MT_TARGET/$MT_RUNNAME . Improve [script], especially indent handling Scalability . Overflow database methodology - combine the best of the v1.63 multi-db approach and the current db-in-tmp approach (currently slowness can be seen when number of tests in a db goes over 50-100k, with the overflow db it will be able to handle 1000's of runs with 50-100k tests per run). High priority - goal is to complete this by 20Q3. Mtutils/CI . Enable mtutil calls from dashboard (for remote control) . Logs browser (esp. for surfacing mtutil related activities) . Embed ftfplan for distributed automation, completed activities trigger QA runs which trigger deployment etc. . Jenkins junit XML support [DONE] . Add output flushing in teamcity support Build system . ./configure => ubuntu, sles11, sles12, rh7 [WIP] . Switch to using simple runs query everywhere . Add end_time to runs and add a rollup call that sets state, status and end_time Code refactoring/quality/performance . Switch to scsh-process pipeline management for job execution/control . Use call-with-environment-variables where possible. Migration to inmem db and or overflow db . Re-work the dbstruct data structure? .. [ run-id.db inmemdb last-mod last-read last-sync inuse ] Some ideas for Megatest 2.0 . Aggressive 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 (example is incomplete). ---------------- [testcopy] %/iind% unison SRC DEST % cp –r SRC DEST ---------------- Add ability to move runs to other Areas (overlaps with overflow db system) . allow shrinking megatest.db data by moving runs to an alternate Megatest area with same keys. . 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. Eliminate ties to homehost (part of overflow db system) . Server creates captain pkt . Create a lock in the db . Relinquish db when done Tasks - better management of run manager processes etc. . adjutant queries tasks table for next action [red]#[Migrate into mtutil]# .. 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#] . adjutant (server/task dispatch/execution manager) Stale propagation . 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?) Bin list . Rerun step and or subsequent steps from gui [DONE?] . 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 . rest 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% . 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 . 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 . 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 or static build . Added option to compile IUP (needed for VMs) . Server side run launching . 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). . 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 [e5228eb513].
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 142 143 144 145 146 147 148 | ------------------------- [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 ~~~~~~~~~~~~~~~~~~~~ NOTE: As of Megatest version v1.6548 trim-trailing-spaces defaults to yes. ------------------ [configf:settings trim-trailing-spaces no] # |<== next line padded with spaces to here DEFAULT_INDENT [configf:settings trim-trailing-spaces no] ------------------ The variable DEFAULT_INDENT would be a string of 3 spaces 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 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 | .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 ----------------- Tests browser view ~~~~~~~~~~~~~~~~~~ The tests browser (see the Run Control tab on the dashboard) has two views for displaying the tests. . Dot (graphviz) based tree . No dot, plain listing 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. ----------------- [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. | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > < | 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 | .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 ----------------- Post Run Hook +++++++++++++ This runs script to-run.sh after all tests have been completed. It is not necessary to use -run-wait as each test will check for other running tests on completion and if there are none it will call the post run hook. Note that the output from the script call will be placed in a log file in the logs directory with a file name derived by replacing / with _ in post-hook-<target>-<runname>.log. ------------------- [runs] post-hook /path/to/script/to-run.sh ------------------- Tests browser view ~~~~~~~~~~~~~~~~~~ The tests browser (see the Run Control tab on the dashboard) has two views for displaying the tests. . Dot (graphviz) based tree . No dot, plain listing 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. ----------------- [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 | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > < > > > > > > > > > > > > > > > > > > > > < > | 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 | 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 ------------------- NOTE: Dynamic waiton lists must be capable of being calculated at the beginning of a run. This is because Megatest walks the tree of waitons to create the list of tests to execute. .This works ------------------- waiton [system somescript.sh] ------------------- .This does NOT work (the full context for the test is not available so #{shell ...} is NOT enabled to evaluate. ------------------- waiton #{shell somescript.sh} ------------------- .This does NOT work ------------------- waiton [system somescript_that_depends_on_a_prior_test.sh] ------------------- 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] | > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | < | | < < | < < < < < < | < | < < < | | | | > > | | | | | > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > < > < > < > < > < > > > > > > > > > > > > > > > > > < > < > < > | > > > | > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > | > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > | > | > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | 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 or if the test/itempath is listed under the matching target in the waivers roll forward file (see below for file spec) 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) ----------------- ###### EXAMPLE FROM testconfig ######### # matching file(s) will be diff'd with previous run and logpro applied # if PASS or WARN result from logpro then WAIVER state is set # [waivers] # logpro_file rulename input_glob waiver_1 logpro lookittmp.log [waiver_rules] # 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 ----------------- Waiver roll-forward files ^^^^^^^^^^^^^^^^^^^^^^^^^ To transfer waivers from one Megatest area to another it is possible to dump waivers into a file and reference that file in another area. .Dumping the waivers --------------------------- megatest -list-waivers -runname %-a > mywaivers.dat --------------------------- .Referencing the saved waivers --------------------------- # In megatest.config, all files listed will be loaded - recomended to use # variables to select directorys to minimize what gets loaded. [setup] waivers-dirs /path/to/waiver/files /another/path/to/waiver/files --------------------------- .Waiver files format --------------------------- [the/target/here] # comments are fine testname1/itempath A comment about why it was waived testname2 A comment for a non-itemized test --------------------------- Ezsteps ~~~~~~~ Ezsteps is the recommended way to implement tests and automation in Megatest. NOTE: Each ezstep must be a single line. Use the [scripts] mechanism to create multiline scripts (see example below). .Example ezsteps with logpro rules ----------------- [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/) ----------------- Automatic environment propagation with Ezsteps ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Turn on ezpropvars and environment variables will be propagated from step to step. Use this to source script files that modify the envionment where the modifications are needed in subsequent steps. NOTE: aliases and variables with strange whitespace or characters will not propagate correctly. Put in a ticket on the http://www.kiatoa.com/fossils/megatest site if you need support for a specific strange character combination. .Turn on auto propagate for bash --------------------------- [setup] ezpropvars sh --------------------------- .Write your ezsteps. The loadenv.csh step will use /bin/csh as its shell, other steps will use bash. --------------------------- [ezsteps] loadenv.csh source $REF/ourenviron.csh compile make install make install --------------------------- Bash and csh are supported. You can override the shell binary location from the default /bin/bash and /bin/csh if needed. .Turn on auto propagate for csh --------------------------- [setup] ezpropvars csh /bin/csh --------------------------- .Example of auto propagation using extensions --------------------------- [ezsteps] step1.sh export SOMEVAR=$(ps -def | wc -l);ls /tmp # The next step will get the value of $SOMEVAR from step1.sh step2.sh echo $SOMEVAR --------------------------- .Example of multi-line script --------------------------- [scripts] tarresults tar cfvz $DEST/srcdir1.tar.gz srcdir1 tar cfvz $DEST/srcdir2.tar.gz srcdir2 [setup] ezpropvars sh [ezsteps] step1 DEST=/tmp/targz;source tarresults --------------------------- The above example will result in files; tarresults and ez_step1 being created in the test dir. 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 -------------- | | | | 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 | # 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 | | > > < < > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > < | 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 | 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 |
Added docs/manual/subrun-opt-stuff.fig version [118dffbc3b].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | #FIG 3.2 Produced by xfig version 3.2.5-alpha5 Landscape Center Inches Letter 100.00 Single -2 1200 2 6 150 5475 1650 9675 2 2 0 1 0 7 50 -1 -1 3.000 0 0 -1 0 0 5 150 5475 1650 5475 1650 9675 150 9675 150 5475 2 2 0 1 0 7 50 -1 -1 3.000 0 0 -1 0 0 5 225 5550 1575 5550 1575 6075 225 6075 225 5550 2 2 0 1 0 7 50 -1 -1 3.000 0 0 -1 0 0 5 225 6150 1575 6150 1575 6675 225 6675 225 6150 2 2 0 1 0 7 50 -1 -1 3.000 0 0 -1 0 0 5 225 6750 1575 6750 1575 7275 225 7275 225 6750 2 2 0 1 0 7 50 -1 -1 3.000 0 0 -1 0 0 5 225 7350 1575 7350 1575 7875 225 7875 225 7350 -6 6 3900 5550 5400 9750 2 2 0 1 0 7 50 -1 -1 3.000 0 0 -1 0 0 5 3900 5550 5400 5550 5400 9750 3900 9750 3900 5550 2 2 0 1 0 7 50 -1 -1 3.000 0 0 -1 0 0 5 3975 5625 5325 5625 5325 6150 3975 6150 3975 5625 2 2 0 1 0 7 50 -1 -1 3.000 0 0 -1 0 0 5 3975 6225 5325 6225 5325 6750 3975 6750 3975 6225 2 2 0 1 0 7 50 -1 -1 3.000 0 0 -1 0 0 5 3975 6825 5325 6825 5325 7350 3975 7350 3975 6825 2 2 0 1 0 7 50 -1 -1 3.000 0 0 -1 0 0 5 3975 7425 5325 7425 5325 7950 3975 7950 3975 7425 -6 6 8325 5700 9525 9825 2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5 8325 6000 9525 6000 9525 6825 8325 6825 8325 6000 2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5 8325 6900 9525 6900 9525 7725 8325 7725 8325 6900 2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5 8325 7800 9525 7800 9525 8625 8325 8625 8325 7800 2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5 8325 8700 9525 8700 9525 9525 8325 9525 8325 8700 4 0 0 50 -1 0 12 0.0000 4 120 405 8475 5850 tests\001 4 0 0 50 -1 0 12 0.0000 4 165 600 8400 6375 startup\001 4 0 0 50 -1 0 12 0.0000 4 195 375 8400 7275 opt1\001 4 0 0 50 -1 0 12 0.0000 4 195 375 8400 8025 opt2\001 4 0 0 50 -1 0 12 0.0000 4 195 585 8400 9075 opt1v2\001 4 0 0 50 -1 0 12 0.0000 4 15 180 8775 9825 ...\001 -6 2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5 4800 450 6000 450 6000 1275 4800 1275 4800 450 2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5 1050 2100 2250 2100 2250 2925 1050 2925 1050 2100 2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5 2925 2100 4125 2100 4125 2925 2925 2925 2925 2100 2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5 4950 2100 6150 2100 6150 2925 4950 2925 4950 2100 2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5 7200 2100 8400 2100 8400 2925 7200 2925 7200 2100 2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5 9375 2100 10575 2100 10575 2925 9375 2925 9375 2100 2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5 2025 4050 3225 4050 3225 4875 2025 4875 2025 4050 2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5 6525 3975 7725 3975 7725 4800 6525 4800 6525 3975 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 5400 1275 1500 2100 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 5325 1275 3525 2100 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 5325 1275 5475 2100 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 5250 1275 7800 2100 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 5325 1275 9900 2100 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 1650 2925 2550 4050 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 3525 2925 2550 4050 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 3525 2925 7050 3975 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 5550 2925 6975 3975 2 2 2 1 0 7 50 -1 -1 3.000 0 0 -1 0 0 5 750 1650 10875 1650 10875 3450 750 3450 750 1650 2 1 0 1 0 7 50 -1 -1 3.000 0 0 -1 1 0 3 0 0 1.00 60.00 120.00 1050 2700 450 2700 450 5550 2 1 0 1 0 7 50 -1 -1 3.000 0 0 -1 1 0 3 0 0 1.00 60.00 120.00 4125 2700 4650 2700 4650 5550 2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5 2100 5475 3300 5475 3300 8700 2100 8700 2100 5475 2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5 2175 6000 3225 6000 3225 6525 2175 6525 2175 6000 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 1500 6375 2325 6300 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 4200 6525 3000 6225 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 7800 2925 7050 3975 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 9975 2925 7125 3900 4 0 0 50 -1 0 12 0.0000 4 165 600 4875 975 startup\001 4 0 0 50 -1 0 12 0.0000 4 15 180 5325 2550 ...\001 4 0 0 50 -1 0 12 0.0000 4 195 2100 900 675 p1278/2/cpdk_r0.5/none\001 4 0 0 50 -1 0 12 0.0000 4 150 675 150 2475 subruns\001 4 0 0 50 -1 0 12 0.0000 4 195 585 2175 4500 opt1v2\001 4 0 0 50 -1 0 12 0.0000 4 195 375 1200 2625 opt1\001 4 0 0 50 -1 0 12 0.0000 4 195 375 3150 2550 opt2\001 4 0 0 50 -1 0 12 0.0000 4 150 2100 3075 150 SUBRUN for Multistack\001 4 0 0 50 -1 0 12 0.0000 4 150 225 300 6375 ftc\001 4 0 0 50 -1 0 12 0.0000 4 150 225 4050 6450 ftc\001 4 0 0 50 -1 0 12 0.0000 4 195 2220 600 5250 p1278/2/cpdk_r0.5/x-opt1\001 4 0 0 50 -1 0 12 0.0000 4 195 2220 4800 5325 p1278/2/cpdk_r0.5/y-opt2\001 |
Added docs/manual/testplan.txt version [2f7346adda].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | // This file is part of Megatest. // // Megatest is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Megatest is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more 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-2020, Matthew Welland. Test Plan --------- Tests ~~~~~ itemwait|33 rerun-downstream-item|20 rerunclean|20 fullrun|18 goodtests|18 kill-rerun|17 items-runconfigvars|16 ro_test|16 runconfig-tests|16 env-pollution|13 itemmap|11 testpatt_envvar|10 toprun|10 chained-waiton|8 skip-on-fileexists|8 killrun_preqfail|7 subrun|6 dependencies|5 itemwait-simple|4 rollup|4 end-of-run|3 killrun|3 listener|3 test2|3 testpatt|3 env-pollution-usecacheno|2 set-values|2 envvars|1 listruns-tests|1 subrun-usecases|1 |
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 |
Added ducttape-lib.scm version [ee2ef474af].
> > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | ;;====================================================================== ;; Copyright 2019, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more 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 ducttape-lib)) (include "ducttape/ducttape-lib.scm") |
Modified ducttape/Makefile from [7c53ca1a83] to [9efb623beb].
︙ | ︙ | |||
12 13 14 15 16 17 18 19 20 21 22 23 24 25 | clean: rm -f *.so *.import.scm test_ducttape test_example foo *.c *.o install: chicken-install test: chicken-install -no-install csc test_ducttape.scm ./test_ducttape rm -f foo test_example: | > | 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | clean: rm -f *.so *.import.scm test_ducttape test_example foo *.c *.o install: chicken-install test: echo '(handle-exceptions exn (begin (print-call-chain) (exit 1)) (load "ducttape-lib.scm") (inote "hello")) (exit 0)' | csi chicken-install -no-install csc test_ducttape.scm ./test_ducttape rm -f foo test_example: |
︙ | ︙ |
Modified ducttape/ducttape-lib.scm from [789effec13] to [59b0a2f94a].
︙ | ︙ | |||
14 15 16 17 18 19 20 | iwarn inote iputs re-match? ; launch-repl keyword-skim skim-cmdline-opts-noarg-by-regex | | > > | 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | iwarn inote iputs re-match? ; launch-repl keyword-skim skim-cmdline-opts-noarg-by-regex skim-cmdline-opts-withargs-by-regex get-cli-arg get-cli-switch concat-lists ducttape-process-command-line ducttape-append-logfile ducttape-activate-logfile isys do-or-die counter-maker |
︙ | ︙ | |||
40 41 42 43 44 45 46 | seconds->wwdate-values isodate->seconds isodate->wwdate wwdate->seconds wwdate->isodate current-wwdate current-isodate | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > | > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | seconds->wwdate-values isodate->seconds isodate->wwdate wwdate->seconds wwdate->isodate current-wwdate current-isodate *this-exe-dir* *this-exe-name* *this-exe-fullpath* ) (import scheme chicken extras ports data-structures ) (use posix regex ansi-escape-sequences test srfi-1 irregex slice srfi-13 rfc3339) ;;scsh-process ;; dropping scsh-process, it was clobbering posix's process and process* (use directory-utils uuid-lib filepath srfi-19 ) ; linenoise ;; plugs a hole in posix-extras in latter chicken versions (use posix-extras pathname-expand files) (define ##sys#expand-home-path pathname-expand) (define (realpath x) (resolve-pathname (pathname-expand (or x "/dev/null")) )) ;; (include "mimetypes.scm") ; provides ext->mimetype ;; (include "workweekdate.scm") ;; gathered from macosx: ;; cat /etc/apache2/mime.types | grep -v '^#' | perl -ne 'print "(\"$2\" . \"$1\")\n" if /(\S+)\s+(\S+)/' > mimetypes.scm ;; + manual manipulation (define ducttape_ext2mimetype '(("ez" . "application/andrew-inset") ("aw" . "application/applixware") ("atom" . "application/atom+xml") ("atomcat" . "application/atomcat+xml") ("atomsvc" . "application/atomsvc+xml") ("ccxml" . "application/ccxml+xml") ("cdmia" . "application/cdmi-capability") ("cdmic" . "application/cdmi-container") ("cdmid" . "application/cdmi-domain") ("cdmio" . "application/cdmi-object") ("cdmiq" . "application/cdmi-queue") ("cu" . "application/cu-seeme") ("davmount" . "application/davmount+xml") ("dbk" . "application/docbook+xml") ("dssc" . "application/dssc+der") ("xdssc" . "application/dssc+xml") ("ecma" . "application/ecmascript") ("emma" . "application/emma+xml") ("epub" . "application/epub+zip") ("exi" . "application/exi") ("pfr" . "application/font-tdpfr") ("gml" . "application/gml+xml") ("gpx" . "application/gpx+xml") ("gxf" . "application/gxf") ("stk" . "application/hyperstudio") ("ink" . "application/inkml+xml") ("ipfix" . "application/ipfix") ("jar" . "application/java-archive") ("ser" . "application/java-serialized-object") ("class" . "application/java-vm") ("js" . "application/javascript") ("json" . "application/json") ("jsonml" . "application/jsonml+json") ("lostxml" . "application/lost+xml") ("hqx" . "application/mac-binhex40") ("cpt" . "application/mac-compactpro") ("mads" . "application/mads+xml") ("mrc" . "application/marc") ("mrcx" . "application/marcxml+xml") ("ma" . "application/mathematica") ("mathml" . "application/mathml+xml") ("mbox" . "application/mbox") ("mscml" . "application/mediaservercontrol+xml") ("metalink" . "application/metalink+xml") ("meta4" . "application/metalink4+xml") ("mets" . "application/mets+xml") ("mods" . "application/mods+xml") ("m21" . "application/mp21") ("mp4s" . "application/mp4") ("doc" . "application/msword") ("mxf" . "application/mxf") ("bin" . "application/octet-stream") ("oda" . "application/oda") ("opf" . "application/oebps-package+xml") ("ogx" . "application/ogg") ("omdoc" . "application/omdoc+xml") ("onetoc" . "application/onenote") ("oxps" . "application/oxps") ("xer" . "application/patch-ops-error+xml") ("pdf" . "application/pdf") ("pgp" . "application/pgp-encrypted") ("asc" . "application/pgp-signature") ("prf" . "application/pics-rules") ("p10" . "application/pkcs10") ("p7m" . "application/pkcs7-mime") ("p7s" . "application/pkcs7-signature") ("p8" . "application/pkcs8") ("ac" . "application/pkix-attr-cert") ("cer" . "application/pkix-cert") ("crl" . "application/pkix-crl") ("pkipath" . "application/pkix-pkipath") ("pki" . "application/pkixcmp") ("pls" . "application/pls+xml") ("ai" . "application/postscript") ("cww" . "application/prs.cww") ("pskcxml" . "application/pskc+xml") ("rdf" . "application/rdf+xml") ("rif" . "application/reginfo+xml") ("rnc" . "application/relax-ng-compact-syntax") ("rl" . "application/resource-lists+xml") ("rld" . "application/resource-lists-diff+xml") ("rs" . "application/rls-services+xml") ("gbr" . "application/rpki-ghostbusters") ("mft" . "application/rpki-manifest") ("roa" . "application/rpki-roa") ("rsd" . "application/rsd+xml") ("rss" . "application/rss+xml") ("rtf" . "application/rtf") ("sbml" . "application/sbml+xml") ("scq" . "application/scvp-cv-request") ("scs" . "application/scvp-cv-response") ("spq" . "application/scvp-vp-request") ("spp" . "application/scvp-vp-response") ("sdp" . "application/sdp") ("setpay" . "application/set-payment-initiation") ("setreg" . "application/set-registration-initiation") ("shf" . "application/shf+xml") ("smi" . "application/smil+xml") ("rq" . "application/sparql-query") ("srx" . "application/sparql-results+xml") ("gram" . "application/srgs") ("grxml" . "application/srgs+xml") ("sru" . "application/sru+xml") ("ssdl" . "application/ssdl+xml") ("ssml" . "application/ssml+xml") ("tei" . "application/tei+xml") ("tfi" . "application/thraud+xml") ("tsd" . "application/timestamped-data") ("plb" . "application/vnd.3gpp.pic-bw-large") ("psb" . "application/vnd.3gpp.pic-bw-small") ("pvb" . "application/vnd.3gpp.pic-bw-var") ("tcap" . "application/vnd.3gpp2.tcap") ("pwn" . "application/vnd.3m.post-it-notes") ("aso" . "application/vnd.accpac.simply.aso") ("imp" . "application/vnd.accpac.simply.imp") ("acu" . "application/vnd.acucobol") ("atc" . "application/vnd.acucorp") ("air" . "application/vnd.adobe.air-application-installer-package+zip") ("fcdt" . "application/vnd.adobe.formscentral.fcdt") ("fxp" . "application/vnd.adobe.fxp") ("xdp" . "application/vnd.adobe.xdp+xml") ("xfdf" . "application/vnd.adobe.xfdf") ("ahead" . "application/vnd.ahead.space") ("azf" . "application/vnd.airzip.filesecure.azf") ("azs" . "application/vnd.airzip.filesecure.azs") ("azw" . "application/vnd.amazon.ebook") ("acc" . "application/vnd.americandynamics.acc") ("ami" . "application/vnd.amiga.ami") ("apk" . "application/vnd.android.package-archive") ("cii" . "application/vnd.anser-web-certificate-issue-initiation") ("fti" . "application/vnd.anser-web-funds-transfer-initiation") ("atx" . "application/vnd.antix.game-component") ("mpkg" . "application/vnd.apple.installer+xml") ("m3u8" . "application/vnd.apple.mpegurl") ("swi" . "application/vnd.aristanetworks.swi") ("iota" . "application/vnd.astraea-software.iota") ("aep" . "application/vnd.audiograph") ("mpm" . "application/vnd.blueice.multipass") ("bmi" . "application/vnd.bmi") ("rep" . "application/vnd.businessobjects") ("cdxml" . "application/vnd.chemdraw+xml") ("mmd" . "application/vnd.chipnuts.karaoke-mmd") ("cdy" . "application/vnd.cinderella") ("cla" . "application/vnd.claymore") ("rp9" . "application/vnd.cloanto.rp9") ("c4g" . "application/vnd.clonk.c4group") ("c11amc" . "application/vnd.cluetrust.cartomobile-config") ("c11amz" . "application/vnd.cluetrust.cartomobile-config-pkg") ("csp" . "application/vnd.commonspace") ("cdbcmsg" . "application/vnd.contact.cmsg") ("cmc" . "application/vnd.cosmocaller") ("clkx" . "application/vnd.crick.clicker") ("clkk" . "application/vnd.crick.clicker.keyboard") ("clkp" . "application/vnd.crick.clicker.palette") ("clkt" . "application/vnd.crick.clicker.template") ("clkw" . "application/vnd.crick.clicker.wordbank") ("wbs" . "application/vnd.criticaltools.wbs+xml") ("pml" . "application/vnd.ctc-posml") ("ppd" . "application/vnd.cups-ppd") ("car" . "application/vnd.curl.car") ("pcurl" . "application/vnd.curl.pcurl") ("dart" . "application/vnd.dart") ("rdz" . "application/vnd.data-vision.rdz") ("uvf" . "application/vnd.dece.data") ("uvt" . "application/vnd.dece.ttml+xml") ("uvx" . "application/vnd.dece.unspecified") ("uvz" . "application/vnd.dece.zip") ("fe_launch" . "application/vnd.denovo.fcselayout-link") ("dna" . "application/vnd.dna") ("mlp" . "application/vnd.dolby.mlp") ("dpg" . "application/vnd.dpgraph") ("dfac" . "application/vnd.dreamfactory") ("kpxx" . "application/vnd.ds-keypoint") ("ait" . "application/vnd.dvb.ait") ("svc" . "application/vnd.dvb.service") ("geo" . "application/vnd.dynageo") ("mag" . "application/vnd.ecowin.chart") ("nml" . "application/vnd.enliven") ("esf" . "application/vnd.epson.esf") ("msf" . "application/vnd.epson.msf") ("qam" . "application/vnd.epson.quickanime") ("slt" . "application/vnd.epson.salt") ("ssf" . "application/vnd.epson.ssf") ("es3" . "application/vnd.eszigno3+xml") ("ez2" . "application/vnd.ezpix-album") ("ez3" . "application/vnd.ezpix-package") ("fdf" . "application/vnd.fdf") ("mseed" . "application/vnd.fdsn.mseed") ("seed" . "application/vnd.fdsn.seed") ("gph" . "application/vnd.flographit") ("ftc" . "application/vnd.fluxtime.clip") ("fm" . "application/vnd.framemaker") ("fnc" . "application/vnd.frogans.fnc") ("ltf" . "application/vnd.frogans.ltf") ("fsc" . "application/vnd.fsc.weblaunch") ("oas" . "application/vnd.fujitsu.oasys") ("oa2" . "application/vnd.fujitsu.oasys2") ("oa3" . "application/vnd.fujitsu.oasys3") ("fg5" . "application/vnd.fujitsu.oasysgp") ("bh2" . "application/vnd.fujitsu.oasysprs") ("ddd" . "application/vnd.fujixerox.ddd") ("xdw" . "application/vnd.fujixerox.docuworks") ("xbd" . "application/vnd.fujixerox.docuworks.binder") ("fzs" . "application/vnd.fuzzysheet") ("txd" . "application/vnd.genomatix.tuxedo") ("ggb" . "application/vnd.geogebra.file") ("ggt" . "application/vnd.geogebra.tool") ("gex" . "application/vnd.geometry-explorer") ("gxt" . "application/vnd.geonext") ("g2w" . "application/vnd.geoplan") ("g3w" . "application/vnd.geospace") ("gmx" . "application/vnd.gmx") ("kml" . "application/vnd.google-earth.kml+xml") ("kmz" . "application/vnd.google-earth.kmz") ("gqf" . "application/vnd.grafeq") ("gac" . "application/vnd.groove-account") ("ghf" . "application/vnd.groove-help") ("gim" . "application/vnd.groove-identity-message") ("grv" . "application/vnd.groove-injector") ("gtm" . "application/vnd.groove-tool-message") ("tpl" . "application/vnd.groove-tool-template") ("vcg" . "application/vnd.groove-vcard") ("hal" . "application/vnd.hal+xml") ("zmm" . "application/vnd.handheld-entertainment+xml") ("hbci" . "application/vnd.hbci") ("les" . "application/vnd.hhe.lesson-player") ("hpgl" . "application/vnd.hp-hpgl") ("hpid" . "application/vnd.hp-hpid") ("hps" . "application/vnd.hp-hps") ("jlt" . "application/vnd.hp-jlyt") ("pcl" . "application/vnd.hp-pcl") ("pclxl" . "application/vnd.hp-pclxl") ("sfd-hdstx" . "application/vnd.hydrostatix.sof-data") ("mpy" . "application/vnd.ibm.minipay") ("afp" . "application/vnd.ibm.modcap") ("irm" . "application/vnd.ibm.rights-management") ("sc" . "application/vnd.ibm.secure-container") ("icc" . "application/vnd.iccprofile") ("igl" . "application/vnd.igloader") ("ivp" . "application/vnd.immervision-ivp") ("ivu" . "application/vnd.immervision-ivu") ("igm" . "application/vnd.insors.igm") ("xpw" . "application/vnd.intercon.formnet") ("i2g" . "application/vnd.intergeo") ("qbo" . "application/vnd.intu.qbo") ("qfx" . "application/vnd.intu.qfx") ("rcprofile" . "application/vnd.ipunplugged.rcprofile") ("irp" . "application/vnd.irepository.package+xml") ("xpr" . "application/vnd.is-xpr") ("fcs" . "application/vnd.isac.fcs") ("jam" . "application/vnd.jam") ("rms" . "application/vnd.jcp.javame.midlet-rms") ("jisp" . "application/vnd.jisp") ("joda" . "application/vnd.joost.joda-archive") ("ktz" . "application/vnd.kahootz") ("karbon" . "application/vnd.kde.karbon") ("chrt" . "application/vnd.kde.kchart") ("kfo" . "application/vnd.kde.kformula") ("flw" . "application/vnd.kde.kivio") ("kon" . "application/vnd.kde.kontour") ("kpr" . "application/vnd.kde.kpresenter") ("ksp" . "application/vnd.kde.kspread") ("kwd" . "application/vnd.kde.kword") ("htke" . "application/vnd.kenameaapp") ("kia" . "application/vnd.kidspiration") ("kne" . "application/vnd.kinar") ("skp" . "application/vnd.koan") ("sse" . "application/vnd.kodak-descriptor") ("lasxml" . "application/vnd.las.las+xml") ("lbd" . "application/vnd.llamagraphics.life-balance.desktop") ("lbe" . "application/vnd.llamagraphics.life-balance.exchange+xml") ("123" . "application/vnd.lotus-1-2-3") ("apr" . "application/vnd.lotus-approach") ("pre" . "application/vnd.lotus-freelance") ("nsf" . "application/vnd.lotus-notes") ("org" . "application/vnd.lotus-organizer") ("scm" . "application/vnd.lotus-screencam") ("lwp" . "application/vnd.lotus-wordpro") ("portpkg" . "application/vnd.macports.portpkg") ("mcd" . "application/vnd.mcd") ("mc1" . "application/vnd.medcalcdata") ("cdkey" . "application/vnd.mediastation.cdkey") ("mwf" . "application/vnd.mfer") ("mfm" . "application/vnd.mfmp") ("flo" . "application/vnd.micrografx.flo") ("igx" . "application/vnd.micrografx.igx") ("mif" . "application/vnd.mif") ("daf" . "application/vnd.mobius.daf") ("dis" . "application/vnd.mobius.dis") ("mbk" . "application/vnd.mobius.mbk") ("mqy" . "application/vnd.mobius.mqy") ("msl" . "application/vnd.mobius.msl") ("plc" . "application/vnd.mobius.plc") ("txf" . "application/vnd.mobius.txf") ("mpn" . "application/vnd.mophun.application") ("mpc" . "application/vnd.mophun.certificate") ("xul" . "application/vnd.mozilla.xul+xml") ("cil" . "application/vnd.ms-artgalry") ("cab" . "application/vnd.ms-cab-compressed") ("xls" . "application/vnd.ms-excel") ("xlam" . "application/vnd.ms-excel.addin.macroenabled.12") ("xlsb" . "application/vnd.ms-excel.sheet.binary.macroenabled.12") ("xlsm" . "application/vnd.ms-excel.sheet.macroenabled.12") ("xltm" . "application/vnd.ms-excel.template.macroenabled.12") ("eot" . "application/vnd.ms-fontobject") ("chm" . "application/vnd.ms-htmlhelp") ("ims" . "application/vnd.ms-ims") ("lrm" . "application/vnd.ms-lrm") ("thmx" . "application/vnd.ms-officetheme") ("cat" . "application/vnd.ms-pki.seccat") ("stl" . "application/vnd.ms-pki.stl") ("ppt" . "application/vnd.ms-powerpoint") ("ppam" . "application/vnd.ms-powerpoint.addin.macroenabled.12") ("pptm" . "application/vnd.ms-powerpoint.presentation.macroenabled.12") ("sldm" . "application/vnd.ms-powerpoint.slide.macroenabled.12") ("ppsm" . "application/vnd.ms-powerpoint.slideshow.macroenabled.12") ("potm" . "application/vnd.ms-powerpoint.template.macroenabled.12") ("mpp" . "application/vnd.ms-project") ("docm" . "application/vnd.ms-word.document.macroenabled.12") ("dotm" . "application/vnd.ms-word.template.macroenabled.12") ("wps" . "application/vnd.ms-works") ("wpl" . "application/vnd.ms-wpl") ("xps" . "application/vnd.ms-xpsdocument") ("mseq" . "application/vnd.mseq") ("mus" . "application/vnd.musician") ("msty" . "application/vnd.muvee.style") ("taglet" . "application/vnd.mynfc") ("nlu" . "application/vnd.neurolanguage.nlu") ("ntf" . "application/vnd.nitf") ("nnd" . "application/vnd.noblenet-directory") ("nns" . "application/vnd.noblenet-sealer") ("nnw" . "application/vnd.noblenet-web") ("ngdat" . "application/vnd.nokia.n-gage.data") ("n-gage" . "application/vnd.nokia.n-gage.symbian.install") ("rpst" . "application/vnd.nokia.radio-preset") ("rpss" . "application/vnd.nokia.radio-presets") ("edm" . "application/vnd.novadigm.edm") ("edx" . "application/vnd.novadigm.edx") ("ext" . "application/vnd.novadigm.ext") ("odc" . "application/vnd.oasis.opendocument.chart") ("otc" . "application/vnd.oasis.opendocument.chart-template") ("odb" . "application/vnd.oasis.opendocument.database") ("odf" . "application/vnd.oasis.opendocument.formula") ("odft" . "application/vnd.oasis.opendocument.formula-template") ("odg" . "application/vnd.oasis.opendocument.graphics") ("otg" . "application/vnd.oasis.opendocument.graphics-template") ("odi" . "application/vnd.oasis.opendocument.image") ("oti" . "application/vnd.oasis.opendocument.image-template") ("odp" . "application/vnd.oasis.opendocument.presentation") ("otp" . "application/vnd.oasis.opendocument.presentation-template") ("ods" . "application/vnd.oasis.opendocument.spreadsheet") ("ots" . "application/vnd.oasis.opendocument.spreadsheet-template") ("odt" . "application/vnd.oasis.opendocument.text") ("odm" . "application/vnd.oasis.opendocument.text-master") ("ott" . "application/vnd.oasis.opendocument.text-template") ("oth" . "application/vnd.oasis.opendocument.text-web") ("xo" . "application/vnd.olpc-sugar") ("dd2" . "application/vnd.oma.dd2+xml") ("oxt" . "application/vnd.openofficeorg.extension") ("pptx" . "application/vnd.openxmlformats-officedocument.presentationml.presentation") ("sldx" . "application/vnd.openxmlformats-officedocument.presentationml.slide") ("ppsx" . "application/vnd.openxmlformats-officedocument.presentationml.slideshow") ("potx" . "application/vnd.openxmlformats-officedocument.presentationml.template") ("xlsx" . "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet") ("xltx" . "application/vnd.openxmlformats-officedocument.spreadsheetml.template") ("docx" . "application/vnd.openxmlformats-officedocument.wordprocessingml.document") ("dotx" . "application/vnd.openxmlformats-officedocument.wordprocessingml.template") ("mgp" . "application/vnd.osgeo.mapguide.package") ("dp" . "application/vnd.osgi.dp") ("esa" . "application/vnd.osgi.subsystem") ("pdb" . "application/vnd.palm") ("paw" . "application/vnd.pawaafile") ("str" . "application/vnd.pg.format") ("ei6" . "application/vnd.pg.osasli") ("efif" . "application/vnd.picsel") ("wg" . "application/vnd.pmi.widget") ("plf" . "application/vnd.pocketlearn") ("pbd" . "application/vnd.powerbuilder6") ("box" . "application/vnd.previewsystems.box") ("mgz" . "application/vnd.proteus.magazine") ("qps" . "application/vnd.publishare-delta-tree") ("ptid" . "application/vnd.pvi.ptid1") ("qxd" . "application/vnd.quark.quarkxpress") ("bed" . "application/vnd.realvnc.bed") ("mxl" . "application/vnd.recordare.musicxml") ("musicxml" . "application/vnd.recordare.musicxml+xml") ("cryptonote" . "application/vnd.rig.cryptonote") ("cod" . "application/vnd.rim.cod") ("rm" . "application/vnd.rn-realmedia") ("rmvb" . "application/vnd.rn-realmedia-vbr") ("link66" . "application/vnd.route66.link66+xml") ("st" . "application/vnd.sailingtracker.track") ("see" . "application/vnd.seemail") ("sema" . "application/vnd.sema") ("semd" . "application/vnd.semd") ("semf" . "application/vnd.semf") ("ifm" . "application/vnd.shana.informed.formdata") ("itp" . "application/vnd.shana.informed.formtemplate") ("iif" . "application/vnd.shana.informed.interchange") ("ipk" . "application/vnd.shana.informed.package") ("twd" . "application/vnd.simtech-mindmapper") ("mmf" . "application/vnd.smaf") ("teacher" . "application/vnd.smart.teacher") ("sdkm" . "application/vnd.solent.sdkm+xml") ("dxp" . "application/vnd.spotfire.dxp") ("sfs" . "application/vnd.spotfire.sfs") ("sdc" . "application/vnd.stardivision.calc") ("sda" . "application/vnd.stardivision.draw") ("sdd" . "application/vnd.stardivision.impress") ("smf" . "application/vnd.stardivision.math") ("sdw" . "application/vnd.stardivision.writer") ("sgl" . "application/vnd.stardivision.writer-global") ("smzip" . "application/vnd.stepmania.package") ("sm" . "application/vnd.stepmania.stepchart") ("sxc" . "application/vnd.sun.xml.calc") ("stc" . "application/vnd.sun.xml.calc.template") ("sxd" . "application/vnd.sun.xml.draw") ("std" . "application/vnd.sun.xml.draw.template") ("sxi" . "application/vnd.sun.xml.impress") ("sti" . "application/vnd.sun.xml.impress.template") ("sxm" . "application/vnd.sun.xml.math") ("sxw" . "application/vnd.sun.xml.writer") ("sxg" . "application/vnd.sun.xml.writer.global") ("stw" . "application/vnd.sun.xml.writer.template") ("sus" . "application/vnd.sus-calendar") ("svd" . "application/vnd.svd") ("sis" . "application/vnd.symbian.install") ("xsm" . "application/vnd.syncml+xml") ("bdm" . "application/vnd.syncml.dm+wbxml") ("xdm" . "application/vnd.syncml.dm+xml") ("tao" . "application/vnd.tao.intent-module-archive") ("pcap" . "application/vnd.tcpdump.pcap") ("tmo" . "application/vnd.tmobile-livetv") ("tpt" . "application/vnd.trid.tpt") ("mxs" . "application/vnd.triscape.mxs") ("tra" . "application/vnd.trueapp") ("ufd" . "application/vnd.ufdl") ("utz" . "application/vnd.uiq.theme") ("umj" . "application/vnd.umajin") ("unityweb" . "application/vnd.unity") ("uoml" . "application/vnd.uoml+xml") ("vcx" . "application/vnd.vcx") ("vsd" . "application/vnd.visio") ("vis" . "application/vnd.visionary") ("vsf" . "application/vnd.vsf") ("wbxml" . "application/vnd.wap.wbxml") ("wmlc" . "application/vnd.wap.wmlc") ("wmlsc" . "application/vnd.wap.wmlscriptc") ("wtb" . "application/vnd.webturbo") ("nbp" . "application/vnd.wolfram.player") ("wpd" . "application/vnd.wordperfect") ("wqd" . "application/vnd.wqd") ("stf" . "application/vnd.wt.stf") ("xar" . "application/vnd.xara") ("xfdl" . "application/vnd.xfdl") ("hvd" . "application/vnd.yamaha.hv-dic") ("hvs" . "application/vnd.yamaha.hv-script") ("hvp" . "application/vnd.yamaha.hv-voice") ("osf" . "application/vnd.yamaha.openscoreformat") ("osfpvg" . "application/vnd.yamaha.openscoreformat.osfpvg+xml") ("saf" . "application/vnd.yamaha.smaf-audio") ("spf" . "application/vnd.yamaha.smaf-phrase") ("cmp" . "application/vnd.yellowriver-custom-menu") ("zir" . "application/vnd.zul") ("zaz" . "application/vnd.zzazz.deck+xml") ("vxml" . "application/voicexml+xml") ("wgt" . "application/widget") ("hlp" . "application/winhlp") ("wsdl" . "application/wsdl+xml") ("wspolicy" . "application/wspolicy+xml") ("7z" . "application/x-7z-compressed") ("abw" . "application/x-abiword") ("ace" . "application/x-ace-compressed") ("dmg" . "application/x-apple-diskimage") ("aab" . "application/x-authorware-bin") ("aam" . "application/x-authorware-map") ("aas" . "application/x-authorware-seg") ("bcpio" . "application/x-bcpio") ("torrent" . "application/x-bittorrent") ("blb" . "application/x-blorb") ("bz" . "application/x-bzip") ("bz2" . "application/x-bzip2") ("cbr" . "application/x-cbr") ("vcd" . "application/x-cdlink") ("cfs" . "application/x-cfs-compressed") ("chat" . "application/x-chat") ("pgn" . "application/x-chess-pgn") ("nsc" . "application/x-conference") ("cpio" . "application/x-cpio") ("csh" . "application/x-csh") ("deb" . "application/x-debian-package") ("dgc" . "application/x-dgc-compressed") ("dir" . "application/x-director") ("wad" . "application/x-doom") ("ncx" . "application/x-dtbncx+xml") ("dtb" . "application/x-dtbook+xml") ("res" . "application/x-dtbresource+xml") ("dvi" . "application/x-dvi") ("evy" . "application/x-envoy") ("eva" . "application/x-eva") ("bdf" . "application/x-font-bdf") ("gsf" . "application/x-font-ghostscript") ("psf" . "application/x-font-linux-psf") ("otf" . "application/x-font-otf") ("pcf" . "application/x-font-pcf") ("snf" . "application/x-font-snf") ("ttf" . "application/x-font-ttf") ("pfa" . "application/x-font-type1") ("woff" . "application/x-font-woff") ("arc" . "application/x-freearc") ("spl" . "application/x-futuresplash") ("gca" . "application/x-gca-compressed") ("ulx" . "application/x-glulx") ("gnumeric" . "application/x-gnumeric") ("gramps" . "application/x-gramps-xml") ("gtar" . "application/x-gtar") ("hdf" . "application/x-hdf") ("install" . "application/x-install-instructions") ("iso" . "application/x-iso9660-image") ("jnlp" . "application/x-java-jnlp-file") ("latex" . "application/x-latex") ("lzh" . "application/x-lzh-compressed") ("mie" . "application/x-mie") ("prc" . "application/x-mobipocket-ebook") ("m3u8" . "application/x-mpegurl") ("application" . "application/x-ms-application") ("lnk" . "application/x-ms-shortcut") ("wmd" . "application/x-ms-wmd") ("wmz" . "application/x-ms-wmz") ("xbap" . "application/x-ms-xbap") ("mdb" . "application/x-msaccess") ("obd" . "application/x-msbinder") ("crd" . "application/x-mscardfile") ("clp" . "application/x-msclip") ("exe" . "application/x-msdownload") ("mvb" . "application/x-msmediaview") ("wmf" . "application/x-msmetafile") ("mny" . "application/x-msmoney") ("pub" . "application/x-mspublisher") ("scd" . "application/x-msschedule") ("trm" . "application/x-msterminal") ("wri" . "application/x-mswrite") ("nc" . "application/x-netcdf") ("nzb" . "application/x-nzb") ("p12" . "application/x-pkcs12") ("p7b" . "application/x-pkcs7-certificates") ("p7r" . "application/x-pkcs7-certreqresp") ("rar" . "application/x-rar-compressed") ("ris" . "application/x-research-info-systems") ("sh" . "application/x-sh") ("shar" . "application/x-shar") ("swf" . "application/x-shockwave-flash") ("xap" . "application/x-silverlight-app") ("sql" . "application/x-sql") ("sit" . "application/x-stuffit") ("sitx" . "application/x-stuffitx") ("srt" . "application/x-subrip") ("sv4cpio" . "application/x-sv4cpio") ("sv4crc" . "application/x-sv4crc") ("t3" . "application/x-t3vm-image") ("gam" . "application/x-tads") ("tar" . "application/x-tar") ("tcl" . "application/x-tcl") ("tex" . "application/x-tex") ("tfm" . "application/x-tex-tfm") ("texinfo" . "application/x-texinfo") ("obj" . "application/x-tgif") ("ustar" . "application/x-ustar") ("src" . "application/x-wais-source") ("der" . "application/x-x509-ca-cert") ("fig" . "application/x-xfig") ("xlf" . "application/x-xliff+xml") ("xpi" . "application/x-xpinstall") ("xz" . "application/x-xz") ("z1" . "application/x-zmachine") ("xaml" . "application/xaml+xml") ("xdf" . "application/xcap-diff+xml") ("xenc" . "application/xenc+xml") ("xhtml" . "application/xhtml+xml") ("xml" . "application/xml") ("dtd" . "application/xml-dtd") ("xop" . "application/xop+xml") ("xpl" . "application/xproc+xml") ("xslt" . "application/xslt+xml") ("xspf" . "application/xspf+xml") ("mxml" . "application/xv+xml") ("yang" . "application/yang") ("yin" . "application/yin+xml") ("zip" . "application/zip") ("adp" . "audio/adpcm") ("au" . "audio/basic") ("mid" . "audio/midi") ("mp4a" . "audio/mp4") ("m4a" . "audio/mp4a-latm") ("mpga" . "audio/mpeg") ("oga" . "audio/ogg") ("s3m" . "audio/s3m") ("sil" . "audio/silk") ("uva" . "audio/vnd.dece.audio") ("eol" . "audio/vnd.digital-winds") ("dra" . "audio/vnd.dra") ("dts" . "audio/vnd.dts") ("dtshd" . "audio/vnd.dts.hd") ("lvp" . "audio/vnd.lucent.voice") ("pya" . "audio/vnd.ms-playready.media.pya") ("ecelp4800" . "audio/vnd.nuera.ecelp4800") ("ecelp7470" . "audio/vnd.nuera.ecelp7470") ("ecelp9600" . "audio/vnd.nuera.ecelp9600") ("rip" . "audio/vnd.rip") ("weba" . "audio/webm") ("aac" . "audio/x-aac") ("aif" . "audio/x-aiff") ("caf" . "audio/x-caf") ("flac" . "audio/x-flac") ("mka" . "audio/x-matroska") ("m3u" . "audio/x-mpegurl") ("wax" . "audio/x-ms-wax") ("wma" . "audio/x-ms-wma") ("ram" . "audio/x-pn-realaudio") ("rmp" . "audio/x-pn-realaudio-plugin") ("wav" . "audio/x-wav") ("xm" . "audio/xm") ("cdx" . "chemical/x-cdx") ("cif" . "chemical/x-cif") ("cmdf" . "chemical/x-cmdf") ("cml" . "chemical/x-cml") ("csml" . "chemical/x-csml") ("xyz" . "chemical/x-xyz") ("bmp" . "image/bmp") ("cgm" . "image/cgm") ("g3" . "image/g3fax") ("gif" . "image/gif") ("ief" . "image/ief") ("jp2" . "image/jp2") ("jpeg" . "image/jpeg") ("ktx" . "image/ktx") ("pict" . "image/pict") ("png" . "image/png") ("btif" . "image/prs.btif") ("sgi" . "image/sgi") ("svg" . "image/svg+xml") ("tiff" . "image/tiff") ("psd" . "image/vnd.adobe.photoshop") ("uvi" . "image/vnd.dece.graphic") ("sub" . "image/vnd.dvb.subtitle") ("djvu" . "image/vnd.djvu") ("dwg" . "image/vnd.dwg") ("dxf" . "image/vnd.dxf") ("fbs" . "image/vnd.fastbidsheet") ("fpx" . "image/vnd.fpx") ("fst" . "image/vnd.fst") ("mmr" . "image/vnd.fujixerox.edmics-mmr") ("rlc" . "image/vnd.fujixerox.edmics-rlc") ("mdi" . "image/vnd.ms-modi") ("wdp" . "image/vnd.ms-photo") ("npx" . "image/vnd.net-fpx") ("wbmp" . "image/vnd.wap.wbmp") ("xif" . "image/vnd.xiff") ("webp" . "image/webp") ("3ds" . "image/x-3ds") ("ras" . "image/x-cmu-raster") ("cmx" . "image/x-cmx") ("fh" . "image/x-freehand") ("ico" . "image/x-icon") ("pntg" . "image/x-macpaint") ("sid" . "image/x-mrsid-image") ("pcx" . "image/x-pcx") ("pic" . "image/x-pict") ("pnm" . "image/x-portable-anymap") ("pbm" . "image/x-portable-bitmap") ("pgm" . "image/x-portable-graymap") ("ppm" . "image/x-portable-pixmap") ("qtif" . "image/x-quicktime") ("rgb" . "image/x-rgb") ("tga" . "image/x-tga") ("xbm" . "image/x-xbitmap") ("xpm" . "image/x-xpixmap") ("xwd" . "image/x-xwindowdump") ("eml" . "message/rfc822") ("igs" . "model/iges") ("msh" . "model/mesh") ("dae" . "model/vnd.collada+xml") ("dwf" . "model/vnd.dwf") ("gdl" . "model/vnd.gdl") ("gtw" . "model/vnd.gtw") ("mts" . "model/vnd.mts") ("vtu" . "model/vnd.vtu") ("wrl" . "model/vrml") ("x3db" . "model/x3d+binary") ("x3dv" . "model/x3d+vrml") ("x3d" . "model/x3d+xml") ("manifest" . "text/cache-manifest") ("appcache" . "text/cache-manifest") ("ics" . "text/calendar") ("css" . "text/css") ("csv" . "text/csv") ("html" . "text/html") ("n3" . "text/n3") ("txt" . "text/plain") ("dsc" . "text/prs.lines.tag") ("rtx" . "text/richtext") ("sgml" . "text/sgml") ("tsv" . "text/tab-separated-values") ("t" . "text/troff") ("ttl" . "text/turtle") ("uri" . "text/uri-list") ("vcard" . "text/vcard") ("curl" . "text/vnd.curl") ("dcurl" . "text/vnd.curl.dcurl") ("scurl" . "text/vnd.curl.scurl") ("mcurl" . "text/vnd.curl.mcurl") ("sub" . "text/vnd.dvb.subtitle") ("fly" . "text/vnd.fly") ("flx" . "text/vnd.fmi.flexstor") ("gv" . "text/vnd.graphviz") ("3dml" . "text/vnd.in3d.3dml") ("spot" . "text/vnd.in3d.spot") ("jad" . "text/vnd.sun.j2me.app-descriptor") ("wml" . "text/vnd.wap.wml") ("wmls" . "text/vnd.wap.wmlscript") ("s" . "text/x-asm") ("c" . "text/x-c") ("f" . "text/x-fortran") ("java" . "text/x-java-source") ("opml" . "text/x-opml") ("p" . "text/x-pascal") ("nfo" . "text/x-nfo") ("etx" . "text/x-setext") ("sfv" . "text/x-sfv") ("uu" . "text/x-uuencode") ("vcs" . "text/x-vcalendar") ("vcf" . "text/x-vcard") ("3gp" . "video/3gpp") ("3g2" . "video/3gpp2") ("h261" . "video/h261") ("h263" . "video/h263") ("h264" . "video/h264") ("jpgv" . "video/jpeg") ("jpm" . "video/jpm") ("mj2" . "video/mj2") ("ts" . "video/mp2t") ("mp4" . "video/mp4") ("mpeg" . "video/mpeg") ("ogv" . "video/ogg") ("qt" . "video/quicktime") ("uvh" . "video/vnd.dece.hd") ("uvm" . "video/vnd.dece.mobile") ("uvp" . "video/vnd.dece.pd") ("uvs" . "video/vnd.dece.sd") ("uvv" . "video/vnd.dece.video") ("dvb" . "video/vnd.dvb.file") ("fvt" . "video/vnd.fvt") ("mxu" . "video/vnd.mpegurl") ("pyv" . "video/vnd.ms-playready.media.pyv") ("uvu" . "video/vnd.uvvu.mp4") ("viv" . "video/vnd.vivo") ("dv" . "video/x-dv") ("webm" . "video/webm") ("f4v" . "video/x-f4v") ("fli" . "video/x-fli") ("flv" . "video/x-flv") ("m4v" . "video/x-m4v") ("mkv" . "video/x-matroska") ("mng" . "video/x-mng") ("asf" . "video/x-ms-asf") ("vob" . "video/x-ms-vob") ("wm" . "video/x-ms-wm") ("wmv" . "video/x-ms-wmv") ("wmx" . "video/x-ms-wmx") ("wvx" . "video/x-ms-wvx") ("avi" . "video/x-msvideo") ("movie" . "video/x-sgi-movie") ("smv" . "video/x-smv") ("ice" . "x-conference/x-cooltalk"))) (use srfi-19) (use test) ;;(use format) (use regex) ;(declare (unit wwdate)) ;; utility procedures to convert among ;; different ways to express date (wwdate, seconds since epoch, isodate) ;; ;; samples: ;; isodate -> "2016-01-01" ;; wwdate -> "16ww01.5" ;; seconds -> 1451631600 ;; procedures provided: ;; ==================== ;; seconds->isodate ;; seconds->wwdate ;; ;; isodate->seconds ;; isodate->wwdate ;; ;; wwdate->seconds ;; wwdate->isodate ;; srfi-19 used extensively; this doc is better tha the eggref: ;; http://srfi.schemers.org/srfi-19/srfi-19.html ;; Author: brandon.j.barclay@intel.com 16ww18.6 (define (date->seconds date) (inexact->exact (string->number (date->string date "~s")))) (define (seconds->isodate seconds) (let* ((date (seconds->date seconds)) (result (date->string date "~Y-~m-~d"))) result)) (define (isodate->seconds isodate) "Takes a string input of the form 'YY-MM-DD' or 'YYYY-MM-DD' and returns epoch time; for YY, assume after Y2K" (let* ((numlist (map string->number (string-split isodate "-"))) (raw-year (car numlist)) (year (if (< raw-year 100) (+ raw-year 2000) raw-year)) (month (list-ref numlist 1)) (day (list-ref numlist 2)) (date (make-date 0 0 0 0 day month year)) (seconds (date->seconds date))) seconds)) ;; adapted from perl Intel::WorkWeek perl module ;; workweek year consists of numbered weeks starting from week 1 ;; days of week are numbered starting from 0 on sunday ;; weeks begin on sunday- day number 0 and end saturday- day 6 ;; week 1 is defined as the week containing jan 1 of the year ;; workweek year does not match calendar year in workweek 1 ;; since workweek 1 contains jan1 and workweek begins sunday, ;; days prior to jan1 in workweek 1 belong to the next workweek year (define (seconds->wwdate-values seconds) (define (date-difference->seconds d1 d2) (- (date->seconds d1) (date->seconds d2))) (let* ((thisdate (seconds->date seconds)) (thisdow (string->number (date->string thisdate "~w"))) (year (date-year thisdate)) ;; intel workweek 1 begins on sunday of week containing jan1 (jan1 (make-date 0 0 0 0 1 1 year)) (jan1dow (date-week-day jan1)) (ww01 (date-subtract-duration jan1 (seconds->time (* 60 60 24 jan1dow)))) (ww01_delta_seconds (date-difference->seconds thisdate ww01)) (wwnum_initial (inexact->exact (add1 (floor (/ ww01_delta_seconds 24 3600 7) )))) ;; we could be in ww1 of next year (this-saturday (seconds->date (+ seconds (* 60 60 24 (- 6 thisdow))))) (this-week-ends-next-year? (> (date-year this-saturday) year)) (intelyear (if this-week-ends-next-year? (add1 year) year)) (intelweek (if this-week-ends-next-year? 1 wwnum_initial))) (values intelyear intelweek thisdow))) (define (string-leftpad in width pad-char) (let* ((unpadded-str (->string in)) (padlen_temp (- width (string-length unpadded-str))) (padlen (if (< padlen_temp 0) 0 padlen_temp)) (padding (make-string padlen pad-char))) (conc padding unpadded-str))) (define (string-rightpad in width pad-char) (let* ((unpadded-str (->string in)) (padlen_temp (- width (string-length unpadded-str))) (padlen (if (< padlen_temp 0) 0 padlen_temp)) (padding (make-string padlen pad-char))) (conc unpadded-str padding))) (define (zeropad num width) (string-leftpad num width #\0)) (define (seconds->wwdate seconds) (let-values (((intelyear intelweek day-of-week-num) (seconds->wwdate-values seconds))) (let ((intelyear-str (zeropad (->string (if (> intelyear 1999) (- intelyear 2000) intelyear)) 2)) (intelweek-str (zeropad (->string intelweek) 2)) (dow-str (->string day-of-week-num))) (conc intelyear-str "ww" intelweek-str "." dow-str)))) (define (isodate->wwdate isodate) (seconds->wwdate (isodate->seconds isodate))) (define (wwdate->seconds wwdate) (let ((match (string-match "^(\\d+)ww(\\d+).(\\d)$" wwdate))) (if (not match) #f (let* ( (intelyear-raw (string->number (list-ref match 1))) (intelyear (if (< intelyear-raw 100) (+ intelyear-raw 2000) intelyear-raw)) (intelww (string->number (list-ref match 2))) (dayofweek (string->number (list-ref match 3))) (day-of-seconds (* 60 60 24 )) (week-of-seconds (* day-of-seconds 7)) ;; get seconds at ww1.0 (new-years-date (make-date 0 0 0 0 1 1 intelyear)) (new-years-seconds (date->seconds new-years-date)) (new-years-dayofweek (date-week-day new-years-date)) (ww1.0_seconds (- new-years-seconds (* day-of-seconds new-years-dayofweek))) (workweek-adjustment (* week-of-seconds (sub1 intelww))) (weekday-adjustment (* dayofweek day-of-seconds)) (result (+ ww1.0_seconds workweek-adjustment weekday-adjustment))) result)))) (define (wwdate->isodate wwdate) (seconds->isodate (wwdate->seconds wwdate))) (define (current-wwdate) (seconds->wwdate (current-seconds))) (define (current-isodate) (seconds->isodate (current-seconds))) (define (wwdate-tests) (test-group "date conversion tests" (let ((test-table '(("16ww01.5" . "2016-01-01") ("16ww18.5" . "2016-04-29") ("1999ww33.5" . "1999-08-13") ("16ww18.4" . "2016-04-28") ("16ww18.3" . "2016-04-27") ("13ww01.0" . "2012-12-30") ("13ww52.6" . "2013-12-28") ("16ww53.3" . "2016-12-28")))) (for-each (lambda (test-pair) (let ((wwdate (car test-pair)) (isodate (cdr test-pair))) (test (conc "(isodate->wwdate "isodate ") => "wwdate) wwdate (isodate->wwdate isodate)) (test (conc "(wwdate->isodate "wwdate ") => "isodate) isodate (wwdate->isodate wwdate)))) test-table)))) (define (ext->mimetype ext) (let ((x (assoc ext ducttape_ext2mimetype))) (if x (cdr x) "text/plain"))) (define ducttape-lib-version 1.00) (define (toplevel-command sym proc) (lambda () #f)) ;; like shell "which" command (define (find-exe exe) (let* ((path-items (string-split (or (get-environment-variable "PATH") "") ":"))) (let loop ((rest-path-items path-items)) (if (null? rest-path-items) #f (let* ((this-dir (car rest-path-items)) (next-rest (cdr rest-path-items)) (candidate (conc this-dir "/" exe))) (if (file-execute-access? candidate) candidate (loop next-rest))))))) ;;;; define some handy globals ;; resolve fullpath to this script or binary. (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)))) ;;(foo (begin (print "hello "(find-exe "/bin/sh") #f))) (fullpath (or (find-exe this-script) (realpath this-script)))) fullpath)) (define *this-exe-fullpath* (__get-this-script-fullpath)) (define *this-exe-dir* (pathname-directory *this-exe-fullpath*)) (define *this-exe-name* (pathname-strip-directory *this-exe-fullpath*)) ;;;; utility procedures ;; begin credit: megatest's process.scm (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) |
︙ | ︙ | |||
580 581 582 583 584 585 586 | (for-each embed-image images-with-content-id-alist) (boundary) (close-output-port sendmail-port))) (do-or-die "/usr/sbin/sendmail -t" stdin-proc: sendmail-proc)) | < < < < < < < < < < < < < < < < < < | 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 | (for-each embed-image images-with-content-id-alist) (boundary) (close-output-port sendmail-port))) (do-or-die "/usr/sbin/sendmail -t" stdin-proc: sendmail-proc)) ;;;; process command line options ;; get command line switches (have no subsequent arg; eg. [-foo]) ;; assumes these are switches without arguments ;; will return list of matches ;; removes matches from command-line-arguments parameter |
︙ | ︙ | |||
635 636 637 638 639 640 641 642 643 644 645 646 647 648 | (if (list? default) (if (equal? default kwval) (loop (list (cadr args-remaining)) (cddr args-remaining) args-to-return) (loop (cons (cadr args-remaining) kwval) (cddr args-remaining) args-to-return)) (loop (cadr args-remaining) (cddr args-remaining) args-to-return))) (else (loop kwval (cdr args-remaining) (cons (car args-remaining) args-to-return)))))) ;; get command line switches (have a subsequent arg; eg. [-foo bar]) ;; assumes these are switches without arguments ;; will return list of arguments to matches ;; removes matches from command-line-arguments parameter | > > > > > > > > > > > > > > > > | 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 | (if (list? default) (if (equal? default kwval) (loop (list (cadr args-remaining)) (cddr args-remaining) args-to-return) (loop (cons (cadr args-remaining) kwval) (cddr args-remaining) args-to-return)) (loop (cadr args-remaining) (cddr args-remaining) args-to-return))) (else (loop kwval (cdr args-remaining) (cons (car args-remaining) args-to-return)))))) (define (get-cli-arg arg #!key (default #f) (is-list #f)) (let* ((temp (skim-cmdline-opts-withargs-by-regex arg))) (if (> (length temp) 0) (if is-list temp (car temp)) default))) (define (get-cli-switch arg) (let ((temp (skim-cmdline-opts-noarg-by-regex arg))) (if (> (length temp) 0) (car temp) #f))) ;; get command line switches (have a subsequent arg; eg. [-foo bar]) ;; assumes these are switches without arguments ;; will return list of arguments to matches ;; removes matches from command-line-arguments parameter |
︙ | ︙ |
Added emacs.config version [f8d660afb3].
> > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 | ;; Indenting module body code at column 0 (defun scheme-module-indent (state indent-point normal-indent) 0) (put 'module 'scheme-indent-function 'scheme-module-indent) (put 'and-let* 'scheme-indent-function 1) (put 'parameterize 'scheme-indent-function 1) (put 'handle-exceptions 'scheme-indent-function 1) (put 'when 'scheme-indent-function 1) (put 'unless 'scheme-indent-function 1) (put 'match 'scheme-indent-function 1) (put 'let-values 'scheme-indent-function 1) |
Modified env.scm from [d8ef48f13e] to [c7d61e935d].
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 | ;;====================================================================== ;; 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 (if (equal? fname ":memory:") #f (common:file-exists? fname))) (db (open-database fname))) (if (not db-exists) (begin (exec (sql db "CREATE TABLE IF NOT EXISTS envvars ( id INTEGER PRIMARY KEY, context TEXT NOT NULL, var TEXT NOT NULL, val TEXT NOT NULL, CONSTRAINT envvars_constraint UNIQUE (context,var))")))) (set-busy-handler! db (busy-timeout 10000)) db)) ;; save vars in given context, this is NOT incremental by default ;; (define (env:save-env-vars db context #!key (incremental #f)(vardat #f)) (with-transaction |
︙ | ︙ | |||
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 | | | | > > > > > > > > > > > > > > > > > > > > > > > | 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 | (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)) ;; envdelta: a-b (start=a, end=b, get the delta) ;; ofile: #f = write to stdout, else write to file with string name ;; (define (env:envdelta db envdelta ofile) (let ((match (string-split envdelta "-")));; (string-match "([a-z0-9_]+)=([a-z0-9_\\-,]+)" envdelta))) (if (not (null? match)) (let* ((parts match) ;; (string-split equn "-")) (minuend (car parts)) (subtraend (cadr parts)) (added (env:get-added db minuend subtraend)) (removed (env:get-removed db minuend subtraend)) (changed (env:get-changed db minuend subtraend))) ;; (pp (hash-table->alist added)) ;; (pp (hash-table->alist removed)) ;; (pp (hash-table->alist changed)) (if (args:get-arg "-o") (with-output-to-file (args:get-arg "-o") (lambda () (env:print added removed changed))) (env:print added removed changed))) #f))) ;; get list of removed variables between two contexts ;; (define (env:get-removed db contexta contextb) (let ((result (make-hash-table))) (query (for-each-row |
︙ | ︙ | |||
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=?)") | | | 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 | (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].
|
| < < < < < < < |
Added example2/rx.v version [936aacf70e].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | //////////////////////////////////////////////////////////////////////////////// // // Filename: rxuartlite.v // // Project: wbuart32, a full featured UART with simulator // // Purpose: Receive and decode inputs from a single UART line. // // // To interface with this module, connect it to your system clock, // and a UART input. Set the parameter to the number of clocks per // baud. When data becomes available, the o_wr line will be asserted // for one clock cycle. // // This interface only handles 8N1 serial port communications. It does // not handle the break, parity, or frame error conditions. // // // Creator: Dan Gisselquist, Ph.D. // Gisselquist Technology, LLC // //////////////////////////////////////////////////////////////////////////////// // // Copyright (C) 2015-2020, Gisselquist Technology, LLC // // This program is free software (firmware): you can redistribute it and/or // modify it under the terms of the 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 MERCHANTIBILITY or // FITNESS FOR A PARTICULAR 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. (It's in the $(ROOT)/doc directory. Run make with no // target there if the PDF file isn't present.) If not, see // <http://www.gnu.org/licenses/> for a copy. // // License: GPL, v3, as defined and found on www.gnu.org, // http://www.gnu.org/licenses/gpl.html // // //////////////////////////////////////////////////////////////////////////////// // // `default_nettype none // `define RXUL_BIT_ZERO 4'h0 `define RXUL_BIT_ONE 4'h1 `define RXUL_BIT_TWO 4'h2 `define RXUL_BIT_THREE 4'h3 `define RXUL_BIT_FOUR 4'h4 `define RXUL_BIT_FIVE 4'h5 `define RXUL_BIT_SIX 4'h6 `define RXUL_BIT_SEVEN 4'h7 `define RXUL_STOP 4'h8 `define RXUL_WAIT 4'h9 `define RXUL_IDLE 4'hf module rxuartlite(i_clk, i_uart_rx, o_wr, o_data); parameter TIMER_BITS = 10; `ifdef FORMAL parameter [(TIMER_BITS-1):0] CLOCKS_PER_BAUD = 16; // Necessary for formal proof `else parameter [(TIMER_BITS-1):0] CLOCKS_PER_BAUD = 868; // 115200 MBaud at 100MHz `endif localparam TB = TIMER_BITS; input wire i_clk; input wire i_uart_rx; output reg o_wr; output reg [7:0] o_data; wire [(TB-1):0] half_baud; reg [3:0] state; assign half_baud = { 1'b0, CLOCKS_PER_BAUD[(TB-1):1] }; reg [(TB-1):0] baud_counter; reg zero_baud_counter; // Since this is an asynchronous receiver, we need to register our // input a couple of clocks over to avoid any problems with // metastability. We do that here, and then ignore all but the // ck_uart wire. reg q_uart, qq_uart, ck_uart; initial q_uart = 1'b1; initial qq_uart = 1'b1; initial ck_uart = 1'b1; always @(posedge i_clk) { ck_uart, qq_uart, q_uart } <= { qq_uart, q_uart, i_uart_rx }; // Keep track of the number of clocks since the last change. // // This is used to determine if we are in either a break or an idle // condition, as discussed further below. reg [(TB-1):0] chg_counter; initial chg_counter = {(TB){1'b1}}; always @(posedge i_clk) if (qq_uart != ck_uart) chg_counter <= 0; else if (chg_counter != { (TB){1'b1} }) chg_counter <= chg_counter + 1; // Are we in the middle of a baud iterval? Specifically, are we // in the middle of a start bit? Set this to high if so. We'll use // this within our state machine to transition out of the IDLE // state. reg half_baud_time; initial half_baud_time = 0; always @(posedge i_clk) half_baud_time <= (!ck_uart)&&(chg_counter >= half_baud-1'b1-1'b1); initial state = `RXUL_IDLE; always @(posedge i_clk) if (state == `RXUL_IDLE) begin // Idle state, independent of baud counter // By default, just stay in the IDLE state state <= `RXUL_IDLE; if ((!ck_uart)&&(half_baud_time)) // UNLESS: We are in the center of a valid // start bit state <= `RXUL_BIT_ZERO; end else if ((state >= `RXUL_WAIT)&&(ck_uart)) state <= `RXUL_IDLE; else if (zero_baud_counter) begin if (state <= `RXUL_STOP) // Data arrives least significant bit first. // By the time this is clocked in, it's what // you'll have. state <= state + 1; end // Data bit capture logic. // // This is drastically simplified from the state machine above, based // upon: 1) it doesn't matter what it is until the end of a captured // byte, and 2) the data register will flush itself of any invalid // data in all other cases. Hence, let's keep it real simple. reg [7:0] data_reg; always @(posedge i_clk) if ((zero_baud_counter)&&(state != `RXUL_STOP)) data_reg <= { qq_uart, data_reg[7:1] }; // Our data bit logic doesn't need nearly the complexity of all that // work above. Indeed, we only need to know if we are at the end of // a stop bit, in which case we copy the data_reg into our output // data register, o_data, and tell others (for one clock) that data is // available. // initial o_wr = 1'b0; initial o_data = 8'h00; always @(posedge i_clk) if ((zero_baud_counter)&&(state == `RXUL_STOP)&&(ck_uart)) begin o_wr <= 1'b1; o_data <= data_reg; end else o_wr <= 1'b0; // The baud counter // // This is used as a "clock divider" if you will, but the clock needs // to be reset before any byte can be decoded. In all other respects, // we set ourselves up for CLOCKS_PER_BAUD counts between baud // intervals. initial baud_counter = 0; always @(posedge i_clk) if (((state==`RXUL_IDLE))&&(!ck_uart)&&(half_baud_time)) baud_counter <= CLOCKS_PER_BAUD-1'b1; else if (state == `RXUL_WAIT) baud_counter <= 0; else if ((zero_baud_counter)&&(state < `RXUL_STOP)) baud_counter <= CLOCKS_PER_BAUD-1'b1; else if (!zero_baud_counter) baud_counter <= baud_counter-1'b1; // zero_baud_counter // // Rather than testing whether or not (baud_counter == 0) within our // (already too complicated) state transition tables, we use // zero_baud_counter to pre-charge that test on the clock // before--cleaning up some otherwise difficult timing dependencies. initial zero_baud_counter = 1'b1; always @(posedge i_clk) if ((state == `RXUL_IDLE)&&(!ck_uart)&&(half_baud_time)) zero_baud_counter <= 1'b0; else if (state == `RXUL_WAIT) zero_baud_counter <= 1'b1; else if ((zero_baud_counter)&&(state < `RXUL_STOP)) zero_baud_counter <= 1'b0; else if (baud_counter == 1) zero_baud_counter <= 1'b1; `ifdef FORMAL `define FORMAL_VERILATOR `else `ifdef VERILATOR `define FORMAL_VERILATOR `endif `endif `ifdef FORMAL `define ASSUME assume `define ASSERT assert `ifdef VERIFIC (* gclk *) wire gbl_clk; global clocking @(posedge gbl_clk); endclocking `endif localparam F_CKRES = 10; (* anyseq *) wire f_tx_start; (* anyconst *) wire [(F_CKRES-1):0] f_tx_step; reg f_tx_zclk; reg [(TB-1):0] f_tx_timer; wire [7:0] f_rx_newdata; reg [(TB-1):0] f_tx_baud; wire f_tx_zbaud; wire [(TB-1):0] f_max_baud_difference; reg [(TB-1):0] f_baud_difference; reg [(TB+3):0] f_tx_count, f_rx_count; (* anyseq *) wire [7:0] f_tx_data; wire f_txclk; reg [1:0] f_rx_clock; reg [(F_CKRES-1):0] f_tx_clock; reg f_past_valid, f_past_valid_tx; initial f_past_valid = 1'b0; always @(posedge i_clk) f_past_valid <= 1'b1; initial f_rx_clock = 3'h0; always @($global_clock) f_rx_clock <= f_rx_clock + 1'b1; always @(*) assume(i_clk == f_rx_clock[1]); /////////////////////////////////////////////////////////// // // // Generate a transmitted signal // // /////////////////////////////////////////////////////////// // First, calculate the transmit clock localparam [(F_CKRES-1):0] F_MIDSTEP = { 2'b01, {(F_CKRES-2){1'b0}} }; // // Need to allow us to slip by half a baud clock over 10 baud intervals // // (F_STEP / (2^F_CKRES)) * (CLOCKS_PER_BAUD)*10 < CLOCKS_PER_BAUD/2 // F_STEP * 2 * 10 < 2^F_CKRES localparam [(F_CKRES-1):0] F_HALFSTEP= F_MIDSTEP/32; localparam [(F_CKRES-1):0] F_MINSTEP = F_MIDSTEP - F_HALFSTEP + 1; localparam [(F_CKRES-1):0] F_MAXSTEP = F_MIDSTEP + F_HALFSTEP - 1; initial assert(F_MINSTEP <= F_MIDSTEP); initial assert(F_MIDSTEP <= F_MAXSTEP); // assume((f_tx_step >= F_MINSTEP)&&(f_tx_step <= F_MAXSTEP)); // // always @(*) assume((f_tx_step == F_MINSTEP) ||(f_tx_step == F_MIDSTEP) ||(f_tx_step == F_MAXSTEP)); always @($global_clock) f_tx_clock <= f_tx_clock + f_tx_step; assign f_txclk = f_tx_clock[F_CKRES-1]; // initial f_past_valid_tx = 1'b0; always @(posedge f_txclk) f_past_valid_tx <= 1'b1; initial assume(i_uart_rx); ////////////////////////////////////////////// // // // Build a simulated transmitter // // ////////////////////////////////////////////// // // First, the simulated timing generator // parameter TIMER_BITS = 10; // parameter [(TIMER_BITS-1):0] CLOCKS_PER_BAUD = 868; // localparam TB = TIMER_BITS; always @(*) if (f_tx_busy) assume(!f_tx_start); initial f_tx_baud = 0; always @(posedge f_txclk) if ((f_tx_zbaud)&&((f_tx_busy)||(f_tx_start))) f_tx_baud <= CLOCKS_PER_BAUD-1'b1; else if (!f_tx_zbaud) f_tx_baud <= f_tx_baud - 1'b1; always @(*) `ASSERT(f_tx_baud < CLOCKS_PER_BAUD); always @(*) if (!f_tx_busy) `ASSERT(f_tx_baud == 0); assign f_tx_zbaud = (f_tx_baud == 0); // But only if we aren't busy initial assume(f_tx_data == 0); always @(posedge f_txclk) if ((!f_tx_zbaud)||(f_tx_busy)||(!f_tx_start)) assume(f_tx_data == $past(f_tx_data)); // Force the data to change on a clock only always @($global_clock) if ((f_past_valid)&&(!$rose(f_txclk))) assume($stable(f_tx_data)); else if (f_tx_busy) assume($stable(f_tx_data)); // always @($global_clock) if ((!f_past_valid)||(!$rose(f_txclk))) begin assume($stable(f_tx_start)); assume($stable(f_tx_data)); end // // // reg [9:0] f_tx_reg; reg f_tx_busy; // Here's the transmitter itself (roughly) initial f_tx_busy = 1'b0; initial f_tx_reg = 0; always @(posedge f_txclk) if (!f_tx_zbaud) begin `ASSERT(f_tx_busy); end else begin f_tx_reg <= { 1'b0, f_tx_reg[9:1] }; if (f_tx_start) f_tx_reg <= { 1'b1, f_tx_data, 1'b0 }; end // Create a busy flag that we'll use always @(*) if (!f_tx_zbaud) f_tx_busy <= 1'b1; else if (|f_tx_reg) f_tx_busy <= 1'b1; else f_tx_busy <= 1'b0; // // Tie the TX register to the TX data always @(posedge f_txclk) if (f_tx_reg[9]) `ASSERT(f_tx_reg[8:0] == { f_tx_data, 1'b0 }); else if (f_tx_reg[8]) `ASSERT(f_tx_reg[7:0] == f_tx_data[7:0] ); else if (f_tx_reg[7]) `ASSERT(f_tx_reg[6:0] == f_tx_data[7:1] ); else if (f_tx_reg[6]) `ASSERT(f_tx_reg[5:0] == f_tx_data[7:2] ); else if (f_tx_reg[5]) `ASSERT(f_tx_reg[4:0] == f_tx_data[7:3] ); else if (f_tx_reg[4]) `ASSERT(f_tx_reg[3:0] == f_tx_data[7:4] ); else if (f_tx_reg[3]) `ASSERT(f_tx_reg[2:0] == f_tx_data[7:5] ); else if (f_tx_reg[2]) `ASSERT(f_tx_reg[1:0] == f_tx_data[7:6] ); else if (f_tx_reg[1]) `ASSERT(f_tx_reg[0] == f_tx_data[7]); // Our counter since we start initial f_tx_count = 0; always @(posedge f_txclk) if (!f_tx_busy) f_tx_count <= 0; else f_tx_count <= f_tx_count + 1'b1; always @(*) if (f_tx_reg == 10'h0) assume(i_uart_rx); else assume(i_uart_rx == f_tx_reg[0]); // // Make sure the absolute transmit clock timer matches our state // always @(posedge f_txclk) if (!f_tx_busy) begin if ((!f_past_valid_tx)||(!$past(f_tx_busy))) `ASSERT(f_tx_count == 0); end else if (f_tx_reg[9]) `ASSERT(f_tx_count == CLOCKS_PER_BAUD -1 -f_tx_baud); else if (f_tx_reg[8]) `ASSERT(f_tx_count == 2 * CLOCKS_PER_BAUD -1 -f_tx_baud); else if (f_tx_reg[7]) `ASSERT(f_tx_count == 3 * CLOCKS_PER_BAUD -1 -f_tx_baud); else if (f_tx_reg[6]) `ASSERT(f_tx_count == 4 * CLOCKS_PER_BAUD -1 -f_tx_baud); else if (f_tx_reg[5]) `ASSERT(f_tx_count == 5 * CLOCKS_PER_BAUD -1 -f_tx_baud); else if (f_tx_reg[4]) `ASSERT(f_tx_count == 6 * CLOCKS_PER_BAUD -1 -f_tx_baud); else if (f_tx_reg[3]) `ASSERT(f_tx_count == 7 * CLOCKS_PER_BAUD -1 -f_tx_baud); else if (f_tx_reg[2]) `ASSERT(f_tx_count == 8 * CLOCKS_PER_BAUD -1 -f_tx_baud); else if (f_tx_reg[1]) `ASSERT(f_tx_count == 9 * CLOCKS_PER_BAUD -1 -f_tx_baud); else if (f_tx_reg[0]) `ASSERT(f_tx_count == 10 * CLOCKS_PER_BAUD -1 -f_tx_baud); else `ASSERT(f_tx_count == 11 * CLOCKS_PER_BAUD -1 -f_tx_baud); /////////////////////////////////////// // // Receiver // /////////////////////////////////////// // // Count RX clocks since the start of the first stop bit, measured in // rx clocks initial f_rx_count = 0; always @(posedge i_clk) if (state == `RXUL_IDLE) f_rx_count = (!ck_uart) ? (chg_counter+2) : 0; else f_rx_count <= f_rx_count + 1'b1; always @(posedge i_clk) if (state == 0) `ASSERT(f_rx_count == half_baud + (CLOCKS_PER_BAUD-baud_counter)); else if (state == 1) `ASSERT(f_rx_count == half_baud + 2 * CLOCKS_PER_BAUD - baud_counter); else if (state == 2) `ASSERT(f_rx_count == half_baud + 3 * CLOCKS_PER_BAUD - baud_counter); else if (state == 3) `ASSERT(f_rx_count == half_baud + 4 * CLOCKS_PER_BAUD - baud_counter); else if (state == 4) `ASSERT(f_rx_count == half_baud + 5 * CLOCKS_PER_BAUD - baud_counter); else if (state == 5) `ASSERT(f_rx_count == half_baud + 6 * CLOCKS_PER_BAUD - baud_counter); else if (state == 6) `ASSERT(f_rx_count == half_baud + 7 * CLOCKS_PER_BAUD - baud_counter); else if (state == 7) `ASSERT(f_rx_count == half_baud + 8 * CLOCKS_PER_BAUD - baud_counter); else if (state == 8) `ASSERT((f_rx_count == half_baud + 9 * CLOCKS_PER_BAUD - baud_counter) ||(f_rx_count == half_baud + 10 * CLOCKS_PER_BAUD - baud_counter)); always @(*) `ASSERT( ((!zero_baud_counter) &&(state == `RXUL_IDLE) &&(baud_counter == 0)) ||((zero_baud_counter)&&(baud_counter == 0)) ||((!zero_baud_counter)&&(baud_counter != 0))); always @(posedge i_clk) if (!f_past_valid) `ASSERT((state == `RXUL_IDLE)&&(baud_counter == 0) &&(zero_baud_counter)); always @(*) begin `ASSERT({ ck_uart,qq_uart,q_uart,i_uart_rx } != 4'h2); `ASSERT({ ck_uart,qq_uart,q_uart,i_uart_rx } != 4'h4); `ASSERT({ ck_uart,qq_uart,q_uart,i_uart_rx } != 4'h5); `ASSERT({ ck_uart,qq_uart,q_uart,i_uart_rx } != 4'h6); `ASSERT({ ck_uart,qq_uart,q_uart,i_uart_rx } != 4'h9); `ASSERT({ ck_uart,qq_uart,q_uart,i_uart_rx } != 4'ha); `ASSERT({ ck_uart,qq_uart,q_uart,i_uart_rx } != 4'hb); `ASSERT({ ck_uart,qq_uart,q_uart,i_uart_rx } != 4'hd); end always @(posedge i_clk) if ((f_past_valid)&&($past(state) >= `RXUL_WAIT)&&($past(ck_uart))) `ASSERT(state == `RXUL_IDLE); always @(posedge i_clk) if ((f_past_valid)&&($past(state) >= `RXUL_WAIT) &&(($past(state) != `RXUL_IDLE)||(state == `RXUL_IDLE))) `ASSERT(zero_baud_counter); // Calculate an absolute value of the difference between the two baud // clocks always @(posedge i_clk) if ((f_past_valid)&&($past(state)==`RXUL_IDLE)&&(state == `RXUL_IDLE)) begin `ASSERT(($past(ck_uart)) ||(chg_counter <= { 1'b0, CLOCKS_PER_BAUD[(TB-1):1] })); end always @(posedge f_txclk) if (!f_past_valid_tx) `ASSERT((state == `RXUL_IDLE)&&(baud_counter == 0) &&(zero_baud_counter)&&(!f_tx_busy)); wire [(TB+3):0] f_tx_count_two_clocks_ago; assign f_tx_count_two_clocks_ago = f_tx_count - 2; always @(*) if (f_tx_count >= f_rx_count + 2) f_baud_difference = f_tx_count_two_clocks_ago - f_rx_count; else f_baud_difference = f_rx_count - f_tx_count_two_clocks_ago; localparam F_SYNC_DLY = 8; reg [(TB+4+F_CKRES-1):0] f_sub_baud_difference; reg [F_CKRES-1:0] ck_tx_clock; reg [((F_SYNC_DLY-1)*F_CKRES)-1:0] q_tx_clock; reg [TB+3:0] ck_tx_count; reg [(F_SYNC_DLY-1)*(TB+4)-1:0] q_tx_count; initial q_tx_count = 0; initial ck_tx_count = 0; initial q_tx_clock = 0; initial ck_tx_clock = 0; always @($global_clock) { ck_tx_clock, q_tx_clock } <= { q_tx_clock, f_tx_clock }; always @($global_clock) { ck_tx_count, q_tx_count } <= { q_tx_count, f_tx_count }; reg [TB+4+F_CKRES-1:0] f_ck_tx_time, f_rx_time; always @(*) f_ck_tx_time = { ck_tx_count, !ck_tx_clock[F_CKRES-1], ck_tx_clock[F_CKRES-2:0] }; always @(*) f_rx_time = { f_rx_count, !f_rx_clock[1], f_rx_clock[0], {(F_CKRES-2){1'b0}} }; reg [TB+4+F_CKRES-1:0] f_signed_difference; always @(*) f_signed_difference = f_ck_tx_time - f_rx_time; always @(*) if (f_signed_difference[TB+4+F_CKRES-1]) f_sub_baud_difference = -f_signed_difference; else f_sub_baud_difference = f_signed_difference; always @($global_clock) if (state == `RXUL_WAIT) `ASSERT((!f_tx_busy)||(f_tx_reg[9:1] == 0)); always @($global_clock) if (state == `RXUL_IDLE) begin `ASSERT((!f_tx_busy)||(f_tx_reg[9])||(f_tx_reg[9:1]==0)); if (!ck_uart) ;//`PHASE_TWO_ASSERT((f_rx_count < 4)||(f_sub_baud_difference <= ((CLOCKS_PER_BAUD<<F_CKRES)/20))); else `ASSERT((f_tx_reg[9:1]==0)||(f_tx_count < (3 + CLOCKS_PER_BAUD/2))); end else if (state == 0) `ASSERT(f_sub_baud_difference <= 2 * ((CLOCKS_PER_BAUD<<F_CKRES)/20)); else if (state == 1) `ASSERT(f_sub_baud_difference <= 3 * ((CLOCKS_PER_BAUD<<F_CKRES)/20)); else if (state == 2) `ASSERT(f_sub_baud_difference <= 4 * ((CLOCKS_PER_BAUD<<F_CKRES)/20)); else if (state == 3) `ASSERT(f_sub_baud_difference <= 5 * ((CLOCKS_PER_BAUD<<F_CKRES)/20)); else if (state == 4) `ASSERT(f_sub_baud_difference <= 6 * ((CLOCKS_PER_BAUD<<F_CKRES)/20)); else if (state == 5) `ASSERT(f_sub_baud_difference <= 7 * ((CLOCKS_PER_BAUD<<F_CKRES)/20)); else if (state == 6) `ASSERT(f_sub_baud_difference <= 8 * ((CLOCKS_PER_BAUD<<F_CKRES)/20)); else if (state == 7) `ASSERT(f_sub_baud_difference <= 9 * ((CLOCKS_PER_BAUD<<F_CKRES)/20)); else if (state == 8) `ASSERT(f_sub_baud_difference <= 10 * ((CLOCKS_PER_BAUD<<F_CKRES)/20)); always @(posedge i_clk) if (o_wr) `ASSERT(o_data == $past(f_tx_data,4)); // always @(posedge i_clk) // if ((zero_baud_counter)&&(state != 4'hf)&&(CLOCKS_PER_BAUD > 6)) // assert(i_uart_rx == ck_uart); // Make sure the data register matches always @(posedge i_clk) // if ((f_past_valid)&&(state != $past(state))) begin if (state == 4'h0) `ASSERT(!data_reg[7]); if (state == 4'h1) `ASSERT((data_reg[7] == $past(f_tx_data[0]))&&(!data_reg[6])); if (state == 4'h2) `ASSERT(data_reg[7:6] == $past(f_tx_data[1:0])); if (state == 4'h3) `ASSERT(data_reg[7:5] == $past(f_tx_data[2:0])); if (state == 4'h4) `ASSERT(data_reg[7:4] == $past(f_tx_data[3:0])); if (state == 4'h5) `ASSERT(data_reg[7:3] == $past(f_tx_data[4:0])); if (state == 4'h6) `ASSERT(data_reg[7:2] == $past(f_tx_data[5:0])); if (state == 4'h7) `ASSERT(data_reg[7:1] == $past(f_tx_data[6:0])); if (state == 4'h8) `ASSERT(data_reg[7:0] == $past(f_tx_data[7:0])); end //////////////////////////////////////////////////////////////////////// // // Cover properties // //////////////////////////////////////////////////////////////////////// // always @(posedge i_clk) cover(o_wr); // Step 626, takes about 20mins always @(posedge i_clk) begin cover(!ck_uart); cover((f_past_valid)&&($rose(ck_uart))); // 82 cover((zero_baud_counter)&&(state == `RXUL_BIT_ZERO)); // 110 cover((zero_baud_counter)&&(state == `RXUL_BIT_ONE)); // 174 cover((zero_baud_counter)&&(state == `RXUL_BIT_TWO)); // 238 cover((zero_baud_counter)&&(state == `RXUL_BIT_THREE));// 302 cover((zero_baud_counter)&&(state == `RXUL_BIT_FOUR)); // 366 cover((zero_baud_counter)&&(state == `RXUL_BIT_FIVE)); // 430 cover((zero_baud_counter)&&(state == `RXUL_BIT_SIX)); // 494 cover((zero_baud_counter)&&(state == `RXUL_BIT_SEVEN));// 558 cover((zero_baud_counter)&&(state == `RXUL_STOP)); // 622 cover((zero_baud_counter)&&(state == `RXUL_WAIT)); // 626 end `endif `ifdef FORMAL_VERILATOR // FORMAL properties which can be tested via Verilator as well as // Yosys FORMAL always @(*) assert((state == 4'hf)||(state <= `RXUL_WAIT)); always @(*) assert(zero_baud_counter == (baud_counter == 0)? 1'b1:1'b0); always @(*) assert(baud_counter <= CLOCKS_PER_BAUD-1'b1); `endif endmodule |
Added example2/tx.v version [de68cf6199].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | //////////////////////////////////////////////////////////////////////////////// // // Filename: txuartlite.v // // Project: wbuart32, a full featured UART with simulator // // Purpose: Transmit outputs over a single UART line. This particular UART // implementation has been extremely simplified: it does not handle // generating break conditions, nor does it handle anything other than the // 8N1 (8 data bits, no parity, 1 stop bit) UART sub-protocol. // // To interface with this module, connect it to your system clock, and // pass it the byte of data you wish to transmit. Strobe the i_wr line // high for one cycle, and your data will be off. Wait until the 'o_busy' // line is low before strobing the i_wr line again--this implementation // has NO BUFFER, so strobing i_wr while the core is busy will just // get ignored. The output will be placed on the o_txuart output line. // // (I often set both data and strobe on the same clock, and then just leave // them set until the busy line is low. Then I move on to the next piece // of data.) // // Creator: Dan Gisselquist, Ph.D. // Gisselquist Technology, LLC // //////////////////////////////////////////////////////////////////////////////// // // Copyright (C) 2015-2020, Gisselquist Technology, LLC // // This program is free software (firmware): you can redistribute it and/or // modify it under the terms of the 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 MERCHANTIBILITY or // FITNESS FOR A PARTICULAR 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. (It's in the $(ROOT)/doc directory. Run make with no // target there if the PDF file isn't present.) If not, see // <http://www.gnu.org/licenses/> for a copy. // // License: GPL, v3, as defined and found on www.gnu.org, // http://www.gnu.org/licenses/gpl.html // // //////////////////////////////////////////////////////////////////////////////// // // `default_nettype none // `define TXUL_BIT_ZERO 4'h0 `define TXUL_BIT_ONE 4'h1 `define TXUL_BIT_TWO 4'h2 `define TXUL_BIT_THREE 4'h3 `define TXUL_BIT_FOUR 4'h4 `define TXUL_BIT_FIVE 4'h5 `define TXUL_BIT_SIX 4'h6 `define TXUL_BIT_SEVEN 4'h7 `define TXUL_STOP 4'h8 `define TXUL_IDLE 4'hf // // module txuartlite(i_clk, i_wr, i_data, o_uart_tx, o_busy); parameter [4:0] TIMING_BITS = 5'd24; localparam TB = TIMING_BITS; parameter [(TB-1):0] CLOCKS_PER_BAUD = 8; // 24'd868; input wire i_clk; input wire i_wr; input wire [7:0] i_data; // And the UART input line itself output reg o_uart_tx; // A line to tell others when we are ready to accept data. If // (i_wr)&&(!o_busy) is ever true, then the core has accepted a byte // for transmission. output wire o_busy; reg [(TB-1):0] baud_counter; reg [3:0] state; reg [7:0] lcl_data; reg r_busy, zero_baud_counter; // Big state machine controlling: r_busy, state // {{{ // initial r_busy = 1'b1; initial state = `TXUL_IDLE; always @(posedge i_clk) begin if (!zero_baud_counter) // r_busy needs to be set coming into here r_busy <= 1'b1; else if (state > `TXUL_STOP) // STATE_IDLE begin state <= `TXUL_IDLE; r_busy <= 1'b0; if ((i_wr)&&(!r_busy)) begin // Immediately start us off with a start bit r_busy <= 1'b1; state <= `TXUL_BIT_ZERO; end end else begin // One clock tick in each of these states ... r_busy <= 1'b1; if (state <=`TXUL_STOP) // start bit, 8-d bits, stop-b state <= state + 1'b1; else state <= `TXUL_IDLE; end end // }}} // o_busy // {{{ // // This is a wire, designed to be true is we are ever busy above. // originally, this was going to be true if we were ever not in the // idle state. The logic has since become more complex, hence we have // a register dedicated to this and just copy out that registers value. assign o_busy = (r_busy); // }}} // lcl_data // {{{ // // This is our working copy of the i_data register which we use // when transmitting. It is only of interest during transmit, and is // allowed to be whatever at any other time. Hence, if r_busy isn't // true, we can always set it. On the one clock where r_busy isn't // true and i_wr is, we set it and r_busy is true thereafter. // Then, on any zero_baud_counter (i.e. change between baud intervals) // we simple logically shift the register right to grab the next bit. initial lcl_data = 8'hff; always @(posedge i_clk) if ((i_wr)&&(!r_busy)) lcl_data <= i_data; else if (zero_baud_counter) lcl_data <= { 1'b1, lcl_data[7:1] }; // }}} // o_uart_tx // {{{ // // This is the final result/output desired of this core. It's all // centered about o_uart_tx. This is what finally needs to follow // the UART protocol. // initial o_uart_tx = 1'b1; always @(posedge i_clk) if ((i_wr)&&(!r_busy)) o_uart_tx <= 1'b0; // Set the start bit on writes else if (zero_baud_counter) // Set the data bit. o_uart_tx <= lcl_data[0]; // }}} // Baud counter // {{{ // All of the above logic is driven by the baud counter. Bits must last // CLOCKS_PER_BAUD in length, and this baud counter is what we use to // make certain of that. // // The basic logic is this: at the beginning of a bit interval, start // the baud counter and set it to count CLOCKS_PER_BAUD. When it gets // to zero, restart it. // // However, comparing a 28'bit number to zero can be rather complex-- // especially if we wish to do anything else on that same clock. For // that reason, we create "zero_baud_counter". zero_baud_counter is // nothing more than a flag that is true anytime baud_counter is zero. // It's true when the logic (above) needs to step to the next bit. // Simple enough? // // I wish we could stop there, but there are some other (ugly) // conditions to deal with that offer exceptions to this basic logic. // // 1. When the user has commanded a BREAK across the line, we need to // wait several baud intervals following the break before we start // transmitting, to give any receiver a chance to recognize that we are // out of the break condition, and to know that the next bit will be // a stop bit. // // 2. A reset is similar to a break condition--on both we wait several // baud intervals before allowing a start bit. // // 3. In the idle state, we stop our counter--so that upon a request // to transmit when idle we can start transmitting immediately, rather // than waiting for the end of the next (fictitious and arbitrary) baud // interval. // // When (i_wr)&&(!r_busy)&&(state == `TXUL_IDLE) then we're not only in // the idle state, but we also just accepted a command to start writing // the next word. At this point, the baud counter needs to be reset // to the number of CLOCKS_PER_BAUD, and zero_baud_counter set to zero. // // The logic is a bit twisted here, in that it will only check for the // above condition when zero_baud_counter is false--so as to make // certain the STOP bit is complete. initial zero_baud_counter = 1'b1; initial baud_counter = 0; always @(posedge i_clk) begin zero_baud_counter <= (baud_counter == 1); if (state == `TXUL_IDLE) begin baud_counter <= 0; zero_baud_counter <= 1'b1; if ((i_wr)&&(!r_busy)) begin baud_counter <= CLOCKS_PER_BAUD - 1'b1; zero_baud_counter <= 1'b0; end end else if ((zero_baud_counter)&&(state == 4'h9)) begin baud_counter <= 0; zero_baud_counter <= 1'b1; end else if (!zero_baud_counter) baud_counter <= baud_counter - 1'b1; else baud_counter <= CLOCKS_PER_BAUD - 1'b1; end // }}} // // // FORMAL METHODS // // // `ifdef FORMAL `ifdef TXUARTLITE `define ASSUME assume `else `define ASSUME assert `endif // Setup // {{{ reg f_past_valid, f_last_clk; initial f_past_valid = 1'b0; always @(posedge i_clk) f_past_valid <= 1'b1; initial `ASSUME(!i_wr); always @(posedge i_clk) if ((f_past_valid)&&($past(i_wr))&&($past(o_busy))) begin `ASSUME(i_wr == $past(i_wr)); `ASSUME(i_data == $past(i_data)); end // }}} // Check the baud counter // {{{ always @(posedge i_clk) assert(zero_baud_counter == (baud_counter == 0)); always @(posedge i_clk) if ((f_past_valid)&&($past(baud_counter != 0))&&($past(state != `TXUL_IDLE))) assert(baud_counter == $past(baud_counter - 1'b1)); always @(posedge i_clk) if ((f_past_valid)&&(!$past(zero_baud_counter))&&($past(state != `TXUL_IDLE))) assert($stable(o_uart_tx)); reg [(TB-1):0] f_baud_count; initial f_baud_count = 1'b0; always @(posedge i_clk) if (zero_baud_counter) f_baud_count <= 0; else f_baud_count <= f_baud_count + 1'b1; always @(posedge i_clk) assert(f_baud_count < CLOCKS_PER_BAUD); always @(posedge i_clk) if (baud_counter != 0) assert(o_busy); // }}} reg [9:0] f_txbits; // {{{ initial f_txbits = 0; always @(posedge i_clk) if (zero_baud_counter) f_txbits <= { o_uart_tx, f_txbits[9:1] }; always @(posedge i_clk) if ((f_past_valid)&&(!$past(zero_baud_counter)) &&(!$past(state==`TXUL_IDLE))) assert(state == $past(state)); reg [3:0] f_bitcount; initial f_bitcount = 0; always @(posedge i_clk) if ((!f_past_valid)||(!$past(f_past_valid))) f_bitcount <= 0; else if ((state == `TXUL_IDLE)&&(zero_baud_counter)) f_bitcount <= 0; else if (zero_baud_counter) f_bitcount <= f_bitcount + 1'b1; always @(posedge i_clk) assert(f_bitcount <= 4'ha); reg [7:0] f_request_tx_data; always @(posedge i_clk) if ((i_wr)&&(!o_busy)) f_request_tx_data <= i_data; wire [3:0] subcount; assign subcount = 10-f_bitcount; always @(posedge i_clk) if (f_bitcount > 0) assert(!f_txbits[subcount]); always @(posedge i_clk) if (f_bitcount == 4'ha) begin assert(f_txbits[8:1] == f_request_tx_data); assert( f_txbits[9]); end always @(posedge i_clk) assert((state <= `TXUL_STOP + 1'b1)||(state == `TXUL_IDLE)); always @(posedge i_clk) if ((f_past_valid)&&($past(f_past_valid))&&($past(o_busy))) cover(!o_busy); // }}} `endif // FORMAL `ifdef VERIFIC_SVA reg [7:0] fsv_data; // // Grab a copy of the data any time we are sent a new byte to transmit // We'll use this in a moment to compare the item transmitted against // what is supposed to be transmitted // always @(posedge i_clk) if ((i_wr)&&(!o_busy)) fsv_data <= i_data; // // One baud interval // {{{ // // 1. The UART output is constant at DAT // 2. The internal state remains constant at ST // 3. CKS = the number of clocks per bit. // // Everything stays constant during the CKS clocks with the exception // of (zero_baud_counter), which is *only* raised on the last clock // interval sequence BAUD_INTERVAL(CKS, DAT, SR, ST); ((o_uart_tx == DAT)&&(state == ST) &&(lcl_data == SR) &&(!zero_baud_counter))[*(CKS-1)] ##1 (o_uart_tx == DAT)&&(state == ST) &&(lcl_data == SR) &&(zero_baud_counter); endsequence // }}} // // One byte transmitted // {{{ // // DATA = the byte that is sent // CKS = the number of clocks per bit // sequence SEND(CKS, DATA); BAUD_INTERVAL(CKS, 1'b0, DATA, 4'h0) ##1 BAUD_INTERVAL(CKS, DATA[0], {{(1){1'b1}},DATA[7:1]}, 4'h1) ##1 BAUD_INTERVAL(CKS, DATA[1], {{(2){1'b1}},DATA[7:2]}, 4'h2) ##1 BAUD_INTERVAL(CKS, DATA[2], {{(3){1'b1}},DATA[7:3]}, 4'h3) ##1 BAUD_INTERVAL(CKS, DATA[3], {{(4){1'b1}},DATA[7:4]}, 4'h4) ##1 BAUD_INTERVAL(CKS, DATA[4], {{(5){1'b1}},DATA[7:5]}, 4'h5) ##1 BAUD_INTERVAL(CKS, DATA[5], {{(6){1'b1}},DATA[7:6]}, 4'h6) ##1 BAUD_INTERVAL(CKS, DATA[6], {{(7){1'b1}},DATA[7:7]}, 4'h7) ##1 BAUD_INTERVAL(CKS, DATA[7], 8'hff, 4'h8) ##1 BAUD_INTERVAL(CKS, 1'b1, 8'hff, 4'h9); endsequence // }}} // // Transmit one byte // {{{ // Once the byte is transmitted, make certain we return to // idle // assert property ( @(posedge i_clk) (i_wr)&&(!o_busy) |=> ((o_busy) throughout SEND(CLOCKS_PER_BAUD,fsv_data)) ##1 (!o_busy)&&(o_uart_tx)&&(zero_baud_counter)); // }}} // {{{ assume property ( @(posedge i_clk) (i_wr)&&(o_busy) |=> (i_wr)&&(o_busy)&&($stable(i_data))); // // Make certain that o_busy is true any time zero_baud_counter is // non-zero // always @(*) assert((o_busy)||(zero_baud_counter) ); // If and only if zero_baud_counter is true, baud_counter must be zero // Insist on that relationship here. always @(*) assert(zero_baud_counter == (baud_counter == 0)); // To make certain baud_counter stays below CLOCKS_PER_BAUD always @(*) assert(baud_counter < CLOCKS_PER_BAUD); // // Insist that we are only ever in a valid state always @(*) assert((state <= `TXUL_STOP+1'b1)||(state == `TXUL_IDLE)); // }}} `endif // Verific SVA endmodule |
Modified ezsteps.scm from [0cbe12a80c] to [0b0178b127].
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 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 | ;; 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 call-with-environment-variables posix-extras z3 csv typed-records pathname-expand matchable) (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") (define (ezsteps:step-name->mode stepname) (match (string-search "\\.([^\\.]+)$" stepname) ((_ ext) (string->symbol ext)) (else #f))) (define (ezsteps:create-step-script envdbf stepname prevstepname mode cmd shellexe) (let* (#;(shebang (case mode ((sh) "/bin/sh") ((csh) "/bin/csh") (else "/bin/bash"))) (sourcef (conc ".ezsteps/vars_" prevstepname "." mode)) (scriptn (conc "ez_" stepname))) ;; remember the name already has an extension .sh, .csh etc. (with-output-to-file scriptn (lambda () ;; the shebang line (print "#!" shellexe) ;; save the env at start (print "megatest -envcap "stepname"_start "envdbf) ;; source vars from previous steps (if (file-exists? sourcef) (print "source " sourcef)) ;; run the command (print cmd) (if (eq? mode 'csh) (print "set ecode=$?") (print "ecode=$?")) ;; save the env at end (print "megatest -envcap "stepname"_end "envdbf) ;; write the delta (print "megatest -envdelta "stepname"_start-"stepname"_end -dumpmode bash -o .ezsteps/vars_"stepname".sh "envdbf) (print "megatest -envdelta "stepname"_start-"stepname"_end -dumpmode csh -o .ezsteps/vars_"stepname".csh "envdbf) (print "exit $ecode"))) (system (conc "chmod a+x " scriptn)))) (define (ezsteps:get-ezpropvars res) ;; testconfig) ;; (let* ((res (configf:lookup testconfig "setup" "ezpropvars"))) (if (string? res) (let* ((dat (string-split res))) (match dat ((s shellexe) (let ((shl (string->symbol s))) `(,shl . ,shellexe))) ((s) (let* ((shl (string->symbol s)) (shellexe (if (eq? shl 'csh) "/bin/csh" "/bin/bash"))) `(,shl . ,shellexe))) (else #f))) #f)) ;; NOTE: returns logpro-used? ;; (define (launch:runstep ezstep run-id test-id exit-info m tal testconfig all-steps-dat prevstepname envdbf) (let* ((stepname (car ezstep)) ;; do stuff to run the step (stepmode-n (ezsteps:step-name->mode stepname)) (stepinfo (cadr ezstep)) (shellmode (ezsteps:get-ezpropvars (configf:lookup testconfig "setup" "ezpropvars"))) ;; returns '(csh|sh . "/path/to/shell") (stepmode (if stepmode-n ;; the .sh or .csh always wins stepmode-n (if shellmode (car shellmode) #f))) (shellexe (if stepmode-n (case stepmode ((csh) "/bin/csh") (else "/bin/bash")) (if shellmode (cdr shellmode) "/bin/bash"))) ;; (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))) (setenv "MT_STEP_NAME" stepname) (hash-table-set! all-steps-dat stepname `((params . ,paramparts))) (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) (if stepmode (ezsteps:create-step-script envdbf stepname prevstepname stepmode stepcmd shellexe)) ;; ;; 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 (if stepmode (conc "ez_" stepname) 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:propogate-mt-vars-to-subrun proc '("MT_TARGET" "MT_LINKTREE" "MT_RUNNAME"))) (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) (let processloop ((i 0)) (let-values (((pid-val exit-status exit-code)(process-wait pid #t))) (mutex-lock! m) (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* "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 ((and (eq? process-exit-status 3) logpro-used) 'check) ;; logpro 3 = check ((and (eq? process-exit-status 4) logpro-used) 'waived) ;; logpro 4 = waived ((and (eq? process-exit-status 5) logpro-used) 'abort) ;; logpro 5 = abort ((and (eq? process-exit-status 6) logpro-used) 'skip) ;; logpro 6 = skip ((eq? process-exit-status 0) 'pass) ;; logpro 0 = pass (else 'fail))) (overall-status (cond ((eq? (launch:einf-rollup-status exit-info) 2) 'warn) ;; rollup-status (vector-ref exit-info 3) ((eq? (launch:einf-rollup-status exit-info) 0) 'pass) ;; (vector-ref exit-info 3) (else 'fail))) (next-status (cond ((eq? overall-status 'pass) this-step-status) ((eq? overall-status 'warn) (if (eq? this-step-status 'fail) 'fail 'warn)) ((eq? overall-status 'abort) 'abort) (else 'fail))) (next-state ;; "RUNNING") ;; WHY WAS THIS CHANGED TO NOT USE (null? tal) ?? (cond ((null? tal) ;; more to run? "COMPLETED") (else "RUNNING")))) (debug:print 4 *default-log-port* "Exit value received: " (launch:einf-exit-code exit-info) " logpro-used: " logpro-used " this-step-status: " this-step-status " overall-status: " overall-status " next-status: " next-status " rollup-status: " (launch:einf-rollup-status exit-info)) ;; (vector-ref exit-info 3)) (case next-status ((warn) (launch:einf-rollup-status-set! exit-info 2) ;; (vector-set! exit-info 3 2) ;; rollup-status ;; NB// test-set-status! does rdb calls under the hood (tests:test-set-status! run-id test-id next-state "WARN" (if (eq? this-step-status 'warn) "Logpro warning found" #f) #f)) ((check) (launch:einf-rollup-status-set! exit-info 3) ;; (vector-set! exit-info 3 3) ;; rollup-status ;; NB// test-set-status! does rdb calls under the hood (tests:test-set-status! run-id test-id next-state "CHECK" (if (eq? this-step-status 'check) "Logpro check found" #f) #f)) ((waived) (launch:einf-rollup-status-set! exit-info 4) ;; (vector-set! exit-info 3 3) ;; rollup-status ;; NB// test-set-status! does rdb calls under the hood (tests:test-set-status! run-id test-id next-state "WAIVED" (if (eq? this-step-status 'check) "Logpro waived found" #f) #f)) ((abort) (launch:einf-rollup-status-set! exit-info 5) ;; (vector-set! exit-info 3 4) ;; rollup-status ;; NB// test-set-status! does rdb calls under the hood (tests:test-set-status! run-id test-id next-state "ABORT" (if (eq? this-step-status 'abort) "Logpro abort found" #f) #f)) ((skip) (launch:einf-rollup-status-set! exit-info 6) ;; (vector-set! exit-info 3 4) ;; rollup-status ;; NB// test-set-status! does rdb calls under the hood (tests:test-set-status! run-id test-id next-state "SKIP" (if (eq? this-step-status 'skip) "Logpro skip found" #f) #f)) ((pass) (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 (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 (the-step-params '())) ;; not exactly "functional" ;; 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 (or (vector-ref exit-info 1) (equal? (alist-ref 'keep-going prev-step-params) 'yes)) (let* ((prev-step-params the-step-params) ;; need to snag this now (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)))) ) (debug:print 0 *default-log-port* "NOTE: stepparms=" stepparms) (set! prev-step-params stepparms) (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)) |
︙ | ︙ |
Added fossil-utils/Makefile version [ce704a362f].
> > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | all : run.sh go : run.sh bash run.sh fossilrebase : fossilrebase.scm csc fossilrebase.scm run.sh : fossilrebase justtesting/*.dat ./fossilrebase dumpcmds justtesting > run.sh |
Added fossil-utils/fossilrebase.scm version [d36203f150].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | (use yaml matchable srfi-1 sqlite3 regex) (define (get-timeline) (let* ((inp (open-input-pipe "fossil json timeline checkin -n 0")) (res (yaml-load inp))) (close-input-pipe inp) res)) (define (get-val data key) (alist-ref key data equal?)) (define (any->string val) (if (string? val) val (conc val))) (define (branch-match branches tags) (if (list? tags) (any (lambda (x) (member x branches)) tags) (member tags branches))) (define (refdb-set-value dbname sheetname row col value) (let ((pid (process-run "refdb" `("set" ,dbname ,sheetname ,row ,col ,value)))) (let-values (((a b c)(process-wait pid))) b))) (define (seconds->std-time-str sec) (time->string (seconds->local-time sec) "%Y-%m-%d %H:%M:%S")) (define (gen-refdb dbname branches) (if (not (file-exists? (conc dbname "/sheet-names.cfg"))) (begin (print "ERROR: You must precreate the refdb with \"refdb edit <dbname>\"") (exit 1))) (print "Getting data from timeline...") (let* ((data (get-timeline)) (branches (string-split branches ","))) (print "Got data from timeline...") (let* ((timeline (get-val (get-val data "payload") "timeline"))) (print "Got " (length timeline) " timeline records. Filling refdb...") (for-each (lambda (rec) (let ((uuid (get-val rec "uuid"))) (if (branch-match branches (get-val rec "tags")) (let ((tagnum 0) (tags (get-val rec "tags"))) (print "uuid: " uuid " tags: " (get-val rec "tags")) ;; First the tags so they are visible to left (for-each (lambda (tagv) (refdb-set-value dbname "timeline" uuid (conc "tag" tagnum) tagv) (set! tagnum (+ tagnum 1))) (if (list? tags) tags (list tags))) (for-each (lambda (key) (refdb-set-value dbname "timeline" uuid key (any->string (get-val rec key)))) '("user" "comment")) (refdb-set-value dbname "extra" uuid "parents" (string-intersperse (get-val rec "parents") ",")) (refdb-set-value dbname "timeline" uuid "timestamp" (seconds->std-time-str (get-val rec "timestamp"))) (refdb-set-value dbname "timeline" uuid "timestamp_sec" (any->string (get-val rec "timestamp"))) )))) timeline)))) (define (escape-string-for-bash str) (string-substitute "'" "''" str #t)) ;; tag0 tag1 tag2 cherrypick backout hide usedate recomment user ;; comment timestamp timestamp_sec ;; (define (get-node-details db node-id) (let* ((result #f) (count 0)) (for-each-row (lambda (rowkey tag0 cmdnum cherrypick do-commit backout hide usedate recomment user comment timestamp timestamp_sec) (set! result `((uuid . ,rowkey) (tag0 . ,tag0) (cmdnum . ,cmdnum) (cherrypick . ,cherrypick) (do-commit . ,do-commit) (backout . ,backout) (hide . ,hide) (usedate . ,usedate) (recomment . ,recomment) (user . ,user) (comment . ,comment) (timestamp . ,timestamp) (timestamp_sec . ,timestamp_sec))) (set! count (+ count 1))) db "SELECT rowkey,tag0,cmdnum,cherrypick,do_commit,backout,hide,usedate,recomment,user,comment,timestamp,timestamp_sec FROM timeline WHERE rowkey LIKE ?;" node-id) (if (> count 1) (print "WARNING: more than one node matches " node-id ", found " count " nodes")) result)) ;; get branches to create ;; (define (get-new-branches db) (let* ((res '())) (for-each-row (lambda (rowkey node mode) (set! res (cons `((branch . ,rowkey) (node . ,node) (mode . ,mode)) res))) db "SELECT rowkey,node,mode FROM branches;") res)) ;; get cherrypicks ;; (define (get-cherry-picks db) (let* ((res '())) (for-each-row (lambda (rowkey tag0 cherrypick firstmerge do-commit usedate comment recomment) (set! res (cons `((uuid . ,rowkey) (tag0 . ,tag0) (cherrypick . ,cherrypick) (firstmerge . ,firstmerge) (do-commit . ,do-commit) (usedate . ,usedate) (comment . ,comment) (recomment . ,recomment)) res))) db ;; sort desc and the cons puts it back in correct order "SELECT rowkey,tag0,cherrypick,firstmerge,do_commit,usedate,comment,recomment FROM timeline WHERE cherrypick != '' AND cherrypick NOT NULL ORDER BY timestamp_sec DESC;") res)) ;; always private and same time as parent node + 1 second ;; ;; fossil branch new BRANCH-NAME BASIS ?OPTIONS? ;; ;; Create a new branch BRANCH-NAME off of check-in BASIS. ;; Supported options for this subcommand include: ;; --private branch is private (i.e., remains local) ;; --bgcolor COLOR use COLOR instead of automatic background ;; --nosign do not sign contents on this branch ;; --date-override DATE DATE to use instead of 'now' ;; --user-override USER USER to use instead of the current default ;; ;; DATE may be "now" or "YYYY-MM-DDTHH:MM:SS.SSS". If in ;; year-month-day form, it may be truncated, the "T" may be ;; replaced by a space, and it may also name a timezone offset ;; from UTC as "-HH:MM" (westward) or "+HH:MM" (eastward). ;; Either no timezone suffix or "Z" means UTC. ;; (define (create-branch db branch-name parent-node) (let* ((parent-info (get-node-details db (conc parent-node "%")))) (if (not parent-info) (print "ERROR: no info found for node " parent-node) (let* ((parent-date (alist-ref 'timestamp parent-info)) (parent-user (alist-ref 'user parent-info))) (print "fossil branch new " branch-name " " parent-node " --private --date-override '" parent-date "'") ;; (print "Creating private branch " branch-name " from node " parent-node) ;; (pp parent-info) ;; (print "") )))) (define (do-cherrypick db cherrypick dbfname) (let* ((tag0 (alist-ref 'tag0 cherrypick)) (uuid (alist-ref 'uuid cherrypick)) (nodeinf (get-node-details db uuid)) (nodedate (alist-ref 'timestamp nodeinf)) (user (alist-ref 'user nodeinf)) (targ (alist-ref 'cherrypick cherrypick)) ;; do fossil up to this node (firstmerge (alist-ref 'firstmerge cherrypick)) (do-commit (alist-ref 'do-commit cherrypick)) ;; if yes do a commit (usedate (alist-ref 'usedate cherrypick)) ;; if no use current time (comment (alist-ref 'comment cherrypick)) (recomment (alist-ref 'recomment cherrypick))) (print "#======= Start of cherrypick for " uuid "=======") (print "fossil checkout " targ) ;; first - do we have a firstmerge? (if (and (string? firstmerge) (> (string-length firstmerge) 0)) (print "fossil merge " firstmerge)) (print "fossil merge --cherrypick " uuid) (if #t ;;(member do-commit '("x" "yes")) (print "fossil commit -m '" (escape-string-for-bash comment) "' " (if (equal? usedate "no") "" (conc " --date-override '" nodedate "'")) " --user-override " user )) (print "if [[ $(fossil status | grep CONFLICT | wc -l) -gt 0 ]];then") (print " echo \"\nHAVE CONFLICT - STOPPING\n\"") (print " echo \"cherry pick of " uuid " into " targ " resulted in conflicts\"") (print " exit 1") (print "else") (print " echo GOOD, marking node " uuid " as DONE") (print " refdb set " dbfname " timeline " uuid " status DONE") (print "fi") (print "#======= end of cherrypick for " uuid "=======") (print "") )) ;; (define (gen-rebase-commands dbname) (let* ((sqldbname (conc "/tmp/" (current-user-name) "-" dbname ".db")) (dbfname (conc (current-directory) "/" dbname))) ;; want the fully qualified path so we can call the generated script from anywhere (print "# Create sqlite db " sqldbname "...") (system (conc "refdb dump2sqlite3 " dbname " " sqldbname)) (let* ((db (open-database sqldbname)) (branches (get-new-branches db)) (cherrypicks (get-cherry-picks db))) ;; create the setup (dump-setup db) ;; create the branches (for-each (lambda (branchdat) (create-branch db (alist-ref 'branch branchdat) (alist-ref 'node branchdat))) branches) ;; create the cherrypicks (for-each (lambda (cherrypick) (do-cherrypick db cherrypick dbfname)) cherrypicks) ))) (define (dump-setup db) (for-each-row (lambda (cmd) (print cmd)) db "SELECT command FROM 'setup' ORDER BY rowkey ASC;")) (define help "fossilrebase - register commits in a refdb, edit them by hand then execute them WARNING: It is highly recommended you do this on a disconnected copy of your fossil database!! Usage: fossilrebase cmd [params ...] where cmd is one of: genrefdb fname b1,b2... : generate a refdb of all the commits for branches matching patterns listed, edit with \"refdb edit fname\" dumpcmds fname : from refdb fname dump fossil commands to implement the rebase you want to do. ") (define (main) (if (< (length (command-line-arguments)) 1) (begin (print help) (exit 1)) (match (command-line-arguments) (("genrefdb" fname branches) (gen-refdb fname branches)) (("dumpcmds" fname) (gen-rebase-commands fname)) (else (print "Sorry, didn't know what to do with \"" (string-intersperse (command-line-arguments) " ") "\"") (exit 1))))) (main) |
Added fossil-utils/justtesting/branches.dat version [44988b069a].
> > > > > > | 1 2 3 4 5 6 | [node] v1.65-broken-fixes 367ffc5bdf nobranch 367ffc5bdf [mode] v1.65-broken-fixes private nobranch private |
Added fossil-utils/justtesting/extra.dat version [ee15d0a10c].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | [parents] e7b6428a2533b1901a3bb12411a4095ce23a4d35 e5c65818cc818ef14c94682202fac7bf40375ec1 e5c65818cc818ef14c94682202fac7bf40375ec1 9fc475313fb461746f4de5df8343ddf15f6b345d,f6dc7607a8ecb7df68b5e50455a97f17eaefa348 9fc475313fb461746f4de5df8343ddf15f6b345d e9153fe95b68ac1ab72d38b5cbe22b1f1237f8cc e9153fe95b68ac1ab72d38b5cbe22b1f1237f8cc 3bd95bc26bb7491d5ab89f264232159d7c188e1b c7baa27145762eab04802b34d95818386df2e3f7 1b0d4f257e6d9740397662ede6dc01bf0f5fcec7 1b0d4f257e6d9740397662ede6dc01bf0f5fcec7 c13726326ce034fbedb36a634179fc1f685ef076 c13726326ce034fbedb36a634179fc1f685ef076 ad2000389bacbff6847a9920ec8cc44363ff9682 ad2000389bacbff6847a9920ec8cc44363ff9682 473d6eaf82c96fb6db9905da82b1ef1419852a93 473d6eaf82c96fb6db9905da82b1ef1419852a93 367ffc5bdf35456922c1d3ceebbe633b65a65bcf f6dc39b0f7277ade8986ad06aa9a5f043c3fba2c 2ded3e4899f49656d06b26c1a35ff730ed9768be 2ded3e4899f49656d06b26c1a35ff730ed9768be 39ec01ec3bb664aa2293ed35dc6f131e00b1d4db 39ec01ec3bb664aa2293ed35dc6f131e00b1d4db 7f1e84d10d19cd8fa9a639fd60c5102aa6c3fdf5 7f1e84d10d19cd8fa9a639fd60c5102aa6c3fdf5 7f0801084261f8dec9f4eaa05707897c239bd577 7f0801084261f8dec9f4eaa05707897c239bd577 901de8992f8a31ef8ddfe47edfb31c251044de61 901de8992f8a31ef8ddfe47edfb31c251044de61 6118471b3384fcc3ae99fd9400d2193b05ceb0f7 6118471b3384fcc3ae99fd9400d2193b05ceb0f7 73dfd99fe60a44fc519d78117e3bfb0791268fa1 73dfd99fe60a44fc519d78117e3bfb0791268fa1 2f7d94848b24bab8702d82654351d25711cc89b6 2f7d94848b24bab8702d82654351d25711cc89b6 875a0b48c6fa9e2eb37094a0b53f80fa316f1189 875a0b48c6fa9e2eb37094a0b53f80fa316f1189 66d6fd1aaf5dee5b79fbf7f47a3e7325851b7d6d 66d6fd1aaf5dee5b79fbf7f47a3e7325851b7d6d 268055792a6b6210a6d53f3bce9555a6b2de7075,e7b6428a2533b1901a3bb12411a4095ce23a4d35 f6dc7607a8ecb7df68b5e50455a97f17eaefa348 3bd95bc26bb7491d5ab89f264232159d7c188e1b f13cb3f1bc36ede7b967ea347fa9cad59d680c88 bd18bd00ac2955b4864a543b19522525434dfe80 3bd95bc26bb7491d5ab89f264232159d7c188e1b 522b48d828c3295920e0dbd15480dae21426a74b 522b48d828c3295920e0dbd15480dae21426a74b 5dc1573e7d958fae8fb3711663a07f7f5a0670f3 5dc1573e7d958fae8fb3711663a07f7f5a0670f3 c5bd5112a83452b0cbae5dddc852d47c76ab9ff4 c5bd5112a83452b0cbae5dddc852d47c76ab9ff4 9d1cc54fe17184885380c438aaa3a2f172d3c275 9d1cc54fe17184885380c438aaa3a2f172d3c275 da2b09089751193627241c81260e7cafa10657bc da2b09089751193627241c81260e7cafa10657bc 7fc5b1bdcc47a6f43723efd27f2edcf63bc564b1 7fc5b1bdcc47a6f43723efd27f2edcf63bc564b1 bb4c7dd6b98dbe9924182e9e5010f8846d702525 bb4c7dd6b98dbe9924182e9e5010f8846d702525 071ebc34ba460be1bdead4ec1a3c261e6bcd2bc4 071ebc34ba460be1bdead4ec1a3c261e6bcd2bc4 64aa9347d5e5af8d43fdcfbf64891596022cebe9 64aa9347d5e5af8d43fdcfbf64891596022cebe9 50237f6e1f5f369b5e1022774427028c4dba7d6b 50237f6e1f5f369b5e1022774427028c4dba7d6b e28be4def5c32dd0a16a6059db1fac22b2aa3653 e28be4def5c32dd0a16a6059db1fac22b2aa3653 b487e8f3c5ee74eeeaa6edabd92e2548a33210f7 b487e8f3c5ee74eeeaa6edabd92e2548a33210f7 63e558983a2101551ea0fa140888a5e6fd4322ae 63e558983a2101551ea0fa140888a5e6fd4322ae 19f75192e22ab76c4de3eacbf57416d192617b48 19f75192e22ab76c4de3eacbf57416d192617b48 8fd408420ba2b46d851b409832a4b0eb55f33a19 8fd408420ba2b46d851b409832a4b0eb55f33a19 2e3a570e3e8896f290135b2dfc012b0f69c3516d 268055792a6b6210a6d53f3bce9555a6b2de7075 aa29985039a593ff4c56ddc64870c8e205999184 2e3a570e3e8896f290135b2dfc012b0f69c3516d e5bf9db624e5904b1efb29df7d7ed14f7fc23bc0 e5bf9db624e5904b1efb29df7d7ed14f7fc23bc0 0a7ddadc4dece2446166d8156ecd1de168115649 0a7ddadc4dece2446166d8156ecd1de168115649 aa29985039a593ff4c56ddc64870c8e205999184 bd18bd00ac2955b4864a543b19522525434dfe80 0cb77d7f74edafa41a5d9ac28467c532b679325d aa29985039a593ff4c56ddc64870c8e205999184 0a9e690b28f0ef4ee710dab3af7b3c45a0e4a38d 3d9c1de6339fcecbd59eb7cbec2be5680f0f914d 6625f3bc6a98d3f05f57ab42d329391613bbe008 6625f3bc6a98d3f05f57ab42d329391613bbe008 3ccc64251fcfc210fe7ba1998fa90a96d3bf2fa3 3ccc64251fcfc210fe7ba1998fa90a96d3bf2fa3 0a9e690b28f0ef4ee710dab3af7b3c45a0e4a38d 0a9e690b28f0ef4ee710dab3af7b3c45a0e4a38d 18da8b6a613e8ee42c2b82fd00fedcf38c153433 18da8b6a613e8ee42c2b82fd00fedcf38c153433 7ff937a8a2df1a3e473a760363b85e98aa01bbc4 7ff937a8a2df1a3e473a760363b85e98aa01bbc4 5b7f0c6aa302ede19e96946ad2e33a7fa97e4fbb 5b7f0c6aa302ede19e96946ad2e33a7fa97e4fbb ea8c3e52e9f9c216ed88a2707722d4c61e246522 ea8c3e52e9f9c216ed88a2707722d4c61e246522 a374d9084bb19e0715a3981a05f81b259a7500fc a374d9084bb19e0715a3981a05f81b259a7500fc 07ff7dca1e64439988168406443a703b0ad929fa 07ff7dca1e64439988168406443a703b0ad929fa 15b59cfa429cb21c7ea1dbe8cdc3d8074d3617b6 0cb77d7f74edafa41a5d9ac28467c532b679325d d825e32743716501b8fe878f973898a5caa0c450 15b59cfa429cb21c7ea1dbe8cdc3d8074d3617b6 0364beb9c92e54e3e658cdf1876d7c75b2d68e15,d825e32743716501b8fe878f973898a5caa0c450 0364beb9c92e54e3e658cdf1876d7c75b2d68e15 0645166f9cdc9cbb2e922e7a3b0094fbf78e9c8c 0645166f9cdc9cbb2e922e7a3b0094fbf78e9c8c 5de2fd17b5348d5283f874e7ec9bf2c53cad12a0 d825e32743716501b8fe878f973898a5caa0c450 220b14a861c4883ff947e46ea39af32c046aaa99 220b14a861c4883ff947e46ea39af32c046aaa99 8724301727841358def98a48e191a0e344ddbf68 8724301727841358def98a48e191a0e344ddbf68 cdd5e92143e616f56b8b4ba90f6bc2114de0dee1 5de2fd17b5348d5283f874e7ec9bf2c53cad12a0 2a858c5054f56588fefe6039621ebaefc5344d29 2a858c5054f56588fefe6039621ebaefc5344d29 0495fb12176784b1907c243c54898c23f2afc140 0495fb12176784b1907c243c54898c23f2afc140 3b86fd8d4c9f097a04885021f902a69cfc375eeb 3b86fd8d4c9f097a04885021f902a69cfc375eeb 367ffc5bdf35456922c1d3ceebbe633b65a65bcf,cdd5e92143e616f56b8b4ba90f6bc2114de0dee1 cdd5e92143e616f56b8b4ba90f6bc2114de0dee1 c7d9089a6f8e857878fcdfda8b46b9034379dcf9 c7d9089a6f8e857878fcdfda8b46b9034379dcf9 c7977972a11df8cb1ea188cf6cf7a30e71d4292f c7977972a11df8cb1ea188cf6cf7a30e71d4292f ccab6e04aff4406711aecbfa9b41ea0a6349fb43 ccab6e04aff4406711aecbfa9b41ea0a6349fb43 eeb358089d89aee9f2b1804a4c630ef42a231ee2 eeb358089d89aee9f2b1804a4c630ef42a231ee2 e9a528680b234a33522c1b4f6d1719d95dda5b7e e9a528680b234a33522c1b4f6d1719d95dda5b7e caed2ecdc2c88e2ee1572137ec4cc6fe38e632bd caed2ecdc2c88e2ee1572137ec4cc6fe38e632bd b82fdf714f1b169991340004c60d758e09ba0fbf b82fdf714f1b169991340004c60d758e09ba0fbf 2c22506f667e6c675af6256a6bcc5bf3519f68c3 2c22506f667e6c675af6256a6bcc5bf3519f68c3 03755c29bfeaf4f4b6d00c21048eb5dd798e5cba 03755c29bfeaf4f4b6d00c21048eb5dd798e5cba 55a9a872eed80f88b6a2e2dd82da8d2822ae3fe6 55a9a872eed80f88b6a2e2dd82da8d2822ae3fe6 f02d97f2923801d99f3dd769654032cb12ce7266 f02d97f2923801d99f3dd769654032cb12ce7266 4c2b15c948deb5ac11fbd034872081dd93b029aa 4c2b15c948deb5ac11fbd034872081dd93b029aa 6fef3e6460425a7627a787fee924c8077ceae6b6 6fef3e6460425a7627a787fee924c8077ceae6b6 03921a66f9001e8fbc4252a2c355763aef6b2198 03921a66f9001e8fbc4252a2c355763aef6b2198 db55d34798110efd902302e670128e5860e4e820 db55d34798110efd902302e670128e5860e4e820 c9f20f12f36bad0d76d71faaac64f7d1a45a610e,367ffc5bdf35456922c1d3ceebbe633b65a65bcf c9f20f12f36bad0d76d71faaac64f7d1a45a610e 3d4fba2e820c1e62f2bc2822311388172aeece58 3d4fba2e820c1e62f2bc2822311388172aeece58 681523dd88dc59a656b458bad144821ec5ac1411 681523dd88dc59a656b458bad144821ec5ac1411 23a58a862f09874f9977dc7e56866c9537b25b3b 23a58a862f09874f9977dc7e56866c9537b25b3b 156279118f7b88026768cec53312a037e6361062 156279118f7b88026768cec53312a037e6361062 8b3c7571c1376d5d6bf49935e2ecdb37ab18a82f 367ffc5bdf35456922c1d3ceebbe633b65a65bcf e1e57863eaf85b8ab3f383491a1ead12a9b46b79,e24a447e399223972ac25a520705a99221429b82 e1e57863eaf85b8ab3f383491a1ead12a9b46b79 0193399945554a426feec8595486cbc212259970 e24a447e399223972ac25a520705a99221429b82 0193399945554a426feec8595486cbc212259970 0193399945554a426feec8595486cbc212259970 37d16ef457b144b699e5d0456a8110e697b0e892 8b3c7571c1376d5d6bf49935e2ecdb37ab18a82f c3f58e0a36a34fc63b39a0e8b6dd714452a81b38 c3f58e0a36a34fc63b39a0e8b6dd714452a81b38 462317ce59bff2956b603255c533579cd960e2c1 462317ce59bff2956b603255c533579cd960e2c1 9d160839b2b6ef2f1f4ec697a4bb58595b9749ed,37d16ef457b144b699e5d0456a8110e697b0e892 37d16ef457b144b699e5d0456a8110e697b0e892 9529e99c78d2bf1ffb1b0fd6d53f8e80c73eba17 9d160839b2b6ef2f1f4ec697a4bb58595b9749ed 879965196f0456b5d09c387f51ad1aa8bc517b7e 879965196f0456b5d09c387f51ad1aa8bc517b7e 074a5dfda2c9ce4d5d98e092edef0214a15e1243 074a5dfda2c9ce4d5d98e092edef0214a15e1243 a6e3ff583a14d4a5ca8d660859a00e7501a9a4bd a6e3ff583a14d4a5ca8d660859a00e7501a9a4bd 6ba016ecfeaf3ae2aa56e66040cc96270b94b147,d0c812fcf1a7463a75a4b0821aad7b53a698ae94 6ba016ecfeaf3ae2aa56e66040cc96270b94b147 51bf826840a8c9ae4cad2e8b5ef6d52183ede70f,9529e99c78d2bf1ffb1b0fd6d53f8e80c73eba17 d0c812fcf1a7463a75a4b0821aad7b53a698ae94 51bf826840a8c9ae4cad2e8b5ef6d52183ede70f 9529e99c78d2bf1ffb1b0fd6d53f8e80c73eba17 164020026e3a719738a3bb388ed211c757b66327 164020026e3a719738a3bb388ed211c757b66327 79f23e4a0a71efe4bcfd5d12194b5be8116b3d95 79f23e4a0a71efe4bcfd5d12194b5be8116b3d95 7dbdcbf5a0b70e2610cc6a033d855cf49277c14b 51bf826840a8c9ae4cad2e8b5ef6d52183ede70f c9f5ad314ed551d772f67971e2bf31c41c86c692 c9f5ad314ed551d772f67971e2bf31c41c86c692 cd0ae03e77f5e6b40577d94b4cad95beb0024205 7dbdcbf5a0b70e2610cc6a033d855cf49277c14b 4021551b199416dec89ccf166f168aef66cf4607 cd0ae03e77f5e6b40577d94b4cad95beb0024205 34c17b3528a056aa806b966b8fe2c875dcdfcf0f 34c17b3528a056aa806b966b8fe2c875dcdfcf0f 28423d419711ab263d31dffd54765ac939b04ed8 28423d419711ab263d31dffd54765ac939b04ed8 4021551b199416dec89ccf166f168aef66cf4607 4021551b199416dec89ccf166f168aef66cf4607 99e278145e3f48aa41d9eec257ed0e9682d80449 99e278145e3f48aa41d9eec257ed0e9682d80449 a0e6c2fdcb7cc5b53a65c204e6aacd6a41980d60 a0e6c2fdcb7cc5b53a65c204e6aacd6a41980d60 4e53ed2041f4640f0f9bd87af471042a56d55539 4e53ed2041f4640f0f9bd87af471042a56d55539 f7368a81a94f513114cb2cc1fed5f0b72269356e f7368a81a94f513114cb2cc1fed5f0b72269356e 1aa2709b5fa6242898d01a2c7a65dac7478a65f0 1aa2709b5fa6242898d01a2c7a65dac7478a65f0 7458dc962f7de10c581e01d58ed10a190e725a95 7458dc962f7de10c581e01d58ed10a190e725a95 7c99ac42bb0d578a369f60222222878bb4bb2cea 7c99ac42bb0d578a369f60222222878bb4bb2cea 5df054d940f33812707b7c4db2ecbabb88c007f9 5df054d940f33812707b7c4db2ecbabb88c007f9 e37d51cfa5b7019e32b59051293ac069a7eb3c76 e37d51cfa5b7019e32b59051293ac069a7eb3c76 36d5ae8d9f42524366b6f3e0766235258888f879 36d5ae8d9f42524366b6f3e0766235258888f879 7e2466117d4b0a7b8d3c096d65254c3a72deaf4d 7e2466117d4b0a7b8d3c096d65254c3a72deaf4d 9fa5ffffd985c6c6835789649594f4c3eabe3e58 9fa5ffffd985c6c6835789649594f4c3eabe3e58 070a358879597c688719a64957b27b06c6ae3470 070a358879597c688719a64957b27b06c6ae3470 c7af076fb5441a6521944c470fcc7eb7e2379d1a c7af076fb5441a6521944c470fcc7eb7e2379d1a fca9c83d5196974ec2583dc568cd6d4d13373700 fca9c83d5196974ec2583dc568cd6d4d13373700 00f6f2a2c39c22d21672f6c7d906c690d0df8df4 00f6f2a2c39c22d21672f6c7d906c690d0df8df4 2d41b2e87dc70ee208e16fb5dbdbddb807635f4d 2d41b2e87dc70ee208e16fb5dbdbddb807635f4d 844ff4c128bf32c32a02735411dbf058e5a1ed6b 844ff4c128bf32c32a02735411dbf058e5a1ed6b 224048bd1995aca9704c0bd8e3702b3da8d89b13 224048bd1995aca9704c0bd8e3702b3da8d89b13 578c1ae2425620886ec2a98b800bdfc5a75fedd6 578c1ae2425620886ec2a98b800bdfc5a75fedd6 201844bfafadb8adbb2f8e8b66d024d0798561c0 201844bfafadb8adbb2f8e8b66d024d0798561c0 9b45090ffbfdaa2b89d848b421a48b2df083977e 9b45090ffbfdaa2b89d848b421a48b2df083977e e313d518c57ab333d2f81356e52ca3cf884672f0 e313d518c57ab333d2f81356e52ca3cf884672f0 6f67e195394c055bd1f81e09f12dcd12b7b00594 6f67e195394c055bd1f81e09f12dcd12b7b00594 e94599755425765da97442e9b266d93f465df718 e94599755425765da97442e9b266d93f465df718 16da8558ede201d82667e5df765977aa99888f7b 16da8558ede201d82667e5df765977aa99888f7b 02787730a2e6787aeb1dc8cbd2d20e43925b9272 6fa2e78406096d30186b3237e119aa7d40206316 9ab2add492901a823f238b673f091a011a259f95 9ab2add492901a823f238b673f091a011a259f95 77cd1aff880b9ae014d9495bfc358095c1007049 77cd1aff880b9ae014d9495bfc358095c1007049 a7636bcfcc51032fb33630218d9761b01c219465 a7636bcfcc51032fb33630218d9761b01c219465 dde06b663fd358e1704ecf43df3465204be6a92e dde06b663fd358e1704ecf43df3465204be6a92e 7e32aa8d9e0889efc2f30250e52aa82a832272a3 7e32aa8d9e0889efc2f30250e52aa82a832272a3 69d1d314cd31b774f4336fa2c8906e4387696013 69d1d314cd31b774f4336fa2c8906e4387696013 7ed5a5de192f37b2b56057b1d227d870c55eb769 02787730a2e6787aeb1dc8cbd2d20e43925b9272 bce20f2af9049caf12c4cab893672a0c7db2f76a 7ed5a5de192f37b2b56057b1d227d870c55eb769 bf33407036998851ea0546470d52a8954d3df5b2 bf33407036998851ea0546470d52a8954d3df5b2 841c3f498e72b482c6dc66631427ab1292cef062 841c3f498e72b482c6dc66631427ab1292cef062 27e03ab10c5de7b1c9479842a274873824d726f0 27e03ab10c5de7b1c9479842a274873824d726f0 b433734ae4d1cd0014708b7172d9cb16303105b9 b433734ae4d1cd0014708b7172d9cb16303105b9 f7cdc16245d3f850767e0c1e4b4ec954d0fa0be4 bce20f2af9049caf12c4cab893672a0c7db2f76a c5229569095ff3749bf58ea164ae082ef65a6937 f7cdc16245d3f850767e0c1e4b4ec954d0fa0be4 830231e6626606438e35d7d4320cd5a449db60ad 830231e6626606438e35d7d4320cd5a449db60ad 88ef67d3eeb590a2f45277fa236264eeda6677f5 88ef67d3eeb590a2f45277fa236264eeda6677f5 600378be441be44b2ec38356993736c374d604cf c5229569095ff3749bf58ea164ae082ef65a6937 a7f72a923ae16e361ae18fc8473754ea2de4b1da a7f72a923ae16e361ae18fc8473754ea2de4b1da 80a94ea109520c8cc719f9f7fb83e78f670a2c06 80a94ea109520c8cc719f9f7fb83e78f670a2c06 c8e58c2956d3ae8924cea61bbfc83fd3f0914b6f 600378be441be44b2ec38356993736c374d604cf f27cf9f446e2c0181415ed25d55c5047200c63ef c8e58c2956d3ae8924cea61bbfc83fd3f0914b6f e22603e687c8a3c0e025a432e8082431420c3d66 e22603e687c8a3c0e025a432e8082431420c3d66 2454028ce7b5efdf6e1c7c467846d322c9b6e8c7 f27cf9f446e2c0181415ed25d55c5047200c63ef 2daae45b51f3454a8f74d876ab6adf98e9fdf836 2daae45b51f3454a8f74d876ab6adf98e9fdf836 27df8e8106135e2cd38975f36f07fdb4d944d484 27df8e8106135e2cd38975f36f07fdb4d944d484 04fc782eae164945d7eca8c85d44ea51c525d547 04fc782eae164945d7eca8c85d44ea51c525d547 577bbbab0b399075da217ec94d0521ae897185b3 2454028ce7b5efdf6e1c7c467846d322c9b6e8c7 c165b411100e84002dded53504d2151a5fda47d5 577bbbab0b399075da217ec94d0521ae897185b3 03fc95cacb87025a409d7dda22687770234e461f 03fc95cacb87025a409d7dda22687770234e461f dfa5ecc8d17d379e8e2961297d116b7d818c9075 dfa5ecc8d17d379e8e2961297d116b7d818c9075 2415804df98278e66a8f2a3837ec93f4c7ca1823 c165b411100e84002dded53504d2151a5fda47d5 64fa416b34d4225a42ca988820b6cd356dc0419b 64fa416b34d4225a42ca988820b6cd356dc0419b 8ec43965a7e5f43a9090442d36674c16595b9641 8ec43965a7e5f43a9090442d36674c16595b9641 78105f5bdbb89ab66f1f2aa409e58d9c9a5cd59f 78105f5bdbb89ab66f1f2aa409e58d9c9a5cd59f 8a260ddbc7f6c72167041280ae17c74934db579b 2415804df98278e66a8f2a3837ec93f4c7ca1823 e057f70f5187dd2e058d15950be4eac0cd49e4ad e057f70f5187dd2e058d15950be4eac0cd49e4ad c54ed87ce367cf35aaf0916a9d3bf7108a52477c c54ed87ce367cf35aaf0916a9d3bf7108a52477c 3decad145bdb968c13959f6f2d7e6b85ca2079b7 3decad145bdb968c13959f6f2d7e6b85ca2079b7 2c1a4adb23ced0b1be1e6b237573f08c48806cdf 2c1a4adb23ced0b1be1e6b237573f08c48806cdf 5c9f3ec17a904eb05e916b3bca595db7ffd12a0e 5c9f3ec17a904eb05e916b3bca595db7ffd12a0e 339aab0882a72b280c84f94b39d94e6f1b101b32 339aab0882a72b280c84f94b39d94e6f1b101b32 740d248cf846ed8128931483a12247ed3a179813 740d248cf846ed8128931483a12247ed3a179813 76caa1268409ae81c086266f91a1904711e90cc1 76caa1268409ae81c086266f91a1904711e90cc1 b7a9734bdf60928400cdc3785c6c0e47ed4ca7fd 8a260ddbc7f6c72167041280ae17c74934db579b 368d761da8fa62ab3fed5bad2aa03bd156d4fd4d,33694be5f862fb551556bc292347983d3629009b 368d761da8fa62ab3fed5bad2aa03bd156d4fd4d 634c52d06c7fd44853ffba7bf5dce34256570a7f 634c52d06c7fd44853ffba7bf5dce34256570a7f b3fbd7024b3f06a8d4dd4bda1cad1c8614367514 b7a9734bdf60928400cdc3785c6c0e47ed4ca7fd 7a5eb536d0e29f04d7927150d3e8bfa43150191f 33694be5f862fb551556bc292347983d3629009b e6e04b8c79af9dba388b2d7bdaaef52e4b46d1ee e6e04b8c79af9dba388b2d7bdaaef52e4b46d1ee dc43b3418e799d4a28a530781b89111b32fea18f dc43b3418e799d4a28a530781b89111b32fea18f b3fbd7024b3f06a8d4dd4bda1cad1c8614367514 7a5eb536d0e29f04d7927150d3e8bfa43150191f 159145e9c371ad7bcab6f91856a06ad57afd509f 159145e9c371ad7bcab6f91856a06ad57afd509f 7f499ea08bb1f3f491aac185a980444ddb694d54 7f499ea08bb1f3f491aac185a980444ddb694d54 b056a2ef6454c89441a49ff127e73ea1d3a5e4bc b056a2ef6454c89441a49ff127e73ea1d3a5e4bc 8fb98dda5f358dfeca48c1d054fe474521ed8c45 8fb98dda5f358dfeca48c1d054fe474521ed8c45 5f97e5ae8d8d44f424886e7dce0224698a157516 5f97e5ae8d8d44f424886e7dce0224698a157516 566a3b0cf88b86bb0c2da1fea2ad970004d12d47 566a3b0cf88b86bb0c2da1fea2ad970004d12d47 d6f3b7c58c9ec886897422a482ca25123ea92ccb d6f3b7c58c9ec886897422a482ca25123ea92ccb 016c7dba29c59cccea17fb2a1bcc93a839cb38d9 016c7dba29c59cccea17fb2a1bcc93a839cb38d9 792cf5fe01f5cf08c1c69bcc242b5ff0fa6e970d 792cf5fe01f5cf08c1c69bcc242b5ff0fa6e970d cfaa83fc7069a9cd0ee9d930b7d2c97042f517a0 cfaa83fc7069a9cd0ee9d930b7d2c97042f517a0 3405d7b2dbfe7eb8f4bb9ce55fb4aa4298d820c4 3405d7b2dbfe7eb8f4bb9ce55fb4aa4298d820c4 d22d4fa40848bafb724a0624c3d6d45da92f7982 d22d4fa40848bafb724a0624c3d6d45da92f7982 074c36575043c530d29db1f9029aa9aecfc2df78 074c36575043c530d29db1f9029aa9aecfc2df78 1773996e332e9fe68035384e4ea956345e5349aa 1773996e332e9fe68035384e4ea956345e5349aa 93858377ad386a94ea9d93b82725bcd351222921 93858377ad386a94ea9d93b82725bcd351222921 23f8fa562020b18153f44fe614bfb6e10576c723 23f8fa562020b18153f44fe614bfb6e10576c723 036b7a9d4e9ad3bc6ec6c8a009b7104708bf2ea4 036b7a9d4e9ad3bc6ec6c8a009b7104708bf2ea4 6afd2e723ab6072f128b66ebdae01d4f84fdaf3c 6afd2e723ab6072f128b66ebdae01d4f84fdaf3c fde3cd0ad14f2e195c1dfd46a5ad3abf3bfd8f6d fde3cd0ad14f2e195c1dfd46a5ad3abf3bfd8f6d 932f8e97c02dd4a1a6a905862ade47d5a33ecefc 932f8e97c02dd4a1a6a905862ade47d5a33ecefc 813b6b2b305151df1a237a4e3f9f3b3e2ca77efb 813b6b2b305151df1a237a4e3f9f3b3e2ca77efb b564e3a921293af1df4c6425823045d083ea7abc b564e3a921293af1df4c6425823045d083ea7abc d684bd81f12e96d65885c9d23936bf313fdac673 d684bd81f12e96d65885c9d23936bf313fdac673 9f0b57c507c1c8f7eff359e8ebd0047084138ff2 9f0b57c507c1c8f7eff359e8ebd0047084138ff2 6b93274918649a6b61050d37c9aa787bb99b1db0 6b93274918649a6b61050d37c9aa787bb99b1db0 5751790037c9a2a99b68388d884c2b514179d44a 5751790037c9a2a99b68388d884c2b514179d44a d64b4b4760be2163a0b5e0321248fd1635dc8277 d64b4b4760be2163a0b5e0321248fd1635dc8277 ebaba5e3733c35203175a40998d9b6f11ade5217 ebaba5e3733c35203175a40998d9b6f11ade5217 a8e82ae9f4bd20bea816b3be31549e58fb7a70e6 a8e82ae9f4bd20bea816b3be31549e58fb7a70e6 232c8ec0e8f142e78bad8f775bd65054b4a6997b 232c8ec0e8f142e78bad8f775bd65054b4a6997b 01be4cf099557c79896956dcf4d0575cd97b71fd 01be4cf099557c79896956dcf4d0575cd97b71fd f83553313cf13c83e8bc13cf8d4c2f071e7a7145 f83553313cf13c83e8bc13cf8d4c2f071e7a7145 22eaf9c6fa040e13c652928b8bd56797ca3c6ae5 22eaf9c6fa040e13c652928b8bd56797ca3c6ae5 f22dab86da656a98303cfa4839907922ed3fbe52 f22dab86da656a98303cfa4839907922ed3fbe52 082ff62d8007aee4c47867bc92261c623d536e83 082ff62d8007aee4c47867bc92261c623d536e83 0df1257922823f33bc48f8d468825ac205477c7c 0df1257922823f33bc48f8d468825ac205477c7c 093e8bc8c2728655b17aeba753a25665ce1c4535 093e8bc8c2728655b17aeba753a25665ce1c4535 d636d628b5a0f41bff89d72b66f374764f85fc69 b3fbd7024b3f06a8d4dd4bda1cad1c8614367514 3eaa18cb5bd478a6d2dc747bef1073b29113abe8 d636d628b5a0f41bff89d72b66f374764f85fc69 28468fe546a2cc9fd6650cac6a4064b70d0ebbe2 28468fe546a2cc9fd6650cac6a4064b70d0ebbe2 07e5f0959111e1144339881645dd599bf793c9ca 07e5f0959111e1144339881645dd599bf793c9ca 6871dc0b7945ef34afd2eadd67f4d32e9a1f4105 3eaa18cb5bd478a6d2dc747bef1073b29113abe8 8a70b57bea4d1e5312f8826ffa5f16417531bbae 6871dc0b7945ef34afd2eadd67f4d32e9a1f4105 b7b562b7b3af9671b0c986dcfdd98972607216a3 b7b562b7b3af9671b0c986dcfdd98972607216a3 028f0d8c40e871fdf6ce62f08a8e5805d513c6a9 028f0d8c40e871fdf6ce62f08a8e5805d513c6a9 77149209be527afd33c4f67b37e55cb5d64b982b 77149209be527afd33c4f67b37e55cb5d64b982b fc8c642fb9b81ae9bcbc73cf5e0036231e09f15b fc8c642fb9b81ae9bcbc73cf5e0036231e09f15b 129edccbd5f34d3128bbb177bd104bad684d7eb4 129edccbd5f34d3128bbb177bd104bad684d7eb4 a1f5573562dd58df7106703a41665b233bf82753 a1f5573562dd58df7106703a41665b233bf82753 78799c8e556b479804fcf4b9cd8e487a405e90b5 78799c8e556b479804fcf4b9cd8e487a405e90b5 1d3928260aa5e7503ca7ccdf71236c9849e51cff 1d3928260aa5e7503ca7ccdf71236c9849e51cff f6d852ea5423899a904625e7ffb4afbdf2dd3045 3dee8c9dd39b25a661cb50f7ed4e9b5533de0489 9b6c3193e6f492c668c89846b83b3a6b0a8f0a7a f6d852ea5423899a904625e7ffb4afbdf2dd3045 9b6c3193e6f492c668c89846b83b3a6b0a8f0a7a 9b6c3193e6f492c668c89846b83b3a6b0a8f0a7a 99551309fa5760491b267e1754c2ee79a9c31c6f 99551309fa5760491b267e1754c2ee79a9c31c6f dc7ab217fe2743658babab5613b2451356e448ed dc7ab217fe2743658babab5613b2451356e448ed 0869d10a938cbcba1b028d87fd7a6cc843303683 0869d10a938cbcba1b028d87fd7a6cc843303683 71a141e42eef4f86e4e1ce50b9aebbf5bf80b0ef 71a141e42eef4f86e4e1ce50b9aebbf5bf80b0ef 386b7b1848ab5f0babbbc73fa424b2514472e359 386b7b1848ab5f0babbbc73fa424b2514472e359 2d1ae5e50841133cb6e39e5e60eb89c368b42ff0 2d1ae5e50841133cb6e39e5e60eb89c368b42ff0 0ffb3c1a2bc275dd5482538586860091b97e9b5f 0ffb3c1a2bc275dd5482538586860091b97e9b5f 634d2c37e0e30b768fcf211d9ae70a6f4860cdf2 634d2c37e0e30b768fcf211d9ae70a6f4860cdf2 a114850abbcb083dc50de6e75cadaeb9ba3ea54c a114850abbcb083dc50de6e75cadaeb9ba3ea54c 54f26c491b0d2dd73fc2c9e7823e3aca72a9f5a2,8a70b57bea4d1e5312f8826ffa5f16417531bbae 8a70b57bea4d1e5312f8826ffa5f16417531bbae 65e88e7bdc2bf7140c941bb20d46cb5875ee35d9 65e88e7bdc2bf7140c941bb20d46cb5875ee35d9 92c72d977c5f448716b94425e030b6f759d89ba3,78c9e0e0c54cab356975604dd664f0df46404580 92c72d977c5f448716b94425e030b6f759d89ba3 a7fef27f05f019b017d6c204aabf432f42b9b40e a7fef27f05f019b017d6c204aabf432f42b9b40e 61dc513a05232d6f7bb36636190b31cda11feace 61dc513a05232d6f7bb36636190b31cda11feace 57d0d68288770282c430fa37afeb360fd9425c8c 57d0d68288770282c430fa37afeb360fd9425c8c 84f39d59fbcb3bc49fa4c856d7126f1adc2f5d4a 84f39d59fbcb3bc49fa4c856d7126f1adc2f5d4a ffb3fa86c6fd6939f728d06b404414cfd9ef55d5 54f26c491b0d2dd73fc2c9e7823e3aca72a9f5a2 5b4dacbff273c38e8706c3aa60a2121d18b3f7d3 5b4dacbff273c38e8706c3aa60a2121d18b3f7d3 fcf5650f1fe9f9a54858beab9087c62539873b93 fcf5650f1fe9f9a54858beab9087c62539873b93 b767764b1adf9413412a3572d33a40a548d30bf9 b767764b1adf9413412a3572d33a40a548d30bf9 e300afb35f20d9867341f92c250e911729cc8453,ffb3fa86c6fd6939f728d06b404414cfd9ef55d5 ffb3fa86c6fd6939f728d06b404414cfd9ef55d5 0d84db9635a9271fa8b4009346c38a35b266b914 e300afb35f20d9867341f92c250e911729cc8453 38212a804adc593bc4386c7445e5932b618605a9 38212a804adc593bc4386c7445e5932b618605a9 0d84db9635a9271fa8b4009346c38a35b266b914 0d84db9635a9271fa8b4009346c38a35b266b914 ad4a6187780e93ca8e49892b4c9b787fc18ab4cb,3e30a989772d3d1931bbe7a7065a905be61385c8 ad4a6187780e93ca8e49892b4c9b787fc18ab4cb 1153bc2fbaf02086ad2b989accba68e6a9cb5ab5 1153bc2fbaf02086ad2b989accba68e6a9cb5ab5 8f2462ead6441802a313373831c049a10465ba73 8f2462ead6441802a313373831c049a10465ba73 7c04317658e9e33cc13113d833b0dff1c92c134e 3e30a989772d3d1931bbe7a7065a905be61385c8 16ede37af50bf397cb08a4b83766a7c7465857d9,7c04317658e9e33cc13113d833b0dff1c92c134e 7c04317658e9e33cc13113d833b0dff1c92c134e 20a8d29b9b4732f0aaa19129e9fa35cb95404edc 20a8d29b9b4732f0aaa19129e9fa35cb95404edc 931244e94b062bb1a9d7af0078fc55465079d14c 16ede37af50bf397cb08a4b83766a7c7465857d9 c4b5049ef650faded2af059d1e2dd2357f917a77,641de07eb28ec9fc09db6a32cf9c82908a8f8fdd c4b5049ef650faded2af059d1e2dd2357f917a77 741ee4b6a72d021b97712a303f6b3dfd5e91e379,e9444e85d37ef71fae8264684e627d14ccdb0e34,931244e94b062bb1a9d7af0078fc55465079d14c 931244e94b062bb1a9d7af0078fc55465079d14c 769eada4588c4c14812c10d8bfcec36e169b46c5 741ee4b6a72d021b97712a303f6b3dfd5e91e379 769eada4588c4c14812c10d8bfcec36e169b46c5,1fe765631fd96ed6e04304818a102c7a232d106e 769eada4588c4c14812c10d8bfcec36e169b46c5 702e56f5a226458ce02fba6c18902b0b7bef2926 702e56f5a226458ce02fba6c18902b0b7bef2926 b2688e276938c63f0e83343755c96e4ee87dcc8d b2688e276938c63f0e83343755c96e4ee87dcc8d e45a9670135d682a6a5f2af660950a6b8b2f589c e45a9670135d682a6a5f2af660950a6b8b2f589c f20587918bc5e1886f910058e5189d33ca07e2bb f20587918bc5e1886f910058e5189d33ca07e2bb ae80d00cc7e94dbfbe164d9a63022f16c61082b2 ae80d00cc7e94dbfbe164d9a63022f16c61082b2 eb90f6fe980d47e0aeec5e24b106ff77ee4373bf eb90f6fe980d47e0aeec5e24b106ff77ee4373bf 2e84f80306de8d059a99affe97a6566244630b50 2e84f80306de8d059a99affe97a6566244630b50 ffaeb9b69270c01c528394cb080e2ba815b0413b ffaeb9b69270c01c528394cb080e2ba815b0413b ec5345e6ecc7783dee188df0d4eae343912d9eac ec5345e6ecc7783dee188df0d4eae343912d9eac 731033a46a8632934c70c4a5aa1d354e91e2619f 731033a46a8632934c70c4a5aa1d354e91e2619f 37a2da3f610d19d28099467f73fabe68713dd44b 37a2da3f610d19d28099467f73fabe68713dd44b f08db11c36260ef555311695aef4290b4e6a22ee f08db11c36260ef555311695aef4290b4e6a22ee af3a660dfbb6065dafea4b91677da02ef8398f7a af3a660dfbb6065dafea4b91677da02ef8398f7a 19f2bc121f642d42ac3ccfab583566cc567bf0b0 19f2bc121f642d42ac3ccfab583566cc567bf0b0 a36cdd0820c18f70ccc19e284c4b81dd1b8be2a1 a36cdd0820c18f70ccc19e284c4b81dd1b8be2a1 00665c494078299dd945b4c438f8d7644cd04608 00665c494078299dd945b4c438f8d7644cd04608 965c3fa0774eee49c5d8a6b128cf820a41f95fb6,f66fad5ea749f3df400e17e58c347b99e380a2dc 965c3fa0774eee49c5d8a6b128cf820a41f95fb6 059415e777ed0967b88997c5e11f10e417024926,f7a5f0b8f14cda009733dc89a69c97a60a7ee4fe 059415e777ed0967b88997c5e11f10e417024926 d3caf011b4c7ec0b40cadc97bd5d619654e5d03b,f66fad5ea749f3df400e17e58c347b99e380a2dc d3caf011b4c7ec0b40cadc97bd5d619654e5d03b 2c08c1f7c0493877c114715633c59bc2381a1113 f7a5f0b8f14cda009733dc89a69c97a60a7ee4fe b129805ac85708a12a222c298b9c361f6ccf116d 2c08c1f7c0493877c114715633c59bc2381a1113 49469ad16e121ddc47ac2cb268a71f5fe4e84e2f 49469ad16e121ddc47ac2cb268a71f5fe4e84e2f 1aaf1064c64285d7466f05f2521d0a3554ea5fb0 1aaf1064c64285d7466f05f2521d0a3554ea5fb0 eecf6b993e5deb874410fa317bb020d3b68b76e1 eecf6b993e5deb874410fa317bb020d3b68b76e1 57d7865ae2c1a2a34822f253dcf9655e2e65de5c 57d7865ae2c1a2a34822f253dcf9655e2e65de5c 0be89c389a4609197fe89dcda300528fc8c35c5a 0be89c389a4609197fe89dcda300528fc8c35c5a b129805ac85708a12a222c298b9c361f6ccf116d b129805ac85708a12a222c298b9c361f6ccf116d f3be772e6ca62c38a11429c4c833cb038efe88e4 f3be772e6ca62c38a11429c4c833cb038efe88e4 2cf2b7b1449efe706e802779e083fe6b358450b5,234608b6ff336c17a62e728fa8940e81393ef2d9 2cf2b7b1449efe706e802779e083fe6b358450b5 44b91abd1f8477a45c7e257a51f5053e1fa207e1 44b91abd1f8477a45c7e257a51f5053e1fa207e1 ca9da88e3e855c589ccb1d55c6661c76724b5279,1b5d412efbfb5634ce7799a505afe4925825df0f ca9da88e3e855c589ccb1d55c6661c76724b5279 e03d5c75f8af0be58e38b630f20de226de34a355 e03d5c75f8af0be58e38b630f20de226de34a355 231a14dc2dd954ba25edc51a72e662daa53a192e 231a14dc2dd954ba25edc51a72e662daa53a192e ec43e24ac438d698688e9afdd1a8e5edac65d67d ec43e24ac438d698688e9afdd1a8e5edac65d67d 351fd3ff4fd7df647baa430e6ed5a131824d655d 351fd3ff4fd7df647baa430e6ed5a131824d655d ac8a516285c3fc79a272f935794a42e06621b46f ac8a516285c3fc79a272f935794a42e06621b46f 3a76f000c0bfa520b3b8d28b68d118caf37ef60d 3a76f000c0bfa520b3b8d28b68d118caf37ef60d b7dfc5691b1deb29ddc0ff2d0d8417914960581f b7dfc5691b1deb29ddc0ff2d0d8417914960581f ab579cdb7a3bc9bca352591376aa7ac11ffe871b ab579cdb7a3bc9bca352591376aa7ac11ffe871b db1d22eadb8a586d7fc580a3d82029bdf7443d3c,8e9712a5d398a9fe5f8934af787d5d5d95a49a15 db1d22eadb8a586d7fc580a3d82029bdf7443d3c f61052be3c1cb795806f4c8895add22d6d1c9bf8,1550ea7ddf75b4478f9cf8719b00fc1cafa26a1e f61052be3c1cb795806f4c8895add22d6d1c9bf8 8293650fcd428a498d500053f6d145e51b6ca526,2ea9ce81b49510a06465aa57e03fa9f5846abed7 8293650fcd428a498d500053f6d145e51b6ca526 6fbc0a6bcf00bdf91d1ad9d133b34a29751ae9df 6fbc0a6bcf00bdf91d1ad9d133b34a29751ae9df 2be9e621916f2895bc52f74d45a2c65b0d10f91c 2be9e621916f2895bc52f74d45a2c65b0d10f91c c038aff905aa4ecad62a1da3d559d4bbd7ed2204,fe83540f6ad304de3f03fda268112557485781de c038aff905aa4ecad62a1da3d559d4bbd7ed2204 28de54b8dbfb3b2e5038fb59ab43ecf869733e70 28de54b8dbfb3b2e5038fb59ab43ecf869733e70 61b1af2634de8b4dd1da756c3c7a57620b517aa6 61b1af2634de8b4dd1da756c3c7a57620b517aa6 54a615c4aafa3617e6a60b911277ed87d163a162 54a615c4aafa3617e6a60b911277ed87d163a162 16e5e51d776f635f0aeec080a5e4c26645cf83f6 16e5e51d776f635f0aeec080a5e4c26645cf83f6 4b37eea7d09d818497b7fdaca5f139d64823e288 4b37eea7d09d818497b7fdaca5f139d64823e288 002d037cb3d0cbab979b4e2e14b09e16ab2c76ee 002d037cb3d0cbab979b4e2e14b09e16ab2c76ee 183f89d3457c45a95e5a70bd77943526eb59e45f 183f89d3457c45a95e5a70bd77943526eb59e45f fa5f74982be4138bda1124183612e353bfe37503 fa5f74982be4138bda1124183612e353bfe37503 3a179173299d7fdbd0cdeb64095bdd889ae3994f 3a179173299d7fdbd0cdeb64095bdd889ae3994f d9ba150235432800ddbd88b1c1d36ec2d1fb3169 d9ba150235432800ddbd88b1c1d36ec2d1fb3169 7ef81d8632ba5534eba2e00152396bf19fae1066,589e316b300ba53abd4c61730283ec7a3026de79 7ef81d8632ba5534eba2e00152396bf19fae1066 7b1e0451690771f00400b797fbda41496c3941b0 7b1e0451690771f00400b797fbda41496c3941b0 73cb4bf58e99c6154baa6981ca3e144c4bcbd03c,1d106be1728ca9ca36f72f9c60f0238bdba094e7 73cb4bf58e99c6154baa6981ca3e144c4bcbd03c 2aaccbd409e28b08e66b8271cce18279d363d982,1b4e30d106adb0ba869c736335aede5e1fd7359d 2aaccbd409e28b08e66b8271cce18279d363d982 31c8ca7f7868fc612e50a40a8b336abfe59947c2,ef2ec4a2aa8bbc0c3f805b815729f8b3430ac207 adbeb66c05311ae7dd12044e50ffe30a7bac4d5c e52f8b2513cf17879f6a00d912aa445b35a45d76 31c8ca7f7868fc612e50a40a8b336abfe59947c2 081ae45cc81c7d9bbcf14dbf11e947868786f4ca 081ae45cc81c7d9bbcf14dbf11e947868786f4ca 8fe99604383456d3e09bf637076453d9c103690f 8fe99604383456d3e09bf637076453d9c103690f 29f35f475c1ed2287f876308834d179cd39611ca e52f8b2513cf17879f6a00d912aa445b35a45d76 0c8e6ec6fdc3c7fbab8ca602f6aeb6cf430add71 0c8e6ec6fdc3c7fbab8ca602f6aeb6cf430add71 bea6ae9a16fa70b27d1b341e7c280af1e97e31c0 bea6ae9a16fa70b27d1b341e7c280af1e97e31c0 13061daea933c0ca8871abf3aa7d09a75b224706 13061daea933c0ca8871abf3aa7d09a75b224706 e69f5bdf52f9b9757fc8db839951fa114296d6b4 e69f5bdf52f9b9757fc8db839951fa114296d6b4 e7f856437160ec8916590616ec6f4b3fd17ce57d 29f35f475c1ed2287f876308834d179cd39611ca 55bfa73d283ae904ae5cea04b8b27e6c3a75eb3a e7f856437160ec8916590616ec6f4b3fd17ce57d 977b907588e312b9feb26c3c49f168aaec0ac0e1 977b907588e312b9feb26c3c49f168aaec0ac0e1 e0622d9f3d96c83e832c2e833c3d619e1ce765dd e0622d9f3d96c83e832c2e833c3d619e1ce765dd b28d552c97adc2d965ab7babf7c890e56e4eb4ce b28d552c97adc2d965ab7babf7c890e56e4eb4ce 366547935e9b654834b37a1cf05cf02a8bf1bbb0 366547935e9b654834b37a1cf05cf02a8bf1bbb0 86a0fe717f7d121df52f81d3b4447c6d89d68c63 86a0fe717f7d121df52f81d3b4447c6d89d68c63 20ab92b6e4a54fbc9f880852cbea28dc4a880f08 20ab92b6e4a54fbc9f880852cbea28dc4a880f08 439caadb720f77df4157a7622ec441c6a01c6890 439caadb720f77df4157a7622ec441c6a01c6890 82da6b65d8f801579b16415c2d2bc937694dbabd 82da6b65d8f801579b16415c2d2bc937694dbabd e660d445bedeea6fc21810ef805b072b12056719 e660d445bedeea6fc21810ef805b072b12056719 f8012076472f9a344abd6e7bafe3fd87c8714c47 f8012076472f9a344abd6e7bafe3fd87c8714c47 959864784f3e7cf5452de90a774c7772eb3f7e51 959864784f3e7cf5452de90a774c7772eb3f7e51 6899c9d176819ece27b00273876bea0647978d87 6899c9d176819ece27b00273876bea0647978d87 723893d25c365adf9a50c309bd86458bad42e854 723893d25c365adf9a50c309bd86458bad42e854 3484aad0053fc732860b110832ad11b445a45a20 1d106be1728ca9ca36f72f9c60f0238bdba094e7 b5a0ecc65a1717a86364171529faf7352cd06bff,55bfa73d283ae904ae5cea04b8b27e6c3a75eb3a 3484aad0053fc732860b110832ad11b445a45a20 da6d7b66552aac978cb586e2851fb56dfd167326,55bfa73d283ae904ae5cea04b8b27e6c3a75eb3a da6d7b66552aac978cb586e2851fb56dfd167326 b0a3cd70ab279e18883552db4a58982f84247294 b0a3cd70ab279e18883552db4a58982f84247294 60b0f467ffc8670113b608b2ddbf88278a8a4ecf 60b0f467ffc8670113b608b2ddbf88278a8a4ecf b5a0ecc65a1717a86364171529faf7352cd06bff 55bfa73d283ae904ae5cea04b8b27e6c3a75eb3a 582b7fa0fbd2cecebceaa05b153860a49174d68f 582b7fa0fbd2cecebceaa05b153860a49174d68f 7566f2bf71d40b4db4e7c42a4ed5b9604f5cc01c 7566f2bf71d40b4db4e7c42a4ed5b9604f5cc01c c7a72a621149e788759cc375d5edf021a4eb35b5,06d1c273aab289fb1085e2d470c892222ca9086b c7a72a621149e788759cc375d5edf021a4eb35b5 4952641dd93462e7fde19779ba307e3e8e970816 4952641dd93462e7fde19779ba307e3e8e970816 3c893a4210512daa70e7c955633e824f84d32d30,017981efcd5dbe3b7a59e19a0b8b1b3345a3deb9 017981efcd5dbe3b7a59e19a0b8b1b3345a3deb9 900b334740ad45bcbcfc7421e0703a51890f05c5 900b334740ad45bcbcfc7421e0703a51890f05c5 d9e675ce754550947c6e46586afc9705499a27fb d9e675ce754550947c6e46586afc9705499a27fb 3c893a4210512daa70e7c955633e824f84d32d30 b5a0ecc65a1717a86364171529faf7352cd06bff 1254c88236907d47f7445c3f21ddb2606a3ea264 1254c88236907d47f7445c3f21ddb2606a3ea264 542b91337514945425da3d5722a87c0564d068c8,3c893a4210512daa70e7c955633e824f84d32d30 3c893a4210512daa70e7c955633e824f84d32d30 d26d705d6d4ae7234ee0a81b5ade3861e21abf15 542b91337514945425da3d5722a87c0564d068c8 50ea23ff376618ba330117cf27c0d105f4e4e35b 50ea23ff376618ba330117cf27c0d105f4e4e35b d26d705d6d4ae7234ee0a81b5ade3861e21abf15 d26d705d6d4ae7234ee0a81b5ade3861e21abf15 ac0148ceafdaced62f5dfa03eaabb657185608de ac0148ceafdaced62f5dfa03eaabb657185608de 430f66247caec1a031a28b997f05a6f84155adda 430f66247caec1a031a28b997f05a6f84155adda 1f6bb250f849ccfceb3ca03d383913896c7ca04b 1f6bb250f849ccfceb3ca03d383913896c7ca04b 6d8663e1519c3c38126b6b35a7dc51d10692b558 ed59d297988963292cb5f31798edb2c095027d2c c6ecb4ee03f6726df71fd4c74448315bdd31c285 6d8663e1519c3c38126b6b35a7dc51d10692b558 32331b404a5e8fd77f7f83a15ef6e0dad4556959,85039c3ea470a14df0c2ce193ed4bc101b0ba761 85039c3ea470a14df0c2ce193ed4bc101b0ba761 32331b404a5e8fd77f7f83a15ef6e0dad4556959 c6ecb4ee03f6726df71fd4c74448315bdd31c285 32331b404a5e8fd77f7f83a15ef6e0dad4556959 32331b404a5e8fd77f7f83a15ef6e0dad4556959 16c73ccb256348cf2de008746ea8d8a61c164173 16c73ccb256348cf2de008746ea8d8a61c164173 8fddfd8f37adc66bdca13e41909e34bfe95ca285 8fddfd8f37adc66bdca13e41909e34bfe95ca285 c066b7977151553d9ec37f5db8eb3776ee1d8c88 c066b7977151553d9ec37f5db8eb3776ee1d8c88 738e6abeed9a984f31700812d084cd6ec40fe47d 738e6abeed9a984f31700812d084cd6ec40fe47d 59a626c53fe61faf9fd4a1565814c0087d38e8b0 aefba9d5f100edcf3c42a787563a2c231f7d27a6 99dec402d5e4207653a81fb914c06cfb50359d7c 99dec402d5e4207653a81fb914c06cfb50359d7c 86beaad7468f163c3efd9f7f224e29768bfbbf0e 86beaad7468f163c3efd9f7f224e29768bfbbf0e 386832d44235c0915bd0c59098ed39eeadc5d789 386832d44235c0915bd0c59098ed39eeadc5d789 adb0f2f99cc50f48d0c1be93f04c78f2ed71f9e3 adb0f2f99cc50f48d0c1be93f04c78f2ed71f9e3 f2aaee910053f7f2803ae67858011d7aaa50a1bd f2aaee910053f7f2803ae67858011d7aaa50a1bd 884a77869d8281d66058ef769c4f880fb6f51865 884a77869d8281d66058ef769c4f880fb6f51865 8a363f876e77ab3e144a67ef3120384b6b1b513c 8a363f876e77ab3e144a67ef3120384b6b1b513c 59a626c53fe61faf9fd4a1565814c0087d38e8b0 59a626c53fe61faf9fd4a1565814c0087d38e8b0 4c0b5593dd64f4f03ea32ee9d1853347fa022db8 4c0b5593dd64f4f03ea32ee9d1853347fa022db8 a5596b73e4822e25faf10acd35abf01b9b111b07 a5596b73e4822e25faf10acd35abf01b9b111b07 5834a7acc8eaf3139a43dac4f56bb59a9c4679e8 5834a7acc8eaf3139a43dac4f56bb59a9c4679e8 74324f583bc9dd7317a7c31cc6a3fd754693a903 74324f583bc9dd7317a7c31cc6a3fd754693a903 eb63661bd1476f9156c6cf61534644f5b2d7b6bc,71d89918c0e5efb435591a5e25dd67b157540146 71d89918c0e5efb435591a5e25dd67b157540146 934132ed7c6b885d00911062f5e0d2cad1032f8b 934132ed7c6b885d00911062f5e0d2cad1032f8b edcc532c167c4ae2b74d6cbbe040ae356e1862f3 edcc532c167c4ae2b74d6cbbe040ae356e1862f3 a647090d9409d12c72248d6b4a20ad38d252214a a647090d9409d12c72248d6b4a20ad38d252214a eb63661bd1476f9156c6cf61534644f5b2d7b6bc eb63661bd1476f9156c6cf61534644f5b2d7b6bc dbcb3cf9a959924a84fdc7cf79d1887c5e95f4dd dbcb3cf9a959924a84fdc7cf79d1887c5e95f4dd b2e6ae7b8938c2518d58179bf92c54d7454c5243 b2e6ae7b8938c2518d58179bf92c54d7454c5243 a4dbbfa5fddfc3e167a1b4c05e57336b05ee9222 a4dbbfa5fddfc3e167a1b4c05e57336b05ee9222 22faaf83686db877ff9058220271ba8827717a9b 22faaf83686db877ff9058220271ba8827717a9b 2b11d3acea19d9917ac6a3b11c71e44d52c200d3 2b11d3acea19d9917ac6a3b11c71e44d52c200d3 866681b74e95b997147b99c51e07da5d60feb432 866681b74e95b997147b99c51e07da5d60feb432 494eadce2e32082499eddbf082ccc0e49ece3466 494eadce2e32082499eddbf082ccc0e49ece3466 c45b0ca87c2b86f41f14bac0b162a446681aa601 c45b0ca87c2b86f41f14bac0b162a446681aa601 11a467a8ef91545bb242890660b7c1ed16481f55 11a467a8ef91545bb242890660b7c1ed16481f55 be6116e971bb865603ed4a6c8f83bd691c54422a fff83466f384a50a9cdbc24fdbec64fbe97b397b be6116e971bb865603ed4a6c8f83bd691c54422a be6116e971bb865603ed4a6c8f83bd691c54422a 38764bf86da93d5795e40d18947e4c6a8d71842f 38764bf86da93d5795e40d18947e4c6a8d71842f 566569e56f5ce387da9bd1238e12e4a4673193a9 566569e56f5ce387da9bd1238e12e4a4673193a9 33cf143a502e8422991ffd33794c4344e3cfd733 33cf143a502e8422991ffd33794c4344e3cfd733 2a51bc466941c8e4cc79a790df3b41f94efe902e 2a51bc466941c8e4cc79a790df3b41f94efe902e 67b2c7d27d32bc86e5c85546911865e6d53cbbd2 67b2c7d27d32bc86e5c85546911865e6d53cbbd2 d12eb7e791044c266d07998cd4e302390f73c881 d12eb7e791044c266d07998cd4e302390f73c881 5d8a2f9b91d23ef0302b3adf7c8c307a138eb03e 5d8a2f9b91d23ef0302b3adf7c8c307a138eb03e 6c93b89220d50081c68cfcc49a18b3f413c91044 6c93b89220d50081c68cfcc49a18b3f413c91044 6733bbf4a7a0255f2134f3bc7013a3a0b44d9723 6733bbf4a7a0255f2134f3bc7013a3a0b44d9723 e669693ecfde3d8f65b6f79da4c0a5275908855a e669693ecfde3d8f65b6f79da4c0a5275908855a 0a8c497528261aa173658da4e2b416b3a58071f8 0a8c497528261aa173658da4e2b416b3a58071f8 058bef15102031f9c04c7887b6497986f722513c 058bef15102031f9c04c7887b6497986f722513c e4339a3c50515554d514886f630f68557ccc57a3,7a8dbd329924b2c3a1c5b3dd7a754ae677995f25 7a8dbd329924b2c3a1c5b3dd7a754ae677995f25 52591d24f412f3dedf650c931009dfe99dd74b3e e4339a3c50515554d514886f630f68557ccc57a3 1b80dd0400d1deace38ef139ff02ff621f785bdf 1b80dd0400d1deace38ef139ff02ff621f785bdf fd4c0d8701b7646e93dba00409e9022dac714827 52591d24f412f3dedf650c931009dfe99dd74b3e fb7e6638f82b75f13d06d9695667992eba806073 fd4c0d8701b7646e93dba00409e9022dac714827 b04e689404c660fdf6727bf2645dd515f6a2fed4 b04e689404c660fdf6727bf2645dd515f6a2fed4 83edad0b8e3b7d7932fa579d0dce19b074773b29 83edad0b8e3b7d7932fa579d0dce19b074773b29 10d6c50ecd62eaaf8476fd1f7878a7e6a4b9bf0f,27a8f638a910eca20e09ad51deb3ea22182077e8 10d6c50ecd62eaaf8476fd1f7878a7e6a4b9bf0f 97716c5057503600ac267505e910b7b601c2ae26 97716c5057503600ac267505e910b7b601c2ae26 fb7e6638f82b75f13d06d9695667992eba806073 fb7e6638f82b75f13d06d9695667992eba806073 d55ba5cbfdf0cb089cdb58a32d7aaea623fef1ed d55ba5cbfdf0cb089cdb58a32d7aaea623fef1ed 6f7d6654c501279e136dae443ed655021fc25124 6f7d6654c501279e136dae443ed655021fc25124 949d5407dbad5db056abd5b028a9cdce2c3eae58 949d5407dbad5db056abd5b028a9cdce2c3eae58 6139430731c2e3daf64bf3515effab4064da2eef 6139430731c2e3daf64bf3515effab4064da2eef c1e7660763b4416639fb0e35b58f290da1a854e5 c1e7660763b4416639fb0e35b58f290da1a854e5 c260f8f3ea5df6be3602ccddc140193ba64443fd c260f8f3ea5df6be3602ccddc140193ba64443fd 2f6d498c71980333cb734d6a1226e8ebd46b2bef 2f6d498c71980333cb734d6a1226e8ebd46b2bef 10a8cb99bfe2b89a84510196977d3a6c9401e78c 10a8cb99bfe2b89a84510196977d3a6c9401e78c f4e6b4ecb213799fe9ebfaff2799b803eb4fa53d f4e6b4ecb213799fe9ebfaff2799b803eb4fa53d 6b4a7cf4a41521712a2d8076f3d20acc84111f61 6b4a7cf4a41521712a2d8076f3d20acc84111f61 96a83f9ea5e62c9adced7d43f9818eb86e832d25 96a83f9ea5e62c9adced7d43f9818eb86e832d25 5a7b531a5237bc6f9d8ccdf4ead5db55a8017ce2 5a7b531a5237bc6f9d8ccdf4ead5db55a8017ce2 ac5c30cfa9a0af5aa442b6cf1c3cb60809e6ae9f ac5c30cfa9a0af5aa442b6cf1c3cb60809e6ae9f eed93e593410ead2dfb213c22cd4d461d748caf5 eed93e593410ead2dfb213c22cd4d461d748caf5 681c4c04e0479999d9c39ba33a6c961c5f21e932 681c4c04e0479999d9c39ba33a6c961c5f21e932 268ce73e8a93b35c48177f348e55e2b09ecf2ac2 268ce73e8a93b35c48177f348e55e2b09ecf2ac2 91fc43b9f0070cc6c64f813846a19dc38e5885fe 91fc43b9f0070cc6c64f813846a19dc38e5885fe c4eadcfc06eeb2f82f7e84ebf3c1eede03f20c65 c4eadcfc06eeb2f82f7e84ebf3c1eede03f20c65 50a6d511213fbb79c2105e6478e0a0c89ae32dff 50a6d511213fbb79c2105e6478e0a0c89ae32dff 55ad7b5c0301c04c61f781ec2e7c760eda44b8a5 55ad7b5c0301c04c61f781ec2e7c760eda44b8a5 c64db4cd71340dec95f5e1fb95ce7a5c4b783cbd c64db4cd71340dec95f5e1fb95ce7a5c4b783cbd e15d743b85df021b3c3a8af77165c81db0684ed8 e15d743b85df021b3c3a8af77165c81db0684ed8 8a75426772eb59bd97a9657c5e622a4e934eecb7 8a75426772eb59bd97a9657c5e622a4e934eecb7 7011408fb5511bc3278fa56429b2f4a43819dcc3 7011408fb5511bc3278fa56429b2f4a43819dcc3 ee1d5c9fac14e0c5a23f0b1479968d535cb361ce ee1d5c9fac14e0c5a23f0b1479968d535cb361ce a3760325d1d17ed96dc4138ae6e1f32bb3107f90 a3760325d1d17ed96dc4138ae6e1f32bb3107f90 0323ded23f0f2937f939f8cb935a0529d1eac99c 0323ded23f0f2937f939f8cb935a0529d1eac99c 5cda9f73463a504d040ccce183bcfc3d1239fcd6 5cda9f73463a504d040ccce183bcfc3d1239fcd6 aa94695956a625174f6d85c2f566a81c4107867e aa94695956a625174f6d85c2f566a81c4107867e 03d9a6fefa74839a49232900092f7c5b1a4e53d9 03d9a6fefa74839a49232900092f7c5b1a4e53d9 abf642e1fb04d7765589d5599e0de281bb92029e abf642e1fb04d7765589d5599e0de281bb92029e 0c15178d6d1f09ff8f09fa430bc73adaab1d2d62 0c15178d6d1f09ff8f09fa430bc73adaab1d2d62 708a0404a7604d2efcede5917e3254725bc86acf 708a0404a7604d2efcede5917e3254725bc86acf e174a07c36829083e912566dcd3907aa9bc83877 6929385e83c3c54019e85e5eb4094d0c4fcbcb21 e174a07c36829083e912566dcd3907aa9bc83877 e174a07c36829083e912566dcd3907aa9bc83877 754913fd32aa45542db1ef62fa4a9652b936fc29 64c9c79a950c8a37d631cf7ea078270ac4eca7d9 1519ed155c9c1400fd579bc02cb50e1c47a3a56b 754913fd32aa45542db1ef62fa4a9652b936fc29 0251c2384e7f1b247cb63560c5ef1b5a7ad6331c 0251c2384e7f1b247cb63560c5ef1b5a7ad6331c 8e8dd3185e704f0b699e8712e1d4e1b4bbc94439,7a74b8e95278601116074b745efb8cc0cda35be5 1519ed155c9c1400fd579bc02cb50e1c47a3a56b 5fb5dbfbf78c969ff4590c7d5e6ee60a98d6a256 5fb5dbfbf78c969ff4590c7d5e6ee60a98d6a256 3200899a59caa8666a805583b2c0ea3228931542 3200899a59caa8666a805583b2c0ea3228931542 39082cc602697fab98b65fa1a07daa276f31d1d0 8e8dd3185e704f0b699e8712e1d4e1b4bbc94439 087b1eac2a1b7f3034e6eb39ba4fa6bb545ed25b,cb3bbc9d2e0a39c37bce340972c524a3b0c8e77f 087b1eac2a1b7f3034e6eb39ba4fa6bb545ed25b 1dd24dcdda7d20f38bd88a0c2c01a4283d0e3eb0 39082cc602697fab98b65fa1a07daa276f31d1d0 a00177454224cbad76c210cdb433359f7628ff07 a00177454224cbad76c210cdb433359f7628ff07 8f16c927857bc68a2d317d10641842e5ae4f475e 8f16c927857bc68a2d317d10641842e5ae4f475e 8abfd3775131b06db3b745f1c67a3b9ad5bba6ec 8abfd3775131b06db3b745f1c67a3b9ad5bba6ec 992c83b80ddbf4d0dbd67afd1f5cb0050d9bbacb 992c83b80ddbf4d0dbd67afd1f5cb0050d9bbacb 7a74b8e95278601116074b745efb8cc0cda35be5,00b438b957bdfbe2385f11cbd189ab5ddb02b05c 00b438b957bdfbe2385f11cbd189ab5ddb02b05c eb1aa9c1230160fe1a8cf99c5943c0c19cc4c82d,7a74b8e95278601116074b745efb8cc0cda35be5 eb1aa9c1230160fe1a8cf99c5943c0c19cc4c82d a32edcfb82854905ee5d3efd3a59c158209c4b16 7a74b8e95278601116074b745efb8cc0cda35be5 2741d9eb4fd52f98b05fc33534428c226c016bef a32edcfb82854905ee5d3efd3a59c158209c4b16 c6224b1a9100e05cc5850b3dd5bcdab4c705fbed 2741d9eb4fd52f98b05fc33534428c226c016bef c661628acbf41075ef824a737bc225f6f173a0c6 c661628acbf41075ef824a737bc225f6f173a0c6 56e69f81e0f86eb66f9ab620298f00e4613232d2 c6224b1a9100e05cc5850b3dd5bcdab4c705fbed ac6f23131f686339af403d236dac13c1fd6f2e14,56e69f81e0f86eb66f9ab620298f00e4613232d2 56e69f81e0f86eb66f9ab620298f00e4613232d2 1dd24dcdda7d20f38bd88a0c2c01a4283d0e3eb0 ac6f23131f686339af403d236dac13c1fd6f2e14 f5fba357bdfc3898731bfbb3866ef40ee75b16c0 f5fba357bdfc3898731bfbb3866ef40ee75b16c0 f5559ef39a659c9f42979d45e7583a1d388c881e 1dd24dcdda7d20f38bd88a0c2c01a4283d0e3eb0 b9f1218ee50d5a4df6aa0b76289e826b72d4f1bc f5559ef39a659c9f42979d45e7583a1d388c881e 335c8473b59bdc38492c9ead1bc3a0b5245d2e17 335c8473b59bdc38492c9ead1bc3a0b5245d2e17 e551f1cae08dbe419dc2320cdd30f1cb04dad75b e551f1cae08dbe419dc2320cdd30f1cb04dad75b 90e6a7e419181c0fb3ea16d70a097b7099e25bd4 90e6a7e419181c0fb3ea16d70a097b7099e25bd4 03ef168ab1775755638995b16d4c73ac64776c75 03ef168ab1775755638995b16d4c73ac64776c75 b9f1218ee50d5a4df6aa0b76289e826b72d4f1bc b9f1218ee50d5a4df6aa0b76289e826b72d4f1bc f5f300b27d1b2a90d051f6137dcad9aae07a556c f5f300b27d1b2a90d051f6137dcad9aae07a556c 2d65cd8ad02de59743a61d2a04517f4b3968718b 2d65cd8ad02de59743a61d2a04517f4b3968718b 93e4191ac585f159d69c56d24ff90f8cbd130f72,e99d630f5587c9fc7c3319e98a4c0c45ee3ce939 e99d630f5587c9fc7c3319e98a4c0c45ee3ce939 649822464b92911db5733c5a6cd604d27f691387 649822464b92911db5733c5a6cd604d27f691387 93e4191ac585f159d69c56d24ff90f8cbd130f72 93e4191ac585f159d69c56d24ff90f8cbd130f72 4f2bafcb9e72d6be2bbfd96f8496b897cae985f3 4f2bafcb9e72d6be2bbfd96f8496b897cae985f3 470f227b7c55112c04a4d63ad7e7d081be0b1e36 470f227b7c55112c04a4d63ad7e7d081be0b1e36 5e968a126b69f89494596d6e429dee59826abbf6 5e968a126b69f89494596d6e429dee59826abbf6 8232118283fc2cfa70eec8239a1012a62a15948d,1ba6aba073c6860a1a020486827144afef86abba 8232118283fc2cfa70eec8239a1012a62a15948d 59a93a028a7d69ebeea9d2148615c411bb8be404 1ba6aba073c6860a1a020486827144afef86abba 94a053d0eab42120fb0896f671db5fc1a9de46f5,a2ee369f433a570c5bcf673ec5d57f93a57ce54b 59a93a028a7d69ebeea9d2148615c411bb8be404 a2ee369f433a570c5bcf673ec5d57f93a57ce54b,94a053d0eab42120fb0896f671db5fc1a9de46f5 a2ee369f433a570c5bcf673ec5d57f93a57ce54b 977ca5be29771ae6680f3cee3cb420feb186a691 977ca5be29771ae6680f3cee3cb420feb186a691 9480b4262994433d56ea454f5f942631f4346774 94a053d0eab42120fb0896f671db5fc1a9de46f5 c28e4b5652ff8d1c9c3a5525a3762034086c9ab6 c28e4b5652ff8d1c9c3a5525a3762034086c9ab6 f8b993531b45d0022629fd19ca5340dd9c397618 9480b4262994433d56ea454f5f942631f4346774 9ebad2b30da5317976e8176fc160fccef4c589fb 9ebad2b30da5317976e8176fc160fccef4c589fb 4aeb75f670ba69c9abd0ad109cc2d5b2ff3033d2 4aeb75f670ba69c9abd0ad109cc2d5b2ff3033d2 d668d912e4bf2d89acbe50c524f72e4eaec835dd d668d912e4bf2d89acbe50c524f72e4eaec835dd c2d166b052fc39a8461a56b46d0ee330893402d0 c2d166b052fc39a8461a56b46d0ee330893402d0 90452f880b21795692a2ac3d5113aefc5963abba f8b993531b45d0022629fd19ca5340dd9c397618 90452f880b21795692a2ac3d5113aefc5963abba 90452f880b21795692a2ac3d5113aefc5963abba c280060f24e08bbd58a9d8ea941ff3780ede11d1 c280060f24e08bbd58a9d8ea941ff3780ede11d1 77f61cd330a3ca2373c1d432d05ce087c8fd0db1 77f61cd330a3ca2373c1d432d05ce087c8fd0db1 9e56800a6942b9cc89cd15a1373c414049393b05 9e56800a6942b9cc89cd15a1373c414049393b05 01ed63fe8a3016ef61c067400cee73407c1a4d79,14e9c3fb650acaa291b75625bfa4a58f05c8297e 14e9c3fb650acaa291b75625bfa4a58f05c8297e 01ed63fe8a3016ef61c067400cee73407c1a4d79 01ed63fe8a3016ef61c067400cee73407c1a4d79 d7e5356bcad6e5622ea68cc039e89e86ba749493 d7e5356bcad6e5622ea68cc039e89e86ba749493 3f0d1f8803cb6a95353b635c2dfe9c9cc4ef3899 3f0d1f8803cb6a95353b635c2dfe9c9cc4ef3899 b5ed77d7454aac9d98703f7cd688bf408847c1ee b5ed77d7454aac9d98703f7cd688bf408847c1ee 2a86e587bcf4871707cb3aa55ceb44702495b91d 2a86e587bcf4871707cb3aa55ceb44702495b91d 497953438434d529d1362091a6ee1fbca1ef2ee9 497953438434d529d1362091a6ee1fbca1ef2ee9 1e9a20f13ab327da684893f312d18f06815f5a77,ae42e0260e2f476bb6c0558e1604d9b812a4b004 ae42e0260e2f476bb6c0558e1604d9b812a4b004 ae21e2aec14b38a3186f609656779e22eec3a11b ae21e2aec14b38a3186f609656779e22eec3a11b 915e74bc332cca88f57964fe501c1d5c05b6e79a 915e74bc332cca88f57964fe501c1d5c05b6e79a d05d52e7504b851b0932af9d52fbef30e08accca d05d52e7504b851b0932af9d52fbef30e08accca 1e9a20f13ab327da684893f312d18f06815f5a77 1e9a20f13ab327da684893f312d18f06815f5a77 b7bca59fa9703a5a024fc550340524fc591132fc b7bca59fa9703a5a024fc550340524fc591132fc f598a7e51ea45ca101f2e89a1b31aa0618a9041e,18868f44fd07e5c73329377c60e946c8c4c4efb5 f598a7e51ea45ca101f2e89a1b31aa0618a9041e b6ea4f981a526654afe9d6d30d5b462ae3a0cf62 b6ea4f981a526654afe9d6d30d5b462ae3a0cf62 c57a166878875b960e8051d72eec716c016baf5b c57a166878875b960e8051d72eec716c016baf5b f1ae1885662d78efd7bc206352c21a1a974a2c0b f1ae1885662d78efd7bc206352c21a1a974a2c0b ab7e6db80c30b830ec8dc016e162f52b2ee7eb94 ab7e6db80c30b830ec8dc016e162f52b2ee7eb94 6961246ad7afecc990d346b9d2f543b6abb76bf7 6961246ad7afecc990d346b9d2f543b6abb76bf7 97727e82b875406e51e022fcddc642180f06e675 97727e82b875406e51e022fcddc642180f06e675 3321c2c52278ba7f8d12aaea3cbc07f6a505fedc 3321c2c52278ba7f8d12aaea3cbc07f6a505fedc 067b4c3661c6a97f88ff34072107ee601e782183 067b4c3661c6a97f88ff34072107ee601e782183 cd9d9347c272aa02e2292cc3fa2fd599f53bd2f8 cd9d9347c272aa02e2292cc3fa2fd599f53bd2f8 64d93529768e368d3dbf59e3da39a1750ab556bb 64d93529768e368d3dbf59e3da39a1750ab556bb 30b0302862cb860f31ab9ab80e7fc8874e5be1a5 30b0302862cb860f31ab9ab80e7fc8874e5be1a5 83fad2f941618f4b3efe58a2a40354e7d7f228e9 83fad2f941618f4b3efe58a2a40354e7d7f228e9 744916ab205a49f31e30a3c215c50b9c1e7ba43c 744916ab205a49f31e30a3c215c50b9c1e7ba43c 8a292192e55474a928883137244d11ff852ac2f5 8a292192e55474a928883137244d11ff852ac2f5 d2b6ddbe9c4dc205ed92955daceae90b976399e4 d2b6ddbe9c4dc205ed92955daceae90b976399e4 794d62eebe3a2bb8dc687152712f02804c76714e 794d62eebe3a2bb8dc687152712f02804c76714e 856838e0f017591c07fa91f41cdca3423710d1a1 856838e0f017591c07fa91f41cdca3423710d1a1 6f2b3e137f04276d578b367adf5b8ef4b1b75e7a 6f2b3e137f04276d578b367adf5b8ef4b1b75e7a f37121f8b18ab9076f299c55249a5f4a5ce83602,fde3dc46b70e5b82c514fe2af4c02cc0c6c8cf78 fde3dc46b70e5b82c514fe2af4c02cc0c6c8cf78 504c555d5a09ab502c55ef8f6eba884ae8090421 504c555d5a09ab502c55ef8f6eba884ae8090421 0179214de8763308df414fdd8c25174c2c4d1ac6 0179214de8763308df414fdd8c25174c2c4d1ac6 237a19178bf7b962c419090447ed12b093f98031 237a19178bf7b962c419090447ed12b093f98031 be9acfd8edc953fd7c1a27df479f5dcb22d3d023 be9acfd8edc953fd7c1a27df479f5dcb22d3d023 6b11655edddb7fe8219566adf05a7313cd3f3a52 f37121f8b18ab9076f299c55249a5f4a5ce83602 3271143f7080ffd0be43286f513b58200a6bde42 6b11655edddb7fe8219566adf05a7313cd3f3a52 fe0ca9de59f0dd99b5fb45340b42bc2884b263f6 3271143f7080ffd0be43286f513b58200a6bde42 fe0ca9de59f0dd99b5fb45340b42bc2884b263f6 ee563960f8474b8b2d6ef1d964ce55be449caa94 fe0ca9de59f0dd99b5fb45340b42bc2884b263f6 fe0ca9de59f0dd99b5fb45340b42bc2884b263f6 114eed176f7dc84e70c567f7a20d59093bed7105,e4b276aa24aa86724ac0cd824a7227881519c126,ece2bfcae2b3897da82c44c8371486191f1e8c10 114eed176f7dc84e70c567f7a20d59093bed7105 a8cb71c532ecef1e04cc0090d7bbc9953f673362 a8cb71c532ecef1e04cc0090d7bbc9953f673362 b79b86ca4b2865063eac92cbdee0fbb37c5f0743 b79b86ca4b2865063eac92cbdee0fbb37c5f0743 de8934622a88ef3efcae29b44871ffbbbaff4753 de8934622a88ef3efcae29b44871ffbbbaff4753 08a3d6e3440b4221f4191377a95795e408e90962 08a3d6e3440b4221f4191377a95795e408e90962 6275b9b5c591725e9d838cfb0d9a69a676cfb736 0fe0deb19435d23d4b71a8b359dcaf38963b7e2e ece2bfcae2b3897da82c44c8371486191f1e8c10 ece2bfcae2b3897da82c44c8371486191f1e8c10 776745031ae77aa2af8cafe7d4f6084780499182 776745031ae77aa2af8cafe7d4f6084780499182 3d4ae9e02e2e680af484d3072dd52945b6c5b83f 3d4ae9e02e2e680af484d3072dd52945b6c5b83f c460b80adbd94283479a317a59632e9ccf4600ce c460b80adbd94283479a317a59632e9ccf4600ce 6275b9b5c591725e9d838cfb0d9a69a676cfb736,0b61bcfc94a82dde32ed899aaebf16a055aa4de9 6275b9b5c591725e9d838cfb0d9a69a676cfb736 aaa37a7f4af579627ee26c512e13e995f0d0f777,5be250d6fc1102b29d0529bc344ab2f604b9e71f aaa37a7f4af579627ee26c512e13e995f0d0f777 bfb563fbe2b0771d55b0f58de88c52b0e65e5157 bfb563fbe2b0771d55b0f58de88c52b0e65e5157 ba67d062aed155feb5898ba14710bb9373576d44 0b61bcfc94a82dde32ed899aaebf16a055aa4de9 ba67d062aed155feb5898ba14710bb9373576d44 ba67d062aed155feb5898ba14710bb9373576d44 93728683855435e098dd85c5865dc9d5394358d5 93728683855435e098dd85c5865dc9d5394358d5 e4718cf7ed770ae44fa1f433204f0313d2a82fef e4b276aa24aa86724ac0cd824a7227881519c126 b711d2b4301cad9eb2d600792480c8365193e2a1 b711d2b4301cad9eb2d600792480c8365193e2a1 e4718cf7ed770ae44fa1f433204f0313d2a82fef e4718cf7ed770ae44fa1f433204f0313d2a82fef 87b98ca112fd8143b05ee24c80ab6734d0eca45a 87b98ca112fd8143b05ee24c80ab6734d0eca45a 9f03d93cddf2c7503c53eb639fe66d37cefb6a9b 9f03d93cddf2c7503c53eb639fe66d37cefb6a9b 8b52109594c7f506182eb0cf780a8e30d7605ab7 8b52109594c7f506182eb0cf780a8e30d7605ab7 a630d7090cea3b1b4eb0b760d16b11506f8a59b6 a630d7090cea3b1b4eb0b760d16b11506f8a59b6 4432b3c8fa5e5205e70b2195ff3869f1ebee18a5 4432b3c8fa5e5205e70b2195ff3869f1ebee18a5 441e299543e0f819da8d988de6f36e5f593b5582 441e299543e0f819da8d988de6f36e5f593b5582 c8b69bc77f121376922659f8a45b85026798313c c8b69bc77f121376922659f8a45b85026798313c a354b5c1cb82ccca2e2ad6ccbe161f88e2e5f0d4 a354b5c1cb82ccca2e2ad6ccbe161f88e2e5f0d4 68d79bff21bb8edebbe644e4ce83279bf1c680b8 68d79bff21bb8edebbe644e4ce83279bf1c680b8 8de562aa651be4ca133a38bc798c05e5e5d9ac4c 8de562aa651be4ca133a38bc798c05e5e5d9ac4c 39718da514fa680d3b36220f278ded94fb864a8f 39718da514fa680d3b36220f278ded94fb864a8f 2e121e3655c16a333eaafabdf3d9a9be0979a99e 2e121e3655c16a333eaafabdf3d9a9be0979a99e a91345f8e232d8d120a1ba2a6959cf9b3009edaf,70391eee14574b70d75f91f6a7ba24fd0ffd93df a91345f8e232d8d120a1ba2a6959cf9b3009edaf 596110698ae00ddcb774e58070f12f35f67b00ab 596110698ae00ddcb774e58070f12f35f67b00ab 7953e9dc317d38b0b7596c1249c2251c5a8528e4 7953e9dc317d38b0b7596c1249c2251c5a8528e4 4a97fe2a81a0aa10a8bec8e6dea7189f6f3f4dc4 18db59ea626c5bcfe6cad451022a7a369e40fa10 4a97fe2a81a0aa10a8bec8e6dea7189f6f3f4dc4 4a97fe2a81a0aa10a8bec8e6dea7189f6f3f4dc4 7cb9fcca308241b8ee47ac03fbe225f34e4eab44 7cb9fcca308241b8ee47ac03fbe225f34e4eab44 dabd344efb93270ef258726f7870d4485d334add dabd344efb93270ef258726f7870d4485d334add c0aef352366ca03fc684a04a26af9123a2d7f403 c0aef352366ca03fc684a04a26af9123a2d7f403 3eb427f66fab067982a1525785b6035db89f8fc3 3eb427f66fab067982a1525785b6035db89f8fc3 25d7ed4419d1f50254f6b4f42dd78938ac4e5d1e 25d7ed4419d1f50254f6b4f42dd78938ac4e5d1e b5369b3646723455d85a19efde21b54b20f99b27,c60797615037705d285c62bb15b4ff38efa77d1a b5369b3646723455d85a19efde21b54b20f99b27 2f99cf9da6268db580aa2046abcc7a4a70644887,55cc440b5e3701841011542eabd752945e529082 2f99cf9da6268db580aa2046abcc7a4a70644887 c0aaf523c6e77bd3dc079a00b5e34a1584863a8a,3944bdfd6a0741fdd3fdf41c8e6ce4d3c124af66 c0aaf523c6e77bd3dc079a00b5e34a1584863a8a 5824d18b655397fe0c5d316c228a886f70ec7e9c,a399f30afdaeb5b0b247b3cfdef05300c6f3803f 5824d18b655397fe0c5d316c228a886f70ec7e9c b054d488904c1db742d4d491a17a2fc7cd287b9e b054d488904c1db742d4d491a17a2fc7cd287b9e 5fe44e93934b015546033d33ecbff9f3fbec8e9f,621d3c2ef213a43cad70eb978b3308a4c3e0595e 5fe44e93934b015546033d33ecbff9f3fbec8e9f b2ea6646eb94c43ebcbb98463157dcd38c1eac50 b2ea6646eb94c43ebcbb98463157dcd38c1eac50 52d24fd4b2ee1236eb33e6f58ebba63f6af9ba79 52d24fd4b2ee1236eb33e6f58ebba63f6af9ba79 244e676ac0b0e386d7620794d23806c13bca9113 244e676ac0b0e386d7620794d23806c13bca9113 b6bf1dd82ba9dedbbbd963c379960f46a2555df0 2abfcad6eb95acc73472061251b4d9fbb897c989 b6bf1dd82ba9dedbbbd963c379960f46a2555df0 b6bf1dd82ba9dedbbbd963c379960f46a2555df0 0f8fa0be12ccac493e1d7d6be25ddcc7cb16a18e,456c27dbc63c1fd70ae48de899833c5ca02e6e32 456c27dbc63c1fd70ae48de899833c5ca02e6e32 9f5f817c0ed579f0a3a7f3ba3a391403f6ee37bc 9f5f817c0ed579f0a3a7f3ba3a391403f6ee37bc 624ddf95e6b54a943a644c0b5e785c990880999f,0f8fa0be12ccac493e1d7d6be25ddcc7cb16a18e 624ddf95e6b54a943a644c0b5e785c990880999f 9a750784a33ab9d714cdc68949906610f76cb964 9a750784a33ab9d714cdc68949906610f76cb964 0706805720a141819654f6446f832416b5c551a4 0f8fa0be12ccac493e1d7d6be25ddcc7cb16a18e 6f42a208581102d3679d23617d936fa9f3c2225a,6789a2c68486802961334f34c07e8e881261e54c 6789a2c68486802961334f34c07e8e881261e54c a01342192b8f798b5700d48b060a927a1714d636,6f42a208581102d3679d23617d936fa9f3c2225a 6f42a208581102d3679d23617d936fa9f3c2225a 9e070b3017644c5621ea48c2beae202be4232c84,f1f17cc9c784db6de2905ed1374879c7524ba376 0706805720a141819654f6446f832416b5c551a4 92c8226782546e3086fef83d361cf2cc866a9ec1 9e070b3017644c5621ea48c2beae202be4232c84 92c8226782546e3086fef83d361cf2cc866a9ec1,849b4de9ea7d0cdf1fe4006709ee7072f2d13e23 92c8226782546e3086fef83d361cf2cc866a9ec1 170a77e923c53908caff93faf855b22cf871cf6a 170a77e923c53908caff93faf855b22cf871cf6a a533b6fa408fd80356242171e2f827a449ea3812 a533b6fa408fd80356242171e2f827a449ea3812 0ae58081efbb1cc9fc7b20368d9c1208972e767b 0ae58081efbb1cc9fc7b20368d9c1208972e767b 77620de737b78f85f7b30f7e298428ddd67bd928 77620de737b78f85f7b30f7e298428ddd67bd928 b95f77dc672b96ded94aa1392769abcdd8eb2470 b95f77dc672b96ded94aa1392769abcdd8eb2470 9d5efca0bda7c6edb3936805bfb5cd7ae32126dd 9d5efca0bda7c6edb3936805bfb5cd7ae32126dd 703316903c43fb0ee8b445fb4811262fc937968e 703316903c43fb0ee8b445fb4811262fc937968e d5ab33bd7c48cc126fb4ef8f086a6d862df59ef5 d5ab33bd7c48cc126fb4ef8f086a6d862df59ef5 57fdf136efcbda786125e07951d6f8a8b7d14592 57fdf136efcbda786125e07951d6f8a8b7d14592 1b76773ad44f3180d8d0dc4e77dc3b50485aa05d 1b76773ad44f3180d8d0dc4e77dc3b50485aa05d 37803689fe1e764cb95508dad401f34972f73179 37803689fe1e764cb95508dad401f34972f73179 0d58b5f4ddb056a6c8cb2350292d118696aa63b0,f8bf61270c28add4f64ab7d4bc9767a21f18e831 0d58b5f4ddb056a6c8cb2350292d118696aa63b0 76b4277ddca72719e1ce0692c44b8907085f9791 76b4277ddca72719e1ce0692c44b8907085f9791 67151b5753c7819309760ac097aaed33d74e2f93,23745b43026065c5ec6a3d61b964e1d65659036a 67151b5753c7819309760ac097aaed33d74e2f93 a9bdb539385321ec79cace958a816d397b6625c7,43341d56e0f80c10302563c5773d8ed4c2f9f420 a9bdb539385321ec79cace958a816d397b6625c7 5c94f3c9196e51913a0b8516423c95a1cca43362 68a6b805c52f5da6ce3a5c58df25270c2045ab32 adc89fda393154699c1712a5d8869184419dd798 5c94f3c9196e51913a0b8516423c95a1cca43362 c3d314c7c50116890ecf8cb6155c6ca7b9f711ef c3d314c7c50116890ecf8cb6155c6ca7b9f711ef 25f400c8f88eaddd0ca48c63e6e3f0791cc9f21a 25f400c8f88eaddd0ca48c63e6e3f0791cc9f21a 8a40b211a4197f5016f1497240761123a7523fb2 8a40b211a4197f5016f1497240761123a7523fb2 a1dbd06515099561a77523765ad303e23051b456 a1dbd06515099561a77523765ad303e23051b456 2f03232e1d7998dd77f1e118585ba2e1420304e8,5464c15055afb0cf2627838a18d92f1081c7b066 2f03232e1d7998dd77f1e118585ba2e1420304e8 a5ed8f0caaed7d6b63ad93abc1dddeb45a27fb8e a5ed8f0caaed7d6b63ad93abc1dddeb45a27fb8e 2120db9cffa7487197f01bf528fdb79c5319d0c9,2f6825c738be3a9d276e65d43975278ba174d9b5 2120db9cffa7487197f01bf528fdb79c5319d0c9 10b99d180db996c6f438191e7521b7c39826979b,32584d6c1d9d8af3873babb0d356e8400c9582c0 10b99d180db996c6f438191e7521b7c39826979b bcfb084eb25a7124496664afc5c48df85d85e838 bcfb084eb25a7124496664afc5c48df85d85e838 82bd7da1b39153c0429fb36653a21994150420c1 82bd7da1b39153c0429fb36653a21994150420c1 900f227fc0add02b87b86d8c509242eff7a6c264,2890f3b6933eb96b4f338b85524ab4562abda157 900f227fc0add02b87b86d8c509242eff7a6c264 eac8148602a78ff2819b562f63e09679f24b4cbf eac8148602a78ff2819b562f63e09679f24b4cbf 841b30b8c962d535454b80a8e0bb5d4161225699 841b30b8c962d535454b80a8e0bb5d4161225699 277cc86ec7d1921574b6fdc40e5af33efd1d27d4 277cc86ec7d1921574b6fdc40e5af33efd1d27d4 69ed787cf98b13e1c6b9031871fbe5fe88284bd3 69ed787cf98b13e1c6b9031871fbe5fe88284bd3 1bf5c0bd2017622e9d5cad94683a7f00b3a7985d,a692915fb36b1f34dabf71452af63e04c91be209 1bf5c0bd2017622e9d5cad94683a7f00b3a7985d d823b9ddaeb9c1f2dfe6e1e914337bd0543357ae,cd95146b0abcec1cd52629d80db969fdd27fa303 d823b9ddaeb9c1f2dfe6e1e914337bd0543357ae 5148b5915f997c933f63570bdff8461f1aa7278e 5148b5915f997c933f63570bdff8461f1aa7278e a6afe6e1d7adba44262416bd4931e54f70b479d8,1c79e4a8344be1d5d9a293a542fc057aa524c50d a6afe6e1d7adba44262416bd4931e54f70b479d8 fc84397e48939f77d2f783eb85143bd9db674e1a fc84397e48939f77d2f783eb85143bd9db674e1a 20865cc9cf5470ee39ab9e99ef6a853233a9ca2a,e821f056086d11d0a8ff2fa6ae58f5a44678f707 20865cc9cf5470ee39ab9e99ef6a853233a9ca2a ddc112387c36d1c270004bc9458b3cd3d6749ce9 ddc112387c36d1c270004bc9458b3cd3d6749ce9 6a182939795451cf6d3817c41c343ecf905e831c 6a182939795451cf6d3817c41c343ecf905e831c c269abcad799c19d0488a098ad3a861256e4aaac c269abcad799c19d0488a098ad3a861256e4aaac 2a906e05b06fa45908f2cf37b416649fecf09b7e,85fa0e2f1429aadd858971eec1a3798867a5112e 2a906e05b06fa45908f2cf37b416649fecf09b7e 346da738c4dd3e54fc827b42ca65790e22239c23,d806a4bc7493caf7d6ac3d447ec476eb4ce428fd 24a725dc99507e55283f453f7b5ca7d8e70be52f 3766f8e4ea2efd1e01520e99d4e5bf2885c302c4,346da738c4dd3e54fc827b42ca65790e22239c23 7b2c89a42fa0a68561aee72886a479db368d713b fa65768bcc90fec0ddaf912d92a6bda4d06b3f61,346da738c4dd3e54fc827b42ca65790e22239c23 aca1299f55bdb0844095f98de9c4a2008eac6ad0 a16fc0d2d04199c1d6664bc80706f165dc915d39,346da738c4dd3e54fc827b42ca65790e22239c23 346da738c4dd3e54fc827b42ca65790e22239c23 b960ebe7d03d215353778093773b8ce3bcc9fb27,eaf721a3d3f690dc5766dca97c05ee8f779f828b 5464c15055afb0cf2627838a18d92f1081c7b066 259631117742cbc4a691f43bc3ce278082455ab1,39bde846fc3cee61a8ca81872ddde83253f48925 b960ebe7d03d215353778093773b8ce3bcc9fb27 259631117742cbc4a691f43bc3ce278082455ab1,03e6b6ae8854c6f585f3e82553dfc5311e49f53e 259631117742cbc4a691f43bc3ce278082455ab1 cdbe742d201adb616cba467563fb2bfb524dd16a cdbe742d201adb616cba467563fb2bfb524dd16a d7af4dd892b8a48a5107c4bf871d5d25f63e8511 d7af4dd892b8a48a5107c4bf871d5d25f63e8511 614169b1acb86b21b562f807a6b54aa164d4056a 614169b1acb86b21b562f807a6b54aa164d4056a 7e269b22b6070768ce18c0b81d7b802662b2b6ed 7e269b22b6070768ce18c0b81d7b802662b2b6ed 7d703fee73ee850af7325ac7e4eebb6514c2757e 7d703fee73ee850af7325ac7e4eebb6514c2757e 6b673d12166ae1a5729aa517bdfd2e8ad974170e 6b673d12166ae1a5729aa517bdfd2e8ad974170e edc83414c9a7955c8f874c2fed261d8e1ae2eb91 edc83414c9a7955c8f874c2fed261d8e1ae2eb91 17f63f989af77ffcca34d142b8ef5c210323e098 17f63f989af77ffcca34d142b8ef5c210323e098 958206e68abbb9bb2cc76256ab3202363678e61f,06a1cb9d9b23aadc5231cbb188b2fac1003fbe28 958206e68abbb9bb2cc76256ab3202363678e61f da26ce8d3cc378e9e0d8246540197575428132f9 da26ce8d3cc378e9e0d8246540197575428132f9 aeabc7304c582c9a58e6098443430cbd2b323616 aeabc7304c582c9a58e6098443430cbd2b323616 6efedc27d5e08a15fb9501ad32c257738c48334e 6efedc27d5e08a15fb9501ad32c257738c48334e 3a9471a6ea20a92b57325b0c56448d3e313a1d1a,1eb7abcd285650928a22eb81185a63d36b1b2cba 3a9471a6ea20a92b57325b0c56448d3e313a1d1a 6aa0069d074711085d57def494f56ddeb65a7551,6129574e1588a0cf30d5d0762a8cf49a9ebb5585 6aa0069d074711085d57def494f56ddeb65a7551 704e7039441ea5383545da405e3b5f4cf01077c3,b0c45c85fe85689c0c59660a15e3476340b6819a 704e7039441ea5383545da405e3b5f4cf01077c3 b44a2afd2a47a63d510b1d4b7d58cdf5fc13b65d b0c45c85fe85689c0c59660a15e3476340b6819a 8a26c9c9d71007dad93508ff17c5971ff7dc13b3 8a26c9c9d71007dad93508ff17c5971ff7dc13b3 b44a2afd2a47a63d510b1d4b7d58cdf5fc13b65d,8528e93d3ce01d0b8b209c599ab261aa1987a108 b44a2afd2a47a63d510b1d4b7d58cdf5fc13b65d 8bb5134286f52a3dbb1979de5bee25d7460b3c36,09c716a4e30e8744365c158619b44006fbf6d3b6 fa65768bcc90fec0ddaf912d92a6bda4d06b3f61 bb194efe1821622d96c8c43d2a4c9de17e800391,8bb5134286f52a3dbb1979de5bee25d7460b3c36 a01342192b8f798b5700d48b060a927a1714d636 bbe5c643c42223f97c8914ba3cd26b3c8d2c5030,8bb5134286f52a3dbb1979de5bee25d7460b3c36 8bb5134286f52a3dbb1979de5bee25d7460b3c36 cb8d623593567f34e3fbf89a1b640cdb7b1eda75,2fae4888f332dfba920901c5afaf9ac448ca89c9 cb8d623593567f34e3fbf89a1b640cdb7b1eda75 c31a46930cee2835641e43171f6c3f8800da3ae8,e71001dca11670f6e468d5b3c05c78292a748834 c31a46930cee2835641e43171f6c3f8800da3ae8 90059ea0179772a7d296a382bb3c94865003c33e,dec8d412cdcc82e55fd516b1b1a874f290e7a806 90059ea0179772a7d296a382bb3c94865003c33e 07eda936ba952eb3255eca4e2cbc00d49c3fd831,a2b3efa030a54e6cfb6c6736fca7e1e27d07cd15 07eda936ba952eb3255eca4e2cbc00d49c3fd831 0ac98cae0481794557025cd5002aa2508d5347b6 0ac98cae0481794557025cd5002aa2508d5347b6 fdfd424b83ec718a8cf74f38b01d8f1005e01faa,50414b8e0e67e191f1ae38bde54e30189de97b34 fdfd424b83ec718a8cf74f38b01d8f1005e01faa 0cadfc4182b8bb43635020f393f5cdd6578b7cfd 0cadfc4182b8bb43635020f393f5cdd6578b7cfd dcf421dabda2384d57913343e73dd01688eb4dcf dcf421dabda2384d57913343e73dd01688eb4dcf 82e28e89e54c198a6aa3c6435b5b32eec05ed65f 82e28e89e54c198a6aa3c6435b5b32eec05ed65f 657b6ecb353c1f5b0b91d2d5161aff9063af3fb0 657b6ecb353c1f5b0b91d2d5161aff9063af3fb0 afa3279d3b6cb8913ba3d6eed8e635f66fa59d8e,30dc6100056269e9d384711478be9dd1bd744ddf afa3279d3b6cb8913ba3d6eed8e635f66fa59d8e 4485968e237121d19cce63d18312987c84f0860e,599461b731bbb3081f49dcd72c356695da4bf483 4485968e237121d19cce63d18312987c84f0860e 21dd573ab7ab0a63d35c0df07df08dae8b19bb16,08a1393c61b3c6d2ee96a35b52ae945806d0299e 21dd573ab7ab0a63d35c0df07df08dae8b19bb16 66eb2de9fa18125906e5d13abf52705839c9d088,3129220de08efe91135e7b1256772167e0dcdf15 66eb2de9fa18125906e5d13abf52705839c9d088 fc9432d5a51c65f1716cf0ba20b1e693ccd2edce,5941191cd2682ef374df3afeebc0ae9d242162db fc9432d5a51c65f1716cf0ba20b1e693ccd2edce f72fea4b3bc98ca7ab186eacce57b3dfd2557032 f72fea4b3bc98ca7ab186eacce57b3dfd2557032 ade6384a7b0e4d065e18076ffa901e580679e26d,dd090afbe47f0aa25d6ec8cfe484fa02c23eb61a |
Added fossil-utils/justtesting/setup.dat version [27b5f4c974].
> > > > > > > > > | 1 2 3 4 5 6 7 8 9 | [command] 0 rm -rf /tmp/$USER/megatest 1 mkdir -p /tmp/$USER/megatest 2 cp /home/matt/fossils/megatest.fossil /tmp/$USER/megatest 3 cd /tmp/$USER/megatest 4 fossil open megatest.fossil;fossil up trunk 5 fossil set autosync 0 7 fossil set gmerge '' 8 fossil scrub --private --force |
Added fossil-utils/justtesting/sheet-names.cfg version [a2c6169f2d].
> > > > | 1 2 3 4 | timeline extra branches setup |
Added fossil-utils/justtesting/sxml/_sheets.sxml version [170f68b304].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | ((@ (http://www.w3.org/2001/XMLSchema-instance:schemaLocation "http://www.gnumeric.org/v9.xsd")) (http://www.gnumeric.org/v10.dtd:Version (@ (Minor "17") (Major "10") (Full "1.10.17") (Epoch "1"))) (http://www.gnumeric.org/v10.dtd:Attributes (http://www.gnumeric.org/v10.dtd:Attribute (http://www.gnumeric.org/v10.dtd:type "4") (http://www.gnumeric.org/v10.dtd:name "WorkbookView::show_horizontal_scrollbar") (http://www.gnumeric.org/v10.dtd:value "TRUE")) (http://www.gnumeric.org/v10.dtd:Attribute (http://www.gnumeric.org/v10.dtd:type "4") (http://www.gnumeric.org/v10.dtd:name "WorkbookView::show_vertical_scrollbar") (http://www.gnumeric.org/v10.dtd:value "TRUE")) (http://www.gnumeric.org/v10.dtd:Attribute (http://www.gnumeric.org/v10.dtd:type "4") (http://www.gnumeric.org/v10.dtd:name "WorkbookView::show_notebook_tabs") (http://www.gnumeric.org/v10.dtd:value "TRUE")) (http://www.gnumeric.org/v10.dtd:Attribute (http://www.gnumeric.org/v10.dtd:type "4") (http://www.gnumeric.org/v10.dtd:name "WorkbookView::do_auto_completion") (http://www.gnumeric.org/v10.dtd:value "TRUE")) (http://www.gnumeric.org/v10.dtd:Attribute (http://www.gnumeric.org/v10.dtd:type "4") (http://www.gnumeric.org/v10.dtd:name "WorkbookView::is_protected") (http://www.gnumeric.org/v10.dtd:value "FALSE"))) (urn:oasis:names:tc:opendocument:xmlns:office:1.0:document-meta (@ (urn:oasis:names:tc:opendocument:xmlns:office:1.0:version "1.2")) (urn:oasis:names:tc:opendocument:xmlns:office:1.0:meta (http://purl.org/dc/elements/1.1/:date "2020-06-01T04:28:18Z") (urn:oasis:names:tc:opendocument:xmlns:meta:1.0:creation-date "2020-06-01T01:13:31Z"))) (http://www.gnumeric.org/v10.dtd:Calculation (@ (MaxIterations "100") (ManualRecalc "0") (IterationTolerance "0.001") (FloatRadix "2") (FloatDigits "53") (EnableIteration "1"))) (http://www.gnumeric.org/v10.dtd:SheetNameIndex (http://www.gnumeric.org/v10.dtd:SheetName (@ (http://www.gnumeric.org/v10.dtd:Rows "65536") (http://www.gnumeric.org/v10.dtd:Cols "256")) "timeline") (http://www.gnumeric.org/v10.dtd:SheetName (@ (http://www.gnumeric.org/v10.dtd:Rows "65536") (http://www.gnumeric.org/v10.dtd:Cols "256")) "extra") (http://www.gnumeric.org/v10.dtd:SheetName (@ (http://www.gnumeric.org/v10.dtd:Rows "65536") (http://www.gnumeric.org/v10.dtd:Cols "256")) "branches") (http://www.gnumeric.org/v10.dtd:SheetName (@ (http://www.gnumeric.org/v10.dtd:Rows "65536") (http://www.gnumeric.org/v10.dtd:Cols "256")) "setup")) (http://www.gnumeric.org/v10.dtd:Geometry (@ (Width "2220") (Height "804"))) (http://www.gnumeric.org/v10.dtd:UIData (@ (SelectedTab "0")))) |
Added fossil-utils/justtesting/sxml/_workbook.sxml version [96ffb7f9d5].
> | 1 | (*TOP* (*PI* xml "version=\"1.0\" encoding=\"UTF-8\"")) |
Added fossil-utils/justtesting/sxml/branches.sxml version [ba44d3c184].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | (http://www.gnumeric.org/v10.dtd:Sheet (@ (Visibility "GNM_SHEET_VISIBILITY_VISIBLE") (OutlineSymbolsRight "1") (OutlineSymbolsBelow "1") (HideZero "0") (HideRowHeader "0") (HideGrid "0") (HideColHeader "0") (GridColor "0:0:0") (DisplayOutlines "1") (DisplayFormulas "0")) (http://www.gnumeric.org/v10.dtd:MaxCol "8") (http://www.gnumeric.org/v10.dtd:MaxRow "16") (http://www.gnumeric.org/v10.dtd:Zoom "1") (http://www.gnumeric.org/v10.dtd:Names (http://www.gnumeric.org/v10.dtd:Name (http://www.gnumeric.org/v10.dtd:name "Print_Area") (http://www.gnumeric.org/v10.dtd:value "#REF!") (http://www.gnumeric.org/v10.dtd:position "A1")) (http://www.gnumeric.org/v10.dtd:Name (http://www.gnumeric.org/v10.dtd:name "Sheet_Title") (http://www.gnumeric.org/v10.dtd:value "\"First_Sheet\"") (http://www.gnumeric.org/v10.dtd:position "A1"))) (http://www.gnumeric.org/v10.dtd:PrintInformation (http://www.gnumeric.org/v10.dtd:Margins (http://www.gnumeric.org/v10.dtd:top (@ (PrefUnit "mm") (Points "93.26"))) (http://www.gnumeric.org/v10.dtd:bottom (@ (PrefUnit "mm") (Points "93.26"))) (http://www.gnumeric.org/v10.dtd:left (@ (PrefUnit "mm") (Points "72"))) (http://www.gnumeric.org/v10.dtd:right (@ (PrefUnit "mm") (Points "72"))) (http://www.gnumeric.org/v10.dtd:header (@ (PrefUnit "mm") (Points "72"))) (http://www.gnumeric.org/v10.dtd:footer (@ (PrefUnit "mm") (Points "72")))) (http://www.gnumeric.org/v10.dtd:Scale (@ (type "percentage") (percentage "100"))) (http://www.gnumeric.org/v10.dtd:vcenter (@ (value "0"))) (http://www.gnumeric.org/v10.dtd:hcenter (@ (value "0"))) (http://www.gnumeric.org/v10.dtd:grid (@ (value "0"))) (http://www.gnumeric.org/v10.dtd:even_if_only_styles (@ (value "0"))) (http://www.gnumeric.org/v10.dtd:monochrome (@ (value "0"))) (http://www.gnumeric.org/v10.dtd:draft (@ (value "0"))) (http://www.gnumeric.org/v10.dtd:titles (@ (value "0"))) (http://www.gnumeric.org/v10.dtd:do_not_print (@ (value "0"))) (http://www.gnumeric.org/v10.dtd:print_range (@ (value "0"))) (http://www.gnumeric.org/v10.dtd:order "d_then_r") (http://www.gnumeric.org/v10.dtd:orientation "portrait") (http://www.gnumeric.org/v10.dtd:Header (@ (Right "") (Middle "&[tab]") (Left ""))) (http://www.gnumeric.org/v10.dtd:Footer (@ (Right "") (Middle "&[page]") (Left ""))) (http://www.gnumeric.org/v10.dtd:paper "na_letter") (http://www.gnumeric.org/v10.dtd:comments "none") (http://www.gnumeric.org/v10.dtd:errors "as_displayed")) (http://www.gnumeric.org/v10.dtd:Styles (http://www.gnumeric.org/v10.dtd:StyleRegion (@ (startRow "0") (startCol "0") (endRow "65535") (endCol "255")) (http://www.gnumeric.org/v10.dtd:Style (@ (WrapText "0") (VAlign "2") (ShrinkToFit "0") (Shade "0") (Rotation "0") (PatternColor "0:0:0") (Locked "1") (Indent "0") (Hidden "0") (HAlign "1") (Format "General") (Fore "0:0:0") (Back "FFFF:FFFF:FFFF")) (http://www.gnumeric.org/v10.dtd:Font (@ (Unit "10") (Underline "0") (StrikeThrough "0") (Script "0") (Italic "0") (Bold "0")) "Sans")))) (http://www.gnumeric.org/v10.dtd:Cols (@ (DefaultSizePts "48")) (http://www.gnumeric.org/v10.dtd:ColInfo (@ (Unit "95.25") (No "0"))) (http://www.gnumeric.org/v10.dtd:ColInfo (@ (Unit "99") (No "1") (HardSize "1"))) (http://www.gnumeric.org/v10.dtd:ColInfo (@ (Unit "64.01") (No "2") (Count "7")))) (http://www.gnumeric.org/v10.dtd:Rows (@ (DefaultSizePts "12.1")) (http://www.gnumeric.org/v10.dtd:RowInfo (@ (Unit "12.64") (No "0"))) (http://www.gnumeric.org/v10.dtd:RowInfo (@ (Unit "13.5") (No "1") (Count "16")))) (http://www.gnumeric.org/v10.dtd:Selections (@ (CursorRow "2") (CursorCol "1")) (http://www.gnumeric.org/v10.dtd:Selection (@ (startRow "2") (startCol "1") (endRow "2") (endCol "1")))) (http://www.gnumeric.org/v10.dtd:SheetLayout (@ (TopLeft "A2")) (http://www.gnumeric.org/v10.dtd:FreezePanes (@ (UnfrozenTopLeft "A2") (FrozenTopLeft "A1")))) (http://www.gnumeric.org/v10.dtd:Solver (@ (ProgramR "0") (ProblemType "0") (NonNeg "1") (ModelType "0") (MaxTime "60") (MaxIter "1000") (Discr "0") (AutoScale "0")))) |
Added fossil-utils/justtesting/sxml/extra.sxml version [b737f7669d].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | (http://www.gnumeric.org/v10.dtd:Sheet (@ (Visibility "GNM_SHEET_VISIBILITY_VISIBLE") (OutlineSymbolsRight "1") (OutlineSymbolsBelow "1") (HideZero "0") (HideRowHeader "0") (HideGrid "0") (HideColHeader "0") (GridColor "0:0:0") (DisplayOutlines "1") (DisplayFormulas "0")) (http://www.gnumeric.org/v10.dtd:MaxCol "8") (http://www.gnumeric.org/v10.dtd:MaxRow "722") (http://www.gnumeric.org/v10.dtd:Zoom "1") (http://www.gnumeric.org/v10.dtd:Names (http://www.gnumeric.org/v10.dtd:Name (http://www.gnumeric.org/v10.dtd:name "Print_Area") (http://www.gnumeric.org/v10.dtd:value "#REF!") (http://www.gnumeric.org/v10.dtd:position "A1")) (http://www.gnumeric.org/v10.dtd:Name (http://www.gnumeric.org/v10.dtd:name "Sheet_Title") (http://www.gnumeric.org/v10.dtd:value "\"First_Sheet\"") (http://www.gnumeric.org/v10.dtd:position "A1"))) (http://www.gnumeric.org/v10.dtd:PrintInformation (http://www.gnumeric.org/v10.dtd:Margins (http://www.gnumeric.org/v10.dtd:top (@ (PrefUnit "mm") (Points "93.26"))) (http://www.gnumeric.org/v10.dtd:bottom (@ (PrefUnit "mm") (Points "93.26"))) (http://www.gnumeric.org/v10.dtd:left (@ (PrefUnit "mm") (Points "72"))) (http://www.gnumeric.org/v10.dtd:right (@ (PrefUnit "mm") (Points "72"))) (http://www.gnumeric.org/v10.dtd:header (@ (PrefUnit "mm") (Points "72"))) (http://www.gnumeric.org/v10.dtd:footer (@ (PrefUnit "mm") (Points "72")))) (http://www.gnumeric.org/v10.dtd:Scale (@ (type "percentage") (percentage "100"))) (http://www.gnumeric.org/v10.dtd:vcenter (@ (value "0"))) (http://www.gnumeric.org/v10.dtd:hcenter (@ (value "0"))) (http://www.gnumeric.org/v10.dtd:grid (@ (value "0"))) (http://www.gnumeric.org/v10.dtd:even_if_only_styles (@ (value "0"))) (http://www.gnumeric.org/v10.dtd:monochrome (@ (value "0"))) (http://www.gnumeric.org/v10.dtd:draft (@ (value "0"))) (http://www.gnumeric.org/v10.dtd:titles (@ (value "0"))) (http://www.gnumeric.org/v10.dtd:do_not_print (@ (value "0"))) (http://www.gnumeric.org/v10.dtd:print_range (@ (value "0"))) (http://www.gnumeric.org/v10.dtd:order "d_then_r") (http://www.gnumeric.org/v10.dtd:orientation "portrait") (http://www.gnumeric.org/v10.dtd:Header (@ (Right "") (Middle "&[tab]") (Left ""))) (http://www.gnumeric.org/v10.dtd:Footer (@ (Right "") (Middle "&[page]") (Left ""))) (http://www.gnumeric.org/v10.dtd:paper "na_letter") (http://www.gnumeric.org/v10.dtd:comments "none") (http://www.gnumeric.org/v10.dtd:errors "as_displayed")) (http://www.gnumeric.org/v10.dtd:Styles (http://www.gnumeric.org/v10.dtd:StyleRegion (@ (startRow "0") (startCol "0") (endRow "65535") (endCol "255")) (http://www.gnumeric.org/v10.dtd:Style (@ (WrapText "0") (VAlign "2") (ShrinkToFit "0") (Shade "0") (Rotation "0") (PatternColor "0:0:0") (Locked "1") (Indent "0") (Hidden "0") (HAlign "1") (Format "General") (Fore "0:0:0") (Back "FFFF:FFFF:FFFF")) (http://www.gnumeric.org/v10.dtd:Font (@ (Unit "10") (Underline "0") (StrikeThrough "0") (Script "0") (Italic "0") (Bold "0")) "Sans")))) (http://www.gnumeric.org/v10.dtd:Cols (@ (DefaultSizePts "48")) (http://www.gnumeric.org/v10.dtd:ColInfo (@ (Unit "243") (No "0"))) (http://www.gnumeric.org/v10.dtd:ColInfo (@ (Unit "462") (No "1"))) (http://www.gnumeric.org/v10.dtd:ColInfo (@ (Unit "64.01") (No "2") (Count "7")))) (http://www.gnumeric.org/v10.dtd:Rows (@ (DefaultSizePts "12.1")) (http://www.gnumeric.org/v10.dtd:RowInfo (@ (Unit "12.64") (No "0"))) (http://www.gnumeric.org/v10.dtd:RowInfo (@ (Unit "13.5") (No "1") (Count "17"))) (http://www.gnumeric.org/v10.dtd:RowInfo (@ (Unit "12.1") (No "18") (Count "705")))) (http://www.gnumeric.org/v10.dtd:Selections (@ (CursorRow "3") (CursorCol "1")) (http://www.gnumeric.org/v10.dtd:Selection (@ (startRow "3") (startCol "1") (endRow "3") (endCol "1")))) (http://www.gnumeric.org/v10.dtd:SheetLayout (@ (TopLeft "A2")) (http://www.gnumeric.org/v10.dtd:FreezePanes (@ (UnfrozenTopLeft "A2") (FrozenTopLeft "A1")))) (http://www.gnumeric.org/v10.dtd:Solver (@ (ProgramR "0") (ProblemType "0") (NonNeg "1") (ModelType "0") (MaxTime "60") (MaxIter "1000") (Discr "0") (AutoScale "0")))) |
Added fossil-utils/justtesting/sxml/setup.sxml version [1e32386adc].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | (http://www.gnumeric.org/v10.dtd:Sheet (@ (Visibility "GNM_SHEET_VISIBILITY_VISIBLE") (OutlineSymbolsRight "1") (OutlineSymbolsBelow "1") (HideZero "0") (HideRowHeader "0") (HideGrid "0") (HideColHeader "0") (GridColor "0:0:0") (DisplayOutlines "1") (DisplayFormulas "0")) (http://www.gnumeric.org/v10.dtd:MaxCol "1") (http://www.gnumeric.org/v10.dtd:MaxRow "8") (http://www.gnumeric.org/v10.dtd:Zoom "1") (http://www.gnumeric.org/v10.dtd:Names (http://www.gnumeric.org/v10.dtd:Name (http://www.gnumeric.org/v10.dtd:name "Print_Area") (http://www.gnumeric.org/v10.dtd:value "#REF!") (http://www.gnumeric.org/v10.dtd:position "A1")) (http://www.gnumeric.org/v10.dtd:Name (http://www.gnumeric.org/v10.dtd:name "Sheet_Title") (http://www.gnumeric.org/v10.dtd:value "\"setup\"") (http://www.gnumeric.org/v10.dtd:position "A1"))) (http://www.gnumeric.org/v10.dtd:PrintInformation (http://www.gnumeric.org/v10.dtd:Margins (http://www.gnumeric.org/v10.dtd:top (@ (PrefUnit "mm") (Points "120"))) (http://www.gnumeric.org/v10.dtd:bottom (@ (PrefUnit "mm") (Points "120"))) (http://www.gnumeric.org/v10.dtd:left (@ (PrefUnit "mm") (Points "72"))) (http://www.gnumeric.org/v10.dtd:right (@ (PrefUnit "mm") (Points "72"))) (http://www.gnumeric.org/v10.dtd:header (@ (PrefUnit "mm") (Points "72"))) (http://www.gnumeric.org/v10.dtd:footer (@ (PrefUnit "mm") (Points "72")))) (http://www.gnumeric.org/v10.dtd:Scale (@ (type "percentage") (percentage "100"))) (http://www.gnumeric.org/v10.dtd:vcenter (@ (value "0"))) (http://www.gnumeric.org/v10.dtd:hcenter (@ (value "0"))) (http://www.gnumeric.org/v10.dtd:grid (@ (value "0"))) (http://www.gnumeric.org/v10.dtd:even_if_only_styles (@ (value "0"))) (http://www.gnumeric.org/v10.dtd:monochrome (@ (value "0"))) (http://www.gnumeric.org/v10.dtd:draft (@ (value "0"))) (http://www.gnumeric.org/v10.dtd:titles (@ (value "0"))) (http://www.gnumeric.org/v10.dtd:do_not_print (@ (value "0"))) (http://www.gnumeric.org/v10.dtd:print_range (@ (value "0"))) (http://www.gnumeric.org/v10.dtd:order "d_then_r") (http://www.gnumeric.org/v10.dtd:orientation "portrait") (http://www.gnumeric.org/v10.dtd:Header (@ (Right "") (Middle "&[TAB]") (Left ""))) (http://www.gnumeric.org/v10.dtd:Footer (@ (Right "") (Middle "Page &[PAGE]") (Left ""))) (http://www.gnumeric.org/v10.dtd:paper "na_letter") (http://www.gnumeric.org/v10.dtd:comments "none") (http://www.gnumeric.org/v10.dtd:errors "as_displayed")) (http://www.gnumeric.org/v10.dtd:Styles (http://www.gnumeric.org/v10.dtd:StyleRegion (@ (startRow "0") (startCol "0") (endRow "65535") (endCol "255")) (http://www.gnumeric.org/v10.dtd:Style (@ (WrapText "0") (VAlign "2") (ShrinkToFit "0") (Shade "0") (Rotation "0") (PatternColor "0:0:0") (Locked "1") (Indent "0") (Hidden "0") (HAlign "1") (Format "General") (Fore "0:0:0") (Back "FFFF:FFFF:FFFF")) (http://www.gnumeric.org/v10.dtd:Font (@ (Unit "10") (Underline "0") (StrikeThrough "0") (Script "0") (Italic "0") (Bold "0")) "Sans")))) (http://www.gnumeric.org/v10.dtd:Cols (@ (DefaultSizePts "48")) (http://www.gnumeric.org/v10.dtd:ColInfo (@ (Unit "48") (No "0"))) (http://www.gnumeric.org/v10.dtd:ColInfo (@ (Unit "333") (No "1")))) (http://www.gnumeric.org/v10.dtd:Rows (@ (DefaultSizePts "12.75")) (http://www.gnumeric.org/v10.dtd:RowInfo (@ (Unit "13.5") (No "0") (Count "9")))) (http://www.gnumeric.org/v10.dtd:Selections (@ (CursorRow "7") (CursorCol "0")) (http://www.gnumeric.org/v10.dtd:Selection (@ (startRow "7") (startCol "0") (endRow "7") (endCol "255")))) (http://www.gnumeric.org/v10.dtd:SheetLayout (@ (TopLeft "A1"))) (http://www.gnumeric.org/v10.dtd:Solver (@ (ProgramR "0") (ProblemType "0") (NonNeg "1") (ModelType "0") (MaxTime "60") (MaxIter "1000") (Discr "0") (AutoScale "0")))) |
Added fossil-utils/justtesting/sxml/timeline.sxml version [78bf77cda1].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | (http://www.gnumeric.org/v10.dtd:Sheet (@ (Visibility "GNM_SHEET_VISIBILITY_VISIBLE") (OutlineSymbolsRight "1") (OutlineSymbolsBelow "1") (HideZero "0") (HideRowHeader "0") (HideGrid "0") (HideColHeader "0") (GridColor "0:0:0") (DisplayOutlines "1") (DisplayFormulas "0")) (http://www.gnumeric.org/v10.dtd:MaxCol "17") (http://www.gnumeric.org/v10.dtd:MaxRow "65535") (http://www.gnumeric.org/v10.dtd:Zoom "1") (http://www.gnumeric.org/v10.dtd:Names (http://www.gnumeric.org/v10.dtd:Name (http://www.gnumeric.org/v10.dtd:name "Print_Area") (http://www.gnumeric.org/v10.dtd:value "#REF!") (http://www.gnumeric.org/v10.dtd:position "A1")) (http://www.gnumeric.org/v10.dtd:Name (http://www.gnumeric.org/v10.dtd:name "Sheet_Title") (http://www.gnumeric.org/v10.dtd:value "\"First_Sheet\"") (http://www.gnumeric.org/v10.dtd:position "A1"))) (http://www.gnumeric.org/v10.dtd:PrintInformation (http://www.gnumeric.org/v10.dtd:Margins (http://www.gnumeric.org/v10.dtd:top (@ (PrefUnit "mm") (Points "93.26"))) (http://www.gnumeric.org/v10.dtd:bottom (@ (PrefUnit "mm") (Points "93.26"))) (http://www.gnumeric.org/v10.dtd:left (@ (PrefUnit "mm") (Points "72"))) (http://www.gnumeric.org/v10.dtd:right (@ (PrefUnit "mm") (Points "72"))) (http://www.gnumeric.org/v10.dtd:header (@ (PrefUnit "mm") (Points "72"))) (http://www.gnumeric.org/v10.dtd:footer (@ (PrefUnit "mm") (Points "72")))) (http://www.gnumeric.org/v10.dtd:Scale (@ (type "percentage") (percentage "100"))) (http://www.gnumeric.org/v10.dtd:vcenter (@ (value "0"))) (http://www.gnumeric.org/v10.dtd:hcenter (@ (value "0"))) (http://www.gnumeric.org/v10.dtd:grid (@ (value "0"))) (http://www.gnumeric.org/v10.dtd:even_if_only_styles (@ (value "0"))) (http://www.gnumeric.org/v10.dtd:monochrome (@ (value "0"))) (http://www.gnumeric.org/v10.dtd:draft (@ (value "0"))) (http://www.gnumeric.org/v10.dtd:titles (@ (value "0"))) (http://www.gnumeric.org/v10.dtd:do_not_print (@ (value "0"))) (http://www.gnumeric.org/v10.dtd:print_range (@ (value "0"))) (http://www.gnumeric.org/v10.dtd:order "d_then_r") (http://www.gnumeric.org/v10.dtd:orientation "portrait") (http://www.gnumeric.org/v10.dtd:Header (@ (Right "") (Middle "&[tab]") (Left ""))) (http://www.gnumeric.org/v10.dtd:Footer (@ (Right "") (Middle "&[page]") (Left ""))) (http://www.gnumeric.org/v10.dtd:paper "na_letter") (http://www.gnumeric.org/v10.dtd:comments "none") (http://www.gnumeric.org/v10.dtd:errors "as_displayed")) (http://www.gnumeric.org/v10.dtd:Styles (http://www.gnumeric.org/v10.dtd:StyleRegion (@ (startRow "0") (startCol "0") (endRow "255") (endCol "63")) (http://www.gnumeric.org/v10.dtd:Style (@ (WrapText "0") (VAlign "2") (ShrinkToFit "0") (Shade "0") (Rotation "0") (PatternColor "0:0:0") (Locked "1") (Indent "0") (Hidden "0") (HAlign "1") (Format "General") (Fore "0:0:0") (Back "FFFF:FFFF:FFFF")) (http://www.gnumeric.org/v10.dtd:Font (@ (Unit "10") (Underline "0") (StrikeThrough "0") (Script "0") (Italic "0") (Bold "0")) "Sans"))) (http://www.gnumeric.org/v10.dtd:StyleRegion (@ (startRow "256") (startCol "0") (endRow "431") (endCol "7")) (http://www.gnumeric.org/v10.dtd:Style (@ (WrapText "0") (VAlign "2") (ShrinkToFit "0") (Shade "0") (Rotation "0") (PatternColor "0:0:0") (Locked "1") (Indent "0") (Hidden "0") (HAlign "1") (Format "General") (Fore "0:0:0") (Back "FFFF:FFFF:FFFF")) (http://www.gnumeric.org/v10.dtd:Font (@ (Unit "10") (Underline "0") (StrikeThrough "0") (Script "0") (Italic "0") (Bold "0")) "Sans"))) (http://www.gnumeric.org/v10.dtd:StyleRegion (@ (startRow "432") (startCol "0") (endRow "463") (endCol "4")) (http://www.gnumeric.org/v10.dtd:Style (@ (WrapText "0") (VAlign "2") (ShrinkToFit "0") (Shade "0") (Rotation "0") (PatternColor "0:0:0") (Locked "1") (Indent "0") (Hidden "0") (HAlign "1") (Format "General") (Fore "0:0:0") (Back "FFFF:FFFF:FFFF")) (http://www.gnumeric.org/v10.dtd:Font (@ (Unit "10") (Underline "0") (StrikeThrough "0") (Script "0") (Italic "0") (Bold "0")) "Sans"))) (http://www.gnumeric.org/v10.dtd:StyleRegion (@ (startRow "464") (startCol "0") (endRow "511") (endCol "7")) (http://www.gnumeric.org/v10.dtd:Style (@ (WrapText "0") (VAlign "2") (ShrinkToFit "0") (Shade "0") (Rotation "0") (PatternColor "0:0:0") (Locked "1") (Indent "0") (Hidden "0") (HAlign "1") (Format "General") (Fore "0:0:0") (Back "FFFF:FFFF:FFFF")) (http://www.gnumeric.org/v10.dtd:Font (@ (Unit "10") (Underline "0") (StrikeThrough "0") (Script "0") (Italic "0") (Bold "0")) "Sans"))) (http://www.gnumeric.org/v10.dtd:StyleRegion (@ (startRow "512") (startCol "0") (endRow "65535") (endCol "63")) (http://www.gnumeric.org/v10.dtd:Style (@ (WrapText "0") (VAlign "2") (ShrinkToFit "0") (Shade "0") (Rotation "0") (PatternColor "0:0:0") (Locked "1") (Indent "0") (Hidden "0") (HAlign "1") (Format "General") (Fore "0:0:0") (Back "FFFF:FFFF:FFFF")) (http://www.gnumeric.org/v10.dtd:Font (@ (Unit "10") (Underline "0") (StrikeThrough "0") (Script "0") (Italic "0") (Bold "0")) "Sans"))) (http://www.gnumeric.org/v10.dtd:StyleRegion (@ (startRow "432") (startCol "5") (endRow "448") (endCol "5")) (http://www.gnumeric.org/v10.dtd:Style (@ (WrapText "0") (VAlign "2") (ShrinkToFit "0") (Shade "0") (Rotation "0") (PatternColor "0:0:0") (Locked "1") (Indent "0") (Hidden "0") (HAlign "1") (Format "General") (Fore "0:0:0") (Back "FFFF:FFFF:FFFF")) (http://www.gnumeric.org/v10.dtd:Font (@ (Unit "10") (Underline "0") (StrikeThrough "0") (Script "0") (Italic "0") (Bold "0")) "Sans"))) (http://www.gnumeric.org/v10.dtd:StyleRegion (@ (startRow "449") (startCol "5") (endRow "449") (endCol "5")) (http://www.gnumeric.org/v10.dtd:Style (@ (WrapText "0") (VAlign "2") (ShrinkToFit "0") (Shade "0") (Rotation "0") (PatternColor "0:0:0") (Locked "1") (Indent "0") (Hidden "0") (HAlign "1") (Format "General") (Fore "0:0:0") (Back "FFFF:FFFF:FFFF")) (http://www.gnumeric.org/v10.dtd:Font (@ (Unit "10") (Underline "0") (StrikeThrough "0") (Script "0") (Italic "0") (Bold "0")) "Sans"))) (http://www.gnumeric.org/v10.dtd:StyleRegion (@ (startRow "450") (startCol "5") (endRow "463") (endCol "5")) (http://www.gnumeric.org/v10.dtd:Style (@ (WrapText "0") (VAlign "2") (ShrinkToFit "0") (Shade "0") (Rotation "0") (PatternColor "0:0:0") (Locked "1") (Indent "0") (Hidden "0") (HAlign "1") (Format "General") (Fore "0:0:0") (Back "FFFF:FFFF:FFFF")) (http://www.gnumeric.org/v10.dtd:Font (@ (Unit "10") (Underline "0") (StrikeThrough "0") (Script "0") (Italic "0") (Bold "0")) "Sans"))) (http://www.gnumeric.org/v10.dtd:StyleRegion (@ (startRow "432") (startCol "6") (endRow "463") (endCol "7")) (http://www.gnumeric.org/v10.dtd:Style (@ (WrapText "0") (VAlign "2") (ShrinkToFit "0") (Shade "0") (Rotation "0") (PatternColor "0:0:0") (Locked "1") (Indent "0") (Hidden "0") (HAlign "1") (Format "General") (Fore "0:0:0") (Back "FFFF:FFFF:FFFF")) (http://www.gnumeric.org/v10.dtd:Font (@ (Unit "10") (Underline "0") (StrikeThrough "0") (Script "0") (Italic "0") (Bold "0")) "Sans"))) (http://www.gnumeric.org/v10.dtd:StyleRegion (@ (startRow "256") (startCol "8") (endRow "511") (endCol "63")) (http://www.gnumeric.org/v10.dtd:Style (@ (WrapText "0") (VAlign "2") (ShrinkToFit "0") (Shade "0") (Rotation "0") (PatternColor "0:0:0") (Locked "1") (Indent "0") (Hidden "0") (HAlign "1") (Format "General") (Fore "0:0:0") (Back "FFFF:FFFF:FFFF")) (http://www.gnumeric.org/v10.dtd:Font (@ (Unit "10") (Underline "0") (StrikeThrough "0") (Script "0") (Italic "0") (Bold "0")) "Sans"))) (http://www.gnumeric.org/v10.dtd:StyleRegion (@ (startRow "0") (startCol "64") (endRow "65535") (endCol "255")) (http://www.gnumeric.org/v10.dtd:Style (@ (WrapText "0") (VAlign "2") (ShrinkToFit "0") (Shade "0") (Rotation "0") (PatternColor "0:0:0") (Locked "1") (Indent "0") (Hidden "0") (HAlign "1") (Format "General") (Fore "0:0:0") (Back "FFFF:FFFF:FFFF")) (http://www.gnumeric.org/v10.dtd:Font (@ (Unit "10") (Underline "0") (StrikeThrough "0") (Script "0") (Italic "0") (Bold "0")) "Sans")))) (http://www.gnumeric.org/v10.dtd:Cols (@ (DefaultSizePts "48")) (http://www.gnumeric.org/v10.dtd:ColInfo (@ (Unit "243.8") (No "0"))) (http://www.gnumeric.org/v10.dtd:ColInfo (@ (Unit "89.25") (No "1") (HardSize "1") (Count "2"))) (http://www.gnumeric.org/v10.dtd:ColInfo (@ (Unit "51") (No "3") (HardSize "1"))) (http://www.gnumeric.org/v10.dtd:ColInfo (@ (Unit "49.5") (No "4") (HardSize "1"))) (http://www.gnumeric.org/v10.dtd:ColInfo (@ (Unit "105") (No "5") (HardSize "1"))) (http://www.gnumeric.org/v10.dtd:ColInfo (@ (Unit "48") (No "6"))) (http://www.gnumeric.org/v10.dtd:ColInfo (@ (Unit "70.5") (No "7") (HardSize "1"))) (http://www.gnumeric.org/v10.dtd:ColInfo (@ (Unit "48") (No "8"))) (http://www.gnumeric.org/v10.dtd:ColInfo (@ (Unit "60.75") (No "9") (HardSize "1"))) (http://www.gnumeric.org/v10.dtd:ColInfo (@ (Unit "34.5") (No "10") (HardSize "1"))) (http://www.gnumeric.org/v10.dtd:ColInfo (@ (Unit "177") (No "11") (HardSize "1"))) (http://www.gnumeric.org/v10.dtd:ColInfo (@ (Unit "63.75") (No "12") (HardSize "1"))) (http://www.gnumeric.org/v10.dtd:ColInfo (@ (Unit "413.2") (No "13") (HardSize "1"))) (http://www.gnumeric.org/v10.dtd:ColInfo (@ (Unit "213.8") (No "14") (HardSize "1"))) (http://www.gnumeric.org/v10.dtd:ColInfo (@ (Unit "198.8") (No "15") (HardSize "1"))) (http://www.gnumeric.org/v10.dtd:ColInfo (@ (Unit "104.2") (No "16"))) (http://www.gnumeric.org/v10.dtd:ColInfo (@ (Unit "78.75") (No "17")))) (http://www.gnumeric.org/v10.dtd:Rows (@ (DefaultSizePts "12.1")) (http://www.gnumeric.org/v10.dtd:RowInfo (@ (Unit "13.5") (No "0"))) (http://www.gnumeric.org/v10.dtd:RowInfo (@ (Unit "13.5") (No "1") (Hidden "1") (Count "17"))) (http://www.gnumeric.org/v10.dtd:RowInfo (@ (Unit "12.1") (No "18") (Hidden "1") (Count "41"))) (http://www.gnumeric.org/v10.dtd:RowInfo (@ (Unit "13.5") (No "59") (Hidden "1"))) (http://www.gnumeric.org/v10.dtd:RowInfo (@ (Unit "12.1") (No "60") (Hidden "1") (Count "131"))) (http://www.gnumeric.org/v10.dtd:RowInfo (@ (Unit "13.5") (No "191") (Hidden "1"))) (http://www.gnumeric.org/v10.dtd:RowInfo (@ (Unit "12.1") (No "192") (Hidden "1") (Count "215"))) (http://www.gnumeric.org/v10.dtd:RowInfo (@ (Unit "13.5") (No "407"))) (http://www.gnumeric.org/v10.dtd:RowInfo (@ (Unit "12.1") (No "408") (Count "10"))) (http://www.gnumeric.org/v10.dtd:RowInfo (@ (Unit "12.1") (No "418") (Hidden "1"))) (http://www.gnumeric.org/v10.dtd:RowInfo (@ (Unit "13.5") (No "419") (Hidden "1"))) (http://www.gnumeric.org/v10.dtd:RowInfo (@ (Unit "12.1") (No "420"))) (http://www.gnumeric.org/v10.dtd:RowInfo (@ (Unit "13.5") (No "421") (Hidden "1"))) (http://www.gnumeric.org/v10.dtd:RowInfo (@ (Unit "12.1") (No "422") (Hidden "1"))) (http://www.gnumeric.org/v10.dtd:RowInfo (@ (Unit "13.5") (No "423") (Hidden "1"))) (http://www.gnumeric.org/v10.dtd:RowInfo (@ (Unit "12.1") (No "424") (Count "18"))) (http://www.gnumeric.org/v10.dtd:RowInfo (@ (Unit "12.1") (No "442") (Hidden "1"))) (http://www.gnumeric.org/v10.dtd:RowInfo (@ (Unit "12.1") (No "443"))) (http://www.gnumeric.org/v10.dtd:RowInfo (@ (Unit "13.5") (No "444") (Hidden "1"))) (http://www.gnumeric.org/v10.dtd:RowInfo (@ (Unit "12.1") (No "445"))) (http://www.gnumeric.org/v10.dtd:RowInfo (@ (Unit "12.1") (No "446") (Hidden "1") (Count "3"))) (http://www.gnumeric.org/v10.dtd:RowInfo (@ (Unit "12.1") (No "449") (Count "7"))) (http://www.gnumeric.org/v10.dtd:RowInfo (@ (Unit "13.5") (No "456") (Hidden "1"))) (http://www.gnumeric.org/v10.dtd:RowInfo (@ (Unit "12.1") (No "457") (Hidden "1"))) (http://www.gnumeric.org/v10.dtd:RowInfo (@ (Unit "12.1") (No "458") (Count "2"))) (http://www.gnumeric.org/v10.dtd:RowInfo (@ (Unit "13.5") (No "460") (Hidden "1") (Count "3"))) (http://www.gnumeric.org/v10.dtd:RowInfo (@ (Unit "12.1") (No "463") (Count "4"))) (http://www.gnumeric.org/v10.dtd:RowInfo (@ (Unit "13.5") (No "467") (Hidden "1") (Count "15"))) (http://www.gnumeric.org/v10.dtd:RowInfo (@ (Unit "12.1") (No "482") (Hidden "1"))) (http://www.gnumeric.org/v10.dtd:RowInfo (@ (Unit "13.5") (No "483") (Hidden "1") (Count "5"))) (http://www.gnumeric.org/v10.dtd:RowInfo (@ (Unit "12.1") (No "488") (Hidden "1"))) (http://www.gnumeric.org/v10.dtd:RowInfo (@ (Unit "13.5") (No "489") (Hidden "1") (Count "4"))) (http://www.gnumeric.org/v10.dtd:RowInfo (@ (Unit "12.1") (No "493") (Hidden "1") (Count "5"))) (http://www.gnumeric.org/v10.dtd:RowInfo (@ (Unit "13.5") (No "498") (Hidden "1") (Count "3"))) (http://www.gnumeric.org/v10.dtd:RowInfo (@ (Unit "12.1") (No "501") (Hidden "1") (Count "65035")))) (http://www.gnumeric.org/v10.dtd:Selections (@ (CursorRow "426") (CursorCol "13")) (http://www.gnumeric.org/v10.dtd:Selection (@ (startRow "426") (startCol "13") (endRow "426") (endCol "13")))) (http://www.gnumeric.org/v10.dtd:SheetLayout (@ (TopLeft "A2")) (http://www.gnumeric.org/v10.dtd:FreezePanes (@ (UnfrozenTopLeft "A2") (FrozenTopLeft "A1")))) (http://www.gnumeric.org/v10.dtd:Filters (http://www.gnumeric.org/v10.dtd:Filter (@ (Area "A1:Q65536")) (http://www.gnumeric.org/v10.dtd:Field (@ (ValueType0 "v1.65-broken") (Value0 "60") (Type "expr") (Op0 "eq") (Index "1"))))) (http://www.gnumeric.org/v10.dtd:Solver (@ (ProgramR "0") (ProblemType "0") (NonNeg "1") (ModelType "0") (MaxTime "60") (MaxIter "1000") (Discr "0") (AutoScale "0")))) |
Added fossil-utils/justtesting/timeline.dat version [59068cf799].
cannot compute difference between binary files
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 [c6a2ab2853].
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 | ;;====================================================================== ;; 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 matchable) (include "db_records.scm") (define genexample:example-logpro #<<EOF ;; You should have at least one expect:required. This ensures that your process ran ;; comment out the line below and replace "put pattern here" with a pattern that will ;; always be seen in your log file if the step runs successfully. ;; |
︙ | ︙ | |||
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! | | | 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 | (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.") | | | | | 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 | (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 | | | 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 | (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 | | | | | | | 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 | (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))))) |
︙ | ︙ | |||
327 328 329 330 331 332 333 | (if (string-match ".*\\.sh$" script) (begin (with-output-to-file (conc testdir "/" script) (lambda () (print genexample:example-script))) (system (conc "chmod ug+r,a+x " (conc testdir "/" script))))))) steps)))))) | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | (if (string-match ".*\\.sh$" script) (begin (with-output-to-file (conc testdir "/" script) (lambda () (print genexample:example-script))) (system (conc "chmod ug+r,a+x " (conc testdir "/" script))))))) steps)))))) ;; easier to work backwards than change the upstream code ;; (define (hrs-min-sec->seconds str) (let* ((parts (string-split str)) (res 0)) (for-each (lambda (part) (set! res (+ res (match (string-match "(\\d+)([a-z])" part) ((_ val units)(* (string->number val)(case (string->symbol units) ((s) 1) ((m) 60) ((h) 3600)))) (else 0))))) parts) res)) ;; generate a skeleton Megatest area from a current area with runs ;; ;; specify target, runname etc to use specific runs for the template ;; (define (genexample:extract-skeleton-area dest-path) (let* ((target (args:get-arg "-target")) (runname (args:get-arg "-runname")) (obtuse (make-hash-table)) (obtusef (args:get-arg "-obfuscate")) (letters (string-split-fields "\\S" "abcdefghijklmnopqrstuvwxyz")) (maxletter (- (length letters) 1)) (lastlet 0) (lastnum 1) (obfuscate (lambda (instr) (or (hash-table-ref/default obtuse instr #f) (if obtusef (let* ((letter (list-ref letters lastlet)) (val (conc letter lastnum))) (if (>= lastlet maxletter) (begin (set! lastlet 0) (set! lastnum (+ lastnum 1))) (set! lastlet (+ lastlet 1))) (hash-table-set! obtuse instr val) val) instr))))) (if (not (and target runname)) (debug:print 0 *default-log-port* "WARNING: For best results please specifiy -target and -runname for a good run to use as a template.")) (if (not (and (file-exists? "megatest.config") (file-exists? "megatest.db"))) (begin (debug:print 0 *default-log-port* "ERROR: this command must be run at the top level of a megatest area where runs have been completed") (exit))) ;; first create the dest path and needed subdirectories (if (not (file-exists? dest-path)) (begin (create-directory dest-path) (create-directory (conc dest-path "/tests"))) (if (file-exists? (conc dest-path "/megatest.config")) (begin (debug:print 0 *default-log-port* "ERROR: destination path already has megatest.config, stopping now.") (exit)))) ;; dump the config files from this area to the dest area (if (args:get-arg "-obfuscate") (debug:print 0 *default-log-port* "WARNING: obfuscation is NOT done on megatest.config and runconfigs.config. Please edit those files to remove any sensitive information!")) (system (conc "megatest -show-config > " dest-path "/megatest.config")) (system (conc "megatest -show-runconfig > " dest-path "/runconfigs.config")) ;; create stepsinfo and items refdbs, some stuff has to be done due to refdb not initing area ;; ;; sheet row col value ;; stepsinfo testname itempath stepname steptime ;; miscinfo "itemsinfo" testname itempath "x" ;; (for-each (lambda (rdbname) (if (not (file-exists? (conc dest-path "/" rdbname))) (begin (create-directory (conc dest-path "/" rdbname "/sxml") #t) (with-output-to-file (conc dest-path "/" rdbname "/sheet-names.cfg") (lambda ()(print)))))) '("stepsinfo" "miscinfo")) (let* ((runs (rmt:simple-get-runs (or runname "%") #f #f (or target "%") #f)) (tests (make-hash-table)) ;; just tests (fullt (make-hash-table)) ;; all test/items (testreg (make-hash-table)) ;; for the testconfigs (stepsrdb (conc dest-path "/stepsinfo")) (miscrdb (conc dest-path "/miscinfo"))) (if (> (length runs) 1) (debug:print-info 0 *default-log-port* "More than one run matches, first found data will be used.")) ;; get all testnames (for-each (lambda (run-id) (let* ((tests-data (rmt:get-tests-for-run run-id "%" '() '() #f #f #f #f #f #f #f #f))) (for-each (lambda (testdat) (let* ((test-id (db:test-get-id testdat)) (testname (db:test-get-testname testdat)) (item-path (db:test-get-item-path testdat)) (tlevel (db:test-get-is-toplevel testdat)) (tfullname (db:test-get-fullname testdat)) ;; now get steps info (test-steps (tests:get-compressed-steps run-id test-id)) (testconfig (tests:get-testconfig testname item-path testreg #f))) (if (not (hash-table-exists? fullt tfullname)) ;; do the work for this test if not previously done (let* ((new-test-dir (conc dest-path "/tests/" (obfuscate testname))) (tconfigf (conc new-test-dir "/testconfig"))) (print "Analyzing and extracting info for " tfullname " as " (obfuscate testname)) (print " toplevel: " (if tlevel "yes" "no")) (hash-table-set! fullt tfullname #t) ;; track that this one has been seen (if (not (directory-exists? new-test-dir)) (create-directory new-test-dir #t)) ;; create the testconfig IIF we are a toplevel or an item AND the testconfig has not been previously created (if (and (or (not tlevel) (not (equal? item-path ""))) (not (file-exists? tconfigf))) (with-output-to-file tconfigf (lambda () ;; first the ezsteps (print "[ezsteps]") (for-each (lambda (teststep) (let* ((step-name (vector-ref teststep 0))) (print (obfuscate step-name) " sleep $(refdb lookup #{getenv MT_RUN_AREA_HOME}/stepsinfo " (obfuscate testname) " $MT_ITEMPATH " (obfuscate step-name) ")"))) test-steps) ;; now the requirements section (if testconfig (begin (print "\n[requirements]") (for-each (lambda (entry) (let* ((key (car entry)) (val (cadr entry))) (case (string->symbol key) ((waiton) (print "waiton " (obfuscate val))) (else (print key " " val))))) (configf:get-section testconfig "requirements"))) #;(print "WARNING: No testconfig data for " testname ", " item-path)) (print "\n[items]") (print "THE_ITEM [system refdb getrow #{getenv MT_RUN_AREA_HOME}/miscinfo itemsinfo " (obfuscate testname)" | awk '{print $1}']") ))) ;; fill the stepsrdb (for-each (lambda (teststep) (let* ((step-name (vector-ref teststep 0)) (step-duration (hrs-min-sec->seconds (vector-ref teststep 4)))) (system (conc "refdb set " stepsrdb " " (obfuscate testname) " '" (if (equal? item-path "") "no-item-path" (obfuscate item-path)) "' " (obfuscate step-name) " " step-duration)))) test-steps) ;; miscinfo "itemsinfo" testname itempath "x" (if (not (equal? item-path "")) (system (conc "refdb set " miscrdb " itemsinfo " (obfuscate testname) " " (obfuscate item-path) " x"))) )))) tests-data))) (map (lambda (runrec)(simple-run-id runrec)) runs))) )) |
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 [67489ed9ab].
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 164 165 166 | (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)))))))) (handle-exceptions exn (debug:print 0 *default-log-port* "Failed to create file " start-file ", exn=" exn) (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) | > > > | | | > | | > | > > > > > | > | | 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 | 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 ", exn=" exn) (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!) (mutex-unlock! *http-mutex*) )) (time-out (lambda () (thread-sleep! 45) (debug:print 0 *default-log-port* "WARNING: send-receive took more than 45 seconds!!") #f)) (th1 (make-thread send-recieve "with-input-from-request")) (th2 (make-thread time-out "time out"))) (thread-start! th1) (thread-start! th2) (thread-join! th1) (thread-terminate! th2) (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) ", exn=" 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") | > > > | | > > > > > > > > > > > > > | | > > > > > > | | 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 | ;; 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 (handle-exceptions exn (debug:print 0 *default-log-port* "Failed to create " started-file ", exn=" exn) (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))) | | < < < < < | < | > | | 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 | (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? exn=" exn) (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) | | > > > > > > > > > > > > > > > > | > > > > > | < < > > > > > | > > > | | > | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | 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 | ;; (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)) " "))) | | | 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 | (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 [940d39d039].
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 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 | ;; Copyright 2006-2017, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more 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)) (declare (uses ezsteps)) (include "common_records.scm") (include "key_records.scm") (include "db_records.scm") (include "megatest-fossil-hash.scm") ;;====================================================================== ;; ezsteps ;;====================================================================== ;; ezsteps were going to be coded as ;; stepname[,predstep1,predstep2 ...] [{VAR1=first,second,third}] command to execute ;; BUT ;; now are ;; stepname {VAR=first,second,third ...} command ... ;; where the {VAR=first,second,third ...} is optional. ;; given an exit code and whether or not logpro was used calculate OK/BAD ;; return #t if we are ok, #f otherwise (define (steprun-good? logpro exitcode stepparms) (or (eq? exitcode 0) (and logpro (eq? exitcode 2)) ;; shouldn't this be (member exitcode 2 ...) with the other ok codes? (let* ((params (alist-ref 'params stepparms)) ;; get the params section (keep-going (if params (alist-ref "keep-going" params equal?) #f))) (debug:print 0 *default-log-port* "keep-going=" keep-going) (and keep-going (equal? (car keep-going) "yes"))))) ;; if handed a string, process it, else look for MT_CMDINFO (define (launch:get-cmdinfo-assoc-list #!key (encoded-cmd #f)) (let ((enccmd (if encoded-cmd encoded-cmd (getenv "MT_CMDINFO")))) (if enccmd (common:read-encoded-string enccmd) '()))) ;; 0 1 2 3 (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: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) | | > | > > > > > > > > > > > > > > > > > > > > > > > > | | | | > > | | | > | | | > | > > > | | | | | | | | > > | | > | > > > > > | | | | | | > > | > | | | > > > > > > > > > | > > | < < < | | > > > > | > > > > | > | | > > | | > | | | > | > > > | > | 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 | (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 (let* ((envdbf (conc "/tmp/."(current-user-name)"-"(current-process-id)"-"run-id"-"test-id".db")) (all-steps-dat (make-hash-table))) ;; keep all the info around as stepname ==> alist; ;;; where 'params is the params list (add other ;;; stuff as needed) (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 ((all-step-names (map car ezstepslst))) (setenv "MT_STEP_NAMES" (string-intersperse all-step-names " ")) (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 all-steps-dat prevstep envdbf)) (stepname (car ezstep)) (stepparms (hash-table-ref all-steps-dat stepname))) (setenv "MT_STEP_NAME" stepname) (pp (hash-table->alist all-steps-dat)) ;; 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) stepparms) (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 update-db: #t) (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 update-db: #t) (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) (if do-sync ;; save meta data about the running of this test (tests:update-central-meta-info run-id test-id new-cpu-load new-disk-free (calc-minutes) #f #f)) (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))))) (if (not (null? pids)) (begin (for-each (lambda (pid) (handle-exceptions exn (begin (debug:print-info 0 *default-log-port* "Unable to kill process with pid " pid ", possibly already killed.") (debug:print 0 *default-log-port* " message: " ((condition-property-accessor 'exn 'message) exn) ", exn=" exn)) (debug:print 0 *default-log-port* "WARNING: Request received to kill job " pid) ;; " (attempt # " kill-tries ")") (debug:print-info 0 *default-log-port* "Signal mask=" (signal-mask)) ;; (if (process:alive? pid) ;; (begin (map (lambda (pid-num) (process-signal pid-num signal/term)) (process:get-sub-pids pid)) (thread-sleep! 5) ;; (if (process:process-alive? pid) (map (lambda (pid-num) (handle-exceptions exn (begin (debug:print 0 *default-log-port* " .... had trouble sending kill to " pid-num ", exn=" 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 update-db: #t))) ;; 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 | | | > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < | | > | > < | > | > > > > > > > > | > > > > | > > > > > | | | > | > | < | > > > | | > > > > > | | > | | | | | | | | | > > > | 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 | (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. ;;((or (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 ;; (and (equal? (db:test-get-state test-info) "COMPLETED") ;; completed/abort => rerun if asked ;; (member (db:test-get-status test-info) '("ABORT")))) ((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))) ((member (db:test-get-state test-info) '("COMPLETED")) ;; we do NOT want to re-run COMPLETED jobs. Mark as NOT_STARTED to run! (debug:print-error 0 *default-log-port* "test state is " (db:test-get-state test-info) ", 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") | > > > > > > > | | > > > > > > > > > > > > > > > > > > > > > > | < | > > > > | > > > | > > > > > > > > > > > > > > | < < < | | | < < | | < > > > > | < < > | | > | < < > > > > > > > > > > > > > > > > > > > > > | > | > > > > > > > > > > > | > > > > > > > > > > > > > | < < < > | | > > | < < > | < > > > | | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | < | < < < > > | < | < | > > | < < | < < < < > > > > | > > > | > > > | > > > > | > | > > > > > > > > > > | > > > > > > < | > > > | > > > | > | | | < | | > > > > > > > > > > > > > > > > > > > > > > > > | | | > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > | 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 | ;; 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* ((is-local (equal? host (get-host-name))) (ssh-cmd (if is-local " " (conc "ssh " host " "))) (cmd (conc ssh-cmd "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. ;; ;; (launch:cache-config) moved to attic below ;; gather available information, if legit read configs in this order: ;; ;; if have cache; ;; read it a return it ;; else ;; megatest.config (do not cache) ;; runconfigs.config (cache if all vars avail) ;; megatest.config (cache if all vars avail) ;; 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))) (define (launch:cache-files-changed? cache-files ref-seconds) (let* ((changed #f)) (if (or (not cache-files) (null? cache-files)) (set! changed #t) ;; yep, they've changed (for-each (lambda (fname) (if (not fname) (set! changed #t) (if (not (file-exists? fname)) (set! changed #t) (if (> (file-modification-time fname) ref-seconds) (set! changed #t))))) cache-files)) changed)) ;; return paths depending on what info is available. ;; (define (launch:get-cache-file-paths areapath toppath target) (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)) ;; 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)) (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) ", exn=" 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) ", exn=" 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)) (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 (begin (debug:print 0 *default-log-port* "failed to create dir " (cadr head) ", exn=" 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)) | | | > | | | | | | | > | > > > | > | | > | | | > | | | | > > | > | | < < < < | < < < < < < < < > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | > > > | > | < | | | | | | | | | > > > > > > > | | | > | | | | < < < < | < < > | | < < < < < > > | | > > > > > > > > > > > > | | 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 | ;; 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 ", exn=" exn) (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, exn=" exn) #;(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. exn=" exn) #;(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. exn=" exn) #;(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))) (begin (debug:print-info 2 *default-log-port* "Creating " toptest-path " and link " lnkpath) (handle-exceptions exn (begin (debug:print 0 *default-log-port* "failed to create directory " toptest-path ", exn=" exn) #f) (create-directory toptest-path #t)) (hash-table-set! *toptest-paths* testname toptest-path))))) ;; The toptest path has been created, the link to the test in the linktree has ;; been created. Now, if this is an iterated test the real test dir must be created (if (not not-iterated) ;; this is an iterated test (begin ;; (let ((lnktarget (conc lnkpath "/" item-path))) (debug:print 2 *default-log-port* "Setting up sub test run area") (debug:print 2 *default-log-port* " - creating run area in " test-path) (handle-exceptions exn (begin (debug:print-error 0 *default-log-port* " Failed to create directory " test-path ((condition-property-accessor 'exn 'message) exn) ", exiting, exn=" exn) (exit 1)) (create-directory test-path #t)) (debug:print 2 *default-log-port* " - creating link from: " test-path "\n" " to: " lnktarget) ;; 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, exn=" exn) (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)))) (defstruct launch:ajt (vars '()) (exekey #f) (host-type #f) (test-sig #f) (cmdline #f)) ;; append vars (define (launch:ajt-add-vars dat vars) (launch:ajt-vars-set! dat (append (launch:ajt-vars dat) vars))) ;; 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* (;; locking code removed from here commented out and pasted at end of file (item-path (item-list->path itemdat)) (contour #f) ;; NOT READY FOR THIS (args:get-arg "-contour"))) ;; launcher-mode will be 'adjutant or 'normal (launcher-mode (string->symbol (or (configf:lookup *configdat* "jobtools" "mode") "normal"))) (ajtdat (make-launch:ajt))) (let loop ((delta (- (current-seconds) *last-launch*)) (launch-delay (configf:lookup-number *configdat* "setup" "launch-delay" default: 0))) (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*) (let ((var-list (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))) ;; 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) (alist->env-vars var-list) ;; the var-list into the ajtdat adjutant record whether it is needed or not. (launch:ajt-add-vars ajtdat var-list)) (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"))) (local-megatest (common:find-local-megatest)) (launcher (let ((l (common:get-launcher *configdat* test-name item-path launcher-mode))) (if (string? l) (string-split l) l))) ;; some nonhomogenuity here. '(cmd param1 param2 ...) OR '(host-type launcher) ;; (item-list->path itemdat))) ;; test-path is the full path including the item-path (test-sig (conc (common:get-testsuite-name) ":" test-name ":" 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) (testinfo (rmt:get-test-info-by-id run-id test-id)) (mt_target (string-intersperse (map cadr keyvals) "/")) (debug-param (append (if (args:get-arg "-debug") (list "-debug" (args:get-arg "-debug")) '()) (if (args:get-arg "-logging")(list "-logging") '()) (if (configf:lookup *configdat* "misc" "profilesw") (list (configf:lookup *configdat* "misc" "profilesw")) '())))) ;; save the test-sig in the ajtdat record (launch:ajt-test-sig-set! ajtdat test-sig) ;; go ahead and figure out if we have a host-type from the ;; launcher call above and save it in the ajtdat record (if (and (eq? launcher-mode 'adjutant) (list? launcher) (> (length launcher) 1)) (launch:ajt-host-type-set! ajtdat (car launcher))) ;; (if hosts (set! hosts (string-split hosts))) ;; set the megatest to be called on the remote host (if (not remote-megatest)(set! remote-megatest local-megatest)) ;; "megatest")) (set! mt-bindir-path (pathname-directory remote-megatest)) ;; (if launcher (set! launcher (string-split launcher))) ;; yuk! ;; set up the run work area for this test (if (and (args:get-arg "-preclean") ;; user has requested to preclean for this run (not (member (db:test-get-rundir testinfo)(list "n/a" "/tmp/badname")))) ;; n/a is a placeholder and thus not a read dir (begin (debug:print-info 0 *default-log-port* "attempting to preclean directory " (db:test-get-rundir testinfo) " for test " test-name "/" item-path) (runs:remove-test-directory testinfo 'remove-data-only))) ;; remove data only, do not perturb the record |
︙ | ︙ | |||
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) | | > > > | | > | | < > < | < | | | | | | | | < | > > | | > > > | | | | | | | | | | | | > > | > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | (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)))))))) ;; save the cmdparms in the ajtdat (launch:ajt-exekey-set! ajtdat cmdparms) ;; 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 ;; save the command line for adjutant mode (might never be needed but best to assemble it here) (launch:ajt-cmdline-set! ajtdat (string-intersperse (append (list remote-megatest "-m" test-sig "-execute" cmdparms) debug-param))) (cond (launcher (set! fullcmd (append launcher (list remote-megatest "-m" test-sig "-execute" cmdparms) debug-param))) (else (if (not useshell)(debug:print 0 *default-log-port* "WARNING: internal launching will not work well without \"useshell yes\" in your [jobtools] section")) (set! fullcmd (append (list remote-megatest "-m" test-sig "-execute" cmdparms) debug-param (list (if useshell "&" "")))))) (if (args:get-arg "-xterm")(set! fullcmd (append fullcmd (list "-xterm")))) (debug:print 1 *default-log-port* "Launching " work-area) ;; set pre-launch-env-vars before launching, keep the vars in prevvals and put the envionment back when done (debug:print 4 *default-log-port* "fullcmd: " fullcmd) (set! *last-launch* (current-seconds)) ;; all that junk above takes time, set this as late as possible. (let* ((env-override-vars (hash-table-ref/default *configdat* "env-override" '())) (commonprevvals (alist->env-vars env-override-vars)) (misc-vars (append (list (list "MT_TEST_RUN_DIR" work-area) (list "MT_TEST_NAME" test-name) (list "MT_ITEM_INFO" (conc itemdat)) (list "MT_RUNNAME" runname) (list "MT_TARGET" mt_target) (list "MT_ITEMPATH" item-path)) itemdat)) (miscprevvals (alist->env-vars misc-vars));; consolidate this code with the code in megatest.scm for "-execute" (test-vars (hash-table-ref/default tconfig "pre-launch-env-overrides" '())) (testprevvals (alist->env-vars test-vars)) ;; Launchwait defaults to true, must override it to turn off wait (launchwait (if (equal? (configf:lookup *configdat* "setup" "launchwait") "no") #f #t)) ;; BB: TODO: refactor this to examine return code of launcher, if nonzero, set state to launch failed. (launch-results-prev (if (eq? launcher-mode 'adjutant) '(#t 0) ;; just some fake data to fool downstream but non-applicable code (apply (if launchwait 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))) (launch:ajt-add-vars ajtdat env-override-vars) (launch:ajt-add-vars ajtdat misc-vars) (launch:ajt-add-vars ajtdat test-vars) ;; if in adjutant mode we register the job in the jobs_queue ;; then fire off an adjutant runner ;; (if (eq? launcher-mode 'adjutant) (let* ((adjutant-runner-cmd (append (cdr launcher) (list remote-megatest "-adjutant" (launch:ajt-host-type ajtdat) "-start-dir" *toppath*))) (adj-cmd (conc (string-intersperse (map conc adjutant-runner-cmd) " ") "&"))) (rmt:no-sync-add-job (launch:ajt-host-type ajtdat) (launch:ajt-vars ajtdat) (launch:ajt-exekey ajtdat) (launch:ajt-cmdline ajtdat)) (print "adj-cmd: " adj-cmd) (system adj-cmd) )) (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")) ;; (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) |
︙ | ︙ | |||
1363 1364 1365 1366 1367 1368 1369 1370 | ;; but this hack will work! Thanks go to Alan Post of the Chicken email list ;; NB// Is this still needed? Should be safe to go back to "exit" now? (process-signal (current-process-id) signal/kill) )) (alist->env-vars miscprevvals) (alist->env-vars testprevvals) (alist->env-vars commonprevvals) launch-results)) | > > > > | > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | ;; but this hack will work! Thanks go to Alan Post of the Chicken email list ;; NB// Is this still needed? Should be safe to go back to "exit" now? (process-signal (current-process-id) signal/kill) )) (alist->env-vars miscprevvals) (alist->env-vars testprevvals) (alist->env-vars commonprevvals) ;; yes, really should mutex all the way to here. Need to put this entire process into a fork. ;; the unlock previously was further up. This seemed wrong as we should not proceed until the ;; vars have been reset. (mutex-unlock! *launch-setup-mutex*) launch-results)) (change-directory *toppath*) (thread-sleep! (configf:lookup-number *configdat* "setup" "inter-test-delay" default: 0.0)))) ;; recover a test where the top controlling mtest may have died ;; (define (launch:recover-test run-id test-id) ;; this function is called on the test run host via ssh ;; ;; 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))) ;;====================================================================== ;; Attic ;;====================================================================== ;; (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)))))) #;(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."))))) |
Added lib/libpangox-1.0.so version [d55c756a93].
cannot compute difference between binary files
Added lib/libpangox-1.0.so.0 version [d55c756a93].
cannot compute difference between binary files
Added lib/libxcb-xlib.so.0 version [b7cbe8e250].
cannot compute difference between binary files
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 [b4d2006c23].
1 2 3 | ;; Always use two or four digit decimal ;; 1.01, 1.02...1.10,1.11,1.1101 ... 1.99,2.00.. | > > > > > > > > > > > > > > > > > | | < | 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.6579) |
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 [d7149ec694].
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 155 156 157 158 159 160 161 162 | ;; Copyright 2006-2017, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more 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) (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 mutils)) (declare (uses adjutant)) (import adjutant) (declare (uses mttop)) (import mttop) ;; (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") (use (prefix sqlite3 sqlite3:) srfi-1 posix regex regex-case srfi-69 (prefix base64 base64:) readline apropos json http-client directory-utils typed-records matchable http-client srfi-18 extras format call-with-environment-variables) ;; Added for csv stuff - will be removed ;; (use sparse-vectors) (import mutils) ;;(require-library mutils) (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 ") help : help for the new Megatest interface 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 (e.g. -kill-wait 0). -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 | | > > > > > > | > | > > > > > > > > | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > | > > > | > > > > | > > > > > > | | > > > > > > > > > > | > > | | > > > > > > | > > > | | | 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 | -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 overwritten by values set in config files. -server -|hostname : start the server (reduces contention on megatest.db), use - to automatically figure out hostname -adjutant host-type : start the server/adjutant with given host-type use 0,0 to auto use full machine -transport http|rpc : use http or rpc for transport (default is http) -log logfile : send stdout and stderr to logfile -list-servers : list the servers -kill-servers : kill all servers -repl : start a repl (useful for extending megatest) -load file.scm : load and run file.scm -mark-incompletes : find and mark incomplete tests -ping run-id|host:port : ping server, exit with 0 if found -debug N|N,M,O... : enable debug 0-N or N and M and O ... -debug-noprop N|M,M,O...: enable debug but do not propagate to subprocesses via MT_DEBUG -config fname : override the megatest.config file with fname -append-config fname : append fname to the megatest.config file Utilities -env2file fname : write the environment to fname.csh and fname.sh -envcap a : save current variables labeled as context 'a' in file envdat.db -envdelta a-b : output enviroment delta from context a to context b to -o fname set the output mode with -dumpmode csh, bash or ini note: ini format will use calls to use curr and minimize path -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, replicate-db (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> -syscheck : do some very basic checks; write access and space in tmp, home, runs, links and is $DISPLAY valid -list-waivers : dump waivers for specified target, runname, testpatt to stdout 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 -diff-html <rep.html> : path to html file to generate Spreadsheet generation -extract-ods fname.ods : extract an open document spreadsheet from the database -pathmod path : insert path, i.e. path/runame/itempath/logfile.html will clear the field if no rundir/testname/itempath/logfile if it contains forward slashes the path will be converted to windows style Getting started -create-megatest-area : create a skeleton megatest area. You will be prompted for paths -create-test testname : create a skeleton megatest test. You will be prompted for info Examples # Get test path, use '.' to get a single path or a specific path/file pattern megatest -test-files 'logs/*.log' -target ubuntu/n%/no% -runname w49% -testpatt test_mt% Called as " (string-intersperse (argv) " ") " Version " megatest-version ", built from " megatest-fossil-hash )) ;; -gui : start a gui interface ;; -config fname : override the runconfigs file with fname (mttop-run (command-line-arguments) '("help")) ;; process args (define remargs (args:get-args (argv) (list "-runtests" ;; run a specific test "-config" ;; override the config file name "-append-config" "-execute" ;; run the command encoded in the base64 parameter "-step" "-target" "-reqtarg" ":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" "-source" "-time-stamp" ;; values and messages ":category" ":variable" ":value" ":expected" ":tol" ":units" ;; misc "-start-dir" "-run-patt" "-target-patt" "-contour" "-area-tag" "-area" "-run-tag" "-server" "-adjutant" "-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 "-debug-noprop" "-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" ;; wizards, area capture, setup new ... "-extract-skeleton" ) (list "-h" "-help" "--help" "-manual" "-version" "-force" "-xterm" "-showkeys" "-show-keys" "-test-status" "-set-values" "-load-test-data" "-summarize-items" "-gui" "-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" "-list-waivers" ;; 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" "-syscheck" "-obfuscate" ;; junk placeholder ;; "-:p" ) args:arg-hash 0)) ;; 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") ) )) (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) ", exn=" 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" "-adjutant" "-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))) ;;(print "no-watchdog-args="no-watchdog-args "no-watchdog-args-vals="no-watchdog-args-vals " start-watchdog-specail-arg-val:" start-watchdog-specail-arg-val " start-watchdog:" start-watchdog) ;;(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) ", exn=" 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 | | | 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 | (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) |
︙ | ︙ | |||
477 478 479 480 481 482 483 | (let ((original-exit (exit-handler))) (exit-handler (lambda (#!optional (exit-code 0)) (printf "Preparing to exit with exit code ~A ...\n" exit-code) (for-each (lambda (pid) (handle-exceptions | | > > | | > > > > > > > > > > > > > > | | | 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 | (let ((original-exit (exit-handler))) (exit-handler (lambda (#!optional (exit-code 0)) (printf "Preparing to exit with exit code ~A ...\n" exit-code) (for-each (lambda (pid) (handle-exceptions exn (begin (printf "process reap failed. exn=~A\n" exn) #t) (let-values (((pid-val exit-status exit-code) (process-wait pid #t))) (if (or (eq? pid-val pid) (eq? pid-val 0)) (begin (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. | > | > | 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 | (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))) | | | 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 | (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 (?,?,?,?);" |
︙ | ︙ | |||
722 723 724 725 726 727 728 | (let ((envcap (args:get-arg "-envcap"))) (if envcap (let* ((db (env:open-db (if (null? remargs) "envdat.db" (car remargs))))) (env:save-env-vars db envcap) (env:close-database db) (set! *didsomething* #t)))) | | > > > | 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 | (let ((envcap (args:get-arg "-envcap"))) (if envcap (let* ((db (env:open-db (if (null? remargs) "envdat.db" (car remargs))))) (env:save-env-vars db envcap) (env:close-database db) (set! *didsomething* #t)))) ;; delta "language" will eventually be res=a+b-c but for now it is just res=a-b ;; ;; db file can be stuck on the end of the command line: ;; megatest -envdelta start-end -dumpmode bash -o .ezsteps/step5.sh /tmp/myfile.db ;; (let ((envdelta (args:get-arg "-envdelta"))) (if envdelta (let ((match (string-split envdelta "-")));; (string-match "([a-z0-9_]+)=([a-z0-9_\\-,]+)" envdelta))) (if (not (null? match)) (let* ((db (env:open-db (if (null? remargs) "envdat.db" (car remargs)))) ;; (resctx (cadr match)) |
︙ | ︙ | |||
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)) | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | (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. ;; (if (args:get-arg "-server") (let ((tl (launch:setup)) (transport-type (string->symbol (or (args:get-arg "-transport") "http")))) (server:launch 0 transport-type) (set! *didsomething* #t))) (define (naylist->alist inlst) (map (lambda (dat) (cons (car dat) (or (if (list? (cdr dat)) (if (null? (cdr dat)) "" (cadr dat)) (cdr dat)) ""))) ;; we need a string for call-with-environment-variables inlst)) ;; The adjutant is a bit different, it does NOT run (launch:setup) as it is not necessarily tied to ;; a specific Megatest area. Detail are being hashed out and this may change. ;; (if (args:get-arg "-adjutant") (let* ((host-type (args:get-arg "-adjutant"))) (launch:setup) ;; dang it, wish this wasn't needed (print "Running the adjutant!") (let loop ((wait-count 0)) (if (< wait-count 10) ;; 6 x 10 seconds = one minute (let* ((dat (rmt:no-sync-take-job host-type))) (match dat ((id ht vars exekey cmdline state event-time last-update) (let ((vars-alist (with-input-from-string vars read) )) (print "Vars:") (pp vars-alist) (call-with-environment-variables (naylist->alist vars-alist) (lambda () (system cmdline)))) (loop 0)) (else (thread-sleep! 10) (loop (+ wait-count 1))))) (print "I'm bored. Exiting."))) ;; (adjutant-run (args:get-arg "-ajutant") rmt:no-sync-take-job) (set! *didsomething* #t))) (if (or (args:get-arg "-list-servers") (args:get-arg "-kill-servers")) (let ((tl (launch:setup))) (if tl ;; all roads from here exit (let* ((servers (server:get-list *toppath*)) (fmtstr "~8a~22a~20a~20a~8a\n")) (format #t fmtstr "pid" "Interface:port" "age (hms)" "Last mod" "State") |
︙ | ︙ | |||
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 | | | 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 | ;; *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 | | > | | 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 | (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 | | | > | | 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 | ((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 | | > > > > > > > > | > | > < | | > | | > | | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > | 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 | ;;====================================================================== ;; 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")) | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | (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 | | | 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 | (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) | | | 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 | (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 | | | 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 | (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) |
︙ | ︙ | |||
1366 1367 1368 1369 1370 1371 1372 | ;; (system (conc "rm -rf " tempdir)) (set! *didsomething* #t) (set! *time-to-exit* #t) ) ;; end if true branch (end of a let) ) ;; end if ) ;; end if -list-runs | < | | | | > > > > > > > | > > > > > > > > > > | > > > > > | > > > > > > > > > > | < > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > | | | | < < < < < < < | < < < < < | > > > | | < < < < < | | | | | | | < | < < | < < | < < < | > > | | < < < < | | 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 | ;; (system (conc "rm -rf " tempdir)) (set! *didsomething* #t) (set! *time-to-exit* #t) ) ;; end if true branch (end of a let) ) ;; end if ) ;; end if -list-runs ;; list-waivers (if (and (args:get-arg "-list-waivers") (launch:setup)) (let* ((runpatt (or (args:get-arg "-runname") "%")) (testpatt (common:args-get-testpatt #f)) (keys (rmt:get-keys)) (runsdat (rmt:get-runs-by-patt keys runpatt (common:args-get-target) #f #f '("id" "runname" "state" "status" "owner" "event_time" "comment") 0)) (runs (db:get-rows runsdat)) (header (db:get-header runsdat)) (results (make-hash-table)) ;; [target] ( (testname/itempath . "comment") ... ) (addtest (lambda (target testname itempath comment) (hash-table-set! results target (cons (cons (conc testname "/" itempath) comment) (hash-table-ref/default results target '()))))) (last-target #f)) (for-each (lambda (run) (let* ((run-id (db:get-value-by-header run header "id")) (target (rmt:get-target run-id)) (runname (db:get-value-by-header run header "runname")) (tests (rmt:get-tests-for-run run-id testpatt '("COMPLETED") '("WAIVED") #f #f #f 'testname 'asc ;; use qryvals if test-spec provided #f #f #f))) (if (not (equal? target last-target)) (print "[" target "]")) (set! last-target target) (print "# " runname) (for-each (lambda (testdat) (let* ((testfullname (conc (db:test-get-testname testdat) (if (equal? "" (db:test-get-item-path testdat)) "" (conc "/" (db:test-get-item-path testdat))) ))) (print testfullname " " (db:test-get-comment testdat)))) tests))) runs) (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* ((precmd (if (args:get-arg "-precmd")(conc (args:get-arg "-precmd") " ") "")) (newcmdline (conc precmd (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")) | | > | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | | | | 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 | (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 (equal? (args:get-arg "-archive") "replicate-db") (begin ;; check if source ;; check if megatest.db exist (print "launch") (launch:setup) (print "launce done") (if (not (args:get-arg "-source")) (begin (debug:print-info 1 *default-log-port* "Missing required argument -source <archive path>") (exit 1))) (if (common:file-exists? (conc *toppath* "/megatest.db")) (begin (debug:print-info 1 *default-log-port* "File " (conc *toppath* "/megatest.db") " already exists. Please remove it before trying to replicate db") (exit 1))) (if (and (common:get-db-tmp-area) (> (length (directory (common:get-db-tmp-area) #f)) 0)) (begin (debug:print-info 1 *default-log-port* (common:get-db-tmp-area) " not empty. Please remove it before trying to replicate db") (exit 1))) ;; check if timestamp (let* ((source (args:get-arg "-source")) (src (if (not (equal? (substring source 0 1) "/")) (conc (current-directory) "/" source) source)) (ts (if (args:get-arg "-time-stamp") (args:get-arg "-time-stamp") "latest"))) (if (common:directory-exists? src) (begin (archive:restore-db src ts) (set! *didsomething* #t)) (begin (debug:print-error 1 *default-log-port* "Path " source " not found") (exit 1)))))) ;; else do a general-run-call (if (and (args:get-arg "-archive") (not (equal? (args:get-arg "-archive") "replicate-db"))) (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 |
︙ | ︙ | |||
1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 | (rmt:teststep-set-status! run-id test-id step state status (or comment msg) logfile)) (begin (debug:print-error 0 *default-log-port* "You must specify :state and :status with every call to -step") (exit 6)))))) (if (args:get-arg "-step") (begin (megatest:step (args:get-arg "-step") (or (args:get-arg "-state")(args:get-arg ":state")) (or (args:get-arg "-status")(args:get-arg ":status")) (args:get-arg "-setlog") (args:get-arg "-m")) ;; (if db (sqlite3:finalize! db)) | > | > | 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 | (rmt:teststep-set-status! run-id test-id step state status (or comment msg) logfile)) (begin (debug:print-error 0 *default-log-port* "You must specify :state and :status with every call to -step") (exit 6)))))) (if (args:get-arg "-step") (begin (thread-sleep! 1.5) (megatest:step (args:get-arg "-step") (or (args:get-arg "-state")(args:get-arg ":state")) (or (args:get-arg "-status")(args:get-arg ":status")) (args:get-arg "-setlog") (args:get-arg "-m")) ;; (if db (sqlite3:finalize! db)) (set! *didsomething* #t) (thread-sleep! 1.5))) (if (or (args:get-arg "-setlog") ;; since setting up is so costly lets piggyback on -test-status ;; (not (args:get-arg "-step"))) ;; -setlog may have been processed already in the "-step" previous ;; NEW POLICY - -setlog sets test overall log on every call. (args:get-arg "-set-toplog") (args:get-arg "-test-status") (args:get-arg "-set-values") |
︙ | ︙ | |||
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 | | > > | | 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 | (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?)) | | | 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 | (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 | | > > > > < > > > > > | | | | > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > | 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 | ;; ;; ;; 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))) (if (args:get-arg "-syscheck") (begin (mutils:syscheck common:raw-get-remote-host-load server:get-best-guess-address read-config) (set! *didsomething* #t))) (if (args:get-arg "-extract-skeleton") (let* ((toppath (launch:setup))) (genexample:extract-skeleton-area (args:get-arg "-extract-skeleton")) (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 [e9055c2687].
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) ", exn=" 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 mtargs.scm version [1e6b59e54f].
> > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | ;;====================================================================== ;; Copyright 2019, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more 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 mtargs)) (include "mtargs/mtargs.scm") |
Added mtargs/Makefile version [f71e390f41].
> > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | # Copyright 2007-2010, Matthew Welland. # # This program is made available under the GNU GPL version 2.0 or # greater. See the accompanying file COPYING for details. # # This program is distributed WITHOUT ANY WARRANTY; without even the # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR # PURPOSE. # TARGDIR = $(shell csi -e "(print (car \#\#sys\#include-pathnames))(exit)") all : uptodate.log # $(TARGDIR)/mtargs.so uptodate.log : mtargs.scm mtargs.setup chicken-install | tee uptodate.log $(TARGDIR)/mtargs.so : mtargs.so @echo installing to $(TARGDIR) cp mtargs.so $(TARGDIR) mtargs.so : mtargs.scm csc -s mtargs.scm |
Added mtargs/mtargs.meta version [65ccfb2eb7].
> > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | ( ; Your egg's license: (license "LGPL") ; Pick one from the list of categories (see below) for your egg and enter it ; here. (category misc) ; A list of eggs mpeg3 depends on. If none, you can omit this declaration ; altogether. If you are making an egg for chicken 3 and you need to use ; procedures from the `files' unit, be sure to include the `files' egg in the ; `needs' section (chicken versions < 3.4.0 don't provide the `files' unit). ; `depends' is an alias to `needs'. (needs srfi-69 srfi-1) ; A list of eggs required for TESTING ONLY. See the `Tests' section. (test-depends test) (author "Matt Welland") (synopsis "Primitive argument processor.")) |
Added mtargs/mtargs.scm version [e2f1c247b7].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | ;; Copyright 2007-2010, Matthew Welland. ;; ;; This file is part of mtargs. ;; ;; mtargs is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; mtargs is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with mtargs. If not, see <http://www.gnu.org/licenses/>. (module mtargs ( arg-hash get-arg get-arg-from usage get-args print-args any-defined? help ) (import scheme chicken data-structures extras posix ports files) (use srfi-69 srfi-1) (define arg-hash (make-hash-table)) (define help "") (define (get-arg arg . default) (if (null? default) (hash-table-ref/default arg-hash arg #f) (hash-table-ref/default arg-hash arg (car default)))) (define (any-defined? . args) (not (null? (filter (lambda (x) x) (map get-arg args))))) ;; (define any any-defined?) (define (get-arg-from ht arg . default) (if (null? default) (hash-table-ref/default ht arg #f) (hash-table-ref/default ht arg (car default)))) (define (usage . args) (if (> (length args) 0) (apply print "ERROR: " args)) (if (string? help) (print help) (print "Usage: " (car (argv)) " ... ")) (exit 0)) (define (get-args args params switches arg-hash num-needed) (let* ((numtargs (length args)) (adj-num-needed (if num-needed (+ num-needed 2) #f))) (if (< numtargs (if adj-num-needed adj-num-needed 2)) (if (>= num-needed 1) (usage "No arguments provided") '()) (let loop ((arg (cadr args)) (tail (cddr args)) (remtargs '())) (cond ((member arg params) ;; args with params (if (< (length tail) 1) (usage "param given without argument " arg) (let ((val (car tail)) (newtail (cdr tail))) (hash-table-set! arg-hash arg val) (if (null? newtail) remtargs (loop (car newtail)(cdr newtail) remtargs))))) ((member arg switches) ;; args with no params (i.e. switches) (hash-table-set! arg-hash arg #t) (if (null? tail) remtargs (loop (car tail)(cdr tail) remtargs))) (else (if (null? tail)(append remtargs (list arg)) ;; return the non-used args (loop (car tail)(cdr tail)(append remtargs (list arg)))))))) )) (define (print-args remtargs arg-hash) (print "ARGS: " remtargs) (for-each (lambda (arg) (print " " arg " " (hash-table-ref/default arg-hash arg #f))) (hash-table-keys arg-hash))) ) |
Added mtargs/mtargs.setup version [8300885e1f].
> > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | ;; Copyright 2007-2010, Matthew Welland. ;; ;; This program is made available under the GNU GPL version 2.0 or ;; greater. See the accompanying file COPYING for details. ;; ;; This program is distributed WITHOUT ANY WARRANTY; without even the ;; implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR ;; PURPOSE. ;;;; mtargs.setup ;; compile the code into a dynamically loadable shared object ;; (will generate mtargs.so) (compile -s mtargs.scm) ;; Install as extension library (standard-extension 'mtargs "mtargs.so") |
Added mtexec.scm version [6016ee8684].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | ; Copyright 2006-2017, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more 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 margs)) (declare (uses configf)) ;; (declare (uses rmt)) ;; (use ducttape-lib) (include "megatest-version.scm") (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)) |# |
Added mttop.scm version [0ba1c89f48].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | ;; Copyright 2006-2011, Matthew Welland. ;; ;; This program is made available under the GNU GPL version 2.0 or ;; greater. See the accompanying file COPYING for details. ;; ;; This program is distributed WITHOUT ANY WARRANTY; without even the ;; implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR ;; PURPOSE. ;; This is from the perl world, a hash of hashes is a super easy way to keep a handle on ;; lots of disparate data ;; (declare (unit mttop)) (module mttop * (import chicken scheme ;; data-structures posix srfi-1 ;; srfi-13 srfi-69 ports extras regex posix data-structures matchable ) (define (str-is-cmd cmd all-cmds) (let* ((rx (regexp (conc "^" cmd ".*"))) (mx (filter string? (map (lambda (x) (let ((res (string-match rx x))) (if res (car res) #f))) all-cmds)))) (if (eq? (length mx) 1) ;; have a command (car mx) #f))) (define (mttop-run args all-cmds) ;; any path through this call must end in exit if it is NOT an old Megatest call (if (null? args) #f ;; continue on and do the old Megatest stuff (let ((cmd (str-is-cmd (car args) all-cmds))) (if cmd (begin (case (string->symbol cmd) ((help)(print "New help")) (else (print "Command " cmd " is not implemented yet."))) (exit)) ;; always exit here #f)))) ;; or continue on to Megatest old stuff here ) |
Modified mtut.scm from [2f0384f486] to [ead30f316f].
|
| | | | > > > > > | | > | > > > | | | > > < > > > > | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | | > > > > > > > > > | | | | | | > > > | > | | | | | > > > > | | > > > > | | | | | | | | | | | | | | | | | | | | | > | | | > > | > | > > > > > > > > > < > > > > > > > > | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > | < < < < < | | < < < < < < < < < < < | | 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 | ; Copyright 2006-2017, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more 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 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)))))) | < < < < < < < | < | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > | | > > > | > | | > > | > > > > > | | < > > | > > > | < < > > > | > > > > > | < < | < | | > > | | | < | | | > > > | > > > > > > > > > | > > > > > > | | | | | | | > | > > > > > | > > > > > > > > | | > > > > > > > > | | > > > > > > > > > > > > > > > | > | > > > | | < < > | | > | < < > > | < < > > | | > > > > | | | | > > > > > > > > | > | < > | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > | | > | | | < < < < < < < < < < < < < < < < < | | > > | > > > | > | | < | | | > > > > > > > > > | | | | | | | | | | | | > > | | > > | > > > > | < < | | | > | | | > | > > > > > > > > > > > | 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 | (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)) | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | > | > > | | > | > > > > > | > > < | | | | > | | | | > | < > > < | | | > | | | | | | > | < | | | | | | | > | | > > > > | | > | | | | | | > > > > > > > > | | | | | | | | > > | | > > | > | > > > | > | | < > | > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | | | > > > > > > > | > | > > > > > > > > > > > > > > > > | | | | | | | | | | > > > > > > > > > > > > > > | | | > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > | > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > | > | | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | (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) "") (if (member action '("-run" "-rerun-clean" "-rerun-all" "-kill-rerun")) "-rerun DEAD,ABORT,KILLED" "")) 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"))))) | > > > > > > | 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 | ;; (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)) |# |
Added mutils.scm version [cd969aa5f3].
> > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | ;;====================================================================== ;; Copyright 2019, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more 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 mutils)) (include "mutils/mutils.scm") |
Added mutils/Makefile version [6e71a235fc].
> > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | # Copyright 2007-2010, Matthew Welland. # # This program is made available under the GNU GPL version 2.0 or # greater. See the accompanying file COPYING for details. # # This program is distributed WITHOUT ANY WARRANTY; without even the # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR # PURPOSE. # TARGDIR = $(shell csi -e "(print (car \#\#sys\#include-pathnames))(exit)") all : uptodate.log # $(TARGDIR)/mutils.so uptodate.log : mutils.scm mutils.setup chicken-setup | tee uptodate.log $(TARGDIR)/mutils.so : mutils.so @echo installing to $(TARGDIR) cp mutils.so $(TARGDIR) mutils.so : mutils.scm csc -s mutils.scm |
Added mutils/mutils.meta version [d4f4a25176].
> > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | ( ; Your egg's license: (license "BSD") ; Pick one from the list of categories (see below) for your egg and enter it ; here. (category misc) ; A list of eggs mpeg3 depends on. If none, you can omit this declaration ; altogether. If you are making an egg for chicken 3 and you need to use ; procedures from the `files' unit, be sure to include the `files' egg in the ; `needs' section (chicken versions < 3.4.0 don't provide the `files' unit). ; `depends' is an alias to `needs'. (needs sparse-vectors) ; A list of eggs required for TESTING ONLY. See the `Tests' section. (test-depends test) (author "Matt Welland") (synopsis "A basic description of the purpose of the egg.")) |
Added mutils/mutils.scm version [9fa9e34972].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | ;; Copyright 2006-2011, Matthew Welland. ;; ;; This program is made available under the GNU GPL version 2.0 or ;; greater. See the accompanying file COPYING for details. ;; ;; This program is distributed WITHOUT ANY WARRANTY; without even the ;; implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR ;; PURPOSE. ;; This is from the perl world, a hash of hashes is a super easy way to keep a handle on ;; lots of disparate data ;; (module mutils * (import chicken scheme ;; data-structures posix srfi-1 ;; srfi-13 srfi-69 ports extras regex posix data-structures matchable ) (define (mutils:hierhash-ref hh . keys) (if (null? keys) #f (let loop ((ht hh) (key (car keys)) (tail (cdr keys))) (if (null? tail) (if (hash-table? ht) (hash-table-ref/default ht key #f) #f) (if (hash-table? ht) (loop (hash-table-ref/default ht key #f) (car tail) (cdr tail)) #f))))) ;; WATCH THE NON-INTUITIVE INTERFACE HERE!!!! ;; val comes first! ;; (define (mutils:hierhash-set! hh val . keys) (if (null? keys) #f (let loop ((ht hh) (key (car keys)) (tail (cdr keys))) (if (null? tail) ;; last one! (hash-table-set! ht key val) (let ((nh (hash-table-ref/default ht key #f))) (if (not nh)(set! nh (make-hash-table))) (hash-table-set! ht key nh) (loop nh (car tail) (cdr tail))))))) ;; nice little routine to add an item to a list in a hashtable ;; (define (mutils:hash-table-add-to-list htbl key item) (let ((l (hash-table-ref/default htbl key #f))) (if l (hash-table-set! htbl key (cons item l)) (hash-table-set! htbl key (list item))))) (define (mutils:hash-table-append-to-list htbl key lst) (let ((l (hash-table-ref/default htbl key #f))) (if l (hash-table-set! htbl key (append lst l)) (hash-table-set! htbl key lst)))) ;;====================================================================== ;; Utils ;;====================================================================== (define (mutils:file->list fname) (let ((fh (open-input-file fname)) (comment (regexp "^\\s*#")) (blank (regexp "^\\s*$"))) (let loop ((l (read-line fh)) (res '())) (if (eof-object? l) (reverse res) (if (or (string-match comment l) (string-match blank l)) (loop (read-line fh) res) (loop (read-line fh) (cons l res))))))) (use sparse-vectors) ;; this is a simple two dimensional sparse array ;; ONLY TWO DIMENSIONS!!! SEE ARRAY-LIB IF YOUR NEEDS ARE GREATER!! ;; (define (mutils:make-sparse-array) (let ((a (make-sparse-vector))) (sparse-vector-set! a 0 (make-sparse-vector)) a)) (define (mutils:sparse-array? a) (and (sparse-vector? a) (sparse-vector? (sparse-vector-ref a 0)))) (define (mutils:sparse-array-ref a x y) (let ((row (sparse-vector-ref a x))) (if row (sparse-vector-ref row y) #f))) (define (mutils:sparse-array-set! a x y val) (let ((row (sparse-vector-ref a x))) (if row (sparse-vector-set! row y val) (let ((new-row (make-sparse-vector))) (sparse-vector-set! a x new-row) (sparse-vector-set! new-row y val))))) ;; some routines for treating assoc lists a bit like hash tables (define (mutils:assoc-get/default alist key default) (let ((res (assoc key alist))) (if (and res (list? res)(> (length res) 1)) (cadr res) default))) (define (mutils:assoc-get alist key) (cadr (assoc key alist))) (define (mutils:hier-list? @hierlist) (and (list? @hierlist) (> (length @hierlist) 0) (list? (car @hierlist)) (> (length (car @hierlist)) 1))) (define (mutils:hier-list-get @hierlist . @path) (if (list? @hierlist) (let* (($path (car @path)) (@rempath (cdr @path)) (@match (assoc $path @hierlist))) (if @match (if (or (not (list? @rempath))(null? @rempath)) (cadr @match) (apply mutils:hier-list-get (cadr @match) @rempath)) #f)) #f)) (define (mutils:hier-list-put! @hierlist . @path) (let* (($path (car @path)) (@rempath (cdr @path)) ($value (cadr @path)) (@match (assoc $path @hierlist)) (@remhierlist (remove (lambda (a) (equal? a @match)) @hierlist)) (@old-pair (let (($value (mutils:hier-list-get @hierlist $path))) (if $value $value '()))) (@new-pair (list $path (if (eq? (length @rempath) 1) (car @rempath) (apply mutils:hier-list-put! @old-pair @rempath))))) (cons @new-pair @remhierlist))) (define (mutils:hier-list-remove! @hierlist . @path) (let (($path (car @path))) (if (eq? (length @path) 1) (remove (lambda (a) (equal? a (assoc $path @hierlist))) @hierlist) (let* ((@rempath (cdr @path)) (@match (assoc $path @hierlist)) (@remhierlist (remove (lambda (a) (equal? @match a)) @hierlist)) (@old-pair (let (($value (mutils:hier-list-get @hierlist $path))) (if $value $value '()))) (@new-pair (list $path (apply mutils:hier-list-remove! @old-pair @rempath)))) (cons @new-pair @remhierlist))))) (define (mutils:keys @hierlist . @path) (map (lambda (@l) (if (and (list? @l)(not (null? @l))) (car @l))) (if (null? @path) @hierlist (apply mutils:hier-list-get @hierlist @path)))) ;;====================================================================== ;; Other utils ;;====================================================================== (define (check-write-create fpath) (and (file-write-access? fpath) (let ((fname (conc fpath "/.junk-" (current-seconds) "-" (random 10000)))) ;;(print "trying to create/remove " fname) (handle-exceptions exn #f (begin (with-output-to-file fname (lambda () (print "You can delete this file"))) (delete-file fname) #t))))) (define (run-and-return-output cmd . params) (let-values (((inp oup pid) (process cmd params))) (let ((res (with-input-from-port inp read-lines))) (let-values (((pidres status estatus) (process-wait pid))) (and status (eq? estatus 0) res))))) (define (confirm-ssh-access-to-host hostname) (run-and-return-output "ssh" hostname "uptime")) (define (check-display dsp) (run-and-return-output "xdpyinfo" "-display" dsp)) #;(define (check-display dsp) (let-values (((inp oup pid) (process "xdpyinfo" `("-display" ,dsp)))) (let ((res (with-input-from-port inp read-lines))) (let-values (((pidres status estatus) (process-wait pid))) (and status (eq? estatus 0) res))))) ;; do some sanity checks on the system ;; (define (mutils:syscheck common:raw-get-remote-host-load server:get-best-guess-address read-config) ;; current dir writeable and do megatest.config, runconfigs.config files exist/readable (print "Current directory " (current-directory) " writeable: " (if (check-write-create ".") "yes" "NO")) ;; home dir writeable (print "Home directory " (get-environment-variable "HOME") " writeable: " (if (check-write-create (get-environment-variable "HOME")) "yes" "NO")) ;; /tmp writeable (print "/tmp directory writeable: " (if (check-write-create "/tmp") "yes" "NO")) ;; load configs (print "$DISPLAY set: " (if (get-environment-variable "DISPLAY") (conc (get-environment-variable "DISPLAY") " yes") "NO")) (print "$DISPLAY accessible? " ;; (eq? (system "xdpyinfo -display $DISPLAY &>/dev/null") 0) (if (check-display (get-environment-variable "DISPLAY")) "yes" "NO")) (print "Password-less ssh access to localhost: " (if (confirm-ssh-access-to-host "localhost") "yes" "NO")) ;; if I'm in a Megatest area do some checks (print "Have megatest.config: " (if (file-exists? "megatest.config") "yes" "NO")) (print "Have runconfigs.config: " (if (file-exists? "runconfigs.config") "yes" "NO")) (if (file-exists? ".homehost") (let* ((homehost (with-input-from-file ".homehost" read-line)) (currhost (get-host-name)) (bestadrs (server:get-best-guess-address currhost))) (print "Have .homehost and it is the localhost: " (if (equal? homehost bestadrs) "yes" (conc ".homehost=" homehost ", localhost=" bestadrs ", NO"))) (print "Have .homehost and it is reachable via ssh: " (if (confirm-ssh-access-to-host homehost) "yes" "NO")) )) (if (file-exists? "megatest.config") (let* ((cdat (read-config "megatest.config" #f #f))) (print "Have [disks] section: " (if (hash-table-ref/default cdat "disks" #f) (conc (hash-table-ref cdat "disks") " yes") "NO")) (for-each (lambda (entry) (match entry ((dname path) (print "Disk " dname " at " path " writeable: " (if (check-write-create path) "yes" "NO"))) (else (print "bad entry: " entry)))) (hash-table-ref/default cdat "disks" '())))) (print "Have link tree and it is writable: " (if (and (file-exists? "lt") (check-write-create "lt")) "yes" "NO")) ;; check load on homehost ) ;; Develop stuff here - then move to where it belongs. ) |
Added mutils/mutils.setup version [4dd63cdcba].
> > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | ;; Copyright 2007-2010, Matthew Welland. ;; ;; This program is made available under the GNU GPL version 2.0 or ;; greater. See the accompanying file COPYING for details. ;; ;; This program is distributed WITHOUT ANY WARRANTY; without even the ;; implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR ;; PURPOSE. ;;;; mutils.setup ;; compile the code into a dynamically loadable shared object ;; (will generate mutils.so) (compile -s mutils.scm) ;; Install as extension library (install-extension 'mutils "mutils.so") |
Added mutils/tests/datastruct.scm version [26239e26a3].
> > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | (use test) (include "datastruct.scm") (define hh (make-hash-table)) (hierhash-set! hh 5 1 2 3 4) (test 5 (hierhash-ref hh 1 2 3 4)) (hierhash-set! hh 10 1 2 3 5) (test 10 (hierhash-ref hh 1 2 3 5)) (test 5 (hierhash-ref hh 1 2 3 4)) |
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) |
Added pkts.scm version [4f496b5684].
> > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | ;;====================================================================== ;; Copyright 2019, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more 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 pkts)) (include "pkts/pkts.scm") |
Added pkts/pktrec.scm version [28997466b3].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | (define-syntax define-record-type (syntax-rules () ((define-record-type type (constructor constructor-tag ...) predicate (field-tag accessor . more) ...) (begin (define type (make-record-type 'type '(field-tag ...))) (define constructor (record-constructor type '(constructor-tag ...))) (define predicate (record-predicate type)) (define-record-field type field-tag accessor . more) ...)))) ; An auxilliary macro for define field accessors and modifiers. ; This is needed only because modifiers are optional. (define-syntax define-record-field (syntax-rules () ((define-record-field type field-tag accessor) (define accessor (record-accessor type 'field-tag))) ((define-record-field type field-tag accessor modifier) (begin (define accessor (record-accessor type 'field-tag)) (define modifier (record-modifier type 'field-tag)))))) ; Record types ; We define the following procedures: ; ; (make-record-type <type-name <field-names>) -> <record-type> ; (record-constructor <record-type<field-names>) -> <constructor> ; (record-predicate <record-type>) -> <predicate> ; (record-accessor <record-type <field-name>) -> <accessor> ; (record-modifier <record-type <field-name>) -> <modifier> ; where ; (<constructor> <initial-value> ...) -> <record> ; (<predicate> <value>) -> <boolean> ; (<accessor> <record>) -> <value> ; (<modifier> <record> <value>) -> <unspecific> ; Record types are implemented using vector-like records. The first ; slot of each record contains the record's type, which is itself a ; record. (define (record-type record) (record-ref record 0)) ;---------------- ; Record types are themselves records, so we first define the type for ; them. Except for problems with circularities, this could be defined as: ; (define-record-type :record-type ; (make-record-type name field-tags) ; record-type? ; (name record-type-name) ; (field-tags record-type-field-tags)) ; As it is, we need to define everything by hand. (define :record-type (make-record 3)) (record-set! :record-type 0 :record-type) ; Its type is itself. (record-set! :record-type 1 ':record-type) (record-set! :record-type 2 '(name field-tags)) ; Now that :record-type exists we can define a procedure for making more ; record types. (define (make-record-type name field-tags) (let ((new (make-record 3))) (record-set! new 0 :record-type) (record-set! new 1 name) (record-set! new 2 field-tags) new)) ; Accessors for record types. (define (record-type-name record-type) (record-ref record-type 1)) (define (record-type-field-tags record-type) (record-ref record-type 2)) ;---------------- ; A utility for getting the offset of a field within a record. (define (field-index type tag) (let loop ((i 1) (tags (record-type-field-tags type))) (cond ((null? tags) (error "record type has no such field" type tag)) ((eq? tag (car tags)) i) (else (loop (+ i 1) (cdr tags)))))) ;---------------- ; Now we are ready to define RECORD-CONSTRUCTOR and the rest of the ; procedures used by the macro expansion of DEFINE-RECORD-TYPE. (define (record-constructor type tags) (let ((size (length (record-type-field-tags type))) (arg-count (length tags)) (indexes (map (lambda (tag) (field-index type tag)) tags))) (lambda args (if (= (length args) arg-count) (let ((new (make-record (+ size 1)))) (record-set! new 0 type) (for-each (lambda (arg i) (record-set! new i arg)) args indexes) new) (error "wrong number of arguments to constructor" type args))))) (define (record-predicate type) (lambda (thing) (and (record? thing) (eq? (record-type thing) type)))) (define (record-accessor type tag) (let ((index (field-index type tag))) (lambda (thing) (if (and (record? thing) (eq? (record-type thing) type)) (record-ref thing index) (error "accessor applied to bad value" type tag thing))))) (define (record-modifier type tag) (let ((index (field-index type tag))) (lambda (thing value) (if (and (record? thing) (eq? (record-type thing) type)) (record-set! thing index value) (error "modifier applied to bad value" type tag thing))))) Records ; This implements a record abstraction that is identical to vectors, ; except that they are not vectors (VECTOR? returns false when given a ; record and RECORD? returns false when given a vector). The following ; procedures are provided: ; (record? <value>) -> <boolean> ; (make-record <size>) -> <record> ; (record-ref <record> <index>) -> <value> ; (record-set! <record> <index> <value>) -> <unspecific> ; ; These can implemented in R5RS Scheme as vectors with a distinguishing ; value at index zero, providing VECTOR? is redefined to be a procedure ; that returns false if its argument contains the distinguishing record ; value. EVAL is also redefined to use the new value of VECTOR?. ; Define the marker and redefine VECTOR? and EVAL. (define record-marker (list 'record-marker)) (define real-vector? vector?) (define (vector? x) (and (real-vector? x) (or (= 0 (vector-length x)) (not (eq? (vector-ref x 0) record-marker))))) ; This won't work if ENV is the interaction environment and someone has ; redefined LAMBDA there. (define eval (let ((real-eval eval)) (lambda (exp env) ((real-eval `(lambda (vector?) ,exp)) vector?)))) ; Definitions of the record procedures. (define (record? x) (and (real-vector? x) (< 0 (vector-length x)) (eq? (vector-ref x 0) record-marker))) (define (make-record size) (let ((new (make-vector (+ size 1)))) (vector-set! new 0 record-marker) new)) (define (record-ref record index) (vector-ref record (+ index 1))) (define (record-set! record index value) (vector-set! record (+ index 1) value)) |
Added pkts/pkts.meta version [b5255a025d].
> > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | ;; -*- scheme -*- ( ; Your egg's license: (license "BSD") ; Pick one from the list of categories (see below) for your egg and enter it ; here. (category db) ; A list of eggs pkts depends on. If none, you can omit this declaration ; altogether. If you are making an egg for chicken 3 and you need to use ; procedures from the `files' unit, be sure to include the `files' egg in the ; `needs' section (chicken versions < 3.4.0 don't provide the `files' unit). ; `depends' is an alias to `needs'. ;; (needs (autoload "3.0")) ; A list of eggs required for TESTING ONLY. See the `Tests' section. (test-depends test) (author "Matt Welland") (synopsis "A sha1-chain based datastore built on packets consisting of single line cards modeled loosely on the fossil scm datastore.")) |
Added pkts/pkts.release-info version [fbbc2937bb].
> > > | 1 2 3 | (repo fossil "http://www.kiatoa.com/cgi-bin/fossils/{egg-name}") (uri zip "http://www.kiatoa.com/cgi-bin/fossils/{egg-name}/zip/{egg-name}.zip?uuid={egg-release}") (release "1.0") |
Added pkts/pkts.scm version [90f8c93eeb].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | ;; Copyright 2006-2017, Matthew Welland. ;; ;; This file is part of Pkts ;; ;; Pkts is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Pkts is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Pkts. If not, see <http://www.gnu.org/licenses/>. ;; ;; CARDS: ;; ;; A card is a line of text, the first two characters are a letter followed by a ;; space. The letter is the card type. ;; ;; PKTS: ;; ;; A pkt is a sorted list of cards with a final card Z that contains the shar1 hash ;; of all of the preceding cards. ;; ;; APKT: ;; ;; An alist mapping card types to card data ;; '((T . "pkttype") ;; (a . "some content")) ;; ;; EPKT: ;; ;; Extended packet using friendly keys. Must use a pktspec to convert to/from epkts ;; '((ptype . "pkttype") ;; (adata . "some content)) ;; ;; DPKT: ;; ;; pkts pulled from the database have this format: ;; ;;((apkt (Z . "7de89c09ac024b3832c93e16cd78d11e2e28733b") <= this is a the alist ;; (t . "v1.63/tip/dev") ;; (c . "QUICKPATT") ;; (T . "runstart") ;; (P . "354eeb67120a921e3e33155ecab1b522ac10b6bd") ;; (D . "1488995096.0")) ;; (id . 8) ;; (group-id . 0) ;; (uuid . "7de89c09ac024b3832c93e16cd78d11e2e28733b") ;; (parent . "") ;; (pkt-type . "runstart") ;; (pkt . "D 1488995096.0\nP 354eeb67120a921e3e33155ecab1b522ac10b6bd\nT runstart\nc QUICKPATT\nt v1.63/tip/dev\nZ 7de89c09ac024b3832c93e16cd78d11e2e28733b")) ;; ;; pktspec is alist of alists mapping types and nicekeys to keys ;; ;; '((posting . ((title . t) ;; (url . u) ;; (blurb . b))) ;; (comment . ((comment . c) ;; (score . s)))) ;; Reserved cards: ;; P : pkt parent ;; R : reference pkt containing mapping of short string -> sha1sum strings ;; T : pkt type ;; D : current time from (current-time), unless provided ;; Z : shar1 hash of the packet ;; Example usage: ;; ;; Create a pkt: ;; ;; (use pkts) ;; (define-values (uuid pkt) ;; (alist->pkt ;; '((fruit . "apple") (meat . "beef")) ;; this is the data to convert ;; '((foods (fruit . f) (meat . m))) ;; this is the pkt spec ;; ptype: ;; 'foods)) ;; ;; Add to pkt queue: ;; ;; (define db (open-queue-db "/tmp/pkts" "pkts.db")) ;; (add-to-queue db pkt uuid 'foods #f 0) ;; no parent and use group_id of 0 ;; ;; Retrieve the packet from the db and extract a value: ;; ;; (alist-ref ;; 'meat ;; (dpkt->alist ;; (car (get-dpkts db #f 0 #f)) ;; '((foods (fruit . f) ;; (meat . m))))) ;; => "beef" ;; (module pkts ( ;; cards, util and misc ;; sort-cards ;; calc-shar1 ;; ;; low-level constructor procs, exposed only for development/testing, will be removed construct-sdat construct-pkt card->type/value add-z-card ;; queue database procs open-queue-db add-to-queue create-and-queue lookup-by-uuid lookup-by-id get-dpkts get-not-processed-pkts get-related find-pkts process-pkts get-descendents get-ancestors get-pkts get-last-descendent with-queue-db load-pkts-to-db ;; procs that operate directly on pkts, sdat, apkts, dpkts etc. pkt->alist ;; pkt -> apkt (i.e. alist) pkt->sdat ;; pkt -> '("a aval" "b bval" ...) sdat->alist ;; '("a aval" "b bval"...) -> ((a . "aval")(b . "bval") ...) dblst->dpkts ;; convert list of tuples from queue db into dpkts dpkt->alist ;; flatten a dpkt into an alist containing all db fields and the pkt alist dpkts->alists ;; apply dpkt->alist to a list of alists using a pkt-spec alist->pkt ;; returns two values uuid, pkt get-value ;; looks up a value given a key in a dpkt flatten-all ;; merge the list of values from a query which includes a pkt into a flat alist <== really useful! check-pkt ;; pkt alists write-alist->pkt read-pkt->alist ;; archive database archive-open-db write-archive-pkts archive-pkts mark-processed ;; pktsdb pktdb-conn ;; useful pktdb-fname pktsdb-open pktsdb-close pktsdb-add-record ;; temporary pktdb-pktspec ;; utility procs increment-string ;; used to get indexes for strings in ref pkts make-report ;; make a .dot file ) (import chicken scheme data-structures posix srfi-1 regex srfi-13 srfi-69 ports extras) (use crypt sha1 message-digest (prefix dbi dbi:) typed-records) ;;====================================================================== ;; DATA MANIPULATION UTILS ;;====================================================================== (define-inline (unescape-data data) (string-translate* data '(("\\n" . "\n") ("\\\\" . "\\")))) (define-inline (escape-data data) (string-translate* data '(("\n" . "\\n") ("\\" . "\\\\")))) (define-inline (make-card type data) (conc type " " (escape-data (->string data)))) ;; reverse an alist for doing pktkey -> external key conversions ;; (define-inline (reverse-aspec aspec) (map (lambda (dat) (cons (cdr dat)(car dat))) aspec)) ;; add a card to the list of cards, sdat ;; if type is #f return only sdat ;; if data is #f return only sdat ;; (define-inline (add-card sdat type data) (if (and type data) (cons (make-card type data) sdat) sdat)) ;;====================================================================== ;; STRING AS FUNKY NUMBER ;;====================================================================== ;; NOTE: PTDZ are removed as they are reserved. NB// the R card is not used in a ;; ref, instead the P parent card is used. ;; Question: Why does it matter to remove PTDZ? ;; To make the ref easier to use the ref strings will be the keys ;; so we cannot have overlap with any actual keys. But this is a ;; bit silly. What we need to do instead is reject keys of length ;; one where the char is in PTDZ ;; ;; This is basically base92 ;; (define string-num-chars (string->list "!#$%&'()*+,-./0123456789:;<=>?@ABCEFGHIJKLMNOQRSUVWXY[\\]^_abcdefghijklmnopqrstuvwxyz{|}~")) ;; "0123456789abcdefghijklmnopqrstuvwxyzABCEFGHIJKLMNOQSUVWXY!#$%&'()*+,-./[]:;<=>?\\^_{}|")) (define (char-incr inchar) (let* ((carry #f) (next-char (let ((rem (member inchar string-num-chars))) (if (eq? (length rem) 1) ;; we are at the last character in our string-num-chars list (begin (set! carry #t) (car string-num-chars)) (cadr rem))))) (values next-char carry))) (define (increment-string str) (if (string-null? str) "0" (let ((strlst (reverse (string->list str)))) ;; need to process the string from the lsd (list->string (let loop ((hed (car strlst)) (tal (cdr strlst)) (res '())) (let-values (((newhed carry)(char-incr hed))) ;; (print "newhed: " newhed " carry: " carry " tal: " tal) (let ((newres (cons newhed res))) (if carry ;; we'll have to propagate the carry (if (null? tal) ;; at the end, tack on "0" (which is really a "1") (cons (car string-num-chars) newres) (loop (car tal)(cdr tal) newres)) (append (reverse tal) newres))))))))) ;;====================================================================== ;; P K T S D B I N T E R F A C E ;; ;; INTEGER, REAL, TEXT ;;====================================================================== ;; ;; spec ;; ( (tablename1 . (field1name L1 TYPE) ;; (field2name L2 TYPE) ... ) ;; (tablename2 ... )) ;; ;; Example: (tests (testname n TEXT) ;; (rundir r TEXT) ;; ... ) ;; ;; pkt keys are taken from the first letter, if that is not unique ;; then look at the next letter and so on ;; ;; use this struct to hold the pktspec and the db handle ;; (defstruct pktdb (fname #f) (pktsdb-spec #f) (pktspec #f) ;; cache the pktspec (field-keys #f) ;; cache the field->key mapping (field1 . k1) ... (key-fields #f) ;; cache the key->field mapping (conn #f) ) ;; WARNING: There is a simplification in the pktsdb spec w.r.t. pktspec. ;; The field specs are the cdr of the table list - not a full ;; list. The extra list level in pktspec is gratuitous and should ;; be removed. ;; (define (pktsdb-spec->pktspec tables-spec) (map (lambda (tablespec) (list (car tablespec) (map (lambda (field-spec) (cons (car field-spec)(cadr field-spec))) (cdr tablespec)))) tables-spec)) (define (pktsdb-open dbfname pktsdb-spec) (let* ((pdb (make-pktdb)) (dbexists (file-exists? dbfname)) (db (dbi:open 'sqlite3 `((dbname . ,dbfname))))) (pktdb-pktsdb-spec-set! pdb pktsdb-spec) (pktdb-pktspec-set! pdb (pktsdb-spec->pktspec pktsdb-spec)) (pktdb-fname-set! pdb dbfname) (pktdb-conn-set! pdb db) (if (not dbexists) (pktsdb-init pdb)) pdb)) (define (pktsdb-init pktsdb) (let* ((db (pktdb-conn pktsdb)) (pktsdb-spec (pktdb-pktsdb-spec pktsdb))) ;; create a table for the pkts themselves (dbi:exec db "CREATE TABLE IF NOT EXISTS pkts (id INTEGER PRIMARY KEY, zkey TEXT, record_id INTEGER, pkt TEXT);") (for-each (lambda (table) (let* ((table-name (car table)) (fields (cdr table)) (stmt (conc "CREATE TABLE IF NOT EXISTS " table-name " (id INTEGER PRIMARY KEY," (string-intersperse (map (lambda (fieldspec) (conc (car fieldspec) " " (caddr fieldspec))) fields) ",") ");"))) (dbi:exec db stmt))) pktsdb-spec))) ;; create pkt from the data and insert into pkts table ;; ;; data is assoc list of (field . value) ... ;; tablename is a symbol matching the table name ;; (define (pktsdb-add-record pktsdb tablename data #!optional (parent #f)) (let*-values (((zkey pkt) (alist->pkt data (pktdb-pktspec pktsdb) ptype: tablename))) ;; have the data as alist so insert it into appropriate table also (let* ((db (pktdb-conn pktsdb))) ;; TODO: Address collisions (dbi:exec db "INSERT INTO pkts (zkey,pkt,record_id) VALUES (?,?,?);" zkey pkt -1) (let* (;; (pktid (pktsdb-pktkey->pktid pktsdb pktkey)) (record-id (pktsdb-insert pktsdb tablename data))) (dbi:exec db "UPDATE pkts SET record_id=? WHERE zkey=?;" record-id zkey) )))) ;; (define (pktsdb-insert pktsdb tablename data) (let* ((db (pktdb-conn pktsdb)) (stmt (conc "INSERT INTO " tablename " (" (string-intersperse (map conc (map car data)) ",") ") VALUES ('" ;; TODO: Add lookup of data type and do not ;; wrap integers with quotes (string-intersperse (map conc (map cdr data)) "','") "');"))) (print "stmt: " stmt) (dbi:exec db stmt) ;; lookup the record-id and return it )) (define (pktsdb-close pktsdb) (dbi:close (pktdb-conn pktsdb))) ;; (let loop ((s "0")(n 0))(print s)(if (< n 5000)(loop (increment-string s)(+ n 1)))) ;;====================================================================== ;; CARDS, MISC and UTIL ;;====================================================================== ;; given string (likely multi-line) "dat" return shar1 hash ;; (define-inline (calc-shar1 instr) (message-digest-string (sha1-primitive) instr)) ;; given a single card return its type and value ;; (define (card->type/value card) (let ((ctype (substring card 0 1)) (cval (substring card 2 (string-length card)))) (values (string->symbol ctype) cval))) ;;====================================================================== ;; SDAT procs ;; sdat is legacy/internal usage. Intention is to remove sdat calls from ;; the exposed calls. ;;====================================================================== ;; sort list of cards ;; (define-inline (sort-cards sdat) (sort sdat string<=?)) ;; pkt rules ;; 1. one card per line ;; 2. at least one card ;; 3. no blank lines ;; given sdat, a list of cards return uuid, packet (as sdat) ;; (define (add-z-card sdat) (let* ((sorted-sdat (sort-cards sdat)) (dat (string-intersperse sorted-sdat "\n")) (uuid (calc-shar1 dat))) (values uuid (conc dat "\nZ " uuid)))) (define (check-pkt pkt) (handle-exceptions exn #f ;; anything goes wrong - call it a crappy pkt (let* ((sdat (string-split pkt "\n")) (rdat (reverse sdat)) ;; reversed (zdat (car rdat)) (Z (cadr (string-split zdat))) (cdat (string-intersperse (reverse (cdr rdat)) "\n"))) (equal? Z (calc-shar1 cdat))))) ;;====================================================================== ;; APKTs ;;====================================================================== ;; convert a sdat (list of cards) to an alist ;; (define (sdat->alist sdat) (let loop ((hed (car sdat)) (tal (cdr sdat)) (res '())) (let-values (( (ctype cval)(card->type/value hed) )) ;; if this card is not one of the common ones tack it on to rem (let* ((oldval (alist-ref ctype res)) (newres (cons (cons ctype (if oldval ;; list or string (if (list? oldval) (cons cval oldval) (cons cval (list oldval))) cval)) res))) (if (null? tal) newres (loop (car tal)(cdr tal) newres)))))) ;;((apkt (Z . "7de89c09ac024b3832c93e16cd78d11e2e28733b") <= this is a the alist ;; (t . "v1.63/tip/dev") ;; (c . "QUICKPATT") ;; (T . "runstart") ;; (P . "354eeb67120a921e3e33155ecab1b522ac10b6bd") ;; (D . "1488995096.0")) ;; (id . 8) ;; (group-id . 0) ;; (uuid . "7de89c09ac024b3832c93e16cd78d11e2e28733b") ;; (parent . "") ;; (pkt-type . "runstart") ;; (pkt . "D 1488995096.0\nP 354eeb67120a921e3e33155ecab1b522ac10b6bd\nT runstart\nc QUICKPATT\nt v1.63/tip/dev\nZ 7de89c09ac024b3832c93e16cd78d11e2e28733b")) ;; ;; pktspec is alist of alists mapping types and nicekeys to keys ;; ;; '((posting . ((title . t) ;; (url . u) ;; (blurb . b))) ;; (comment . ((comment . c) ;; (score . s)))) ;; DON'T USE? ;; (define (get-value field dpkt . spec-in) (if (null? spec-in) (alist-ref field dpkt) (let* ((spec (car spec-in)) (apkt (alist-ref 'apkt dpkt))) ;; get the pkt alist (if (and apkt spec) (let* ((ptype (alist-ref 'pkt-type dpkt)) (pspec (alist-ref (string->symbol ptype) spec))) ;; do we have a spec for this type of pkt (and pspec (let* ((key (alist-ref field pspec))) (and key (alist-ref key apkt))))) #f)))) ;; convert a dpkt to a pure alist given a pktspec ;; this flattens out the alist to include the data from ;; the queue database record ;; (define (dpkt->alist dpkt pktspec) (let* ((apkt (alist-ref 'apkt dpkt)) (pkt-type (or (alist-ref 'pkt-type dpkt) ;; pkt-type is from the database field pkt_type (alist-ref 'T apkt))) (pkt-fields (alist-ref (string->symbol pkt-type) pktspec)) (rev-fields (if pkt-fields (reverse-aspec pkt-fields) '()))) (append (map (lambda (entry) (let* ((pkt-key (car entry)) (new-key (or (alist-ref pkt-key rev-fields) pkt-key))) `(,new-key . ,(cdr entry)))) apkt) dpkt))) ;; convert a list of dpkts into a list of alists using pkt-spec ;; (define (dpkts->alists dpkts pkt-spec) (map (lambda (x) (dpkt->alist x pkt-spec)) dpkts)) ;; Generic flattener, make the tuple and pkt into a single flat alist ;; ;; qry-result-spec is a list of symbols corresponding to each field ;; (define (flatten-all inlst pktspec . qry-result-spec) (map (lambda (tuple) (dpkt->alist (apply dblst->dpkts tuple qry-result-spec) pktspec)) inlst)) ;; call like this: ;; (construct-sdat 'a "a data" 'S "S data" ...) ;; returns list of cards ;; ( "A a value" "D 12345678900" ...) ;; (define (construct-sdat . alldat) (let ((have-D-card #f)) ;; flag (if (even? (length alldat)) (let loop ((type (car alldat)) (data (cadr alldat)) (tail (cddr alldat)) (res '())) (if (eq? type 'D)(set! have-D-card #t)) (if (null? tail) (if have-D-card ;; return the constructed pkt, add a D card if none found (add-card res type data) (add-card (add-card res 'D (current-seconds)) type data)) (loop (car tail) (cadr tail) (cddr tail) (add-card res type data)))) #f))) ;; #f means it failed to create the sdat (define (construct-pkt . alldat) (add-z-card (apply construct-sdat alldat))) ;;====================================================================== ;; CONVERTERS ;;====================================================================== (define (pkt->sdat pkt) (map unescape-data (string-split pkt "\n"))) ;; given a pure pkt return an alist ;; (define (pkt->alist pkt #!key (pktspec #f)) (let ((sdat (cond ((string? pkt) (pkt->sdat pkt)) ((list? pkt) pkt) (else #f)))) (if pkt (if pktspec (dpkt->alist (list (cons 'apkt (sdat->alist sdat))) pktspec) (sdat->alist sdat)) #f))) ;; convert an alist to an sdat ;; in: '((a . "blah")(b . "foo")) ;; out: '("a blah" "b foo") ;; (define (alist->sdat adat) (map (lambda (dat) (conc (car dat) " " (cdr dat))) adat)) ;; adat is the incoming alist, aspec is the mapping ;; from incoming key to the pkt key (usually one ;; letter to keep data tight) see the pktspec at the ;; top of this file ;; ;; NOTE: alists can contain multiple instances of the same key (supported fine by pkts) ;; but you (obviously I suppose) cannot use alist-ref to access those entries. ;; (define (alist->pkt adat aspec #!key (ptype #f)) (let* ((pkt-type (or ptype (alist-ref 'T adat) ;; can provide in the incoming alist #f)) (pkt-spec (if pkt-type ;; alist of external-key -> key (or (alist-ref pkt-type aspec) '()) (if (null? aspec) '() (cdar aspec)))) ;; default to first one if nothing specified (new-alist (map (lambda (dat) (let* ((key (car dat)) (val (cdr dat)) (newkey (or (alist-ref key pkt-spec) key))) (cons newkey (escape-data (conc val))))) ;; convert all incoming data (symbols, numbers etc.) to a string and then escape newlines. adat)) (new-with-type (if (alist-ref 'T new-alist) new-alist (cons `(T . ,pkt-type) new-alist))) (with-d-card (if (alist-ref 'D new-with-type) new-with-type (cons `(D . ,(current-seconds)) new-with-type)))) (add-z-card (alist->sdat with-d-card)))) ;;====================================================================== ;; D B Q U E U E I N T E R F A C E ;;====================================================================== ;; pkts ( ;; id SERIAL PRIMARY KEY, ;; uuid TEXT NOT NULL, ;; parent_uuid TEXT default '', ;; pkt_type INTEGER DEFAULT 0, ;; group_id INTEGER NOT NULL, ;; pkt TEXT NOT NULL ;; schema is list of SQL statements - can be used to extend db with more tables ;; (define (open-queue-db dbpath dbfile #!key (schema '())) (let* ((dbfname (conc dbpath "/" dbfile)) (dbexists (if (file-exists? dbfname) #t (begin (create-directory dbpath #t) #f))) (db (dbi:open 'sqlite3 (list (cons 'dbname dbfname))))) ;; (set-busy-handler! (dbi:db-conn db) (busy-timeout 10000)) (if (not dbexists) ;; NOTE: In the archive we allow duplicates and other messiness. (for-each (lambda (stmt) (dbi:exec db stmt)) (cons "CREATE TABLE IF NOT EXISTS pkts (id INTEGER PRIMARY KEY, group_id INTEGER NOT NULL, uuid TEXT NOT NULL, parent_uuid TEXT TEXT DEFAULT '', pkt_type TEXT NOT NULL, pkt TEXT NOT NULL, processed INTEGER DEFAULT 0)" schema))) ;; 0=not processed, 1=processed, 2... for expansion db)) (define (add-to-queue db pkt uuid pkt-type parent-uuid group-id) (dbi:exec db "INSERT INTO pkts (uuid,parent_uuid,pkt_type,pkt,group_id) VALUES(?,?,?,?,?);" ;; $1,$2,$3,$4,$5);" uuid (if parent-uuid parent-uuid "");; use null string as placeholder for no parent uuid. (if pkt-type (conc pkt-type) "") pkt group-id)) ;; given all needed parameters create a pkt and store it in the queue ;; procs is an alist that maps pkt-type to a function that takes a list of pkt params ;; in data and returns the uuid and pkt ;; (define (create-and-queue conn procs pkt-type parent-uuid group-id data) (let ((proc (alist-ref pkt-type procs))) (if proc (let-values (( (uuid pkt) (proc data) )) (add-to-queue conn pkt uuid pkt-type parent-uuid group-id) uuid) #f))) ;; given uuid get pkt, if group-id is specified use it (reduces probablity of ;; being messed up by a uuid collision) ;; (define (lookup-by-uuid db pkt-uuid group-id) (if group-id (dbi:get-one db "SELECT pkt FROM pkts WHERE group_id=? AND uuid=?;" group-id pkt-uuid) (dbi:get-one db "SELECT pkt FROM pkts WHERE uuid=?;" pkt-uuid))) ;; find a packet by its id ;; (define (lookup-by-id db id) (dbi:get-one db "SELECT pkt FROM pkts WHERE id=?;" id)) ;; apply a proc to the open db handle for a pkt db in pdbpath ;; (define (with-queue-db pdbpath proc #!key (schema #f)) (cond ((not (equal? (file-owner pdbpath)(current-effective-user-id))) (print "ERROR: directory " pdbpath " is not owned by " (current-effective-user-name))) (else (let* ((pdb (open-queue-db pdbpath "pkts.db" schema: schema)) ;; '("CREATE TABLE groups (id INTEGER PRIMARY KEY,groupname TEXT, CONSTRAINT group_constraint UNIQUE (groupname));")))) (res (proc pdb))) (dbi:close pdb) res)))) (define (load-pkts-to-db pktsdirs pdbpath #!key (schema #f)) (with-queue-db pdbpath (lambda (pdb) (for-each (lambda (pktsdir) ;; look at all (cond ((not (file-exists? pktsdir)) (print "ERROR: packets directory " pktsdir " does not exist.")) ((not (directory? pktsdir)) (print "ERROR: packets directory path " pktsdir " is not a directory.")) ((not (file-read-access? pktsdir)) (print "ERROR: packets directory path " pktsdir " is not readable.")) (else ;; (print "INFO: 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)))) ;;====================================================================== ;; P R O C E S S P K T S ;;====================================================================== ;; given a list of field values pulled from the queue db generate a list ;; of dpkt's ;; (define (dblst->dpkts lst . altmap) (let* ((maplst (if (null? altmap) '(id group-id uuid parent pkt-type pkt processed) altmap)) (res (map cons maplst lst))) ;; produces list of pairs, i.e an alist (cons `(apkt . ,(pkt->alist (alist-ref 'pkt res))) res))) ;; NB// ptypes is a list of symbols, '() or #f find all types ;; (define (get-dpkts db ptypes group-id parent-uuid #!key (uuid #f)) (let* ((ptype-qry (if (and ptypes (not (null? ptypes))) (conc " IN ('" (string-intersperse (map conc ptypes) "','") "')") (conc " LIKE '%' "))) (rows (dbi:get-rows db (conc "SELECT id,group_id,uuid,parent_uuid,pkt_type,pkt,processed FROM pkts WHERE pkt_type " ptype-qry " AND group_id=? AND processed=0 " (if parent-uuid (conc "AND parent_uuid='" parent-uuid "' ") "") (if uuid (conc "AND uuid='" uuid "' ") "") "ORDER BY id DESC;") group-id))) (map dblst->dpkts (map vector->list rows)))) ;; get N pkts not yet processed for group-id ;; (define (get-not-processed-pkts db group-id pkt-type limit offset) (map dblst->dpkts (map vector->list (dbi:get-rows db "SELECT id,group_id,uuid,parent_uuid,pkt_type,pkt,processed FROM pkts WHERE pkt_type = ? AND group_id = ? AND processed=0 LIMIT ? OFFSET ?;" (conc pkt-type) ;; convert symbols to string group-id limit offset )))) ;; given a uuid, get not processed child pkts ;; (define (get-related db group-id uuid) (map dblst->dpkts (dbi:get-rows db "SELECT id,group_id,uuid,parent_uuid,pkt_type,pkt,processed FROM pkts WHERE parent_uuid=? AND group_id=? AND processed=0;" uuid group-id))) ;; generic pkt processor ;; ;; find all packets in group-id of type in ptypes and apply proc to pktdat ;; (define (process-pkts conn group-id ptypes parent-uuid proc) (let* ((pkts (get-dpkts conn ptypes group-id parent-uuid))) (map proc pkts))) ;; criteria is an alist ((k . valpatt) ...) ;; - valpatt is a regex ;; - ptypes is a list of types (symbols expected) ;; match-type: 'any or 'all ;; (define (find-pkts db ptypes criteria #!key (processed #f)(match-type 'any)(pkt-spec #f)) ;; processed=#f, don't use, else use (let* ((pkts (get-dpkts db ptypes 0 #f)) (match-rules (lambda (pktdat) ;; returns a list of matching rules (filter (lambda (c) ;; (print "c: " c) (let* ((ctype (car c)) ;; card type (rx (cdr c)) ;; card pattern ;; (t (alist-ref 'pkt-type pktdat)) (pkt (alist-ref 'pkt pktdat)) (apkt (pkt->alist pkt)) (cdat (alist-ref ctype apkt))) ;; (print "cdat: " cdat) ;; " apkt: " apkt) (if cdat (string-match rx cdat) #f))) criteria))) (res (filter (lambda (pktdat) (if (null? criteria) ;; looking for all pkts #t (case match-type ((any)(not (null? (match-rules pktdat)))) ((all)(eq? (length (match-rules pktdat))(length criteria))) (else (print "ERROR: bad match type " match-type ", expecting any or all."))))) pkts))) (if pkt-spec (dpkts->alists res pkt-spec) res))) ;; get descendents of parent-uuid ;; ;; NOTE: Should be doing something like the following: ;; ;; given a uuid, get not processed child pkts ;; processed: ;; #f => get all ;; 0 => get not processed ;; 1 => get processed ;; (define (get-ancestors db group-id uuid #!key (processed #f)) (map dblst->dpkts (map vector->list (dbi:get-rows db (conc "SELECT id,group_id,uuid,parent_uuid,pkt_type,pkt,processed FROM pkts WHERE uuid IN (WITH RECURSIVE tree(uuid,parent_uuid) AS ( SELECT uuid, parent_uuid FROM pkts WHERE uuid = ? UNION ALL SELECT t.uuid, t.parent_uuid FROM pkts t JOIN tree ON t.uuid = tree.parent_uuid ) SELECT uuid FROM tree) AND group_id=?" (if processed (conc " AND processed=" processed) "") ";") uuid group-id)))) ;; Untested ;; (define (get-descendents db group-id uuid #!key (processed #f)) (map dblst->dpkts (map vector->list (dbi:get-rows db (conc "SELECT id,group_id,uuid,parent_uuid,pkt_type,pkt,processed FROM pkts WHERE uuid IN (WITH RECURSIVE tree(uuid,parent_uuid) AS ( SELECT uuid, parent_uuid FROM pkts WHERE uuid = ? UNION ALL SELECT t.uuid, t.parent_uuid FROM pkts t JOIN tree ON t.parent_uuid = tree.uuid ) SELECT uuid FROM tree) AND group_id=?" (if processed (conc " AND processed=" processed) "") ";") uuid group-id)))) ;; look up descendents based on given info unless passed in a list via inlst ;; (define (get-last-descendent db group-id uuid #!key (processed #f)(inlst #f)) (let ((descendents (or inlst (get-descendents db group-id uuid processed: processed)))) (if (null? descendents) #f (last descendents)))) ;;====================================================================== ;; A R C H I V E S - always to a sqlite3 db ;;====================================================================== ;; open an archive db ;; path: archive-dir/<year>/month.db ;; (define (archive-open-db archive-dir) (let* ((curr-time (seconds->local-time (current-seconds))) (dbpath (conc archive-dir "/" (time->string curr-time "%Y"))) (dbfile (conc dbpath "/" (time->string curr-time "%m") ".db")) (dbexists (if (file-exists? dbfile) #t (begin (create-directory dbpath #t) #f)))) (let ((db (dbi:open 'sqlite3 (list (cons 'dbname dbfile))))) ;; (set-busy-handler! db (busy-timeout 10000)) (if (not dbexists) ;; NOTE: In the archive we allow duplicates and other messiness. (dbi:exec db "CREATE TABLE IF NOT EXISTS pkts (id INTEGER, group_id INTEGER, uuid TEXT, parent_uuid TEXT, pkt_type TEXT, pkt TEXT, processed INTEGER DEFAULT 0)")) db))) ;; turn on transactions! otherwise this will be painfully slow ;; (define (write-archive-pkts src-db db pkt-ids) (let ((pkts (dbi:get-rows src-db (conc "SELECT id,group_id,uuid,parent_uuid,pkt_type,pkt FROM pkts WHERE id IN (" (string-intersperse (map conc pkt-ids) ",") ")")))) ;; (dbi:with-transaction ;; db (lambda () (for-each (lambda (pkt) (apply dbi:exec db "INSERT INTO pkts (id,group_id,uuid,parent_uuid,pkt_type,pkt) VALUES (?,?,?,?,?,?)" pkt)) pkts)))) ;; ) ;; given a list of uuids and lists of uuids move all to ;; the sqlite3 db for the current archive period ;; (define (archive-pkts conn pkt-ids archive-dir) (let ((db (archive-open-db archive-dir))) (write-archive-pkts conn db pkt-ids) (dbi:close db)) ;; (pg:with-transaction ;; conn ;; (lambda () (for-each (lambda (id) (dbi:get-one conn "DELETE FROM pkts WHERE id=?" id)) pkt-ids)) ;; )) ;; given a list of ids mark all as processed ;; (define (mark-processed conn pkt-ids) ;; (pg:with-transaction ;; conn ;; (lambda () (for-each (lambda (id) (dbi:get-one conn "UPDATE pkts SET processed=1 WHERE id=?;" id)) pkt-ids)) ;; x)) ;; a generic pkt getter, gets from the pkts db ;; (define (get-pkts conn ptypes) (let* ((ptypes-str (if (null? ptypes) "" (conc " WHERE pkt_type IN ('" (string-intersperse ptypes ",") "') "))) (qry-str (conc "SELECT id,group_id,uuid,parent_uuid,pkt_type,pkt,processed FROM pkts" ptypes-str))) (map vector->list (dbi:get-rows conn qry-str)))) ;; make a report of the pkts in the db ;; ptypes of '() gets all pkts ;; display-fields ;; (define (make-report dest conn pktspec display-fields . ptypes) (let* (;; (conn (dbi:db-conn (s:db))) (all-rows (get-pkts conn ptypes)) (all-pkts (flatten-all all-rows pktspec 'id 'group-id 'uuid 'parent 'pkt-type 'pkt 'processed)) (by-uuid (let ((ht (make-hash-table))) (for-each (lambda (pkt) (let ((uuid (alist-ref 'uuid pkt))) (hash-table-set! ht uuid pkt))) all-pkts) ht)) (by-parent (let ((ht (make-hash-table))) (for-each (lambda (pkt) (let ((parent (alist-ref 'parent pkt))) (hash-table-set! ht parent (cons pkt (hash-table-ref/default ht parent '()))))) all-pkts) ht)) (oup (if dest (open-output-file dest) (current-output-port)))) (with-output-to-port oup (lambda () (print "digraph megatest_state_status { // ranksep=0.05 rankdir=LR; node [shape=\"box\"]; ") ;; first all the names (for-each (lambda (pkt) (let* ((uuid (alist-ref 'uuid pkt)) (shortuuid (substring uuid 0 4)) (type (alist-ref 'pkt-type pkt)) (processed (alist-ref 'processed pkt))) (print "\"" uuid "\" [label=\"" shortuuid ", (" type ", " (if processed "processed" "not processed") ")") (for-each (lambda (key-field) (let ((val (alist-ref key-field pkt))) (if val (print key-field "=" val)))) display-fields) (print "\" ];"))) all-pkts) ;; now for parent-child relationships (for-each (lambda (pkt) (let ((uuid (alist-ref 'uuid pkt)) (parent (alist-ref 'parent pkt))) (if (not (equal? parent "")) (print "\"" parent "\" -> \"" uuid"\";")))) all-pkts) (print "}") )) (if dest (begin (close-output-port oup) (system "dot -Tpdf out.dot -o out.pdf"))) )) ;;====================================================================== ;; Read ref pkts into a vector < laststr hash table > ;;====================================================================== ;;====================================================================== ;; Read/write packets to files (convience functions) ;;====================================================================== ;; write alist to a pkt file ;; (define (write-alist->pkt targdir dat #!key (pktspec '())(ptype #f)) (let-values (((uuid pkt)(alist->pkt dat pktspec ptype: ptype))) (with-output-to-file (conc targdir "/" uuid ".pkt") (lambda () (print pkt))) uuid)) ;; return the uuid ;; read pkt into alist ;; (define (read-pkt->alist pkt-file #!key (pktspec #f)) (pkt->alist (with-input-from-file pkt-file read-string) pktspec: pktspec)) ) ;; module pkts |
Added pkts/pkts.setup version [bf666feb42].
> > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 | ;; Copyright 2007-2017, Matthew Welland. ;; ;; This program is made available under the GNU GPL version 2.0 or ;; greater. See the accompanying file COPYING for details. ;; ;; This program is distributed WITHOUT ANY WARRANTY; without even the ;; implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR ;; PURPOSE. ;;;; pkts.setup (standard-extension 'pkts "1.0") |
Added pkts/tests/run.scm version [957c7c2ae2].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | (use test) ;; (use (prefix pkts pkts:)) (use pkts (prefix dbi dbi:)) ;; (use trace)(trace sdat->alist pkt->alist) (if (file-exists? "queue.db")(delete-file "queue.db")) (test-begin "pkts and pkt archives") ;;====================================================================== ;; Basic pkt creation, parsing and conversion routines ;;====================================================================== (test-begin "basic packets") (test #f '(A "This is a packet") (let-values (((t v) (card->type/value "A This is a packet"))) (list t v))) (test #f "A A\nZ 664449e7299e0065a3e25c138ccef2df13ba291e" (let-values (((uuid res) (add-z-card '("A A")))) res)) (test #f '("CC C++" "D 1486332719.0" "a A" "b C")(sort (construct-sdat 'b "C" 'a "A" 'CC "C++" 'D 1486332719.0) string<=?)) (define pkt-example #f) (test #f "CC C++\nD 1486332719.0\na A\nb C\nZ 263eb3b6193de7fe65b1ded5bcda513e8b4d6b84" (let-values (((uuid res) (construct-pkt 'b "C" 'a "A" 'CC "C++" 'D 1486332719.0))) (set! pkt-example (cons uuid res)) res)) (test-end "basic packets") ;;====================================================================== ;; Sqlite and postgresql based queue of pkts ;;====================================================================== (test-begin "pkt queue") (define db #f) (test #f 'sqlite3 (let ((dbh (open-queue-db "." "queue.db"))) (set! db dbh) (dbi:db-dbtype dbh))) (test #f (cdr pkt-example) (begin (add-to-queue db (cdr pkt-example)(car pkt-example) 'basic #f 0) (lookup-by-uuid db (car pkt-example) 0))) (test #f (cdr pkt-example) (lookup-by-id db 1)) (test #f 1 (length (find-pkts db '(basic) '()))) (test-end "pkt queue") ;;====================================================================== ;; Process groups of pkts ;;====================================================================== (test-begin "lists of packets") (test #f '((apkt . #f) (id . 1) (group-id . 2) (uuid . 3) (parent . 4) (pkt-type . 5)) ;; ((id . 1) (group-id . 2) (uuid . 3) (parent . 4) (pkt-type . 5)) (dblst->dpkts '(1 2 3 4 5))) (test #f '(((apkt (Z . "263eb3b6193de7fe65b1ded5bcda513e8b4d6b84") (b . "C") (a . "A") (D . "1486332719.0") (C . " C++")) (id . 1) (group-id . 0) (uuid . "263eb3b6193de7fe65b1ded5bcda513e8b4d6b84") (parent . "") (pkt-type . "basic") (pkt . "CC C++\nD 1486332719.0\na A\nb C\nZ 263eb3b6193de7fe65b1ded5bcda513e8b4d6b84") (processed . 0))) ;; '(((apkt (Z . "263eb3b6193de7fe65b1ded5bcda513e8b4d6b84") (b . "C") (a . "A") (D . "1486332719.0") (C . " C++")) (id . 1) (group-id . 0) (uuid . "263eb3b6193de7fe65b1ded5bcda513e8b4d6b84") (parent . "") (pkt-type . "basic") (pkt . "CC C++\nD 1486332719.0\na A\nb C\nZ 263eb3b6193de7fe65b1ded5bcda513e8b4d6b84"))) ;; '(((id . 1) (group-id . 0) (uuid . "263eb3b6193de7fe65b1ded5bcda513e8b4d6b84") (parent . "") (pkt-type . "basic") (pkt . "CC C++\nD 1486332719.0\na A\nb C\nZ 263eb3b6193de7fe65b1ded5bcda513e8b4d6b84"))) (get-dpkts db '(basic) 0 #f)) (test #f '(((apkt (Z . "263eb3b6193de7fe65b1ded5bcda513e8b4d6b84") (b . "C") (a . "A") (D . "1486332719.0") (C . " C++")) (id . 1) (group-id . 0) (uuid . "263eb3b6193de7fe65b1ded5bcda513e8b4d6b84") (parent . "") (pkt-type . "basic") (pkt . "CC C++\nD 1486332719.0\na A\nb C\nZ 263eb3b6193de7fe65b1ded5bcda513e8b4d6b84") (processed . 0))) ;; '(((apkt (Z . "263eb3b6193de7fe65b1ded5bcda513e8b4d6b84") (b . "C") (a . "A") (D . "1486332719.0") (C . " C++")) (id . 1) (group-id . 0) (uuid . "263eb3b6193de7fe65b1ded5bcda513e8b4d6b84") (parent . "") (pkt-type . "basic") (pkt . "CC C++\nD 1486332719.0\na A\nb C\nZ 263eb3b6193de7fe65b1ded5bcda513e8b4d6b84"))) ;; '(((id . 1) (group-id . 0) (uuid . "263eb3b6193de7fe65b1ded5bcda513e8b4d6b84") (parent . "") (pkt-type . "basic") (pkt . "CC C++\nD 1486332719.0\na A\nb C\nZ 263eb3b6193de7fe65b1ded5bcda513e8b4d6b84"))) (get-not-processed-pkts db 0 'basic 1000 0)) (test-end "lists of packets") (test-begin "pkts as alists") (define pktspec '((posting . ((title . t) ;; NOTE: same as ((posting (title . t)(url . u)(blub . b)) ... (url . u) (blurb . b))) (comment . ((comment . c) (score . s))) (basic . ((b-field . b) (a-field . a))))) (define pktlst (find-pkts db '(basic) '())) (define dpkt (car pktlst)) (test #f "A" (get-value 'a-field dpkt pktspec)) (test #f "C" (alist-ref 'b-field (dpkt->alist dpkt pktspec))) (define basic-spec '((nada (foo . b)(bar . f))(basic (foo . f)(bar . b)))) (define test-pkt '((foo . "fooval")(bar . "barval"))) (let*-values (((u p) (alist->pkt test-pkt basic-spec ptype: 'basic)) ((apkt) (pkt->alist p)) ((bpkt) (pkt->alist p pktspec: basic-spec))) (test #f "fooval" (alist-ref 'f apkt)) (test #f "fooval" (alist-ref 'foo bpkt)) (test #f #f (alist-ref 'f bpkt))) (test-end "pkts as alists") (test-begin "descendents and ancestors") (define (get-uuid pkt)(alist-ref 'uuid pkt)) ;; add a child to 263e (let-values (((uuid pkt) (construct-pkt 'x "X" 'y "Y" 'P "263eb3b6193de7fe65b1ded5bcda513e8b4d6b84" 'D "1486332719.0"))) (add-to-queue db pkt uuid 'basic "263eb3b6193de7fe65b1ded5bcda513e8b4d6b84" 0)) (test #f '("263eb3b6193de7fe65b1ded5bcda513e8b4d6b84" "818fe30988c9673441b8f203972a8bda6af682f8") (map (lambda (x)(alist-ref 'uuid x)) (get-descendents db 0 "263eb3b6193de7fe65b1ded5bcda513e8b4d6b84"))) (test #f '("263eb3b6193de7fe65b1ded5bcda513e8b4d6b84" "818fe30988c9673441b8f203972a8bda6af682f8") (map (lambda (x)(alist-ref 'uuid x)) (get-ancestors db 0 "818fe30988c9673441b8f203972a8bda6af682f8"))) (test-end "descendents and ancestors") (test-end "pkts and pkt archives") (test-begin "pktsdb") (define spec '((tests (testname n TEXT) (testpath p TEXT) (duration d INTEGER)))) ;; (define pktsdb (make-pktdb)) ;; (pktdb-pktsdb-spec-set! pktsdb spec) (define pktsdb #f) (test #f #t (dbi:database? (let ((pdb (pktsdb-open "test.db" spec))) (set! pktsdb pdb) (pktdb-conn pdb)))) ;; (pp (pktdb-pktspec pktsdb)) (test #f #t (pktsdb-add-record pktsdb 'tests '((testname . "test1")))) (pktsdb-close pktsdb) (test-end "pktsdb") |
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 [f9dfbe5500].
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 201 202 203 204 205 206 207 208 209 210 211 | (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 exn (begin (debug:print 0 *default-log-port* "failed to identify if process " pid ", on host " host " is alive. exn=" exn) #f) ;; anything goes wrong - assume the process in NOT running. (with-input-from-pipe cmd (lambda () (let loop ((inl (read-line))) (if (eof-object? inl) #f (let* ((clean-str (string-substitute "^[^\\d]*([0-9]+)[^\\d]*$" "\\1" inl)) |
︙ | ︙ |
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 |
Added reindent.el version [9e7e328bbc].
> > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | ; Indenting module body code at column 0 (defun scheme-module-indent (state indent-point normal-indent) 0) (put 'module 'scheme-indent-function 'scheme-module-indent) (put 'and-let* 'scheme-indent-function 1) (put 'parameterize 'scheme-indent-function 1) (put 'handle-exceptions 'scheme-indent-function 1) (put 'when 'scheme-indent-function 1) (put 'unless 'scheme-indent-function 1) (put 'match 'scheme-indent-function 1) (put 'let-values 'scheme-indent-function 1) ;; do the work (indent-region (point-min) (point-max) nil) |
Deleted remotediff-nmsg.scm version [50100144d4].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Modified rmt.scm from [2cee428d81] to [9f2b8feba3].
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 | ;;====================================================================== ;; Copyright 2006-2017, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more 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") (include "db_records.scm") ;; (declare (uses rmtmod)) ;; (import rmtmod) ;; ;; THESE ARE ALL CALLED ON THE CLIENT SIDE!!! ;; ;; generate entries for ~/.megatestrc with the following ;; |
︙ | ︙ | |||
42 43 44 45 46 47 48 49 50 51 52 53 54 | cinfo (if (server:check-if-running areapath) (client:setup areapath) #f)))) (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*) | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > | < < < < < < < < < < > > > | | | | | > > > > | | | | | | > > | | | > > > | | > > > | < < < < | | > > > > > > | | > > > > > > > | | | | > > > > | > > > | | > > > | | | | | | > > > | < > > > > | > > > > > > | > > > > | | | | | | > > > > > > > | | | | | | | > | > > > > > > > > > > | < > | > | < < < < < < < < < < < < | | | < > < < < < > > > > | | | | | | < < < < < < < < | < < > > > | > > > > > > | 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 | cinfo (if (server:check-if-running areapath) (client:setup areapath) #f)))) (define *send-receive-mutex* (make-mutex)) ;; should have separate mutex per run-id (define *rmt-query-last-call-time* 0) (define *rmt-query-last-rest-time* 0) ;; last time there was at least a 1/2 second rest - giving other processes access to the db ;; NOTE: This query rest algorythm will not adapt to long query times. REDESIGN NEEDED. TODO. FIXME. ;; (define (rmt:query-rest cmd rid params) (let* ((now (current-milliseconds))) (cond ((> (- now *rmt-query-last-call-time*) 100) ;; it's been a while since last query - no need to rest (set! *rmt-query-last-rest-time* now) (set! *rmt-query-last-call-time* now)) ((> (- now *rmt-query-last-rest-time*) 5000) ;; no natural rests have happened (debug:print 0 *default-log-port* "query rest needed. blocking for 0.1 second. cmd="cmd", run id="rid", params="params) (thread-sleep! 0.1) ;; force a rest of a half second (set! *rmt-query-last-rest-time* now) (set! *rmt-query-last-call-time* now)) (else ;; sufficient rests have occurred, just record the last query time (set! *rmt-query-last-call-time* now))))) ;; 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 (not (equal? (configf:lookup *configdat* "setup" "query-rest") "no")) (rmt:query-rest cmd rid 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:print-db-stats) (let ((fmtstr "~40a~7-d~9-d~20,2-f")) ;; "~20,2-f" (debug:print 18 *default-log-port* "DB Stats\n========") (debug:print 18 *default-log-port* (format #f "~40a~8a~10a~10a" "Cmd" "Count" "TotTime" "Avg")) (for-each (lambda (cmd) (let ((cmd-dat (hash-table-ref *db-stats* cmd))) |
︙ | ︙ | |||
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)) | | | | | | | > > | | < < < < < < < < < < < | 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 | (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) ", exn=" 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 '()))) (success (common:safe-vector-ref resdat 0 #f)) ;; (vector-ref resdat 0)) (res (common:safe-vector-ref resdat 1 #f)) ;; (vector-ref resdat 1)) (duration (- (current-milliseconds) start))) (if (and read-only qry-is-write) (debug:print 0 *default-log-port* "ERROR: attempt to write to read-only database ignored. cmd=" cmd)) (if (not success) (if (> remretries 0) (begin (debug:print-error 0 *default-log-port* "local query failed. Trying again.") (thread-sleep! (/ (random 5000) 1000)) ;; some random delay (rmt:open-qry-close-locally cmd run-id params remretries: (- remretries 1))) (begin (debug:print-error 0 *default-log-port* "too many retries in rmt:open-qry-close-locally, giving up") #f)) (begin ;; (rmt:update-db-stats run-id cmd params duration) ;; mark this run as dirty if this was a write, the watchdog is responsible for syncing it (if qry-is-write (let ((start-time (current-seconds))) (mutex-lock! *db-multi-sync-mutex*) (set! *db-last-access* start-time) ;; THIS IS PROBABLY USELESS? (we are on a client) (mutex-unlock! *db-multi-sync-mutex*))))) res)) (define (rmt:send-receive-no-auto-client-setup connection-info cmd run-id params) (let* ((run-id (if run-id run-id 0)) (res (handle-exceptions exn (begin (print "transport failed. exn=" exn) #f) (http-transport:client-api-send-receive run-id connection-info cmd params)))) (if (and res (vector-ref res 0)) (vector-ref res 1) ;;; YES!! THIS IS CORRECT!! CHANGE IT HERE, THEN CHANGE rmt:send-receive ALSO!!! #f))) ;;====================================================================== ;; ;; A C T U A L A P I C A L L S ;; ;;====================================================================== ;;====================================================================== |
︙ | ︙ | |||
377 378 379 380 381 382 383 | (rmt:send-receive 'general-call run-id (append (list stmtname run-id) params))) ;; given a hostname, return a pair of cpu load and update time representing latest intelligence from tests running on that host (define (rmt:get-latest-host-load hostname) (rmt:send-receive 'get-latest-host-load 0 (list hostname))) | < < < > > > > > > > > > | 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 | (rmt:send-receive 'general-call run-id (append (list stmtname run-id) params))) ;; given a hostname, return a pair of cpu load and update time representing latest intelligence from tests running on that host (define (rmt:get-latest-host-load hostname) (rmt:send-receive 'get-latest-host-load 0 (list hostname))) (define (rmt:sdb-qry qry val run-id) ;; 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)) ) (define (rmt:drop-all-triggers) (rmt:send-receive 'drop-all-triggers #f '())) (define (rmt:create-all-triggers) (rmt:send-receive 'create-all-triggers #f '())) ;;====================================================================== ;; T E S T M E T A ;;====================================================================== (define (rmt:get-tests-tags) (rmt:send-receive 'get-tests-tags #f '())) |
︙ | ︙ | |||
432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 | 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) (rmt:general-call 'register-test run-id run-id test-name item-path)) (define (rmt:get-test-id run-id testname item-path) (rmt:send-receive 'get-test-id run-id (list run-id testname item-path))) | > > > > | | > > > > > > > > > > > > > > > > > | 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 | 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) (rmt:general-call 'register-test run-id run-id test-name item-path)) (define (rmt:get-test-id run-id testname item-path) (rmt:send-receive 'get-test-id run-id (list run-id testname item-path))) ;; run-id is NOT used - but it will be! ;; (define (rmt:get-test-info-by-id run-id test-id) (if (number? test-id) (let* ((testdat (rmt:send-receive 'get-test-info-by-id run-id (list run-id test-id))) (trundir (vector-ref testdat 10)) (trundatf (conc trundir"/.mt_data/test-run.dat"))) ;; now we can update a couple fields from the filesystem (handle-exceptions exn (begin (debug:print-info 0 *default-log-port* "Could not update testdat record from "trundatf", exn=" exn) #f) (if (and trundir (file-exists? trundatf)) (let* ((duration (vector-ref testdat 12)) ;; (db:test-get-run_duration testdat)) (event-time (vector-ref testdat 5)) ;; (db:test-get-event_time testdat)) (last-touch (file-modification-time trundatf)) (new-duration (max duration (- last-touch event-time)))) (vector-set! testdat 12 new-duration)))) #;(db:test-set-run_duration! testdat (max duration (- last-touch event-time))) testdat) (begin (debug:print 0 *default-log-port* "WARNING: Bad data handed to rmt:get-test-info-by-id run-id=" run-id ", test-id=" test-id) (print-call-chain (current-error-port)) #f))) (define (rmt:test-get-rundir-from-test-id run-id test-id) (rmt:send-receive 'test-get-rundir-from-test-id run-id (list run-id test-id))) |
︙ | ︙ | |||
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) | | | | | | | > > > > > > | 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 | (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)) ;; '()))) (define (rmt:get-tests-for-run-state-status run-id testpatt last-update) (rmt:send-receive 'get-tests-for-run-state-status run-id (list run-id testpatt last-update))) ;; 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))) |
︙ | ︙ | |||
529 530 531 532 533 534 535 | ;; (apply append (map (lambda (run-id) ;; (rmt:send-receive 'get-tests-for-run-mindata run-id (list run-ids testpatt states status not-in))) ;; run-id-list)))) (define (rmt:delete-test-records run-id test-id) (rmt:send-receive 'delete-test-records run-id (list run-id test-id))) | < < < < < | 654 655 656 657 658 659 660 661 662 663 664 665 666 667 | ;; (apply append (map (lambda (run-id) ;; (rmt:send-receive 'get-tests-for-run-mindata run-id (list run-ids testpatt states status not-in))) ;; run-id-list)))) (define (rmt:delete-test-records run-id test-id) (rmt:send-receive 'delete-test-records run-id (list run-id test-id))) (define (rmt:test-set-state-status run-id test-id state status msg) (rmt:send-receive 'test-set-state-status run-id (list run-id test-id state status msg))) (define (rmt:test-toplevel-num-items run-id test-name) (rmt:send-receive 'test-toplevel-num-items run-id (list run-id test-name))) ;; (define (rmt:get-previous-test-run-record run-id test-name item-path) |
︙ | ︙ | |||
576 577 578 579 580 581 582 | (define (rmt:test-get-paths-matching-keynames-target-new keynames target res testpatt statepatt statuspatt runname) (let ((run-ids (rmt:get-run-ids-matching-target keynames target res runname testpatt statepatt statuspatt))) (apply append (map (lambda (run-id) (rmt:send-receive 'test-get-paths-matching-keynames-target-new run-id (list run-id keynames target res testpatt statepatt statuspatt runname))) run-ids)))) | < < < > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | > > > > > > > > > | 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 | (define (rmt:test-get-paths-matching-keynames-target-new keynames target res testpatt statepatt statuspatt runname) (let ((run-ids (rmt:get-run-ids-matching-target keynames target res runname testpatt statepatt statuspatt))) (apply append (map (lambda (run-id) (rmt:send-receive 'test-get-paths-matching-keynames-target-new run-id (list run-id keynames target res testpatt statepatt statuspatt runname))) run-ids)))) (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) (if (number? run-id) (rmt:send-receive 'get-count-tests-running-for-run-id run-id (list run-id)) 0)) (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 last-update) (rmt:send-receive 'simple-get-runs #f (list runpatt count offset target last-update))) (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-tesdata-on-repilcate-db old-lt new-lt) (rmt:send-receive 'update-tesdata-on-repilcate-db #f (list old-lt new-lt))) (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))) (define (rmt:get-var varname) (rmt:send-receive 'get-var #f (list varname))) (define (rmt:del-var varname) (rmt:send-receive 'del-var #f (list varname))) (define (rmt:set-var varname value) (rmt:send-receive 'set-var #f (list varname value))) (define (rmt:inc-var varname) (rmt:send-receive 'inc-var #f (list varname))) (define (rmt:dec-var varname) (rmt:send-receive 'dec-var #f (list varname))) (define (rmt:add-var varname value) (rmt:send-receive 'add-var #f (list varname value))) ;;====================================================================== ;; M U L T I R U N Q U E R I E S ;;====================================================================== ;; Need to move this to multi-run section and make associated changes (define (rmt:find-and-mark-incomplete-all-runs #!key (ovr-deadtime #f)) (let ((run-ids (rmt:get-all-run-ids))) |
︙ | ︙ | |||
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))) | > > > > > > > | < | | > > | 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 | (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))) | > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | (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))) (define (rmt:no-sync-add-job host-type vars-list exekey cmdline) (rmt:send-receive 'no-sync-add-job #f `(,host-type ,vars-list ,exekey ,cmdline))) (define (rmt:no-sync-take-job host-type) (rmt:send-receive 'no-sync-take-job #f `(,host-type))) (define (rmt:no-sync-job-records-clean) (rmt:set-receive 'no-sync-job-records-clean #f '())) ;;====================================================================== ;; 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))) | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | (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 [6b720dfd33].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 2017, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more 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)) (declare (uses apimod)) ;; (declare (uses apimod.import)) (declare (uses ulex)) ;; (include "ulex/ulex.scm") (module rmtmod * (import scheme chicken data-structures extras) (import (prefix sqlite3 sqlite3:) posix typed-records srfi-18) (import (prefix commonmod cmod:)) (import apimod) (import (prefix ulex ulex:)) (defstruct alldat (areapath #f) (ulexdat #f) ) ;; return the handle struct for sending queries to a specific database ;; - initializes the connection object if this is the first access ;; - finds the "captain" and asks who to talk to for the given dbfname ;; - establishes the connection to the current dbowner ;; #;(define (rmt:connect alldat dbfname dbtype) (let* ((ulexdat (or (alldat-ulexdat alldat) (rmt:setup-ulex alldat)))) (ulex:connect ulexdat dbfname dbtype))) ;; setup the remote calls #;(define (rmt:setup-ulex alldat) (let* ((udata (ulex:setup))) ;; establish connection to ulex (alldat-ulexdat-set! alldat udata) ;; register all needed procs (ulex:register-handler udata 'ping cmod:get-full-version) ;; override ping with get-full-version (ulex:register-handler udata 'login cmod:get-full-version) ;; force setup of the connection (ulex:register-handler udata 'execute api:execute-requests) udata)) ;; set up a connection to the current owner of the dbfile associated with rid ;; then send the query to that dbfile owner and wait for a response. ;; #;(define (rmt:send-receive alldat cmd rid params #!key (attemptnum 1)(area-dat #f)) ;; start attemptnum at 1 so the modulo below works as expected (let* (;; (alldat *alldat*) (areapath (alldat-areapath alldat)) (dbtype (if (or (not rid)(< rid 1)) ;; this is the criteria for "main.db" "main" "runs")) (dbfname (if (equal? dbtype "main") "main.db" (conc rid ".db"))) (dbfile (conc areapath "/.db/" dbfname)) (ulexconn (rmt:connect alldat dbfname dbtype)) ;; ulexconn is our new *runremote*, it is a dbowner struct < pdat lastrefresh > (udata (alldat-ulexdat alldat))) (ulex:remote-request udata ulexconn 'immediate dbfile 'execute rid params))) ;; need to call this on the other side ;; (api:execute-requests dbstruct-local (vector (symbol->string cmd) params)))) #;(with-input-from-string (ulex:remote-request udata ulexconn 'immediate dbfile 'execute rid (with-output-to-string (lambda ()(serialize params)))) (lambda ()(deserialize))) ) |
Deleted rpc-transport.scm version [f2b0cd0198].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
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 [10c892ad0a].
|
| < | > | > > > > | | > | > > | | | < | > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | ;; 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 matchable) (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") ;; (include "debugger.scm") ;; use this struct to facilitate refactoring ;; (defstruct runs:dat reglen regfull runname max-concurrent-jobs run-id test-patts required-tests test-registry registry-mutex flags keyvals run-info all-tests-registry ;; stores results from last runs:can-run-more-tests (can-run-more-tests #f) ;; (list can-run-more-flag num-running num-running-in-jobgroup max-concurrent-jobs job-group-limit) ((can-run-more-tests-count 0) : fixnum) (last-fuel-check 0) ;; time when we last checked fuel (beginning-of-time (current-seconds)) (load-mgmt-function #f) (wait-for-jobs-function #f) (last-load-check-time 0) (last-jobs-check-time 0) ) (defstruct runs:testdat hed tal reg reruns test-record test-name item-path jobgroup waitons testmode newtal itemmaps prereqs-not-met) (module runsmod ( runs:wait-if-seen-recently ) (import scheme chicken data-structures extras files) (import posix typed-records srfi-18 srfi-69 md5 message-digest regex srfi-1) (define *last-seen-ht* (make-hash-table)) (define (runs:wait-if-seen-recently wait-until . keys) (let* ((full-key (string-intersperse keys "-")) (last-seen (hash-table-ref/default *last-seen-ht* full-key 0)) (now (current-seconds)) (delta (- now last-seen)) (needed (if (< delta wait-until) 0 (- wait-until delta)))) (if (> needed 0)(thread-sleep! needed)) (hash-table-set! *last-seen-ht* full-key (current-seconds)) needed)) ) (import runsmod) ;; look in the $MT_RUN_AREA_HOME/.softlocks directory for key-host-pid.softlock files ;; - remove any that are over 3600 seconds old ;; - if there are any that are younger than 10 seconds ;; * sleep 10 seconds ;; * touch my key-host-pid.softlock file ;; * return ;; - if there are no files younger than 10 seconds ;; * touch my key-host-pid.softlock file ;; * return ;; (define (runs:wait-on-softlock rdat key) (if (not (and *toppath* (file-exists? *toppath*))) ;; don't seem to have toppath yet (debug:print-info 0 *default-log-port* "Can't create softlocks - don't see MTRAH yet.") (let* ((softlocks-dir (conc *toppath* "/.softlocks"))) (if (not (file-exists? softlocks-dir)) (create-directory softlocks-dir #t)) (let* ((my-lock-file (conc softlocks-dir "/" key "-" (get-host-name) "-" (current-process-id) ".softlock")) (lock-files (filter (lambda (x) (not (equal? x my-lock-file))) (glob (conc softlocks-dir "/" key "*.softlock")))) (fresh-locks (any (lambda (x) ;; do we have any locks younger than 10 seconds (let* ((mod-time (file-modification-time x)) (age (- (current-seconds) mod-time))) (cond ((> age 3600) ;; too old to keep, remove it (delete-file* x) #f) ((< age 10) #t) (else #f)))) lock-files))) (if fresh-locks (begin (if (runs:lownoise "runners-softlock-wait" 360) (debug:print-info 0 *default-log-port* "Other runners in flight, giving up some time...")) (thread-sleep! 2)) (begin (if (runs:lownoise "runners-softlock-nowait" 360) (debug:print-info 0 *default-log-port* "No runners in flight, updating softlock")) (let* ((ouf (open-output-file my-lock-file))) (with-output-to-port ouf (lambda ()(print (current-seconds)))) (close-output-port ouf)))) (runs:dat-last-fuel-check-set! rdat (current-seconds)))))) ;; Fourth try, do accounting through time ;; (define (runs:parallel-runners-mgmt rdat) (let ((time-to-check (configf:lookup-number *configdat* "runners" "time-to-check" default: 10)) ;; 28 (time-to-wait (configf:lookup-number *configdat* "runners" "time-to-wait" default: 30)) (now-time (current-seconds))) (if (> (- now-time (runs:dat-last-fuel-check rdat)) time-to-check) ;; time to check (runs:wait-on-softlock rdat "runners")))) ;; To test parallel-runners management start a repl: ;; megatest -repl ;; then run: ;; (runs:test-parallel-runners 60) ;; (define (runs:test-parallel-runners duration #!optional (proc #f)) (let* ((rdat (make-runs:dat)) (rtime 0) (startt (current-seconds)) (endt (+ startt duration))) ((or proc runs:parallel-runners-mgmt) rdat) (let loop () (let* ((wstart (current-seconds))) (if (< wstart endt) (let* ((work-time (random 10))) #;(debug:print-info 0 *default-log-port* "working for " work-time " seconds. Total work: " rtime ", elapsed time: " (- wstart startt)) (thread-sleep! work-time) (set! rtime (+ rtime work-time)) ((or proc runs:parallel-runners-mgmt) rdat) (loop))))) (let* ((done-time (current-seconds))) (debug:print-info 0 *default-log-port* "DONE: rtime=" rtime ", elapsed time=" (- done-time startt) ", ratio=" (/ rtime (- done-time startt)))))) (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"))) |
︙ | ︙ | |||
92 93 94 95 96 97 98 | (let fatal-loop ((count 0)) (handle-exceptions 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. | | > | | > > | > > > > > > > > > | 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 | (let fatal-loop ((count 0)) (handle-exceptions 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 ", exn=" exn) (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)) | > | | | < < | | < < < > > | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > | | | | | 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 | (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)) (if (runs:dat-load-mgmt-function runsdat)((runs:dat-load-mgmt-function runsdat))) (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 (configf:lookup-number *configdat* "jobgroups" jobgroup))) (if (and (number? num-running) ;; checking for number - had a crash where a non-number was returned. Not sure why. (number? num-running-in-jobgroup) ;; probably can remove this when rmt switches away from http. (> (+ 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 ", exn=" exn) #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) ", exn=" 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 ", exn=" exn) #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) ", exn=" 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.")))))) (define (runs:rerun-hook test-id new-test-path testdat rerunlst) (let* ((rerun-hook (configf:lookup *configdat* "runs" "rerun-hook")) (log-dir (conc *toppath* "/reruns/logs")) (target (getenv "MT_TARGET")) (runname (common:args-get-runname)) (rundir (db:test-get-rundir testdat)) (tarfiledir (conc *toppath* "/reruns")) (status (db:test-get-status testdat)) (comment (conc "\"" (db:test-get-comment testdat) "\"" )) (testname (db:test-get-testname testdat)) (itempath (db:test-get-item-path testdat)) (file-body (conc status "-" (string-translate target "/" "-") "-" runname "." testname (if (not (string=? itempath "")) (conc "." (string-translate itempath "/" "-")) ""))) (log-file (conc file-body ".log")) ;; (log-file (conc status "-" (string-translate target "/" "-") "-" runname "." testname (if (not (string=? itempath "")) (conc "." (string-translate itempath "/" "-")) "") ".log")) (full-log-fname (conc log-dir "/" log-file)) (tarfilename (conc file-body ".tar")) ;; (tarfilename (conc status "." (string-translate target "/" "-") "." runname "." testname (if (not (string=? itempath "")) (conc "." (string-translate itempath "/" "-")) "") ".tar")) ) (if rerun-hook (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 ", exn=" exn) #f) (create-directory log-dir #t) #t) #t)) (start-time (current-seconds)) (actual-logf (if use-log-dir full-log-fname log-file)) (sys-call-text (conc rerun-hook " " tarfilename " " rundir " " actual-logf " " runname " " tarfiledir " " status " " target " " comment " " testname " " itempath " >> " actual-logf " 2>&1")) ) (debug:print 2 *default-log-port* "Found rerun-hook in config:" rerun-hook) (handle-exceptions exn (begin (print-call-chain *default-log-port*) (debug:print 0 *default-log-port* "Message: " ((condition-property-accessor 'exn 'message) exn) ", exn=" exn) (debug:print 0 *default-log-port* "ERROR: failed to run rerun-hook " rerun-hook ", check the log " log-file)) (debug:print-info 0 *default-log-port* "running rerun-hook: \"" rerun-hook "\", log is " actual-logf) ;; call the hook (debug:print-info 0 *default-log-port* "Calling rerun-hook for " test-id new-test-path testdat rerunlst) (debug:print-info 0 *default-log-port* "rerun hook: " rerun-hook) (debug:print-info 0 *default-log-port* "tarfilename: " tarfilename) (debug:print-info 0 *default-log-port* "rundir: " rundir) (debug:print-info 0 *default-log-port* "actual-logf: " actual-logf) (debug:print-info 0 *default-log-port* "runname: " runname) (debug:print-info 0 *default-log-port* "sys-call-text: " sys-call-text) (system sys-call-text) (debug:print-info 0 *default-log-port* "rerun-hook \"" rerun-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))) (define *find-and-mark-incomplete-last-run* (make-hash-table)) ;;====================================================================== ;; 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) (cache-files (launch:get-cache-file-paths #f (common:get-toppath *toppath* ) target)) (runstart-time (current-seconds))) ;; 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)) | | | | | > > > > > > > > > > > > > > > < | 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 | (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!? ;; ;;====================================================================== | > > > > > > > > > > > > > > > | > | > > > > > > > > > | | | | | | | > | | > > > > > > > > > > | | < < | < < | > | | > | | | > > > | | | < < > | < < < < < < < < < < < < < | | | > > > | > > < < > > > > > > > | | > > > > > > > | | | | > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > | > < | < < > > > > > | > > > > | > | > | 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 | (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 launched 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) (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 ", exn=" exn) ;; lets run this only if a run has been NOT seen for more than 900 seconds (if (> (- (current-seconds)(hash-table-ref/default *find-and-mark-incomplete-last-run* run-id 0)) 900) (begin (rmt:find-and-mark-incomplete run-id #f) (hash-table-set! *find-and-mark-incomplete-last-run* run-id (current-seconds))) )))) ;; 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! th2) (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 (launch:cache-files-changed? cache-files runstart-time) (begin ;; force a start-over (launch:setup force-reread: #t) (runs:run-tests target runname test-patts user flags run-count: 0))) ;; 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" "ABORT,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 ""))) | | < | < | | > | > > > > | < | < | | > | > > | < < < | > | > > > | > < < < < | 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 | (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) ", going to wait 60 sec.") ;; ;; 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) CHECKTHIS!!! ;; No runsdat, can't do this yet ;; (if (runs:dat-load-mgmt-function runsdat)((runs:dat-load-mgmt-function runsdat))) ;; (thread-sleep! 5) ;; 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)) | > > > | 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 | (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)) | | < | > | > > > > > > > > > > > > | > > > > > > | < | < < | 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 | (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)) ;; 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 ;; (if (runs:dat-load-mgmt-function runsdat) ((runs:dat-load-mgmt-function runsdat)) (runs:dat-load-mgmt-function-set! runsdat (lambda () ;; jobtools maxload is useful for where the full Megatest run is done on one machine (if (and (not (common:on-homehost?)) 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)))))) (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) | | | 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 | (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))) |
︙ | ︙ | |||
864 865 866 867 868 869 870 | ;; If no resources are available just kill time and loop again ;; ((not have-resources) ;; simply try again after waiting a second (if (runs:lownoise "no resources" 60) (debug:print-info 1 *default-log-port* "no resources to run new tests, waiting ...")) ;; Have gone back and forth on this but db starvation is an issue. ;; wait one second before looking again to run jobs. | | | < < < | < | < < > > | > > > | | | > > > > | > < | < < < | > | < | < < | | < < < < | < < | | | > | < | | | | > > | | | < | < > > | | 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 | ;; If no resources are available just kill time and loop again ;; ((not have-resources) ;; simply try again after waiting a second (if (runs:lownoise "no resources" 60) (debug:print-info 1 *default-log-port* "no resources to run new tests, waiting ...")) ;; Have gone back and forth on this but db starvation is an issue. ;; wait one second before looking again to run jobs. (thread-sleep! 1) ;; changed back to 1 from 0.25 ;; could have done hed tal here but doing car/cdr of newtal to rotate tests (list (car newtal)(cdr newtal) reg reruns)) ;; This is the final stage, everything is in place so launch the test ;; ((and have-resources (or (null? prereqs-not-met) (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)) (run:test run-id run-info keyvals runname test-record flags #f test-registry all-tests-registry runsdat testdat) (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) ;; hed should be dropped at this time #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 ;; a message and drop hed from the items to be processed. ;; (runs:mixed-list-testname-and-testrec->list-of-strings prereqs-not-met) (if (and (not (null? prereqs-not-met)) (runs:lownoise (conc "waiting on tests " prereqs-not-met hed) 60)) (debug:print-info 1 *default-log-port* "waiting on tests; " (string-intersperse (runs:mixed-list-testname-and-testrec->list-of-strings prereqs-not-met) ", "))) (if (or (null? fails) (member 'toplevel testmode)) (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...")) ;; (if (runs:dat-load-mgmt-function runsdat)((runs:dat-load-mgmt-function runsdat))) (thread-sleep! 5) (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 ) | | | | > > | | | | | | | | > > > > > > > > | 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 | 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)) (last-update (runs:gendat-inc-results-last-update *runs:general-data*))) (if (> (- curr-sec last-update) 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) last-update '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) '()))))) (runs:gendat-inc-results-last-update-set! *runs:general-data* (- curr-sec 1)) (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 |
︙ | ︙ | |||
1079 1080 1081 1082 1083 1084 1085 | state status dtime (seconds->hr-min-sec duration) (conc "lt/" target "/" runname "/" test-name (if (string-null? item-path) "" (conc "/" item-path)))) (hash-table-set! (runs:gendat-inc-results *runs:general-data*) (conc run-id "," test-id) testdat))))) testsdat))) | > > | > > > > > > > > > | | | | | | | | < < < | | | | > | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | > > > > > > | | < > > > > > > > > > > > > > > > > > > > > | < < < < < | | | | 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 | state status dtime (seconds->hr-min-sec duration) (conc "lt/" target "/" runname "/" test-name (if (string-null? item-path) "" (conc "/" item-path)))) (hash-table-set! (runs:gendat-inc-results *runs:general-data*) (conc run-id "," test-id) testdat))))) testsdat))) ;; I don't think this should be here? -- Matt #;(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)) (define (runs:pretty-long-list lst) (if (> (length lst) 8)(append (take lst 3)(list "...")) lst)) ;;====================================================================== ;; 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)) (misc-data (make-hash-table)) ;; use as needed (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) )) ;; WAIT FOR TIME ON TIGHT LOOP (if (< (- (current-milliseconds)(hash-table-ref/default misc-data "tight-loop-last-time" 0)) 100) ;; less than 1/100 second since came through the loop (thread-sleep! 0.1)) ;; wait a 1/100 seconds (hash-table-set! misc-data "tight-loop-last-time" (current-milliseconds)) ;; (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) (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)))) | | < > > > | < | > | > | 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 | (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: " (runs:pretty-long-list 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) ) ;; (runs:parallel-runners-mgmt runsdat) ;; 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 | 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)) | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > | | > | | | | | | | | > > | > > > > > > > | | | | | | | | | | | | | | | > | | | | | > > > | > > > > > > > > | > | > > | < > | > | | < > | > > > | | | > > > | | | 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 | 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)) ;; gonna try a strategy change here. ;; ;; check if can run more tests. if yes, continue, if no, rest until can run more ;; look at the test jobgroup and tot jobs running ;; ;; NOTE: This does NOT actually gate here, only captures the proc to be called later ;; (if (not (runs:dat-wait-for-jobs-function runsdat)) (runs:dat-wait-for-jobs-function-set! runsdat (lambda (testdat-in) (let* ((jobgroup (runs:testdat-jobgroup testdat-in)) (can-run-more-tests (runs:dat-can-run-more-tests runsdat)) (last-jobs-check-time (runs:dat-last-jobs-check-time runsdat)) (should-check-jobs (match can-run-more-tests ((can-run-more-flag num-running nr-in-jobgroup max-concurrent-jobs . params) (if (< (- max-concurrent-jobs num-running) 25) (begin (debug:print-info 0 *default-log-port* "less than 20 jobs headroom, ("max-concurrent-jobs "-"num-running")>20. Forcing prelaunch check.") #t) #f)) (else #f)))) ;; no record yet (if should-check-jobs (let loop-can-run-more ((res (runs:can-run-more-tests runsdat run-id jobgroup max-concurrent-jobs)) (remtries 1440)) ;; we can wait for up to two hours for jobs to get done (match res ((run-more num-running . rem) (if (or run-more (< remtries 1)) (begin (if (runs:lownoise "num-running" 30) (debug:print-info 0 *default-log-port* "Have "num-running" tests of max " max-concurrent-jobs)) (runs:dat-can-run-more-tests-set! runsdat res)) ;; capture the result and then drop through (begin (if (runs:lownoise "num-running" 10) (debug:print-info 0 *default-log-port* "Can't run more tests, have "num-running" tests of " max-concurrent-jobs " allowed.")) (thread-sleep! 5) ;; if we've hit max concurrent jobs take a breather, nb// make this configurable ;; wait for load here (if (runs:dat-load-mgmt-function runsdat)((runs:dat-load-mgmt-function runsdat))) (loop-can-run-more (runs:can-run-more-tests runsdat run-id jobgroup max-concurrent-jobs) (- remtries 1))))))) ))))) ;; I'm not clear on why prereqs are gathered here TODO: verfiy this is needed (let ((waited (runs:wait-if-seen-recently 5 "prereqs-not-met" hed item-path))) ;; if we've been down this path in the past 5 seconds - wait out the difference (if (> waited 0)(debug:print 0 *default-log-port* "Waited for prereqs-not-met-"hed"-"item-path" for " waited "seconds."))) (runs:testdat-prereqs-not-met-set! testdat (rmt:get-prereqs-not-met run-id waitons hed item-path mode: testmode itemmaps: itemmaps)) ;; I'm not clear on why we'd capture running job counts here TODO: verify this is needed (runs:dat-can-run-more-tests-set! runsdat (runs:can-run-more-tests runsdat run-id jobgroup max-concurrent-jobs)) (let ((loop-list (runs:process-expanded-tests runsdat testdat))) ;; in process-expanded-tests ultimately run:test -> launch-test -> test actually running (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 #f)) ;; (runs:can-run-more-tests runsdat run-id jobgroup max-concurrent-jobs))) (if (not can-run-more) #;(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) ;; (if (runs:dat-load-mgmt-function runsdat)((runs:dat-load-mgmt-function runsdat))) (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 ;; Here we mark any old defunct tests as incomplete. Do this every fifteen minutes ;; (debug:print 0 *default-log-port* "Got here eh! num-running=" num-running " (> num-running 0) " (> num-running 0)) (if (> (- (current-seconds)(hash-table-ref/default *find-and-mark-incomplete-last-run* run-id 0)) 900) ;; (begin(if (> (current-seconds)(+ last-time-incomplete 900)) (let ((actual-num-running num-running)) ;; (rmt:get-count-tests-running-for-run-id run-id))) ;; why call it again? (debug:print-info 0 *default-log-port* "Marking stuck tests as INCOMPLETE while waiting for run " run-id ". Running as pid " (current-process-id) " on " (get-host-name)) ;; (set! last-time-incomplete (current-seconds)) ;; FIXME, this might be causing slow down - use of set! (rmt:find-and-mark-incomplete run-id #f) (hash-table-set! *find-and-mark-incomplete-last-run* run-id (current-seconds)) (debug:print-info 0 *default-log-port* "run-wait specified, waiting on " actual-num-running " tests in RUNNING, REMOTEHOSTSTART or LAUNCHED state at " (time->string (seconds->local-time (current-seconds)))))) ;; (if (runs:dat-load-mgmt-function runsdat)((runs:dat-load-mgmt-function runsdat))) (thread-sleep! 5) ;; (if (>= num-running max-concurrent-jobs) 5 1)) (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)) |
︙ | ︙ | |||
1448 1449 1450 1451 1452 1453 1454 | (if (not (vector? t)) (conc t) (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 ;; | | > > > > > < < < < < < > > > > > > > > > > > > > < | | | 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 | (if (not (vector? t)) (conc t) (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 runsdat testdat-rec) ;; 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 () |
︙ | ︙ | |||
1515 1516 1517 1518 1519 1520 1521 | (debug:print 2 *default-log-port* "WARN: Test not pre-created? test-name=" test-name ", item-path=" item-path ", run-id=" run-id) (rmt:register-test run-id test-name item-path) (set! test-id (rmt:get-test-id run-id test-name item-path)))) (debug:print-info 4 *default-log-port* "test-id=" test-id ", run-id=" run-id ", test-name=" test-name ", item-path=\"" item-path "\"") (set! testdat (rmt:get-test-info-by-id run-id test-id)) (if (not testdat) (begin | | > | | | 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 | (debug:print 2 *default-log-port* "WARN: Test not pre-created? test-name=" test-name ", item-path=" item-path ", run-id=" run-id) (rmt:register-test run-id test-name item-path) (set! test-id (rmt:get-test-id run-id test-name item-path)))) (debug:print-info 4 *default-log-port* "test-id=" test-id ", run-id=" run-id ", test-name=" test-name ", item-path=\"" item-path "\"") (set! testdat (rmt:get-test-info-by-id run-id test-id)) (if (not testdat) (begin (debug:print-info 0 *default-log-port* "WARNING: server is overloaded, trying again in two seconds") ;; (if (runs:dat-load-mgmt-function runsdat)((runs:dat-load-mgmt-function runsdat))) (thread-sleep! 2) (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 |
︙ | ︙ | |||
1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 | keepgoing) ;; Require to force re-run for COMPLETED or *anything* + PASS,WARN or CHECK (or (member (test:get-status testdat) '("PASS" "WARN" "CHECK" "SKIP" "WAIVED")) (member (test:get-state testdat) '("COMPLETED")))) (debug:print-info 2 *default-log-port* "running test " test-name "/" item-path " suppressed as it is " (test:get-state testdat) " and " (test:get-status testdat)) (hash-table-set! test-registry full-test-name 'DONOTRUN) ;; COMPLETED) (set! runflag #f)) ;; -rerun and status is one of the specifed, run it ((and rerun (let* ((rerunlst (string-split rerun ",")) (must-rerun (member (test:get-status testdat) rerunlst))) (debug:print-info 3 *default-log-port* "-rerun list: " rerun ", test-status: " (test:get-status testdat)", must-rerun: " must-rerun) must-rerun)) (debug:print-info 2 *default-log-port* "Rerun forced for test " test-name "/" item-path) | > | > > > > > > | > | > | 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 | keepgoing) ;; Require to force re-run for COMPLETED or *anything* + PASS,WARN or CHECK (or (member (test:get-status testdat) '("PASS" "WARN" "CHECK" "SKIP" "WAIVED")) (member (test:get-state testdat) '("COMPLETED")))) (debug:print-info 2 *default-log-port* "running test " test-name "/" item-path " suppressed as it is " (test:get-state testdat) " and " (test:get-status testdat)) (hash-table-set! test-registry full-test-name 'DONOTRUN) ;; COMPLETED) (set! runflag #f)) ;; -rerun and status is one of the specifed, run it ((and rerun (let* ((rerunlst (string-split rerun ",")) (must-rerun (member (test:get-status testdat) rerunlst))) (debug:print-info 3 *default-log-port* "-rerun list: " rerun ", test-status: " (test:get-status testdat)", must-rerun: " must-rerun) must-rerun)) (debug:print-info 2 *default-log-port* "Rerun forced for test " test-name "/" item-path) (set! runflag #t) (debug:print-info 2 *default-log-port* "Calling rerun hook") (runs:rerun-hook test-id new-test-path testdat rerun) ) ;; -keepgoing, do not rerun FAIL ((and keepgoing (member (test:get-status testdat) '("FAIL"))) (set! runflag #f)) ((and (not rerun) (member (test:get-status testdat) '("FAIL" "n/a"))) (set! runflag #t)) (else (set! runflag #f))) (debug:print 4 *default-log-port* "RUNNING => runflag: " runflag " STATE: " (test:get-state testdat) " STATUS: " (test:get-status testdat)) (if (not runflag) (if (not parent-test) (if (runs:lownoise (conc "not starting test" full-test-name) 60) (debug:print 1 *default-log-port* "NOTE: Not starting test " full-test-name " as it is state \"" (test:get-state testdat) "\" and status \"" (test:get-status testdat) "\", use -rerun \"" (test:get-status 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")))) | > > | | > > | | > | > > > > > > > > > > > > > > > > > > > > | | | | | > > > | | 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 | ;; 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 ;; (begin ;; wait for less than max jobs here (if (runs:dat-wait-for-jobs-function runsdat) ((runs:dat-wait-for-jobs-function runsdat) testdat-rec)) (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)) ) ;; wait again here? )))))) ((KILLED) (debug:print 1 *default-log-port* "NOTE: " full-test-name " is already running or was explictly killed, use -force to launch it.") (hash-table-set! test-registry (db:test-make-full-name test-name test-path) 'DONOTRUN)) ;; KILLED)) ((LAUNCHED REMOTEHOSTSTART RUNNING) (debug:print 2 *default-log-port* "NOTE: " test-name " is already running")) ;; (if (> (- (current-seconds)(+ (db:test-get-event_time testdat) ;; (db:test-get-run_duration testdat))) ;; (or incomplete-timeout ;; 6000)) ;; i.e. no update for more than 6000 seconds ;; (begin ;; (debug:print 0 *default-log-port* "WARNING: Test " test-name " appears to be dead. Forcing it to state INCOMPLETE and status STUCK/DEAD") ;; (tests:test-set-status! run-id test-id "INCOMPLETE" "STUCK/DEAD" "" #f)) ;; ;; (tests:test-set-status! test-id "INCOMPLETE" "STUCK/DEAD" "" #f)) ;; (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)) | | > > > > > > > > > > > > > > > > > | > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > | > > > > > > > > > > > > > > > | > > > > > | > > > > > > > | | | | > > | < | | | | | | > > > > > > > < > | > > | | > > | > > | | | | | > > > > > > | > > > > > | < | | | | | | | > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | | | | | | | | | | | | | | | | | | | | | > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | > | > | | > > > | | | > | > | > > > | | | < < > | | | > | > > > > > > < > > > > > > > > | > | | > > > > > > > > > > > > > > > > | | | | | | | | | | | | > > | > | | 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 | ;; 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 #f))) (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") "")) (action-chk (member (string->symbol "remove-runs") actions))) ;; check the sequence of actions archive must comme before remove-runs (if (and action-chk (member (string->symbol "archive") action-chk)) (begin (debug:print-error 0 *default-log-port* "action remove-runs must come after archive") (exit 1))) (print "Actions: " actions " age: " age) (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))) (hash-table-keys runs-ht)) (for-each (lambda (action) (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 action " " target ":") (for-each (lambda (run) (let ((remove #t ));(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")) (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) (print "in remove-runs") (if remove (let ((cmd (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" "")))) (print cmd) (system cmd)))) ((archive) (if remove (let ((cmd (conc precmd " megatest -archive save-remove -target " target " -runname " (simple-run-runname run) " -testpatt %"))) (print cmd) (system cmd)))) ((kill-runs) (if remove (system (conc precmd " megatest -kill-runs -target " target " -runname " (simple-run-runname run) " -testpatt %")))) (else (print "unrecognised cmd " action)))))) sorted))) (hash-table-keys runs-ht))) actions) 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: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) (tests:glob-like-match (conc "%/" 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: " (tests:glob-like-match (conc "%/" target "/%") rundir)) (debug:print 2 *default-log-port* "Target: " target) ;;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! 5) (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)) (if (or (equal? (args:get-arg "-archive") "save") (equal? (args:get-arg "-archive") "save-remove")) (begin (print "db archive started") (archive:megatest-db target runnamepatt) (print "db archived"))) ) #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 exn (debug:print-error 0 *default-log-port* " Failed to remove symlink " run-dir ((condition-property-accessor 'exn 'message) exn) ", attempting to continue, exn=" exn) (delete-file run-dir))) (if (directory? run-dir) (if (> (directory-fold (lambda (f x)(+ 1 x)) 0 run-dir) 0) (debug:print 0 *default-log-port* "WARNING: refusing to remove " run-dir " as it is not empty") (handle-exceptions exn (debug:print-error 0 *default-log-port* " Failed to remove directory " run-dir ((condition-property-accessor 'exn 'message) exn) ", attempting to continue, exn=" exn) (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) | | > > > > | | > > | | > > | | | | 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 | (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))) | | > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | 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 | (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 ", exn=" exn))) (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 ")) (for-each (lambda (f) (handle-exceptions exn (debug:print 0 *default-log-port* "WARNING: Failed to remove file " f ", exn=" exn) (delete-file f))) files)))) (debug:print-error 0 *default-log-port* "-clean-cache requires -runname.")) (debug:print-error 0 *default-log-port* "-clean-cache requires -target or -reqtarg"))) |
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 [5771575e2e].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | ;; Copyright 2006-2017, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more 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)) (define (sauth-common:src-size path) (let ((output (with-input-from-pipe (conc "/usr/bin/du -s " path " | awk '{print $1}'") (lambda() (read-line))))) (string->number output))) (define (sauth-common:space-left-at-dest path) (let* ((output (run/string (pipe (df ,path ) (tail -1)))) (size (caddr (cdr (string-split output " "))))) (string->number size))) ;; 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 (conc "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 [b4d2f08e65].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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)) (include "megatest-version.scm") (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 [8697088094].
|
| < | | > | > > > > | | > | > > > | < > | | < | > > > > > > > > > > > > | | 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 |
︙ | ︙ | |||
104 105 106 107 108 109 110 111 112 113 114 115 | ;; (dot-server-url (server:check-if-running areapath)) (curr-ip (server:get-best-guess-address curr-host)) (curr-pid (current-process-id)) (homehost (common:get-homehost)) ;; configf:lookup *configdat* "server" "homehost" )) (target-host (car homehost)) (testsuite (common:get-testsuite-name)) (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 | > > | > > | > > | > > > | | 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 | ;; (dot-server-url (server:check-if-running areapath)) (curr-ip (server:get-best-guess-address curr-host)) (curr-pid (current-process-id)) (homehost (common:get-homehost)) ;; configf:lookup *configdat* "server" "homehost" )) (target-host (car homehost)) (testsuite (common:get-testsuite-name)) (logfile (conc areapath "/logs/server.log")) ;; -" curr-pid "-" target-host ".log")) (profile-mode (or (configf:lookup *configdat* "misc" "profilesw") "")) (cmdln (conc (common:get-megatest-exe) " -server " (or target-host "-") (if (equal? (configf:lookup *configdat* "server" "daemonize") "yes") " -daemonize " "") ;; " -log " logfile " -m testsuite:" testsuite " " profile-mode )) ;; (conc " >> " logfile " 2>&1 &"))))) (log-rotate (make-thread common:rotate-logs "server run, rotate logs thread")) ;; why are we rotating logs here? This is a sensitive location with a lot going on!? (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 ;; (define (server:logf-get-start-info logf) (let ((rx (regexp "^SERVER STARTED: (\\S+):(\\d+) AT ([\\d\\.]+)"))) ;; SERVER STARTED: host:port AT timesecs (handle-exceptions exn (begin (print "failed to get server info from " logf ", exn=" exn) (list #f #f #f)) ;; no idea what went wrong, call it a bad server (with-input-from-file logf (lambda () (let loop ((inl (read-line)) (lnum 0)) (if (not (eof-object? inl)) (let ((mlst (string-match rx inl))) |
︙ | ︙ | |||
172 173 174 175 176 177 178 | ;; otherwise attempt to create the logs dir and then ;; continue (if (if (directory-exists? (conc areapath "/logs")) '() (if (file-write-access? areapath) (begin (condition-case | | | | | > > | | | | | | | > > > > > > > > > > > > > > | 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 | ;; otherwise attempt to create the logs dir and then ;; continue (if (if (directory-exists? (conc areapath "/logs")) '() (if (file-write-access? areapath) (begin (condition-case (create-directory (conc areapath "/logs") #t) (exn (i/o file)(debug:print 0 *default-log-port* "ERROR: Cannot create directory at " (conc areapath "/logs"))) (exn ()(debug:print 0 *default-log-port* "ERROR: Unknown error attemtping to get server list. exn=" exn))) (directory-exists? (conc areapath "/logs"))) '())) (let* ((server-logs (glob (conc areapath "/logs/server-*.log"))) (num-serv-logs (length server-logs))) (if (null? server-logs) '() (let loop ((hed (car server-logs)) (tal (cdr server-logs)) (res '())) (let* ((mod-time (handle-exceptions exn (begin (debug:print 0 *default-log-port* "failed to get modification time on " hed ", exn=" exn) (current-seconds)) ;; 0 (file-modification-time hed))) ;; default to *very* old so log gets ignored if deleted (down-time (- (current-seconds) mod-time)) (serv-dat (if (or (< num-serv-logs 10) (< down-time 900)) ;; day-seconds)) (server:logf-get-start-info hed) '())) ;; don't waste time processing server files not touched in the 15 minutes if there are more than ten servers to look at (serv-rec (cons mod-time serv-dat)) (fmatch (string-match fname-rx hed)) (pid (if fmatch (string->number (list-ref fmatch 2)) #f)) (new-res (if (null? serv-dat) 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 | > | | | | | 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 | (> (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 (or (not (configf:lookup *configdat* "server" "runtime")) ;; skip if not set (< (- now start-time) (+ (- (string->number (configf:lookup *configdat* "server" "runtime")) 180) (random 360)))) ;; under one hour running time +/- 180 )) #f)) srvlst) (lambda (a b) (< (list-ref a 3) (list-ref b 3)))))) (if (> (length slst) nums) |
︙ | ︙ | |||
272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 | (define (server:get-client-signature) ;; BB> why is this proc named "get-"? it returns nothing -- set! has not return value. (if *my-client-signature* *my-client-signature* (let ((sig (server:mk-signature))) (set! *my-client-signature* sig) *my-client-signature*))) ;; kind start up of servers, wait 40 seconds before allowing another server for a given ;; run-id to be launched (define (server:kind-run areapath) (if (not (server:check-if-running areapath)) ;; why try if there is already a server running? (let* ((last-run-dat (hash-table-ref/default *server-kind-run* areapath '(0 0))) ;; callnum, whenrun (call-num (car last-run-dat)) (when-run (cadr last-run-dat)) (run-delay (+ (case call-num ((0) 0) ((1) 20) ((2) 300) (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) | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > | > > | 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 | (define (server:get-client-signature) ;; BB> why is this proc named "get-"? it returns nothing -- set! has not return value. (if *my-client-signature* *my-client-signature* (let ((sig (server:mk-signature))) (set! *my-client-signature* sig) *my-client-signature*))) ;; wait for server=start-last to be three seconds old ;; (define (server:wait-for-server-start-last-flag areapath) (let* ((flag-dir (conc areapath "/logs")) (start-flag (conc flag-dir "/server-start-last")) ;;; THIS INTERACTS WITH [server] timeout. Suggest using 0.1 or above for timeout (6 seconds) (reftime (configf:lookup-number *configdat* "server" "idletime" default: 4)) (server-key (conc (get-host-name) "-" (current-process-id))) (create-key-file (lambda () (with-output-to-file start-flag (lambda () (print server-key))))) (check-key-file (lambda () (let ((res (with-input-from-file start-flag (lambda () (read-line))))) (equal? server-key res)))) (get-file-age (lambda () (let* ((fmodtime (file-modification-time start-flag))) (- (current-seconds) fmodtime))))) (if (not (directory-exists? flag-dir)) (begin (debug:print-info 0 *default-log-port* "Directory " flag-dir " does not exist! Cannot gate.") #f) (if (file-exists? start-flag) (if (check-key-file) ;; is it me? #t ;; yes, it is me, proceed (let* ((file-age (get-file-age))) (if (> file-age reftime) ;; let the previous guy have at least 4 seconds to do their thing (begin ;; file is old enough, we can try to take it (create-key-file) ;; take the file and try again (server:wait-for-server-start-last-flag areapath)) (let* ((remtime (max 1 (min file-age reftime)))) (debug:print-info 0 *default-log-port* "Gating server start, waiting remtime="remtime) (thread-sleep! remtime) (server:wait-for-server-start-last-flag areapath))))) (begin (create-key-file) (server:wait-for-server-start-last-flag areapath)))))) ;; wait for server=start-last to be three seconds old ;; (define (server:wait-for-server-start-last-flag-old areapath) (let* ((start-flag (conc areapath "/logs/server-start-last")) ;;; THIS INTERACTS WITH [server] timeout. Suggest using 0.1 or above for timeout (6 seconds) (reftime (configf:lookup-number *configdat* "server" "idletime" default: 4)) (server-key (conc (get-host-name) "-" (current-process-id))) (create-key-file (lambda () (with-output-to-file start-flag (lambda () (print server-key))))) (check-key-file (lambda () (let ((res (with-input-from-file start-flag (lambda () (read-line))))) (equal? server-key res))))) ;; (thread-sleep! (/ (random 500) 1000)) ;; I don't think this made a difference (if (file-exists? start-flag) (let* ((fmodtime (file-modification-time start-flag)) (delta (- (current-seconds) fmodtime)) (all-go (> delta reftime))) (if (and all-go (begin (create-key-file) (thread-sleep! 0.25) (check-key-file))) #t ;; (system (conc "touch " start-flag)) ;; lazy but safe (begin (debug:print-info 0 *default-log-port* "Gating server start, last start: " fmodtime ", delta: " delta ", reftime: " reftime ", all-go=" all-go) (thread-sleep! reftime) (server:wait-for-server-start-last-flag areapath))))))) ;; kind start up of servers, wait 40 seconds before allowing another server for a given ;; run-id to be launched ;; (define (server:kind-run areapath) ;; look for $MT_RUN_AREA_HOME/logs/server-start-last ;; and wait for it to be at least 3 seconds old (server:wait-for-server-start-last-flag areapath) (if (not (server:check-if-running areapath)) ;; why try if there is already a server running? (let* ((last-run-dat (hash-table-ref/default *server-kind-run* areapath '(0 0))) ;; callnum, whenrun (call-num (car last-run-dat)) (when-run (cadr last-run-dat)) (run-delay (+ (case call-num ((0) 0) ((1) 20) ((2) 300) (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) (let* ((start-flag (conc areapath "/logs/server-start-last"))) (common:simple-file-lock-and-wait lock-file expire-time: 15) (system (conc "touch " start-flag)) ;; lazy but safe (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)))))) ;; this one seems to be the general entry point ;; (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)) (if (or server-url (> (current-seconds) give-up-time)) ;; server-url will be #f if no server available. server-url |
︙ | ︙ | |||
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))) | | > | | > | > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > | > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | (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)) (dbbackupfile (conc mtdbfile ".backup")) (res2 (cond ((eq? 0 res ) (if (file-exists? dbbackupfile) (delete-file* dbbackupfile) ) (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)) (stmt-cache (dbr:dbstruct-stmt-cache dbstruct)) (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 stmt-cache) (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 [d0bcfc709c].
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 | ;; 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)) (include "megatest-version.scm") (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 ;;====================================================================== | | | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | > > > > > > > > > > > > > > > > > > > > > | > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > | > > > > > > | | > > > > > > > > > | | | > | > > > > > > > > | > > > > > > > > > > > > > > | | | | | | | | | | | | > > > | < < < > | | | < < < < | | | | | < | > | > | < | < | | < < < < | > > > | | | > | | > | | | < | > | < < < < < | < | > > | | > | | > > | | | > | < | < | < < < | < < | | | > | > | < | | | < | > | < < < < < | < > | > | | < < < < < < < | | | < < < | < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < | | 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 | ((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 (< (sauth-common:space-left-at-dest target-path) (sauth-common:src-size src-path)) (begin (sauth:print-error "Destination does not have enough disk space.") (exit 1))) (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 [15a6ca2860].
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 | ;; 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)) (include "megatest-version.scm") (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 ;;====================================================================== | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | > | > > | > > > > > > < < | > > > | > | | > | > | > > > > > > > > > > > | > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | > > | > > > > > > | > > > | < > | > > | | | | | | | | > | | | | | | < < < | | | | | | | | | | < < | | | | | | | > | < < < < < < < | < | < < < < < < < < < < | | | > | > > | | > > | | < > > > > > > > > > | > > > > > | | | | | > | > > > > > > > | | > | > > > > > > > | > > > > > > > | | > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > | | < > | > > > | > > > > > > > | > | > > > > > > > > > > | > > > | > > > | > > > > > > > > | < < > | > > > | > | > | | < < < < < < < < < < < < < < < < < < < < > | | > > > | 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 | (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)))) (sauth:print-error start-dir) (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 stml2.scm version [63b057818a].
> > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | ;;====================================================================== ;; Copyright 2019, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more 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 stml2)) (include "stml2/stml2.scm") |
Added stml2/COPYING version [7d7e3bd444].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) 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 this service 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 make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. 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. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute 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 and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), 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 distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the 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 a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, 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. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE 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. 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 convey 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 2 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, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision 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, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. <signature of Ty Coon>, 1 April 1989 Ty Coon, President of Vice This 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 Library General Public License instead of this License. GNU Free Documentation License ****************************** Version 1.1, March 2000 Copyright (C) 2000 Free Software Foundation, Inc. 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. 0. PREAMBLE The purpose of this License is to make a manual, textbook, or other written document "free" in the sense of freedom: to assure everyone the effective freedom to copy and redistribute it, with or without modifying it, either commercially or noncommercially. Secondarily, this License preserves for the author and publisher a way to get credit for their work, while not being considered responsible for modifications made by others. This License is a kind of "copyleft", which means that derivative works of the document must themselves be free in the same sense. It complements the GNU General Public License, which is a copyleft license designed for free software. We have designed this License in order to use it for manuals for free software, because free software needs free documentation: a free program should come with manuals providing the same freedoms that the software does. But this License is not limited to software manuals; it can be used for any textual work, regardless of subject matter or whether it is published as a printed book. We recommend this License principally for works whose purpose is instruction or reference. 1. APPLICABILITY AND DEFINITIONS This License applies to any manual or other work that contains a notice placed by the copyright holder saying it can be distributed under the terms of this License. The "Document", below, refers to any such manual or work. Any member of the public is a licensee, and is addressed as "you". A "Modified Version" of the Document means any work containing the Document or a portion of it, either copied verbatim, or with modifications and/or translated into another language. A "Secondary Section" is a named appendix or a front-matter section of the Document that deals exclusively with the relationship of the publishers or authors of the Document to the Document's overall subject (or to related matters) and contains nothing that could fall directly within that overall subject. (For example, if the Document is in part a textbook of mathematics, a Secondary Section may not explain any mathematics.) The relationship could be a matter of historical connection with the subject or with related matters, or of legal, commercial, philosophical, ethical or political position regarding them. The "Invariant Sections" are certain Secondary Sections whose titles are designated, as being those of Invariant Sections, in the notice that says that the Document is released under this License. The "Cover Texts" are certain short passages of text that are listed, as Front-Cover Texts or Back-Cover Texts, in the notice that says that the Document is released under this License. A "Transparent" copy of the Document means a machine-readable copy, represented in a format whose specification is available to the general public, whose contents can be viewed and edited directly and straightforwardly with generic text editors or (for images composed of pixels) generic paint programs or (for drawings) some widely available drawing editor, and that is suitable for input to text formatters or for automatic translation to a variety of formats suitable for input to text formatters. A copy made in an otherwise Transparent file format whose markup has been designed to thwart or discourage subsequent modification by readers is not Transparent. A copy that is not "Transparent" is called "Opaque". Examples of suitable formats for Transparent copies include plain ASCII without markup, Texinfo input format, LaTeX input format, SGML or XML using a publicly available DTD, and standard-conforming simple HTML designed for human modification. Opaque formats include PostScript, PDF, proprietary formats that can be read and edited only by proprietary word processors, SGML or XML for which the DTD and/or processing tools are not generally available, and the machine-generated HTML produced by some word processors for output purposes only. The "Title Page" means, for a printed book, the title page itself, plus such following pages as are needed to hold, legibly, the material this License requires to appear in the title page. For works in formats which do not have any title page as such, "Title Page" means the text near the most prominent appearance of the work's title, preceding the beginning of the body of the text. 2. VERBATIM COPYING You may copy and distribute the Document in any medium, either commercially or noncommercially, provided that this License, the copyright notices, and the license notice saying this License applies to the Document are reproduced in all copies, and that you add no other conditions whatsoever to those of this License. You may not use technical measures to obstruct or control the reading or further copying of the copies you make or distribute. However, you may accept compensation in exchange for copies. If you distribute a large enough number of copies you must also follow the conditions in section 3. You may also lend copies, under the same conditions stated above, and you may publicly display copies. 3. COPYING IN QUANTITY If you publish printed copies of the Document numbering more than 100, and the Document's license notice requires Cover Texts, you must enclose the copies in covers that carry, clearly and legibly, all these Cover Texts: Front-Cover Texts on the front cover, and Back-Cover Texts on the back cover. Both covers must also clearly and legibly identify you as the publisher of these copies. The front cover must present the full title with all words of the title equally prominent and visible. You may add other material on the covers in addition. Copying with changes limited to the covers, as long as they preserve the title of the Document and satisfy these conditions, can be treated as verbatim copying in other respects. If the required texts for either cover are too voluminous to fit legibly, you should put the first ones listed (as many as fit reasonably) on the actual cover, and continue the rest onto adjacent pages. If you publish or distribute Opaque copies of the Document numbering more than 100, you must either include a machine-readable Transparent copy along with each Opaque copy, or state in or with each Opaque copy a publicly-accessible computer-network location containing a complete Transparent copy of the Document, free of added material, which the general network-using public has access to download anonymously at no charge using public-standard network protocols. If you use the latter option, you must take reasonably prudent steps, when you begin distribution of Opaque copies in quantity, to ensure that this Transparent copy will remain thus accessible at the stated location until at least one year after the last time you distribute an Opaque copy (directly or through your agents or retailers) of that edition to the public. It is requested, but not required, that you contact the authors of the Document well before redistributing any large number of copies, to give them a chance to provide you with an updated version of the Document. 4. MODIFICATIONS You may copy and distribute a Modified Version of the Document under the conditions of sections 2 and 3 above, provided that you release the Modified Version under precisely this License, with the Modified Version filling the role of the Document, thus licensing distribution and modification of the Modified Version to whoever possesses a copy of it. In addition, you must do these things in the Modified Version: A. Use in the Title Page (and on the covers, if any) a title distinct from that of the Document, and from those of previous versions (which should, if there were any, be listed in the History section of the Document). You may use the same title as a previous version if the original publisher of that version gives permission. B. List on the Title Page, as authors, one or more persons or entities responsible for authorship of the modifications in the Modified Version, together with at least five of the principal authors of the Document (all of its principal authors, if it has less than five). C. State on the Title page the name of the publisher of the Modified Version, as the publisher. D. Preserve all the copyright notices of the Document. E. Add an appropriate copyright notice for your modifications adjacent to the other copyright notices. F. Include, immediately after the copyright notices, a license notice giving the public permission to use the Modified Version under the terms of this License, in the form shown in the Addendum below. G. Preserve in that license notice the full lists of Invariant Sections and required Cover Texts given in the Document's license notice. H. Include an unaltered copy of this License. I. Preserve the section entitled "History", and its title, and add to it an item stating at least the title, year, new authors, and publisher of the Modified Version as given on the Title Page. If there is no section entitled "History" in the Document, create one stating the title, year, authors, and publisher of the Document as given on its Title Page, then add an item describing the Modified Version as stated in the previous sentence. J. Preserve the network location, if any, given in the Document for public access to a Transparent copy of the Document, and likewise the network locations given in the Document for previous versions it was based on. These may be placed in the "History" section. You may omit a network location for a work that was published at least four years before the Document itself, or if the original publisher of the version it refers to gives permission. K. In any section entitled "Acknowledgments" or "Dedications", preserve the section's title, and preserve in the section all the substance and tone of each of the contributor acknowledgments and/or dedications given therein. L. Preserve all the Invariant Sections of the Document, unaltered in their text and in their titles. Section numbers or the equivalent are not considered part of the section titles. M. Delete any section entitled "Endorsements". Such a section may not be included in the Modified Version. N. Do not retitle any existing section as "Endorsements" or to conflict in title with any Invariant Section. If the Modified Version includes new front-matter sections or appendices that qualify as Secondary Sections and contain no material copied from the Document, you may at your option designate some or all of these sections as invariant. To do this, add their titles to the list of Invariant Sections in the Modified Version's license notice. These titles must be distinct from any other section titles. You may add a section entitled "Endorsements", provided it contains nothing but endorsements of your Modified Version by various parties--for example, statements of peer review or that the text has been approved by an organization as the authoritative definition of a standard. You may add a passage of up to five words as a Front-Cover Text, and a passage of up to 25 words as a Back-Cover Text, to the end of the list of Cover Texts in the Modified Version. Only one passage of Front-Cover Text and one of Back-Cover Text may be added by (or through arrangements made by) any one entity. If the Document already includes a cover text for the same cover, previously added by you or by arrangement made by the same entity you are acting on behalf of, you may not add another; but you may replace the old one, on explicit permission from the previous publisher that added the old one. The author(s) and publisher(s) of the Document do not by this License give permission to use their names for publicity for or to assert or imply endorsement of any Modified Version. 5. COMBINING DOCUMENTS You may combine the Document with other documents released under this License, under the terms defined in section 4 above for modified versions, provided that you include in the combination all of the Invariant Sections of all of the original documents, unmodified, and list them all as Invariant Sections of your combined work in its license notice. The combined work need only contain one copy of this License, and multiple identical Invariant Sections may be replaced with a single copy. If there are multiple Invariant Sections with the same name but different contents, make the title of each such section unique by adding at the end of it, in parentheses, the name of the original author or publisher of that section if known, or else a unique number. Make the same adjustment to the section titles in the list of Invariant Sections in the license notice of the combined work. In the combination, you must combine any sections entitled "History" in the various original documents, forming one section entitled "History"; likewise combine any sections entitled "Acknowledgments", and any sections entitled "Dedications". You must delete all sections entitled "Endorsements." 6. COLLECTIONS OF DOCUMENTS You may make a collection consisting of the Document and other documents released under this License, and replace the individual copies of this License in the various documents with a single copy that is included in the collection, provided that you follow the rules of this License for verbatim copying of each of the documents in all other respects. You may extract a single document from such a collection, and distribute it individually under this License, provided you insert a copy of this License into the extracted document, and follow this License in all other respects regarding verbatim copying of that document. 7. AGGREGATION WITH INDEPENDENT WORKS A compilation of the Document or its derivatives with other separate and independent documents or works, in or on a volume of a storage or distribution medium, does not as a whole count as a Modified Version of the Document, provided no compilation copyright is claimed for the compilation. Such a compilation is called an "aggregate", and this License does not apply to the other self-contained works thus compiled with the Document, on account of their being thus compiled, if they are not themselves derivative works of the Document. If the Cover Text requirement of section 3 is applicable to these copies of the Document, then if the Document is less than one quarter of the entire aggregate, the Document's Cover Texts may be placed on covers that surround only the Document within the aggregate. Otherwise they must appear on covers around the whole aggregate. 8. TRANSLATION Translation is considered a kind of modification, so you may distribute translations of the Document under the terms of section 4. Replacing Invariant Sections with translations requires special permission from their copyright holders, but you may include translations of some or all Invariant Sections in addition to the original versions of these Invariant Sections. You may include a translation of this License provided that you also include the original English version of this License. In case of a disagreement between the translation and the original English version of this License, the original English version will prevail. 9. TERMINATION You may not copy, modify, sublicense, or distribute the Document except as expressly provided for under this License. Any other attempt to copy, modify, sublicense or distribute the Document is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 10. FUTURE REVISIONS OF THIS LICENSE The Free Software Foundation may publish new, revised versions of the GNU Free Documentation 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. See `http://www.gnu.org/copyleft/'. Each version of the License is given a distinguishing version number. If the Document specifies that a particular numbered version of this License "or any later version" applies to it, you have the option of following the terms and conditions either of that specified version or of any later version that has been published (not as a draft) by the Free Software Foundation. If the Document does not specify a version number of this License, you may choose any version ever published (not as a draft) by the Free Software Foundation. ADDENDUM: How to use this License for your documents ---------------------------------------------------- To use this License in a document you have written, include a copy of the License in the document and put the following copyright and license notices just after the title page: Copyright (C) YEAR YOUR NAME. Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.1 or any later version published by the Free Software Foundation; with the Invariant Sections being LIST THEIR TITLES, with the Front-Cover Texts being LIST, and with the Back-Cover Texts being LIST. A copy of the license is included in the section entitled ``GNU Free Documentation License''. If you have no Invariant Sections, write "with no Invariant Sections" instead of saying which ones are invariant. If you have no Front-Cover Texts, write "no Front-Cover Texts" instead of "Front-Cover Texts being LIST"; likewise for Back-Cover Texts. If your document contains nontrivial examples of program code, we recommend releasing these examples in parallel under your choice of free software license, such as the GNU General Public License, to permit their use in free software. |
Added stml2/INSTALL version [25d174366c].
> > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | These are rough installation instructions. Please contact me at matt@kiatoa.com if you have trouble installing. 1. Copy install.cfg.template to install.cfg and modify appropriately 2. Copy stml.config.template to your cgi dir as .stml.config and modify appropriately - choose your db 3. Copy requirements.scm.template to requirements.scm and modify as needed - choose your db (must match what you choose in 2. above) If on 64 bit and you get error in compiling try fPIC: CSC_OPTIONS='-C "-fPIC"' make run > make or > CSC_OPTIONS='-C "-fPIC"' make |
Added stml2/Makefile version [0ba4186b5a].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 2007-2008, Matthew Welland. # # This program is made available under the GNU GPL version 2.0 or # greater. See the accompanying file COPYING for details. # # This program is distributed WITHOUT ANY WARRANTY; without even the # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR # PURPOSE. # # Following needed on bluehost (maybe on all 64bit?) # # CSC_OPTIONS='-C "-fPIC"' make # include install.cfg SRCFILES = stml2.scm misc-stml.scm session.scm sqltbl.scm formdat.scm setup.scm keystore.scm html-filter.scm cookie.scm MODULEFILES = $(wildcard modules/*/*-mod.scm) SOFILES = $(MODULEFILES:%.scm=%.so) CFILES = $(MODULEFILES:%.scm=%.c) OFILES = $(SRCFILES:%.scm=%.o) TARGFILES = $(notdir $(SOFILES)) MODULES = $(addprefix $(TARGDIR)/modules/,$(TARGFILES)) install : $(TARGDIR)/stmlrun $(LOGDIR) $(MODULES) chicken-install all : $(SOFILES) # stmlrun : stmlrun.scm formdat.scm misc-stml.scm session.scm stml.scm \ # setup.scm html-filter.scm requirements.scm keystore.scm \ # cookie.scm sqltbl.scm # csc stmlrun.scm $(TARGDIR)/stmlrun : stmlrun stml2.so echo "NOTE: CSC_OPTIONS='-C \"-fPIC\"' make" install stmlrun $(TARGDIR) chmod a+rx $(TARGDIR)/stmlrun $(TARGDIR)/modules : mkdir -p $(TARGDIR)/modules $(MODULES) : $(SOFILES) $(TARGDIR)/modules cp $< $@ stmlrun : $(OFILES) stmlrun.scm requirements.scm stmlcommon.scm csc $(CSCOPTS) $(OFILES) stmlrun.scm -o stmlrun stml.so : stmlmodule.so cp stmlmodule.so stml.so stmlmodule.so : $(OFILES) stmlmodule.scm requirements.scm stmlcommon.scm csc $(CSCOPTS) $(OFILES) -s stmlmodule.scm # logging currently relies on this # $(LOGDIR) : mkdir -p $(LOGDIR) chmod a+rwx $(LOGDIR) test: kiatoa.db cookie.so echo '(exit)'| csi -q ./tests/test.scm # modules # %.so : %.scm csc $(CSCOPTS) -I modules/* -s $< %.o : %.scm csc $(CSCOPTS) -c $< # Cookie is a special case for now. Make a loadable so for test # Complile it in by include (see dependencies above). cookie.so : cookie.scm csc i$(CSCOPTS) -s cookie.scm clean : rm -f doc/*~ modules/*/*.so *.import.scm *.import.so *.o *.so *~ # $(CFILES): build/%.c: ../scm/%.scm ../scm/macros.scm # chicken $< -output-file $@ # # # $(OFILES): src/%.o: src/%.c # gcc -c $< `chicken-config -cflags` -o $@ # # $(src_code): %: src/%.o src/laedlib.o src/layobj.o # gcc src/$*.o src/laedlib.o src/layobj.o -o $* `chicken-config -libs` # |
Added stml2/README version [a1795f6205].
> | 1 | This is the stml, scheme based cgi application framework. |
Added stml2/TODO version [14eed9b843].
> > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | 1. Documentation. multiple apps in same cgi dir compilation of models for speed and code protection tricks 2. Hierarchial pages. Currently pages can be hierarchial but the control.scm doesn't get called at the right time. 3. For sqlite3 usage put session into own db? 4. A mechanism for sharing variables better between control and view would be good. Perhaps: (let () (load control) (load view)) 5. Change all the "included" files to be seperately compiled units and adj. makefile accordingly. This would speed up compilation when changes are isolated to one or two files. 6. The dbi interface needs a simple config mecanism alternative to the current list of pairs which is hard to use on the fly. Something like the perl: "dbi:host:port:user:password" I'm sure there is more ... |
Added stml2/cookie.scm version [d78a525a3a].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | ;;; ;;; cookie.scm - parse and construct http state information ;;; ;;; Copyright (c) 2000-2003 Shiro Kawai, All rights reserved. ;;; ;;; Redistribution and use in source and binary forms, with or without ;;; modification, are permitted provided that the following conditions ;;; are met: ;;; ;;; 1. Redistributions of source code must retain the above copyright ;;; notice, this list of conditions and the following disclaimer. ;;; ;;; 2. Redistributions in binary form must reproduce the above copyright ;;; notice, this list of conditions and the following disclaimer in the ;;; documentation and/or other materials provided with the distribution. ;;; ;;; 3. Neither the name of the authors nor the names of its contributors ;;; may be used to endorse or promote products derived from this ;;; software without specific prior written permission. ;;; ;;; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ;;; "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ;;; LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ;;; A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ;;; OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ;;; SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED ;;; TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR ;;; PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF ;;; LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING ;;; NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ;;; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ;;; ;;; Ported to Chicken by Reed Sheridan ;;; ;; Parser and constructor of http "Cookies" defined in ;; RFC 2965 HTTP state managemnet mechanism ;; <ftp://ftp.isi.edu/in-notes/rfc2965.txt> ;; See also ;; RFC 2964 Use of HTTP state management ;; <ftp://ftp.isi.edu/in-notes/rfc2964.txt> ;; The parser also supports the old Netscape spec ;; <http://www.netscape.com/newsref/std/cookie_spec.html> ;; (declare (unit cookie)) (module cookie * (import chicken scheme data-structures extras srfi-13 ports posix) (require-extension srfi-1 srfi-13 srfi-14 regex) ;; (use srfi-1 srfi-13 srfi-14 regex) ;; (declare (export parse-cookie-string construct-cookie-string)) ;; #> ;; #include <time.h> ;; <# ;; ;; (define fmt-time ;; (foreign-lambda* c-string ((long secs_since_epoch)) ;; "static char buf[256];" ;; "time_t t = (time_t) secs_since_epoch;" ;; "strftime(buf, sizeof(buf), \"%a, %d-%b-%Y %H:%M:%S GMT\", gmtime(&t));" ;; "return(buf);")) (define (fmt-time seconds) (time->string (seconds->utc-time seconds) "%D")) ;; utility fn. breaks ``attr=value;attr=value ... '' into alist. ;; version is a cookie version. if version>0, we allow comma as the ;; delimiter as well as semicolon. (define (parse-av-pairs input version) (define attr-regexp (if (= version 0) (regexp "\\s*([\\w$_-]+)\\s*([=\\;]\\s*)?") (regexp "\\s*([\\w$_-]+)\\s*([=\\;,]\\s*)?"))) (define attr-delim (if (= version 0) #\; (char-set #\, #\\ #\;))) (define (read-attr input r) (cond ((string-null? input) (reverse! r)) ((string-search attr-regexp input) => (lambda (m) (if (and-let* ((delimiter (third m))) ;;is an attr_value pai (string-prefix? "=" delimiter)) (let ((attr (second m)) (rest (string-search-after attr-regexp input))) (if (string-prefix? "\"" rest) (read-token-quoted attr (string-drop rest 1) r) (read-token attr rest r))) (read-attr (string-search-after attr-regexp input) ;; Skip ahead if broken input? (alist-cons (second m) #f r))))) (else ;; the input is broken; for now, we ignore the rest. (reverse! r)))) (define (read-token attr input r) (cond ((string-index input attr-delim) => (lambda (i) (read-attr (string-drop input (+ i 1)) (alist-cons attr (string-trim-right (string-take input i)) r)))) (else (reverse! (alist-cons attr (string-trim-right input) r))))) (define (read-token-quoted attr input r) (let loop ((input input) (partial '())) (cond ((string-index input (char-set #\\ #\")) => (lambda (i) (let ((c (string-ref input i))) (if (char=? c #\\) (if (< (string-length input) (+ i 1)) (error-unterminated attr) (loop (string-drop input (+ i 2)) (cons* (string (string-ref input (+ i 1))) (string-take input i) partial))) (read-attr (string-drop input (+ i 1)) (alist-cons attr (string-concatenate-reverse (cons (string-take input i) partial)) r)))))) (else (error-unterminated attr))))) (define (error-unterminated attr) (error "Unterminated quoted value given for attribute" attr)) (read-attr input '())) ;; Parses the header value of "Cookie" request header. ;; If cookie version is known by "Cookie2" request header, it should ;; be passed to version (as integer). Otherwise, it figures out ;; the cookie version from input. ;; ;; Returns the following format. ;; ((<name> <value> [:path <path>] [:domain <domain>] [:port <port>]) ;; ...) (define (parse-cookie-string input #!optional version) (let ((ver (cond ((integer? version) version) ((string-search "^\\s*\\$Version\\s*=\\s*(\\d+)" input) => (lambda (m) (string->number (cadr m)))) (else 0)))) (let loop ((av-pairs (parse-av-pairs input ver)) (r '()) (current '())) (cond ((null? av-pairs) (if (null? current) (reverse r) (reverse (cons (reverse current) r)))) ((string-ci=? "$path" (caar av-pairs)) (loop (cdr av-pairs) r (cons* (cdar av-pairs) path: current))) ((string-ci=? "$domain" (caar av-pairs)) (loop (cdr av-pairs) r (cons* (cdar av-pairs) domain: current))) ((string-ci=? "$port" (caar av-pairs)) (loop (cdr av-pairs) r (cons* (cdar av-pairs) port: current))) (else (if (null? current) (loop (cdr av-pairs) r (list (cdar av-pairs) (caar av-pairs))) (loop (cdr av-pairs) (cons (reverse current) r) (list (cdar av-pairs) (caar av-pairs))))))))) ;; Construct a cookie string suitable for Set-Cookie or Set-Cookie2 header. ;; specs is the following format. ;; ;; ((<name> <value> [:comment <comment>] [:comment-url <comment-url>] ;; [:discard <bool>] [:domain <domain>] ;; [:max-age <age>] [:path <value>] [:port <port-list>] ;; [:secure <bool>] [:version <version>] [:expires <date>] ;; ) ...) ;; ;; Returns a list of cookie strings for each <name>=<value> pair. In the ;; ``new cookie'' implementation, you can join them by comma and send it ;; at once with Set-cookie2 header. For the old netscape protocol, you ;; must send each of them by Set-cookie header. (define (construct-cookie-string specs #!optional (version 1)) (map (lambda (spec) (construct-cookie-string-1 spec version)) specs)) (define (construct-cookie-string-1 spec ver) (when (< (length spec) 2) (error "bad cookie spec: at least <name> and <value> required" spec)) (let ((name (car spec)) (value (cadr spec))) (let loop ((attr (cddr spec)) (r (list (if value (string-append name "=" (quote-if-needed value)) name)))) (define (next s) (loop (cddr attr) (cons s r))) (define (ignore) (loop (cddr attr) r)) (cond ((null? attr) (string-join (reverse r) ";")) ((null? (cdr attr)) (error (conc "bad cookie spec: attribute " (car attr) " requires value" ))) ((eqv? comment: (car attr)) (if (> ver 0) (next (string-append "Comment=" (quote-if-needed (cadr attr)))) (ignore))) ((eqv? comment-url: (car attr)) (if (> ver 0) (next (string-append "CommentURL=" (quote-value (cadr attr)))) (ignore))) ((eqv? discard: (car attr)) (if (and (> ver 0) (cadr attr)) (next "Discard") (ignore))) ((eqv? domain: (car attr)) (next (string-append "Domain=" (cadr attr)))) ((eqv? max-age: (car attr)) (if (> ver 0) (next (sprintf "Max-Age=~a" (cadr attr))) (ignore))) ((eqv? path: (car attr)) (next (string-append "Path=" (quote-if-needed (cadr attr))))) ((eqv? port: (car attr)) (if (> ver 0) (next (string-append "Port=" (quote-value (cadr attr)))) (ignore))) ((eqv? secure: (car attr)) (if (cadr attr) (next "Secure") (ignore))) ((eqv? version: (car attr)) (if (> ver 0) (next (sprintf "Version=~a" (cadr attr))) (ignore))) ((eqv? expires: (car attr)) (if (> ver 0) (ignore) (next (make-expires-attr (cadr attr))))) (else (error "Unknown cookie attribute" (car attr)))) )) ) ;; (define (quote-value value) ;; (string-append "\"" (regexp-replace-all #/\"|\\/ value "\\\\\\0") "\"")) (define (quote-value value) (string-append "\"" (string-substitute* value '(("\\\"" . "\\\"") ("\\\\" . "\\\\"))) "\"")) (define quote-if-needed (let ((rx (regexp "[\\\",;\\\\ \\t\\n]"))) (lambda (value) (if (string-search rx value) (quote-value value) value)))) (define (make-expires-attr time) (sprintf "Expires=~a" (if (number? time) (fmt-time time) time))) ;;;; Added support functions from my utils, split this out (define (string-search-after r s #!optional (start 0)) (and-let* ((match-indices (string-search-positions r s start)) (right-match (second (first match-indices)))) (substring s right-match))) ) |
Added stml2/doc/Makefile version [93337f215f].
> > > > > > > | 1 2 3 4 5 6 7 | all : manual.pdf web-page.html manual.pdf : manual.txt a2x -a toc -f pdf manual.txt # asciidoc -a toc plan.txt a2x -f chunked -a toc manual.txt |
Added stml2/doc/howto.txt version [2ccf521fee].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | Gotchas! ======= All items for a page *must* be part of a list! ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ OK: (list (function1 param1)(function2 param2)) NOT OK: (begin (function1 param1)(function2 param2)) Various components ~~~~~~~~~~~~~~~~~~ The URL: http://the.domain.com/pagename/p1/p2/p3?param1=value1 (s:get-page-params) => '("p1" "p2") (s:get-param 'param1) => "value1" (s:get-param 'param1 'number) => number or #f NOTE: it is often practical to use the generic (s:get-inp ...) which will first look for the POST input variable and then fall back to the GET param. This allows one to switch back and forth between GET and POST during development without changing the code. (s:get-inp 'param1) ;; trys to find input by name of param1, followed by trying get-param Create a link. ~~~~~~~~~~~~~~ (s:a name 'href (s:link-to "pagename/blah" "")) Call current page with new param ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ In view.scm: (s:center "[" (s:a 'href (s:link-to "polls" 'id (begin (poll:poll 'fill-polls) (poll:poll 'get-next-poll))) "Go to the next poll") "]") In control.scm: (let ((poll-id (s:get-param 'id))) ;; do stuff based on poll-id Call an action on a specific page ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ (s:a 'href (s:link-to "polls" 'id (poll:poll 'get 'id) 'action "poll.edit") "Suggest changes to this poll") NOT TRUE! This calls fuction poll.edit (should be in control.scm). Parameter set is 'id to a poll num. A complex link example ~~~~~~~~~~~~~~~~~~~~~~ (s:a "Reply" 'href (s:link-to (s:current-page) 'action "discussion.reply" ;; <page>.<action> 'reply_to (number->string (hash-table-ref row 'posts.id)) 'id (s:get "discussion.parent_object_id")) "reply") ;; use (s:get-param to get the 'id, or 'reply_to values Get and set a session var ~~~~~~~~~~~~~~~~~~~~~~~~~ (s:session-var-get "keyname") (s:session-var-get "keyname" 'number) (s:session-var-set! "keyname" "value") 5.1 Page local vars (s:set! key val) (s:get key) make a selection drop down ~~~~~~~~~~~~~~~~~~~~~~~~~~ ;; items is a hierarchial alist ;; ( (label1 value1 dispval1 #t) ;; <== this one is selected ;; (label2 (label3 value2 dispval2) ;; (label4 value3 dispval3))) In view.scm: ;; Label Value visible-str selected (s:select '(("World" 0)("Country" 1)("State" 2 "The state" #t )("Town/City" 3)) 'name 'scope) Visible str will be shown if provided. Selected will set that entry to pre-selected. To select a specific entry: (s:select '(("World" 0 "world" #f)("Country" 1 "country" #t)("State" 2 "state" #f)("Town/City" 3 "town" #f)) 'name 'scope) In control.scm: (let ((scope (s:get-input 'scope)) (scope-num (s:get-input 'scope 'number))) ;; 'number, 'raw or 'escaped .... The optional fourth entry sets that item as selected if true Simple error reporting ~~~~~~~~~~~~~~~~~~~~~~ In control.scm: (s:set-err "You must provide an email address") In view.scm: (s:get-err s:err-font) Or: (s:get-err (lambda (x)(s:err-font x (s:br)))) Sharing data between pages ~~~~~~~~~~~~~~~~~~~~~~~~~~ NOTE: This data is *not* preserved between cgi calls. ;; In first page called (s:shared-set! "somekey" somevalue) ;; In a page called later (let ((dat (s:shared-get "somekey"))) ( .... )) Misc useful stuff ~~~~~~~~~~~~~~~~~ i. Lazy/safe string->number (s:any->number val) ii. Random string (session:make-rand-string len) iii. string to number for pgint (s:any->pgint val) Forms and input ~~~~~~~~~~~~~~~ (s:form 'action "login.login" 'method "post" (s:input-preserve 'type "text" 'name "email-address" 'size "16" 'maxlength "30") (s:input 'type "submit" 'name "form-name" 'value "login")) (s:get-input 'email-address) To preserve the input simply do a set of the value on the 'name field: (s:set! "email-address" "matt@kiatoa.com") Radio buttons: (s:div 'class "col_3" (s:input 'type "radio" 'id "group-type1" 'name "group-type" 'value "private" 'checked "checked") (s:label 'for "group-type1" 'class "inline" "Private") (s:input 'type "radio" 'id "group-type2" 'name "group-type" 'value "public") (s:label 'for "group-type2" 'class "inline" "Public")) (s:get-input 'group-type) ==> returns private or public depending on which is selected. |
Added stml2/doc/manual.txt version [ae796565bb].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | STML User Manual ================ Matt Welland <matt@kiatoa.com> v1.0, 2012-6 NOT DONE YET! :( sorry. :numbered!: [abstract] Example Abstract ---------------- Yada about stml :numbered: User Data Specification ----------------------- .User Data [width="100%",options="header",cols="<s,2m,2e,2e,2e",frame="topbot"] |============================== | Field | Field Template |Short form| Example | Description | Likes | :likes |:l | :likes rock, jazz, blues | List of things liked, used to narrow down music liked etc. |============================== .Example stuff ----------------------------- stuff eh ----------------------------- // ----------------------- <<<<<<<<<<<<<<<<< Plan ---- Today ~~~~~ . Nothing scheduled Done Stuff ~~~~~~~~~~ Phase 3 ~~~~~~~ . Error printing with debug levels . Complete the manual . Get working with Chromium, test with Internet Explorer and other browsers Notes ----- |
Added stml2/doc/stml-snapshot.png version [e6cb8d257e].
cannot compute difference between binary files
Added stml2/example/Makefile version [d224d59dca].
> > > > > > > > > > > > > > > > > > > > > > > > > > | 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 2007-2008, Matthew Welland. # # This program is made available under the GNU GPL version 2.0 or # greater. See the accompanying file COPYING for details. # # This program is distributed WITHOUT ANY WARRANTY; without even the # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR # PURPOSE. # Uncomment and fix path if you want your models to be compiled # MODELS := $(wildcard models/*scm) SOFILES := $(patsubst %.scm,%.so,$(MODELS)) # all : $(SOFILES) # If you want compiled models uncomment the following # # $(SOFILES) : %.so: %.scm # csc -s $< test: # $(SOFILES) echo '(exit)'| csi -q ./tests/test.scm # cgi-util proplist cgi-util cookie |
Added stml2/example/POLICY version [da39a3ee5e].
Added stml2/example/README version [a8907c6b3f].
> > > | 1 2 3 | This is an (unfinished) example application. To see it live go to: www.approvalvote.org |
Added stml2/example/TODO version [71853c6197].
> > | 1 2 |
Added stml2/example/db/db-tweaks.sql version [b1c54e147f].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | >-- create table polls(id serial not null,poll_type text,title text,description text,poll_state text); -- create table poll_categories(id serial not null,poll_id integer,description text); -- create table poll_votes(id serial not null,period integer,poll_type text,poll_category text,voter_group integer, votes integer); -- create table vote_items (id serial primary key,type integer,item_id integer,item_level text,town_votes integer,state_votes integer,country_votes integer,world_votes integer); -- -- alter table vote_items alter column town_votes set default 0; -- alter table vote_items alter column state_votes set default 0; -- alter table vote_items alter column country_votes set default 0; -- alter table vote_items alter column world_votes set default 0; -- -- alter table poll_items add column class_0 int4; -- alter table poll_items add column class_1 int4; -- alter table poll_items add column class_2 int4; -- -- alter table poll_items add column classp_0 int4; -- alter table poll_items add column classp_1 int4; -- alter table poll_items add column classp_2 int4; -- -- alter table poll_items alter column classp_0 set default 0; -- alter table poll_items alter column classp_1 set default 0; -- alter table poll_items alter column classp_2 set default 0; -- -- alter table poll_items add column suggestor int4; -- -- alter table poll_items alter column class_0 set default 0; -- alter table poll_items alter column class_1 set default 0; -- alter table poll_items alter column class_2 set default 0; -- -- alter table poll_items add column status int4; -- alter table poll_items alter column status set default 0; -- alter table poll_items add column url text; -- alter table vote_items add column submit_date date; -- alter table poll_items add column submit_date date; -- alter table people add column pt_balance int4; -- alter table people alter column pt_balance set default 0; -- alter table people add column cert_date date; -- alter table people alter column pt_balance set default 0; -- create table pt_transactions (id serial not null,from_id integer,to_id integer,amount integer,transaction_time timestamp); -- alter table pt_transactions alter column amount set default 0; -- alter table classifieds add column points int4; -- alter table classifieds alter column points set default 0; -- alter table pt_transactions add column comment text; -- alter table pt_transactions add column comment text; -- create table temp_key(id serial not null,key text,sent_date date); -- alter table people add column lastlogin timestamp; -- create table pictures(id serial not null,owner integer,size integer,name text,type text,md5sum text,uploaded date); -- alter table pictures add column status text; -- create table pic_allocation(id serial not null,picnum integer,used_by integer); -- alter table posts add column url text; -- alter table posts add column blurb text; insert into subjects (subjectid,subject,item_type,description) values('VoSp','Spanish','lang','Basic Spanish Vocabulary'); insert into subjects (subjectid,subject,item_type,description) values('HoMe','Homeopathy','Info','Basic Homeopathy'); alter table items add column group_name text; alter table items add column state int4; create table sessions (id serial not null,session_key text); create table session_vars (id serial not null,session_id integer,page text,key text,value text); alter table poll_items add column num_voted integer default 0; alter table poll_items add column vote_tot integer default 0; alter table poll_items add column item_votes integer default 0; -- remember ballots are used for many things other than polls!!!!!!!! create table ballots (id serial not null, item_id integer, class_id integer, votes integer, type_id integer); create table ballot_classes (id serial not null, name text, pts_per_vote integer); -- join with ballots to sum up votes (pts are really votes) insert into ballot_classes values (0,'',1); insert into ballot_classes values (1,'',2); insert into ballot_classes values (2,'',10); insert into ballot_classes values (3,'',20); insert into ballot_classes values (4,'',45); insert into ballot_classes values (5,'',90); insert into ballot_classes values (6,'',105); insert into ballot_classes values (7,'',145); insert into ballot_classes values (8,'',205); insert into ballot_classes values (9,'',245); create table ballot_types (id serial not null, name text); -- poll plurality = 0, poll approval = 1 insert into ballot_types (id,name) values (0,'poll plurality'); insert into ballot_types (id,name) values (1,'poll approval'); alter table voted add column type_id integer; alter table voted add column id serial not null; create table voted_types (id serial not null, name text); insert into voted_types (id, name) values (0, 'poll vote'); -- YES!!! WE DO NEED voted_types SEPERATE FROM ballot_types insert into voted_types (id, name) values (1, 'council vote for poll'); -- yes, they are similar but I think combining them would be insert into voted_types (id, name) values (2, 'council vote for item'); -- painful. insert into voted_types (id, name) values (3, 'council vote for story'); alter table people add column email_validated integer default 0; -- has email been validated? Hmmm... should this be a seperate table alter table people add column grade integer default 0; -- alter table voted add column grade integer default 0; -- grade -- -- 0 - no status (refusing cookies) -- 1 - has session -- 2 - logged in, has user id -- 3 - email validated -- 4 ++ add 1 for every 20 points of cert_level alter table poll_items drop column class_0 ; alter table poll_items drop column class_1 ; alter table poll_items drop column class_2 ; alter table poll_items drop column classp_0 ; alter table poll_items drop column classp_1 ; alter table poll_items drop column classp_2 ; alter table poll_items drop column votes ; alter table poll_items drop column vote_tot ; alter table poll_items drop column num_voted; alter table poll_items add column a_vote_tot integer default 0; -- approval votes total alter table poll_items add column p_vote_tot integer default 0; -- plurality votes total alter table people alter column num set default 0; alter table polls add column discussion_id integer default 0; create table poll_status (id serial not null, name text); insert into poll_status (id,name) values (0, 'In queue'); -- just posted and in queue insert into poll_status (id,name) values (1, 'Posted'); -- published to discussion -- fix default cert_level alter table people alter column cert_level set default 0; update people set cert_level=0 where cert_level is NULL; create table discussions (id serial not null,type_id integer,activity_state integer); update posts set thread=id where parent=0; -- was this necessary? insert into discussions select id,0,1 from posts where parent=0; -- ====================================================================== -- New council stuff --====================================================================== create table councils (id serial not null, name text, discussion_id integer default 0); alter table council_members add column join_date date; -- DONE ON TANG UP TO HERE --====================================================================== -- New locations table --====================================================================== create table locations (id serial not null, parent_id integer default 0, council_id integer,nick text, fullname text, level_id integer, blurb text, pict_id integer); insert into locations(council_id,nick,fullname,level_id,blurb) values(0,'','World',0,'Our beloved Planet Earth'); insert into locations(council_id,nick,fullname,level_id,blurb) values(1,'us','United States',1,'The Land of the Free'); insert into locations(parent_id,council_id,nick,fullname,level_id,blurb) values(1,2,'az','Arizona',2,'It''s a dry heat'); drop table location; drop table towns; drop table states; drop table neighborhoods ; drop table countries; |
Added stml2/example/db/dump_db version [ce7ea67483].
> | 1 | pg_dump -d kiatoa | grep -v 'INSERT INTO session_vars' | grep -v 'INSERT INTO sessions' > Kiatoa.sql |
Added stml2/example/docs/Setup-notes.txt version [5087f9f4e8].
> > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 1) add: host all all 192.168.1.1/32 password to the bottom of /etc/postgresql/8.2/main/pg_hba.conf 2) ln -s /home/matt/kiatoa/kiatoa-scm/kiatoa /var/www 3) copy/update the stml.conf file sudo cp stml.conf.template /usr/lib/cgi-bin/.stml.conf sudo vi /usr/lib/cgi-bin/.stml.conf |
Added stml2/example/docs/comments.txt version [77b3863af7].
> > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | If we had any at all of the alternative voting ideas like instant runoff, Condorcet, any of them, I think it might make the whole process better My thought was to get people familiar with approval voting, then get people to pledge only to vote for a candidate if that candidate supported approval voting. I put the beginings of a site together here: http://approvalvote.org but stopped working on it because I decided not to push the idea for this election. Morally, in my opinion, letting the neocons in for another term is unacceptable, I suspect (but don't know) that McCain is a participant of the neocon movement. Since these elections can hinge on a few hundreds of votes I thought it wasn't worth even the infintesimal risk of any activity that would get people thinking about the alternatives to the top two pulling votes away from Obama. I did think of pushing the idea in venues dominated by interest in Ron Paul but there was some beer in the fridge and, well, you can guess the rest of that story. Although the current implementation needs major rework I do think the idea has potential. 1. Get people to experience plurality vs approval voting. IMHO once you've tried it going back to plurality is actually quite uncomfortable. 2. Get people to pledge to vote only for candidates that support approval voting. 3. Get candidates to address approval voting. Now why approval and not Condorcet, range, IRV or any one of the dozens of other voting techniques? 1. Approval is 100% doable using existing election machines 2. Approval is highly resistant to any meaningful strategic voting. 3. Approval is easy for the end users. Go try doing some condorcet or IRV ranked voting. It is really tedious. 4. IRV is *worse* than Plurality in its vunerablity to strategic voting. 5. Condorcet is too hard to grok for most folks. I knew once how it worked but couldn't explain it to someone right now for the life of me. In short the marginal improvement of the more complex voting solutions over approval doesn't buy much. |
Added stml2/example/example/layout.css version [bbe0114338].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /*-General-----------------------------------------------*/ html, body { margin:0px; padding:0px; } form { display:inline; margin:0px; padding:0px; } a img { border:none; margin:0px; padding:0px; } h1, h2, h3, h4, h5, h6, p, div { margin:0px; padding:0px; } .right { float:right; } .left{ float:left; } /*-Main Layout-------------------------------------------*/ #overall { margin:5px 12px 0px 12px; padding:0px; } /*-Header-------------*/ .header { position:relative; height:90px; } /*-Footer-------------*/ .footer { padding:40px 0px 0px 0px; position:relative; clear:both; } /*-Content Area-------*/ .content { width:100%; } /*-Left Column--------*/ .leftcolumn { float:left; width:145px; margin:5px; } .leftcolumn .node { margin:0px 0px 15px 0px; } .leftcolumn .node h1 { padding:0px 0px 0px 3px; } .leftcolumn .node ul { margin:0px; padding:0px; } .leftcolumn .node li { display:block; padding:0px 0px 0px 3px; margin:0px; } .leftcolumn .node li.more{ padding:0px 0px 0px 6px; } /*-Center Column------*/ .centercolumn { margin: 5px; margin-left:152px; margin-right:200px; font-family:"\"}\""; font-family:inherit; } .centercolumn .node h1 { padding: 0px 0px 0px 13px; } .centercolumn .node h4 { margin: 15px 0px 10px 0px; } .centercolumn .node p { margin: 0px 0px 10px 0px; */ padding: 0px 0px 0px 0px; } /* this seemed not to work */ .posts_0 { margin: 0px 0px 0px 0px; } .posts_1 { margin: 0px 0px 0px 20px; } .posts_2 { margin: 0px 0px 0px 40px; } .posts_3 { margin: 0px 0px 0px 60px; } .posts_4 { margin: 0px 0px 0px 80px; } .posts_5 { margin: 0px 0px 0px 100px; } .posts_6 { margin: 0px 0px 0px 120px; } .posts_7 { margin: 0px 0px 0px 140px; } .posts_8 { margin: 0px 0px 0px 160px; } .posts_9 { margin: 0px 0px 0px 160px; } .posts_10 { margin: 0px 0px 0px 180px; } /*-Right Column-------*/ .rightcolumn { float:right; width:190px; margin:5px 5px 0px 0px; } * html .rightcolumn { margin:3px 3px 3px 3px; } body>div .rightcolumn { margin:0px 0px 0px 0px; } .rightcolumn .node { margin:0px 0px 5px 0px; padding:0px; } .rightcolumn .node h2 { margin:3px 3px 3px 2px; } .rightcolumn .node ul { list-style-position:inside; margin:0px; padding:1px; } .rightcolumn .node ul.none { list-style-position:inside; } .rightcolumn .node ul.dot { list-style-position:inside; } .rightcolumn .node ul.books { list-style-position:outside; margin:0px 0px 0px 35px; } .rightcolumn .node li { padding:0px 0px 0px 3px; margin:0px; } /*-Remaining layout--------------------------------------*/ #title { top: 0px; left: 0px; position: absolute; } #search { float:left; margin:0px 0px 0px 30px; } #randomquote { float:right; margin:0px 30px 0px 0px; } #copyright { text-align:center; padding:15px 0px 0px 0px; margin:0px 0px 0px 0px; clear:both; } #bottomNav { text-align:center; margin:0px 0px 20px 0px; padding:0px; } #oldStuffNav { font-weight:bold; text-align:right; } |
Added stml2/example/example/markup.css version [2ee4a6fa76].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /*-General-----------------------------------------------*/ body { background-color:#ffffff; color:#0f0f0f; font-family:serif; font-weight:normal; text-decoration:none; /* font-size:x-small; */ voice-family:"\"}\""; voice-family:inherit; font-size:small; } html>body { font-size:small; } .strong { font-weight:bold; } #red { color: #ff0000 } /*-Main Markup-------------------------------------------*/ #overall { background-color: #ffffff; color:#000000; } /*-Left Column--------*/ .leftcolumn .node a { color:#006666; background-color:transparent; } .leftcolumn .node p { font-size:1.2em; font-weight:normal; } .leftcolumn .node h1 { font-weight:normal; font-size:1.2em; color:#ffffff; background-color:#000000; /* #005991; #7f9bff #006666; */ } .leftcolumn .node h1 a { color:#ffffff; background-color:transparent; } .leftcolumn .node h2 { font-weight:bold; font-size:.95em; } .leftcolumn .node ul { list-style-type:none; } .leftcolumn .node li.more { font-weight:bold; font-size:.75em; } .leftcolumn .node li.selected { font-weight:bold; font-size:1.18em; color:#000000; background-color:#cccccc; } .leftcolumn .node li.selected a { color:#000000; background-color:transparent; } /*-Center Column for classifieds-*/ .centercolumn .classifieds h1 { font-family:Arial, Helvetica, serif; font-weight:bold; font-size:1.38em; color:#000000; /* ffffff; */ background: #5390b7; /* a6bcac; #0c1e0f; 043b0d; 1a6126; */ } /*-Center Column------*/ .centercolumn .node { font-family:serif; } .centercolumn .node a { color:#006666; background-color:transparent; } .centercolumn .node h1 { font-family:Arial, Helvetica, serif; font-weight:bold; font-size:1.38em; color:#ffffff; background:#000000; /* #005991; */ } /* #006666 /* url('../images/slc.gif') no-repeat; */ .centercolumn .node h1 a { color:#ffffff; background-color:transparent; } .centercolumn .node h2 { font-weight:bold; font-size:1.18em; } .centercolumn .node h3 { font-weight:bold; font-size:.95em; } .centercolumn .node h4 { font-weight:normal; font-size:1.2em; } .centercolumn .node h4 a { font-weight:bold; } .centercolumn .node p { font-weight:normal; } .centercolumn .posts_0 h1 { color:#ffffff; background-color:#606060; font-size:1.18em; } .centercolumn .posts_1 h1 { color:#ffffff; background-color:#606060; font-size:1.18em; } .centercolumn .posts_2 h1 { color:#ffffff; background-color:#606060; font-size:1.18em; } .centercolumn .posts_3 h1 { color:#ffffff; background-color:#606060; font-size:1.18em; } .centercolumn .posts_4 h1 { color:#ffffff; background-color:#606060; font-size:1.18em; } .centercolumn .posts_5 h1 { color:#ffffff; background-color:#606060; font-size:1.18em; } .centercolumn .posts_6 h1 { color:#ffffff; background-color:#606060; font-size:1.18em; } .centercolumn .posts_7 h1 { color:#ffffff; background-color:#606060; font-size:1.18em; } .centercolumn .posts_8 h1 { color:#ffffff; background-color:#606060; font-size:1.18em; } .centercolumn .posts_9 h1 { color:#ffffff; background-color:#606060; font-size:1.18em; } .centercolumn .posts_10 h1 { color:#ffffff; background-color:#606060; font-size:1.18em; } /*-Right Column-------*/ .rightcolumn .node { color:#000000; background-color:#cccccc; font-family:serif; } .rightcolumn .node a { color:#000000; /* #005991; #006666; */ background-color:transparent; } .rightcolumn .node h1 { font-family:Arial, Helvetica, serif; font-weight:bold; font-size:0.95em; /* 1.38em; */ color:#ffffff; background-color: #000000; /* #005991; #006666; */ } .rightcolumn .node h1 a { color:#ffffff; background-color:transparent; } .rightcolumn .node h2 { font-weight:bold; font-size:.95em; } .rightcolumn .node ul.none { list-style-type:none; } .rightcolumn .node ul.dot { list-style-type:none; /* list-style-image:url('../images/listdot.gif'); */ } .rightcolumn .node ul.books { list-style-type:disc; } /*-OSDN Navagation bar-----------------------------------*/ #OSDNNavbar { background-color:#999999; color:#000000; /* #005991; /* #006666; */ } #OSDNNavbar div#links { background-color:#999999; color:#000000; /* #005991; /* #006666; */ } #OSDNNavbar a { background-color: transparent; color: #000000; /* #005991; /* #006666; */ } /*-Remaining layout--------------------------------------*/ #randomquote { font-size:1.2em; font-style:italic; } #copyright { font-size:.75em; font-family:Arial, Helvetica, serif; background-color:transparent; color:#000000; /* #005991; /* #006666; */ } #copyright a { background-color:transparent; color:#000000; /* #005991; /* #006666; */ } #bottomNav { background-color:transparent; color:#000000; /* #005991; /* #006666; */ } #bottomNav a { background-color:transparent; color:#ffffff; } #oldStuffNav { font-weight:bold; } |
Added stml2/example/models/candidate.scm version [70b60eb247].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | ;; Copyright 2007-2008, Matthew Welland. matt@kiatoa.com All rights reserved. ;; ;; models/candidates.scm ;; (define (candidate:get-top n) (dbi:get-rows (s:db) "SELECT DISTINCT id,name,url,party,desc,supports_av,date_added,score,pscore FROM candidates AS c ORDER BY score DESC LIMIT ?;" n)) ;; HERE !!!! getting vote counts... DONT'USE- SEE VOTED INSTEAD (define (candidate:get-votes candidates vote_type) (let ((ids (map (lambda (c)(candidate:get-id c)) candidates))) (dbi:get-rows (s:db) (conc "SELECT id,sum(votes*(1+score)) WHERE vote_date>" (- (current-time) (* 24 60 60 7)) ;; seven days " AND id IN " (apply conc (intersperse ids ",")))))) (define (candidate:get-by-name name) (dbi:get-one-row (s:db) "SELECT id,name,url,party,desc,supports_av,date_added,score,pscore FROM candidates WHERE name=?;" name)) ;; update an existing candidate or create if new (define (candidate:update dat) (let* ((name (candidate:get-name dat)) (olddat (candidate:get-by-name name))) (if olddat (begin (dbi:exec (s:db) "UPDATE candidates SET url=?,party=?,desc=?,supports_av=? WHERE name=?;" (candidate:get-url dat) (candidate:get-party dat) (candidate:get-desc dat) (candidate:get-supports-av dat) name) (candidate:get-by-name name)) (begin (dbi:exec (s:db) "INSERT INTO candidates (name,url,party,desc,supports_av) VALUES(?,?,?,?,?);" name (candidate:get-url dat) (candidate:get-party dat) (candidate:get-desc dat) (candidate:get-supports-av dat)) (candidate:get-by-name name))))) (define (candidate:get-id dat)(vector-ref dat 0)) (define (candidate:get-name dat)(vector-ref dat 1)) (define (candidate:get-url dat)(vector-ref dat 2)) (define (candidate:get-party dat)(vector-ref dat 3)) (define (candidate:get-desc dat)(vector-ref dat 4)) (define (candidate:get-supports-av dat)(vector-ref dat 5)) (define (candidate:get-date-added dat)(vector-ref dat 6)) (define (candidate:get-score dat)(vector-ref dat 7)) (define (candidate:get-pscore dat)(vector-ref dat 8)) (define (candidate:set-id! dat val)(vector-set! dat 0 val)) (define (candidate:set-name! dat val)(vector-set! dat 1 val)) (define (candidate:set-url! dat val)(vector-set! dat 2 val)) (define (candidate:set-party! dat val)(vector-set! dat 3 val)) (define (candidate:set-desc! dat val)(vector-set! dat 4 val)) (define (candidate:set-supports-av! dat val)(vector-set! dat 5 val)) (define (candidate:set-date-added! dat val)(vector-set! dat 6 val)) (define (candidate:set-score! dat val)(vector-set! dat 7 val)) |
Added stml2/example/models/maint.scm version [236b7343e4].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | ;; Copyright 2007-2008, Matthew Welland. matt@kiatoa.com All rights reserved. ;; ;; maint/control.scm ;; ;; evolve your schema here! ;; Add entries and then go to http:/your-url/maint ;; ;; first make maint:db available as a global ;; (define maint:db (slot-ref s:session 'conn)) ;; you can store lambda's or SQL queries to be exectuted ;; be extremely careful - especially with the lambda's!!! (define maint:schema-updates (list (list 1 (lambda ()(keystore:set! maint:db "MAINTPW" "Abc123"))) (list 2 "CREATE TABLE people (id INTEGER PRIMARY KEY,name TEXT DEFAULT '',nick TEXT DEFAULT '',email TEXT,password TEXT,status INTEGER DEFAULT 0,score INTEGER DEFAULT 0,location_id INTEGER DEFAULT 0);") (list 3 "CREATE TABLE candidates (id INTEGER PRIMARY KEY,name TEXT DEFAULT '',url TEXT DEFAULT '',party TEXT DEFAULT '',desc TEXT DEFAULT '',supports_av INTEGER,date_added DATETIME,score INTEGER DEFAULT 0);") (list 4 "CREATE TABLE votes (id INTEGER PRIMARY KEY,candidate_id INTEGER,vote_date INTEGER,votes INTEGER,score INTEGER,vote_type INTEGER);") (list 5 "CREATE TABLE voted (id INTEGER PRIMARY KEY,user_id INTEGER,vote_date INTEGER,score INTEGER);") ;; location_type can be: city, town, state, region, county etc (list 6 "CREATE TABLE locations (id INTEGER PRIMARY KEY,parent_id INTEGER,codename TEXT,name TEXT,location_type TEXT,desc TEXT,url TEXT);") (list 7 "INSERT INTO locations VALUES(0,0,'ea','earth','planet','Home Planet of Humans','');") (list 8 "ALTER TABLE candidates ADD column pscore INTEGER DEFAULT 0;") )) (define (maint:am-i-maint?) ;; Enter a maint password - return #t if good #t) (define (maint:update-tables) (let* ((db (slot-ref s:session 'conn)) (curr-ver (s:any->number (keystore:get db "SCHEMA-VERSION")))) (if (not curr-ver) (begin (keystore:set! (slot-ref s:session 'conn) "SCHEMA-VERSION" 0) (set! curr-ver 0))) (if (null? maint:schema-updates) (keystore:set! (slot-ref s:session 'conn) "SCHEMA-VERSION" 0) (let loop ((hed (car maint:schema-updates)) (tal (cdr maint:schema-updates)) (highest-ver 0)) (if (< (length hed) 2) (s:log "Malformed maint:schema-updates table in maint/control.scm") (let ((ver (car hed)) (act (cadr hed))) (if (> ver curr-ver) ;; need to apply this one (begin (if (string? act) (dbi:exec db act) (act)) ;; yes, do this for each one, just in case of a crash (keystore:set! db "SCHEMA-VERSION" ver))) (if (null? tal) highest-ver (loop (car tal)(cdr tal) ver)))))))) |
Added stml2/example/models/person.scm version [13b176d6ef].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 2007-2008, Matthew Welland. matt@kiatoa.com All rights reserved. ;; ;; models/person.scm ;; (require "md5") (define (person:get-dat email) (dbi:get-one-row (s:db) "SELECT id,name,email,status,password,score FROM people WHERE email=?;" email)) ;; this effectively auto logs in using "" as the password (define (person:create-or-get email) (let ((dat (person:get-dat email))) (if dat (person:authenticate email "") (person:set-password email "")))) (define (person:password-match? password cryptedpw) (string=? (md5:digest password) cryptedpw)) (define (person:authenticate email password) (let ((pdat (person:get-dat email))) (if pdat ;; (if (s:password-match? password (vector-ref pdat 4)) (if (person:password-match? password (vector-ref pdat 4)) pdat ;; password matched, return basic record id,name,email,status #f) #f))) ;; sets password, creates user if doesn't exist (define (person:set-password email password) (let ((pdat (person:get-dat email)) ;; (cpwd (s:crypt-passwd password #f))) (cpwd (md5:digest password))) (if pdat (dbi:exec (s:db) "UPDATE people SET password=? WHERE email=?;" cpwd email) (dbi:exec (s:db) "INSERT INTO people (name,email,password) VALUES(?,?,?);" "" email cpwd)) (if pdat pdat (person:get-dat email)))) (define (person:learn_enabled? email) (eq? (dbi:get-one (s:db) "SELECT status FROM people WHERE email=?;" email) 1)) (define(person:files_enabled? email) #f) ;; id,name,email,status,password,score (define (person:get-id dat)(vector-ref dat 0)) (define (person:get-name dat)(vector-ref dat 1)) (define (person:get-email dat)(vector-ref dat 2)) (define (person:get-status dat)(vector-ref dat 3)) (define (person:get-password dat)(vector-ref dat 4)) (define (person:get-score dat)(vector-ref dat 5)) (define (person:set-id! dat val)(vector-set! dat 0 val)) (define (person:set-name! dat val)(vector-set! dat 1 val)) (define (person:set-email! dat val)(vector-set! dat 2 val)) (define (person:set-status! dat val)(vector-set! dat 3 val)) (define (person:set-password! dat val)(vector-set! dat 4 val)) (define (person:set-score! dat val)(vector-set! dat 5 val)) |
Added stml2/example/models/voting.scm version [5caf28d651].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 2007-2008, Matthew Welland. matt@kiatoa.com All rights reserved. ;; ;; models/voting.scm ;; ;; store the votes! ;; look up the entry to which to add (define (voting:get-entry-id candidate-id score type) (dbi:get-one (s:db) "SELECT id FROM votes WHERE candidate_id=? AND score=? AND vote_type=? AND vote_date>?;" candidate-id score type (- (current-seconds) 86400))) ;; i.e. since 24 hrs ago (define (voting:apply-vote dat candidate-id vote-type) (let* ((score (person:get-score dat)) (vote-entry-id (voting:get-entry-id candidate-id score vote-type))) (if vote-entry-id (dbi:exec (s:db) "UPDATE votes SET votes=votes+1 WHERE id=?;" vote-entry-id) (dbi:exec (s:db) "INSERT INTO votes (candidate_id,vote_date,votes,score,vote_type) VALUES(?,?,?,?,?);" candidate-id (current-seconds) 1 score vote-type)))) (define (voting:rollup-votes) (let ((adat (dbi:get-rows (s:db) "SELECT candidate_id AS id,SUM(votes*(score+1)) AS score FROM votes WHERE vote_date>? AND vote_type=1 GROUP BY candidate_id;" (- (current-seconds) (* 24 60 60 7)))) (pdat (dbi:get-rows (s:db) "SELECT candidate_id AS id,SUM(votes*(score+1)) AS score FROM votes WHERE vote_date>? AND vote_type=0 GROUP BY candidate_id;" (- (current-seconds) (* 24 60 60 7))))) (for-each (lambda (row) (dbi:exec (s:db) "UPDATE candidates SET score=? WHERE id=?;" (vector-ref row 1)(vector-ref row 0))) adat) (for-each (lambda (row) (dbi:exec (s:db) "UPDATE candidates SET pscore=? WHERE id=?;" (vector-ref row 1)(vector-ref row 0))) pdat))) ;; vote_type: 0=plurality, 1=approval (define (voting:handle-votes email approval plurality) (let* ((pdat (let ((e (s:session-var-get "email"))) (if e (person:get-dat e) (person:create-or-get (if (or (not (string? email)) (string-match (regexp "^\\s*$") email)) "noname" email)))))) ;; is this really the logic I wanted? ;; (s:log "Got here eh!" " pdat: " pdat) (if (not pdat) (s:set! "errmsg" "Failed to auto log in/register, email or nick already in use. Consider reseting your password") (begin (s:session-var-set! "email" (person:get-email pdat)) (voting:apply-vote pdat plurality 0) (map (lambda (candidate-id) (voting:apply-vote pdat candidate-id 1)) approval) (voting:rollup-votes))))) |
Added stml2/example/pages/action/view.scm version [e72ae3f7dd].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | ;; Copyright 2007-2008, Matthew Welland. Kiatoa.com All rights reserved. ;; (s:div 'class "node" (s:h1 "Approval voting works") "<p>Approval voting is very resistant to strategic voting and it is extremely easy to implement using existing ballot technology. <p>Every four years voters must make a painful strategic choice, either vote for the candidate they <b><i>really</i></b> want and risk getting saddled with a candidate they <b><i>don't</b></i> want, OR vote for the most palatable frontrunner, and send a false message of disinterest in their true choice." (s:h1 "Thinking is required for a democracy to work") "<p>Consider trying the "fool test" on an unsuspecting friend or aquaintence. . Pick a popular smear or other known distortion aimed at a candidate you suspect your "person under test", or PUT, doesn't like. Research the item and find out the truth about it as best you can. Start with <A target=\"_blank\" href=\"http://factcheck.org\"> factcheck.org</a> but don't stop there. Use google or other search engines to build up a picture of what is true. <p>Once you are armed with information you can apply the test. Ask your friend or collegue for the truth behind the smear. Be neutral. Accept their answer without judgement if it is incorrect. Say "oh", or "thanks" and let it be at that. Again, DO NOT CORRECT THEM! <p>If your PUT fails the test don't harp on them or correct them. Although everyone is responsible for researching the facts many people will lock onto their existing ideas if challenged. Instead say something like, "you may want to research that" and accept that you are dealing with someone who just might be a fool, unwilling or unable to look at their favorite candidate with a critical eye. <p>Finally, be prepared to be tested yourself, aggressively research the smears your favored candidates put out. If they are true be prepared to prove it, if they are false, be prepared to put them in context or simply admit they are false. No candidate will be perfect." (s:h1 "A strategy for change") "<p>Get a yes/no answer from your favored candidate about approval voting. If your candidate refuses to support approval voting first hear them out. If their reasons are good then publish them so we can all learn from it. If their reasons are weak then look for an alternative candidate to support. <p>Improve your score here on approvalvote.org and then vote again in our front page poll. Your score will adjust the power of your vote such that the poll will reflect the choices of those who are willing to think. We will advocate that everyone votes for an approval vote supporting independant candidate if that candidate is at least 10% ahead of the next candidate of the same leaning (i.e. liberal or conservative). Otherwise you should vote for the frontrunner candidate of your choosen leaning due to the dangers of plurality voting.") |
Added stml2/example/pages/footer/view.scm version [619df4dd0e].
> > > > > | 1 2 3 4 5 | ;; Copyright 2007-2008, Matthew Welland. Kiatoa.com All rights reserved. ;; ;; footer (list (s:div 'class "node" "This is the footer")) |
Added stml2/example/pages/header/control.scm version [c7463c753e].
> > > > > > > > > | 1 2 3 4 5 6 7 8 9 | ;; Copyright 2007-2008, Matthew Welland. Kiatoa.com All rights reserved. ;; ;; header/control.scm ;; (load (s:model-path "blah")) (define header:menu-items '(("home" "Home")("learn" "Learn")("action" "Take Action")("discussion" "Discussion") ("preferences" "Preferences"))) (define header:title (let ((t (s:get-param 'section))) (if t t "Home"))) |
Added stml2/example/pages/header/view.scm version [c14538dbad].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 2007-2008, Matthew Welland. Kiatoa.com All rights reserved. ;; ;; header/view.scm ;; (list ;; (s:div 'id "titlebar" (s:table (s:tr (s:td (s:img 'src "/www/images/approvalvote.png" 'alt "ApprovalVote.com" 'title "Welcome to ApprovalVote.com")) (s:td 'valign "top" 'align "right" (s:table 'border "0" 'cellspacing "0" (s:tr (s:td 'valign "center" ;; 'width "250" ;; 'rowspan "2" (s:a (s:small " * NOW IS A GREAT TIME TO PUSH FOR APPROVAL VOTING! * ")) (s:br))) (s:tr (s:td 'columnspan="3" (s:center "*********")))))) ;; header:title)))))) ;; this is the horizontal menus (s:tr 'columnspan "4" (s:table (s:tr (map (lambda (m-item) (s:td (s:small "[" (s:a 'href (s:link-to (car m-item))(cadr m-item)) "]"))) header:menu-items) )))));; ) |
Added stml2/example/pages/home/view.scm version [03740d3139].
> > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 | ;; Copyright 2007-2008, Matthew Welland. Kiatoa.com All rights reserved. ;; (s:div 'class "node" (s:h1 "Please Help Save Our Democracy.") "<p>We need approval voting to re-energize our democracy. Our system is in danger of failing us since it leaves us powerless to force change. Arguably the biggest problem lies in our use of plurality voting to choose leaders. ") (s:div 'class "node" (s:h1 "Practice some approval voting now!") (s:call "uspresident")) |
Added stml2/example/pages/index/control.scm version [733e1bc04a].
> > > > > > | 1 2 3 4 5 6 | ;; Copyright 2007-2008, Matthew Welland. Kiatoa.com All rights reserved. ;; ;; this gets read for ALL pages. Don't weigh it down excessively! ;; ;; index/control.scm |
Added stml2/example/pages/index/view.scm version [e6eeff7675].
> > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | ;; Copyright 2007-2008, Matthew Welland. Kiatoa.com All rights reserved. ;; ;; index (list (s:html (s:head (s:title "Approval Voting Now!") (s:link 'rel "stylesheet" 'type "text/css" 'href "/approvalvote/markup.css") (s:link 'rel "stylesheet" 'type "text/css" 'href "/approvalvote/layout.css")) (s:body (s:div 'class "header" (s:call "header")) (s:div 'class "rightcolumn" (s:call "rightcol")) (s:div 'class "leftcolumn" (s:call "leftnav")) (s:div 'class "centercolumn" (let ((page (slot-ref s:session 'page))) (if page (s:call page) (list (s:h2 "Home") (s:call "sys-state"))))) (s:div 'class "footer" (s:call "footer"))))) |
Added stml2/example/pages/learn/view.scm version [d368f45a4d].
> > > > > > > | 1 2 3 4 5 6 7 | ;; Copyright 2007-2008, Matthew Welland. Kiatoa.com All rights reserved. ;; (s:div 'class "node" (s:h1 "Resources") "<p>Two excellent sites with more information on approval voting: <p><A target=\"_blank\" href=\"http://approvalvoting.org\">approvalvoting.org</a> <p><a target=\"_blank\" href=\"http://approvalvoting.com\">approvalvoting.com</a>") |
Added stml2/example/pages/leftnav/control.scm version [077adf479c].
> > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 | ;; Copyright 2007-2008, Matthew Welland. Kiatoa.com All rights reserved. ;; ;; leftnav/control.scm ;; nothing needed here yet! (define (leftnav-action action) (case action ('logout (s:logout)))) |
Added stml2/example/pages/leftnav/view.scm version [29c5bd43ae].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 2007-2008, Matthew Welland. Kiatoa.com All rights reserved. ;; ;; leftnav/view.scm (list (s:div 'class "node" (s:h1 "Navigation") (let ((section (slot-ref s:session 'page))) (cond ((or (not section) ;; this is home (string=? section "home")) "Home menu") ((string=? section "discussions") (list (s:a "Filter" 'href (s:link-to "discussions" 'filter "on")))) ((string=? section "learn") (list (s:a "Learn" 'href (s:link-to "learn" 'action "learn.teach"))(s:br) (s:a "Test" 'href (s:link-to "learn" 'action "learn.test"))(s:br) )) ((string=? section "preferences") (list (s:a "Password" 'href (s:link-to "preferences" 'action "password"))(s:br) (s:a "Messages" 'href (s:link-to "preferences" 'action "messages"))(s:br) (s:a "Preferences" 'href (s:link-to "preferences" 'action "preferences"))(s:br))) (else '( "nada" )))) (s:br)) (s:div 'class "node" (s:h1 "About you") (let ((email (s:session-var-get "email"))) (if email (list email (s:br)) "Not logged in"))) (s:div 'class "node" (s:call "pledge"))) |
Added stml2/example/pages/login/control.scm version [878dfed9da].
> > > > > > > > > > > > > > > > > > > > > > > > > | 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 2007-2008, Matthew Welland. Kiatoa.com All rights reserved. ;; (load (s:model-path "person")) (define (login-action action) (case (string->symbol action) ('login ;; the actual login code (s:log "Got here, doing login") (let ((email (s:get-input 'email-address)) (passwd (s:get-input 'password))) ;; (person (make-person))) ;; DO WE NEED A PERSON "OBJECT"? (s:set! "email-address" email) ;; preserve user as email-address (if (and email passwd) (let ((good-login (person:authenticate email passwd))) (if good-login (begin (s:set! "msg" "Login successful!") (s:session-var-set! "email" email)) (s:set! "msg" "Bad password or email. Please try again"))) (s:set! "msg" "Missing password or email")))) ('logout (s:delete-session)) ('nada (s:log "Got here, action=" action)))) |
Added stml2/example/pages/login/view.scm version [2971ee1fb1].
> > > > > > > > > > > > > > > > > > > > > > > > | 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-2008, Matthew Welland. Kiatoa.com All rights reserved. ;; ;; Login view (s:div 'class "node" ;; (s:p (s:get-err s:strong)) ;; error message (if (s:session-var-get "email") (s:a "Log out" 'href (s:link-to (s:current-page) 'action "login.logout")) (list (s:center (s:p (s:strong "Log in here!"))) (let ((msg (s:get "msg"))) (if msg (begin (s:del! "msg") (s:err-font msg)) (s:null ""))) (s:form 'action "login.login" 'method "post" (s:strong "Id: (*)")(s:br) (s:input-preserve 'type "text" 'name "email-address" 'size "14" 'maxlength "30")(s:br) (s:strong "Password:")(s:br) (s:input 'type "password" 'name "password" 'size "14" 'maxlength "30")(s:br) (s:input 'type "submit" 'name "form-name" 'value "login")(s:br) (s:a "Create account" 'href (s:link-to "new_account")) )))) |
Added stml2/example/pages/maint/control.scm version [b0f23bc746].
> > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 | ;; Copyright 2007-2008, Matthew Welland. matt@kiatoa.com All rights reserved. ;; ;; maint/control.scm ;; (s:load-model "maint") ;; remember that the system will call the function <pagename>-action with the action as a parameter (define (maint-action action) (let ((asym (string->symbol action))) (s:log "Doing action! " action) (case asym ('update_tables (maint:update-tables))))) |
Added stml2/example/pages/maint/view.scm version [7f97c343f3].
> > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 | ;; Copyright 2007-2008, Matthew Welland. Kiatoa.com All rights reserved. ;; ;; maint/view.scm ;; (if (maint:am-i-maint?) (list (s:h1 "Hello Maint!") (s:p (s:a "Update Tables" 'href (s:link-to (s:current-page) 'action "maint.update_tables")))) '()) |
Added stml2/example/pages/new_account/control.scm version [79ed917ee5].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 2007-2008, Matthew Welland. matt@iatoa.com All rights reserved. ;; ;; new_account/control.scm (load (s:model-path "person")) (define (new_account:validate-inputs password password-again email-address email-address-again) (cond ((or (not password)(not password-again) (not email-address)(not email-address-again)) (s:set-err "Form is incomplete. Please fill in all fields and try again") #f) ((< (string-length password) 2) (s:set-err "Password is too short. Please try again") #f) ((not (string=? password password-again)) (s:set-err "Passwords do not match. Please try again") #f) ((> (string-length password) 9) (s:set-err "Password is too long. Please try again") #f) ((not (string=? email-address email-address-again)) (s:set-err "Email addresses provided do not match. Please try again") #f) ((and (not (string-match (regexp "^\\s*$") email-address)) (not (string-match (regexp "^[^@]+@[^@]+\\.[^@]+$") email-address))) (s:set-err "Not a valid email address, please try again") #f) (else #t))) (define (new_account-action action) (case (string->symbol action) ('create (s:log "Got here, doing create new account") (let ((password (s:get-input 'password)) (password-again (s:get-input 'password-again)) (email-address (s:string-downcase (s:get-input 'email-address))) (email-address-again (s:string-downcase (s:get-input 'email-address-again)))) ;; save preserved inputs (s:set! "email-address" email-address) (s:log "Saved inputs. Now check inputs") (if (new_account:validate-inputs password password-again email-address email-address-again) ;; Great!! Now have good inputs (if (person:get-dat email-address) (s:set-err "There is already an account for that email address!") (let ((pdat (person:set-password email-address password))) (if pdat (s:set-err "SUCCESS!! You can now log in with " email-address " and your password") (s:set-err "ERROR!! Unable to automatically log you on with the same credentials used to create your account. This shouldn't happen. Please send email to matt@kiatoa.com about this")))) ;; bad inputs #f))) ('else (s:log "Placeholder for future actions. Shouldn't get here")))) |
Added stml2/example/pages/new_account/view.scm version [bc26c5b01c].
> > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 2007-2008, Matthew Welland. Kiatoa.com All rights reserved. ;; ;; new_account/view.scm ;; (list (s:div 'class "node" ;; (s:p (s:get-err s:strong)) ;; error message (s:p "")(s:p (s:get-err s:err-font)) (if (not (s:session-var-get "email")) ;; setting email defines "logged in" (s:form 'action "new_account.create" 'method "post" (s:table 'border "0" 'spacing "0" (s:tr (s:td (s:strong "Email address:")) ;; (s:br) (s:td (s:input-preserve 'type "text" 'name "email-address" 'size "16" 'maxlength "30"))) ;; (s:br) (s:tr (s:td (s:strong "Email address again:")) ;; (s:br) (s:td (s:input-preserve 'type "text" 'name "email-address-again" 'size "16" 'maxlength "30"))) ;; (s:br) (s:tr (s:td (s:strong "Password:")) ;; (s:br) (s:td (s:input 'type "password" 'name "password" 'size "16" 'maxlength "16"))) ;; (s:br) (s:tr (s:td (s:strong "Password again:")) ;; (s:br) (s:td (s:input 'type "password" 'name "password-again" 'size "16" 'maxlength "16")))); (s:br) (s:input 'type "submit" 'name "form-name" 'value "submit")) (s:h1 "Welcome " (s:session-var-get "email") ":" (s:session-var-get "location") "!")))) |
Added stml2/example/pages/pledge/view.scm version [7d0aadf21d].
> > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | ;; Copyright 2007-2008, Matthew Welland. matt@iatoa.com All rights reserved. ;; (s:if-sessionvar "email" (list (s:h1 "Pledge now!") (s:fieldset "Pledge" (s:form 'action "pledge.pledge" 'method "post" (s:i " - I will vote" (s:b "ONLY") " for a candidate who supports approval voting!") (s:table (s:tr (s:td "Yes") (s:td (s:input 'type "radio" 'name "pledge_answer" 'value "yes"))) (s:tr (s:td "No") (s:td (s:input 'type "radio" 'name "pledge_answer" 'value "no"))) (s:tr (s:td "Maybe")(s:td (s:input 'type "radio" 'name "pledge_answer" 'value "maybe")))) (s:input 'type "button" 'name "pledge_answer" 'value "Submit"))))) |
Added stml2/example/pages/preferences/view.scm version [fb61146f52].
> > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 | ;; Copyright 2007-2008, Matthew Welland. matt@iatoa.com All rights reserved. ;; ;; preferences/view.scm ;; (s:div 'class "node" (s:h1 "Register your email address") (s:p "Adds 9 pts to your score the first time you do it and enables very occasional email updates. If you change your email address you need to re-register to keep your 9 pts.") (s:form 'action "preferences.register_email" 'method "post" (s:input 'type "submit" 'name "register_email" 'value "Register Email"))) |
Added stml2/example/pages/rightcol/view.scm version [f05a664b96].
> > > > > > > > > | 1 2 3 4 5 6 7 8 9 | ;; Copyright 2007-2008, Matthew Welland. Kiatoa.com All rights reserved. ;; ;; rightcol (list (s:div 'class "node" (s:call "login"))) ;; "This is the right-most column")) |
Added stml2/example/pages/sys-state/view.scm version [b45ac32796].
> > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | ;; Copyright 2007-2008, Matthew Welland. Kiatoa.com All rights reserved. ;; ;; sys-state (list (let ((p (open-input-pipe "env"))) (let loop ((l (read-line p)) (res '())) (if (not (eof-object? l)) (loop (read-line p)(cons (list l "<BR>") res)) res))) ;; "USER=" (user-information (current-user-id)) (s:h2 "Form data") (session:pp-formdat s:session) "argv=" (argv)) |
Added stml2/example/pages/uspresident/control.scm version [0387534663].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | ;; Copyright 2007-2008, Matthew Welland. Kiatoa.com All rights reserved. ;; ;; this gets read for ALL pages. Don't weigh it down excessively! ;; ;; uspresident/control.scm (s:load-model "candidate") (s:load-model "voting") (s:load-model "person") (define candidates (candidate:get-top 10)) (define candidates:vote-sum-approval (apply + (map candidate:get-score candidates))) (define candidates:vote-sum-plurality (apply + (map candidate:get-pscore candidates))) (define candidates:top-plurality-id (let ((id #f) (topscore 0)) (for-each (lambda (cand) (if (> (candidate:get-pscore cand) topscore) (begin (set! topscore (candidate:get-pscore cand)) (set! id (candidate:get-id cand))))) candidates) id)) (define candidates:top-approval-id (let ((id #f) (topscore 0)) (for-each (lambda (cand) (if (> (candidate:get-score cand) topscore) (begin (set! topscore (candidate:get-score cand)) (set! id (candidate:get-id cand))))) candidates) id)) (define (uspresident-action action) (let ((acsym (string->symbol action))) (cond ('vote (let ((button (s:get-input 'vote))) (cond ((equal? button "Vote") (let* ((approval (s:get-input 'approval)) (plurality (s:get-input 'plurality)) (newdat (make-vector 9 "")) (email (s:session-var-get "email")) (newcandname (s:get-input 'poll_name)) (nick-email (if email email (s:get-input 'users_email)))) (if (not (list? approval)) (set! approval (list approval))) (if (string-match (regexp "^[a-zA-Z]+") newcandname) (let* ((dat (candidate:get-by-name newcandname))) (if dat ;; i.e. this is a new candidate (set! newdat dat) (begin (candidate:set-name! newdat newcandname) (candidate:set-supports-av! newdat (s:get-input 'poll_supports_av)) (candidate:set-party! newdat (s:get-input 'poll_party)) (candidate:set-url! newdat (s:get-input 'poll_url)) (set! newdat (candidate:update newdat)))) (s:log "cid: " (candidate:get-id newdat)) (set! approval (cons (candidate:get-id newdat) approval)) (set! plurality (candidate:get-id newdat)))) (set! approval (filter (lambda (x)(or (number? x)(string? x))) approval)) ;; clean the approval list (s:log "using email: " nick-email) (s:log "approval: " approval) (s:log "plurality: " plurality) (if (and approval plurality (not (null? approval))) (begin (voting:handle-votes nick-email approval plurality) (s:session-var-set! "voted" "yes")) (s:set! "errmsg" "Please select one plurality vote and one or more approval votes")))))))))) |
Added stml2/example/pages/uspresident/view.scm version [00ad05ecb3].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 2007-2008, Matthew Welland. Kiatoa.com All rights reserved. ;; ;; Note: the (list is actually no longer needed. (list (s:if-sessionvar "email" (s:if-sessionvar "voted" "We are glad you tried approval voting. Try again to see how the system works. Don't worry about the poll numbers. This poll is for you to play with.")) (s:fieldset "Poll" (s:center (s:if-param "errmsg" (let ((err (s:get "errmsg"))) (s:del! "errmsg") (s:err-font err))) (s:form 'action "uspresident.vote" 'method "post" (s:table 'border "1" 'cellspacing "0" (s:tr (s:td "Candidate")(s:td "Party")(s:td "Supports approval?") (s:if-sessionvar "voted" (list (s:td "Plurality") (s:td "Approval") (s:td "Plurality" (conc "(" candidates:vote-sum-plurality "votes" ")")) (s:td "Approval" (conc "(" candidates:vote-sum-plurality "votes" ")"))) (list (s:td "Plurality (vote for one only)")(s:td "Approval (vote for all which you approve of)")))) ;; map the poll items for each row (map (lambda (candidate) (let ((poll-item-id (number->string (candidate:get-id candidate))) (poll-item-url (s:tidy-url (candidate:get-url candidate))) (poll-item-name (candidate:get-name candidate)) (poll-item-description (candidate:get-desc candidate)) (poll-item-percent-a (quotient (* 100 (candidate:get-score candidate)) candidates:vote-sum-plurality)) (poll-item-percent-p (quotient (* 100 (candidate:get-pscore candidate)) candidates:vote-sum-plurality))) (list (s:tr (s:td (if poll-item-url (s:a 'href poll-item-url 'target "_blank" poll-item-name) poll-item-name)) ;; (if (poll:poll 'have-description?) ;; (s:td 'bgcolor "#f0f0f0" poll-item-description) ;; description ;; '()) (s:td (candidate:get-party candidate)) (s:td (candidate:get-supports-av candidate)) ;; (if (not (s:session-var-get "voted")) ;; here are the check buttons for plurality and approval voting ;; (list (s:td (s:center (s:input 'type "radio" 'name "plurality" 'value poll-item-id))) (s:td (s:center (s:input 'type "checkbox" 'name "approval" 'value poll-item-id))) (s:if-sessionvar "voted" (list (s:td (conc poll-item-percent-p "%") 'bgcolor (if (eq? (candidate:get-id candidate) candidates:top-plurality-id) "cyan" "lightgrey") (conc "(" (candidate:get-pscore candidate) ")") 'align "center") (s:td (conc poll-item-percent-a "%") 'bgcolor (if (eq? (candidate:get-id candidate) candidates:top-approval-id) "cyan" "lightgrey") (conc "(" (candidate:get-score candidate) ")") 'align "center"))))))) ;; % votes candidates) (s:tr (s:td "Write in (name):<br>" (s:input-preserve 'type "text" 'name "poll_name" 'size "15" 'maxlength "40")) (s:td "Party:<br>" (s:input-preserve 'type "text" 'name "poll_party" 'size "10" 'maxlength "40")) (s:td "Supports approval:<br>" (s:input-preserve 'type "text" 'name "poll_supports_av" 'size "10" 'maxlength "40")) (s:td "Url:<br>" (s:input-preserve 'type "text" 'name "poll_url" 'size "40" 'maxlength "120") 'colspan 4)) (s:tr (s:td 'colspan 7 (s:center (s:input 'type "submit" 'name "vote" 'value "Vote") (s:if-sessionvar "email" '() (list "Email or nickname:" (s:input-preserve 'type "text" 'name "users_email" 'size 20 'maxlength 40) "(required), Country code:" (s:input-preserve 'type "text" 'name "users_country_code" 'size 2 'maxlength 2) "(optional)" )) )))))))) |
Added stml2/example/tests/test.scm version [f614028724].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | #!/usr/local/bin/csi -q ;; This currently requires that the stml code is available in a parallel directory. (use test) (if (file-exists? "test.db") (begin (print "Removing old test.db") (system "rm -f test.db"))) (load "../stml/misc-stml.scm") (load "../stml/formdat.scm") (load "../stml/stml.scm") (load "../stml/session.scm") (load "../stml/sqltbl.scm") (load "../stml/html-filter.scm") ;; required for s:split-string (load "../stml/dbi.scm") (load "../stml/keystore.scm") (load "../stml/sugar.scm") ;; create a session to work with") (setenv "REQUEST_URI" "/stmlrun?action=maint.nada") (setenv "SCRIPT_NAME" "/cgi-bin/stmlrun") (setenv "PATH_INFO" "/maint") (setenv "QUERY_STRING" "action=maint.nada") (setenv "SERVER_NAME" "localhost") (setenv "REQUEST_METHOD" "GET") ;; (define session-name "pfNOeqUHkJ26BpU6y49IN") ;; ensure this session already exists ;; (setenv "HTTP_COOKIE" (string-append "session_key=" session-name)) ;; to09ipFJ9_2KXT96b2f9Q") (load "../stml/setup.scm") ;; (test (string-append "Session set to existing session " session-name) ;; session-name (slot-ref s:session 'session-key)) (s:validate-inputs) ;; test session variables ;; lazy stuff (define *conn* (slot-ref s:session 'conn)) ;; setup tables (load "models/maint.scm") (test "Create tables" #t (> (maint:update-tables) 0)) ;; test person (let ((fh (open-input-pipe "ls models/*.scm"))) (let loop ((l (read-line fh))) (if (not (eof-object? l)) (begin (print "loading " l) (load l) (loop (read-line fh))))) (close-input-port fh)) (let ((fh (open-input-pipe "find pages -name control.scm"))) ;; ls pages/*/control.scm"))) (let loop ((l (read-line fh))) (if (not (eof-object? l)) (begin (print "loading " l) (load l) (loop (read-line fh))))) (close-input-port fh)) (let ((fh (open-input-pipe "ls pages/*/view.scm"))) (let loop ((l (read-line fh))) (if (not (eof-object? l)) (begin (print "loading " l) (load l) (loop (read-line fh))))) (close-input-port fh)) ;;====================================================================== ;; Maint ;;====================================================================== ;; (load "models/maint.scm") (test "Update tables" #t (> (maint:update-tables))) ;; *conn* 2 "us") 0)) (test "Add user" "matt@kiatoa.com" (vector-ref (person:set-password "matt@kiatoa.com" "Password") 2)) (test "Authenticate" "matt@kiatoa.com" (vector-ref (person:authenticate "matt@kiatoa.com" "Password") 2)) (test "Validate inputs" #t (new_account:validate-inputs "Password" "Password" "matt@kiatoa.com" "matt@kiatoa.com")) |
Added stml2/example/www/layout.css version [c0a14ff4c4].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /*-General-----------------------------------------------*/ html, body { margin:0px; padding:0px; } form { display:inline; margin:0px; padding:0px; } a img { border:none; margin:0px; padding:0px; } h1, h2, h3, h4, h5, h6, p, div { margin:0px; padding:0px; } .right { float:right; } .left{ float:left; } /*-Main Layout-------------------------------------------*/ #overall { /* margin:5px 12px 0px 12px; */ padding:0px; } /*-Header-------------*/ .header { /* float:top; */ position:relative; height:55px; } /*-Footer-------------*/ .footer { padding:40px 0px 0px 0px; position:relative; clear:both; } /*-Content Area-------*/ .content { width:100%; } /*-Left Column--------*/ .leftcolumn { float:left; width:145px; margin:5px; } .leftcolumn .node { margin:0px 0px 15px 0px; } .leftcolumn .node h1 { padding:0px 0px 0px 3px; } .leftcolumn .node ul { margin:0px; padding:0px; } .leftcolumn .node li { display:block; padding:0px 0px 0px 3px; margin:0px; } .leftcolumn .node li.more{ padding:0px 0px 0px 6px; } /*-Center Column------*/ .centercolumn { margin: 5px; margin-left:152px; margin-right:140px; font-family:"\"}\""; font-family:inherit; } .centercolumn .node h1 { padding: 0px 0px 0px 13px; } .centercolumn .node h4 { margin: 15px 0px 10px 0px; } .centercolumn .node p { margin: 0px 0px 10px 0px; */ padding: 0px 0px 0px 0px; } /* this seemed not to work */ .posts_0 { margin: 0px 0px 0px 0px; } .posts_1 { margin: 0px 0px 0px 20px; } .posts_2 { margin: 0px 0px 0px 40px; } .posts_3 { margin: 0px 0px 0px 60px; } .posts_4 { margin: 0px 0px 0px 80px; } .posts_5 { margin: 0px 0px 0px 100px; } .posts_6 { margin: 0px 0px 0px 120px; } .posts_7 { margin: 0px 0px 0px 140px; } .posts_8 { margin: 0px 0px 0px 160px; } .posts_9 { margin: 0px 0px 0px 160px; } .posts_10 { margin: 0px 0px 0px 180px; } /*-Right Column-------*/ .rightcolumn { float:right; width:130px; margin:5px 5px 0px 0px; } * html .rightcolumn { margin:3px 3px 3px 3px; } body>div .rightcolumn { margin:0px 0px 0px 0px; } .rightcolumn .node { margin:0px 0px 5px 0px; padding:0px; } .rightcolumn .node h2 { margin:3px 3px 3px 2px; } .rightcolumn .node ul { list-style-position:inside; margin:0px; padding:1px; } .rightcolumn .node ul.none { list-style-position:inside; } .rightcolumn .node ul.dot { list-style-position:inside; } .rightcolumn .node ul.books { list-style-position:outside; margin:0px 0px 0px 35px; } .rightcolumn .node li { padding:0px 0px 0px 3px; margin:0px; } /*-Remaining layout--------------------------------------*/ #title { top: 0px; left: 0px; position: absolute; } #search { float:left; margin:0px 0px 0px 30px; } #randomquote { float:right; margin:0px 30px 0px 0px; } #copyright { text-align:center; padding:15px 0px 0px 0px; margin:0px 0px 0px 0px; clear:both; } #bottomNav { text-align:center; margin:0px 0px 20px 0px; padding:0px; } #oldStuffNav { font-weight:bold; text-align:right; } |
Added stml2/example/www/markup.css version [45cda36b65].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /*-General-----------------------------------------------*/ body { background-color:#ffffff; color:#0f0f0f; /* font-family:serif; */ font-weight:normal; text-decoration:none; font-size:x-small; voice-family:"\"}\""; voice-family:inherit; font-size:small; } html>body { font-size:small; } .strong { font-weight:bold; } #red { color: #ff0000 } /*-Main Markup-------------------------------------------*/ #overall { background-color: #ffffff; color:#000000; } /*-Left Column--------*/ .leftcolumn .node a { color:#006666; background-color:transparent; } .leftcolumn .node p { font-size:1.2em; font-weight:normal; } .leftcolumn .node h1 { font-weight:normal; font-size:1.2em; color:#ffffff; background-color:#000000; /* #005991; #7f9bff #006666; */ } .leftcolumn .node h1 a { color:#ffffff; background-color:transparent; } .leftcolumn .node h2 { font-weight:bold; font-size:.95em; } .leftcolumn .node ul { list-style-type:none; } .leftcolumn .node li.more { font-weight:bold; font-size:.75em; } .leftcolumn .node li.selected { font-weight:bold; font-size:1.18em; color:#000000; background-color:#cccccc; } .leftcolumn .node li.selected a { color:#000000; background-color:transparent; } /*-Center Column for classifieds-*/ .centercolumn .classifieds h1 { font-family:Arial, Helvetica, serif; font-weight:bold; font-size:1.38em; color:#000000; /* ffffff; */ background: #5390b7; /* a6bcac; #0c1e0f; 043b0d; 1a6126; */ } /*-Center Column------*/ .centercolumn .node { /* font-family:serif; */ } .centercolumn .node a { color:#006666; background-color:transparent; } .centercolumn .node h1 { font-family:Arial, Helvetica, serif; font-weight:bold; font-size:1.38em; color:#ffffff; background:#000000; /* #005991; */ } /* #006666 /* url('../images/slc.gif') no-repeat; */ .centercolumn .node h1 a { color:#ffffff; background-color:transparent; } .centercolumn .node h2 { font-weight:bold; font-size:1.18em; } .centercolumn .node h3 { font-weight:bold; font-size:.95em; } .centercolumn .node h4 { font-weight:normal; font-size:1.2em; } .centercolumn .node h4 a { font-weight:bold; } .centercolumn .node p { font-weight:normal; } .centercolumn .posts_0 h1 { color:#ffffff; background-color:#606060; font-size:1.18em; } .centercolumn .posts_1 h1 { color:#ffffff; background-color:#606060; font-size:1.18em; } .centercolumn .posts_2 h1 { color:#ffffff; background-color:#606060; font-size:1.18em; } .centercolumn .posts_3 h1 { color:#ffffff; background-color:#606060; font-size:1.18em; } .centercolumn .posts_4 h1 { color:#ffffff; background-color:#606060; font-size:1.18em; } .centercolumn .posts_5 h1 { color:#ffffff; background-color:#606060; font-size:1.18em; } .centercolumn .posts_6 h1 { color:#ffffff; background-color:#606060; font-size:1.18em; } .centercolumn .posts_7 h1 { color:#ffffff; background-color:#606060; font-size:1.18em; } .centercolumn .posts_8 h1 { color:#ffffff; background-color:#606060; font-size:1.18em; } .centercolumn .posts_9 h1 { color:#ffffff; background-color:#606060; font-size:1.18em; } .centercolumn .posts_10 h1 { color:#ffffff; background-color:#606060; font-size:1.18em; } /*-Right Column-------*/ .rightcolumn .node { color:#000000; background-color:#cccccc; font-family:serif; } .rightcolumn .node a { color:#000000; /* #005991; #006666; */ background-color:transparent; } .rightcolumn .node h1 { font-family:Arial, Helvetica, serif; font-weight:bold; font-size:0.95em; /* 1.38em; */ color:#ffffff; background-color: #000000; /* #005991; #006666; */ } .rightcolumn .node h1 a { color:#ffffff; background-color:transparent; } .rightcolumn .node h2 { font-weight:bold; font-size:.95em; } .rightcolumn .node ul.none { list-style-type:none; } .rightcolumn .node ul.dot { list-style-type:none; /* list-style-image:url('../images/listdot.gif'); */ } .rightcolumn .node ul.books { list-style-type:disc; } /*-OSDN Navagation bar-----------------------------------*/ #OSDNNavbar { background-color:#999999; color:#000000; /* #005991; /* #006666; */ } #OSDNNavbar div#links { background-color:#999999; color:#000000; /* #005991; /* #006666; */ } #OSDNNavbar a { background-color: transparent; color: #000000; /* #005991; /* #006666; */ } /*-Remaining layout--------------------------------------*/ #randomquote { font-size:1.2em; font-style:italic; } #copyright { font-size:.75em; font-family:Arial, Helvetica, serif; background-color:transparent; color:#000000; /* #005991; /* #006666; */ } #copyright a { background-color:transparent; color:#000000; /* #005991; /* #006666; */ } #bottomNav { background-color:transparent; color:#000000; /* #005991; /* #006666; */ } #bottomNav a { background-color:transparent; color:#ffffff; } #oldStuffNav { font-weight:bold; } |
Added stml2/formdat.scm version [f4b16c20f8].
> > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | ;; Copyright 2007-2011, Matthew Welland. ;; ;; This program is made available under the GNU GPL version 2.0 or ;; greater. See the accompanying file COPYING for details. ;; ;; This program is distributed WITHOUT ANY WARRANTY; without even the ;; implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR ;; PURPOSE. ;; (declare (unit formdat)) (module formdat * (import chicken scheme data-structures extras srfi-13 ports ) (use html-filter) (use regex) (require-extension srfi-69) ) |
Added stml2/html-filter.scm version [55ec64cff2].
> > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | ;; Copyright 2007-2011, Matthew Welland. ;; ;; This program is made available under the GNU GPL version 2.0 or ;; greater. See the accompanying file COPYING for details. ;; ;; This program is distributed WITHOUT ANY WARRANTY; without even the ;; implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR ;; PURPOSE. ;; (declare (unit html-filter)) (module html-filter * (import chicken scheme data-structures extras srfi-13 ports ) (use misc-stml) (require-extension regex) ;; ) |
Added stml2/install.cfg.template version [e6a66ae405].
> > > > > > | 1 2 3 4 5 6 | TARGDIR=/usr/lib/cgi-bin LOGDIR=/tmp/stmlrun SQLITE3=/usr/bin/sqlite3 # this was needed on the nokia n800 :-) # SQLITE3=/tmp/sqlite3 |
Added stml2/keystore.scm version [672ac89374].
> > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | ;; Copyright 2007-2011, Matthew Welland. ;; ;; This program is made available under the GNU GPL version 2.0 or ;; greater. See the accompanying file COPYING for details. ;; ;; This program is distributed WITHOUT ANY WARRANTY; without even the ;; implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR ;; PURPOSE. ;;====================================================================== ;; The meta data key store, just a general dumping ground for values ;; only used occasionally ;;====================================================================== ;; (declare (unit keystore)) (module keystore * (import chicken scheme data-structures extras srfi-13 ports ) ) |
Added stml2/misc-stml.scm version [30ba5d90bf].
> > > > > > > > > > > > > > > > > > > > > > > > | 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-2011, Matthew Welland. ;; ;; This program is made available under the GNU GPL version 2.0 or ;; greater. See the accompanying file COPYING for details. ;; ;; This program is distributed WITHOUT ANY WARRANTY; without even the ;; implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR ;; PURPOSE. ;;====================================================================== ;; dumbobj helpers ;;====================================================================== ;; (declare (unit misc-stml)) (module misc-stml * (import chicken scheme data-structures extras srfi-13 ports posix) (use regex (prefix dbi dbi:)) (use (prefix crypt c:)) (use (prefix dbi dbi:)) ) |
Added stml2/modules/twiki/Makefile version [a439548019].
> > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 | twiki.l.scm : twiki.l csi -batch -eval '(use silex)(if (lex "twiki.l" "twiki.l.scm")(exit 0)(exit 1))' test-silex : twiki.l.scm test-silex.scm csc test-silex.scm twikicount : twiki.l.scm twikicount.scm csc twikicount.scm |
Added stml2/modules/twiki/misc-notes.txt version [1de77e33b5].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | #| telnet localhost 80 GET cgi-bin/kiatoa/twiki?image=4&wiki_key=bG9jYXRpb25zIHdvcmxk HTTP/1.1 Accept: */* Accept-Language: en-us Connection: Keep-Alive Host: localhost Referer: http://localhost/links.asp User-Agent: Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0) Accept-Encoding: gzip, deflate GET /kiatoa/images/kiatoa.png HTTP/1.1 Accept: */* Accept-Language: en-us Connection: Keep-Alive Host: localhost Referer: http://localhost/links.asp GET index.html HTTP/1.1 Accept: */* Accept-Language: en-us Connection: Keep-Alive Host: localhost Referer: http://localhost/links.asp GET /cgi-bin/kiatoa/twiki?image=2&wiki_key=bG9jYXRpb25zIHdvcmxk HTTP/1.1 Accept: */* Accept-Language: en-us Connection: Keep-Alive Host: localhost Referer: http://192.168.2.1/cgi-bin/kiatoa/location/?twiki_maint=2 User-Agent: Mozilla/4.0 Accept-Encoding: gzip, deflate HTTP/1.1 200 OK Date: Tue, 01 Sep 2009 02:18:16 GMT Server: Apache/2.2.11 (Ubuntu) PHP/5.2.6-3ubuntu4.2 with Suhosin-Patch Last-Modified: Sun, 19 Jul 2009 02:47:52 GMT ETag: "a38005-12c2-46f060c330600" Accept-Ranges: bytes Content-Length: 4802 Keep-Alive: timeout=15, max=100 Connection: Keep-Alive Content-Type: image/png |# |
Added stml2/modules/twiki/tlayout.css version [b333339cf0].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /*{{{*/ * html .tiddler {height:1%;} body {font-size:.75em; font-family:arial,helvetica; margin:0; padding:0;} h1,h2,h3,h4,h5,h6 {font-weight:bold; text-decoration:none;} h1,h2,h3 {padding-bottom:1px; margin-top:1.2em;margin-bottom:0.3em;} h4,h5,h6 {margin-top:1em;} h1 {font-size:1.35em;} h2 {font-size:1.25em;} h3 {font-size:1.1em;} h4 {font-size:1em;} h5 {font-size:.9em;} hr {height:1px;} a {text-decoration:none;} dt {font-weight:bold;} ol {list-style-type:decimal;} ol ol {list-style-type:lower-alpha;} ol ol ol {list-style-type:lower-roman;} ol ol ol ol {list-style-type:decimal;} ol ol ol ol ol {list-style-type:lower-alpha;} ol ol ol ol ol ol {list-style-type:lower-roman;} ol ol ol ol ol ol ol {list-style-type:decimal;} .txtOptionInput {width:11em;} #contentWrapper .chkOptionInput {border:0;} .externalLink {text-decoration:underline;} .indent {margin-left:3em;} .outdent {margin-left:3em; text-indent:-3em;} code.escaped {white-space:nowrap;} .tiddlyLinkExisting {font-weight:bold;} .tiddlyLinkNonExisting {font-style:italic;} /* the 'a' is required for IE, otherwise it renders the whole tiddler in bold */ a.tiddlyLinkNonExisting.shadow {font-weight:bold;} #mainMenu .tiddlyLinkExisting, #mainMenu .tiddlyLinkNonExisting, #sidebarTabs .tiddlyLinkNonExisting {font-weight:normal; font-style:normal;} #sidebarTabs .tiddlyLinkExisting {font-weight:bold; font-style:normal;} .header {position:relative;} .header a:hover {background:transparent;} .headerShadow {position:relative; padding:4.5em 0em 1em 1em; left:-1px; top:-1px;} .headerForeground {position:absolute; padding:4.5em 0em 1em 1em; left:0px; top:0px;} .siteTitle {font-size:3em;} .siteSubtitle {font-size:1.2em;} #mainMenu {position:absolute; left:0; width:10em; text-align:right; line-height:1.6em; padding:1.5em 0.5em 0.5em 0.5em; font-size:1.1em;} #sidebar {position:absolute; right:3px; width:16em; font-size:.9em;} #sidebarOptions {padding-top:0.3em;} #sidebarOptions a {margin:0em 0.2em; padding:0.2em 0.3em; display:block;} #sidebarOptions input {margin:0.4em 0.5em;} #sidebarOptions .sliderPanel {margin-left:1em; padding:0.5em; font-size:.85em;} #sidebarOptions .sliderPanel a {font-weight:bold; display:inline; padding:0;} #sidebarOptions .sliderPanel input {margin:0 0 .3em 0;} #sidebarTabs .tabContents {width:15em; overflow:hidden;} .wizard {padding:0.1em 1em 0em 2em;} .wizard h1 {font-size:2em; font-weight:bold; background:none; padding:0em 0em 0em 0em; margin:0.4em 0em 0.2em 0em;} .wizard h2 {font-size:1.2em; font-weight:bold; background:none; padding:0em 0em 0em 0em; margin:0.4em 0em 0.2em 0em;} .wizardStep {padding:1em 1em 1em 1em;} .wizard .button {margin:0.5em 0em 0em 0em; font-size:1.2em;} .wizardFooter {padding:0.8em 0.4em 0.8em 0em;} .wizardFooter .status {padding:0em 0.4em 0em 0.4em; margin-left:1em;} .wizard .button {padding:0.1em 0.2em 0.1em 0.2em;} #messageArea {position:fixed; top:2em; right:0em; margin:0.5em; padding:0.5em; z-index:2000; _position:absolute;} .messageToolbar {display:block; text-align:right; padding:0.2em 0.2em 0.2em 0.2em;} #messageArea a {text-decoration:underline;} .tiddlerPopupButton {padding:0.2em 0.2em 0.2em 0.2em;} .popupTiddler {position: absolute; z-index:300; padding:1em 1em 1em 1em; margin:0;} .popup {position:absolute; z-index:300; font-size:.9em; padding:0; list-style:none; margin:0;} .popup .popupMessage {padding:0.4em;} .popup hr {display:block; height:1px; width:auto; padding:0; margin:0.2em 0em;} .popup li.disabled {padding:0.4em;} .popup li a {display:block; padding:0.4em; font-weight:normal; cursor:pointer;} .listBreak {font-size:1px; line-height:1px;} .listBreak div {margin:2px 0;} .tabset {padding:1em 0em 0em 0.5em;} .tab {margin:0em 0em 0em 0.25em; padding:2px;} .tabContents {padding:0.5em;} .tabContents ul, .tabContents ol {margin:0; padding:0;} .txtMainTab .tabContents li {list-style:none;} .tabContents li.listLink { margin-left:.75em;} #contentWrapper {display:block;} #splashScreen {display:none;} #displayArea {margin:1em 17em 0em 14em;} .toolbar {text-align:right; font-size:.9em;} .tiddler {padding:1em 1em 0em 1em;} .missing .viewer,.missing .title {font-style:italic;} .title {font-size:1.6em; font-weight:bold;} .missing .subtitle {display:none;} .subtitle {font-size:1.1em;} .tiddler .button {padding:0.2em 0.4em;} .tagging {margin:0.5em 0.5em 0.5em 0; float:left; display:none;} .isTag .tagging {display:block;} .tagged {margin:0.5em; float:right;} .tagging, .tagged {font-size:0.9em; padding:0.25em;} .tagging ul, .tagged ul {list-style:none; margin:0.25em; padding:0;} .tagClear {clear:both;} .footer {font-size:.9em;} .footer li {display:inline;} .annotation {padding:0.5em; margin:0.5em;} * html .viewer pre {width:99%; padding:0 0 1em 0;} .viewer {line-height:1.4em; padding-top:0.5em;} .viewer .button {margin:0em 0.25em; padding:0em 0.25em;} .viewer blockquote {line-height:1.5em; padding-left:0.8em;margin-left:2.5em;} .viewer ul, .viewer ol {margin-left:0.5em; padding-left:1.5em;} .viewer table, table.twtable {border-collapse:collapse; margin:0.8em 1.0em;} .viewer th, .viewer td, .viewer tr,.viewer caption,.twtable th, .twtable td, .twtable tr,.twtable caption {padding:3px;} table.listView {font-size:0.85em; margin:0.8em 1.0em;} table.listView th, table.listView td, table.listView tr {padding:0px 3px 0px 3px;} .viewer pre {padding:0.5em; margin-left:0.5em; font-size:1.2em; line-height:1.4em; overflow:auto;} .viewer code {font-size:1.2em; line-height:1.4em;} .editor {font-size:1.1em;} .editor input, .editor textarea {display:block; width:100%; font:inherit;} .editorFooter {padding:0.25em 0em; font-size:.9em;} .editorFooter .button {padding-top:0px; padding-bottom:0px;} .fieldsetFix {border:0; padding:0; margin:1px 0px 1px 0px;} .sparkline {line-height:1em;} .sparktick {outline:0;} .zoomer {font-size:1.1em; position:absolute; overflow:hidden;} .zoomer div {padding:1em;} * html #backstage {width:99%;} * html #backstageArea {width:99%;} #backstageArea {display:none; position:relative; overflow: hidden; z-index:150; padding:0.3em 0.5em 0.3em 0.5em;} #backstageToolbar {position:relative;} #backstageArea a {font-weight:bold; margin-left:0.5em; padding:0.3em 0.5em 0.3em 0.5em;} #backstageButton {display:none; position:absolute; z-index:175; top:0em; right:0em;} #backstageButton a {padding:0.1em 0.4em 0.1em 0.4em; margin:0.1em 0.1em 0.1em 0.1em;} #backstage {position:relative; width:100%; z-index:50;} #backstagePanel {display:none; z-index:100; position:absolute; width:90%; margin:0em 3em 0em 3em; padding:1em 1em 1em 1em;} .backstagePanelFooter {padding-top:0.2em; float:right;} .backstagePanelFooter a {padding:0.2em 0.4em 0.2em 0.4em;} #backstageCloak {display:none; z-index:20; position:absolute; width:100%; height:100px;} .whenBackstage {display:none;} .backstageVisible .whenBackstage {display:block;} /*}}}*/ |
Added stml2/modules/twiki/twiki-mod.scm version [d4d21ad337].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | ;; Copyright 2007-2010, Matthew Welland. ;; ;; This program is made available under the GNU GPL version 2.0 or ;; greater. See the accompanying file COPYING for details. ;; ;; This program is distributed WITHOUT ANY WARRANTY; without even the ;; implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR ;; PURPOSE. ;; twiki module (require-extension sqlite3 regex posix md5 message-digest base64) (import (prefix base64 base64:)) ;; TODO ;; ;; * Inline tiddlers [inline[TiddlerName]] ;; * Pics [pic X Y[picname.jpg]] ;; * Move twiki parsing/expanding to mattsutils as loadable module ;; Routines intended to be overridden by end users ;; (twiki:access keys wiki-name user-id) ;; search the code for "override" for more. ;; twiki css ;; ========= ;; Block tag ;; ----- --- ;; twiki twiki ;; twiki body div twiki-node ;; twiki main menu twiki-main-menu ;; This is the currently supported mechanism. Postgres will be added later -mrw- 7/26/2009 ;; (define (twiki:open-db key . create-not-ok) ;; (s:log "Got to twiki:open-db with key: " key) (let* ((create-ok (if (null? create-not-ok) #t (car create-not-ok))) (fdat (twiki:key->fname key)) (basepath (sdat-get-twikidir s:session)) (fpath (car fdat)) (fname (cadr fdat)) (fulldir (conc basepath "/" fpath)) (fullname (let ((fn (conc fulldir "/" fname))) (if (sdat-get-debugmode s:session)(s:log "\ntwikipath: " fn)) fn)) (fexists (file-exists? fullname)) (db (if fexists (dbi:open 'sqlite3 (list (cons 'dbname fullname))) #f))) (if (and (not db) (not create-ok)) (exit 100) (begin (if (not fexists) (begin ;; (print "fullname: " fullname) (if (sdat-get-debugmode s:session) (s:log "\ncreating fulldir: " fulldir)) (twiki:register-wiki key fullname) (system (conc "mkdir -p " fulldir)) ;; create the path (if (file-exists? fpath) (s:log "OK: dir " fpath " has been made") (s:log "ERROR: Failed to make the path for the twiki")) (set! db (dbi:open 'sqlite3 (list (cons 'dbname fullname)))) (for-each (lambda (sqry) ;; (print sqry) (dbi:exec db sqry)) ;; types: 0 text, 1 jpg, 2 png, 3 svg, 4 spreadsheet, 5 audio, 6 video :: better specs to come... (list "CREATE TABLE pics (id INTEGER PRIMARY KEY,name TEXT,wiki_id INTEGER,dat_id INTEGER,thumb_dat_id INTEGER,created_on INTEGER,owner_id INTEGER);" "CREATE TABLE dats (id INTEGER PRIMARY KEY,md5sum TEXT,dat BLOB,type INTEGER);" ;; on every modification a new tiddlers entry is created. When displaying the tiddlers do: ;; select where created_on < somedate order by created_on desc limit 1 "CREATE TABLE tiddlers (id INTEGER PRIMARY KEY,wiki_id INTEGER,name TEXT,rev INTEGER,dat_id INTEGER,created_on INTEGER,owner_id INTEGER);" ;; rev and tag only utilized when user sets a tag. All results from a select as above for tiddlers are set to the tag "CREATE TABLE revs (id INTEGER PRIMARY KEY,tag TEXT);" ;; wikis is here for when postgresql support is added or if a sub wiki is created. "CREATE TABLE wikis (id INTEGER PRIMARY KEY,name TEXT,created_on INTEGER);" ;; access control, negative numbered groups are private groups, postive numbered groups are system groups ;; permissions are on a per-wiki granularity ;; access; 0=none,1=read,2=read/write "CREATE TABLE perms (id INTEGER PRIMARY KEY,wiki_id INTEGER,group_id INTEGER,access INTEGER);" "CREATE TABLE groups (id INTEGER PRIMARY KEY,name TEXT);" "CREATE TABLE members (id INTEGER PRIMARY KEY,person_id INTEGER,group_id INTEGER);" ;; setup and configuration data "CREATE TABLE meta (id INTEGER PRIMARY KEY,key TEXT,val TEXT);" ;; need to create an entry for *this* twiki (conc "INSERT INTO wikis (id,name,created_on) VALUES (1,'main'," (current-seconds) ");"))) ;; (conc "INSERT INTO tiddlers (wiki_id,name,created_on) VALUES(1,'MainMenu'," (current-seconds) ");"))))) (twiki:save-tiddler db "MainMenu" "[[FirstTiddler]]" "" 1 1))) ;; (sqlite3:set-busy-timeout!(dbi:db-conn db) 1000000) db)))) ;;====================================================================== ;; twikis (db naming, sqlite vs postgresql, keys etc. ;;====================================================================== ;; A wiki is specified by a list of keys, here we convert that list to a single string (define (twiki:keys->key keys) (if (not (null? keys)) (string-intersperse (map conc keys) " ") " ")) (define (twiki:key->fname key) (let* (;; (md5keypath (md5:digest key)) ;; (twiki:keys->key keys))) (keypath (twiki:web64enc key)) (delta (quotient (string-length keypath) 3)) ;; (p1 (substring keypath 0 delta)) ;; 0 8)) (p2 (substring keypath delta (* delta 2)));; 8 16)) (p3 (substring keypath (* delta 2) (* delta 3)))) ;; 16 24)) (list (string-intersperse (list "dbs" p1 p2 p3) "/") keypath))) ;; look up the wid based on the keys, this is used for sub wikis only. I.e. a wiki instantiated inside another wiki ;; giving a separate namespace to all the tiddlers (define (twiki:name->wid db name) (let ((wid (dbi:get-one db "SELECT id FROM wikis WHERE name=?;" name))) (if wid wid (begin (dbi:exec db "INSERT INTO wikis (name,created_on) VALUES(?,?);" name (current-seconds)) (twiki:name->wid db name))))) ;;====================================================================== ;; twiki record ;;====================================================================== ;; make-vector-record twiki wiki wid name key dbh (define (make-twiki:wiki)(make-vector 5)) (define-inline (twiki:wiki-get-wid vec) (vector-ref vec 0)) (define-inline (twiki:wiki-get-name vec) (vector-ref vec 1)) (define-inline (twiki:wiki-get-key vec) (vector-ref vec 2)) (define-inline (twiki:wiki-get-dbh vec) (vector-ref vec 3)) (define-inline (twiki:wiki-get-perms vec) (vector-ref vec 4)) (define-inline (twiki:wiki-set-wid! vec val)(vector-set! vec 0 val)) (define-inline (twiki:wiki-set-name! vec val)(vector-set! vec 1 val)) (define-inline (twiki:wiki-set-key! vec val)(vector-set! vec 2 val)) (define-inline (twiki:wiki-set-dbh! vec val)(vector-set! vec 3 val)) (define-inline (twiki:wiki-set-perms! vec val)(vector-set! vec 4 val)) ;;====================================================================== ;; twiki misc ;;====================================================================== ;; returns help html (define (twiki:help section) (let ((main (twiki:div 'node "twiki-help" (list (twiki:h3 "Help stuff") (twiki:pre " Link to page: [[Page Title]] Heading3: !!! The heading Underline: __underlined__ Table: | cell1 | cell2 | List: # item1 ## item2 Bullet: * item1 ** item2 Preformatted: {{{stuff here}}} Insert a picture: [pic[PicName]] Or with size: [pic100x100[PicName]] Upload the picture using the \"Pic\" link first"))))) ;;(case section main)) ;;====================================================================== ;; twiki access control ;;====================================================================== ;; idea here is for the end user to redefine this routine, ;; and call twiki:interal-access if desired ;; ;; if override is #t then give access no matter what (define (twiki:access keys wiki-name user-id) '(r w)) ;; Add support for storing groups, users and access internally ;; (define (twiki:internal-access keys wiki-name user-id) #f) ;;====================================================================== ;; twiki registry ;;====================================================================== ;; these can be overridden by end user (just create a new routine by the same name) (define (twiki:open-registry) (let* ((basepath (sdat-get-twikidir s:session)) (regfile (conc basepath "/registry.db")) (regexists (file-exists? regfile)) (db #f)) (if (sdat-get-debugmode s:session) (s:log "regfile: " regfile " regexists: " regexists " db: " db)) (set! db (dbi:open 'sqlite3 (list (cons 'dbname regfile)))) (if regexists db (begin (for-each (lambda (stmt)(dbi:exec db stmt)) (list "CREATE TABLE wikis (key TEXT PRIMARY KEY,path TEXT,creation_date INTEGER,creator_id INTEGER);")) db)))) (define (twiki:register-wiki key path) (let ((db (twiki:open-registry))) (dbi:exec db "INSERT OR REPLACE INTO wikis (key,path,creation_date,creator_id) VALUES(?,?,?,?);" key path (current-seconds) (twiki:get-id)) (dbi:close db))) ;;====================================================================== ;; tiddlers ;;====================================================================== (define twiki:tiddler-selector "SELECT t.id,t.name,t.rev,t.dat_id,t.created_on,t.owner_id FROM tiddlers AS t INNER JOIN dats AS d ON t.dat_id=d.id") (define (twiki:tiddler-make)(make-vector 8 #f)) (define-inline (twiki:tiddler-get-id vec) (vector-ref vec 0)) (define-inline (twiki:tiddler-get-name vec) (vector-ref vec 1)) (define-inline (twiki:tiddler-get-rev vec) (vector-ref vec 2)) (define-inline (twiki:tiddler-get-dat-id vec) (vector-ref vec 3)) (define-inline (twiki:tiddler-get-created_on vec) (vector-ref vec 4)) (define-inline (twiki:tiddler-get-owner_id vec) (vector-ref vec 5)) ;; (define-inline (twiki:tiddler-get-dat-type vec) (vector-ref vec 6)) (define-inline (twiki:tiddler-set-id! vec val)(vector-set! vec 0 val) vec) (define-inline (twiki:tiddler-set-name! vec val)(vector-set! vec 1 val) vec) (define-inline (twiki:tiddler-set-rev! vec val)(vector-set! vec 2 val) vec) (define-inline (twiki:tiddler-set-dat-id! vec val)(vector-set! vec 3 val) vec) (define-inline (twiki:tiddler-set-created_on! vec val)(vector-set! vec 4 val) vec) ;; (define-inline (twiki:tiddler-set-owner_id! vec val)(vector-set! vec 5 val)) ;;====================================================================== ;; Routines for displaying, editing, browsing etc. tiddlers ;;====================================================================== ;; should change this to take a tiddler structure? ;; This is the display of a single tiddler (define (twiki:view dat tkey wid tiddler wiki) ;; close, close others, edit, more (let ((is-not-main (not (equal? "MainMenu" (twiki:tiddler-get-name tiddler)))) (edit-allowed (member 'w (twiki:wiki-get-perms wiki)))) (s:div 'class "tiddler" (s:div 'class "tiddler-menu" (if (equal? "MainMenu" (twiki:tiddler-get-name tiddler)) (if edit-allowed (list (s:a "edit" 'href (s:link-to (twiki:get-link-back-to-current) 'edit_tiddler (twiki:tiddler-get-id tiddler)))) '()) (s:div 'class "tiddler-menu-internal" (s:a "close" 'href (s:link-to (twiki:get-link-back-to-current) 'close_tiddler (twiki:tiddler-get-id tiddler))) "." (s:a "close others" 'href (s:link-to (twiki:get-link-back-to-current) 'close_other_tiddlers (twiki:tiddler-get-id tiddler))) "." (if edit-allowed (s:a "edit" 'href (s:link-to (twiki:get-link-back-to-current) 'edit_tiddler (twiki:tiddler-get-id tiddler))) '())))) (s:p (twiki:dat->html dat wiki))))) (define (twiki:view-tiddler db tkey wid tiddler wiki) (let* ((dat-id (twiki:tiddler-get-dat-id tiddler)) (dat (twiki:get-dat db dat-id)) (tnum (twiki:tiddler-get-id tiddler))) ;; (s:log "twid: " dat-id " dat: " dat) (twiki:view dat tkey wid tiddler wiki))) ;; call with param => action-name-key e.g. save-bWFpbg__-aGVsbG8gbnVyc2U_ (save main "hello nurse") ;; this one is called when an edit form is submitted (i.e. POST) (define (twiki:action params) (if (and (list? params) (> (length params) 0)) (let* ((cmdln (string-split (car params) "-")) (cmd (string->symbol (car cmdln))) (tkey (twiki:web64dec (caddr cmdln))) (wid (string->number (cadr cmdln))) (tdb (twiki:open-db tkey))) (s:log "cmdln: " cmdln " cmd: " cmd " tkey: " tkey " wid: " wid) (case cmd ((save) (twiki:save-curr-tiddler tdb wid)) ((savepic) (s:log "twiki:action got to savepic") (twiki:save-pic-from-form tdb wid)) ((cancel) ;; deprecated. Use a link for this (i.e in the twiki:twiki proc (s:del! (conc "CURRENT_TWIDLER_UNDER_EDIT:" wid)) ))))) ;; generate a form for editing a twiddler tnum (define (twiki:edit-tiddler db tkey wid tnum) (s:log "twiki:edit-tiddler: tkey=" tkey " wid: " wid) (let* ((enc-key (twiki:web64enc tkey)) (tiddats (twiki:get-tiddlers-by-num db wid (list tnum)))) (if (null? tiddats) (let* ((tid 0) (dat-id 0)) (s:set! "twiki_title" "") (s:set! "twiki_body" "")) (let* ((tid (car tiddats)) (dat-id (twiki:tiddler-get-dat-id tid))) ;; (s:log "tid: " tid " dat-id: " dat-id) (s:set! "twiki_title" (twiki:tiddler-get-name tid)) (s:set! "twiki_body" (twiki:get-dat db dat-id)))) (s:form 'action (s:link-to (twiki:get-link-back-to-current) 'action (conc "twiki.save-" (number->string wid) "-" enc-key)) 'method "post" ;; 'twikiname tkey ;; done, cancel, delete (s:input 'type "submit" 'name "form-name" 'value "save" 'twikiname tkey) ;; (s:a "done" 'href (s:link-to (twiki:get-link-back-to-current) 'save_tmenu tnum)) (s:a "cancel" 'href (s:link-to (twiki:get-link-back-to-current) 'cancel_tedit tnum)) "." (s:a "delete" 'href (s:link-to (twiki:get-link-back-to-current) 'delete_tiddler tnum))(s:br) (s:input-preserve 'type "text" 'name "twiki_title" 'size "58" 'maxlength "150") (s:textarea-preserve 'type "textarea" 'name "twiki_body" 'rows "10" 'cols "65") (s:p "Tags" (s:input-preserve 'type "text" 'name "twiki_tags" 'size "55" 'maxlength "150"))))) ;; save a tiddler to the db for the twiki twik, getting data from the INPUT (define (twiki:save-curr-tiddler tdb wid) (formdat:printall (sdat-get-formdat s:session) s:log) (let* ((heading (s:get-input 'twiki_title)) (body (s:get-input 'twiki_body)) (tags (s:get-input 'twiki_tags)) (uid (twiki:get-id))) ;; (s:log "twiki:save-curr-tiddler heading: " heading " body: " body " tags: " tags) (s:set! 'twiki_title heading) (if body (begin (set! body (string-chomp body)) (s:set! 'twiki_body body))) (s:set! 'twiki_tags tags) (s:del! (conc "CURRENT_TWIDLER_UNDER_EDIT:" wid)) (let ((res (twiki:save-tiddler tdb heading body tags wid uid))) ;; Now, replace this twiddler number in the view list with ;; the new number from the db (twiki:normalize-current-twiddlers tdb wid) (s:del! 'twiki_title) (s:del! 'twiki_body) (s:del! 'twiki_tags) res) )) (define (twiki:normalize-current-twiddlers tdb wid) (let* ((cvar (conc "CURRENT_TWIDLERS:" wid)) (curr-slst (s:get cvar)) (curr-lst (map string->number (string-split curr-slst ","))) (tdlrs (twiki:get-tiddlers-by-num tdb wid curr-lst)) (names (remove (lambda (t)(string=? "MainMenu" t)) (map twiki:tiddler-get-name tdlrs))) (newnums (map twiki:tiddler-get-id (map (lambda (tn) (twiki:get-tiddler-by-name tdb wid tn)) names)))) (s:set! cvar (string-intersperse (map number->string newnums) ",")))) ;; generic save tiddler (define (twiki:save-tiddler tdb heading body tags wid uid) (if (misc:non-zero-string heading) (let* ((prev-tid (twiki:get-tiddler-by-name tdb wid heading)) (prev-dat-id (if prev-tid (twiki:tiddler-get-dat-id prev-tid) -1)) (dat-id (twiki:save-dat tdb body 0))) ;; 0=text ;; (s:log "twiki:save-tiddler dat-id: " dat-id " body: " body) (if (equal? prev-dat-id dat-id) ;; no need to insert a new record if the dat didn't change #t (dbi:exec tdb "INSERT INTO tiddlers (wiki_id,name,dat_id,created_on,owner_id) VALUES(?,?,?,?,?);" wid heading dat-id (current-seconds) uid)) #t) ;; success #f)) ;; non-success ;; text=0, jpg=1, png=2 (define (twiki:save-dat db dat type) (let* ((md5sum (message-digest-string (md5-primitive) dat)) ;; (md5-digest dat)) (datid (twiki:dat-exists? db md5sum type)) (datblob (if (string? dat) (string->blob dat) dat))) (if datid datid (begin (case type ((0) (dbi:exec db "INSERT INTO dats (md5sum,dat,type) VALUES(?,?,?);" md5sum datblob 0)) ((1) (dbi:exec db "INSERT INTO dats (md5sum,dat,type) VALUES(?,?,?);" md5sum datblob 1)) (else (dbi:exec db "INSERT INTO dats (md5sum,dat,type) VALUES(?,?,?);" md5sum datblob type))) (twiki:dat-exists? db md5sum type))))) (define (twiki:dat-exists? db md5sum type) (dbi:get-one db "SELECT id FROM dats WHERE md5sum=? AND type=?;" md5sum type)) (define (twiki:get-dat db id) (if (and id (number? id)) (if (< id 0) "" (let ((res (dbi:get-one-row db "SELECT dat,type FROM dats WHERE id=?;" id))) (if res (case (vector-ref res 1) ((0)(blob->string (vector-ref res 0))) (else (vector-ref res 0))) #f))) #f)) (define (twiki:maint_area tdb wid tkey wiki) (let ((maint (s:get-param 'twiki_maint)) (write-perm (member 'w (twiki:wiki-get-perms wiki)))) (s:div 'class "twiki-menu-internal" (if write-perm (list (s:a "Orphans" 'href (s:link-to (twiki:get-link-back-to-current) 'twiki_maint 1))(s:br) (s:a "Pics" 'href (s:link-to (twiki:get-link-back-to-current) 'twiki_maint 2))(s:br) (s:a "Help" 'href (s:link-to (twiki:get-link-back-to-current) 'twiki_maint 4))(s:br)) '()) (s:a "Search" 'href (s:link-to (twiki:get-link-back-to-current) 'twiki_maint 3))(s:br) (case maint ((1) (twiki:list-orphans tdb)) (else '()))))) ;;====================================================================== ;; Orphans ;;====================================================================== (define (twiki:make-tiddler-list tdlrs . tnums) (conc (string-intersperse (map conc (delete-duplicates (append (map twiki:tiddler-get-id tdlrs) tnums))) ","))) (define (twiki:get-orphans tdb) '()) (define (twiki:list-orphans tdb) '()) ;;====================================================================== ;; Pictures ;;====================================================================== (define (twiki:pic_mgmt tdb wid tkey) (s:div (s:a "Add pic" 'href (s:link-to (twiki:get-link-back-to-current) 'twiki_maint 2 'twiki_maint_add_pics 1))(s:br) (if (s:get-param "twiki_maint_add_pics") (s:form 'enctype "multipart/form-data" ;; 'name "does-a-form-have-a-name" (s:input 'type "file" 'name "input-picture" 'value "Upload pic") (s:input 'type "submit" 'name "submit-picture" 'value "Submit") 'method "post" 'action (s:link-to (twiki:get-link-back-to-current) 'action (conc "twiki.savepic-" (number->string wid) "-" (twiki:web64enc tkey))) (s:input 'type "text" 'name "picture-name" 'value "")) '()) (let ((pics (dbi:get-rows tdb "SELECT id,name,dat_id,thumb_dat_id FROM pics WHERE wiki_id=?;" wid))) (map (lambda (pic) (s:div 'class "tiddlerthumb" (s:img 'title (vector-ref pic 1) 'alt (vector-ref pic 1) ;; 'src (s:link-to "twiki" 'wiki_key (twiki:web64enc tkey) 'image (vector-ref pic 0))) 'src (s:link-to "twiki" 'wiki_key (conc (number->string wid) "-" (twiki:web64enc tkey)) 'thumb (vector-ref pic 0))) ;; (conc "twiki/" wid "/thumbs/" (vector-ref pic 0)))) (vector-ref pic 0) (vector-ref pic 1))) pics)))) (define (twiki:save-pic-from-form tdb wid) (let* ((pic-dat (s:get-input 'input-picture)) (alt-name (s:get-input 'picture-name))) (if pic-dat (begin (s:log "twiki:save-pic-from-form with pic-dat=" pic-dat " and alt-name=" alt-name) (twiki:save-pic tdb pic-dat wid alt-name)) #f))) ;; get pic id for a pic name, returns the latest (define (twiki:get-pic-id tdb pic-name wid) (dbi:get-one tdb "SELECT pics.id FROM pics WHERE pics.name=? AND pics.wiki_id=? ORDER BY pics.id DESC LIMIT 1;" pic-name wid)) (define (twiki:save-pic tdb pic-dat wid alt) (let ((pic-name (car pic-dat)) (pic-type (cadr pic-dat)) (pic-data (caddr pic-dat)) ;; I'm not too happy with this solution but I can't seem to chomp the \n\d from the end of the string (alt-name (if alt (string-substitute (regexp "[^\\w ]") "" alt #t) #f))) (if (and alt-name (string-match (regexp "\\w+") alt-name)) (set! pic-name alt-name)) (s:log "alt: " alt " alt-name: " alt-name) (if pic-data (let ((dat-id (twiki:save-dat tdb pic-data (twiki:mime->twiki-type pic-type))) (creation-time (current-seconds))) ;; (twiki:delete-pic-by-name tdb pic-name) (dbi:exec tdb "INSERT INTO pics (name,wiki_id,dat_id,created_on,owner_id) VALUES(?,?,?,?,?);" pic-name wid dat-id creation-time (twiki:get-id)) (let ((pic-id (twiki:get-pic-id tdb pic-name wid))) (twiki:make-thumbnail tdb pic-id wid)) #t) #f))) (define (twiki:get-pic-dat tdb wid pic-id) (dbi:get-one tdb "SELECT dat FROM pics INNER JOIN dats ON pics.dat_id=dats.id WHERE pics.id=? AND wiki_id=?;" pic-id wid)) (define (twiki:get-thumb-dat tdb wid pic-id) (dbi:get-one tdb "SELECT dat FROM pics INNER JOIN dats ON pics.thumb_dat_id=dats.id WHERE pics.id=? AND wiki_id=?;" pic-id wid)) ;; this one sets up the Content type, puts the data into page-dat and is done (define (twiki:return-image-dat tdb wid pic-id) (let ((dat (twiki:get-pic-dat tdb wid pic-id))) (s:log "twiki:return-image-dat dat is: " dat " of size: " (if (blob? dat)(blob-size dat) "[not a blob]")) (sdat-set-page-type! s:session 'image) (sdat-set-content-type! s:session "image/jpeg") (sdat-set-alt-page-dat! s:session dat))) ;; (session:alt-out s:session))) ;; this one sets up the Content type, puts the data into page-dat and is done (define (twiki:return-thumb-dat tdb wid pic-id) (let ((dat (twiki:get-thumb-dat tdb wid pic-id))) (s:log "twiki:return-image-dat dat is: " dat " of size: " (if (blob? dat)(blob-size dat) "[not a blob]")) (sdat-set-page-type! s:session 'image) (sdat-set-content-type! s:session "image/jpeg") (sdat-set-alt-page-dat! s:session dat))) ;; (session:alt-out s:session))) (define (twiki:make-thumbnail tdb pic-id wid) (let ((indat (twiki:get-pic-dat tdb wid pic-id))) ;; (outdat (open-output-string))) (let-values (((inp oup pid)(process "convert" (list "-size" "500x180" "-" "-thumbnail" "250x90" "-unsharp" "0x.5" "-")))) (write-string (blob->string indat) #f oup) (close-input-port oup) ;; (write-string #f inp (blob->string indat)) (let ((l (read-string #f inp))) (close-output-port inp) ;; (write-string l #f outdat) (let* ((newdat (string->blob l)) ;; (get-output-string outdat))) (dat-id (twiki:save-dat tdb newdat 2))) ;; bug? (dbi:exec tdb "UPDATE pics SET thumb_dat_id=? WHERE id=?;" dat-id pic-id) dat-id))))) ;; not tested (define (twiki:picdat->thumbdat picdat) (let-values (((inp oup pid)(process "convert" ;; (list "-size" "500x180" "-" "-thumbnail" "250x90" "-unsharp" "0x.5" "-")))) (list "-size" "500x180" "-" "-thumbnail" "200x70" "-unsharp" "0x.5" "-")))) (write-string (blob->string picdat) #f oup) (close-input-port oup) ;; (write-string #f inp (blob->string indat)) (let ((l (read-string #f inp))) (close-output-port inp) (write-string l #f oup) (string->blob l)))) (define (twiki:mime->twiki-type mime-type) (case (string->symbol mime-type) ((image/jpeg) 1) ((image/png) 2) (else 0))) ;;====================================================================== ;; Wiki stuff ;;====================================================================== ;; curr-tiddlers is a list of the names of the current tiddlers displayed ;; tiddler-under-edit is the tiddler being edited (or #f for none). (define (twiki:wiki name keys) (let ((perms (twiki:access name keys (twiki:get-id)))) ;; (s:log "twiki:wiki name: \"" name "\" keys: " keys) (if (or (not name) (string=? name "")) ;; name must be "" or #f to get here and return an image ;; handle returning pictures, note keys and name are ignored for these. They are called out in ;; the twiki/view.scm (twiki:twiki "blah" '(nada foo)) call. (let ((image (s:get-param "image")) (thumb (s:get-param "thumb"))) (s:log "image: " image " thumb: " thumb " wiki_key: " (s:get-param 'wiki_key)) (if (and (member 'r perms) image) (let* ((varlst (string-split (s:get-param 'wiki_key) "-")) (tkey (twiki:web64dec (cadr varlst))) (wid (string->number (car varlst))) (tdbn (twiki:open-db tkey #f))) (s:log "tkey: " tkey " image number: " image) (twiki:return-image-dat tdbn wid (string->number image)))) ;; do not return from twiki:return-image (if (and (member 'r perms) thumb) (let* ((varlst (string-split (s:get-param 'wiki_key) "-")) (tkey (twiki:web64dec (cadr varlst))) (wid (string->number (car varlst))) (tdbn (twiki:open-db tkey #f))) (s:log "tkey: " tkey " thumb number: " image) (twiki:return-thumb-dat tdbn wid (string->number thumb))))) ;; do not return from twiki:return-image (if (not (member 'r perms)) ;; read access '() ;; return a blank slate (twiki:display-wiki name keys perms))))) (define (twiki:display-wiki name keys perms) (let* ((wikidat (make-twiki:wiki)) (tkey (twiki:keys->key keys)) (tdb (twiki:open-db tkey)) (wid (twiki:name->wid tdb name)) (cvar (conc "CURRENT_TWIDLERS:" wid)) ;; page var to store current twiddlers being viewed (cvar-ed (conc "CURRENT_TWIDLER_UNDER_EDIT:" wid)) (tnumedit (if (s:get cvar-ed) (string->number (s:get cvar-ed)) #f)) ;; #f => nothing to edit, -1 create a new tiddler (tnumview #f) (lmenu (twiki:get-tiddlers tdb wid (list "MainMenu"))) ;; store tiddlers for this page/twiki in cvar (i.e. CURRENT_TWIDLERS:<wid> (tdlnums (if (s:get cvar) (map string->number (string-split (s:get cvar) ",")) '())) ;; list of tiddler numbers (tdlrs '()) (tedited (if (member 'w perms) #f #t)) ;; force no edits if not a writer (edit-tmenu-id (if (and (member 'w perms) (s:get-param "edit_tmenu")) (string->number (s:get-param "edit_tmenu")) #f)) (edit-tiddler (if (and (member 'w perms) (s:get-param "edit_tiddler")) ;; this handles the "edit" link in the tiddler control bar (let ((t (twiki:get-tiddlers-by-num tdb wid (list (string->number (s:get-param "edit_tiddler")))))) (s:log "t: " t) (if t (car t ) ;; should be a list of one (twiki:tiddler-set-name! (twiki:tiddler-set-id! (twiki:tiddler-make) -1) "NewTiddler"))) #f)) (view-tiddler (if (s:get-param "view_tiddler") (let* ((tname (twiki:web64dec (s:get-param "view_tiddler"))) (t (twiki:get-tiddler-by-name tdb wid tname))) (s:log "t: " t) (if t t (begin (twiki:save-tiddler tdb tname (conc "!" tname) "" wid (twiki:get-id)) (twiki:get-tiddler-by-name tdb wid tname)))) #f)) ) ;; image is the dat_id, keep it simple silly. (twiki:wiki-set-wid! wikidat wid) (twiki:wiki-set-key! wikidat tkey) (twiki:wiki-set-name! wikidat name) (twiki:wiki-set-dbh! wikidat tdb) (twiki:wiki-set-perms! wikidat perms) ;; (s:log "edit-tmenu-id: " edit-tmenu-id " edit-tiddler: " edit-tiddler) ;; Handle other URI commands here (if (s:get-param "cancel_tedit") ;; doesn't matter which tiddler - just use this to cancel any edit (begin (s:del! (conc "CURRENT_TWIDLER_UNDER_EDIT:" wid)) (set! edit-tiddler #f) (set! tnumedit #f) (set! view-tiddler #f) (twiki:normalize-current-twiddlers tdb wid) (if (s:get cvar) (set! tdlnums (map string->number (string-split (s:get cvar) ",")))))) (if (s:get-param "delete_tiddler") '()) ;; (twiki:delete_tiddler tdb wid (string->number (s:get-param "delete_tiddler")))) (s:set! "TWIKI_KEY" tkey) ;; this mechanism will fail for hierarchial twikis ;; override the twiddler to edit when editing MainMenu (if edit-tiddler (begin (set! tnumedit (twiki:tiddler-get-id edit-tiddler)) (s:set! 'twiki_title (twiki:tiddler-get-name edit-tiddler)) (s:set! 'twiki_body (twiki:get-dat tdb (twiki:tiddler-get-dat-id edit-tiddler))))) (if view-tiddler (begin (set! tnumview (twiki:tiddler-get-id view-tiddler)))) ;; NOW WHAT FOR VIEW - fix the links, add to tdlst (if edit-tmenu-id (set! tnumedit edit-tmenu-id)) (if tnumedit (set! tdlnums (cons tnumedit tdlnums))) (if tnumview (set! tdlnums (cons tnumview tdlnums))) (set! tdlrs (twiki:get-tiddlers-by-num tdb wid tdlnums)) ;; remove tdlrs from the list if close_tiddler called (if (s:get-param "close_tiddler") (set! tdlrs (let ((tnum (string->number (s:get-param "close_tiddler")))) (remove (lambda (t) (equal? (twiki:tiddler-get-id t) tnum)) tdlrs)))) ;; remove all others if close_other_tiddlers called (if (s:get-param "close_other_tiddlers") (set! tdlrs (let ((tnum (string->number (s:get-param "close_other_tiddlers")))) (remove (lambda (t) (not (equal? (twiki:tiddler-get-id t) tnum))) tdlrs)))) (s:set! cvar (twiki:make-tiddler-list tdlrs)) (if tnumedit (s:set! cvar-ed tnumedit) (s:del! cvar-ed)) ;; must have a MainMenu tiddler by now (if (null? lmenu) (begin (twiki:save-tiddler tdb "MainMenu" "" "" wid (twiki:get-id)) (set! lmenu (twiki:get-tiddlers tdb wid (list "MainMenu"))))) ;; get the tiddlers from the db now (set! result (s:div 'class "twiki" ;; float to the right the control menu (s:div 'class "twiki-main-menu" (twiki:maint_area tdb wid tkey wikidat)) (twiki:view-tiddler tdb tkey wid (car lmenu) wikidat) ;; this is probably not needed as there is no reason to create tiddlers this way ;; (if (eq? tnumedit -1)(twiki:edit-tiddler tdb tkey wid tnumedit) '()) ;; insert the picture editor window if enabled (if (equal? (s:get-param "twiki_maint") "2")(twiki:pic_mgmt tdb wid tkey) '()) (if (equal? (s:get-param "twiki_maint") "4")(twiki:help 1) '()) (if (not (null? tdlrs)) (map (lambda (tdlr) (let ((tnum (twiki:tiddler-get-id tdlr))) (s:log "tnum: " tnum " tnumedit: " tnumedit) (if (and tnumedit (not tedited) (equal? tnumedit tnum)) (begin (set! tedited #t) ;; only allow editing one tiddler at a time (twiki:edit-tiddler tdb tkey wid tnum)) (twiki:view-tiddler tdb tkey wid tdlr wikidat)))) tdlrs) '()))) (dbi:close tdb) result)) ;; should do a single more efficient query but this is good enough (define (twiki:get-tiddlers db wid tnames) (apply twiki:get-tiddlers-by-name db wid tnames)) ;; (let* ((tdlrs '()) ;; ;; (conn (sdat-get-conn s:session)) ;; (namelst (conc "('" (string-intersperse (map conc tnames) "','") "')")) ;; (qry (conc twiki:tiddler-selector " WHERE t.wiki_id=? AND t.id IN " namelst ";"))) ;; ;; (print qry) ;; (dbi:for-each-row ;; (lambda (row) ;; (set! tdlrs (cons row tdlrs))) ;; db qry wid) ;; (reverse tdlrs))) ;; !Twiki\ ;; tlst is a list of tiddler nums (define (twiki:get-tiddlers-by-num db wid tlst) ;; (s:log "Got to twiki:get-tiddlers with keys: " tlst " and wid: " wid) ;; select where created_on < somedate order by created_on desc limit 1 (let* ((tdlrs '()) (tlststr (string-intersperse (map number->string tlst) ",")) (already-got (make-hash-table)) (qry (conc twiki:tiddler-selector " WHERE t.wiki_id=? AND t.id IN (" tlststr ") ORDER BY created_on DESC;"))) (dbi:for-each-row (lambda (row) (let ((tname (twiki:tiddler-get-name row))) (if (not (hash-table-ref/default already-got tname #f)) (begin (set! tdlrs (cons row tdlrs)) (hash-table-set! already-got tname #t))))) db qry wid) (if (null? tdlrs) tdlrs (reverse tdlrs)))) ;; !Twiki\nTitle, pictures, etc.\n{{{\nCode\n}}}\n[[links]]\n|table|of|stuff|\n|more|stuff|here|\n")) ;; wid = wiki id ;; returns a list of twiki:tiddlers (define (twiki:get-tiddlers-by-name tdb wid . names) (let ((tdlrs '())) (for-each (lambda (name) (let ((tdlr (twiki:get-tiddler-by-name tdb wid name))) (if tdlr (set! tdlrs (cons tdlr tdlrs))))) names) (reverse tdlrs))) ;; with the right query it should be possible to do this much faster approach for twiki:get-tiddlers-by-name ;; (let ((tdlrs '()) ;; (namelst (conc "('" (string-intersperse names "','") "')"))) ;; (dbi:for-each-row ;; (lambda (row) ;; (set! tdlrs (cons row tdlrs))) ;; tdb ;; (conc twiki:tiddler-selector " WHERE t.wiki_id=? AND t.name IN " namelst) wid) ;; (reverse tdlrs))) ;; get the tiddler with the given name and the max date (define (twiki:get-tiddler-by-name tdb wid name) (dbi:get-one-row tdb (conc twiki:tiddler-selector " WHERE t.wiki_id=? AND t.name=? ORDER BY created_on DESC LIMIT 1;") wid name)) (define (twiki:tiddler-name->id db tname) (dbi:get-one db "SELECT id FROM tiddlers WHERE name=?;" tname)) ;;====================================================================== ;; twiki text formating, parsing and display ;;====================================================================== ;; twiki formating routines (override these to change your look and feel (define twiki:twiki-tag s:b) (define twiki:h3 s:h3) (define twiki:h2 s:h2) (define twiki:h1 s:h1) ;; (define twiki:make-tlink s:i) (define twiki:ul s:ul) (define twiki:ol s:ol) (define twiki:li s:li) (define twiki:pre s:pre) (define twiki:p s:p) (define twiki:u s:u) (define twiki:td s:td) (define twiki:tr s:tr) (define twiki:table s:table) (define twiki:div s:div) (define (twiki:web64enc str) (string-substitute "=" "_" (base64:base64-encode str) #t)) (define (twiki:web64dec str) (base64:base64-decode (string-substitute "_" "=" str #t))) (define (twiki:make-tlink text tiddlername) (s:a text 'href (s:link-to (twiki:get-link-back-to-current) 'view_tiddler (twiki:web64enc tiddlername)))) (define (twiki:pic pic-name size wiki) (let* ((tdb (twiki:wiki-get-dbh wiki)) (tkey (twiki:wiki-get-key wiki)) (xy (string-split size "x")) (pic-id (twiki:get-pic-id tdb pic-name (twiki:wiki-get-wid wiki))) (img-lnk (s:link-to "twiki" 'wiki_key (conc (number->string (twiki:wiki-get-wid wiki)) "-" (twiki:web64enc tkey)) 'image pic-id))) (if (and (> (length xy) 1) (car xy) (cadr xy)) ;; yep, have two numbers (s:img 'title pic-name 'alt pic-name 'width (car xy) 'height (cadr xy) 'src img-lnk) (s:img 'title pic-name 'alt pic-name 'src img-lnk)))) ;; override these also (define (twiki:get-id) (s:session-var-get "id")) ;; override this to set links inside wiki's (define (twiki:get-link-back-to-current) (s:current-page)) ;; regexes are listed in the order in which they should be checked (define twiki:h3-patt (regexp "^!!!(.*)$")) (define twiki:h2-patt (regexp "^!!(.*)$")) (define twiki:h1-patt (regexp "^!(.*)$")) (define twiki:tlink-patt (regexp "^(.*)\\[\\[([^\\[\\]]*)\\]\\](.*)$")) (define twiki:pic-patt (regexp "^(.*)\\[pic([0-9%]*x*[0-9%]*)\\[([^\\[\\]]+)\\]\\](.*)$")) (define twiki:underline-patt (regexp "^(.*)__(.*)__(.*)$")) (define twiki:table-patt (regexp "^\\|(.*)\\|$")) ;; these are for multi-line formating (define twiki:list-patt (regexp "^(\\*+|\\#+)(.*)$")) (define twiki:bullet-patt (regexp "^(\\*+)(.*)$")) (define twiki:number-patt (regexp "^(\\#+)(.*)$")) (define twiki:prefor-patt (regexp "^\\{\\{\\{$")) (define twiki:prefor-end-patt (regexp "^\\}\\}\\}$")) ;; regex (define t:match #f) (define (t-match r s) (let ((res (string-match r s))) (set! t:match res) res)) ;; should switch to recursively processing by block? ;; (process-block dat) ;; ... ;; (process-block remdat) (define (twiki:dat->html dat wiki) (let* ((inp (open-input-string dat)) (nest-depth 0) ;; depth of nested lists ;; token (i.e. line) handling stuff (next-line #f) (peek-line (lambda () next-line)) (get-line (lambda () (let ((res next-line)) (set! next-line (read-line inp)) ;; (print "get-line: prev=" res " next=" next-line "\n") res))) (l (get-line))) ;; discard the #f in next-line (twiki:read-block peek-line get-line nest-depth #f wiki))) ;; blk-type is #f for not in a block (i.e. at top level), 'pre for preformated, 'ul or 'ol ;; call with first line as legit data ;; i.e. for preform - skip the {{{ line then call read-block ;; for # or * call with first line (define (twiki:read-block peek-line get-line nest-depth blk-type wiki) (let loop ((res '()) (l (peek-line))) ;; should this be a peek-line? yes!! ;; (print "twiki:read-block loop nest-depth="nest-depth " blk-type=" blk-type " l=" l "\n res=" res) (if (eof-object? l) ;; we are done! return the list res ;; process it! (cond ;; handle preformated text ((eq? blk-type 'pre) (if (t-match twiki:prefor-end-patt l) (begin (get-line) ;; discard the }}} res) ;; end of preformatted (begin ;; (get-line) ;; discard the {{{ (loop (append res (list (get-line))) (peek-line))))) ;; handle tables ((eq? blk-type 'table) (if (t-match twiki:table-patt l) (let ((cels (string-split (cadr t:match) "|"))) (get-line) (loop (append res (twiki:tr (map twiki:td (map (lambda (x)(twiki:line->html x #f wiki)) cels)))) (get-line))) res)) ;; handle lists ((or (t-match twiki:bullet-patt l) ;; have * (t-match twiki:number-patt l)) (let* ((directive (cadr t:match)) (levelnum (string-length directive)) (text (twiki:line->html (caddr t:match) #t wiki)) (btype (if (string=? "#" (substring directive 0 1)) 'ol 'ul)) (func (if (eq? btype 'ul) twiki:ul twiki:ol))) ;; (print "handling " btype ": levelnum=" levelnum " text=" text " nest-depth=" nest-depth " blk-type=" blk-type) (cond ((not blk-type) ;; i.e first member of the list! (loop (append res (func (twiki:read-block peek-line get-line levelnum btype wiki))) (get-line))) ((> levelnum nest-depth) (loop (append res (func (twiki:read-block peek-line get-line (+ nest-depth 1) btype wiki))) (peek-line))) ((< levelnum nest-depth) (append res (twiki:li text))) ;; return the bulleted item, don't get the next line?? (else (get-line) (loop (append res (twiki:li text)) (peek-line)))))) ((t-match twiki:prefor-patt l) (get-line) ;; discard the {{{ (loop (append res (twiki:pre (twiki:read-block peek-line get-line nest-depth 'pre wiki))) (peek-line))) ((t-match twiki:table-patt l) (get-line) (loop (append res (twiki:table 'border 1 'cellspacing 0 (twiki:read-block peek-line get-line 0 'table wiki))) (peek-line))) (else (get-line) (loop (append res (twiki:line->html l #t wiki)) (peek-line))))))) (define (twiki:line->html dat firstcall wiki) (if firstcall ;; process the patterns that test for beginning of line only on the first call (cond ((t-match twiki:h3-patt dat) (twiki:h3 (twiki:line->html (cadr t:match) #f wiki))) ((t-match twiki:h2-patt dat) (twiki:h2 (twiki:line->html (cadr t:match) #f wiki))) ((t-match twiki:h1-patt dat) (twiki:h1 (twiki:line->html (cadr t:match) #f wiki))) ;; why was the (s:br) here? trying without (else (twiki:line->html dat #f wiki))) ;; (else (append (twiki:line->html dat #f wiki)(list (s:br)))));; (s:p 'class "tiddlerpar" ;; not firstcall so process other patterns (cond ((t-match twiki:tlink-patt dat) (let ((pre (cadr t:match)) (lnk (caddr t:match)) (post (cadddr t:match))) (list (twiki:line->html pre #f wiki) (twiki:make-tlink (twiki:line->html lnk #f wiki) lnk) ;; special handling (twiki:line->html post #f wiki)))) ((t-match twiki:pic-patt dat) (let ((pre (cadr t:match)) (size (caddr t:match)) (pic (cadddr t:match)) (post (list-ref t:match 4))) (list (twiki:line->html pre #f wiki) (twiki:pic pic size wiki) (twiki:line->html post #t wiki)))) ((t-match twiki:underline-patt dat) (let ((pre (cadr t:match)) (lnk (caddr t:match)) (post (cadddr t:match))) (list (twiki:line->html pre #f wiki) (twiki:u (twiki:line->html lnk #f wiki)) (twiki:line->html post #f wiki)))) ((t-match twiki:table-patt dat) (let ((cels (string-split (cadr t:match) "|"))) (twiki:tr (map twiki:td (twiki:line->html cels #f wiki))))) (else (list dat))))) #| (twiki:dat->html "a\n{{{\nb\nc\nd\n}}}\n!e\n[[f]]\n[[g]]\n*h" wiki) (s:output (current-output-port) (twiki:dat->html "!Testing [[my first link]]\n* Test\n* Foo\nblah" wiki)) (s:output (current-output-port) (twiki:dat->html "[[a]]\n{{{\nb\n c\n d\n}}}\n*x\n[[f]]\n[[g]]\n*h" wiki)) (s:output (current-output-port) |# |
Added stml2/modules/twiki/twiki-test.scm version [ee0fdeaa83].
> > > > > | 1 2 3 4 5 | (include "../../stml.scm") ;; (include "../../session.scm") (include "../../misc-stml.scm") (include "twiki-mod.scm") |
Added stml2/modules/twiki/twiki.l version [8e7948394a].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | ;; twiki period \. comma , semicolon \; opensq \[ closesq \] opensquig \{ closesquig \} digit [0-9] letter [a-zA-Z] okchars [_%\/\.:\*\+\-\(\)\\#'] escape \\ whitespace [ \9] linefeed \n bang ! plaintext ({letter}|{digit}|{okchars}|{whitespace}|{linefeed})+ %% {opensq} (list 'opensq yytext) {closesq} (list 'closesq yytext) {opensquig} (list 'opensquig yytext) {closesquig} (list 'closesquig yytext) {bang} (list 'bang yytext) {plaintext} (list 'plaintext yytext) <<EOF>> (list 'end-of-input #f ) ;; yyline) <<ERROR>> (lex-error (conc yyline " : illegal character ") (yygetc)) |
Added stml2/modules/twiki/twiki.l.scm version [4356cb4b0e].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | ; *** This file starts with a copy of the file multilex.scm *** ; Copyright (C) 1997 Danny Dube', Universite' de Montre'al. ; All rights reserved. ; SILex 1.0. ; ; Gestion des Input Systems ; Fonctions a utiliser par l'usager: ; lexer-make-IS, lexer-get-func-getc, lexer-get-func-ungetc, ; lexer-get-func-line, lexer-get-func-column et lexer-get-func-offset ; ; Taille initiale par defaut du buffer d'entree (define lexer-init-buffer-len 1024) ; Numero du caractere newline (define lexer-integer-newline (char->integer #\newline)) ; Constructeur d'IS brut (define lexer-raw-IS-maker (lambda (buffer read-ptr input-f counters) (let ((input-f input-f) ; Entree reelle (buffer buffer) ; Buffer (buflen (string-length buffer)) (read-ptr read-ptr) (start-ptr 1) ; Marque de debut de lexeme (start-line 1) (start-column 1) (start-offset 0) (end-ptr 1) ; Marque de fin de lexeme (point-ptr 1) ; Le point (user-ptr 1) ; Marque de l'usager (user-line 1) (user-column 1) (user-offset 0) (user-up-to-date? #t)) ; Concerne la colonne seul. (letrec ((start-go-to-end-none ; Fonctions de depl. des marques (lambda () (set! start-ptr end-ptr))) (start-go-to-end-line (lambda () (let loop ((ptr start-ptr) (line start-line)) (if (= ptr end-ptr) (begin (set! start-ptr ptr) (set! start-line line)) (if (char=? (string-ref buffer ptr) #\newline) (loop (+ ptr 1) (+ line 1)) (loop (+ ptr 1) line)))))) (start-go-to-end-all (lambda () (set! start-offset (+ start-offset (- end-ptr start-ptr))) (let loop ((ptr start-ptr) (line start-line) (column start-column)) (if (= ptr end-ptr) (begin (set! start-ptr ptr) (set! start-line line) (set! start-column column)) (if (char=? (string-ref buffer ptr) #\newline) (loop (+ ptr 1) (+ line 1) 1) (loop (+ ptr 1) line (+ column 1))))))) (start-go-to-user-none (lambda () (set! start-ptr user-ptr))) (start-go-to-user-line (lambda () (set! start-ptr user-ptr) (set! start-line user-line))) (start-go-to-user-all (lambda () (set! start-line user-line) (set! start-offset user-offset) (if user-up-to-date? (begin (set! start-ptr user-ptr) (set! start-column user-column)) (let loop ((ptr start-ptr) (column start-column)) (if (= ptr user-ptr) (begin (set! start-ptr ptr) (set! start-column column)) (if (char=? (string-ref buffer ptr) #\newline) (loop (+ ptr 1) 1) (loop (+ ptr 1) (+ column 1)))))))) (end-go-to-point (lambda () (set! end-ptr point-ptr))) (point-go-to-start (lambda () (set! point-ptr start-ptr))) (user-go-to-start-none (lambda () (set! user-ptr start-ptr))) (user-go-to-start-line (lambda () (set! user-ptr start-ptr) (set! user-line start-line))) (user-go-to-start-all (lambda () (set! user-ptr start-ptr) (set! user-line start-line) (set! user-column start-column) (set! user-offset start-offset) (set! user-up-to-date? #t))) (init-lexeme-none ; Debute un nouveau lexeme (lambda () (if (< start-ptr user-ptr) (start-go-to-user-none)) (point-go-to-start))) (init-lexeme-line (lambda () (if (< start-ptr user-ptr) (start-go-to-user-line)) (point-go-to-start))) (init-lexeme-all (lambda () (if (< start-ptr user-ptr) (start-go-to-user-all)) (point-go-to-start))) (get-start-line ; Obtention des stats du debut du lxm (lambda () start-line)) (get-start-column (lambda () start-column)) (get-start-offset (lambda () start-offset)) (peek-left-context ; Obtention de caracteres (#f si EOF) (lambda () (char->integer (string-ref buffer (- start-ptr 1))))) (peek-char (lambda () (if (< point-ptr read-ptr) (char->integer (string-ref buffer point-ptr)) (let ((c (input-f))) (if (char? c) (begin (if (= read-ptr buflen) (reorganize-buffer)) (string-set! buffer point-ptr c) (set! read-ptr (+ point-ptr 1)) (char->integer c)) (begin (set! input-f (lambda () 'eof)) #f)))))) (read-char (lambda () (if (< point-ptr read-ptr) (let ((c (string-ref buffer point-ptr))) (set! point-ptr (+ point-ptr 1)) (char->integer c)) (let ((c (input-f))) (if (char? c) (begin (if (= read-ptr buflen) (reorganize-buffer)) (string-set! buffer point-ptr c) (set! read-ptr (+ point-ptr 1)) (set! point-ptr read-ptr) (char->integer c)) (begin (set! input-f (lambda () 'eof)) #f)))))) (get-start-end-text ; Obtention du lexeme (lambda () (substring buffer start-ptr end-ptr))) (get-user-line-line ; Fonctions pour l'usager (lambda () (if (< user-ptr start-ptr) (user-go-to-start-line)) user-line)) (get-user-line-all (lambda () (if (< user-ptr start-ptr) (user-go-to-start-all)) user-line)) (get-user-column-all (lambda () (cond ((< user-ptr start-ptr) (user-go-to-start-all) user-column) (user-up-to-date? user-column) (else (let loop ((ptr start-ptr) (column start-column)) (if (= ptr user-ptr) (begin (set! user-column column) (set! user-up-to-date? #t) column) (if (char=? (string-ref buffer ptr) #\newline) (loop (+ ptr 1) 1) (loop (+ ptr 1) (+ column 1))))))))) (get-user-offset-all (lambda () (if (< user-ptr start-ptr) (user-go-to-start-all)) user-offset)) (user-getc-none (lambda () (if (< user-ptr start-ptr) (user-go-to-start-none)) (if (< user-ptr read-ptr) (let ((c (string-ref buffer user-ptr))) (set! user-ptr (+ user-ptr 1)) c) (let ((c (input-f))) (if (char? c) (begin (if (= read-ptr buflen) (reorganize-buffer)) (string-set! buffer user-ptr c) (set! read-ptr (+ read-ptr 1)) (set! user-ptr read-ptr) c) (begin (set! input-f (lambda () 'eof)) 'eof)))))) (user-getc-line (lambda () (if (< user-ptr start-ptr) (user-go-to-start-line)) (if (< user-ptr read-ptr) (let ((c (string-ref buffer user-ptr))) (set! user-ptr (+ user-ptr 1)) (if (char=? c #\newline) (set! user-line (+ user-line 1))) c) (let ((c (input-f))) (if (char? c) (begin (if (= read-ptr buflen) (reorganize-buffer)) (string-set! buffer user-ptr c) (set! read-ptr (+ read-ptr 1)) (set! user-ptr read-ptr) (if (char=? c #\newline) (set! user-line (+ user-line 1))) c) (begin (set! input-f (lambda () 'eof)) 'eof)))))) (user-getc-all (lambda () (if (< user-ptr start-ptr) (user-go-to-start-all)) (if (< user-ptr read-ptr) (let ((c (string-ref buffer user-ptr))) (set! user-ptr (+ user-ptr 1)) (if (char=? c #\newline) (begin (set! user-line (+ user-line 1)) (set! user-column 1)) (set! user-column (+ user-column 1))) (set! user-offset (+ user-offset 1)) c) (let ((c (input-f))) (if (char? c) (begin (if (= read-ptr buflen) (reorganize-buffer)) (string-set! buffer user-ptr c) (set! read-ptr (+ read-ptr 1)) (set! user-ptr read-ptr) (if (char=? c #\newline) (begin (set! user-line (+ user-line 1)) (set! user-column 1)) (set! user-column (+ user-column 1))) (set! user-offset (+ user-offset 1)) c) (begin (set! input-f (lambda () 'eof)) 'eof)))))) (user-ungetc-none (lambda () (if (> user-ptr start-ptr) (set! user-ptr (- user-ptr 1))))) (user-ungetc-line (lambda () (if (> user-ptr start-ptr) (begin (set! user-ptr (- user-ptr 1)) (let ((c (string-ref buffer user-ptr))) (if (char=? c #\newline) (set! user-line (- user-line 1)))))))) (user-ungetc-all (lambda () (if (> user-ptr start-ptr) (begin (set! user-ptr (- user-ptr 1)) (let ((c (string-ref buffer user-ptr))) (if (char=? c #\newline) (begin (set! user-line (- user-line 1)) (set! user-up-to-date? #f)) (set! user-column (- user-column 1))) (set! user-offset (- user-offset 1))))))) (reorganize-buffer ; Decaler ou agrandir le buffer (lambda () (if (< (* 2 start-ptr) buflen) (let* ((newlen (* 2 buflen)) (newbuf (make-string newlen)) (delta (- start-ptr 1))) (let loop ((from (- start-ptr 1))) (if (< from buflen) (begin (string-set! newbuf (- from delta) (string-ref buffer from)) (loop (+ from 1))))) (set! buffer newbuf) (set! buflen newlen) (set! read-ptr (- read-ptr delta)) (set! start-ptr (- start-ptr delta)) (set! end-ptr (- end-ptr delta)) (set! point-ptr (- point-ptr delta)) (set! user-ptr (- user-ptr delta))) (let ((delta (- start-ptr 1))) (let loop ((from (- start-ptr 1))) (if (< from buflen) (begin (string-set! buffer (- from delta) (string-ref buffer from)) (loop (+ from 1))))) (set! read-ptr (- read-ptr delta)) (set! start-ptr (- start-ptr delta)) (set! end-ptr (- end-ptr delta)) (set! point-ptr (- point-ptr delta)) (set! user-ptr (- user-ptr delta))))))) (list (cons 'start-go-to-end (cond ((eq? counters 'none) start-go-to-end-none) ((eq? counters 'line) start-go-to-end-line) ((eq? counters 'all ) start-go-to-end-all))) (cons 'end-go-to-point end-go-to-point) (cons 'init-lexeme (cond ((eq? counters 'none) init-lexeme-none) ((eq? counters 'line) init-lexeme-line) ((eq? counters 'all ) init-lexeme-all))) (cons 'get-start-line get-start-line) (cons 'get-start-column get-start-column) (cons 'get-start-offset get-start-offset) (cons 'peek-left-context peek-left-context) (cons 'peek-char peek-char) (cons 'read-char read-char) (cons 'get-start-end-text get-start-end-text) (cons 'get-user-line (cond ((eq? counters 'none) #f) ((eq? counters 'line) get-user-line-line) ((eq? counters 'all ) get-user-line-all))) (cons 'get-user-column (cond ((eq? counters 'none) #f) ((eq? counters 'line) #f) ((eq? counters 'all ) get-user-column-all))) (cons 'get-user-offset (cond ((eq? counters 'none) #f) ((eq? counters 'line) #f) ((eq? counters 'all ) get-user-offset-all))) (cons 'user-getc (cond ((eq? counters 'none) user-getc-none) ((eq? counters 'line) user-getc-line) ((eq? counters 'all ) user-getc-all))) (cons 'user-ungetc (cond ((eq? counters 'none) user-ungetc-none) ((eq? counters 'line) user-ungetc-line) ((eq? counters 'all ) user-ungetc-all)))))))) ; Construit un Input System ; Le premier parametre doit etre parmi "port", "procedure" ou "string" ; Prend un parametre facultatif qui doit etre parmi ; "none", "line" ou "all" (define lexer-make-IS (lambda (input-type input . largs) (let ((counters-type (cond ((null? largs) 'line) ((memq (car largs) '(none line all)) (car largs)) (else 'line)))) (cond ((and (eq? input-type 'port) (input-port? input)) (let* ((buffer (make-string lexer-init-buffer-len #\newline)) (read-ptr 1) (input-f (lambda () (read-char input)))) (lexer-raw-IS-maker buffer read-ptr input-f counters-type))) ((and (eq? input-type 'procedure) (procedure? input)) (let* ((buffer (make-string lexer-init-buffer-len #\newline)) (read-ptr 1) (input-f input)) (lexer-raw-IS-maker buffer read-ptr input-f counters-type))) ((and (eq? input-type 'string) (string? input)) (let* ((buffer (string-append (string #\newline) input)) (read-ptr (string-length buffer)) (input-f (lambda () 'eof))) (lexer-raw-IS-maker buffer read-ptr input-f counters-type))) (else (let* ((buffer (string #\newline)) (read-ptr 1) (input-f (lambda () 'eof))) (lexer-raw-IS-maker buffer read-ptr input-f counters-type))))))) ; Les fonctions: ; lexer-get-func-getc, lexer-get-func-ungetc, ; lexer-get-func-line, lexer-get-func-column et lexer-get-func-offset (define lexer-get-func-getc (lambda (IS) (cdr (assq 'user-getc IS)))) (define lexer-get-func-ungetc (lambda (IS) (cdr (assq 'user-ungetc IS)))) (define lexer-get-func-line (lambda (IS) (cdr (assq 'get-user-line IS)))) (define lexer-get-func-column (lambda (IS) (cdr (assq 'get-user-column IS)))) (define lexer-get-func-offset (lambda (IS) (cdr (assq 'get-user-offset IS)))) ; ; Gestion des lexers ; ; Fabrication de lexer a partir d'arbres de decision (define lexer-make-tree-lexer (lambda (tables IS) (letrec (; Contenu de la table (counters-type (vector-ref tables 0)) (<<EOF>>-pre-action (vector-ref tables 1)) (<<ERROR>>-pre-action (vector-ref tables 2)) (rules-pre-actions (vector-ref tables 3)) (table-nl-start (vector-ref tables 5)) (table-no-nl-start (vector-ref tables 6)) (trees-v (vector-ref tables 7)) (acc-v (vector-ref tables 8)) ; Contenu du IS (IS-start-go-to-end (cdr (assq 'start-go-to-end IS))) (IS-end-go-to-point (cdr (assq 'end-go-to-point IS))) (IS-init-lexeme (cdr (assq 'init-lexeme IS))) (IS-get-start-line (cdr (assq 'get-start-line IS))) (IS-get-start-column (cdr (assq 'get-start-column IS))) (IS-get-start-offset (cdr (assq 'get-start-offset IS))) (IS-peek-left-context (cdr (assq 'peek-left-context IS))) (IS-peek-char (cdr (assq 'peek-char IS))) (IS-read-char (cdr (assq 'read-char IS))) (IS-get-start-end-text (cdr (assq 'get-start-end-text IS))) (IS-get-user-line (cdr (assq 'get-user-line IS))) (IS-get-user-column (cdr (assq 'get-user-column IS))) (IS-get-user-offset (cdr (assq 'get-user-offset IS))) (IS-user-getc (cdr (assq 'user-getc IS))) (IS-user-ungetc (cdr (assq 'user-ungetc IS))) ; Resultats (<<EOF>>-action #f) (<<ERROR>>-action #f) (rules-actions #f) (states #f) (final-lexer #f) ; Gestion des hooks (hook-list '()) (add-hook (lambda (thunk) (set! hook-list (cons thunk hook-list)))) (apply-hooks (lambda () (let loop ((l hook-list)) (if (pair? l) (begin ((car l)) (loop (cdr l))))))) ; Preparation des actions (set-action-statics (lambda (pre-action) (pre-action final-lexer IS-user-getc IS-user-ungetc))) (prepare-special-action-none (lambda (pre-action) (let ((action #f)) (let ((result (lambda () (action ""))) (hook (lambda () (set! action (set-action-statics pre-action))))) (add-hook hook) result)))) (prepare-special-action-line (lambda (pre-action) (let ((action #f)) (let ((result (lambda (yyline) (action "" yyline))) (hook (lambda () (set! action (set-action-statics pre-action))))) (add-hook hook) result)))) (prepare-special-action-all (lambda (pre-action) (let ((action #f)) (let ((result (lambda (yyline yycolumn yyoffset) (action "" yyline yycolumn yyoffset))) (hook (lambda () (set! action (set-action-statics pre-action))))) (add-hook hook) result)))) (prepare-special-action (lambda (pre-action) (cond ((eq? counters-type 'none) (prepare-special-action-none pre-action)) ((eq? counters-type 'line) (prepare-special-action-line pre-action)) ((eq? counters-type 'all) (prepare-special-action-all pre-action))))) (prepare-action-yytext-none (lambda (pre-action) (let ((get-start-end-text IS-get-start-end-text) (start-go-to-end IS-start-go-to-end) (action #f)) (let ((result (lambda () (let ((yytext (get-start-end-text))) (start-go-to-end) (action yytext)))) (hook (lambda () (set! action (set-action-statics pre-action))))) (add-hook hook) result)))) (prepare-action-yytext-line (lambda (pre-action) (let ((get-start-end-text IS-get-start-end-text) (start-go-to-end IS-start-go-to-end) (action #f)) (let ((result (lambda (yyline) (let ((yytext (get-start-end-text))) (start-go-to-end) (action yytext yyline)))) (hook (lambda () (set! action (set-action-statics pre-action))))) (add-hook hook) result)))) (prepare-action-yytext-all (lambda (pre-action) (let ((get-start-end-text IS-get-start-end-text) (start-go-to-end IS-start-go-to-end) (action #f)) (let ((result (lambda (yyline yycolumn yyoffset) (let ((yytext (get-start-end-text))) (start-go-to-end) (action yytext yyline yycolumn yyoffset)))) (hook (lambda () (set! action (set-action-statics pre-action))))) (add-hook hook) result)))) (prepare-action-yytext (lambda (pre-action) (cond ((eq? counters-type 'none) (prepare-action-yytext-none pre-action)) ((eq? counters-type 'line) (prepare-action-yytext-line pre-action)) ((eq? counters-type 'all) (prepare-action-yytext-all pre-action))))) (prepare-action-no-yytext-none (lambda (pre-action) (let ((start-go-to-end IS-start-go-to-end) (action #f)) (let ((result (lambda () (start-go-to-end) (action))) (hook (lambda () (set! action (set-action-statics pre-action))))) (add-hook hook) result)))) (prepare-action-no-yytext-line (lambda (pre-action) (let ((start-go-to-end IS-start-go-to-end) (action #f)) (let ((result (lambda (yyline) (start-go-to-end) (action yyline))) (hook (lambda () (set! action (set-action-statics pre-action))))) (add-hook hook) result)))) (prepare-action-no-yytext-all (lambda (pre-action) (let ((start-go-to-end IS-start-go-to-end) (action #f)) (let ((result (lambda (yyline yycolumn yyoffset) (start-go-to-end) (action yyline yycolumn yyoffset))) (hook (lambda () (set! action (set-action-statics pre-action))))) (add-hook hook) result)))) (prepare-action-no-yytext (lambda (pre-action) (cond ((eq? counters-type 'none) (prepare-action-no-yytext-none pre-action)) ((eq? counters-type 'line) (prepare-action-no-yytext-line pre-action)) ((eq? counters-type 'all) (prepare-action-no-yytext-all pre-action))))) ; Fabrique les fonctions de dispatch (prepare-dispatch-err (lambda (leaf) (lambda (c) #f))) (prepare-dispatch-number (lambda (leaf) (let ((state-function #f)) (let ((result (lambda (c) state-function)) (hook (lambda () (set! state-function (vector-ref states leaf))))) (add-hook hook) result)))) (prepare-dispatch-leaf (lambda (leaf) (if (eq? leaf 'err) (prepare-dispatch-err leaf) (prepare-dispatch-number leaf)))) (prepare-dispatch-< (lambda (tree) (let ((left-tree (list-ref tree 1)) (right-tree (list-ref tree 2))) (let ((bound (list-ref tree 0)) (left-func (prepare-dispatch-tree left-tree)) (right-func (prepare-dispatch-tree right-tree))) (lambda (c) (if (< c bound) (left-func c) (right-func c))))))) (prepare-dispatch-= (lambda (tree) (let ((left-tree (list-ref tree 2)) (right-tree (list-ref tree 3))) (let ((bound (list-ref tree 1)) (left-func (prepare-dispatch-tree left-tree)) (right-func (prepare-dispatch-tree right-tree))) (lambda (c) (if (= c bound) (left-func c) (right-func c))))))) (prepare-dispatch-tree (lambda (tree) (cond ((not (pair? tree)) (prepare-dispatch-leaf tree)) ((eq? (car tree) '=) (prepare-dispatch-= tree)) (else (prepare-dispatch-< tree))))) (prepare-dispatch (lambda (tree) (let ((dicho-func (prepare-dispatch-tree tree))) (lambda (c) (and c (dicho-func c)))))) ; Fabrique les fonctions de transition (read & go) et (abort) (prepare-read-n-go (lambda (tree) (let ((dispatch-func (prepare-dispatch tree)) (read-char IS-read-char)) (lambda () (dispatch-func (read-char)))))) (prepare-abort (lambda (tree) (lambda () #f))) (prepare-transition (lambda (tree) (if (eq? tree 'err) (prepare-abort tree) (prepare-read-n-go tree)))) ; Fabrique les fonctions d'etats ([set-end] & trans) (prepare-state-no-acc (lambda (s r1 r2) (let ((trans-func (prepare-transition (vector-ref trees-v s)))) (lambda (action) (let ((next-state (trans-func))) (if next-state (next-state action) action)))))) (prepare-state-yes-no (lambda (s r1 r2) (let ((peek-char IS-peek-char) (end-go-to-point IS-end-go-to-point) (new-action1 #f) (trans-func (prepare-transition (vector-ref trees-v s)))) (let ((result (lambda (action) (let* ((c (peek-char)) (new-action (if (or (not c) (= c lexer-integer-newline)) (begin (end-go-to-point) new-action1) action)) (next-state (trans-func))) (if next-state (next-state new-action) new-action)))) (hook (lambda () (set! new-action1 (vector-ref rules-actions r1))))) (add-hook hook) result)))) (prepare-state-diff-acc (lambda (s r1 r2) (let ((end-go-to-point IS-end-go-to-point) (peek-char IS-peek-char) (new-action1 #f) (new-action2 #f) (trans-func (prepare-transition (vector-ref trees-v s)))) (let ((result (lambda (action) (end-go-to-point) (let* ((c (peek-char)) (new-action (if (or (not c) (= c lexer-integer-newline)) new-action1 new-action2)) (next-state (trans-func))) (if next-state (next-state new-action) new-action)))) (hook (lambda () (set! new-action1 (vector-ref rules-actions r1)) (set! new-action2 (vector-ref rules-actions r2))))) (add-hook hook) result)))) (prepare-state-same-acc (lambda (s r1 r2) (let ((end-go-to-point IS-end-go-to-point) (trans-func (prepare-transition (vector-ref trees-v s))) (new-action #f)) (let ((result (lambda (action) (end-go-to-point) (let ((next-state (trans-func))) (if next-state (next-state new-action) new-action)))) (hook (lambda () (set! new-action (vector-ref rules-actions r1))))) (add-hook hook) result)))) (prepare-state (lambda (s) (let* ((acc (vector-ref acc-v s)) (r1 (car acc)) (r2 (cdr acc))) (cond ((not r1) (prepare-state-no-acc s r1 r2)) ((not r2) (prepare-state-yes-no s r1 r2)) ((< r1 r2) (prepare-state-diff-acc s r1 r2)) (else (prepare-state-same-acc s r1 r2)))))) ; Fabrique la fonction de lancement du lexage a l'etat de depart (prepare-start-same (lambda (s1 s2) (let ((peek-char IS-peek-char) (eof-action #f) (start-state #f) (error-action #f)) (let ((result (lambda () (if (not (peek-char)) eof-action (start-state error-action)))) (hook (lambda () (set! eof-action <<EOF>>-action) (set! start-state (vector-ref states s1)) (set! error-action <<ERROR>>-action)))) (add-hook hook) result)))) (prepare-start-diff (lambda (s1 s2) (let ((peek-char IS-peek-char) (eof-action #f) (peek-left-context IS-peek-left-context) (start-state1 #f) (start-state2 #f) (error-action #f)) (let ((result (lambda () (cond ((not (peek-char)) eof-action) ((= (peek-left-context) lexer-integer-newline) (start-state1 error-action)) (else (start-state2 error-action))))) (hook (lambda () (set! eof-action <<EOF>>-action) (set! start-state1 (vector-ref states s1)) (set! start-state2 (vector-ref states s2)) (set! error-action <<ERROR>>-action)))) (add-hook hook) result)))) (prepare-start (lambda () (let ((s1 table-nl-start) (s2 table-no-nl-start)) (if (= s1 s2) (prepare-start-same s1 s2) (prepare-start-diff s1 s2))))) ; Fabrique la fonction principale (prepare-lexer-none (lambda () (let ((init-lexeme IS-init-lexeme) (start-func (prepare-start))) (lambda () (init-lexeme) ((start-func)))))) (prepare-lexer-line (lambda () (let ((init-lexeme IS-init-lexeme) (get-start-line IS-get-start-line) (start-func (prepare-start))) (lambda () (init-lexeme) (let ((yyline (get-start-line))) ((start-func) yyline)))))) (prepare-lexer-all (lambda () (let ((init-lexeme IS-init-lexeme) (get-start-line IS-get-start-line) (get-start-column IS-get-start-column) (get-start-offset IS-get-start-offset) (start-func (prepare-start))) (lambda () (init-lexeme) (let ((yyline (get-start-line)) (yycolumn (get-start-column)) (yyoffset (get-start-offset))) ((start-func) yyline yycolumn yyoffset)))))) (prepare-lexer (lambda () (cond ((eq? counters-type 'none) (prepare-lexer-none)) ((eq? counters-type 'line) (prepare-lexer-line)) ((eq? counters-type 'all) (prepare-lexer-all)))))) ; Calculer la valeur de <<EOF>>-action et de <<ERROR>>-action (set! <<EOF>>-action (prepare-special-action <<EOF>>-pre-action)) (set! <<ERROR>>-action (prepare-special-action <<ERROR>>-pre-action)) ; Calculer la valeur de rules-actions (let* ((len (quotient (vector-length rules-pre-actions) 2)) (v (make-vector len))) (let loop ((r (- len 1))) (if (< r 0) (set! rules-actions v) (let* ((yytext? (vector-ref rules-pre-actions (* 2 r))) (pre-action (vector-ref rules-pre-actions (+ (* 2 r) 1))) (action (if yytext? (prepare-action-yytext pre-action) (prepare-action-no-yytext pre-action)))) (vector-set! v r action) (loop (- r 1)))))) ; Calculer la valeur de states (let* ((len (vector-length trees-v)) (v (make-vector len))) (let loop ((s (- len 1))) (if (< s 0) (set! states v) (begin (vector-set! v s (prepare-state s)) (loop (- s 1)))))) ; Calculer la valeur de final-lexer (set! final-lexer (prepare-lexer)) ; Executer les hooks (apply-hooks) ; Resultat final-lexer))) ; Fabrication de lexer a partir de listes de caracteres taggees (define lexer-make-char-lexer (let* ((char->class (lambda (c) (let ((n (char->integer c))) (list (cons n n))))) (merge-sort (lambda (l combine zero-elt) (if (null? l) zero-elt (let loop1 ((l l)) (if (null? (cdr l)) (car l) (loop1 (let loop2 ((l l)) (cond ((null? l) l) ((null? (cdr l)) l) (else (cons (combine (car l) (cadr l)) (loop2 (cddr l)))))))))))) (finite-class-union (lambda (c1 c2) (let loop ((c1 c1) (c2 c2) (u '())) (if (null? c1) (if (null? c2) (reverse u) (loop c1 (cdr c2) (cons (car c2) u))) (if (null? c2) (loop (cdr c1) c2 (cons (car c1) u)) (let* ((r1 (car c1)) (r2 (car c2)) (r1start (car r1)) (r1end (cdr r1)) (r2start (car r2)) (r2end (cdr r2))) (if (<= r1start r2start) (cond ((< (+ r1end 1) r2start) (loop (cdr c1) c2 (cons r1 u))) ((<= r1end r2end) (loop (cdr c1) (cons (cons r1start r2end) (cdr c2)) u)) (else (loop c1 (cdr c2) u))) (cond ((> r1start (+ r2end 1)) (loop c1 (cdr c2) (cons r2 u))) ((>= r1end r2end) (loop (cons (cons r2start r1end) (cdr c1)) (cdr c2) u)) (else (loop (cdr c1) c2 u)))))))))) (char-list->class (lambda (cl) (let ((classes (map char->class cl))) (merge-sort classes finite-class-union '())))) (class-< (lambda (b1 b2) (cond ((eq? b1 'inf+) #f) ((eq? b2 'inf-) #f) ((eq? b1 'inf-) #t) ((eq? b2 'inf+) #t) (else (< b1 b2))))) (finite-class-compl (lambda (c) (let loop ((c c) (start 'inf-)) (if (null? c) (list (cons start 'inf+)) (let* ((r (car c)) (rstart (car r)) (rend (cdr r))) (if (class-< start rstart) (cons (cons start (- rstart 1)) (loop c rstart)) (loop (cdr c) (+ rend 1)))))))) (tagged-chars->class (lambda (tcl) (let* ((inverse? (car tcl)) (cl (cdr tcl)) (class-tmp (char-list->class cl))) (if inverse? (finite-class-compl class-tmp) class-tmp)))) (charc->arc (lambda (charc) (let* ((tcl (car charc)) (dest (cdr charc)) (class (tagged-chars->class tcl))) (cons class dest)))) (arc->sharcs (lambda (arc) (let* ((range-l (car arc)) (dest (cdr arc)) (op (lambda (range) (cons range dest)))) (map op range-l)))) (class-<= (lambda (b1 b2) (cond ((eq? b1 'inf-) #t) ((eq? b2 'inf+) #t) ((eq? b1 'inf+) #f) ((eq? b2 'inf-) #f) (else (<= b1 b2))))) (sharc-<= (lambda (sharc1 sharc2) (class-<= (caar sharc1) (caar sharc2)))) (merge-sharcs (lambda (l1 l2) (let loop ((l1 l1) (l2 l2)) (cond ((null? l1) l2) ((null? l2) l1) (else (let ((sharc1 (car l1)) (sharc2 (car l2))) (if (sharc-<= sharc1 sharc2) (cons sharc1 (loop (cdr l1) l2)) (cons sharc2 (loop l1 (cdr l2)))))))))) (class-= eqv?) (fill-error (lambda (sharcs) (let loop ((sharcs sharcs) (start 'inf-)) (cond ((class-= start 'inf+) '()) ((null? sharcs) (cons (cons (cons start 'inf+) 'err) (loop sharcs 'inf+))) (else (let* ((sharc (car sharcs)) (h (caar sharc)) (t (cdar sharc))) (if (class-< start h) (cons (cons (cons start (- h 1)) 'err) (loop sharcs h)) (cons sharc (loop (cdr sharcs) (if (class-= t 'inf+) 'inf+ (+ t 1))))))))))) (charcs->tree (lambda (charcs) (let* ((op (lambda (charc) (arc->sharcs (charc->arc charc)))) (sharcs-l (map op charcs)) (sorted-sharcs (merge-sort sharcs-l merge-sharcs '())) (full-sharcs (fill-error sorted-sharcs)) (op (lambda (sharc) (cons (caar sharc) (cdr sharc)))) (table (list->vector (map op full-sharcs)))) (let loop ((left 0) (right (- (vector-length table) 1))) (if (= left right) (cdr (vector-ref table left)) (let ((mid (quotient (+ left right 1) 2))) (if (and (= (+ left 2) right) (= (+ (car (vector-ref table mid)) 1) (car (vector-ref table right))) (eqv? (cdr (vector-ref table left)) (cdr (vector-ref table right)))) (list '= (car (vector-ref table mid)) (cdr (vector-ref table mid)) (cdr (vector-ref table left))) (list (car (vector-ref table mid)) (loop left (- mid 1)) (loop mid right)))))))))) (lambda (tables IS) (let ((counters (vector-ref tables 0)) (<<EOF>>-action (vector-ref tables 1)) (<<ERROR>>-action (vector-ref tables 2)) (rules-actions (vector-ref tables 3)) (nl-start (vector-ref tables 5)) (no-nl-start (vector-ref tables 6)) (charcs-v (vector-ref tables 7)) (acc-v (vector-ref tables 8))) (let* ((len (vector-length charcs-v)) (v (make-vector len))) (let loop ((i (- len 1))) (if (>= i 0) (begin (vector-set! v i (charcs->tree (vector-ref charcs-v i))) (loop (- i 1))) (lexer-make-tree-lexer (vector counters <<EOF>>-action <<ERROR>>-action rules-actions 'decision-trees nl-start no-nl-start v acc-v) IS)))))))) ; Fabrication d'un lexer a partir de code pre-genere (define lexer-make-code-lexer (lambda (tables IS) (let ((<<EOF>>-pre-action (vector-ref tables 1)) (<<ERROR>>-pre-action (vector-ref tables 2)) (rules-pre-action (vector-ref tables 3)) (code (vector-ref tables 5))) (code <<EOF>>-pre-action <<ERROR>>-pre-action rules-pre-action IS)))) (define lexer-make-lexer (lambda (tables IS) (let ((automaton-type (vector-ref tables 4))) (cond ((eq? automaton-type 'decision-trees) (lexer-make-tree-lexer tables IS)) ((eq? automaton-type 'tagged-chars-lists) (lexer-make-char-lexer tables IS)) ((eq? automaton-type 'code) (lexer-make-code-lexer tables IS)))))) ; ; Table generated from the file twiki.l by SILex 1.0 ; (define lexer-default-table (vector 'line (lambda (yycontinue yygetc yyungetc) (lambda (yytext yyline) (list 'end-of-input #f ) ;; yyline) )) (lambda (yycontinue yygetc yyungetc) (lambda (yytext yyline) (lex-error (conc yyline " : illegal character ") (yygetc)) )) (vector #t (lambda (yycontinue yygetc yyungetc) (lambda (yytext yyline) (list 'opensq yytext) )) #t (lambda (yycontinue yygetc yyungetc) (lambda (yytext yyline) (list 'closesq yytext) )) #t (lambda (yycontinue yygetc yyungetc) (lambda (yytext yyline) (list 'opensquig yytext) )) #t (lambda (yycontinue yygetc yyungetc) (lambda (yytext yyline) (list 'closesquig yytext) )) #t (lambda (yycontinue yygetc yyungetc) (lambda (yytext yyline) (list 'bang yytext) )) #t (lambda (yycontinue yygetc yyungetc) (lambda (yytext yyline) (list 'plaintext yytext) ))) 'decision-trees 0 0 '#((59 (35 (32 (9 err (11 1 err)) (33 1 (34 2 err))) (38 (= 36 err 1) (44 (39 err 1) (45 err 1)))) (95 (92 (65 err (91 1 6)) (93 1 (94 5 err))) (123 (= 96 err 1) (125 (124 4 err) (126 3 err))))) (44 (35 (11 (9 err 1) (= 32 1 err)) (37 (36 1 err) (= 38 err 1))) (92 (59 (45 err 1) (65 err (91 1 err))) (96 (93 1 (95 err 1)) (97 err (123 1 err))))) err err err err err) '#((#f . #f) (5 . 5) (4 . 4) (3 . 3) (2 . 2) (1 . 1) (0 . 0)))) ; ; User functions ; (define lexer #f) (define lexer-get-line #f) (define lexer-getc #f) (define lexer-ungetc #f) (define lexer-init (lambda (input-type input) (let ((IS (lexer-make-IS input-type input 'line))) (set! lexer (lexer-make-lexer lexer-default-table IS)) (set! lexer-get-line (lexer-get-func-line IS)) (set! lexer-getc (lexer-get-func-getc IS)) (set! lexer-ungetc (lexer-get-func-ungetc IS))))) |
Added stml2/modules/twiki/twiki.scm version [d0b51a85fd].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | ;; twiki module (require-extension silex sqlite3 regex posix) (include "twiki.l.scm") (define (twiki:open-db keys) (let* ((fname (twiki:keys->fname keys)) (fexists (file-exists? fname)) (db (dbi:open 'sqlite3 '((dbname . fname))))) (if (not fexists) (for-each (lambda (sqry) (dbi:exec db sqry)) '("CREATE TABLE dats (id INTEGER PRIMARY KEY,md5sum TEXT,dat BLOB,type INTEGER);" "CREATE TABLE tiddlers (id INTEGER PRIMARY KEY,wiki_id INTEGER,name TEXT,rev INTEGER,dat_id INTEGER,created_on INTEGER,changed_on INTEGER,owner_id INTEGER);" "CREATE TABLE revs (id INTEGER PRIMARY KEY,tag TEXT);" "CREATE TABLE wikis (id INTEGER PRIMARY KEY,key_name TEXT,title TEXT,created_on INTEGER);"))) (sqlite3:set-busy-timeout!(dbi:db-conn db) 1000000) db)) (define (twiki:view) (s:div 'class "node" (s:h1 "Twiki") "Title, pictures, etc." (let () "blah"))) (define (twiki:wiki . keys) (let ((key (conc keys))) (twiki:view))) (define (twiki:extract-tiddlers dat) (let* ((inp (open-input-string dat)) (prev-state #f) (stack (list 'start)) (links '()) (currlnk #f)) (lexer-init 'port inp) (let loop ((token (lexer))) (let ((token-type (car token)) (token-val (cadr token)) (state (car stack))) (if (not (eq? prev-state state)) (begin (print "state: " state) (set! prev-state state))) (case token-type ('end-of-input (print "Done")(close-input-port inp)) ('twikilink-start (set! stack (cons 'twikilink-start stack)) (loop (lexer))) ('twikilink-end (set! links (cons currlnk links)) (set! stack (cdr stack)) (loop (lexer))) ('twikitext (if (eq? state 'twikilink-start) (set! currlnk (cadr token)) (print "Got " token)) (loop (lexer))) ('anydat (loop (lexer))) (else (print "ERROR: unknown token " token " on line " (lexer-get-line)) (loop (lexer)))))) links)) |
Added stml2/modules/twiki/twikiparser.scm version [cc34f7c51f].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | (require-extension sqlite3 regex posix eformat silex stack regex) (define help " Usage: nldb [options] General -h : this help Netlist data queries -findpath start,end : find path from start to end. % is a wildcard Managing netlist data -load /path/to/netlist : load a model into the db -d dbname : name of the .db file -dump fname : dump the netlist in to verilog file ") (include "/nfs/an/home/mrwellan/stuff/tools/lnkmkr/args.scm") (include "verilog.l.scm") ;; process args (define remargs (get-args (argv) (list "-load" "-d" "-dump" "-findpath") (list "-h" ) arg-hash 0)) ;; (define dbpaths (list "testing.db")) (define dbpath #f) (if (get-arg "-d") (set! dbpath (get-arg "-d")) (for-each (lambda (path) (if (file-exists? path) (set! dbpath path))) dbpaths)) (if (and (not dbpath) (get-arg "-d")) (begin (print "Can't find db. " (get-arg "-d") " Try again or contact Matt!") (exit 1))) (define dbexists (file-exists? dbpath)) (define realuser (getenv "USER")) (define user realuser) (define db (sqlite3:open dbpath)) (sqlite3:set-busy-timeout! db 1000000) (define (mk-tables) (for-each (lambda (sqlstmt) (sqlite3:exec db sqlstmt)) (list "CREATE TABLE modules(id INTEGER PRIMARY KEY,name_id INTEGER);" "CREATE TABLE nets (id INTEGER PRIMARY KEY,name_id INTEGER,module_id INTEGER);" "CREATE TABLE insts (id INTEGER PRIMARY KEY,name_id INTEGER,module_id INTEGER,parent_id INTEGER);" "CREATE TABLE pins (id INTEGER PRIMARY KEY,name_id INTEGER,module_id INTEGER,net_id INTEGER,type_id INTEGER);" "CREATE TABLE conns (id INTEGER PRIMARY KEY,net_id INTEGER,inst_id INTEGER,pin_id INTEGER);" "CREATE TABLE names (id INTEGER PRIMARY KEY,name TEXT);" "CREATE TABLE types(id INTEGER PRIMARY KEY,type TEXT);" "INSERT INTO types VALUES(1, 'undef');" "INSERT INTO types VALUES(2, 'input');" "INSERT INTO types VALUES(3, 'output');" "INSERT INTO types VALUES(4, 'inout');" "INSERT INTO types VALUES(5, 'pwr');" "PRAGMA synchronous=OFF;"))) (if (not dbexists)(mk-tables)) ;;====================================================================== ;; NETLIST READING ;;====================================================================== ;; Use a stack to tracking state ;; (define nldb:*stack* (make-stack)) (define (nldb:read-files fnames) ;; read in a list of files (for-each (lambda (fname) (if (file-exists? fname) (nldb:read-file fname))) fnames)) ;;====================================================================== ;; PRECOMPILED REGEXS ;;====================================================================== (define nldb:escaped-name (regexp "^\\s*\\\\([^\\s]+)\\s*")) (define nldb:trailing-garbage (regexp "^\\s*([^\\s,;]+)[,;\\s]*$")) (define nldb:module-pin (regexp "^\\s*([^\\s]+)\\s*([,\\s\\)]*)")) (define nldb:pins-end (regexp "\\)\\s*;")) (define nldb:input-output (regexp "\\s*(input|output)\\s+([^\\s]+)[\\s;,]")) ;; modname instname( .\pinname[35] (\netname ), (define nldb:instance (regexp "^\\s*([^\\s]+)\\s+([^\\s]+)\\s*\\(\\s*\\.([^\\s]+)\\s*\\(\\s*([^\\s]+)\\s*\\)\\s*,")) (define nldb:inst-conn (regexp "^\\s*\\.([^\\s]+)\\s*\\(\\s*([^\\s])+\\s+\\)\\s*([\\),;]+)")) ;; module_name netname (opt) (define nldb:module-regex (regexp "^\\s*module\\s+([^\\s]+)\\s*\\(\\s*([^\\s,]+\\s*,|)$")) ;;====================================================================== ;; MISC ;;====================================================================== ;; apply regex and set nldb:match-val (define nldb:match-val #f) (define (nldb:regex-match r l) (let ((m (string-match r l))) (set! nldb:match-val m) m)) ;; stmt can only return *one* value!! (define (nldb:sqlite3:get-one stmt . params) (let ((sqlstmt (sqlite3:prepare db stmt)) (result #f)) (apply sqlite3:for-each-row (lambda (x) (set! result x)) sqlstmt params) (sqlite3:finalize! sqlstmt) result)) ;;====================================================================== ;; CACHE ;;====================================================================== (define *cache* (make-hash-table)) (define *module-name-cache* (make-hash-table)) (define (cache-get-module-hash module) (sub-hash-create-get *cache* module)) (define (sub-hash-create-get subhash key) (let ((shash (hash-table-get/default subhash key))) (if shash shash (let ((newh (make-hash-table))) (hash-table-set! subhash key newh) newh)))) ;; (cache-set! "abc_adder" 'pin "addrin" 0) (define (cache-set! module objtype objname value) (let* ((mhash (cache-get-module-hash module)) (thash (sub-hash-create-get mhash objtype))) (hash-table-set! thash objname value))) (define (cache-ref module objtype objname) (let ((mhash (hash-table-ref/default *cache* module))) (if mhash (let ((ohash (hash-table-ref/default mhash objtype))) (if ohash (hash-table-ref/default ohash objname) #f)) #f))) ;;====================================================================== ;; NAMES ;;====================================================================== (define nldb:names-hash (make-hash-table)) ;; always sucessful. inserts name if not found (define (nldb:get-name-id name) (let ((cached-id (hash-table-ref/default nldb:names-hash name #f))) (if cached-id cached-id (let ((id (nldb:sqlite3:get-one "SELECT id FROM names WHERE name=?;" name))) (if id (begin (hash-table-set! nldb:names-hash name id ) id) (begin (sqlite3:exec db "INSERT INTO names (name) VALUES (?);" name) (nldb:get-name-id name))))))) (define (nldb:clean-name name) (if (nldb:regex-match nldb:escaped-name name) ;; process escaped identifiers (list-ref nldb:match-val 1) (if (nldb:regex-match nldb:trailing-garbage name) (list-ref nldb:match-val 1) name))) ;;====================================================================== ;; MODULES ;;====================================================================== ;; add a module and return its id. (define (nldb:get-module-id name-id) (let ((id (nldb:sqlite3:get-one "SELECT id FROM modules WHERE name_id=?;" name-id))) (if id id (begin (nldb:insert-module name-id) (nldb:get-module-id name-id))))) ;; now retrieve and return the id ;; not safe to use outside of get-module-id - could add duplicates (define (nldb:insert-module name-id) (sqlite3:exec db "INSERT INTO modules (name_id) VALUES (?);" name-id)) ;; module namespace is unique so this is ok, should check for redefining though. (define (nldb:get-module-by-name name) (let ((module-id (hash-table-ref *module-name-cache* name))) (if module-id module-id (let ((mid (nldb:get-module-id (nldb:get-name-id name)))) (hash-table-set! *module-name-cache* name mid))))) ;;====================================================================== ;; PINS ;;====================================================================== (define (nldb:get-pin-id module-id name-id) (nldb:sqlite3:get-one (string-append "SELECT id FROM pins WHERE module_id=? AND name_id=?;") module-id name-id)) (define (nldb:add-pin module-id name-id type-id) (let ((pin-id (nldb:get-pin-id module-id name-id))) (if pin-id pin-id (begin (nldb:insert-pin module-id name-id type-id) (nldb:get-pin-id module-id name-id))))) (define (nldb:insert-pin module-id name-id type-id) (sqlite3:exec db "INSERT INTO pins (module_id,name_id,type_id) VALUES (?,?,?);" module-id name-id (if type-id type-id 0))) (define (nldb:set-pin-direction pin-id direction) (sqlite3:exec db "UPDATE pins SET type_id=(SELECT id FROM types WHERE type=?) WHERE id=?;" direction pin-id)) (define (nldb:set-pin-net pin-id net-id) (sqlite3:exec db "UPDATE pins SET net_id=? WHERE id=?;" net-id pin-id)) ;;==================================================================== ;; CONNS ;;====================================================================== (define (nldb:get-conn-id inst-id pin-id) ;; (if (not (and inst-id pin-id))(print "ERROR: nldb:get-conn-id called with bad params: inst-id " inst-id " pin-id " pin-id) (nldb:sqlite3:get-one "SELECT id FROM conns WHERE inst_id=? AND pin_id=?;" inst-id pin-id)) (define (nldb:add-conn inst-id pin-id net-id) ;; (if (not (and inst-id pin-id net-id))(print "ERROR: nldb:add-conn called with bad params: inst-id " inst-id " pin-id " pin-id " net-id " net-id) (let ((conn-id (nldb:get-conn-id inst-id pin-id))) (if conn-id conn-id (begin (nldb:insert-conn inst-id pin-id net-id) (nldb:get-conn-id inst-id pin-id))))) (define (nldb:insert-conn inst-id pin-id net-id) ;; (if (not (and inst-id pin-id net-id))(print "ERROR: nldb:insert-conn called with bad params: inst-id " inst-id " pin-id " pin-id " net-id " net-id) (sqlite3:exec db "INSERT INTO conns (inst_id,pin_id,net_id) VALUES (?,?,?);" inst-id pin-id net-id )) ;;====================================================================== ;; NET ;;====================================================================== (define (nldb:get-net-id module-id name-id) (nldb:sqlite3:get-one "SELECT id FROM nets WHERE name_id=?;" name-id)) (define (nldb:add-net module-id name-id) (let ((net-id (nldb:get-net-id module-id name-id))) (if net-id net-id (begin (nldb:insert-net module-id name-id) (nldb:get-net-id module-id name-id))))) (define (nldb:insert-net module-id name-id) (sqlite3:exec db "INSERT INTO nets (module_id,name_id) VALUES(?,?);" module-id name-id)) ;;====================================================================== ;; INSTANCES ;;====================================================================== (define (nldb:get-inst-id parent-id name-id) (nldb:sqlite3:get-one "SELECT id FROM insts WHERE parent_id=? AND name_id=?;" parent-id name-id)) ;; sub-mod-id = type of instance, parent-id = where instantiated (define (nldb:add-inst module-id parent-id name-id) (let ((inst-id (nldb:get-inst-id parent-id name-id))) ;; parent and name are enough to identify it (if inst-id inst-id (begin (nldb:insert-inst module-id parent-id name-id) (nldb:get-inst-id parent-id name-id))))) (define (nldb:insert-inst module-id parent-id name-id) (sqlite3:exec db "INSERT INTO insts (module_id,parent_id,name_id) VALUES(?,?,?);" module-id parent-id name-id)) ;;====================================================================== ;; RECORD FOR STATE ;;====================================================================== (define *statevec* (make-vector 5)) (define-inline (curr-pin-id) (vector-ref *statevec* 0)) (define-inline (curr-inst-id) (vector-ref *statevec* 1)) (define-inline (curr-module-id) (vector-ref *statevec* 2)) (define-inline (curr-inst-module-id) (vector-ref *statevec* 3)) (define-inline (set-curr-pin-id! id)(vector-set! *statevec* 0 id)) (define-inline (set-curr-inst-id! id)(vector-set! *statevec* 1 id)) (define-inline (set-curr-module-id! id)(vector-set! *statevec* 2 id)) (define-inline (set-curr-inst-module-id! id)(vector-set! *statevec* 3 id)) ;;====================================================================== ;; FILE I/O ;;====================================================================== ;; Initialization and support routines for nldb:read-file (stack-push! nldb:*stack* 'start) (define nldb:esc-regex (regexp "^\\\\([^\\s]*)\\s*$") ) (define (nldb:clean-identifier token) (let* ((t (car token)) (v (cadr token)) (ctm (string-match nldb:esc-regex v))) (list 'identifier (list-ref ctm 1)))) (define (nldb:read-file fname) (let* ((inp (open-input-file fname)) (prev-state #f)) (lexer-init 'port inp) (let loop ((token (lexer))) (let ((token-type (car token)) (token-val (cadr token)) (state (stack-peek herc:*stack*))) (if (not (eq? prev-state state)) (begin (print "state: " state) (set! prev-state state))) (case token-type ('end-of-input (print "Done")(close-input-port inp)) ('whitespace (loop (lexer))) ;; skip whitespace ('comment-begin (stack-push! herc:*stack* 'comment ) (loop (lexer))) ('comment-end (stack-pop! herc:*stack*)(loop (lexer))) ('begin (stack-push! herc:*stack* 'begin)(loop (lexer))) ('end (stack-pop! herc:*stack*)(loop (lexer))) ('cell (case state ('begin (stack-push! herc:*stack* 'cell-name) (loop (lexer))) (else (loop (lexer))))) ('plainidentifier (case state ('cell-name ('statementend (stack-pop! nldb:*stack*)(loop (lexer))) ('endparen (stack-pop! nldb:*stack*)(loop (lexer))) ('endmodule (stack-pop! nldb:*stack*)(loop (lexer))) ('startparen (case state ('module-pins (loop (lexer))) ('inst-def (loop (lexer))) ('inst-conn-def (loop (lexer))) ('pin-net (loop (lexer))) (else (print "ERROR: Didn't expect an open paren here! Line " (lexer-get-line))))) ('comma (case state ('module-pins (loop (lexer))) ('input-pin (loop (lexer))) ('output-pin (loop (lexer))) ('wire (loop (lexer))) ('inst-conn-def (loop (lexer))) ;; (stack-pop! nldb:*stack*) (loop (lexer))) (else (print "ERROR: Didn't expect a comma here! Line " (lexer-get-line))))) ('module (case state ('start (stack-push! nldb:*stack* 'module) ;; we will be in a module (stack-push! nldb:*stack* 'module-def)) ;; starting in the def (else (print "ERROR: Didn't expect module declaration here! Line " (lexer-get-line)))) (loop (lexer))) ('input (case state ('module (stack-push! nldb:*stack* 'input-pin)) (else (print "ERROR: Didn't expect \"input\" statement here! Linenum " (lexer-get-line)))) (loop (lexer))) ('output (case state ('module (stack-push! nldb:*stack* 'output-pin)) (else (print "ERROR: Didn't expect \"output\" statement here! Linenum " (lexer-get-line)))) (loop (lexer))) ('inout (case state ('module (stack-push! nldb:*stack* 'inout-pin)) (else (print "ERROR: Didn't expect \"inout\" statement here! Linenum " (lexer-get-line)))) (loop (lexer))) ('pin (case state ('inst-conn-def (let* ((pin-name (substring token-val 1 (string-length token-val))) (pin-name-id (nldb:get-name-id pin-name)) (pin-id (nldb:add-pin (curr-module-id) pin-name-id #f))) (stack-push! nldb:*stack* 'pin-net) (set-curr-pin-id! pin-id) (loop (lexer)))) (else (print "ERROR: Didn't expect pin here " token-val " Linenum: " (lexer-get-line))))) ('identifier (case state ('module ;; this must be an instance, an identifier at the top level (let* ((inst-mod-id (nldb:get-module-by-name token-val))) (set-curr-inst-module-id! inst-mod-id) (stack-push! nldb:*stack* 'inst-def)) (loop (lexer))) ('inst-def ;; inst-module type parent-id inst-name-id (let* ((inst-id (nldb:add-inst (curr-inst-module-id)(curr-module-id)(nldb:get-name-id token-val)))) (set-curr-inst-id! inst-id)) (stack-push! nldb:*stack* 'inst-conn-def) (loop (lexer))) ('module-def (let* ((m-id (nldb:get-module-by-name token-val))) (set-curr-module-id! m-id)) (stack-push! nldb:*stack* 'module-pins)) ('module-pins (nldb:add-pin (curr-module-id) (nldb:get-name-id token-val) #f)) ('input-pin (let ((pin-id (nldb:get-pin-id (curr-module-id) (nldb:get-name-id token-val)))) (nldb:set-pin-direction pin-id "input"))) ('output-pin (let ((pin-id (nldb:get-pin-id (curr-module-id) (nldb:get-name-id token-val)))) (nldb:set-pin-direction pin-id "output"))) ('inout-pin (let ((pin-id (nldb:get-pin-id (curr-module-id) (nldb:get-name-id token-val)))) (nldb:set-pin-direction pin-id "inout"))) ('pin-net (let* ((net-name-id (nldb:get-name-id token-val)) (net-id (nldb:add-net (curr-inst-module-id) net-name-id))) (nldb:add-conn (curr-inst-id) (curr-pin-id) net-id))) (else (print "ERROR: Didn't expect an identifier here! Token " token-val " Line " (lexer-get-line)))) (loop (lexer))) (else (print "ERROR: unknown token " token " on line " (lexer-get-line)) (loop (lexer)))))))) |
Added stml2/requirements.scm.template version [b71aaa144e].
> > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | ;; choose your db interface as appropriate (require-extension sqlite3) (import (prefix sqlite3 sqlite3:)) ;; (require-extension postgresql) ;; (import (prefix postgresql pg:)) ;; (require-extension cgi-util) ;; (require-extension cookie) (use posix) ;; (require-extension proplist) (use regex) (use srfi-1) ;; (require-extension tinyclos) (use srfi-69) (use data-structures) |
Added stml2/rollup-pages.scm version [b24bc2e231].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | (use regex posix srfi-69 srfi-1) (define extract-rx (regexp "pages\\/(.*)_(view|ctrl).scm")) (define (print-page-wrapper lookup page) (print "(define (pages:" page " session db shared)") (if (hash-table-ref/default lookup (conc page "_ctrl") #f) (print "(include \"pages/" page "_ctrl.scm\")")) (if (hash-table-ref/default lookup (conc page "_view") #f) (print "(include \"pages/" page "_view.scm\")")) (print ")\n")) (let* ((views (glob "pages/*_view.scm")) (ctrls (glob "pages/*_ctrl.scm")) (all (append views ctrls)) (lookup (make-hash-table)) (pages (delete-duplicates (map (lambda (x) (let* ((res (string-match extract-rx x)) (page (cadr res)) (type (caddr res))) (hash-table-set! lookup (conc page "_" type) #t) (cadr res))) all)))) (if (null? all)(begin (print "No page files matching pages/*_(view|ctrl).scm")(exit))) (print "Pages: " pages) ;; first the individual rollup wrappers (used by the dynamic load) (for-each (lambda (page) (let ((pagefile (conc "pages/" page ".scm"))) (print "page " page " ") (if (not (file-exists? pagefile)) (begin (with-output-to-file pagefile (lambda () (print-page-wrapper lookup page))) (print " created")) (print " already created")))) pages) ;; then the monolithic rollup wrapper (used in compiling the single-executable) (with-output-to-file "all_pages.scm" (lambda () (for-each (lambda (page) (print-page-wrapper lookup page)) pages)))) |
Added stml2/session.scm version [300e7014a0].
> > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | ;; Copyright 2007-2011, Matthew Welland. ;; ;; This program is made available under the GNU GPL version 2.0 or ;; greater. See the accompanying file COPYING for details. ;; ;; This program is distributed WITHOUT ANY WARRANTY; without even the ;; implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR ;; PURPOSE. ;; (declare (unit session)) (module session * (import chicken scheme data-structures extras srfi-13 ports posix files srfi-1) (use (prefix dbi dbi:) srfi-69) (require-extension regex) (use cookie stmlcommon) ;; (declare (uses cookie)) ) |
Added stml2/sessions.sql version [051fddcb13].
> > > > > | 1 2 3 4 5 | CREATE TABLE session_vars (id integer primary key, session_id integer, page text, key text, value text); CREATE TABLE sessions ( id integer primary key, session_key text); |
Added stml2/setup.scm version [27fec5f813].
> > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | ;; Copyright 2007-2011, Matthew Welland. ;; ;; This program is made available under the GNU GPL version 2.0 or ;; greater. See the accompanying file COPYING for details. ;; ;; This program is distributed WITHOUT ANY WARRANTY; without even the ;; implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR ;; PURPOSE. (module setup * (import chicken scheme data-structures extras srfi-13 ports posix) (uses session misc-stml) ;; (declare (unit setup))se ;; (declare (uses session)) (require-extension srfi-69) (require-extension regex) ) |
Added stml2/spiffyserver.scm version [0953505b2d].
> > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 | ;; This doesn't work yet ;; (use spiffy cgi-handler) (spiffy-debug-mode #t) (spiffy-file-ext-handlers `(("drcdb" . ,(cgi-handler* "/path/to/drcdb")))) (spiffy-root-path "/path/to/web") (start-server location: (get-host-name) init: noop) |
Added stml2/sqlite3.scm version [935dbe7787].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | ;; Copyright 2007-2011, Matthew Welland. ;; ;; This program is made available under the GNU GPL version 2.0 or ;; greater. See the accompanying file COPYING for details. ;; ;; This program is distributed WITHOUT ANY WARRANTY; without even the ;; implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR ;; PURPOSE. ;; ;; I used this to get a simple interactive sqlite editor on the nokia n800 ;; since I couldn't get sqlite3 to install (for reasons I can't remember). (use sqlite3) (define args (argv)) (define num-args (length args)) (define dbname #f) (define cmd #f) (if (> num-args 1) (set! dbname (cadr args)) (exit 0)) (if (> num-args 2) (set! cmd (caddr args))) (define db (sqlite3:open dbname)) (define (interactive db) (let ((prompt " > ")) (display prompt) (let loop ((cmd (read-line))) (cond ((> (string-length cmd) 0) (process-cmd db cmd) (display prompt) (loop (read-line))) (else (loop (read-line))))))) (define (process-cmd db cmd) (sqlite3:for-each-row (lambda (a . b) (print a " " (string-intersperse b " "))) db cmd)) (if cmd (process-cmd db cmd) (interactive db)) (sqlite3:finalize! db) |
Added stml2/stml.config.template version [007967e3ce].
> > > > > > > > | 1 2 3 4 5 6 7 8 | '(sroot "/path/to/{pages,models}/dir" logfile "/tmp/stmlrun/logs.log" dbtype sqlite3 dbinit ((dbname . "test-stml.db") (user . "nobody") (password . "Dapassword") (host . "localhost")) domain "192.168.1.150") |
Added stml2/stml2.meta version [e8cabdbc79].
> > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | ( ; Your egg's license: (license "LGPL") ; Pick one from the list of categories (see below) for your egg and enter it ; here. (category misc) ; A list of eggs mpeg3 depends on. If none, you can omit this declaration ; altogether. If you are making an egg for chicken 3 and you need to use ; procedures from the `files' unit, be sure to include the `files' egg in the ; `needs' section (chicken versions < 3.4.0 don't provide the `files' unit). ; `depends' is an alias to `needs'. (needs srfi-69) ; A list of eggs required for TESTING ONLY. See the `Tests' section. (test-depends test) (author "Matt Welland") (synopsis "Primitive argument processor.")) |
Added stml2/stml2.scm version [ee4c13898d].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | ;; Copyright 2007-2011, Matthew Welland. ;; ;; This program is made available under the GNU GPL version 2.0 or ;; greater. See the accompanying file COPYING for details. ;; ;; This program is distributed WITHOUT ANY WARRANTY; without even the ;; implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR ;; PURPOSE. ;; stml is a list of html strings ;; (declare (unit stml)) (module stml2 * (import chicken scheme data-structures extras srfi-13 ports posix srfi-69 files srfi-1) (import cookie) (use (prefix dbi dbi:) (prefix crypt c:) typed-records) ;; (declare (uses misc-stml)) (use regex) ;; The (usually global) sdat contains everything about the session ;; (defstruct sdat ;; database (dbtype 'pg) (dbinit #f) (conn #f) ;; page info (page "index") (page-type 'html) (toppage "index") (curr-page "index") (content-type "Content-type: text/html; charset=iso-8859-1\n\n") ;; forms and variables (formdat #f) (params '()) (path-params '()) (session-key #f) (pagedat '()) (alt-page-dat #f) (session-cookie #f) (pagevars (make-hash-table)) (pagevars-before (make-hash-table)) (sessionvars (make-hash-table)) (sessionvars-before (make-hash-table)) (globalvars (make-hash-table)) (globalvars-before (make-hash-table)) ;; ports and log file (curr-err #f) (log-port (current-error-port)) (logfile "/tmp/stml.log") (seen-pages '()) (page-dir-style 'flat) (debug-mode #f) (session-id #f) (request-method #f) (domain "localhost") (twikidir #f) (script #f) (force-ssl #f) (shared-hash (make-hash-table)) ;; paths (sroot "./") (models #f) (views #f) ) (define (sdat-set-if session configdat var settor) (let ((val (s:find-param var configdat))) (if val (settor session val)))) (define (session:initialize session #!optional (configf #f)) ;; (let* ((rawconfigdat (session:read-config session configf)) ;; (configdat (if rawconfigdat (eval rawconfigdat) '()))) ;; (sdat-set-if session configdat 'sroot sdat-root-set!) ;; (sdat-set-if session configdat 'logfile sdat-logfile-set!) ;; (sdat-set-if session configdat 'dbtype sdat-dbtype-set!) ;; (sdat-set-if session configdat 'dbinit sdat-dbinit-set!) ;; (sdat-set-if session configdat 'domain sdat-domain-set!) ;; (sdat-set-if session configdat 'twikidir sdat-twikidir-set!) ;; (sdat-set-if session configdat 'page-dir-style sdat-page-set!) ;; (sdat-set-if session configdat 'sroot sdat-root-set!) ;; (sdat-set-if session configdat 'sroot sdat-root-set!) ;; (sdat-set-if session configdat 'sroot sdat-root-set!) ;; following are set always from config ;; (sdat-page-dir-style-set! session (s:find-param 'page-dir-style configdat)) (let* ((rawconfigdat (session:read-config session configf)) (configdat (if rawconfigdat (eval rawconfigdat) '())) (sroot (s:find-param 'sroot configdat)) (models (s:find-param 'models configdat)) (views (s:find-param 'views configdat)) (logfile (s:find-param 'logfile configdat)) (dbtype (s:find-param 'dbtype configdat)) (dbinit (s:find-param 'dbinit configdat)) (domain (s:find-param 'domain configdat)) (twikidir (s:find-param 'twikidir configdat)) (page-dir (s:find-param 'page-dir-style configdat)) (debugmode (or (s:find-param 'debug-mode configdat)(s:find-param 'debugmode configdat))) (script (s:find-param 'script configdat)) (force-ssl (s:find-param 'force-ssl configdat))) (if sroot (sdat-sroot-set! session sroot)) (if models (sdat-models-set! session models)) (if views (sdat-views-set! session views)) (if logfile (sdat-logfile-set! session logfile)) (if dbtype (sdat-dbtype-set! session dbtype)) (if dbinit (sdat-dbinit-set! session dbinit)) (if domain (sdat-domain-set! session domain)) (if twikidir (sdat-twikidir-set! session twikidir)) (if debugmode (sdat-debug-mode-set! session debugmode)) (if script (sdat-script-set! session script)) (if force-ssl (sdat-force-ssl-set! session force-ssl)) (sdat-page-dir-style-set! session page-dir) ;; (print "configdat: ")(pp configdat) (if debugmode (session:log session "sroot: " sroot " logfile: " logfile " dbtype: " dbtype " dbinit: " dbinit " domain: " domain " page-dir-style: " page-dir)) )) ;; extract various tokens from the parameter list ;; 'key val => put in the params list ;; strings => maintain order and add to the datalist <<== IMPORTANT (define (s:extract inlst) (if (null? inlst) inlst (let loop ((data '()) (params '()) (head (car inlst)) (tail (cdr inlst))) ;; (print "head=" head " tail=" tail) (cond ((null? tail) (if (symbol? head) ;; the last item is a param - borked (s:log "ERROR: param with no value")) (list (append data (list (s:any->string head))) params)) ((or (string? head)(list? head)(number? head)) (loop (append data (list (s:any->string head))) params (car tail) (cdr tail))) ((symbol? head) (let ((new-params (cons (list head (car tail)) params)) (new-tail (cdr tail))) (if (null? new-tail) ;; we are done, no more params etc. (list data new-params) (loop data new-params (car new-tail)(cdr new-tail))))) (else (s:log "WARNING: Malformed input, you have broken stml, remember that all stml calls should return a result (null list or empty string is ok):\n head=" head "\n tail=" tail "\n inlst=" inlst "\n params=" params) (if (null? tail) (list data params) (loop data params (car tail)(cdr tail)))))))) ;; most tags can be handled by this routine (define (s:common-tag tagname args) (let* ((inputs (s:extract args)) (data (car inputs)) (params (s:process-params (cadr inputs)))) (list (conc "<" tagname params ">") data (conc "</" tagname ">")))) ;; Suggestion: order these alphabetically (define (s:a . args) (s:common-tag "A" args)) (define (s:b . args) (s:common-tag "B" args)) (define (s:u . args) (s:common-tag "U" args)) (define (s:big . args) (s:common-tag "BIG" args)) (define (s:body . args) (s:common-tag "BODY" args)) (define (s:button . args) (s:common-tag "BUTTON" args)) (define (s:center . args) (s:common-tag "CENTER" args)) (define (s:code . args) (s:common-tag "CODE" args)) (define (s:div . args) (s:common-tag "DIV" args)) (define (s:h1 . args) (s:common-tag "H1" args)) (define (s:h2 . args) (s:common-tag "H2" args)) (define (s:h3 . args) (s:common-tag "H3" args)) (define (s:h4 . args) (s:common-tag "H4" args)) (define (s:h5 . args) (s:common-tag "H5" args)) (define (s:head . args) (s:common-tag "HEAD" args)) (define (s:html . args) (s:common-tag "HTML" args)) (define (s:i . args) (s:common-tag "I" args)) (define (s:img . args) (s:common-tag "IMG" args)) (define (s:input . args) (s:common-tag "INPUT" args)) (define (s:output . args) (s:common-tag "OUTPUT" args)) (define (s:link . args) (s:common-tag "LINK" args)) (define (s:p . args) (s:common-tag "P" args)) (define (s:strong . args) (s:common-tag "STRONG" args)) (define (s:table . args) (s:common-tag "TABLE" args)) (define (s:tbody . args) (s:common-tag "TBODY" args)) (define (s:thead . args) (s:common-tag "THEAD" args)) (define (s:th . args) (s:common-tag "TH" args)) (define (s:td . args) (s:common-tag "TD" args)) (define (s:title . args) (s:common-tag "TITLE" args)) (define (s:tr . args) (s:common-tag "TR" args)) (define (s:small . args) (s:common-tag "SMALL" args)) (define (s:quote . args) (s:common-tag "QUOTE" args)) (define (s:hr . args) (s:common-tag "HR" args)) (define (s:li . args) (s:common-tag "LI" args)) (define (s:ul . args) (s:common-tag "UL" args)) (define (s:ol . args) (s:common-tag "OL" args)) (define (s:dl . args) (s:common-tag "DL" args)) (define (s:dt . args) (s:common-tag "DT" args)) (define (s:dd . args) (s:common-tag "DD" args)) (define (s:pre . args) (s:common-tag "PRE" args)) (define (s:span . args) (s:common-tag "SPAN" args)) (define (s:label . args) (s:common-tag "LABEL" args)) (define (s:script . args) (s:common-tag "SCRIPT" args)) (define (s:dblquote . args) (let* ((inputs (s:extract args)) (data (caar inputs)) (params (s:process-params (cadr inputs)))) (conc """ data """))) (define (s:br . args) "<BR>") ;; THIS MAY NOT WORK!!!! BR CAN (MISTAKENLY) GET PARAM TEXT ;; (define (s:br . args) (s:common-tag "BR" args)) (define (s:font . args) (s:common-tag "FONT" args)) (define (s:err-font . args) (s:b (s:font 'color "red" args))) (define (s:comment . args) (let* ((inputs (s:extract args)) (data (car inputs)) (params (s:process-params (cadr inputs)))) (list "<!--" data "-->"))) (define (s:null . args) ;; nop (let* ((inputs (s:extract args)) (data (car inputs)) (params (s:process-params (cadr inputs)))) (list data))) ;; puts a nice box around a chunk of stuff (define (s:fieldset legend . args) (list "<FIELDSET><LEGEND>" legend "</LEGEND>" args "</FIELDSET>")) ;; given a string return the string if it is non-white space or otherwise (define (s:nbsp str) (if (string-match "^\\s*$" str) " " str)) ;; USE 'page_override to override a linkto page from a button (define (s:form . args) ;; create a link for calling back into the current page and calling a specified ;; function (let* ((action (let ((v (s:find-param 'action args))) (if v v "default"))) (id (let ((i (s:find-param 'id args))) (if i i #f))) (page (let ((p (sdat-page s:session))) (if p p "home"))) ;; (link (session:link-to s:session page (if id ;; (list 'action action 'id id) ;; (list 'action action))))) (link (if (string=? (substring action 0 5) "http:") ;; if first part of string is http: action (session:link-to s:session page (if id (list 'action action 'id id) (list 'action action)))))) ;; (script (slot-ref s:session 'script)) ;; (action-str (string-append script "/" page "?action=" action))) (s:common-tag "FORM" (append (s:remove-param-matching (s:remove-param-matching args 'action) 'id) (list 'action link))))) ;; look up the variable name (via the 'name tag) then inject the value from the session var ;; replacing the 'value value if it is already there, adding it if it is not. (define (s:preserve tag args) (let* ((var-name (s:find-param 'name args)) ;; name='varname' (value (let ((v (s:get var-name))) (if v v #f))) (newargs (append (s:remove-param-matching args 'value) (if value (list 'value value) '())))) (s:common-tag tag newargs))) (define (s:input-preserve . args) (s:preserve "INPUT" args)) ;; text areas are done a little differently. The value is stored between the tags <textarea ...>the value goes here</textarea> (define (s:textarea-preserve . args) (let* ((var-name (s:find-param 'name args)) (value (let ((v (s:get var-name))) (if v v #f)))) (s:common-tag "TEXTAREA" (if value (cons value args) args)))) (define (s:option dat) (let ((len (length dat))) (cond ((eq? len 1) (let ((item (car dat))) (s:option (list item item item)))) ((eq? len 2) (s:option (append dat (list (car dat))))) (else (let ((label (car dat)) (value (cadr dat)) (dispval (caddr dat)) (selected (if (> len 3)(cadddr dat) #f))) (list (conc "<OPTION " (if selected " selected " "") "label=\"" label "\" value=\"" value "\">" dispval "</OPTION>"))))))) ;; call only with (label (label value dispval [#t]) ...) ;; NB// sadly this block is redundantly almost identical to the s:select ;; fix that later ... (define (s:optgroup dat) (let ((label (car dat)) (rem (cdr dat))) (if (null? rem) (s:common-tag "OPTGROUP" `('label ,label)) (let loop ((hed (car rem)) (tal (cdr rem)) (res (list (conc "<OPTGROUP label=" label)))) ;; (print "hed: " hed " tal: " tal " res: " res) (let ((new (append res (list (if (list? (cadr hed)) (s:optgroup hed) (s:option hed)))))) (if (null? tal) (append new (list "</OPTGROUP>")) (loop (car tal)(cdr tal) new))))))) ;; items is a hierarchial alist ;; ( (label1 value1 dispval1 #t) ;; <== this one is selected ;; (label2 (label3 value2 dispval2) ;; (label4 value3 dispval3))) ;; ;; required arg is 'name (define (s:select items . args) (if (null? items) (s:common-tag "SELECT" args) (let loop ((hed (car items)) (tal (cdr items)) (res '())) ;; (print "hed: " hed " tal: " tal " res: " res) (let ((new (append res (list (if (and (> (length hed) 1) (list? (cadr hed))) (s:optgroup hed) (s:option hed)))))) (if (null? tal) (s:common-tag "SELECT" (cons new args)) (loop (car tal)(cdr tal) new)))))) (define (s:color . args) "#00ff00") (define (s:print indent inlst) (map (lambda (x) (cond ((or (string? x)(symbol? x)) (print (conc (make-string (* indent 2) #\ ) (s:any->string x)))) ((list? x) (s:print (+ indent 1) x)) (else ;; (print "ERROR: Bad input 01") ;; why do anything with junk? ))) inlst)) ;; Moved to misc-stml ;; #;(define (s:cgi-out inlst) (s:output (current-output-port) inlst)) #;(define (s:output port inlst) (map (lambda (x) (cond ((string? x) (print x)) ;; (print x)) ((symbol? x) (print x)) ;; (print x)) ((list? x) (s:output port x)) (else "" ;; (print "ERROR: Bad input 02") ;; why do anything? don't output junk. ))) inlst)) ; (if (> (length inlst) 2) ; (print))) #;(define (s:output-new port inlst) (with-output-to-port port (lambda () (map (lambda (x) (cond ((string? x) (print x)) ((symbol? x) (print x)) ((list? x) (s:output port x)) (else ;; (print "ERROR: Bad input 03") ))) inlst)))) ;;====================================================================== ;; Not sure where these should go ;;====================================================================== ;; (include "requirements.scm"), dbi has autoload, should not need this any more. ;;====================================================================== ;; setup - convience calls to functions wrapped with a global s:session ;;====================================================================== ;; macros in sugar don't work, have to load in all files or use compiled mode? ;; ;; (include "sugar.scm") ;; use this for getting data from page to page when scope and evals ;; get in the way ;; save data for use in the page generation here. Does NOT persist across page reads. (define *page-data* (make-hash-table)) (define (s:lset! var val) (hash-table-set! *page-data* var val)) (define (s:lget var . default) (hash-table-ref/default *page-data* var (if (null? default) #f (car default)))) ;; to obscure and indirect database ids use one time keys ;; ;; (s:get-key 'n 1) => "n99e1882" n=number 99e is the week number since 1970, remainder is random ;; (s:key->val "n1882") => 1 ;; ;; first letter is a type: n=number, s=string, b=boolean (define (s:get-key key-type val) (let ((mkrandstr (lambda (innum)(number->string (random innum) 16))) (week (number->string (quotient (current-seconds) (* 7 24 60 60)) 16))) (let loop ((siz 1000) (key (conc key-type week (mkrandstr 100))) (num 0)) (if (s:session-var-get key) ;; have a collision (loop (cond ;; in the unlikey event we have trouble getting a new var, keep increasing the size of the number ((< num 50) 100) ((< num 100) 1000) ((< num 200) 10000) ((< num 300) 100000) ((< num 400) 1000000) ;; can't imagine needing to get here. remember that this is for a single user (else 100000000)) (conc key-type (mkrandstr siz)) (+ num 1)) (begin (s:session-var-set! key val) key))))) ;; given a key Xnnnn, look up the stored value and convert it appropriately, then ;; destroy the stored session var ;; (define (s:key->val key) (let ((val (s:session-var-get key)) (typ (string->symbol (substring key 0 1)))) (if val (begin (s:session-var-del! key) ;; we take this opportunity to clean up old keyed session vars ;; if more than 100 vars, remove all that are over 1-2 weeks old ;(s:cleanup-session-vars) (case typ ((n)(string->number val)) ((s) val) (else val))) val))) ;; clean up session vars ;; (define (s:cleanup-session-vars) (let* ((session-vars (hash-table-keys (s:session-get-sessionvars))) (week-num (quotient (current-seconds) (* 7 24 60 60))) (week (number->string week-num 16))) (if (> (length session-vars) 100) (for-each (lambda (var) (if (> (string-length var) 5) ;; can't have keyed values with keys less than 5 characters long (let ((var-week (string->number (substring var 1 4) 16))) (if (and var-week (>= (- week-num var-week) 2)) (s:session-var-del! var))))) session-vars)))) ;; inputs ;; ;; param: (dtype [tag1 tag2 ...]) ;; dtype: ;; 'raw : do no conversion ;; 'number : convert to number, return #f if fails ;; 'escaped : use html-escape to protect the input ;; (define (s:get-input key . params) (session:get-input s:session key params)) (define (s:get-input-keys) (session:get-input-keys s:session)) ;; get-input else, get-param else #f ;; (define (s:get-inp key . params) (or (apply s:get-input key params) (apply s:get-param key params))) (define (s:load-model model) (session:load-model s:session model)) (define (s:model-path) (session:model-path s:session)) ;; share data between pages calls. NOTE: This is not persistent ;; between cgi calls. Use sessionvars for that. ;; (define (s:shared-hash) (sdat-shared-hash s:session)) (define (s:shared-set! key val) (hash-table-set! (sdat-shared-hash s:session) key val)) ;; What to return when no value for key? ;; (define (s:shared-get key) (hash-table-ref/default (sdat-shared-hash s:session) key #f)) ;; http://foo.bar.com/pagename/p1/p2 => '("p1" "p2") ;; #### DEPRECATED #### (define (s:get-page-params) (sdat-path-params s:session)) (define (s:get-path-params) (sdat-path-params s:session)) (define (s:db) (sdat-conn s:session)) ;;====================================================================== ;; cgi and session stuff ;;====================================================================== ;;(declare (uses cookie)) ;;(declare (uses html-filter)) ;;(declare (uses misc-stml)) ;;(declare (uses formdat)) ;;(declare (uses stml)) ;;(declare (uses session)) ;;(declare (uses setup)) ;; s:session gets created here ;;(declare (uses sqltbl)) ;;(declare (uses keystore)) ;; given a list of symbols give the count of the matching symbol ;; l => '(a b c) (dumobj:indx a 'b) => 1 (define (s:get-fieldnum lst field-name) (let loop ((head (car lst)) (tail (cdr lst)) (fnum 0)) (if (eq? head field-name) fnum (if (null? tail) #f (loop (car tail)(cdr tail)(+ fnum 1)))))) (define (s:fields->string lst) (string-join (map symbol->string lst) ",")) (define (s:vector-get-field vec field field-list) (vector-ref vec (s:get-fieldnum field-list field))) ;;====================================================================== ;; ;;====================================================================== ;; moved to misc-stml ;; #;(define (err:log . msg) (with-output-to-port (current-error-port) ;; (slot-ref self 'logpt) (lambda () (apply print msg)))) (define (s:tidy-url url) (if url (let ((r1 (regexp "^http:\\/\\/")) (r2 (regexp "^[ \\t]*$"))) ;; blank (if (string-match r1 url) url (if (string-match r2 url) #f ;; convert a blank to #f (conc "http://" url)))) url)) (define (s:lazy->num num) (if (number? num) num (if (string->number num) (string->number num) (if num 1 0)))) ;; wierd eh! yep, #f=>0 #t=>1 ;;====================================================================== ;; D B ;;====================================================================== ;; convert values to appropriate strings ;; #;(define (s:sqlparam-val->string val) (cond ((list? val)(string-join (map symbol->string val) ",")) ;; (a b c) => a,b,c ((string? val)(conc "'" (dbi:escape-string val) "'")) ((number? val)(number->string val)) ((symbol? val)(dbi:escape-string (symbol->string val))) ((boolean? val) (if val "TRUE" "FALSE")) ;; should this be "TRUE" or 1? ;; should this be "FALSE" or 0 or NULL? (else (err:log "sqlparam: unknown type for value: " val) ""))) ;; (sqlparam "INSERT INTO foo(name,age) VALUES(?,?);" "bob" 20) ;; NB// 1. values only!! ;; 2. terminating semicolon required (used as part of logic) ;; ;; a=? 1 (number) => a=1 ;; a=? 1 (string) => a='1' ;; a=? #f => a=FALSE ;; a=? a (symbol) => a=a ;; #;(define (s:sqlparam query . args) (let* ((query-parts (string-split query "?")) (num-parts (length query-parts)) (num-args (length args))) (if (not (= (+ num-args 1) num-parts)) (err:log "ERROR, sqlparam: wrong number of arguments or missing semicolon, " num-args " for query " query) (if (= num-args 0) query (let loop ((section (car query-parts)) (tail (cdr query-parts)) (result "") (arg (car args)) (argtail (cdr args))) (let* ((valstr (s:sqlparam-val->string arg)) (newresult (conc result section valstr))) (if (null? argtail) ;; we are done (conc newresult (car tail)) (loop (car tail) (cdr tail) newresult (car argtail) (cdr argtail))))))))) ;;====================================================================== ;; M I S C S T R I N G S T U F F ;;====================================================================== (define (s:string-downcase str) (if (string? str) (string-translate str "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz") str)) ;; (define session:valid-chars "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789") #;(define session:valid-chars "abcdefghijklmnopqrstuvwxyz0123456789") ;; cookies are case insensitive. #;(define session:num-valid-chars (string-length session:valid-chars)) #;(define (session:get-nth-char nth) (substring session:valid-chars nth (+ nth 1))) #;(define (session:get-rand-char) (session:get-nth-char (random session:num-valid-chars))) #;(define (session:make-rand-string len) (let loop ((res "") (n 1)) (if (> n len) res (loop (string-append res (session:get-rand-char)) (+ n 1))))) ;; maybe replace above make-rand-string with this someday? ;; #;(define (session:generic-make-rand-string len seed-string) (let ((num-chars (string-length seed-string))) (let loop ((res "") (n 1)) (let ((char-num (random num-chars))) (if (> n len) res (loop (string-append res (substring seed-string char-num (+ char-num 1))) (+ n 1))))))) ;; Rely on crypt egg's default settings being secure enough, accept ;; backwards-compatible OpenSSL crypt passwords too. ;; (define (s:crypt-passwd pw s) (c:crypt pw (or s (c:crypt-gensalt)))) (define (s:password-match? password crypted) (let* ((salt (substring crypted 0 2)) (pcrypted (s:crypt-passwd password salt))) ;; (s:log "INFO: pcrypted=" pcrypted " crypted=" crypted) (and (string? password) (string? pcrypted) (string=? pcrypted crypted)))) ;; (read-line (open-input-pipe "echo foo | mkpasswd -S ab -s")) ;; BUG: The regex implements a rule, but what rule? AH! usaztempe, get rid of this? No, this also looks for &key=value ... (define (s:validate-uri) (let ((uri (get-environment-variable "REQUEST_URI")) (qrs (get-environment-variable "QUERY_STRING"))) (if (not uri) (set! uri qrs)) (if uri (string-match (regexp "^(/[a-z\\-\\._:0-9]*)*(|\\?([A-Za-z0-9_\\-\\+]+=[A-Za-z0-9_\\-\\.\\+]*&{0,1})*)$") uri) (begin "REQUEST URI NOT AVAILABLE!" (let ((p (open-input-pipe "env"))) (let loop ((l (read-line p)) (res '())) (if (eof-object? l) res (loop (read-line p)(cons (list l "<BR>") res))))) #t)))) ;; moved to misc-stml ;; ;; anything except a list is converted to a string!!! #;(define (s:any->string val) (cond ((string? val) val) ((number? val) (number->string val)) ((symbol? val) (symbol->string val)) ((eq? val #f) "") ((eq? val #t) "TRUE") ((list? val) val) (else (let ((ostr (open-output-string))) (with-output-to-port ostr (lambda () (display val))) (get-output-string ostr))))) #;(define (s:any->number val) (cond ((number? val) val) ((string? val) (string->number val)) ((symbol? val) (string->number (symbol->string val))) (else #f))) ;; NB// this is *illegal* pgint (define (s:illegal-pgint val) (cond ((> val 2147483647) 1) ((< val -2147483648) -1) (else #f))) (define (s:any->pgint val) (let ((n (s:any->number val))) (if n (if (s:illegal-pgint n) #f n) n))) ;; string is a string and non-zero length (define (misc:non-zero-string str) (if (and (string? str) (> (string-length str) 0)) str #f)) ;;====================================================================== ;; html-filter ;;====================================================================== (define (s:split-string strng delim) (if (eq? (string-length strng) 0) (list strng) (let loop ((head (make-string 1 (car (string->list strng)))) (tail (cdr (string->list strng))) (dest '()) (temp "")) (cond ((equal? head delim) (set! dest (append dest (list temp))) (set! temp "")) ((null? head) (set! dest (append dest (list temp)))) (else (set! temp (string-append temp head)))) ;; end if (cond ((null? tail) (set! dest (append dest (list temp))) dest) (else (loop (make-string 1 (car tail)) (cdr tail) dest temp)))))) ;; allowed-tags is a list of tags as symbols: ;; '(a b center p a) ;; parsing is simplistic and the response conservative ;; if a < is found without the tag and closing > then ;; the < or > is replaced with < or > without ;; even trying hard to figure out if there is a legit tag ;; buried in the text somewhere. ;; a list of strings is returned. ;; ;; NOTES ;; 1. case is important in the allowed-tags list! ;; 2. only "solid" tags are supported i.e. <a href="foo"> will not work? ;; ;; (s:cgi-out (eval (s:output (s:html-filter "hello<b>goodbye</b><b> eh" '(a b i)))) ;; strategy ;; 1. convert \n to <linefeed> ;; 2. Split on "<" ;; 3. Split on ">" ;; 4. Fix (define (s:html-filter input-text allowed-tags) (let* ((toks (s:str->toks input-text)) (tmp (s:toks->stml '(s:null) #f toks allowed-tags)) (res (car tmp)) (nxttag (cadr tmp)) (rem (caddr tmp))) res)) (define (s:html-filter->string input-text allowed-tags) (let ((ostr (open-output-string))) ;;; (s:output-new ostr (s:html-filter input-text allowed-tags)) (s:output-new ostr (car (eval (s:html-filter input-text allowed-tags)))) (string-chomp (get-output-string ostr)))) ;; don't need the linefeed, could stop adding it ... ;; (if (null? rem) ;; res '()) ;; (s:toks->stml (if (list? res) res '()) #f rem allowed-tags)))) (define (s:str->toks str) (apply append (map (lambda (tok) (intersperse (s:split-string tok ">") ">")) (intersperse (s:split-string str "<") "<")))) (define (s:tag->stml tag) (string->symbol (string-append "s:" (symbol->string tag)))) (define (s:toks->stml res tag rem allowed) ;; (print "tag: " tag " rem: " rem) (if (null? rem) (list (append res (if tag (list (s:tag->stml tag)) '())) #f '() allowed) ;; the case of a lone tag ;; handle a starting tag (let* ((tmp (s:upto-tag rem allowed)) (txt (car tmp)) ;; this txt goes with tag!!! (nexttag (cadr tmp)) ;; this is the NEXT DAMN tag! (begin-tag (caddr tmp)) (newrem (cadddr tmp))) ;; (print "txt: " txt "\nnexttag: " nexttag "\nbegin-tag: " begin-tag "\nnewrem: " newrem "\nres: " res "\n") (if begin-tag ;; nest the following stuff (let* ((childdat (s:toks->stml '() nexttag newrem allowed)) (child (car childdat)) (newtag (cadr childdat)) (newrem2 (caddr childdat)) (allowed (cadddr childdat))) ;; ya, it shouldn't have changed (if tag (s:toks->stml (append res (list (append (list (s:tag->stml tag)) child (list txt)))) newtag newrem2 allowed) (s:toks->stml (append res (list txt) child) newtag newrem2 allowed))) ;; it must have been an end tag (list (append res (list (if tag (list (s:tag->stml tag) txt) txt))) #f newrem allowed))))) ;; "<" "b" ">" => "<b>" ;; "<" ;; (define (s:rebuild-tags input-list) ;; ("blah blah" "<" "b" ">" "more stuff" "<" "i" ">" ) ;; => ("blah blah" b #t ( "more stuff" "<" "i" ">" )) ;; ("blah blah" "<" "/b" ">" "more stuff" "<" "i" ">" ) ;; => ("blah blah" b #f ( "more stuff" "<" "i" ">" )) (define (s:upto-tag inlst allowed-tags) (if (null? inlst) inlst (let loop ((tok (car inlst)) (tail (cdr inlst)) (prel "")) ;; create a string or a list of string parts? (if (string=? tok "<") ;; might have a tag (if (> (length tail) 1) ;; to be a tag, need tag and closing ">" (let ((tag (car tail)) (end (cadr tail)) (rem (cddr tail))) (if (string=? end ">") ;; yep, it is probably a tag (let* ((trim-tag (if (string=? "/" (substring tag 0 1)) (substring tag 1 (string-length tag)) #f)) (tag-sym (string->symbol (if trim-tag trim-tag tag)))) (if (member tag-sym allowed-tags) ;; have a valid tag, rebuild it and return the result (list prel tag-sym (if trim-tag #f #t) rem) ;; not a valid tag, convert "<" and ">" and add all to prel (let ((newprel (string-append prel "<" tag ">"))) (if (null? rem)(list newprel #f #f '()) ;; return newprel - add #f #f ??? (loop (car rem)(cdr rem) newprel))))) ;; so, it wasn't a tag (let ((newprel (string-append prel "<" tag))) (if (null? tail) (list newprel #f #f '()) (loop (car rem)(cdr rem) newprel))))) ;; too short to be a tag (list (apply string-append prel "<" tail) #f #f '())) (if (null? tail) ;; we're done (list (string-append prel tok) #f #f '()) (loop (car tail)(cdr tail)(string-append prel tok))))))) (define (s:divy-up-cgi-str instr) (map (lambda (x) (string-split x "=")) (string-split instr "&"))) (define (s:decode-str instr) (let* ((abc (string-substitute "\\+" " " instr #t)) (toks (s:split-string abc "%"))) (if (< (length toks) 2) abc (let loop ((head (cadr toks)) (tail (cddr toks)) (result (car toks))) (if (string=? head "") (if (null? tail) result (loop (car tail)(cdr tail) result)) (let* ((key (substring head 0 2)) (rem (substring head 2 (string-length head))) (num (string->number key 16)) (ch (if (and (number? num) (exact? num)) (integer->char num) #f)) ;; this is an error. I will probably regret this some day (chstr (if ch (make-string 1 ch) "")) (newres (if ch (string-append result chstr rem) (string-append result head)))) ;; (print "head: " head " num: " num " ch: |" ch "| chstr: " chstr) (if (null? tail) newres (loop (car tail)(cdr tail) newres)))))))) ;; probably a bug: ;; ;; (s:process-cgi-input "=bar") ;; => ((bar "")) ;; (define (s:process-cgi-input instr) (map (lambda (xy) (list (string->symbol (s:decode-str (car xy))) (if (eq? (length xy) 1) "" (s:decode-str (cadr xy))))) (s:divy-up-cgi-str instr))) ;; for testing -- deletme ;; (define blah "post_title=%2B%2B%2B%2B%2B%2B%2B%2B%2B%2B%2Bhello-------------+++++++++++%26%26%26%26%26%26%26%26%26%40%40%40%40%40%40%40%40%40&post_body=%2B%2B%2B%2B%2B%2B%2B%2B%2B%2B%2Bhello-------------+++++++++++%26%26%26%26%26%26%26%26%26%40%40%40%40%40%40%40%40%40%0D%0A%0D%0A%2B%2B%2B%2B%2B%2B%2B%2B%2B%2B%2Bhello-------------+++++++++++%26%26%26%26%26%26%26%26%26%40%40%40%40%40%40%40%40%40%0D%0A%0D%0A%0D%0A%2B%2B%2B%2B%2B%2B%2B%2B%2B%2B%2Bhello-------------+++++++++++%26%26%26%26%26%26%26%26%26%40%40%40%40%40%40%40%40%40&new_post=Submit") ;; (define blah2 "post_title=5%25&post_body=and+10%25&new_post=Submit") ;;====================================================================== ;; formdat ;;====================================================================== (define formdat:*debug* #f) ;; Old data format was something like this. BUT! ;; Forms do not have names so the hierarcy is ;; unnecessary (I think) ;; ;; hashtable ;; |-formname --> <formdat> 'form-name=formname ;; | 'form-data=hashtable ;; | | name => value ;; ;; New data format is only the <formdat> portion from above ;; (define-class <formdat> () ;; (form-data ;; )) (define (make-formdat:formdat)(vector (make-hash-table))) (define (formdat:formdat-get-data vec) (vector-ref vec 0)) (define (formdat:formdat-set-data! vec val)(vector-set! vec 0 val)) (define (formdat:initialize self) (formdat:formdat-set-data! self (make-hash-table))) (define (formdat:get self key) (hash-table-ref/default (formdat:formdat-get-data self) (cond ((symbol? key) key) ((string? key) (string->symbol key)) (else key)) #f)) ;; change to convert data to list and append val if already exists ;; or is a list (define (formdat:set! self key val) (let ((prev-val (formdat:get self key)) (ht (formdat:formdat-get-data self))) (if prev-val (if (list? prev-val) (hash-table-set! ht key (cons val prev-val)) (hash-table-set! ht key (list val prev-val))) (hash-table-set! ht key val)) self)) (define (formdat:keys self) (hash-table-keys (formdat:formdat-get-data self))) (define (formdat:printall self printproc) (printproc "formdat:printall " (formdat:keys self)) (for-each (lambda (k) (printproc k " => " (formdat:get self k))) (formdat:keys self))) (define (formdat:all->strings self) (let ((res '())) (for-each (lambda (k) (set! res (cons (conc k "=>" (formdat:get self k)) res))) (formdat:keys self)) res)) ;; call with *one* of the lists in the list of lists created by CGI:url-unquote (define (formdat:load self formlist) (let ((ht (formdat:formdat-get-data self))) (if (null? formlist) self ;; no values provided, return self for no good reason (let loop ((head (car formlist)) (tail (cdr formlist))) (let ((key (car head)) (val (cdr head))) ;; (err:log "key=" key " val=" val) (if (> (length val) 1) (formdat:set! self key val) (formdat:set! self key (car val))) (if (null? tail) self ;; we are done (loop (car tail)(cdr tail)))))))) ;; get the header from datstr (define (formdat:read-header datstr) ;; datstr is an input string port (let loop ((hs (read-line datstr)) (header '())) (if (or (eof-object? hs) (string=? hs "")) header (loop (read-line datstr)(append header (list hs)))))) ;; get the data up to the next key. if there is no key then return #f ;; return (dat remdat) (define (formdat:read-dat dat key) (let ((index (substring-index key dat))) ;; (string-search-positions key dat))) (if (or (not index) (null? index)) ;; the key was not found #f (let* ((datstr (open-input-string dat)) ;; (result (read-string (caar index) datstr)) (result (read-string index datstr)) (remdat (read-string #f datstr))) (close-input-port datstr) (list result remdat))))) ;; inp is port to read data from, maxsize is max data allowed to read (total) (define (formdat:dat->list inp maxsize #!key (debug-port #f)) ;; read 1Meg chunks from the input port. If a block is not complete ;; tack on the next 1Meg chunk as needed. Set up so the header is always ;; at the beginning of the chunk ;;-----------------------------29932024411502323332136214973 ;;Content-Disposition: form-data; name="input-picture"; filename="breadfruit.jpg" ;;Content-Type: image/jpeg (let loop ((dat (read-string 1000000 inp)) (res '()) (siz 0)) (if debug-port (format debug-port "dat: ~A\n" dat)) (if debug-port (format debug-port "eof: ~A\n" (eof-object? (read inp)))) (if (> siz maxsize) (begin (print "DATA TOO BIG") res) (let* ((datstr (open-input-string dat)) (header (formdat:read-header datstr)) (key (if (not (null? header))(car header) #f)) (remdat (read-string #f datstr)) ;; used in next line, discard if got data, else revert to (alldat (if key (formdat:read-dat remdat key) #f)) ;; try to extract the data (thsdat (if alldat (car alldat) #f)) ;; the data (newdat (if alldat (cadr alldat) #f)) ;; left over data, must process ... (thsres (list header thsdat)) ;; speculatively construct results (newres (append res (list thsres)))) ;; speculatively construct results (close-input-port datstr) (cond ;; either no header or single input ((and (not alldat) (or (null? header) (not (string-match formdat:delim-patt-rex (car header))))) ;; (print "Got here") (cons (list header "") res)) ;; note use header as dat and use "" as header???? ;; didn't find end key in this block ((not alldat) (let ((mordat (read-string 1000000 inp))) (if (string=? mordat "") ;; there is no more data, discard results and use remdat as data, this input is broken (cons (list header remdat) res) (loop (string-append dat mordat) res (+ siz 2000000))))) ;; add the extra 1000000 (alldat ;; got data, don't attempt to check if there is more, just loop and rely on (not alldat) to get more data (loop newdat newres (+ siz 1000000)))))))) (define formdat:bin-data-disp-rex (regexp "^Content-Disposition:\\s+form-data;")) (define formdat:bin-data-name-rex (regexp "\\Wname=\"([^\"]+)\"")) (define formdat:bin-file-name-rex (regexp "\\Wfilename=\"([^\"]+)\"")) (define formdat:bin-file-type-rex (regexp "Content-Type:\\s+([^\\s]+)")) (define formdat:delim-patt-rex (regexp "^\\-+[0-9]+\\-*$")) ;; returns a hash with entries for all forms - could well use a proplist? (define (formdat:load-all) (let ((request-method (get-environment-variable "REQUEST_METHOD"))) (if (and request-method (string=? request-method "POST")) (formdat:load-all-port (current-input-port)) (make-formdat:formdat)))) ;; (s:process-cgi-input (caaar dat)) (define (formdat:load-all-port inp) (let* ((formdat (make-formdat:formdat)) (debugp #f)) ;; (open-output-file (conc "/tmp/delme-" (current-user-id) ".log")))) ;; (write-string (read-string #f inp) #f debugp) ;; destroys all data! (formdat:initialize formdat) (let ((alldats (formdat:dat->list inp 10e6 debug-port: debugp))) (if debugp (format debugp "formdat : alldats: ~A\n" alldats)) (let ((firstitem (car alldats)) (multipass #f)) (if (and (not (null? firstitem)) (not (null? (car firstitem)))) (if (string-match formdat:delim-patt-rex (caar firstitem)) (set! multipass #t))) (if multipass ;; handle multi-part form (for-each (lambda (datlst) (let* ((header (formdat:extract-header-info (car datlst))) (name (if (assoc 'name header) (string->symbol (cadr (assoc 'name header))) "")) ;; grumble (fnamel (assoc 'filename header)) (content (assoc 'content header)) (dat (cadr datlst))) ;; (print "header: " header " name: " name " fnamel: " fnamel " content: " content) ;; " dat: " (dat) (formdat:set! formdat name (if fnamel (list (cadr fnamel) (if content (cadr content) "unknown") (string->blob dat)) dat)))) alldats) ;; handle single part form ;; (if (and (string? name) ;; (string=? name "")) ;; this is the short form input I guess ;; (let* ((datstr (caar datlst)) ;; (munged (s:process-cgi-input datstr))) ;; (print "datstr: " datstr " munged: " munged) (if (and (not (null? alldats)) (not (null? (car alldats))) (not (null? (caar alldats)))) (formdat:load formdat (s:process-cgi-input (caaar alldats))))) ;; munged)) ;; (format debugp "formdat : name: ~A content: ~A\n" name content) (if debugp (close-output-port debugp)) ;; (sdat-formdat-set! s:session formdat) formdat)))) #| (define inp (open-input-file "tests/example.post.in")) (define dat (read-string #f inp)) (define datstr (open-input-string dat)) ;; or (define inp (open-input-file "tests/example.post.binary.in")) (define dat (read-string #f inp)) (define datstr (open-input-string dat)) (formdat:read-header datstr) (define dat (formdat:dat->list inp 10e6)) (close-input-port inp) |# (define (formdat:extract-header-info header) (if (null? header) '() (let loop ((hed (car header)) (tal (cdr header)) (res '())) (if (string-match formdat:bin-data-disp-rex hed) ;; (let* ((data-namem (string-match formdat:bin-data-name-rex hed)) (file-namem (string-match formdat:bin-file-name-rex hed)) (data-name (if data-namem (cadr data-namem) #f)) (this (if file-namem (list (list 'name data-name)(list 'filename (cadr file-namem))) (list (list 'name data-name))))) (if (null? tal) (append res this) (loop (car tal)(cdr tal)(append res this)))) (let ((content (string-match formdat:bin-file-type-rex hed))) ;; this is the stanza for the content type (if content (let ((newres (cons (list 'content (cadr content)) res))) (if (null? tal) newres (loop (car tal)(cdr tal) newres))) (if (null? tal) res (loop (car tal)(cdr tal) res) ))))))) ;; (let loop ((l (read-line)) ;; (if (eq? mode 'norm)(read-line)(read-char))) ;; (endline #f) ;; (num 0)) ;; ;; (format debugp "~A\n" l) ;; (if (or (not (eof-object? l)) ;; (not (and (eq? mode 'bin) ;; (string=? l "")))) ;; if in bin mode empty string is end of file ;; (case mode ;; ((start) ;; (set! mode 'norm) ;; (if (string-match delim-patt-rex l) ;; (begin ;; (set! delim-string l) ;; (set! delim-len (string-length l)) ;; (loop (read-line) #f 0)) ;; (loop l #f 0))) ;; ((norm) ;; ;; I don't like how this gets checked on every single input. Must be a better way. FIXME ;; (if (and (string-match bin-data-disp-rex l) ;; (string-match bin-data-name-rex l) ;; (string-match bin-file-name-rex l)) ;; (begin ;; (set! data-name (cadr (string-match bin-data-name-rex l))) ;; (set! file-name (cadr (string-match bin-file-name-rex l))) ;; (set! mode 'content) ;; (loop (read-line) #f num))) ;; (let* ((dat (s:process-cgi-input l))) ;; (CGI:url-unquote l)) ;; (format debugp "PROCESS-CGI-INPUT: ~A\n" (intersperse dat ",")) ;; (formdat:load formdat dat) ;; (loop (read-line) #f num))) ;; ((content) ;; (if (string-match bin-file-type-rex l) ;; (begin ;; (set! mode 'bin) ;; (set! data-type (cadr (string-match bin-file-type-rex l))) ;; (loop (read-string 1) #f num)))) ;; ((bin) ;; ;; delim-string: \n"---------------12345" ;; ;; 012345678901234567890 ;; ;; endline: "---------------12" ;; ;; l = "3" ;; ;; delim-len = 20 ;; ;; (substring "---------------12345" 17 18) => "3" ;; ;; ;; (cond ;; ;; haven't found the start of an endline, is the next char a newline? ;; ((and (not endline) ;; (string=? l "\n")) ;; required first character ;; (let ((newendline (open-output-string))) ;; ;; (write-line l newendline) ;; discard the newline. add it back if don't have a lock on delim-string ;; (loop (read-string 1) newendline (+ num 1)))) ;; ((not endline) ;; (write-string l #f bin-dat) ;; (loop (read-string 1) #f (+ num 1))) ;; ;; string so far matches delim-string ;; (endline ;; (let* ((endstr (get-output-string endline)) ;; (endlen (string-length endstr))) ;; (if (> endlen 0) ;; (format debugp " delim: ~A\nendstr: ~A\n" delim-string endstr)) ;; (if (and (> delim-len endlen) ;; (string=? l (substring delim-string endlen (+ endlen 1)))) ;; ;; yes, this character matches the next in the delim-string ;; (if (eq? delim-len endlen) ;; have a match! Ignore that a newline is required. Lazy bugger. ;; (let* ((fn (string->symbol data-name))) ;; (formdat:set! formdat fn (list file-name data-type (string->blob (get-output-string bin-dat)))) ;; (set! mode 'norm) ;; (loop (read-line) #f 0)) ;; (begin ;; (write-string l #f endline) ;; (loop (read-string 1) endline (+ num 1)))) ;; ;; no, this character does NOT match the next in line in delim-string ;; (begin ;; (write-string "\n" #f bin-dat) ;; don't forget that newline we dropped ;; (write-string endstr #f bin-dat) ;; (write-string l #f bin-dat) ;; (loop (read-string 1) #f (+ num 1)))))))) ;; ))))) ;; (formdat:printall formdat (lambda (x)(write-line x debugp))) #| (define inp (open-input-file "/tmp/stmlrun/delme-33.log.keep-for-ref")) (define dat (read-string #f inp)) (close-input-port inp) |# ;;====================================================================== ;; use a table in your db called metadat to store key value pairs ;;====================================================================== (define (keystore:get db key) (dbi:get-one db "SELECT value FROM metadata WHERE key=?;" key)) (define (keystore:set! db key value) (let ((curr-val (keystore:get db key))) (if curr-val (dbi:exec db "UPDATE metadata SET value=? WHERE key=?;" value key) (dbi:exec db "INSERT INTO metadata (key,value) VALUES (?,?);" key value)))) (define (keystore:del! db key) (dbi:exec db "DELETE FROM metadata WHERE key=?;" key)) ;;====================================================================== ;; stuff from misc-stml.scm ;;====================================================================== ;; moved to stmlcommon ;; (bunch of stuff) ;; moved from stmlcommon ;; ;; anything except a list is converted to a string!!! (define (s:any->string val) (cond ((string? val) val) ((number? val) (number->string val)) ((symbol? val) (symbol->string val)) ((eq? val #f) "") ((eq? val #t) "TRUE") ((list? val) val) (else (let ((ostr (open-output-string))) (with-output-to-port ostr (lambda () (display val))) (get-output-string ostr))))) (define (s:any->number val) (cond ((number? val) val) ((string? val) (string->number val)) ((symbol? val) (string->number (symbol->string val))) (else #f))) ;; Moved from stmlcommon ;; (define (s:cgi-out inlst) (s:output-new (current-output-port) inlst)) #;(define (s:output port inlst) (map (lambda (x) (cond ((string? x) (print x)) ;; (print x)) ((symbol? x) (print x)) ;; (print x)) ((list? x) (s:output port x)) (else "" ;; (print "ERROR: Bad input 02") ;; why do anything? don't output junk. ))) inlst)) ; (if (> (length inlst) 2) ; (print))) (define (s:output-new port inlst) (with-output-to-port port (lambda () (map (lambda (x) (cond ((string? x) (print x)) ((symbol? x) (print x)) ((list? x) (s:output-new port x)) (else ;; (print "ERROR: Bad input 03") ))) inlst)))) (define (err:log . msg) (with-output-to-port (current-error-port) ;; (slot-ref self 'logpt) (lambda () (apply print msg)))) ;;====================================================================== ;; D B ;;====================================================================== ;; convert values to appropriate strings ;; (define (s:sqlparam-val->string val) (cond ((list? val)(string-join (map symbol->string val) ",")) ;; (a b c) => a,b,c ((string? val)(conc "'" (dbi:escape-string val) "'")) ((number? val)(number->string val)) ((symbol? val)(dbi:escape-string (symbol->string val))) ((boolean? val) (if val "TRUE" "FALSE")) ;; should this be "TRUE" or 1? ;; should this be "FALSE" or 0 or NULL? (else (err:log "sqlparam: unknown type for value: " val) ""))) ;; (sqlparam "INSERT INTO foo(name,age) VALUES(?,?);" "bob" 20) ;; NB// 1. values only!! ;; 2. terminating semicolon required (used as part of logic) ;; ;; a=? 1 (number) => a=1 ;; a=? 1 (string) => a='1' ;; a=? #f => a=FALSE ;; a=? a (symbol) => a=a ;; (define (s:sqlparam query . args) (let* ((query-parts (string-split query "?")) (num-parts (length query-parts)) (num-args (length args))) (if (not (= (+ num-args 1) num-parts)) (err:log "ERROR, sqlparam: wrong number of arguments or missing semicolon, " num-args " for query " query) (if (= num-args 0) query (let loop ((section (car query-parts)) (tail (cdr query-parts)) (result "") (arg (car args)) (argtail (cdr args))) (let* ((valstr (s:sqlparam-val->string arg)) (newresult (conc result section valstr))) (if (null? argtail) ;; we are done (conc newresult (car tail)) (loop (car tail) (cdr tail) newresult (car argtail) (cdr argtail))))))))) ;; (define session:valid-chars "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789") (define session:valid-chars "abcdefghijklmnopqrstuvwxyz0123456789") ;; cookies are case insensitive. (define session:num-valid-chars (string-length session:valid-chars)) (define (session:get-nth-char nth) (substring session:valid-chars nth (+ nth 1))) (define (session:get-rand-char) (session:get-nth-char (random session:num-valid-chars))) (define (session:make-rand-string len) (let loop ((res "") (n 1)) (if (> n len) res (loop (string-append res (session:get-rand-char)) (+ n 1))))) ;; maybe replace above make-rand-string with this someday? ;; (define (session:generic-make-rand-string len seed-string) (let ((num-chars (string-length seed-string))) (let loop ((res "") (n 1)) (let ((char-num (random num-chars))) (if (> n len) res (loop (string-append res (substring seed-string char-num (+ char-num 1))) (+ n 1))))))) ;;====================================================================== ;; P A R A M S ;;====================================================================== ;; input: 'a ('a "val a" 'b "val b") => "val a" (define (s:find-param key param-lst) (let loop ((head (car param-lst)) (tail (cdr param-lst))) (if (eq? head key) (car tail) (if (< (length tail) 2) #f (loop (cadr tail)(cddr tail)))))) (define (s:param->string param) (conc (symbol->string (car param)) "=" "\"" (cadr param) "\"")) ;; remove 'foo "bar" from ('foo "bar" 'bar "foo") (define (s:remove-param-matching params key) (if (= (length params) 0)'() ;; proper params list >= 2 items (let loop ((head (car params)) (tail (cdr params)) (result '())) (if (symbol? head) ;; symbols have params (let ((val (car tail)) (newtail (cdr tail))) (if (eq? head key) ;; get rid of this one (if (null? newtail) result (loop (car newtail)(cdr newtail) result)) (let ((newresult (append result (list head val)))) (if (null? newtail) newresult (loop (car newtail)(cdr newtail) newresult))))) (let ((newresult (append result (list head)))) (if (null? tail) newresult (loop (car tail)(cdr tail) newresult))))))) (define (session:get-param-from params key) (let ((r1 (regexp (conc "^" (s:any->string key) "=(.*)$")))) (if (null? params) #f (let loop ((head (car params)) (tail (cdr params))) (let ((match (string-match r1 head))) (if match (list-ref match 1) (if (null? tail) #f (loop (car tail)(cdr tail))))))))) (define (s:process-params params) (if (null? params) "" (let loop ((res "") (head (car params)) (tail (cdr params))) (if (null? tail) (conc res " " (s:param->string head)) (loop (conc res " " (s:param->string head)) (car tail) (cdr tail)))))) ;; remove key=var from (key=var key1=var1 key2=var2 ...) (define (k=v-params:remove-matching params key) (if (= (length params) 0) params (let ((r1 (regexp (conc "^" key "=")))) (let loop ((head (car params)) (tail (cdr params)) (result '())) (if (string-match r1 head) (if (null? tail) result (loop (car tail)(cdr tail) result)) (let ((newlst (cons head result))) (if (null? tail) newlst (loop (car tail)(cdr tail) newlst)))))))) ;;====================================================================== ;; stuff pulled from session ;;====================================================================== ;; sessions table ;; id session_id session_key ;; create table sessions (id serial not null,session-key text); ;; session_vars table ;; id session_id page_id key value ;; create table session_vars (id serial not null,session_id integer,page text,key text,value text); ;; TODO ;; Concept of order num incremented with each page access ;; if a branch is taken then a new session would need to be created ;; ;; make-vector-record session session dbtype dbinit conn params path-params session-key session-id domain toppage page curr-page content-type page-type sroot twikidir pagedat alt-page-dat pagevars pagevars-before sessionvars sessionvars-before globalvars globalvars-before logpt formdat request-method session-cookie curr-err log-port logfile seen-pages page-dir-style debugmode ;; (define (make-sdat)(make-vector 36)) ;; (define (sdat-dbtype vec) (vector-ref vec 0)) ;; (define (sdat-dbinit vec) (vector-ref vec 1)) ;; (define (sdat-conn vec) (vector-ref vec 2)) ;; (define (sdat-pgconn vec) (vector-ref (vector-ref vec 2) 1)) ;; (define (sdat-params vec) (vector-ref vec 3)) ;; (define (sdat-path-params vec) (vector-ref vec 4)) ;; (define (sdat-session-key vec) (vector-ref vec 5)) ;; (define (sdat-session-id vec) (vector-ref vec 6)) ;; (define (sdat-domain vec) (vector-ref vec 7)) ;; (define (sdat-toppage vec) (vector-ref vec 8)) ;; (define (sdat-page vec) (vector-ref vec 9)) ;; (define (sdat-curr-page vec) (vector-ref vec 10)) ;; (define (sdat-content-type vec) (vector-ref vec 11)) ;; (define (sdat-page-type vec) (vector-ref vec 12)) ;; (define (sdat-sroot vec) (vector-ref vec 13)) ;; (define (sdat-twikidir vec) (vector-ref vec 14)) ;; (define (sdat-pagedat vec) (vector-ref vec 15)) ;; (define (sdat-alt-page-dat vec) (vector-ref vec 16)) ;; (define (sdat-pagevars vec) (vector-ref vec 17)) ;; (define (sdat-pagevars-before vec) (vector-ref vec 18)) ;; (define (sdat-sessionvars vec) (vector-ref vec 19)) ;; (define (sdat-sessionvars-before vec) (vector-ref vec 20)) ;; (define (sdat-globalvars vec) (vector-ref vec 21)) ;; (define (sdat-globalvars-before vec) (vector-ref vec 22)) ;; (define (sdat-logpt vec) (vector-ref vec 23)) ;; (define (sdat-formdat vec) (vector-ref vec 24)) ;; (define (sdat-request-method vec) (vector-ref vec 25)) ;; (define (sdat-session-cookie vec) (vector-ref vec 26)) ;; (define (sdat-curr-err vec) (vector-ref vec 27)) ;; (define (sdat-log-port vec) (vector-ref vec 28)) ;; (define (sdat-logfile vec) (vector-ref vec 29)) ;; (define (sdat-seen-pages vec) (vector-ref vec 30)) ;; (define (sdat-page-dir-style vec) (vector-ref vec 31)) ;; (define (sdat-debugmode vec) (vector-ref vec 32)) ;; (define (sdat-shared-hash vec) (vector-ref vec 33)) ;; (define (sdat-script vec) (vector-ref vec 34)) ;; (define (sdat-force-ssl vec) (vector-ref vec 35)) ;; ;; (define (session:get-shared vec varname) ;; (hash-table-ref/default (vector-ref vec 33) varname #f)) ;; ;; (define (sdat-dbtype-set! vec val)(vector-set! vec 0 val)) ;; (define (sdat-dbinit-set! vec val)(vector-set! vec 1 val)) ;; (define (sdat-conn-set! vec val)(vector-set! vec 2 val)) ;; (define (sdat-params-set! vec val)(vector-set! vec 3 val)) ;; (define (sdat-path-set-params! vec val)(vector-set! vec 4 val)) ;; (define (sdat-session-set-key! vec val)(vector-set! vec 5 val)) ;; (define (sdat-session-set-id! vec val)(vector-set! vec 6 val)) ;; (define (sdat-domain-set! vec val)(vector-set! vec 7 val)) ;; (define (sdat-toppage-set! vec val)(vector-set! vec 8 val)) ;; (define (sdat-page-set! vec val)(vector-set! vec 9 val)) ;; (define (sdat-curr-set-page! vec val)(vector-set! vec 10 val)) ;; (define (sdat-content-set-type! vec val)(vector-set! vec 11 val)) ;; (define (sdat-page-set-type! vec val)(vector-set! vec 12 val)) ;; (define (sdat-sroot-set! vec val)(vector-set! vec 13 val)) ;; (define (sdat-twikidir-set! vec val)(vector-set! vec 14 val)) ;; (define (sdat-pagedat-set! vec val)(vector-set! vec 15 val)) ;; (define (sdat-alt-set-page-dat! vec val)(vector-set! vec 16 val)) ;; (define (sdat-pagevars-set! vec val)(vector-set! vec 17 val)) ;; (define (sdat-pagevars-set-before! vec val)(vector-set! vec 18 val)) ;; (define (sdat-sessionvars-set! vec val)(vector-set! vec 19 val)) ;; (define (sdat-sessionvars-set-before! vec val)(vector-set! vec 20 val)) ;; (define (sdat-globalvars-set! vec val)(vector-set! vec 21 val)) ;; (define (sdat-globalvars-set-before! vec val)(vector-set! vec 22 val)) ;; (define (sdat-logpt-set! vec val)(vector-set! vec 23 val)) ;; (define (sdat-formdat-set! vec val)(vector-set! vec 24 val)) ;; (define (sdat-request-set-method! vec val)(vector-set! vec 25 val)) ;; (define (sdat-session-set-cookie! vec val)(vector-set! vec 26 val)) ;; (define (sdat-curr-set-err! vec val)(vector-set! vec 27 val)) ;; (define (sdat-log-set-port! vec val)(vector-set! vec 28 val)) ;; (define (sdat-logfile-set! vec val)(vector-set! vec 29 val)) ;; (define (sdat-seen-set-pages! vec val)(vector-set! vec 30 val)) ;; (define (sdat-page-set-dir-style! vec val)(vector-set! vec 31 val)) ;; (define (sdat-debugmode-set! vec val)(vector-set! vec 32 val)) ;; (define (sdat-shared-set-hash! vec val)(vector-set! vec 33 val)) ;; (define (sdat-script-set! vec val)(vector-set! vec 34 val)) ;; (define (sdat-force-set-ssl! vec val)(vector-set! vec 35 val)) ;; ;; (define (session:set-shared! vec varname val) ;; (hash-table-set! (vector-ref vec 33) varname val)) ;; The global session (define s:session (make-sdat)) ;; SPLIT INTO STRAIGHT FORWARD INIT AND COMPLEX INIT #;(define (session:initialize self #!optional (configf #f)) (sdat-dbtype-set! self 'pg) (sdat-page-set! self "home") ;; these are defaults (sdat-curr-set-page! self "home") (sdat-content-set-type! self "Content-type: text/html; charset=iso-8859-1\n\n") (sdat-page-set-type! self 'html) (sdat-toppage-set! self "index") (sdat-params-set! self '()) ;; (sdat-path-set-params! self '()) (sdat-session-set-key! self #f) (sdat-pagedat-set! self '()) (sdat-alt-set-page-dat! self #f) (sdat-sroot-set! self "./") (sdat-session-set-cookie! self #f) (sdat-curr-set-err! self #f) (sdat-log-set-port! self (current-error-port)) (sdat-seen-set-pages! self '()) (sdat-page-set-dir-style! self #t) ;; #t : pages/<pagename>_(view|cntl).scm ;; #f : pages/<pagename>/(view|control).scm (sdat-debugmode-set! self #f) (sdat-pagevars-set! self (make-hash-table)) (sdat-sessionvars-set! self (make-hash-table)) (sdat-globalvars-set! self (make-hash-table)) (sdat-pagevars-set-before! self (make-hash-table)) (sdat-sessionvars-set-before! self (make-hash-table)) (sdat-globalvars-set-before! self (make-hash-table)) (sdat-domain-set! self "locahost") ;; end of defaults (sdat-script-set! self #f) (sdat-force-set-ssl! self #f) (let* ((rawconfigdat (session:read-config self configf)) (configdat (if rawconfigdat (eval rawconfigdat) '())) (sroot (s:find-param 'sroot configdat)) (logfile (s:find-param 'logfile configdat)) (dbtype (s:find-param 'dbtype configdat)) (dbinit (s:find-param 'dbinit configdat)) (domain (s:find-param 'domain configdat)) (twikidir (s:find-param 'twikidir configdat)) (page-dir (s:find-param 'page-dir-style configdat)) (debugmode (s:find-param 'debugmode configdat)) (script (s:find-param 'script configdat)) (force-ssl (s:find-param 'force-ssl configdat))) (if sroot (sdat-sroot-set! self sroot)) (if logfile (sdat-logfile-set! self logfile)) (if dbtype (sdat-dbtype-set! self dbtype)) (if dbinit (sdat-dbinit-set! self dbinit)) (if domain (sdat-domain-set! self domain)) (if twikidir (sdat-twikidir-set! self twikidir)) (if debugmode (sdat-debugmode-set! self debugmode)) (if script (sdat-script-set! self script)) (if force-ssl (sdat-force-set-ssl! self force-ssl)) (sdat-page-set-dir-style! self page-dir) ;; (print "configdat: ")(pp configdat) (if debugmode (session:log self "sroot: " sroot " logfile: " logfile " dbtype: " dbtype " dbinit: " dbinit " domain: " domain " page-dir-style: " page-dir)) ) (sdat-shared-set-hash! self (make-hash-table)) ) ;; Used for the strangely inconsistent handling of the config file. A better way is needed. ;; ;; (let ((dbtype (sdat-dbtype self))) ;; (print "dbtype: " dbtype) ;; (sdat-dbtype-set! self (eval dbtype)))) (define (session:setup self #!optional (configf #f)) (session:initialize self configf) (let ((dbtype (sdat-dbtype self)) (debugmode (sdat-debug-mode self)) (dbinit (eval (sdat-dbinit self))) (dbexists #f)) (let ((dbfname (alist-ref 'dbname dbinit))) (if debugmode (session:log self "session:setup dbfname=" dbfname ", dbtype=" dbtype ", dbinit=" dbinit)) (if (eq? dbtype 'sqlite3) ;; The 'auto method will distribute dbs across the disk using hash ;; of user host and user. TODO ;; (if (eq? dbfname 'auto) ;; This is the auto assignment of a db based on hash of IP (let ((dbpath (pathname-directory dbfname))) ;; do a couple sanity checks here to make setting up easier (if debugmode (session:log self "INFO: setting up for sqlite3 db access to " dbfname)) (if (not (file-write-access? dbpath)) (session:log self "WARNING: Cannot write to " dbpath) (if debugmode (session:log self "INFO: " dbpath " is writeable"))) (if (file-exists? dbfname) (begin ;; (session:log self "setting dbexists to #t") (set! dbexists #t)))) (if debugmode (session:log self "INFO: setting up for pg db access to account info " dbinit))) (if debugmode (session:log self "dbtype: " dbtype " dbfname: " dbfname " dbexists: " dbexists))) (sdat-conn-set! self (dbi:open dbtype dbinit)) (set! *db* (sdat-conn self)) (if (and (not dbexists)(eq? dbtype 'sqlite3)) (begin (print "WARNING: Setting up session db with sqlite3") (session:setup-db self))) (session:process-url-path self) (session:setup-session-key self) ;; capture stdin if this is a POST (sdat-request-method-set! self (get-environment-variable "REQUEST_METHOD")) (sdat-formdat-set! self (formdat:load-all)))) ;; setup the db with session tables, works for sqlite only right now (define (session:setup-db self) (let ((conn (sdat-conn self))) (for-each (lambda (stmt) (dbi:exec conn stmt)) (list "CREATE TABLE session_vars (id INTEGER PRIMARY KEY,session_id INTEGER,page TEXT,key TEXT,value TEXT);" "CREATE TABLE sessions (id INTEGER PRIMARY KEY,session_key TEXT,last_used TIMESTAMP);" "CREATE TABLE metadata (id INTEGER PRIMARY KEY,key TEXT,value TEXT);")))) ;; ;; if we have a session_key look up the session-id and store it ;; (sdat-session-set-id! self (session:get-id self))) ;; only set session-cookie when a new session is created (define (session:setup-session-key self) (let* ((sk (session:extract-session-key self)) (sid (if sk (session:get-id self sk) #f))) (if (not sid) ;; need a new key (let* ((new-key (session:get-new-key self)) (new-sid (session:get-id self new-key))) (sdat-session-key-set! self new-key) (sdat-session-id-set! self new-sid) (sdat-session-cookie-set! self (session:make-cookie self))) (sdat-session-id-set! self sid)))) (define (session:make-cookie self) ;; (list (conc "session_key=" (sdat-session-key self) "; Path=/; Domain=." (sdat-domain self) "; Max-Age=" (* 86400 14) "; Version=1"))) ;; According to ;; http://www.codemarvels.com/2010/11/apache-rewriterule-set-a-cookie-on-localhost/ ;; Here are the 2 (often left out) requirements to set a cookie using ;; httpd-F�s rewrite rule (mod_rewrite), while working on localhost:-A ;; ;; Use the IP 127.0.0.1 instead of localhost/machine-name as the ;; domain; e.g. [CO=someCookie:someValue:127.0.0.1:2:/], which says ;; create a cookie -Y�someCookie� with value �someValue� for the ;; domain �127.0.0.1$B!m(B having a life time of 2 mins, for any path in ;; the domain (path=/). (Obviously you will have to run the ;; application with this value in the URL) ;; ;; To make a session cookie, limit the flag statement to just three ;; attributes: name, value and domain. e.g ;; [CO=someCookie:someValue:127.0.0.1] %G–%@ Any further ;; settings, apache writes an� expires� attribute for the set-cookie ;; header, which makes the cookie a persistent one (not really ;; persistent, as the expires value set is the current server time ;; %G–%@ so you don-F-F�t even get to see your cookie!)-A (list (string-substitute ";" "; " (car (construct-cookie-string ;; warning! messing up this itty bitty bit of code will cost much time! `(("session_key" ,(sdat-session-key self) expires: ,(+ (current-seconds) (* 14 86400)) ;; max-age: (* 14 86400) path: "/" ;; domain: ,(string-append "." (sdat-domain self)) version: 1)) 0))))) ;; look up a given session key and return the id if found, #f if not found (define (session:get-id self session-key) ;; (let ((session-key (sdat-session-key self))) (if session-key (let ((query (string-append "SELECT id FROM sessions WHERE session_key='" session-key "'")) (conn (sdat-conn self)) (result #f)) (dbi:for-each-row (lambda (tuple) (set! result (vector-ref tuple 0))) conn query) (if result (dbi:exec conn (conc "UPDATE sessions SET last_used=" (dbi:now conn) " WHERE session_key=?;") session-key)) result) #f)) ;; (define (session:process-url-path self) (let ((path-info (get-environment-variable "PATH_INFO")) (query-string (get-environment-variable "QUERY_STRING"))) ;; (session:log self "path-info=" path-info " query-string=" query-string) (if path-info (let* ((parts (string-split path-info "/")) (numparts (length parts))) (if (> numparts 0) (sdat-page-set! self (car parts))) ;; (session:log self "url-path=" url-path " parts=" parts) (if (> numparts 1) (sdat-path-params-set! self (cdr parts))) (if query-string (sdat-params-set! self (string-split query-string "&"))))))) ;; BUGGY! (define (session:get-new-key self) (let ((conn (sdat-conn self)) (tmpkey (session:make-rand-string 20)) (status #f)) (dbi:for-each-row (lambda (tuple) (set! status #t)) conn (string-append "INSERT INTO sessions (session_key) VALUES ('" tmpkey "')")) tmpkey)) ;; returns session key IFF it is in the HTTP_COOKIE (define (session:extract-session-key self) (let ((http-cookie (get-environment-variable "HTTP_COOKIE"))) ;; (err:log "http-cookie: " http-cookie) (if http-cookie (session:extract-key-from-param self (string-split-fields ";\\s+" http-cookie infix:) "session_key") #f))) (define (session:get-session-id self session-key) (let ((query "SELECT id FROM sessions WHERE session_key=?;") (result #f)) ;; (pg:query-for-each (lambda (tuple) ;; (set! result (vector-ref tuple 0))) ;; (vector-ref tuple 0))) ;; (s:sqlparam query session-key) ;; (sdat-conn self)) ;; conn) (dbi:for-each-row (lambda (tuple) (set! result (vector-ref tuple 0))) ;; (vector-ref tuple 0))) (sdat-conn self) (s:sqlparam query session-key)) result)) ;; delete all records for a session ;; ;; NEEDS TO BE TRANSACTIONIZED! ;; (define (session:delete-session self session-key) (let ((session-id (session:get-session-id self session-key)) (qry1 ;; (conc "BEGIN;" "DELETE FROM session_vars WHERE session_id=?;") (qry2 "DELETE FROM sessions WHERE id=?;") ;; "COMMIT;")) (conn (sdat-conn self))) (if session-id (begin (dbi:exec conn qry1 session-id) ;; session-id) (dbi:exec conn qry2 session-id) ;; (session:initialize self) (session:setup self))) (not (session:get-session-id self session-key)))) ;; (define (session:delete-session self session-key) ;; (let ((session-id (session:get-session-id self session-key)) ;; (queries (list "BEGIN;" ;; "DELETE FROM session_vars WHERE session_id=?;" ;; "DELETE FROM sessions WHERE id=?;" ;; "COMMIT;")) ;; (conn (sdat-conn self))) ;; (if session-id ;; (begin ;; (for-each ;; (lambda (query) ;; (dbi:exec conn query session-id)) ;; queries) ;; (initialize self '()) ;; (session:setup self))) ;; (not (session:get-session-id self session-key)))) (define (session:extract-key self key) (let ((params (sdat-params self))) (session:extract-key-from-param self params key))) (define (session:extract-key-from-param self params key) (let ((r1 (regexp (string-append "^" key "=([^=]+)$")))) (err:log "INFO: Looking for " key " in " params) (if (< (length params) 1) #f (let loop ((head (car params)) (tail (cdr params))) (let ((match (string-match r1 head))) (cond (match (let ((session-key (list-ref match 1))) (err:log "INFO: Found session key=" session-key) (sdat-session-key-set! self (list-ref match 1)) session-key)) ((null? tail) #f) (else (loop (car tail) (cdr tail))))))))) (define (session:set-page! self page_name) (sdat-page-set! self page_name)) (define (session:close self) (dbi:close (sdat-conn self))) ;; (close-output-port (sdat-logpt self)) (define (session:err-msg self msg) (hash-table-set! (sdat-sessionvars self) "ERROR_MSG" (string-intersperse (map s:any->string msg) " "))) (define (session:prev-err self) (let ((prev-err (hash-table-ref/default (sdat-sessionvars-before self) "ERROR_MSG" #f)) (curr-err (hash-table-ref/default (sdat-sessionvars self) "ERROR_MSG" #f))) (if prev-err prev-err (if curr-err curr-err #f)))) ;; session vars ;; 1. keys are always a string NOT a symbol ;; 2. values are always a string conversion is the responsibility of the ;; consuming function (at least for now, I'd like to change this) ;; set a session var for the current page ;; (define (session:curr-page-set! self key value) (hash-table-set! (sdat-pagevars self) (s:any->string key) (s:any->string value))) ;; del a var for the current page ;; (define (session:page-var-del! self key) (hash-table-delete! (sdat-pagevars self) (s:any->string key))) ;; get the appropriate hash given a page "*sessionvars*, *globalvars* or page ;; (define (session:get-page-hash self page) (if (string=? page "*sessionvars*") (sdat-sessionvars self) (if (string=? page "*globalvars*") (sdat-globalvars self) (sdat-pagevars self)))) ;; set a session var for a given page ;; (define (session:set! self page key value) (let ((ht (session:get-page-hash self page))) (hash-table-set! ht (s:any->string key) (s:any->string value)))) ;; get session vars for the current page ;; (define (session:page-get self key) (hash-table-ref/default (sdat-pagevars self) key #f)) ;; get session vars for a specified page ;; (define (session:get self page key params) (let* ((ht (session:get-page-hash self page)) (res (hash-table-ref/default ht (s:any->string key) #f))) (session:apply-type-preference res params))) ;; delete a session var for a specified page ;; (define (session:del! self page key) (let ((ht (session:get-page-hash self page))) (hash-table-delete! ht (s:any->string key)))) ;; get ALL keys for this page and store in the session pagevars hash ;; (define (session:get-vars self) (let ((session-id (sdat-session-id self))) (if (not session-id) (err:log "ERROR: No session id in session object! session:get-vars") (let* ((result #f) (conn (sdat-conn self)) (pagevars-before (sdat-pagevars-before self)) (sessionvars-before (sdat-sessionvars-before self)) (globalvars-before (sdat-globalvars-before self)) (pagevars (sdat-pagevars self)) (sessionvars (sdat-sessionvars self)) (globalvars (sdat-globalvars self)) (page-name (sdat-page self)) (session-key (sdat-session-key self)) (query (string-append "SELECT key,value FROM session_vars INNER JOIN sessions ON session_vars.session_id=sessions.id " "WHERE session_key=? AND page=?;"))) ;; first the page specific vars (dbi:for-each-row (lambda (tuple) (let ((k (vector-ref tuple 0)) (v (vector-ref tuple 1))) (hash-table-set! pagevars-before k v) (hash-table-set! pagevars k v))) conn (s:sqlparam query session-key page-name)) ;; then the session specific vars (dbi:for-each-row (lambda (tuple) (let ((k (vector-ref tuple 0)) (v (vector-ref tuple 1))) (hash-table-set! sessionvars-before k v) (hash-table-set! sessionvars k v))) conn (s:sqlparam query session-key "*sessionvars*")) ;; and finally the global vars (dbi:for-each-row (lambda (tuple) (let ((k (vector-ref tuple 0)) (v (vector-ref tuple 1))) (hash-table-set! globalvars-before k v) (hash-table-set! globalvars k v))) conn (s:sqlparam query session-key "*globalvars")) )))) (define (session:save-vars self) (let ((session-id (sdat-session-id self))) (if (not session-id) (err:log "ERROR: No session id in session object! session:get-vars") (let* ((status #f) (conn (sdat-conn self)) (page-name (sdat-page self)) (del-query "DELETE FROM session_vars WHERE session_id=? AND page=? AND key=?;") (ins-query "INSERT INTO session_vars (session_id,page,key,value) VALUES(?,?,?,?);") (upd-query "UPDATE session_vars set value=? WHERE key=? AND session_id=? AND page=?;") (changed-count 0)) ;; save the delta only (for-each (lambda (page) ;; page is: "*globalvars*" "*sessionvars*" or otherstring (let* ((before-after-ht (cond ((string=? page "*sessionvars*") (vector (sdat-sessionvars self) (sdat-sessionvars-before self))) ((string=? page "*globalvars*") (vector (sdat-globalvars self) (sdat-globalvars-before self))) (else (vector (sdat-pagevars self) (sdat-pagevars-before self))))) (master-ht (vector-ref before-after-ht 0)) (before-ht (vector-ref before-after-ht 1)) (master-keys (hash-table-keys master-ht)) (before-keys (hash-table-keys before-ht)) (all-keys (delete-duplicates (append master-keys before-keys)))) (for-each (lambda (key) (let ((master-value (hash-table-ref/default master-ht key #f)) (before-value (hash-table-ref/default before-ht key #f))) (cond ;; before and after exist and value unchanged - do nothing ((and master-value before-value (equal? master-value before-value))) ;; before and after exist but are changed ((and master-value before-value) (dbi:for-each-row (lambda (tuple) (set! changed-count (+ changed-count 1))) conn (s:sqlparam upd-query master-value key session-id page))) ;; master-value no longer exists (i.e. #f) - remove item ((not master-value) (dbi:for-each-row (lambda (tuple) (set! changed-count (+ changed-count 1))) conn (s:sqlparam del-query session-id page key))) ;; before-value doesn't exist - insert a new value ((not before-value) (dbi:for-each-row (lambda (tuple) (set! changed-count (+ changed-count 1))) conn (s:sqlparam ins-query session-id page key master-value))) (else (err:log "Shouldn't get here"))))) all-keys))) ;; process all keys (list "*sessionvars*" "*globalvars*" page-name)))))) ;; (pg:sql-null-object? element) (define (session:read-config self #!optional (fname #f)) (let* ((cgi-path (pathname-directory (car (argv)))) (name (or fname (string-append (if cgi-path (conc cgi-path "/") "") "." (pathname-file (car (argv))) ".config")))) (if (not (file-exists? name)) (print name " not found at " (current-directory)) (let* ((fp (open-input-file name)) (initargs (read fp))) (close-input-port fp) initargs)))) ;; call the controller if it exists ;; ;; WARNING - this code needs a defense agains recursive calling!!!!! ;; ;; I suggest a limit of 100 calls. Plenty for allowing multiple instances ;; of a page inside another page. ;; ;; parts = 'both | 'control | 'view ;; (define (files-read->string . files) (string-intersperse (apply append (map file-read->string files)) "\n")) (define (file-read->string f) (let ((p (open-input-file f))) (let loop ((hed (read-line p)) (res '())) (if (eof-object? hed) res (loop (read-line p)(append res (list hed))))))) (define (process-port p) (let ((e (interaction-environment))) (map (lambda (x) (cond ((list? x) x) ((string? x) x) (else '()))) (port-map (lambda (s) (eval s e)) (lambda ()(read p)))))) (define (session:process-file f) (let* ((p (open-input-file f)) (dat (process-port p))) (close-input-port p) dat)) ;; May 2011, putting all pages into one directory for the following reasons: ;; 1. want filename to reflect page name (emacs limitation) ;; 2. that's it! no other reason. could make it configurable ... ;; page-dir-style is: ;; 'stored => stored in executable ;; 'flat => pages flat directory ;; 'dir => directory tree pages/<pagename>/{view,control}.scm ;; parts: ;; 'both => load control and view (anything other than view or control and the default) ;; 'view => load view only ;; 'control => load control only (define (session:call-parts self page #!key (parts 'both)) (sdat-curr-page-set! self page) (let* ((dir-style (sdat-page-dir-style self));; (equal? (sdat-page-dir-style self) "onedir")) ;; flag #t for onedir, #f for old style (dir (string-append (sdat-sroot self) (if dir-style (conc "/pages/") (conc "/pages/" page))))) (case dir-style ;; NB// Stored always loads both control and view ((stored) ((eval (string->symbol (conc "pages:" page))) self ;; the session (sdat-conn self) ;; the db connection (sdat-shared-hash self) ;; a shared hash table for passing data to/from page calls )) ((flat) (let* ((so-file (conc dir page ".so")) (scm-file (conc dir page ".scm")) (src-file (or (file-exists? so-file) (file-exists? scm-file)))) (if src-file (begin (load src-file) ((eval (string->symbol (conc "pages:" page))) self ;; the session (sdat-conn self) ;; the db connection (sdat-shared-hash self) ;; a shared hash table for passing data to/from page calls )) (list "<p>Page not found " page " </p>")))) ;; first the control ;; (let ((control-file (conc "pages/" page "_ctrl.scm")) ;; (view-file (conc "pages/" page "_view.scm"))) ;; (if (and (file-exists? control-file) ;; (not (eq? parts 'view))) ;; (begin ;; (session:set-called! self page) ;; (load control-file))) ;; (if (file-exists? view-file) ;; (if (not (eq? parts 'control)) ;; (session:process-file view-file)) ;; (list "<p>Page not found " page " </p>"))) ((dir) "ERROR: dir style not yet re-implemented") (else (list "ERROR: page-dir-style must be stored, dir or flat, got " dir-style))))) (define (session:call self page parts) (session:call-parts self page 'both)) (define (session:load-model self model) (let* ((mpath (session:model-path self)) (model.scm (string-append mpath "/" model ".scm")) (model.so (string-append mpath "/" model ".so"))) (if (file-exists? model.so) (load model.so) (if (file-exists? model.scm) (load model.scm) (s:log "ERROR: model " model.scm " not found"))))) (define (session:model-path self) (or (sdat-models self) (string-append (sdat-sroot self) "/models/"))) (define (session:pp-formdat self) (let ((dat (formdat:all->strings (sdat-formdat self)))) (string-intersperse dat "<br> "))) (define (session:param->string params) ;; (err:log "params=" params) (if (< (length params) 1) "" (let loop ((key (car params)) (val (cadr params)) (tail (cddr params)) (result '())) (let ((newresult (cons (string-append (s:any->string key) "=" (s:any->string val)) result))) (if (< (length tail) 1) ;; true if done (string-intersperse newresult "&") (loop (car tail)(cadr tail)(cddr tail) newresult)))))) (define (session:link-to self page params) (let* ((https-host (get-environment-variable "HTTPS_HOST")) (force-ssl (sdat-force-ssl self)) (server (or https-host ;; Assuming HTTPS_HOST is only set if available (get-environment-variable "HTTP_HOST") (get-environment-variable "SERVER_NAME") (sdat-domain self))) (force-script (sdat-script self)) (script (or force-script (let ((script-name (string-split (get-environment-variable "SCRIPT_NAME") "/"))) (if (> (length script-name) 1) (string-append (car script-name) "/" (cadr script-name)) (get-environment-variable "SCRIPT_NAME"))))) ;; build script name from first two elements. This is a hangover from before I used ? in the URL.) (session-key (sdat-session-key self)) (paramstr (session:param->string params))) (session:log self "server=" server " script=" script " page=" page) (string-append (if (or https-host force-ssl) "https://" "http://") server "/" script "/" page "?" paramstr))) ;; "/sn=" session-key))) (define (session:cgi-out self) (let* ((content (list (sdat-content-type self))) ;; '("Content-type: text/html; charset=iso-8859-1\n\n")) (header (let ((cookie (sdat-session-cookie self))) (if cookie (cons (string-append "Set-Cookie: " (car cookie)) content) content))) (pagedat (sdat-pagedat self))) (s:cgi-out (cons header pagedat)))) (define (session:log self . msg) (with-output-to-port (sdat-log-port self) ;; (sdat-logpt self) (lambda () (apply print msg)))) ;; escape, convert or return raw when given user input data that potentially ;; could be malicious ;; (define (session:apply-type-preference res params) (let* ((dtype (if (null? params) 'escaped (car params))) (tags (if (null? params) '() (cdr params)))) (case dtype ((raw) res) ((number) (if (string? res)(string->number res) #f)) ((escaped) (if (string? res) (s:html-filter->string res tags) res)) ((escaped-nl) (if (string? res) ;; escape \n and \r (string-intersperse (string-split (string-intersperse (string-split (s:html-filter->string res tags) "\n") "\\n") "\r") "\\r") res)) ;; should return #f if not a string and can't escape it? (else (if (string? res) (s:html-filter->string res '()) res))))) #;(define (session:get-param-from params key) (let ((r1 (regexp (conc "^" (s:any->string key) "=(.*)$")))) (if (null? params) #f (let loop ((head (car params)) (tail (cdr params))) (let ((match (string-match r1 head))) (if match (list-ref match 1) (if (null? tail) #f (loop (car tail)(cdr tail))))))))) ;; params are stored as list of key=val ;; (define (session:get-param self key type-params) ;; (session:log s:session "params=" (slot-ref s:session 'params)) (let* ((params (sdat-params self)) (res (session:get-param-from params key))) (session:apply-type-preference res type-params))) ;; This one will get the first value found regardless of form ;; param: (dtype [tag1 tag2 ...]) ;; dtype: ;; 'raw : do no conversion ;; 'number : convert to number, return #f if fails ;; 'escaped : use html-escape to protect the input -- this is the default ;; (define (session:get-input self key params) (let* ((dtype (if (null? params) 'escaped (car params))) (tags (if (null? params) '() (cdr params))) (formdat (sdat-formdat self)) (res (if (not formdat) #f (if (or (string? key)(number? key)(symbol? key)) (if (and (vector? formdat) (eq? (vector-length formdat) 1) (hash-table? (vector-ref formdat 0))) (formdat:get formdat key) (begin (session:log self "ERROR: formdat: " formdat " is not of class <formdat>") #f)) (begin (session:log self "ERROR: bad key " key) #f))))) (case dtype ((raw) res) ((number) (if (string? res)(string->number res) #f)) ((escaped) (if (string? res) (s:html-filter->string res tags) res)) (else (if (string? res) (s:html-filter->string res '()) res))))) ;; This one will get the first value found regardless of form (define (session:get-input-keys self) (let* ((formdat (sdat-formdat self))) (if (not formdat) #f (if (and (vector? formdat) (eq? (vector-length formdat) 1) (hash-table? (vector-ref formdat 0))) (formdat:keys formdat) (begin (session:log self "ERROR: formdat: " formdat " is not of class <formdat>") #f))))) (define (session:run-actions self) (let* ((action (session:get-param self 'action '(raw))) (page (sdat-page self))) ;; (print "action=" action " page=" page) (if action (let ((action-lst (string-split action "."))) ;; (print "action-lst=" action-lst) (if (not (= (length action-lst) 2)) (err:log "Action should be of form: module.action") (let* ((targ-page (car action-lst)) (proc-name (string-append targ-page "-action")) (targ-action (cadr action-lst))) ;; (err:log "targ-page=" targ-page " proc-name=" proc-name " targ-action=" targ-action) ;; call here only if never called before (if (session:never-called-page? self targ-page) (session:call-parts self targ-page 'control)) ;; proc action (if #t ;; set to #t to see better error messages during debuggin :-) ((eval (string->symbol proc-name)) targ-action) ;; unsafe execution (condition-case ((eval (string->symbol proc-name)) targ-action) ((exn file) (s:log "file error")) ((exn i/o) (s:log "i/o error")) ((exn ) (s:log "Action not implemented: " proc-name " action: " targ-action)) (var () (s:log "Unknown Error")))))))))) (define (session:never-called-page? self page) (session:log self "Checking for page: " page) (not (member page (sdat-seen-pages self)))) (define (session:set-called! self page) (sdat-seen-pages-set! self (cons page (sdat-seen-pages self)))) ;;====================================================================== ;; Alternative data type delivery ;;====================================================================== (define (session:alt-out self) (let ((dat (sdat-alt-page-dat self))) ;; (s:log "dat is: " dat) ;; (print "HTTP/1.1 200 OK") (print "Date: " (time->string (seconds->utc-time (current-seconds)))) (print "Content-Type: " (sdat-content-type self)) (print "Accept-Ranges: bytes") (print "Content-Length: " (if (blob? dat) (blob-size dat) 0)) (print "Keep-Alive: timeout=15, max=100") (print "Connection: Keep-Alive") (print "") (write-string (blob->string dat) #f (current-output-port)))) ;;====================================================================== ;; Orphaned functions ;;====================================================================== ;; was in setup ;; (define (s:log . msg) (apply session:log s:session msg)) ;; Usage: (s:get-err s:big) (define (s:get-err wrapperfunc) (let ((errmsg (sdat-curr-err s:session))) (if errmsg ((if wrapperfunc wrapperfunc s:strong) errmsg) '()))) (define (stml:cgi-session session #!optional (configf #f)) ;; (session:initialize session) (session:setup session configf) (session:get-vars session) (sdat-log-port-set! session ;; (current-error-port)) (open-output-file (sdat-logfile session) #:append)) (s:validate-inputs) (change-directory (sdat-sroot session)) (session:run-actions session) (sdat-pagedat-set! session (append (sdat-pagedat session) (s:call (sdat-toppage session)))) (if (eq? (sdat-page-type session) 'html) ;; default is html. (session:cgi-out session) (session:alt-out session)) (session:save-vars session) (session:close session)) (define (s:validate-inputs) (if (not (s:validate-uri)) (begin (s:error-page "Bad URI" (let ((ref (get-environment-variable "HTTP_REFERER"))) (if ref (list "referred from" ref) ""))) (exit)))) (define (s:error-page . err) (s:cgi-out (cons "Content-type: text/html; charset=iso-8859-1\n\n" (s:html (s:head (s:title err) (s:body (s:h1 "ERROR") (s:p err))))))) (define (stml:main proc #!optional (configf #f)) (handle-exceptions exn (if (sdat-debug-mode s:session) (begin (print "Content-type: text/html") (print "") (print "<html> <head> <title>EXCEPTION</title> </head> <body>") (print " QUERY_STRING is: <b> " (get-environment-variable "QUERY_STRING") " </b> <br>") (print "<pre>") ;; (print " EXCEPTION: " ((condition-property-accessor 'exn 'message) exn)) (print-error-message exn) (print-call-chain) (print "</pre>") (print "<table>") (for-each (lambda (var) (print "<tr><td>" (car var) "</td><td>" (cdr var) "</td></tr>")) (get-environment-variables)) (print "</table>") (print "</body></html>")) (begin (with-output-to-file (conc "/tmp/stml-crash-" (current-process-id) ".log") (lambda () (print "EXCEPTION") (print " QUERY_STRING is: " (get-environment-variable "QUERY_STRING") ) (print "") ;; (print " EXCEPTION: " ((condition-property-accessor 'exn 'message) exn)) (print-error-message exn) (print-call-chain) (print "") (for-each (lambda (var) (print (car var) "\t" (cdr var))) (get-environment-variables)))) ;; return something useful to the user (print "Content-type: text/html") (print "") (print "<html> <head> <title>EXCEPTION</title> </head> <body>") (print "<h1>CRASH!</h1>") (print " Please notify support at " (sdat-domain s:session) " that the error log is stml-crash-" (current-process-id) ".log</b> <br>") ;; (print "<pre>") ;; ;; (print " EXCEPTION: " ((condition-property-accessor 'exn 'message) exn)) ;; ;; (print-error-message exn) ;; ;; (print-call-chain) ;; (print "</pre>") ;; (print "<table>") ;; (for-each (lambda (var) ;; (print "<tr><td>" (car var) "</td><td>" (cdr var) "</td></tr>")) ;; (get-environment-variables)) ;; (print "</table>") (print "</body></html>"))) (if proc (proc s:session) (stml:cgi-session s:session configf)) ;; (raise-error) ;; (exit) )) ;; find out if we are in debugmode (define (s:debug-mode?) (sdat-debug-mode s:session)) (define (s:never-called-page? page) (session:never-called-page? s:session page)) (define (s:set-err . args) (sdat-curr-err-set! s:session args)) (define (s:current-page) (sdat-page s:session)) (define (s:delete-session) (session:delete-session s:session (sdat-session-key s:session))) (define (s:call page . partsl) (if (null? partsl) (session:call s:session page #f) (session:call s:session page (car partsl)))) (define (s:link-to page . params) (session:link-to s:session page params)) (define (s:get-param key . type-params) (session:get-param s:session key type-params)) ;; these are page local (define (s:get key) (session:page-get s:session key)) (define (s:set! key val) (session:curr-page-set! s:session key val)) (define (s:del! key) (session:page-var-del! s:session key)) #;(define (s:get-n-del! key) (let ((val (session:page-get s:session key))) (session:del! s:session val key) val)) ;; these are session wide (define (s:session-var-get key . params) (session:get s:session "*sessionvars*" key params)) (define (s:session-var-set! key val) (session:set! s:session "*sessionvars*" key val)) (define (s:session-var-get-n-del! key) (let ((val (session:page-get s:session key))) (session:del! s:session "*sessionvars*" key) val)) (define (s:session-var-del! key) (session:del! s:session "*sessionvars*" key)) (define s:session-var-delete! s:session-var-del!) ;; utility to get all vars as hash table (define (s:session-get-sessionvars) (sdat-sessionvars s:session)) ;;====================================================================== ;; Sugar ;;====================================================================== ;; ;; (require 'syntax-case) ;; ;; (define-syntax s:if-param ;; (syntax-rules () ;; [(_ s x) (if (s:get s) x (s:comment "s:if not"))] ;; [(_ s x y) (if (s:get s) x y)])) ;; ;; ;; (define-syntax s:if-test ;; (syntax-rules () ;; [(_ s x) (if (string=? "yep" s) x (list "s:if not"))] ;; [(_ s x y) (if (string=? "yep" s) x y)])) ;; Some of these routines use: ;; ;; http://www.cs.toronto.edu/~gfb/scheme/simple-macros.html ;; ;; Syntax for defining macros in a simple style similar to function definiton, ;; when there is a single pattern for the argument list and there are no keywords. ;; ;; (define-simple-syntax (name arg ...) body ...) ;; (define-syntax define-simple-syntax (syntax-rules () ((_ (name arg ...) body ...) (define-syntax name (syntax-rules () ((name arg ...) (begin body ...))))))) ;;====================================================================== ;; syntatic sugar items ;;====================================================================== ;; We often seem to want to include stuff if a conditional is met ;; otherwise not include it. This routine makes that slightly cleaner ;; since using a pure if results in #<undefined> objects. (admittedly they ;; should be ignored but this is slightly cleaner I think). ;; ;; NOTE: This has to be a macro or the true clause will be evaluated ;; whether "a" is true or false ;; If a is true return b, else return '() (define-simple-syntax (s:if a b) (if a b '())) ;; Using the Simple-Syntax System ;; ;; The syntax for defining macros in this system is similar to that for defining functions. In fact if the macro has a fixed number of arguments the syntax is identical. For example: ;; ;; ; Define a simple macro to add a value to a variable. ;; ; ;; (define-simple-syntax (+= variable value) ;; (set! variable (+ variable value))) ;; ;; ; Use it. ;; ; ;; (define v 2) ;; (+= v 7) ;; v ; => 9 ;; ;; For a fixed number of arguments followed by an unknown number of arguments we use ... after a single argument to represent the unknown number (possibly zero) of arguments. For example, let's revise our definition of += to allow zero or more values to be added: ;; ;; ; Define a simple macro to add a zero or more values to a variable ;; ; ;; (define-simple-syntax (+= variable value ...) ;; (set! variable (+ variable value ...))) ;; ;; ; Use it ;; ; ;; (define v 2) ;; (+= v 7) ;; v ; => 9 ;; (+= v 3 4) ;; v ; => 16 ;; (+= v) ;; v ; => 16 ;; (define-simple-syntax (s:if-param varname first ...) (if (s:get varname) (begin first ...) '())) (define-simple-syntax (s:if-sessionvar varname first ...) (if (s:session-var-get varname) (begin first ...) '())) ;; (define-macro (s:if-param varname ...) ;; (match dat ;; (() '()) ;; ((a) `(if (s:get ,varname) ,a '())) ;; ((a b) `(if (s:get ,varname) ,a ,b)))) ;; ;; (define-macro (s:if-sessionvar varname . dat) ;; (match dat ;; (() '()) ;; ((a) `(if (s:session-var-get ,varname) ,a '())) ;; ((a b) `(if (s:session-var-get ,varname) ,a ,b)))) ;; ) |
Added stml2/stml2.setup version [54bbd223c3].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 2007-2010, Matthew Welland. ;; ;; This program is made available under the GNU GPL version 2.0 or ;; greater. See the accompanying file COPYING for details. ;; ;; This program is distributed WITHOUT ANY WARRANTY; without even the ;; implied warranty of MERCHANTABILITY or FITNlmESS FOR A PARTICULAR ;; PURPOSE. ;;;; margs.setup ;; compile the code into a dynamically loadable shared object ;; (will generate margs.so) ;; (compile -s margs.scm) ;; Install as extension library ;; handle cookies (standard-extension 'cookie "0.5") ;; (standard-extension 'stmlcommon "0.5") (standard-extension 'stml2 "0.5") ;; (standard-extension 'session "0.5") ;; (standard-extension 'misc-stml "0.5") ;; moved to stmlcommon.scm ;; (standard-extension 'html-filter "0.5") ;; moved to stmlcommon.scm ;; (standard-extension 'formdat "0.5") ;; moved into stmlcommon.scm ;; (standard-extension 'setup "0.5") ;; moved into stmlcommon.scm ;; (standard-extension 'keystore "0.5") ;; moved into stmlcommon.scm ;; (standard-extension 'sqltbl "0.5") ;; eliminated ;; (install-extension 'stml "stml.so") |
Added stml2/stmlcommon.scm version [d0639f2742].
> > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | ;; Copyright 2007-2011, Matthew Welland. ;; ;; This program is made available under the GNU GPL version 2.0 or ;; greater. See the accompanying file COPYING for details. ;; ;; This program is distributed WITHOUT ANY WARRANTY; without even the ;; implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR ;; PURPOSE. ;; (require-extension syntax-case) ;; (declare (run-time-macros)) (module stmlcommon * (import chicken scheme data-structures extras srfi-13 ports posix) (use (prefix dbi dbi:) regex (prefix crypt c:) srfi-69) ) |
Added stml2/stmlmodule.scm version [296e0e34a7].
> > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | ;; Copyright 2007-2011, Matthew Welland. ;; ;; This program is made available under the GNU GPL version 2.0 or ;; greater. See the accompanying file COPYING for details. ;; ;; This program is distributed WITHOUT ANY WARRANTY; without even the ;; implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR ;; PURPOSE. ;; (require-extension syntax-case) ;; (declare (run-time-macros)) (include "stmlcommon.scm") |
Added stml2/stmlrun.scm version [a5be661fee].
> > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | #!/usr/local/bin/csi -q ;; Copyright 2007-2011, Matthew Welland. ;; ;; This program is made available under the GNU GPL version 2.0 or ;; greater. See the accompanying file COPYING for details. ;; ;; This program is distributed WITHOUT ANY WARRANTY; without even the ;; implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR ;; PURPOSE. ;; (require-extension syntax-case) ;; (declare (run-time-macros)) ;; (include "stmlcommon.scm") (require-library stml) (stml:main #f) |
Added stml2/sugar.scm version [b784df1be7].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | ;; Copyright 2007-2011, Matthew Welland. ;; ;; This program is made available under the GNU GPL version 2.0 or ;; greater. See the accompanying file COPYING for details. ;; ;; This program is distributed WITHOUT ANY WARRANTY; without even the ;; implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR ;; PURPOSE. ;; ;;====================================================================== ;; Sugar ;;====================================================================== ;; ;; (require 'syntax-case) ;; ;; (define-syntax s:if-param ;; (syntax-rules () ;; [(_ s x) (if (s:get s) x (s:comment "s:if not"))] ;; [(_ s x y) (if (s:get s) x y)])) ;; ;; ;; (define-syntax s:if-test ;; (syntax-rules () ;; [(_ s x) (if (string=? "yep" s) x (list "s:if not"))] ;; [(_ s x y) (if (string=? "yep" s) x y)])) ;; Some of these routines use: ;; ;; http://www.cs.toronto.edu/~gfb/scheme/simple-macros.html ;; ;; Syntax for defining macros in a simple style similar to function definiton, ;; when there is a single pattern for the argument list and there are no keywords. ;; ;; (define-simple-syntax (name arg ...) body ...) ;; (define-syntax define-simple-syntax (syntax-rules () ((_ (name arg ...) body ...) (define-syntax name (syntax-rules () ((name arg ...) (begin body ...))))))) ;;====================================================================== ;; syntatic sugar items ;;====================================================================== ;; We often seem to want to include stuff if a conditional is met ;; otherwise not include it. This routine makes that slightly cleaner ;; since using a pure if results in #<undefined> objects. (admittedly they ;; should be ignored but this is slightly cleaner I think). ;; ;; NOTE: This has to be a macro or the true clause will be evaluated ;; whether "a" is true or false ;; If a is true return b, else return '() (define-simple-syntax (s:if a b) (if a b '())) ;; Using the Simple-Syntax System ;; ;; The syntax for defining macros in this system is similar to that for defining functions. In fact if the macro has a fixed number of arguments the syntax is identical. For example: ;; ;; ; Define a simple macro to add a value to a variable. ;; ; ;; (define-simple-syntax (+= variable value) ;; (set! variable (+ variable value))) ;; ;; ; Use it. ;; ; ;; (define v 2) ;; (+= v 7) ;; v ; => 9 ;; ;; For a fixed number of arguments followed by an unknown number of arguments we use ... after a single argument to represent the unknown number (possibly zero) of arguments. For example, let's revise our definition of += to allow zero or more values to be added: ;; ;; ; Define a simple macro to add a zero or more values to a variable ;; ; ;; (define-simple-syntax (+= variable value ...) ;; (set! variable (+ variable value ...))) ;; ;; ; Use it ;; ; ;; (define v 2) ;; (+= v 7) ;; v ; => 9 ;; (+= v 3 4) ;; v ; => 16 ;; (+= v) ;; v ; => 16 ;; (define-simple-syntax (s:if-param varname first ...) (if (s:get varname) first ...)) (define-simple-syntax (s:if-sessionvar varname first ...) (if (s:session-var-get varname) first ...)) ;; (define-macro (s:if-param varname ...) ;; (match dat ;; (() '()) ;; ((a) `(if (s:get ,varname) ,a '())) ;; ((a b) `(if (s:get ,varname) ,a ,b)))) ;; ;; (define-macro (s:if-sessionvar varname . dat) ;; (match dat ;; (() '()) ;; ((a) `(if (s:session-var-get ,varname) ,a '())) ;; ((a b) `(if (s:session-var-get ,varname) ,a ,b)))) ;; |
Added stml2/test.scm version [62a996e095].
> > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | (use test md5) (require-extension sqlite3) (import (prefix sqlite3 sqlite3:)) (require-library dbi) ;; (declare (uses stml)) (include "requirements.scm") (include "cookie.scm") (include "misc-stml.scm") (include "formdat.scm") (include "stml.scm") (include "session.scm") (include "sqltbl.scm") (include "html-filter.scm") (include "keystore.scm") (define p (open-input-file "test.stml")) (print (process-port p)) (close-input-port p) |
Added stml2/test.stml version [0f6611f558].
> > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 | ;; Copyright 2007-2008, Matthew Welland. Kiatoa.com All rights reserved. ;; ;; index (list (s:html (s:head (s:title "Kiatoa") (s:link 'rel "stylesheet" 'type "text/css" 'href "/kiatoa/markup.css") (s:link 'rel "stylesheet" 'type "text/css" 'href "/kiatoa/layout.css")))) |
Added stml2/tests/example.post.binary.in version [a9df00433e].
cannot compute difference between binary files
Added stml2/tests/example.post.in version [459133135e].
> | 1 | email-address=matt%3A1&password=Blah&form-name=login |
Added stml2/tests/models/test.scm version [d92e100cbc].
> > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 | ;; Copyright 2007-2008, Matthew Welland. ;; ;; This program is made available under the GNU GPL version 2.0 or ;; greater. See the accompanying file COPYING for details. ;; ;; This program is distributed WITHOUT ANY WARRANTY; without even the ;; implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR ;; PURPOSE. ;; ;; models/test.scm |
Added stml2/tests/pages/test/control.scm version [3d3e9e16d3].
> > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 | ;; Copyright 2007-2008, Matthew Welland. ;; ;; This program is made available under the GNU GPL version 2.0 or ;; greater. See the accompanying file COPYING for details. ;; ;; This program is distributed WITHOUT ANY WARRANTY; without even the ;; implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR ;; PURPOSE. ;; ;; pages/test/control.scm |
Added stml2/tests/pages/test/view.scm version [79bce22dd6].
> > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 | ;; Copyright 2007-2008, Matthew Welland. ;; ;; This program is made available under the GNU GPL version 2.0 or ;; greater. See the accompanying file COPYING for details. ;; ;; This program is distributed WITHOUT ANY WARRANTY; without even the ;; implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR ;; PURPOSE. ;; ;; pages/test/view.scm |
Added stml2/tests/test.scm version [5b953a7034].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | #!/usr/local/bin/csi -q ;; Copyright 2007-2008, Matthew Welland. ;; ;; This program is made available under the GNU GPL version 2.0 or ;; greater. See the accompanying file COPYING for details. ;; ;; This program is distributed WITHOUT ANY WARRANTY; without even the ;; implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR ;; PURPOSE. (use test md5) (require-extension sqlite3) (import (prefix sqlite3 sqlite3:)) ;; (require-library dbi) (use (prefix dbi dbi:)) (load "./requirements.scm") (load "./cookie.scm") (load "./misc-stml.scm") (load "./formdat.scm") (load "./stml.scm") (load "./session.scm") (load "./sqltbl.scm") (load "./html-filter.scm") (load "./keystore.scm") ;; Test the primitive dbi interface (system "rm -f tests/test.db") (define db (dbi:open 'sqlite3 '((dbname . "tests/test.db")))) (dbi:exec db "CREATE TABLE foo(id INTEGER PRIMARY KEY,name TEXT);") (dbi:exec db "INSERT INTO foo(name) VALUES(?);" "Matt") (dbi:for-each-row (lambda (tuple) (print (vector-ref tuple 0) " " (vector-ref tuple 1))) db "SELECT * FROM foo;") (test "dbi:get-one" "Matt" (dbi:get-one db "SELECT name FROM foo WHERE name='Matt';")) ;; keystore (dbi:exec db "CREATE TABLE metadata (id INTEGER PRIMARY KEY,key TEXT,value TEXT);") (keystore:set! db "SCHEMA-VERSION" 1.2) (test "Keystore get" "1.2" (keystore:get db "SCHEMA-VERSION")) (keystore:del! db "SCHEMA-VERSION") (test "Keystore get deleted" #f (keystore:get db "SCHEMA-VERSION")) (system "rm -f tests/test.db") ;; create a session to work with") (setenv "REQUEST_URI" "/stmlrun?action=test.test") (setenv "SCRIPT_NAME" "/cgi-bin/stmlrun") (setenv "PATH_INFO" "/test") (setenv "QUERY_STRING" "action=test.test") (setenv "SERVER_NAME" "localhost") (setenv "REQUEST_METHOD" "GET") (load "./setup.scm") (s:validate-inputs) ;; test session variables (session:get-vars s:session) (define nada "andnndhhshaas") (s:session-var-set! "nick" nada) (test "Session var set/get" nada (s:session-var-get "nick")) (print "got here") (session:save-vars s:session) (session:get-vars s:session) (test "Session var set/get after save/get" nada (s:session-var-get "nick")) (session:del! s:session "*sessionvars*" "nick") (test "Session var del" #f (s:session-var-get "nick")) (session:save-vars s:session) (session:get-vars s:session) (s:session-var-set! "nick" nada) (session:save-vars s:session) ;; (test "Session var del" #f (s:session-var-get "nick")) ;; test person (load "./tests/models/test.scm") (print "Session key is " (sdat-get-session-key s:session)) (test "Delete session" #t (s:delete-session)) (let ((fh (open-input-pipe "ls ./tests/pages/*/control.scm"))) (let loop ((l (read-line fh))) (if (not (eof-object? l)) (begin ;; (print "loading " l) (load l) (loop (read-line fh))))) (close-input-port fh)) ;; Should have poll:poll defined now. (test "Make a random string" 2 (string-length (session:make-rand-string 2))) (test "Create an encrypted password using DES (backwards compat)" "abQ9KY.KfrYrc" (s:crypt-passwd "foo" "ab")) (test "Create an encrypted password using Blowfish" "$2a$12$GyoKHX/UOxMLGtwdSTr7EOF9KQzlyyyRqFTKx1YvLA3sMukbV4WBC" (s:crypt-passwd "foo" "$2a$12$GyoKHX/UOxMLGtwdSTr7EO")) (test "s:any->string on a hash-table" "#<hash-table>" (s:any->string (make-hash-table))) (define select-list '((a b c)(d (e f g)(h i j #t)))) (define result '("<SELECT name=\"efg\">" ((("<OPTION label=\"a\" value=\"b\">c</OPTION>") ("<OPTGROUP label=d" ("<OPTION label=\"e\" value=\"f\">g</OPTION>") ("<OPTION selected label=\"h\" value=\"i\">j</OPTION>") "</OPTGROUP>"))) "</SELECT>")) (test "Select list" result (s:select select-list 'name "efg")) ;; Test modules (test "misc:non-zero-string \"\"" #f (misc:non-zero-string "")) (test "misc:non-zero-string #f" #f (misc:non-zero-string #f)) (test "misc:non-zero-string 'blah" #f (misc:non-zero-string 'blah)) ;; forms (define form #f) (test "make <formdat>" #t (let ((f (make-formdat:formdat))) (set! form f) #t)) (test "formdat: set!/get" "Yep!" (begin (formdat:set! form "blah" "Yep!") (formdat:get form "blah"))) (test "s:string->pgint" 123 (s:any->pgint "123")) (test "s:illegal-pgint (legal)" #f (s:illegal-pgint 1011)) (test "s:illegal-pgint (illegal big)" 1 (s:illegal-pgint 9999999999)) (test "s:illegalpgint (illegal small)" -1 (s:illegal-pgint -9999999999)) ;; The twiki module ;; clean up (system "rm -rf twikis/*") (load "modules/twiki/twiki-mod.scm") (define keys (list "blah" 1 'nada)) (test "twiki:keys->key" "blah 1 nada" (twiki:keys->key keys)) (define key (twiki:keys->key keys)) (define *tdb* #f) (test "twiki:open-db" #t (let ((db (twiki:open-db key))) (set! *tdb* db) (if *tdb* #t #f))) (define wiki (make-twiki:wiki)) (twiki:wiki-set-wid! wiki 1) (twiki:wiki-set-name! wiki "main") (twiki:wiki-set-perms! wiki '(r w)) (test "twiki:dat->html" '("Hello" "<BR>") (twiki:dat->html "Hello" wiki)) (test "twiki:keys->fname" '("twikis/Ymxha/CAxIG/5hZGE" "YmxhaCAxIG5hZGE_") ;; ("twikis/d99a2de9/6808493b/23770f70" "d99a2de96808493b23770f70c76dffe4") (twiki:key->fname key)) (test "twiki:name->wid" 1 (twiki:name->wid *tdb* "main")) (test "twiki:get-tiddlers-by-num" '() (twiki:get-tiddlers-by-num *tdb* 0 (list 1 2 3))) (test "twiki:get-tiddlers-by-name" '() (twiki:get-tiddlers-by-name *tdb* 0 "MainMenu")) (test "twiki:get-tiddlers" '() (twiki:get-tiddlers *tdb* 0 (list "MainMenu"))) (test "twiki:get-tiddlers" '() (twiki:get-tiddlers *tdb* 0 (list "MainMenu" "AnotherOne"))) (test "twiki:wiki" "<TABLE>" (car (twiki:wiki "main" (list "blah" 1 'nada)))) (test "twiki:view" "<DIV class=\"node\">" (car (twiki:view "" "" 0 (twiki:tiddler-make) wiki))) (test "s:td" '("<TD>" (()) "</TD>") (s:td '())) ;; (test "twiki:get-tiddlers-by-name" '() (twiki:get-tiddlers-by-name 1 "fred")) (test "twiki:tiddler-name->id" 1 (twiki:tiddler-name->id *tdb* "MainMenu")) (test "s:set! a var to #f" "" (begin (s:set! "BLAH" #f) (s:get "BLAH"))) ;; don't know if this one makes sense. Setting to #f should really delete the value (test "twiki:save-dat" 2 (twiki:save-dat *tdb* "dat" 0)) (test "twiki:get-dat" "dat" (twiki:get-dat *tdb* 2)) (test "twiki:get-dat" #f (twiki:get-dat *tdb* 5)) ;; (test "twiki:get-dat" #f (twiki:get-dat *tdb* #f)) (test "twiki:save-tiddler" #t (twiki:save-tiddler *tdb* "heading" "body" "tags" key 0)) ;; (test "twiki:save-curr-tiddler" #f (twiki:save-curr-tiddler *tdb* 1)) (test "twiki:edit-twiddler" #t (list? (twiki:edit-tiddler *tdb* key 0 0))) (test "twiki:maint_area" "<DIV>" (car (twiki:maint_area *tdb* 1 key wiki))) (test "twiki:pic_mgmt" "<DIV>" (car (twiki:pic_mgmt *tdb* 1 key))) ;; get a blob jpg to process (define inp2 (open-input-file "tests/kiatoa.png")) (define dat (string->blob (read-string #f inp2))) (close-input-port inp2) (test "twiki:save-pic" #t (twiki:save-pic *tdb* (list "mypic.jpg" "image/jpeg" dat) 0)) ;; (string->blob "testing eh!")))) ;; (test "twiki:save-pic-from-form" #f (twiki:save-pic-from-form *tdb* 1)) ;; more tests on dats (define dat #f) (let ((inp (open-input-file "tests/kiatoa.png"))) (set! dat (read-string #f inp)) (close-input-port inp)) (use md5) (define dat-md5 (md5:digest dat)) (test "twiki:save-dat (binary)" 4 (twiki:save-dat *tdb* dat 1)) (test "twiki:get-dat (binary)" dat-md5 (let ((d (twiki:get-dat *tdb* 4))) (md5:digest d))) ;; forms ;; (define inp (open-input-file "tests/example.post.in")) ;; (define dat (read-string #f inp)) ;; (define datstr (open-input-string dat)) ;; binary inputs (define inp (open-input-file "tests/example.post.binary.in")) (define dat #f) (test "formdat:load-all-port multipart" #t (let ((idat (formdat:load-all-port inp))) (set! dat idat) #t)) (test "formdat:keys" '(picture-name input-picture "" submit-picture) (formdat:keys dat)) (define inp (open-input-file "tests/example.post.in")) (test "formdat:load-all-port single part" #t (let ((idat (formdat:load-all-port inp))) (set! dat idat) #t)) (test "formdat:keys" '(email-address form-name password) (formdat:keys dat)) (close-input-port inp) |
Added stml2/testscript.sh version [48d4209584].
> > > > > > > | 1 2 3 4 5 6 7 | export REQUEST_URI='/stmlrun?action=login.login' export SCRIPT_NAME=/cgi-bin/stmlrun export PATH_INFO=/classifieds export QUERY_STRING='action=login.login' export SERVER_NAME=localhost export REQUEST_METHOD=GET export HTTP_COOKIE='session_key=to09ipFJ9_2KXT96b2f9Q' |
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 [e136a37772].
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 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 | (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)))))) (define (tasks:get-task-db-path) (let ((dbdir (or (configf:lookup *configdat* "setup" "monitordir") (configf:lookup *configdat* "setup" "dbdir") (conc (common:get-linktree) "/.db")))) (handle-exceptions exn (begin (debug:print-error 0 *default-log-port* "Couldn't create path to " dbdir ", exn=" exn) (exit 1)) (if (not (directory? dbdir))(create-directory dbdir #t))) dbdir)) ;; If file exists AND ;; file readable ;; ==> open it |
︙ | ︙ | |||
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 [6658a745e5].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | ;; Copyright 2006-2017, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more 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-version.scm") (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 [698654fba2].
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 | ;;====================================================================== ;; 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 ;;====================================================================== (declare (unit tests)) (declare (uses lock-queue)) (declare (uses db)) (declare (uses tdb)) (declare (uses common)) ;; (declare (uses dcommon)) ;; needed for the steps processing (declare (uses items)) (declare (uses runconfig)) ;; (declare (uses sdb)) (declare (uses server)) ;;(declare (uses stml2)) (use sqlite3 srfi-1 posix regex regex-case srfi-69 dot-locking tcp directory-utils) (import (prefix sqlite3 sqlite3:)) (require-library stml) (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))) | | | > > > > > > > | 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 | (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) | | | | | 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 | (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 | > > > > > > > > | > > | | | | | | | | | | | | | | | > > > > > > > > | | > > > > > > > > > > > > > > > | | | | | | | > | < < | | 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 | ;; ;; [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) ","))))) (define *glob-like-match-cache* (make-hash-table)) (define (tests:cache-regexp str-in flag) (let* ((key (conc str-in flag))) (or (hash-table-ref/default *glob-like-match-cache* key #f) (let* ((newrx (regexp str-in flag))) (hash-table-set! *glob-like-match-cache* key newrx) newrx)))) ;; tests:glob-like-match (define (tests:glob-like-match patt str) (let* ((like (substring-index "%" patt)) (notpatt (equal? (substring-index "~" patt) 0)) (newpatt (if notpatt (substring patt 1) patt)) (finpatt (if like (string-substitute (regexp "%") ".*" newpatt #f) (string-substitute (regexp "\\*") ".*" newpatt #f))) (rx (tests:cache-regexp finpatt (if like #t #f))) (res (string-match rx str))) (if notpatt (not res) res))) ;; if itempath is #f then look only at the testname part ;; (define (tests:match patterns testname itempath #!key (required '())) (if (string? patterns) (let ((patts (append (string-split patterns ",") required))) (if (null? patts) ;;; no pattern(s) means no match |
︙ | ︙ | |||
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")) | | | | 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 | (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)) | | | | | > > > > > | 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 | ;; (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)) |
︙ | ︙ | |||
491 492 493 494 495 496 497 | (change-directory orig-dir) ;; NB// tests:test-set-toplog! is remote internal... (tests:test-set-toplog! run-id test-name outputfilename)) ;; didn't get the lock, check to see if current update started later than this ;; update, if so we can exit without doing any work (if (> my-start-time (handle-exceptions exn | > > | | 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 | (change-directory orig-dir) ;; NB// tests:test-set-toplog! is remote internal... (tests:test-set-toplog! run-id test-name outputfilename)) ;; didn't get the lock, check to see if current update started later than this ;; update, if so we can exit without doing any work (if (> my-start-time (handle-exceptions exn (begin (print "failed to get mod time on " lockf ", exn=" exn) 0) (file-modification-time lockf))) ;; we started since current re-gen in flight, delay a little and try again (begin (debug:print-info 1 *default-log-port* "Waiting to update " outputfilename ", another test currently updating it") (thread-sleep! (+ 5 (random 5))) ;; delay between 5 and 10 seconds (loop (common:simple-file-lock lockf)))))))))) |
︙ | ︙ | |||
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;} | > > > > > > | < | 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 | 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))) | > > > > > > > > > > > > > > > > > > | 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 | } } } </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 714 715 716 | (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:create-html-tree "test-index.html") ;; (define (tests:create-html-tree outf) | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | < < < | | | < < < < < < | < < < < < < < < < < < < < | < < < | < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | (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)) (begin (debug-print 0 *default-log-port* "Failed to get lock on file outf, lockfile: " 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)))) | | | 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 | "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")) | | | 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 | (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")) | | | | | 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 | (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"))) | > > > > > > > > > > > > > > > > > > > | 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 | (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")) | | | | 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 | (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)) |
︙ | ︙ | |||
1112 1113 1114 1115 1116 1117 1118 1119 | (if fnamepatt (apply append (map (lambda (p) (if (directory-exists? p) (let ((glob-query (conc p "/" fnamepatt))) (handle-exceptions exn (with-input-from-pipe | > > | | | | | | | > | | | > > | | > > > > > > > > > > > | > > > > > > > > > > > > > | > | | 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 | (if fnamepatt (apply append (map (lambda (p) (if (directory-exists? p) (let ((glob-query (conc p "/" fnamepatt))) (handle-exceptions exn (begin (print "built-in glob on " glob-query ", failed, try using the shell. exn=" exn) (with-input-from-pipe (conc "echo " glob-query) read-lines)) ;; we aren't going to try too hard. If glob breaks it is likely because someone tried to do */*/*.log or similar (glob glob-query))) '())) paths-from-db)) paths-from-db))) ;;====================================================================== ;; 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 (begin (debug:print 0 *default-log-port* "failed to read " cache-file ", exn=" exn) #f) ;; any issues, just give up with the cached version and re-read (configf:read-alist cache-file)) #f)) (test-full-name (if (and item-path (not (string-null? item-path))) (conc test-name "/" item-path) test-name))) (if cached-dat cached-dat (let ((dat (hash-table-ref/default *testconfigs* test-full-name #f))) (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)) | | | | 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 | (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 |
︙ | ︙ | |||
1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 | ;; (lambda (x)(equal? "node" (car x))) ;; (map string-split (tests:easy-dot test-records "plain")))))) ;; (map car (sort data (lambda (a b) ;; (> (string->number (caddr a))(string->number (caddr b))))))) ;; )) (sort all-tests sort-fn1)))) ;; avoid dealing with deleted tests, look at the hash table (define (tests:easy-dot test-records outtype) (let-values (((fd temp-path) (file-mkstemp (conc "/tmp/" (current-user-name) ".XXXXXX")))) (let ((all-testnames (hash-table-keys test-records)) (temp-port (open-output-file* fd))) ;; (format temp-port "This file is ~A.~%" temp-path) (format temp-port "digraph tests {\n") (format temp-port " size=4,8\n") ;; (format temp-port " splines=none\n") (for-each (lambda (testname) (let* ((testrec (hash-table-ref test-records testname)) | > > > > > > > > > > > > > > > > > | > > | | 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 | ;; (lambda (x)(equal? "node" (car x))) ;; (map string-split (tests:easy-dot test-records "plain")))))) ;; (map car (sort data (lambda (a b) ;; (> (string->number (caddr a))(string->number (caddr b))))))) ;; )) (sort all-tests sort-fn1)))) ;; avoid dealing with deleted tests, look at the hash table ;; look up all waitons that are related to test "testname" ;; (define (tests:get-mt-waitons testname flatten) (let* ((mt-waitons (configf:get-section *configdat* "waitons")) (my-waitons (filter (lambda (x) (string-match (conc "^(" testname "|" testname"/.*)$") (car x))) mt-waitons))) (if flatten (map (lambda (w) (car (string-split w "/"))) (apply append (map (lambda (x) (string-split (cadr x))) my-waitons))) my-waitons))) ;; NOT USED (define (tests:easy-dot test-records outtype) (let-values (((fd temp-path) (file-mkstemp (conc "/tmp/" (current-user-name) ".XXXXXX")))) (let ((all-testnames (hash-table-keys test-records)) (temp-port (open-output-file* fd))) ;; (format temp-port "This file is ~A.~%" temp-path) (format temp-port "digraph tests {\n") (format temp-port " size=4,8\n") ;; (format temp-port " splines=none\n") (for-each (lambda (testname) (let* ((testrec (hash-table-ref test-records testname)) (waitons (or (tests:testqueue-get-waitons testrec) '())) (my-mt-waitons (tests:get-mt-waitons testname #t))) ;; (print "my-mt-waitons=" my-mt-waitons) (for-each (lambda (waiton) (format temp-port (conc " " waiton " -> " testname " [splines=ortho]\n"))) (append waitons my-mt-waitons)))) all-testnames) (format temp-port "}\n") (close-output-port temp-port) (with-input-from-pipe (conc "env -i PATH=$PATH dot -T" outtype " < " temp-path) (lambda () (let ((res (read-lines))) |
︙ | ︙ | |||
1321 1322 1323 1324 1325 1326 1327 1328 | (tal (cdr all-testnames)) (res (list "digraph tests {" (conc " size=\"" (or sizex 11) "," (or sizey 11) "\";") " ratio=0.95;" ))) (let* ((testrec (hash-table-ref test-records hed)) (waitons (or (tests:testqueue-get-waitons testrec) '())) (newres (append res | > > | | < > | 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 | (tal (cdr all-testnames)) (res (list "digraph tests {" (conc " size=\"" (or sizex 11) "," (or sizey 11) "\";") " ratio=0.95;" ))) (let* ((testrec (hash-table-ref test-records hed)) (waitons (or (tests:testqueue-get-waitons testrec) '())) (my-mt-waitons (tests:get-mt-waitons hed #t)) (all-waitons (delete-duplicates (append waitons my-mt-waitons))) (newres (append res (if (null? all-waitons) (list (conc " \"" hed "\" [shape=box];")) (map (lambda (waiton) (conc " \"" waiton "\" -> \"" hed "\" [shape=box];")) all-waitons))))) ;; (debug:print 0 *default-log-port* "For test "hed" got "all-waitons) (if (null? tal) (append newres (list "}")) (loop (car tal)(cdr tal) newres) )))))) ;; (tests:run-dot (list "digraph tests {" "a -> b" "}") "plain") |
︙ | ︙ | |||
1349 1350 1351 1352 1353 1354 1355 1356 | (lambda () (read-lines))))) (close-input-port inp) res))) ;; read data from tmp file or create if not exists ;; if exists regen in background ;; | > | | | | | | | | | | | | | > > > > > > | 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 | (lambda () (read-lines))))) (close-input-port inp) res))) ;; read data from tmp file or create if not exists ;; if exists regen in background ;; mode: raw (return data as read) or munged (convert to list of lists and remove " from strings) ;; (define (tests:lazy-dot testrecords outtype sizex sizey mode) (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) (let ((data (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)) (with-input-from-file fname (lambda () (read-lines))))))) (if (eq? mode 'raw) data (map (lambda (inl) (map (lambda (s) (string-substitute "\"" "" s #t)) (string-split inl))) data))))) ;; for each test: ;; (define (tests:filter-non-runnable run-id testkeynames testrecordshash) (let ((runnables '())) (for-each (lambda (testkeyname) |
︙ | ︙ | |||
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 | | | 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 | (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 | | | 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 | ;; (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 |
︙ | ︙ | |||
1520 1521 1522 1523 1524 1525 1526 | (lambda (count) (set! res count)) tdb "SELECT count(id) FROM test_rundat;") res)) 0) | > | > > > > > > > > > > > > > > > > > > > > | > > | | | | | | | > | < < < < < < < < < < < < < < < < < < < < < < < | 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 | (lambda (count) (set! res count)) tdb "SELECT count(id) FROM test_rundat;") res)) 0) ;; (define (tests:update-central-meta-info run-id test-id cpuload diskfree minutes uname hostname #!key (update-db #f)(tmpfree #f)) (if (get-environment-variable "MT_TEST_RUN_DIR") (let* ((dest-dir (conc (get-environment-variable "MT_TEST_RUN_DIR") "/.mt_data")) (or-dash (lambda (instr) (cond ((not instr) "") ;; #f -> blank, indicates value unchanged since last measurement taken ((string? instr)(if (string-search " " instr) (conc "\"" instr "\"") instr)) (else instr)))) (file-new (not (directory-exists? dest-dir)))) (if file-new (create-directory dest-dir #t)) (let* ((outp (open-output-file (conc dest-dir "/test-run.dat") #:append))) (with-output-to-port outp (lambda () (if file-new (print "epoch_time,run_id,test_id,cpuload,diskfree,tmpfree,run_minutes,hostname,uname")) (print (current-seconds) "," (or-dash run-id) "," (or-dash test-id) "," (or-dash cpuload) "," (or-dash diskfree) "," (or-dash tmpfree) "," (or-dash minutes) "," (or-dash hostname) "," (or-dash uname)))) ;; put uname last as it has spaces in it (close-output-port outp))) (begin (rmt:general-call 'update-test-rundat run-id test-id (current-seconds) (or cpuload -1)(or diskfree -1) -1 (or minutes -1)))) (if update-db (begin (if (and cpuload diskfree) (rmt:general-call 'update-cpuload-diskfree run-id cpuload diskfree test-id)) (if minutes (rmt:general-call 'update-run-duration run-id minutes test-id)) (if (and uname hostname) (rmt:general-call 'update-uname-host run-id uname hostname test-id))))) ;; This one is for running with no db access (i.e. via rmt: internally) (define (tests:set-full-meta-info db test-id run-id minutes work-area remtries #!key (update-db #f)) ;; (define (tests:set-full-meta-info test-id run-id minutes work-area) ;; (let ((remtries 10)) (let* ((cpuload (get-cpu-load)) (diskfree (get-df (current-directory))) (tmpfree (get-df "/tmp")) (uname (get-uname "-srvpio")) (hostname (get-host-name))) (tests:update-central-meta-info run-id test-id cpuload diskfree minutes uname hostname update-db: update-db tmpfree: tmpfree))) ;;====================================================================== ;; A R C H I V I N G ;;====================================================================== (define (test:archive db test-id) #f) (define (test:archive-tests db keynames target) #f) |
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 [52fe593b26].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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))) 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 [2e51ccf329].
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 (string? (server:get-best-guess-address (get-host-name)))) (test #f #t (string? (car (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 (vector? (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 [5b84d6f782].
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 | ;;====================================================================== ;; 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 "megatest-version.scm") (include "common_records.scm") (include "db_records.scm") (include "key_records.scm") ;;====================================================================== ;; T R E E S T U F F ;;====================================================================== |
︙ | ︙ | |||
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)) | | > > > | 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 | ;; 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].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Added ulex.scm version [39353b5283].
> > > > > > > > > > > > > > > > > > > > > > > > | 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 2019, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more 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 ulex)) (declare (uses pkts)) (include "ulex/ulex.scm") |
Added ulex/ulex.scm version [42b648b50c].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | ;; ulex: Distributed sqlite3 db ;;; ;; Copyright (C) 2018 Matt Welland ;; Redistribution and use in source and binary forms, with or without ;; modification, is permitted. ;; ;; THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS ;; OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ;; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ;; ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE ;; LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ;; CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT ;; OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR ;; BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF ;; LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ;; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE ;; USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH ;; DAMAGE. ;;====================================================================== ;; ABOUT: ;; See README in the distribution at https://www.kiatoa.com/fossils/ulex ;; NOTES: ;; Why sql-de-lite and not say, dbi? - performance mostly, then simplicity. ;; ;;====================================================================== (use mailbox) (module ulex * (import scheme posix chicken data-structures ports extras files mailbox) (import srfi-18 pkts matchable regex typed-records srfi-69 srfi-1 srfi-4 regex-case (prefix sqlite3 sqlite3:) foreign tcp6 ;; ulex-netutil hostinfo ) ;; make it a global? Well, it is local to area module (define *captain-pktspec* `((captain (host . h) (port . p) (pid . i) (ipaddr . a) ) #;(data (hostname . h) ;; sender hostname (port . p) ;; sender port (ipaddr . a) ;; sender ip (hostkey . k) ;; sending host key - store info at server under this key (servkey . s) ;; server key - this needs to match at server end or reject the msg (format . f) ;; sb=serialized-base64, t=text, sx=sexpr, j=json (data . d) ;; base64 encoded slln data ))) ;; struct for keeping track of our world (defstruct udat ;; captain info (captain-address #f) (captain-host #f) (captain-port #f) (captain-pid #f) (captain-lease 0) ;; time (unix epoc) seconds when the lease is up (ulex-dir (conc (get-environment-variable "HOME") "/.ulex")) (cpkts-dir (conc (get-environment-variable "HOME") "/.ulex/pkts")) (cpkt-spec *captain-pktspec*) ;; this processes info (my-cpkt-key #f) ;; put Z card here when I create a pkt for myself as captain (my-address #f) (my-hostname #f) (my-port #f) (my-pid (current-process-id)) (my-dbs '()) ;; server and handler thread (serv-listener #f) ;; this processes server info (handler-thread #f) (mboxes (make-hash-table)) ;; key => mbox ;; other servers (peers (make-hash-table)) ;; host-port => peer record (dbowners (make-hash-table)) ;; dbfile => host-port (handlers (make-hash-table)) ;; dbfile => proc ;; (outgoing-conns (make-hash-table)) ;; host:port -> conn (work-queue (make-queue)) ;; most stuff goes here ;; (fast-queue (make-queue)) ;; super quick stuff goes here (e.g. ping) (busy #f) ;; is either of the queues busy, use to switch between queuing tasks or doing immediately ;; app info (appname #f) (dbtypes (make-hash-table)) ;; this should be an alist but hash is easier. dbtype => [ initproc syncproc ] ;; cookies (cnum 0) ;; cookie num ) ;;====================================================================== ;; NEW APPROACH ;;====================================================================== ;; start-server-find-port ;; gotta have a server port ready from the very begining ;; udata - all the connection info, captain, server, ulex db etc. MUST BE PASSED IN ;; dbpath - full path and filename of the db to talk to or a symbol naming the db? ;; callname - the remote call to execute ;; params - parameters to pass to the remote call ;; (define (remote-call udata dbpath dbtype callname . params) (start-server-find-port udata) ;; ensure we have a local server (find-or-setup-captain udata) ;; look at connect, process-request, send, send-receive (let-values (((cookie-key host-port)(get-db-owner udata dbpath dbtype))) (send-receive udata host-port callname cookie-key params))) ;;====================================================================== ;; KEY FUNCTIONS - THESE ARE TOO BE EXPOSED AND USED ;;====================================================================== ;; connection setup and management functions ;; This is the basic setup command. Must always be ;; called before connecting to a db using connect. ;; ;; find or become the captain ;; setup and return a ulex object ;; (define (find-or-setup-captain udata) ;; see if we already have a captain and if the lease is ok (if (and (udat-captain-address udata) (udat-captain-port udata) (< (current-seconds) (udat-captain-lease udata))) udata (let* ((cpkts (get-all-captain-pkts udata)) ;; read captain pkts (captn (get-winning-pkt cpkts))) (if captn (let* ((port (alist-ref 'port captn)) (host (alist-ref 'host captn)) (ipaddr (alist-ref 'ipaddr captn)) (pid (alist-ref 'pid captn)) (Z (alist-ref 'Z captn))) (udat-captain-address-set! udata ipaddr) (udat-captain-host-set! udata host) (udat-captain-port-set! udata port) (udat-captain-pid-set! udata pid) (udat-captain-lease-set! udata (+ (current-seconds) 10)) (let-values (((success pingtime)(ping udata (conc ipaddr ":" port)))) (if success udata (begin (print "Found unreachable captain at " ipaddr ":" port ", removing pkt") (remove-captain-pkt udata captn) (find-or-setup-captain udata)))) (begin (setup-as-captain udata) ;; this saves the thread to captain-thread and starts the thread (find-or-setup-captain udata))))))) ;; connect to a specific dbfile ;; - if already connected - return the dbowner host-port ;; - ask the captain who to talk to for this db ;; - put the entry in the dbowners hash as dbfile => host-port ;; (define (connect udata dbfname dbtype) (or (hash-table-ref/default (udat-dbowners udata) dbfname #f) (let-values (((success dbowner-host-port)(get-db-owner udata dbfname dbtype))) (if success (begin ;; just clobber the record, this is the new data no matter what (hash-table-set! (udat-dbowners udata) dbfname dbowner-host-port) dbowner-host-port) #f)))) ;; returns: success pingtime ;; ;; NOTE: causes the callee to store the info on this host along with the dbs this host currently owns ;; (define (ping udata host-port) (let* ((start (current-milliseconds)) (cookie (make-cookie udata)) (dbs (udat-my-dbs udata)) (msg (string-intersperse dbs " ")) (res (send udata host-port 'ping cookie msg retval: #t)) (delta (- (current-milliseconds) start))) (values (equal? res cookie) delta))) ;; returns: success pingtime ;; ;; NOTE: causes all references to this worker to be wiped out in the ;; callee (ususally the captain) ;; (define (goodbye-ping udata host-port) (let* ((start (current-milliseconds)) (cookie (make-cookie udata)) (dbs (udat-my-dbs udata)) (res (send udata host-port 'goodbye cookie "nomsg" retval: #t)) (delta (- (current-milliseconds) start))) (values (equal? res cookie) delta))) (define (goodbye-captain udata) (let* ((host-port (udat-captain-host-port udata))) (if host-port (goodbye-ping udata host-port) (values #f -1)))) (define (get-db-owner udata dbname dbtype) (let* ((host-port (udat-captain-host-port udata))) (if host-port (let* ((cookie (make-cookie udata)) (msg #f) ;; (conc dbname " " dbtype)) (params `(,dbname ,dbtype)) (res (send udata host-port 'db-owner cookie msg params: params retval: #t))) (match (string-split res) ((retcookie owner-host-port) (values (equal? retcookie cookie) owner-host-port)))) (values #f -1)))) ;; called in ulex-handler to dispatch work, called on the workers side ;; calls (proc params data) ;; returns result with cookie ;; ;; pdat is the info of the caller, used to send the result data ;; prockey is key into udat-handlers hash dereferencing a proc ;; procparam is a first param handed to proc - often to do further derefrencing ;; NOTE: params is intended to be a list of strings, encoding on data ;; is up to the user but data must be a single line ;; (define (process-request udata pdat dbname cookie prockey procparam data) (let* ((dbrec (ulex-open-db udata dbname)) ;; this will be a dbconn record, looks for in udata first (proc (hash-table-ref udata prockey))) (let* ((result (proc dbrec procparam data))) result))) ;; remote-request - send to remote to process in process-request ;; uconn comes from a call to connect and can be used instead of calling connect again ;; uconn is the host-port to call ;; we send dbname to the worker so they know which file to open ;; data must be a string with no newlines, it will be handed to the proc ;; at the remote site unchanged. It is up to the user to encode/decode it's contents ;; ;; rtype: immediate, read-only, normal, low-priority ;; (define (remote-request udata uconn rtype dbname prockey procparam data) (let* ((cookie (make-cookie udata))) (send-receive udata uconn rtype cookie data `(,prockey procparam)))) (define (ulex-open-db udata dbname) #f) ;;====================================================================== ;; Ulex db ;; ;; - track who is captain, lease expire time ;; - track who owns what db, lease ;; ;;====================================================================== ;; ;; (define (ulex-dbfname) (let ((dbdir (conc (get-environment-variable "HOME") "/.ulex"))) (if (not (file-exists? dbdir)) (create-directory dbdir #t)) (conc dbdir "/network.db"))) ;; always goes in ~/.ulex/network.db ;; role is captain, adjutant, node ;; (define (ulexdb-setup) (let* ((dbfname (ulex-dbfname)) (have-db (file-exists? dbfname)) (db (sqlite3:open-database dbfname))) (sqlite3:set-busy-handler! db (sqlite3:make-busy-timeout 136000)) (sqlite3:execute db "PRAGMA synchronous = 0;") (if (not have-db) (sqlite3:with-transaction db (lambda () (for-each (lambda (stmt) (if stmt (sqlite3:execute db stmt))) `("CREATE TABLE IF NOT EXISTS nodes (id INTEGER PRIMARY KEY, role TEXT NOT NULL, host TEXT NOT NULL, port TEXT NOT NULL, ipadr TEXT NOT NULL, pid INTEGER NOT NULL, zcard TEXT NOT NULL, regtime INTEGER DEFAULT (strftime('%s','now')), lease_thru INTEGER DEFAULT (strftime('%s','now')), last_update INTEGER DEFAULT (strftime('%s','now')));" "CREATE TRIGGER IF NOT EXISTS update_nodes_trigger AFTER UPDATE ON nodes FOR EACH ROW BEGIN UPDATE nodes SET last_update=(strftime('%s','now')) WHERE id=old.id; END;" "CREATE TABLE IF NOT EXISTS dbs (id INTEGER PRIMARY KEY, dbname TEXT NOT NULL, dbfile TEXT NOT NULL, dbtype TEXT NOT NULL, host_port TEXT NOT NULL, regtime INTEGER DEFAULT (strftime('%s','now')), lease_thru INTEGER DEFAULT (strftime('%s','now')), last_update INTEGER DEFAULT (strftime('%s','now')));" "CREATE TRIGGER IF NOT EXISTS update_dbs_trigger AFTER UPDATE ON dbs FOR EACH ROW BEGIN UPDATE dbs SET last_update=(strftime('%s','now')) WHERE id=old.id; END;"))))) db)) (define (get-host-port-lease db dbfname) (sqlite3:fold-row (lambda (rem host-port lease-thru) (list host-port lease-thru)) #f db "SELECT host_port,lease_thru FROM dbs WHERE dbfile = ?" dbfname)) (define (register-captain db host ipadr port pid zcard #!key (lease 20)) (let* ((dbfname (ulex-dbfname)) (host-port (conc host ":" port))) (sqlite3:with-transaction db (lambda () (match (get-host-port-lease db dbfname) ((host-port lease-thru) (if (> (current-seconds) lease-thru) (begin (sqlite3:execute db "UPDATE dbs SET host_port=?,lease_thru=? WHERE dbname=?" (conc host ":" port) (+ (current-seconds) lease) dbfname) #t) #f)) (#f (sqlite3:execute db "INSERT INTO dbs (dbname,dbfile,dbtype,host_port,lease_thru) VALUES (?,?,?,?,?)" "captain" dbfname "captain" host-port (+ (current-seconds) lease))) (else (print "ERROR: Unrecognised result from fold-row") (exit 1))))))) ;;====================================================================== ;; network utilities ;;====================================================================== (define (rate-ip ipaddr) (regex-case ipaddr ( "^127\\..*" _ 0 ) ( "^(10\\.0|192\\.168)\\..*" _ 1 ) ( else 2 ) )) ;; Change this to bias for addresses with a reasonable broadcast value? ;; (define (ip-pref-less? a b) (> (rate-ip a) (rate-ip b))) (define (get-my-best-address) (let ((all-my-addresses (get-all-ips)) ;;(all-my-addresses-old (vector->list (hostinfo-addresses (hostname->hostinfo (get-host-name))))) ) (cond ((null? all-my-addresses) (get-host-name)) ;; no interfaces? ((eq? (length all-my-addresses) 1) (car all-my-addresses)) ;; only one to choose from, just go with it (else (car (sort all-my-addresses ip-pref-less?))) ;; (else ;; (ip->string (car (filter (lambda (x) ;; take any but 127. ;; (not (eq? (u8vector-ref x 0) 127))) ;; all-my-addresses)))) ))) (define (get-all-ips-sorted) (sort (get-all-ips) ip-pref-less?)) (define (get-all-ips) (map ip->string (vector->list (hostinfo-addresses (host-information (current-hostname)))))) (define (udat-my-host-port udata) (if (and (udat-my-address udata)(udat-my-port udata)) (conc (udat-my-address udata) ":" (udat-my-port udata)) #f)) (define (udat-captain-host-port udata) (if (and (udat-captain-address udata)(udat-captain-port udata)) (conc (udat-captain-address udata) ":" (udat-captain-port udata)) #f)) (define (udat-get-peer udata host-port) (hash-table-ref/default (udat-peers udata) host-port #f)) ;; struct for keeping track of others we are talking to (defstruct peer (addr-port #f) (hostname #f) (pid #f) ;; (inp #f) ;; (oup #f) (dbs '()) ;; list of databases this peer is currently handling ) (defstruct work (peer-dat #f) (handlerkey #f) (qrykey #f) (data #f) (start (current-milliseconds))) #;(defstruct dbowner (pdat #f) (last-update (current-seconds))) ;;====================================================================== ;; Captain functions ;;====================================================================== ;; NB// This needs to be started in a thread ;; ;; setup to be a captain ;; - local server MUST be started already ;; - create pkt ;; - start server port handler ;; (define (setup-as-captain udata) (if (create-captain-pkt udata) (let* ((my-addr (udat-my-address udata)) (my-port (udat-my-port udata)) (th (make-thread (lambda () (ulex-handler-loop udata)) "Captain handler"))) (udat-handler-thread-set! udata th) (udat-captain-address-set! udata my-addr) (udat-captain-port-set! udata my-port) (thread-start! th)) (begin (print "ERROR: failed to create captain pkt") #f))) ;; given a pkts dir read ;; (define (get-all-captain-pkts udata) (let* ((pktsdir (let ((d (udat-cpkts-dir udata))) (if (file-exists? d) d (begin (create-directory d #t) d)))) (all-pkt-files (glob (conc pktsdir "/*.pkt"))) (pkt-spec (udat-cpkt-spec udata))) (map (lambda (pkt-file) (read-pkt->alist pkt-file pktspec: pkt-spec)) all-pkt-files))) ;; sort by D then Z, return one, choose the oldest then ;; differentiate if needed using the Z key ;;l (define (get-winning-pkt pkts) (if (null? pkts) #f (car (sort pkts (lambda (a b) (let ((ad (string->number (alist-ref 'D a))) (bd (string->number (alist-ref 'D b)))) (if (eq? a b) (let ((az (alist-ref 'Z a)) (bz (alist-ref 'Z b))) (string>=? az bz)) (> ad bd)))))))) ;; put the host, ip, port and pid into a pkt in ;; the captain pkts dir ;; - assumes user has already fired up a server ;; which will be in the udata struct ;; (define (create-captain-pkt udata) (if (not (udat-serv-listener udata)) (begin (print "ERROR: create-captain-pkt called with out a listener") #f) (let* ((pktdat `((port . ,(udat-my-port udata)) (host . ,(udat-my-hostname udata)) (ipaddr . ,(udat-my-address udata)) (pid . ,(udat-my-pid udata)))) (pktdir (udat-cpkts-dir udata)) (pktspec (udat-cpkt-spec udata)) ) (udat-my-cpkt-key-set! udata (write-alist->pkt pktdir pktdat pktspec: pktspec ptype: 'captain)) (udat-my-cpkt-key udata)))) ;; remove pkt associated with captn (the Z key .pkt) ;; (define (remove-captain-pkt udata captn) (let ((Z (alist-ref 'Z captn)) (cpktdir (udat-cpkts-dir udata))) (delete-file* (conc cpktdir "/" Z ".pkt")))) ;; call all known peers and tell them to delete their info on the captain ;; thus forcing them to re-read pkts and connect to a new captain ;; call this when the captain needs to exit and if an older captain is ;; detected. Due to delays in sending file meta data in NFS multiple ;; captains can be initiated in a "Storm of Captains", book soon to be ;; on Amazon ;; (define (drop-captain udata) (let* ((peers (hash-table-keys (udat-peers udata))) (cookie (make-cookie udata))) (for-each (lambda (host-port) (send udata host-port 'dropcaptain cookie "nomsg" retval: #t)) peers))) ;;====================================================================== ;; server primitives ;;====================================================================== (define (make-cookie udata) (let ((newcnum (+ (udat-cnum udata) 1))) (udat-cnum-set! udata newcnum) (conc (udat-my-address udata) ":" (udat-my-port udata) "-" (udat-my-pid udata) "-" newcnum))) ;; create a tcp listener and return a populated udat struct with ;; my port, address, hostname, pid etc. ;; return #f if fail to find a port to allocate. ;; ;; if udata-in is #f create the record ;; if there is already a serv-listener return the udata ;; (define (start-server-find-port udata-in #!optional (port 4242)) (let ((udata (or udata-in (make-udat)))) (if (udat-serv-listener udata) ;; TODO - add check that the listener is alive and ready? udata (handle-exceptions exn (if (< port 65535) (start-server-find-port udata (+ port 1)) #f) (connect-server udata port))))) (define (connect-server udata port) ;; (tcp-listener-socket LISTENER)(socket-name so) ;; sockaddr-address, sockaddr-port, sockaddr->string (let* ((tlsn (tcp-listen port 1000 #f)) ;; (tcp-listen TCPPORT [BACKLOG [HOST]]) (addr (get-my-best-address))) ;; (hostinfo-addresses (host-information (current-hostname))) (udat-my-address-set! udata addr) (udat-my-port-set! udata port) (udat-my-hostname-set! udata (get-host-name)) (udat-serv-listener-set! udata tlsn) udata)) (define (get-peer-dat udata host-port #!optional (hostname #f)(pid #f)) (let* ((pdat (or (udat-get-peer udata host-port) (handle-exceptions ;; ERROR - MAKE THIS EXCEPTION HANDLER MORE SPECIFIC exn #f (let ((npdat (make-peer addr-port: host-port))) (if hostname (peer-hostname-set! npdat hostname)) (if pid (peer-pid-set! npdat pid)) npdat))))) pdat)) ;; send structured data to recipient ;; ;; NOTE: qrykey is what was called the "cookie" previously ;; ;; retval tells send to expect and wait for return data (one line) and return it or time out ;; this is for ping where we don't want to necessarily have set up our own server yet. ;; (define (send udata host-port handler qrykey data #!key (hostname #f)(pid #f)(params '())(retval #f)) (let* ((my-host-port (udat-my-host-port udata)) (isme (equal? host-port my-host-port)) ;; am I calling ;; myself? (dat (list handler ;; " " my-host-port ;; " " (udat-my-pid udata) ;; " " qrykey params ;;(if (null? params) "" (conc " " ;;(string-intersperse params " "))) ))) ;; (print "send isme is " (if isme "true!" "false!") ", ;; my-host-port: " my-host-port ", host-port: " host-port) (if isme (ulex-handler udata dat data) (handle-exceptions ;; ERROR - MAKE THIS EXCEPTION HANDLER MORE ;; SPECIFIC exn #f (let-values (((inp oup)(tcp-connect host-port))) ;; ;; CONTROL LINE: ;; handlerkey host:port pid qrykey params ... ;; (let ((res (if (and inp oup) (let* () (if my-host-port (begin (write dat oup) (write data oup) ;; send as sexpr ;; (print "Sent dat: " dat " data: " data) (if retval (read inp) #t)) (begin (print "ERROR: send called but no receiver has been setup. Please call setup first!") #f)) ;; NOTE: DO NOT BE TEMPTED TO LOOK AT ANY DATA ON INP HERE! ;; (there is a listener for handling that) ) #f))) ;; #f means failed to connect and send (close-input-port inp) (close-output-port oup) res)))))) ;; send a request to the given host-port and register a mailbox in udata ;; wait for the mailbox data and return it ;; (define (send-receive udata host-port handler qrykey data #!key (hostname #f)(pid #f)(params '())(timeout 20)) (let ((mbox (make-mailbox)) (mbox-time (current-milliseconds)) (mboxes (udat-mboxes udata))) (hash-table-set! mboxes qrykey mbox) (if (send udata host-port handler qrykey data hostname: hostname pid: pid params: params) (let* ((mbox-timeout-secs timeout) (mbox-timeout-result 'MBOX_TIMEOUT) (res (mailbox-receive! mbox mbox-timeout-secs mbox-timeout-result)) (mbox-receive-time (current-milliseconds))) (hash-table-delete! mboxes qrykey) (if (eq? res 'MBOX_TIMEOUT) #f res)) #f))) ;; #f means failed to communicate ;; (define (ulex-handler udata controldat data) (print "controldat: " controldat " data: " data) (match controldat ;; (string-split controldat) ((handlerkey host-port pid qrykey params ...) ;; (print "handlerkey: " handlerkey " host-port: " host-port " pid: " pid " qrykey: " qrykey " params: " params) (case handlerkey ;; (string->symbol handlerkey) ((ack)(print "Got ack!")) ((ping) ;; special case - return result immediately on the same connection (let* ((proc (hash-table-ref/default (udat-handlers udata) 'ping #f)) (val (if proc (proc) "gotping")) (peer (make-peer addr-port: host-port pid: pid)) (dbshash (udat-dbowners udata))) (peer-dbs-set! peer params) ;; params for ping is list of dbs owned by pinger (for-each (lambda (dbfile) (hash-table-set! dbshash dbfile host-port)) ;; WRONG? params) ;; register each db in the dbshash (if (not (hash-table-exists? (udat-peers udata) host-port)) (hash-table-set! (udat-peers udata) host-port peer)) ;; save the details of this caller in peers qrykey)) ;; End of ping ((goodbye) ;; remove all traces of the caller in db ownership etc. (let* ((peer (hash-table-ref/default (udat-peers udata) host-port #f)) (dbs (if peer (peer-dbs peer) '())) (dbshash (udat-dbowners udata))) (for-each (lambda (dbfile)(hash-table-delete! dbshash dbfile)) dbs) (hash-table-delete! (udat-peers udata) host-port) qrykey)) ((dropcaptain) ;; remove all traces of the captain (udat-captain-address-set! udata #f) (udat-captain-host-set! udata #f) (udat-captain-port-set! udata #f) (udat-captain-pid-set! udata #f) qrykey) ((rucaptain) ;; remote is asking if I'm the captain (if (udat-my-cpkt-key udata) "yes" "no")) ((db-owner) ;; given a db name who do I send my queries to ;; look up the file in handlers, if have an entry ping them to be sure ;; they are still alive and then return that host:port. ;; if no handler found or if the ping fails pick from peers the oldest that ;; is managing the fewest dbs (match params ((dbfile dbtype) (let* ((owner-host-port (hash-table-ref/default (udat-dbowners udata) dbfile #f))) (if owner-host-port (conc qrykey " " owner-host-port) (let* ((pdat (or (hash-table-ref/default (udat-peers udata) host-port #f) ;; no owner - caller gets to own it! (make-peer addr-port: host-port pid: pid dbs: `(,dbfile))))) (hash-table-set! (udat-peers udata) host-port pdat) (hash-table-set! (udat-dbowners udata) dbfile host-port) (conc qrykey " " host-port))))) (else (conc qrykey " BADDATA")))) ;; for work items: ;; handler is one of; immediate, read-only, read-write, high-priority ((immediate read-only normal low-priority) ;; do this work immediately ;; host-port (caller), pid (caller), qrykey (cookie), params <= all from first line ;; data => a single line encoded however you want, or should I build json into it? (print "handlerkey=" handlerkey) (let* ((pdat (get-peer-dat udata host-port))) (match params ;; dbfile prockey procparam ((dbfile prockey procparam) (case handlerkey ((immediate read-only) (process-request udata pdat dbfile qrykey prockey procparam data)) ((normal low-priority) ;; split off later and add logic to support low priority (add-to-work-queue udata pdat dbfile qrykey prockey procparam data)) (else #f))) (else (print "INFO: params=" params " handlerkey=" handlerkey " controldat=" controldat) #f)))) (else ;; (add-to-work-queue udata (get-peer-dat udata host-port) handlerkey qrykey data) #f))) (else (print "BAD DATA? controldat=" controldat " data=" data) #f)));; handles the incoming messages and dispatches to queues ;; (define (ulex-handler-loop udata) (let* ((serv-listener (udat-serv-listener udata))) ;; data comes as two lines ;; handlerkey resp-addr:resp-port hostname pid qrykey [dbpath/dbfile.db] ;; data (let loop ((state 'start)) (let-values (((inp oup)(tcp-accept serv-listener))) (let* ((controldat (read inp)) (data (read inp)) (resp (ulex-handler udata controldat data))) (if resp (write resp oup)) (close-input-port inp) (close-output-port oup)) (loop state))))) ;; add a proc to the handler list, these are done symetrically (i.e. in all instances) ;; so that the proc can be dereferenced remotely ;; (define (register-handler udata key proc) (hash-table-set! (udat-handlers udata) key proc)) ;;====================================================================== ;; work queues ;;====================================================================== (define (add-to-work-queue udata peer-dat handlerkey qrykey data) (let ((wdat (make-work peer-dat: peer-dat handlerkey: handlerkey qrykey: qrykey data: data))) (if (udat-busy udata) (queue-add! (udat-work-queue udata) wdat) (process-work udata wdat)) ;; passing in wdat tells process-work to first process the passed in wdat )) (define (do-work udata wdat) #f) (define (process-work udata #!optional wdat) (if wdat (do-work udata wdat)) ;; process wdat (let ((wqueue (udat-work-queue udata))) (if (not (queue-empty? wqueue)) (let loop ((wd (queue-remove! wqueue))) (do-work udata wd) (if (not (queue-empty? wqueue)) (loop (queue-remove! wqueue))))))) ;;====================================================================== ;; Generic db handling ;; setup a inmem db instance ;; open connection to on-disk db ;; sync on-disk db to inmem ;; get lock in on-disk db for dbowner of this db ;; put sync-proc, init-proc, on-disk handle, inmem handle in dbconn stuct ;; return the stuct ;;====================================================================== (defstruct dbconn (fname #f) (inmem #f) (conn #f) (sync #f) ;; sync proc (init #f) ;; init proc (lastsync (current-seconds)) ) (defstruct dbinfo (initproc #f) (syncproc #f)) ;; open inmem and disk database ;; init with initproc ;; return db struct ;; ;; appname; megatest, ulex or something else. ;; (define (setup-db-connection udata fname-in appname dbtype) (let* ((is-ulex (eq? appname 'ulex)) (dbinf (if is-ulex ;; ulex is a built-in special case (make-dbinfo initproc: ulexdb-init syncproc: ulexdb-sync) (hash-table-ref/default (udat-dbtypes udata) dbtype #f))) (initproc (dbinfo-initproc dbinf)) (syncproc (dbinfo-syncproc dbinf)) (fname (if is-ulex (conc (udat-ulex-dir udata) "/ulex.db") fname-in)) (inmem-db (open-and-initdb udata #f 'inmem (dbinfo-initproc dbinf))) (disk-db (open-and-initdb udata fname 'disk (dbinfo-initproc dbinf)))) (make-dbconn inmem: inmem-db conn: disk-db sync: syncproc init: initproc))) ;; dest='inmem or 'disk ;; (define (open-and-initdb udata filename dest init-proc) (let* ((inmem (eq? dest 'inmem)) (dbfile (if inmem ":INMEM:" filename)) (dbexists (if inmem #t (file-exists? dbfile))) (db (sqlite3:open-database dbfile))) (sqlite3:set-busy-handler! db (sqlite3:make-busy-timeout 136000)) (if (not dbexists) (init-proc db)) db)) ;;====================================================================== ;; Previous Ulex db stuff ;;====================================================================== (define (ulexdb-init db inmem) (sqlite3:with-transaction db (lambda () (for-each (lambda (stmt) (if stmt (sqlite3:execute db stmt))) `("CREATE TABLE IF NOT EXISTS processes (id INTEGER PRIMARY KEY, host TEXT NOT NULL, ipadr TEXT NOT NULL, port INTEGER NOT NULL, pid INTEGER NOT NULL, regtime INTEGER DEFAULT (strftime('%s','now')), last_update INTEGER DEFAULT (strftime('%s','now')));" (if inmem "CREATE TRIGGER IF NOT EXISTS update_proces_trigger AFTER UPDATE ON processes FOR EACH ROW BEGIN UPDATE processes SET last_update=(strftime('%s','now')) WHERE id=old.id; END;" #f)))))) ;; open databases, do initial sync (define (ulexdb-sync dbconndat udata) #f) ) ;; END OF ULEX ;;; ;;====================================================================== ;;; ;; D E B U G H E L P E R S ;;; ;;====================================================================== ;;; ;;; (define (dbg> . args) ;;; (with-output-to-port (current-error-port) ;;; (lambda () ;;; (apply print "dbg> " args)))) ;;; ;;; (define (debug-pp . args) ;;; (if (get-environment-variable "ULEX_DEBUG") ;;; (with-output-to-port (current-error-port) ;;; (lambda () ;;; (apply pp args))))) ;;; ;;; (define *default-debug-port* (current-error-port)) ;;; ;;; (define (sdbg> fn stage-name stage-start stage-end start-time . message) ;;; (if (get-environment-variable "ULEX_DEBUG") ;;; (with-output-to-port *default-debug-port* ;;; (lambda () ;;; (apply print "ulex:" fn " " stage-name " took " (- (if stage-end stage-end (current-milliseconds)) stage-start) " ms. " ;;; (if start-time ;;; (conc "total time " (- (current-milliseconds) start-time) ;;; " ms.") ;;; "") ;;; message ;;; ))))) ;;====================================================================== ;; M A C R O S ;;====================================================================== ;; iup callbacks are not dumping the stack, this is a work-around ;; ;; Some of these routines use: ;; ;; http://www.cs.toronto.edu/~gfb/scheme/simple-macros.html ;; ;; Syntax for defining macros in a simple style similar to function definiton, ;; when there is a single pattern for the argument list and there are no keywords. ;; ;; (define-simple-syntax (name arg ...) body ...) ;; ;; ;; (define-syntax define-simple-syntax ;; (syntax-rules () ;; ((_ (name arg ...) body ...) ;; (define-syntax name (syntax-rules () ((name arg ...) (begin body ...))))))) ;; ;; (define-simple-syntax (catch-and-dump proc procname) ;; (handle-exceptions ;; exn ;; (begin ;; (print-call-chain (current-error-port)) ;; (with-output-to-port (current-error-port) ;; (lambda () ;; (print ((condition-property-accessor 'exn 'message) exn)) ;; (print "Callback error in " procname) ;; (print "Full condition info:\n" (condition->list exn))))) ;; (proc))) ;; ;; ;;====================================================================== ;; R E C O R D S ;;====================================================================== ;;; ;; information about me as a server ;;; ;; ;;; (defstruct area ;;; ;; about this area ;;; (useportlogger #f) ;;; (lowport 32768) ;;; (server-type 'auto) ;; auto=create up to five servers/pkts, main=create pkts, passive=no pkt (unless there are no pkts at all) ;;; (conn #f) ;;; (port #f) ;;; (myaddr (get-my-best-address)) ;;; pktid ;; get pkt from hosts table if needed ;;; pktfile ;;; pktsdir ;;; dbdir ;;; (dbhandles (make-hash-table)) ;; fname => list-of-dbh, NOTE: Should really never need more than one? ;;; (mutex (make-mutex)) ;;; (rtable (make-hash-table)) ;; registration table of available actions ;;; (dbs (make-hash-table)) ;; filename => random number, used for choosing what dbs I serve ;;; ;; about other servers ;;; (hosts (make-hash-table)) ;; key => hostdat ;;; (hoststats (make-hash-table)) ;; key => alist of fname => ( qcount . qtime ) ;;; (reqs (make-hash-table)) ;; uri => queue ;;; ;; work queues ;;; (wqueues (make-hash-table)) ;; fname => qdat ;;; (stats (make-hash-table)) ;; fname => totalqueries ;;; (last-srvup (current-seconds)) ;; last time we updated the known servers ;;; (cookie2mbox (make-hash-table)) ;; map cookie for outstanding request to mailbox of awaiting call ;;; (ready #f) ;;; (health (make-hash-table)) ;; ipaddr:port => num failed pings since last good ping ;;; ) ;;; ;;; ;; host stats ;;; ;; ;;; (defstruct hostdat ;;; (pkt #f) ;;; (dbload (make-hash-table)) ;; "dbfile.db" => queries/min ;;; (hostload #f) ;; normalized load ( 5min load / numcpus ) ;;; ) ;;; ;;; ;; dbdat ;;; ;; ;;; (defstruct dbdat ;;; (dbh #f) ;;; (fname #f) ;;; (write-access #f) ;;; (sths (make-hash-table)) ;; hash mapping query strings to handles ;;; ) ;;; ;;; ;; qdat ;;; ;; ;;; (defstruct qdat ;;; (writeq (make-queue)) ;;; (readq (make-queue)) ;;; (rwq (make-queue)) ;;; (logq (make-queue)) ;; do we need a queue for logging? yes, if we use sqlite3 db for logging ;;; (osshort (make-queue)) ;;; (oslong (make-queue)) ;;; (misc (make-queue)) ;; used for things like ping-full ;;; ) ;;; ;;; ;; calldat ;;; ;; ;;; (defstruct calldat ;;; (ctype 'dbwrite) ;;; (obj #f) ;; this would normally be an SQL statement e.g. SELECT, INSERT etc. ;;; (rtime (current-milliseconds))) ;;; ;;; ;; make it a global? Well, it is local to area module ;;; ;;; (define *pktspec* ;;; `((server (hostname . h) ;;; (port . p) ;;; (pid . i) ;;; (ipaddr . a) ;;; ) ;;; (data (hostname . h) ;; sender hostname ;;; (port . p) ;; sender port ;;; (ipaddr . a) ;; sender ip ;;; (hostkey . k) ;; sending host key - store info at server under this key ;;; (servkey . s) ;; server key - this needs to match at server end or reject the msg ;;; (format . f) ;; sb=serialized-base64, t=text, sx=sexpr, j=json ;;; (data . d) ;; base64 encoded slln data ;;; ))) ;;; ;;; ;; work item ;;; ;; ;;; (defstruct witem ;;; (rhost #f) ;; return host ;;; (ripaddr #f) ;; return ipaddr ;;; (rport #f) ;; return port ;;; (servkey #f) ;; the packet representing the client of this workitem, used by final send-message ;;; (rdat #f) ;; the request - usually an sql query, type is rdat ;;; (action #f) ;; the action: immediate, dbwrite, dbread,oslong, osshort ;;; (cookie #f) ;; cookie id for response ;;; (data #f) ;; the data payload, i.e. parameters ;;; (result #f) ;; the result from processing the data ;;; (caller #f)) ;; the calling peer according to rpc itself ;;; ;;; (define (trim-pktid pktid) ;;; (if (string? pktid) ;;; (substring pktid 0 4) ;;; "nopkt")) ;;; ;;; (define (any->number num) ;;; (cond ;;; ((number? num) num) ;;; ((string? num) (string->number num)) ;;; (else num))) ;;; ;;; (use trace) ;;; (trace-call-sites #t) ;;; ;;; ;;====================================================================== ;;; ;; D A T A B A S E H A N D L I N G ;;; ;;====================================================================== ;;; ;;; ;; look in dbhandles for a db, return it, else return #f ;;; ;; ;;; (define (get-dbh acfg fname) ;;; (let ((dbh-lst (hash-table-ref/default (area-dbhandles acfg) fname '()))) ;;; (if (null? dbh-lst) ;;; (begin ;;; ;; (print "opening db for " fname) ;;; (open-db acfg fname)) ;; Note that the handles get put back in the queue in the save-dbh calls ;;; (let ((rem-lst (cdr dbh-lst))) ;;; ;; (print "re-using saved connection for " fname) ;;; (hash-table-set! (area-dbhandles acfg) fname rem-lst) ;;; (car dbh-lst))))) ;;; ;;; (define (save-dbh acfg fname dbdat) ;;; ;; (print "saving dbh for " fname) ;;; (hash-table-set! (area-dbhandles acfg) fname (cons dbdat (hash-table-ref/default (area-dbhandles acfg) fname '())))) ;;; ;;; ;; open the database, if never before opened init it. put the handle in the ;;; ;; open db's hash table ;;; ;; returns: the dbdat ;;; ;; ;;; (define (open-db acfg fname) ;;; (let* ((fullname (conc (area-dbdir acfg) "/" fname)) ;;; (exists (file-exists? fullname)) ;;; (write-access (if exists ;;; (file-write-access? fullname) ;;; (file-write-access? (area-dbdir acfg)))) ;;; (db (sqlite3:open-database fullname)) ;;; (handler (sqlite3:make-busy-timeout 136000)) ;;; ) ;;; (sqlite3:set-busy-handler! db handler) ;;; (sqlite3:execute db "PRAGMA synchronous = 0;") ;;; (if (not exists) ;; need to init the db ;;; (if write-access ;;; (let ((isql (get-rsql acfg 'dbinitsql))) ;; get the init sql statements ;;; ;; (sqlite3:with-transaction ;;; ;; db ;;; ;; (lambda () ;;; (if isql ;;; (for-each ;;; (lambda (sql) ;;; (sqlite3:execute db sql)) ;;; isql))) ;;; (print "ERROR: no write access to " (area-dbdir acfg)))) ;;; (make-dbdat dbh: db fname: fname write-access: write-access))) ;;; ;;; ;; This is a low-level command to retrieve or to prepare, save and return a prepared statment ;;; ;; you must extract the db handle ;;; ;; ;;; (define (get-sth db cache stmt) ;;; (if (hash-table-exists? cache stmt) ;;; (begin ;;; ;; (print "Reusing cached stmt for " stmt) ;;; (hash-table-ref/default cache stmt #f)) ;;; (let ((sth (sqlite3:prepare db stmt))) ;;; (hash-table-set! cache stmt sth) ;;; ;; (print "prepared stmt for " stmt) ;;; sth))) ;;; ;;; ;; a little more expensive but does all the tedious deferencing - only use if you don't already ;;; ;; have dbdat and db sitting around ;;; ;; ;;; (define (full-get-sth acfg fname stmt) ;;; (let* ((dbdat (get-dbh acfg fname)) ;;; (db (dbdat-dbh dbdat)) ;;; (sths (dbdat-sths dbdat))) ;;; (get-sth db sths stmt))) ;;; ;;; ;; write to a db ;;; ;; acfg: area data ;;; ;; rdat: request data ;;; ;; hdat: (host . port) ;;; ;; ;;; ;; (define (dbwrite acfg rdat hdat data-in) ;;; ;; (let* ((dbname (car data-in)) ;;; ;; (dbdat (get-dbh acfg dbname)) ;;; ;; (db (dbdat-dbh dbdat)) ;;; ;; (sths (dbdat-sths dbdat)) ;;; ;; (stmt (calldat-obj rdat)) ;;; ;; (sth (get-sth db sths stmt)) ;;; ;; (data (cdr data-in))) ;;; ;; (print "dbname: " dbname " acfg: " acfg " rdat: " (calldat->alist rdat) " hdat: " hdat " data: " data) ;;; ;; (print "dbdat: " (dbdat->alist dbdat)) ;;; ;; (apply sqlite3:execute sth data) ;;; ;; (save-dbh acfg dbname dbdat) ;;; ;; #t ;;; ;; )) ;;; ;;; (define (finalize-all-db-handles acfg) ;;; (let* ((dbhandles (area-dbhandles acfg)) ;; dbhandles is hash of fname ==> dbdat ;;; (num 0)) ;;; (for-each ;;; (lambda (area-name) ;;; (print "Closing handles for " area-name) ;;; (let ((dbdats (hash-table-ref/default dbhandles area-name '()))) ;;; (for-each ;;; (lambda (dbdat) ;;; ;; first close all statement handles ;;; (for-each ;;; (lambda (sth) ;;; (sqlite3:finalize! sth) ;;; (set! num (+ num 1))) ;;; (hash-table-values (dbdat-sths dbdat))) ;;; ;; now close the dbh ;;; (set! num (+ num 1)) ;;; (sqlite3:finalize! (dbdat-dbh dbdat))) ;;; dbdats))) ;;; (hash-table-keys dbhandles)) ;;; (print "FINALIZED " num " dbhandles"))) ;;; ;;; ;;====================================================================== ;;; ;; W O R K Q U E U E H A N D L I N G ;;; ;;====================================================================== ;;; ;;; (define (register-db-as-mine acfg dbname) ;;; (let ((ht (area-dbs acfg))) ;;; (if (not (hash-table-ref/default ht dbname #f)) ;;; (hash-table-set! ht dbname (random 10000))))) ;;; ;;; (define (work-queue-add acfg fname witem) ;;; (let* ((work-queue-start (current-milliseconds)) ;;; (action (witem-action witem)) ;; NB the action is the index into the rdat actions ;;; (qdat (or (hash-table-ref/default (area-wqueues acfg) fname #f) ;;; (let ((newqdat (make-qdat))) ;;; (hash-table-set! (area-wqueues acfg) fname newqdat) ;;; newqdat))) ;;; (rdat (hash-table-ref/default (area-rtable acfg) action #f))) ;;; (if rdat ;;; (queue-add! ;;; (case (calldat-ctype rdat) ;;; ((dbwrite) (register-db-as-mine acfg fname)(qdat-writeq qdat)) ;;; ((dbread) (register-db-as-mine acfg fname)(qdat-readq qdat)) ;;; ((dbrw) (register-db-as-mine acfg fname)(qdat-rwq qdat)) ;;; ((oslong) (qdat-oslong qdat)) ;;; ((osshort) (qdat-osshort qdat)) ;;; ((full-ping) (qdat-misc qdat)) ;;; (else ;;; (print "ERROR: no queue for " action ". Adding to dbwrite queue.") ;;; (qdat-writeq qdat))) ;;; witem) ;;; (case action ;;; ((full-ping)(qdat-misc qdat)) ;;; (else ;;; (print "ERROR: No action " action " was registered")))) ;;; (sdbg> "work-queue-add" "queue-add" work-queue-start #f #f) ;;; #t)) ;; for now, simply return #t to indicate request got to the queue ;;; ;;; (define (doqueue acfg q fname dbdat dbh) ;;; ;; (print "doqueue: " fname) ;;; (let* ((start-time (current-milliseconds)) ;;; (qlen (queue-length q))) ;;; (if (> qlen 1) ;;; (print "Processing queue of length " qlen)) ;;; (let loop ((count 0) ;;; (responses '())) ;;; (let ((delta (- (current-milliseconds) start-time))) ;;; (if (or (queue-empty? q) ;;; (> delta 400)) ;; stop working on this queue after 400ms have passed ;;; (list count delta responses) ;; return count, delta and responses list ;;; (let* ((witem (queue-remove! q)) ;;; (action (witem-action witem)) ;;; (rdat (witem-rdat witem)) ;;; (stmt (calldat-obj rdat)) ;;; (sth (full-get-sth acfg fname stmt)) ;;; (ctype (calldat-ctype rdat)) ;;; (data (witem-data witem)) ;;; (cookie (witem-cookie witem))) ;;; ;; do the processing and save the result in witem-result ;;; (witem-result-set! ;;; witem ;;; (case ctype ;; action ;;; ((noblockwrite) ;; blind write, no ack of success returned ;;; (apply sqlite3:execute sth data) ;;; (sqlite3:last-insert-rowid dbh)) ;;; ((dbwrite) ;; blocking write ;;; (apply sqlite3:execute sth data) ;;; #t) ;;; ((dbread) ;; TODO: consider breaking this up and shipping in pieces for large query ;;; (apply sqlite3:map-row (lambda x x) sth data)) ;;; ((full-ping) 'full-ping) ;;; (else (print "Not ready for action " action) #f))) ;;; (loop (add1 count) ;;; (if cookie ;;; (cons witem responses) ;;; responses)))))))) ;;; ;;; ;; do up to 400ms of processing on each queue ;;; ;; - the work-queue-processor will allow the max 1200ms of work to complete but it will flag as overloaded ;;; ;; ;;; (define (process-db-queries acfg fname) ;;; (if (hash-table-exists? (area-wqueues acfg) fname) ;;; (let* ((process-db-queries-start-time (current-milliseconds)) ;;; (qdat (hash-table-ref/default (area-wqueues acfg) fname #f)) ;;; (queue-sym->queue (lambda (queue-sym) ;;; (case queue-sym ;; lookup the queue from qdat given a name (symbol) ;;; ((wqueue) (qdat-writeq qdat)) ;;; ((rqueue) (qdat-readq qdat)) ;;; ((rwqueue) (qdat-rwq qdat)) ;;; ((misc) (qdat-misc qdat)) ;;; (else #f)))) ;;; (dbdat (get-dbh acfg fname)) ;;; (dbh (if (dbdat? dbdat)(dbdat-dbh dbdat) #f)) ;;; (nowtime (current-seconds))) ;;; ;; handle the queues that require a transaction ;;; ;; ;;; (map ;; ;;; (lambda (queue-sym) ;;; ;; (print "processing queue " queue-sym) ;;; (let* ((queue (queue-sym->queue queue-sym))) ;;; (if (not (queue-empty? queue)) ;;; (let ((responses ;;; (sqlite3:with-transaction ;; todo - catch exceptions... ;;; dbh ;;; (lambda () ;;; (let* ((res (doqueue acfg queue fname dbdat dbh))) ;; this does the work! ;;; ;; (print "res=" res) ;;; (match res ;;; ((count delta responses) ;;; (update-stats acfg fname queue-sym delta count) ;;; (sdbg> "process-db-queries" "sqlite3-transaction" process-db-queries-start-time #f #f) ;;; responses) ;; return responses ;;; (else ;;; (print "ERROR: bad return data from doqueue " res))) ;;; ))))) ;;; ;; having completed the transaction, send the responses. ;;; ;; (print "INFO: sending " (length responses) " responses.") ;;; (let loop ((responses-left responses)) ;;; (cond ;;; ((null? responses-left) #t) ;;; (else ;;; (let* ((witem (car responses-left)) ;;; (response (cdr responses-left))) ;;; (call-deliver-response acfg (witem-ripaddr witem)(witem-rport witem) ;;; (witem-cookie witem)(witem-result witem))) ;;; (loop (cdr responses-left)))))) ;;; ))) ;;; '(wqueue rwqueue rqueue)) ;;; ;;; ;; handle misc queue ;;; ;; ;;; ;; (print "processing misc queue") ;;; (let ((queue (queue-sym->queue 'misc))) ;;; (doqueue acfg queue fname dbdat dbh)) ;;; ;; .... ;;; (save-dbh acfg fname dbdat) ;;; #t ;; just to let the tests know we got here ;;; ) ;;; #f ;; nothing processed ;;; )) ;;; ;;; ;; run all queues in parallel per db but sequentially per queue for that db. ;;; ;; - process the queues every 500 or so ms ;;; ;; - allow for long running queries to continue but all other activities for that ;;; ;; db will be blocked. ;;; ;; ;;; (define (work-queue-processor acfg) ;;; (let* ((threads (make-hash-table))) ;; fname => thread ;;; (let loop ((fnames (hash-table-keys (area-wqueues acfg))) ;;; (target-time (+ (current-milliseconds) 50))) ;;; ;;(if (not (null? fnames))(print "Processing for these databases: " fnames)) ;;; (for-each ;;; (lambda (fname) ;;; ;; (print "processing for " fname) ;;; ;;(process-db-queries acfg fname)) ;;; (let ((th (hash-table-ref/default threads fname #f))) ;;; (if (and th (not (member (thread-state th) '(dead terminated)))) ;;; (begin ;;; (print "WARNING: worker thread for " fname " is taking a long time.") ;;; (print "Thread is in state " (thread-state th))) ;;; (let ((th1 (make-thread (lambda () ;;; ;; (catch-and-dump ;;; ;; (lambda () ;;; ;; (print "Process queries for " fname) ;;; (let ((start-time (current-milliseconds))) ;;; (process-db-queries acfg fname) ;;; ;; (thread-sleep! 0.01) ;; need the thread to take at least some time ;;; (hash-table-delete! threads fname)) ;; no mutexes? ;;; fname) ;;; "th1"))) ;; )) ;;; (hash-table-set! threads fname th1) ;;; (thread-start! th1))))) ;;; fnames) ;;; ;; (thread-sleep! 0.1) ;; give the threads some time to process requests ;;; ;; burn time until 400ms is up ;;; (let ((now-time (current-milliseconds))) ;;; (if (< now-time target-time) ;;; (let ((delta (- target-time now-time))) ;;; (thread-sleep! (/ delta 1000))))) ;;; (loop (hash-table-keys (area-wqueues acfg)) ;;; (+ (current-milliseconds) 50))))) ;;; ;;; ;;====================================================================== ;;; ;; S T A T S G A T H E R I N G ;;; ;;====================================================================== ;;; ;;; (defstruct stat ;;; (qcount-avg 0) ;; coarse running average ;;; (qtime-avg 0) ;; coarse running average ;;; (qcount 0) ;; total ;;; (qtime 0) ;; total ;;; (last-qcount 0) ;; last ;;; (last-qtime 0) ;; last ;;; (dbs '()) ;; list of db files handled by this node ;;; (when 0)) ;; when the last query happened - seconds ;;; ;;; ;;; (define (update-stats acfg fname bucket duration numqueries) ;;; (let* ((key fname) ;; for now do not use bucket. Was: (conc fname "-" bucket)) ;; lazy but good enough ;;; (stats (or (hash-table-ref/default (area-stats acfg) key #f) ;;; (let ((newstats (make-stat))) ;;; (hash-table-set! (area-stats acfg) key newstats) ;;; newstats)))) ;;; ;; when the last query happended (used to remove the fname from the active list) ;;; (stat-when-set! stats (current-seconds)) ;;; ;; last values ;;; (stat-last-qcount-set! stats numqueries) ;;; (stat-last-qtime-set! stats duration) ;;; ;; total over process lifetime ;;; (stat-qcount-set! stats (+ (stat-qcount stats) numqueries)) ;;; (stat-qtime-set! stats (+ (stat-qtime stats) duration)) ;;; ;; coarse average ;;; (stat-qcount-avg-set! stats (/ (+ (stat-qcount-avg stats) numqueries) 2)) ;;; (stat-qtime-avg-set! stats (/ (+ (stat-qtime-avg stats) duration) 2)) ;;; ;;; ;; here is where we add the stats for a given dbfile ;;; (if (not (member fname (stat-dbs stats))) ;;; (stat-dbs-set! stats (cons fname (stat-dbs stats)))) ;;; ;;; )) ;;; ;;; ;;====================================================================== ;;; ;; S E R V E R S T U F F ;;; ;;====================================================================== ;;; ;;; ;; this does NOT return! ;;; ;; ;;; (define (find-free-port-and-open acfg) ;;; (let ((port (or (area-port acfg) 3200))) ;;; (handle-exceptions ;;; exn ;;; (begin ;;; (print "INFO: cannot bind to port " (rpc:default-server-port) ", trying next port") ;;; (area-port-set! acfg (+ port 1)) ;;; (find-free-port-and-open acfg)) ;;; (rpc:default-server-port port) ;;; (area-port-set! acfg port) ;;; (tcp-read-timeout 120000) ;;; ;; ((rpc:make-server (tcp-listen port)) #t) ;;; (tcp-listen (rpc:default-server-port) ;;; )))) ;;; ;;; ;; register this node by putting a packet into the pkts dir. ;;; ;; look for other servers ;;; ;; contact other servers and compile list of servers ;;; ;; there are two types of server ;;; ;; main servers - dashboards, runners and dedicated servers - need pkt ;;; ;; passive servers - test executers, step calls, list-runs - no pkt ;;; ;; ;;; (define (register-node acfg hostip port-num) ;;; ;;(mutex-lock! (area-mutex acfg)) ;;; (let* ((server-type (area-server-type acfg)) ;; auto, main, passive (no pkt created) ;;; (best-ip (or hostip (get-my-best-address))) ;;; (mtdir (area-dbdir acfg)) ;;; (pktdir (area-pktsdir acfg))) ;; conc mtdir "/.server-pkts"))) ;;; (print "Registering node " best-ip ":" port-num) ;;; (if (not mtdir) ;; require a home for this node to put or find databases ;;; #f ;;; (begin ;;; (if (not (directory? pktdir))(create-directory pktdir)) ;;; ;; server is started, now create pkt if needed ;;; (print "Starting server in " server-type " mode with port " port-num) ;;; (if (member server-type '(auto main)) ;; TODO: if auto, count number of servers registers, if > 3 then don't put out a pkt ;;; (begin ;;; (area-pktid-set! acfg ;;; (write-alist->pkt ;;; pktdir ;;; `((hostname . ,(get-host-name)) ;;; (ipaddr . ,best-ip) ;;; (port . ,port-num) ;;; (pid . ,(current-process-id))) ;;; pktspec: *pktspec* ;;; ptype: 'server)) ;;; (area-pktfile-set! acfg (conc pktdir "/" (area-pktid acfg) ".pkt")))) ;;; (area-port-set! acfg port-num) ;;; #;(mutex-unlock! (area-mutex acfg)))))) ;;; ;;; (define *cookie-seqnum* 0) ;;; (define (make-cookie key) ;;; (set! *cookie-seqnum* (add1 *cookie-seqnum*)) ;;; ;;(print "MAKE COOKIE CALLED -- on "servkey"-"*cookie-seqnum*) ;;; (conc key "-" *cookie-seqnum*) ;;; ) ;;; ;;; ;; dispatch locally if possible ;;; ;; ;;; (define (call-deliver-response acfg ipaddr port cookie data) ;;; (if (and (equal? (area-myaddr acfg) ipaddr) ;;; (equal? (area-port acfg) port)) ;;; (deliver-response acfg cookie data) ;;; ((rpc:procedure 'response ipaddr port) cookie data))) ;;; ;;; (define (deliver-response acfg cookie data) ;;; (let ((deliver-response-start (current-milliseconds))) ;;; (thread-start! (make-thread ;;; (lambda () ;;; (let loop ((tries-left 5)) ;;; ;;(print "TOP OF DELIVER_RESPONSE LOOP; triesleft="tries-left) ;;; ;;(pp (hash-table->alist (area-cookie2mbox acfg))) ;;; (let* ((mbox (hash-table-ref/default (area-cookie2mbox acfg) cookie #f))) ;;; (cond ;;; ((eq? 0 tries-left) ;;; (print "ulex:deliver-response: I give up. Mailbox never appeared. cookie="cookie) ;;; ) ;;; (mbox ;;; ;;(print "got mbox="mbox" got data="data" send.") ;;; (mailbox-send! mbox data)) ;;; (else ;;; ;;(print "no mbox yet. look for "cookie) ;;; (thread-sleep! (/ (- 6 tries-left) 10)) ;;; (loop (sub1 tries-left)))))) ;;; ;; (debug-pp (list (conc "ulex:deliver-response took " (- (current-milliseconds) deliver-response-start) " ms, cookie=" cookie " data=") data)) ;;; (sdbg> "deliver-response" "mailbox-send" deliver-response-start #f #f cookie) ;;; ) ;;; (conc "deliver-response thread for cookie="cookie)))) ;;; #t) ;;; ;;; ;; action: ;;; ;; immediate - quick actions, no need to put in queues ;;; ;; dbwrite - put in dbwrite queue ;;; ;; dbread - put in dbread queue ;;; ;; oslong - os actions, e.g. du, that could take a long time ;;; ;; osshort - os actions that should be quick, e.g. df ;;; ;; ;;; (define (request acfg from-ipaddr from-port servkey action cookie fname params) ;; std-peer-handler ;;; ;; NOTE: Use rpc:current-peer for getting return address ;;; (let* ((std-peer-handler-start (current-milliseconds)) ;;; ;; (raw-data (alist-ref 'data dat)) ;;; (rdat (hash-table-ref/default ;;; (area-rtable acfg) action #f)) ;; this looks up the sql query or other details indexed by the action ;;; (witem (make-witem ripaddr: from-ipaddr ;; rhost: from-host ;;; rport: from-port action: action ;;; rdat: rdat cookie: cookie ;;; servkey: servkey data: params ;; TODO - rename data to params ;;; caller: (rpc:current-peer)))) ;;; (if (not (equal? servkey (area-pktid acfg))) ;;; `(#f . ,(conc "I don't know you servkey=" servkey ", pktid=" (area-pktid acfg))) ;; immediately return this ;;; (let* ((ctype (if rdat ;;; (calldat-ctype rdat) ;; is this necessary? these should be identical ;;; action))) ;;; (sdbg> "std-peer-handler" "immediate" std-peer-handler-start #f #f) ;;; (case ctype ;;; ;; (dbwrite acfg rdat (cons from-ipaddr from-port) data))) ;;; ((full-ping) `(#t "ack to full ping" ,(work-queue-add acfg fname witem) ,cookie)) ;;; ((response) `(#t "ack from requestor" ,(deliver-response acfg fname params))) ;;; ((dbwrite) `(#t "db write submitted" ,(work-queue-add acfg fname witem) ,cookie)) ;;; ((dbread) `(#t "db read submitted" ,(work-queue-add acfg fname witem) ,cookie )) ;;; ((dbrw) `(#t "db read/write submitted" ,cookie)) ;;; ((osshort) `(#t "os short submitted" ,cookie)) ;;; ((oslong) `(#t "os long submitted" ,cookie)) ;;; (else `(#f "unrecognised action" ,ctype))))))) ;;; ;;; ;; Call this to start the actual server ;;; ;; ;;; ;; start_server ;;; ;; ;;; ;; mode: ' ;;; ;; handler: proc which takes pktrecieved as argument ;;; ;; ;;; ;;; (define (start-server acfg) ;;; (let* ((conn (find-free-port-and-open acfg)) ;;; (port (area-port acfg))) ;;; (rpc:publish-procedure! ;;; 'delist-db ;;; (lambda (fname) ;;; (hash-table-delete! (area-dbs acfg) fname))) ;;; (rpc:publish-procedure! ;;; 'calling-addr ;;; (lambda () ;;; (rpc:current-peer))) ;;; (rpc:publish-procedure! ;;; 'ping ;;; (lambda ()(real-ping acfg))) ;;; (rpc:publish-procedure! ;;; 'request ;;; (lambda (from-addr from-port servkey action cookie dbname params) ;;; (request acfg from-addr from-port servkey action cookie dbname params))) ;;; (rpc:publish-procedure! ;;; 'response ;;; (lambda (cookie res-dat) ;;; (deliver-response acfg cookie res-dat))) ;;; (area-ready-set! acfg #t) ;;; (area-conn-set! acfg conn) ;;; ((rpc:make-server conn) #f)));; ((tcp-listen (rpc:default-server-port)) #t) ;;; ;;; ;;; (define (launch acfg) ;; #!optional (proc std-peer-handler)) ;;; (print "starting launch") ;;; (update-known-servers acfg) ;; gotta do this on every start (thus why limit number of publicised servers) ;;; #;(let ((original-handler (current-exception-handler))) ;; is th ;;; (lambda (exception) ;;; (server-exit-procedure) ;;; (original-handler exception))) ;;; (on-exit (lambda () ;;; (shutdown acfg))) ;; (finalize-all-db-handles acfg))) ;;; ;; set up the rpc handler ;;; (let* ((th1 (make-thread ;;; (lambda ()(start-server acfg)) ;;; "server thread")) ;;; (th2 (make-thread ;;; (lambda () ;;; (print "th2 starting") ;;; (let loop () ;;; (work-queue-processor acfg) ;;; (print "work-queue-processor crashed!") ;;; (loop))) ;;; "work queue thread"))) ;;; (thread-start! th1) ;;; (thread-start! th2) ;;; (let loop () ;;; (thread-sleep! 0.025) ;;; (if (area-ready acfg) ;;; #t ;;; (loop))) ;;; ;; attempt to fix my address ;;; (let* ((all-addr (get-all-ips-sorted))) ;; could use (tcp-addresses conn)? ;;; (let loop ((rem-addrs all-addr)) ;;; (if (null? rem-addrs) ;;; (begin ;;; (print "ERROR: Failed to figure out the ip address of myself as a server. Giving up.") ;;; (exit 1)) ;; BUG Changeme to raising an exception ;;; ;;; (let* ((addr (car rem-addrs)) ;;; (good-addr (handle-exceptions ;;; exn ;;; #f ;;; ((rpc:procedure 'calling-addr addr (area-port acfg)))))) ;;; (if good-addr ;;; (begin ;;; (print "Got good-addr of " good-addr) ;;; (area-myaddr-set! acfg good-addr)) ;;; (loop (cdr rem-addrs))))))) ;;; (register-node acfg (area-myaddr acfg)(area-port acfg)) ;;; (print "INFO: Server started on " (area-myaddr acfg) ":" (area-port acfg)) ;;; ;; (update-known-servers acfg) ;; gotta do this on every start (thus why limit number of publicised servers) ;;; )) ;;; ;;; (define (clear-server-pkt acfg) ;;; (let ((pktf (area-pktfile acfg))) ;;; (if pktf (delete-file* pktf)))) ;;; ;;; (define (shutdown acfg) ;;; (let (;;(conn (area-conn acfg)) ;;; (pktf (area-pktfile acfg)) ;;; (port (area-port acfg))) ;;; (if pktf (delete-file* pktf)) ;;; (send-all "imshuttingdown") ;;; ;; (rpc:close-all-connections!) ;; don't know if this is actually needed ;;; (finalize-all-db-handles acfg))) ;;; ;;; (define (send-all msg) ;;; #f) ;;; ;;; ;; given a area record look up all the packets ;;; ;; ;;; (define (get-all-server-pkts acfg) ;;; (let ((all-pkt-files (glob (conc (area-pktsdir acfg) "/*.pkt")))) ;;; (map (lambda (pkt-file) ;;; (read-pkt->alist pkt-file pktspec: *pktspec*)) ;;; all-pkt-files))) ;;; ;;; #;((Z . "9a0212302295a19610d5796fce0370fa130758e9") ;;; (port . "34827") ;;; (pid . "28748") ;;; (hostname . "zeus") ;;; (T . "server") ;;; (D . "1549427032.0")) ;;; ;;; #;(define (get-my-best-address) ;;; (let ((all-my-addresses (get-all-ips))) ;; (vector->list (hostinfo-addresses (hostname->hostinfo (get-host-name)))))) ;;; (cond ;;; ((null? all-my-addresses) ;;; (get-host-name)) ;; no interfaces? ;;; ((eq? (length all-my-addresses) 1) ;;; (ip->string (car all-my-addresses))) ;; only one to choose from, just go with it ;;; (else ;;; (ip->string (car (filter (lambda (x) ;; take any but 127. ;;; (not (eq? (u8vector-ref x 0) 127))) ;;; all-my-addresses))))))) ;;; ;;; ;; whoami? I am my pkt ;;; ;; ;;; (define (whoami? acfg) ;;; (hash-table-ref/default (area-hosts acfg)(area-pktid acfg) #f)) ;;; ;;; ;;====================================================================== ;;; ;; "Client side" operations ;;; ;;====================================================================== ;;; ;;; (define (safe-call call-key host port . params) ;;; (handle-exceptions ;;; exn ;;; (begin ;;; (print "Call " call-key " to " host ":" port " failed") ;;; #f) ;;; (apply (rpc:procedure call-key host port) params))) ;;; ;;; ;; ;; convert to/from string / sexpr ;;; ;; ;;; ;; (define (string->sexpr str) ;;; ;; (if (string? str) ;;; ;; (with-input-from-string str read) ;;; ;; str)) ;;; ;; ;;; ;; (define (sexpr->string s) ;;; ;; (with-output-to-string (lambda ()(write s)))) ;;; ;;; ;; is the server alive? ;;; ;; ;;; (define (ping acfg host port) ;;; (let* ((myaddr (area-myaddr acfg)) ;;; (myport (area-port acfg)) ;;; (start-time (current-milliseconds)) ;;; (res (if (and (equal? myaddr host) ;;; (equal? myport port)) ;;; (real-ping acfg) ;;; ((rpc:procedure 'ping host port))))) ;;; (cons (- (current-milliseconds) start-time) ;;; res))) ;;; ;;; ;; returns ( ipaddr port alist-fname=>randnum ) ;;; (define (real-ping acfg) ;;; `(,(area-myaddr acfg) ,(area-port acfg) ,(get-host-stats acfg))) ;;; ;;; ;; is the server alive AND the queues processing? ;;; ;; ;;; #;(define (full-ping acfg servpkt) ;;; (let* ((start-time (current-milliseconds)) ;;; (res (send-message acfg servpkt '(full-ping) 'full-ping))) ;;; (cons (- (current-milliseconds) start-time) ;;; res))) ;; (equal? res "got ping")))) ;;; ;;; ;;; ;; look up all pkts and get the server id (the hash), port, host/ip ;;; ;; store this info in acfg ;;; ;; return the number of responsive servers found ;;; ;; ;;; ;; DO NOT VERIFY THAT THE SERVER IS ALIVE HERE. This is called at times where the current server is not yet alive and cannot ping itself ;;; ;; ;;; (define (update-known-servers acfg) ;;; ;; readll all pkts ;;; ;; foreach pkt; if it isn't me ping the server; if alive, add to hosts hash, else rm the pkt ;;; (let* ((start-time (current-milliseconds)) ;;; (all-pkts (delete-duplicates ;;; (append (get-all-server-pkts acfg) ;;; (hash-table-values (area-hosts acfg))))) ;;; (hostshash (area-hosts acfg)) ;;; (my-id (area-pktid acfg)) ;;; (pktsdir (area-pktsdir acfg)) ;; needed to remove pkts from non-responsive servers ;;; (numsrvs 0) ;;; (delpkt (lambda (pktsdir sid) ;;; (print "clearing out server " sid) ;;; (delete-file* (conc pktsdir "/" sid ".pkt")) ;;; (hash-table-delete! hostshash sid)))) ;;; (area-last-srvup-set! acfg (current-seconds)) ;;; (for-each ;;; (lambda (servpkt) ;;; (if (list? servpkt) ;;; ;; (pp servpkt) ;;; (let* ((shost (alist-ref 'ipaddr servpkt)) ;;; (sport (any->number (alist-ref 'port servpkt))) ;;; (res (handle-exceptions ;;; exn ;;; (begin ;;; ;; (print "INFO: bad server on " shost ":" sport) ;;; #f) ;;; (ping acfg shost sport))) ;;; (sid (alist-ref 'Z servpkt)) ;; Z code is our name for the server ;;; (url (conc shost ":" sport)) ;;; ) ;;; #;(if (or (not res) ;;; (null? res)) ;;; (begin ;;; (print "STRANGE: ping of " url " gave " res))) ;;; ;;; ;; (print "Got " res " from " shost ":" sport) ;;; (match res ;;; ((qduration . payload) ;;; ;; (print "Server pkt:" (alist-ref 'ipaddr servpkt) ":" (alist-ref 'port servpkt) ;;; ;; (if payload ;;; ;; "Success" "Fail")) ;;; (match payload ;;; ((host port stats) ;;; ;; (print "From " host ":" port " got stats: " stats) ;;; (if (and host port stats) ;;; (let ((url (conc host ":" port))) ;;; (hash-table-set! hostshash sid servpkt) ;;; ;; store based on host:port ;;; (hash-table-set! (area-hoststats acfg) sid stats)) ;;; (print "missing data from the server, not sure what that means!")) ;;; (set! numsrvs (+ numsrvs 1))) ;;; (#f ;;; (print "Removing pkt " sid " due to #f from server or failed ping") ;;; (delpkt pktsdir sid)) ;;; (else ;;; (print "Got ")(pp res)(print " from server ")(pp servpkt) " but response did not match (#f/#t . msg)"))) ;;; (else ;;; ;; here we delete the pkt - can't reach the server, remove it ;;; ;; however this logic is inadequate. we should mark the server as checked ;;; ;; and not good, if it happens a second time - then remove the pkt ;;; ;; or something similar. I.e. don't be too quick to assume the server is wedged or dead ;;; ;; could be it is simply too busy to reply ;;; (let ((bad-pings (hash-table-ref/default (area-health acfg) url 0))) ;;; (if (> bad-pings 1) ;; two bad pings - remove pkt ;;; (begin ;;; (print "INFO: " bad-pings " bad responses from " url ", deleting pkt " sid) ;;; (delpkt pktsdir sid)) ;;; (begin ;;; (print "INFO: " bad-pings " bad responses from " shost ":" sport " not deleting pkt yet") ;;; (hash-table-set! (area-health acfg) ;;; url ;;; (+ (hash-table-ref/default (area-health acfg) url 0) 1)) ;;; )) ;;; )))) ;;; ;; servpkt is not actually a pkt? ;;; (begin ;;; (print "Bad pkt " servpkt)))) ;;; all-pkts) ;;; (sdbg> "update-known-servers" "end" start-time #f #f " found " numsrvs ;;; " servers, pkts: " (map (lambda (p) ;;; (alist-ref 'Z p)) ;;; all-pkts)) ;;; numsrvs)) ;;; ;;; (defstruct srvstat ;;; (numfiles 0) ;; number of db files handled by this server - subtract 1 for the db being currently looked at ;;; (randnum #f) ;; tie breaker number assigned to by the server itself - applies only to the db under consideration ;;; (pkt #f)) ;; the server pkt ;;; ;;; ;;(define (srv->srvstat srvpkt) ;;; ;;; ;; Get the server best for given dbname and key ;;; ;; ;;; ;; NOTE: key is not currently used. The key points to the kind of query, this may be useful for directing read-only queries. ;;; ;; ;;; (define (get-best-server acfg dbname key) ;;; (let* (;; (servers (hash-table-values (area-hosts acfg))) ;;; (servers (area-hosts acfg)) ;;; (skeys (sort (hash-table-keys servers) string>=?)) ;; a stable listing ;;; (start-time (current-milliseconds)) ;;; (srvstats (make-hash-table)) ;; srvid => srvstat ;;; (url (conc (area-myaddr acfg) ":" (area-port acfg)))) ;;; ;; (print "scores for " dbname ": " (map (lambda (k)(cons k (calc-server-score acfg dbname k))) skeys)) ;;; (if (null? skeys) ;;; (if (> (update-known-servers acfg) 0) ;;; (get-best-server acfg dbname key) ;; some risk of infinite loop here, TODO add try counter ;;; (begin ;;; (print "ERROR: no server found!") ;; since this process is also a server this should never happen ;;; #f)) ;;; (begin ;;; ;; (print "in get-best-server with skeys=" skeys) ;;; (if (> (- (current-seconds) (area-last-srvup acfg)) 10) ;;; (begin ;;; (update-known-servers acfg) ;;; (sdbg> "get-best-server" "update-known-servers" start-time #f #f))) ;;; ;;; ;; for each server look at the list of dbfiles, total number of dbs being handled ;;; ;; and the rand number, save the best host ;;; ;; also do a delist-db for each server dbfile not used ;;; (let* ((best-server #f) ;;; (servers-to-delist (make-hash-table))) ;;; (for-each ;;; (lambda (srvid) ;;; (let* ((server (hash-table-ref/default servers srvid #f)) ;;; (stats (hash-table-ref/default (area-hoststats acfg) srvid '(())))) ;;; ;; (print "stats: " stats) ;;; (if server ;;; (let* ((dbweights (car stats)) ;;; (srvload (length (filter (lambda (x)(not (equal? dbname (car x)))) dbweights))) ;;; (dbrec (alist-ref dbname dbweights equal?)) ;; get the pair with fname . randscore ;;; (randnum (if dbrec ;;; dbrec ;; (cdr dbrec) ;;; 0))) ;;; (hash-table-set! srvstats srvid (make-srvstat numfiles: srvload randnum: randnum pkt: server)))))) ;;; skeys) ;;; ;;; (let* ((sorted (sort (hash-table-values srvstats) ;;; (lambda (a b) ;;; (let ((numfiles-a (srvstat-numfiles a)) ;;; (numfiles-b (srvstat-numfiles b)) ;;; (randnum-a (srvstat-randnum a)) ;;; (randnum-b (srvstat-randnum b))) ;;; (if (< numfiles-a numfiles-b) ;; Note, I don't think adding an offset works here. Goal was only move file handling to a different server if it has 2 less ;;; #t ;;; (if (and (equal? numfiles-a numfiles-b) ;;; (< randnum-a randnum-b)) ;;; #t ;;; #f)))))) ;;; (best (if (null? sorted) ;;; (begin ;;; (print "ERROR: should never be null due to self as server.") ;;; #f) ;;; (srvstat-pkt (car sorted))))) ;;; #;(print "SERVER(" url "): " dbname ": " (map (lambda (srv) ;;; (let ((p (srvstat-pkt srv))) ;;; (conc (alist-ref 'ipaddr p) ":" (alist-ref 'port p) ;;; "(" (srvstat-numfiles srv)","(srvstat-randnum srv)")"))) ;;; sorted)) ;;; best)))))) ;;; ;;; ;; send out an "I'm about to exit notice to all known servers" ;;; ;; ;;; (define (death-imminent acfg) ;;; '()) ;;; ;;; ;;====================================================================== ;;; ;; U L E X - T H E I N T E R E S T I N G S T U F F ! ! ;;; ;;====================================================================== ;;; ;;; ;; register a handler ;;; ;; NOTES: ;;; ;; dbinitsql is reserved for a list of sql statements for initializing the db ;;; ;; dbinitfn is reserved for a db init function, if exists called after dbinitsql ;;; ;; ;;; (define (register acfg key obj #!optional (ctype 'dbwrite)) ;;; (let ((ht (area-rtable acfg))) ;;; (if (hash-table-exists? ht key) ;;; (print "WARNING: redefinition of entry " key)) ;;; (hash-table-set! ht key (make-calldat obj: obj ctype: ctype)))) ;;; ;;; ;; usage: register-batch acfg '((key1 . sql1) (key2 . sql2) ... ) ;;; ;; NB// obj is often an sql query ;;; ;; ;;; (define (register-batch acfg ctype data) ;;; (let ((ht (area-rtable acfg))) ;;; (map (lambda (dat) ;;; (hash-table-set! ht (car dat)(make-calldat obj: (cdr dat) ctype: ctype))) ;;; data))) ;;; ;;; (define (initialize-area-calls-from-specfile area specfile) ;;; (let* ((callspec (with-input-from-file specfile read ))) ;;; (for-each (lambda (group) ;;; (register-batch ;;; area ;;; (car group) ;;; (cdr group))) ;;; callspec))) ;;; ;;; ;; get-rentry ;;; ;; ;;; (define (get-rentry acfg key) ;;; (hash-table-ref/default (area-rtable acfg) key #f)) ;;; ;;; (define (get-rsql acfg key) ;;; (let ((cdat (get-rentry acfg key))) ;;; (if cdat ;;; (calldat-obj cdat) ;;; #f))) ;;; ;;; ;;; ;;; ;; blocking call: ;;; ;; client server ;;; ;; ------ ------ ;;; ;; call() ;;; ;; send-message() ;;; ;; nmsg-send() ;;; ;; nmsg-receive() ;;; ;; nmsg-respond(ack,cookie) ;;; ;; ack, cookie ;;; ;; mbox-thread-wait(cookie) ;;; ;; nmsg-send(client,cookie,result) ;;; ;; nmsg-respond(ack) ;;; ;; return result ;;; ;; ;;; ;; reserved action: ;;; ;; 'immediate ;;; ;; 'dbinitsql ;;; ;; ;;; (define (call acfg dbname action params #!optional (count 0)) ;;; (let* ((call-start-time (current-milliseconds)) ;;; (srv (get-best-server acfg dbname action)) ;;; (post-get-start-time (current-milliseconds)) ;;; (rdat (hash-table-ref/default (area-rtable acfg) action #f)) ;;; (myid (trim-pktid (area-pktid acfg))) ;;; (srvid (trim-pktid (alist-ref 'Z srv))) ;;; (cookie (make-cookie myid))) ;;; (sdbg> "call" "get-best-server" call-start-time #f call-start-time " from: " myid " to server: " srvid " for " dbname " action: " action " params: " params " rdat: " rdat) ;;; (print "INFO: call to " (alist-ref 'ipaddr srv) ":" (alist-ref 'port srv) " from " (area-myaddr acfg) ":" (area-port acfg) " for " dbname) ;;; (if (and srv rdat) ;; need both to dispatch a request ;;; (let* ((ripaddr (alist-ref 'ipaddr srv)) ;;; (rsrvid (alist-ref 'Z srv)) ;;; (rport (any->number (alist-ref 'port srv))) ;;; (res-full (if (and (equal? ripaddr (area-myaddr acfg)) ;;; (equal? rport (area-port acfg))) ;;; (request acfg ripaddr rport (area-pktid acfg) action cookie dbname params) ;;; (safe-call 'request ripaddr rport ;;; (area-myaddr acfg) ;;; (area-port acfg) ;;; #;(area-pktid acfg) ;;; rsrvid ;;; action cookie dbname params)))) ;;; ;; (print "res-full: " res-full) ;;; (match res-full ;;; ((response-ok response-msg rem ...) ;;; (let* ((send-message-time (current-milliseconds)) ;;; ;; (match res-full ;;; ;; ((response-ok response-msg) ;;; ;; (response-ok (car res-full)) ;;; ;; (response-msg (cadr res-full) ;;; ) ;;; ;; (res (take res-full 3))) ;; ctype == action, TODO: converge on one term <<=== what was this? BUG ;;; ;; (print "ulex:call: send-message took " (- send-message-time post-get-start-time) " ms params=" params) ;;; (sdbg> "call" "send-message" post-get-start-time #f call-start-time) ;;; (cond ;;; ((not response-ok) #f) ;;; ((member response-msg '("db read submitted" "db write submitted")) ;;; (let* ((cookie-id (cadddr res-full)) ;;; (mbox (make-mailbox)) ;;; (mbox-time (current-milliseconds))) ;;; (hash-table-set! (area-cookie2mbox acfg) cookie-id mbox) ;;; (let* ((mbox-timeout-secs 20) ;;; (mbox-timeout-result 'MBOX_TIMEOUT) ;;; (res (mailbox-receive! mbox mbox-timeout-secs mbox-timeout-result)) ;;; (mbox-receive-time (current-milliseconds))) ;;; (hash-table-delete! (area-cookie2mbox acfg) cookie-id) ;;; (sdbg> "call" "mailbox-receive" mbox-time #f call-start-time " from: " myid " to server: " srvid " for " dbname) ;;; ;; (print "ulex:call mailbox-receive took " (- mbox-receive-time mbox-time) "ms params=" params) ;;; res))) ;;; (else ;;; (print "Unhandled response \""response-msg"\"") ;;; #f)) ;;; ;; depending on what action (i.e. ctype) is we will block here waiting for ;;; ;; all the data (mechanism to be determined) ;;; ;; ;;; ;; if res is a "working on it" then wait ;;; ;; wait for result ;;; ;; mailbox thread wait on ;;; ;;; ;; if res is a "can't help you" then try a different server ;;; ;; if res is a "ack" (e.g. for one-shot requests) then return res ;;; )) ;;; (else ;;; (if (< count 10) ;;; (let* ((url (conc (alist-ref 'ipaddr srv) ":" (alist-ref 'port srv)))) ;;; (thread-sleep! 1) ;;; (print "ERROR: Bad result from " url ", dbname: " dbname ", action: " action ", params: " params ". Trying again in 1 second.") ;;; (call acfg dbname action params (+ count 1))) ;;; (begin ;;; (error (conc "ERROR: " count " tries, still have improper response res-full=" res-full))))))) ;;; (begin ;;; (if (not rdat) ;;; (print "ERROR: action " action " not registered.") ;;; (if (< count 10) ;;; (begin ;;; (thread-sleep! 1) ;;; (area-hosts-set! acfg (make-hash-table)) ;; clear out all known hosts ;;; (print "ERROR: no server found, srv=" srv ", trying again in 1 seconds") ;;; (call acfg dbname action params (+ count 1))) ;;; (begin ;;; (error (conc "ERROR: no server found after 10 tries, srv=" srv ", giving up.")) ;;; #;(error "No server available")))))))) ;;; ;;; ;;; ;;====================================================================== ;;; ;; U T I L I T I E S ;;; ;;====================================================================== ;;; ;;; ;; get a signature for identifing this process ;;; ;; ;;; (define (get-process-signature) ;;; (cons (get-host-name)(current-process-id))) ;;; ;;; ;;====================================================================== ;;; ;; S Y S T E M S T U F F ;;; ;;====================================================================== ;;; ;;; ;; 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 (get-normalized-cpu-load) ;;; (let ((res (get-normalized-cpu-load-raw)) ;;; (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 (get-normalized-cpu-load-raw) ;;; (let* ((actual-host (get-host-name))) ;; #f is localhost ;;; (let ((data (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))))) ;;; 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 (get-host-stats acfg) ;;; (let ((stats-hash (area-stats acfg))) ;;; ;; use this opportunity to remove references to dbfiles which have not been accessed in a while ;;; (for-each ;;; (lambda (dbname) ;;; (let* ((stats (hash-table-ref stats-hash dbname)) ;;; (last-access (stat-when stats))) ;;; (if (and (> last-access 0) ;; if zero then there has been no access ;;; (> (- (current-seconds) last-access) 10)) ;; not used in ten seconds ;;; (begin ;;; (print "Removing " dbname " from stats list") ;;; (hash-table-delete! stats-hash dbname) ;; remove from stats hash ;;; (stat-dbs-set! stats (hash-table-keys stats)))))) ;;; (hash-table-keys stats-hash)) ;;; ;;; `(,(hash-table->alist (area-dbs acfg)) ;; dbname => randnum ;;; ,(map (lambda (dbname) ;; dbname is the db name ;;; (cons dbname (stat-when (hash-table-ref stats-hash dbname)))) ;;; (hash-table-keys stats-hash)) ;;; (cpuload . ,(get-normalized-cpu-load))))) ;;; #;(stats . ,(map (lambda (k) ;; create an alist from the stats data ;;; (cons k (stat->alist (hash-table-ref (area-stats acfg) k)))) ;;; (hash-table-keys (area-stats acfg)))) ;;; ;;; #;(trace ;;; ;; assv ;;; ;; cdr ;;; ;; caar ;;; ;; ;; cdr ;;; ;; call ;;; ;; finalize-all-db-handles ;;; ;; get-all-server-pkts ;;; ;; get-normalized-cpu-load ;;; ;; get-normalized-cpu-load-raw ;;; ;; launch ;;; ;; nmsg-send ;;; ;; process-db-queries ;;; ;; receive-message ;;; ;; std-peer-handler ;;; ;; update-known-servers ;;; ;; work-queue-processor ;;; ) ;;; ;;; ;;====================================================================== ;;; ;; netutil ;;; ;; move this back to ulex-netutil.scm someday? ;;; ;;====================================================================== ;;; ;;; ;; #include <stdio.h> ;;; ;; #include <netinet/in.h> ;;; ;; #include <string.h> ;;; ;; #include <arpa/inet.h> ;;; ;;; (foreign-declare "#include \"sys/types.h\"") ;;; (foreign-declare "#include \"sys/socket.h\"") ;;; (foreign-declare "#include \"ifaddrs.h\"") ;;; (foreign-declare "#include \"arpa/inet.h\"") ;;; ;;; ;; get IP addresses from ALL interfaces ;;; (define get-all-ips ;;; (foreign-safe-lambda* scheme-object () ;;; " ;;; ;;; // from https://stackoverflow.com/questions/17909401/linux-c-get-default-interfaces-ip-address : ;;; ;;; ;;; C_word lst = C_SCHEME_END_OF_LIST, len, str, *a; ;;; // struct ifaddrs *ifa, *i; ;;; // struct sockaddr *sa; ;;; ;;; struct ifaddrs * ifAddrStruct = NULL; ;;; struct ifaddrs * ifa = NULL; ;;; void * tmpAddrPtr = NULL; ;;; ;;; if ( getifaddrs(&ifAddrStruct) != 0) ;;; C_return(C_SCHEME_FALSE); ;;; ;;; // for (i = ifa; i != NULL; i = i->ifa_next) { ;;; for (ifa = ifAddrStruct; ifa != NULL; ifa = ifa->ifa_next) { ;;; if (ifa->ifa_addr->sa_family==AF_INET) { // Check it is ;;; // a valid IPv4 address ;;; tmpAddrPtr = &((struct sockaddr_in *)ifa->ifa_addr)->sin_addr; ;;; char addressBuffer[INET_ADDRSTRLEN]; ;;; inet_ntop(AF_INET, tmpAddrPtr, addressBuffer, INET_ADDRSTRLEN); ;;; // printf(\"%s IP Address %s\\n\", ifa->ifa_name, addressBuffer); ;;; len = strlen(addressBuffer); ;;; a = C_alloc(C_SIZEOF_PAIR + C_SIZEOF_STRING(len)); ;;; str = C_string(&a, len, addressBuffer); ;;; lst = C_a_pair(&a, str, lst); ;;; } ;;; ;;; // else if (ifa->ifa_addr->sa_family==AF_INET6) { // Check it is ;;; // // a valid IPv6 address ;;; // tmpAddrPtr = &((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr; ;;; // char addressBuffer[INET6_ADDRSTRLEN]; ;;; // inet_ntop(AF_INET6, tmpAddrPtr, addressBuffer, INET6_ADDRSTRLEN); ;;; //// printf(\"%s IP Address %s\\n\", ifa->ifa_name, addressBuffer); ;;; // len = strlen(addressBuffer); ;;; // a = C_alloc(C_SIZEOF_PAIR + C_SIZEOF_STRING(len)); ;;; // str = C_string(&a, len, addressBuffer); ;;; // lst = C_a_pair(&a, str, lst); ;;; // } ;;; ;;; // else { ;;; // printf(\" not an IPv4 address\\n\"); ;;; // } ;;; ;;; } ;;; ;;; freeifaddrs(ifa); ;;; C_return(lst); ;;; ;;; ")) ;;; ;;; ;; Change this to bias for addresses with a reasonable broadcast value? ;;; ;; ;;; (define (ip-pref-less? a b) ;;; (let* ((rate (lambda (ipstr) ;;; (regex-case ipstr ;;; ( "^127\\." _ 0 ) ;;; ( "^(10\\.0|192\\.168\\.)\\..*" _ 1 ) ;;; ( else 2 ) )))) ;;; (< (rate a) (rate b)))) ;;; ;;; ;;; (define (get-my-best-address) ;;; (let ((all-my-addresses (get-all-ips)) ;;; ;;(all-my-addresses-old (vector->list (hostinfo-addresses (hostname->hostinfo (get-host-name))))) ;;; ) ;;; (cond ;;; ((null? all-my-addresses) ;;; (get-host-name)) ;; no interfaces? ;;; ((eq? (length all-my-addresses) 1) ;;; (car all-my-addresses)) ;; only one to choose from, just go with it ;;; ;;; (else ;;; (car (sort all-my-addresses ip-pref-less?))) ;;; ;; (else ;;; ;; (ip->string (car (filter (lambda (x) ;; take any but 127. ;;; ;; (not (eq? (u8vector-ref x 0) 127))) ;;; ;; all-my-addresses)))) ;;; ;;; ))) ;;; ;;; (define (get-all-ips-sorted) ;;; (sort (get-all-ips) ip-pref-less?)) ;;; ;;; |
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/Makefile.whodunit version [2690881b41].
> > > > > > > > > | 1 2 3 4 5 6 7 8 9 | .DEFAULT : all all : whodunit clean : rm whodunit whodunit : whodunit.scm csc -static -L -static -L -lm -L -ldl -L -lpthread -L -lssl -L -lcrypto -L -lz whodunit.scm -o whodunit |
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 [713ec8f660].
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 61 62 | #!/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" libdir="$prefix/bin/.$(lsb_release -sr)/lib" # 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 echo "INFO: Writing $cfgfile" >&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:$libdir else export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$libdir 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 | > > > > > > > > > > > | | 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 | 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 |
Added utils/mk_wrapper_tool version [69ed35f3e4].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | #!/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 # 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 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)/bin/$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 $chicken_bin_dir/$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 [c7d387d56c].
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 | #!/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> remrun behavior can be changed by setting the following env vars: NBFAKE_LOG Logfile for remrun output __EOF exit fi export NBFAKE_HOST=$1 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 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | #!/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> remrun behavior can be changed by setting the following env vars: NBFAKE_LOG Logfile for remrun output __EOF exit fi export NBFAKE_HOST=$1 shift cmd="" for var in $(env | egrep "^(PARENT_|MT_)"|cut -d= -f1);do new_var="`echo ${!var}`" cmd="$cmd export $var=$new_var;" done cmd="$cmd $*" exec nbfake $cmd |
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) { |
︙ | ︙ |
Added utils/softlock/Makefile version [8ff197b872].
> > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 | #Need a chicken 5.1.0 with system-information egg installed in your path .DEFAULT : all all : softlock softlock : softlock.scm csc -static -L -static -L -lm -L -dl -L -lpthread -L -lcrypto -L -lz softlock.scm clean: rm softlock *.o |
Added utils/softlock/softlock.scm version [d7275b3208].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | ;;====================================================================== ;; Copyright 2019, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. ;; ;;====================================================================== (import (chicken string) (chicken pathname) system-information (chicken file posix) (chicken process-context posix) (chicken process-context) (chicken process) (chicken file posix) (chicken file) (chicken time) srfi-18 ) (if (< (length (command-line-arguments)) 2) ;; require at least lockfile command (begin (print "Usage: softlock lockfile command args ... Softlock does weak, transient locking. This is useful to slow down a deluge of events that can overwhelm hardware or software systems. Locks are only good for one second, just enough time to spread events out. On NFS the Unix file locking mechanism works well but lock handling on the filers can be overwhelmed by many locks occuring quickly. Jobs that must use NFS file locks can use softlock to minimize the rate that the file locks are created, preventing the NFS filer from being swamped. Environment variables: SOFTLOCK_DEBUG_MODE - if defined enable some messages WARNING: the file <lockfile>.softlock will be overwritten and removed by softlock! Part of the Megatest project http://www.kiatoa.com/fossils/megatest") (exit 1))) (define (read-lock-file fname) (handle-exceptions exn (begin (if (get-environment-variable "SOFTLOCK_DEBUG_MODE") (print "Exception on reading lock file. exn=" exn)) #f) (with-input-from-file fname read-line))) (define (lock-file-old fname) (and (file-exists? fname) (> (- (current-seconds)(file-modification-time fname)) 1))) ;; hard coded to one second (define (check-locked-by-me fname mykey) (if (file-exists? fname) (let ((lock-data (read-lock-file fname))) (if (and lock-data (equal? mykey lock-data)) #t (not (lock-file-old fname)))) ;; if the lockfile is old we are NOT locked. #f)) (define (check-locked-by-someone-else fname mykey) (if (file-exists? fname) (let ((lock-data (read-lock-file fname))) (and lock-data (not (equal? mykey lock-data)) (not (lock-file-old fname)))) ;; if the lockfile is old we are NOT locked. #f)) (define (take-lock fname mykey) (with-output-to-file fname (lambda () (print mykey)))) (define (run-the-command command params) (process-wait (process-run command params))) (let* ((lockfile (car (command-line-arguments))) (fulllock (conc lockfile ".softlock")) ;; prevent accidentally removing important files (lockfdir (pathname-directory lockfile)) (command (cadr (command-line-arguments))) (params (cddr (command-line-arguments))) (mykey (conc (get-host-name) "-" (current-process-id)))) ;; sanity checks (cond ((not lockfdir) (print "ERROR: lock file parameter must include path component, e.g. ./mylock") (exit 1)) ((not (file-writable? lockfdir)) (print "ERROR: Can not access directory for lock " lockfdir) (exit 1)) ;; add more sanity checks here ) (let loop ((remtries 10)) (if (> remtries 0) (if (check-locked-by-someone-else fulllock mykey) (begin (print "... lock " fulllock " exists, waiting...") (thread-sleep! 1.9) (loop (- remtries 1))) (begin (take-lock fulllock mykey) (if (check-locked-by-me fulllock mykey) (run-the-command command params) (begin ;; didn't get the lock (thread-sleep! (+ 1.9 (/ 1 (+ 1 (random 20))))) ;; add some noise to prevent nyquist problems (loop (- remtries 1)))))) (begin (print "ERROR: not able to get the lock. Gonna take it and proceed...") (take-lock fulllock mykey) (run-the-command command params))))) |
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 [4709c0e629].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | ;; Copyright 2006-2017, Matthew Welland. ;; ;; This file is part of Megatest. ;; ;; Megatest is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; Megatest is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with Megatest. If not, see <http://www.gnu.org/licenses/>. ;; (module whodunit * (import (chicken process-context) (chicken process) (chicken string) (chicken base) (chicken sort) (chicken io) srfi-69 scheme ) (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) (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))))) ;; sum up (define (sum-up data ht) (for-each (lambda (indat) (let ((pid (car indat)) (usr (cadr indat)) (cpu (list-ref indat 8))) (hash-table-set! ht usr (+ cpu (hash-table-ref/default ht usr 0))))) data)) (define (print-results userhash) (for-each (lambda (usr) (let* ((usage (inexact->exact (round (/ (hash-table-ref userhash usr) *numsamples*))))) (if (> usage 0) (print usr (if (< (string-length usr) 8) "\t\t" "\t") usage)))) (sort (hash-table-keys userhash) (lambda (a b) (> (hash-table-ref userhash a) (hash-table-ref userhash b)))))) ) (import whodunit srfi-69 (chicken sort)) (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 data userhash) (print-results userhash) |
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 "$@" |