1 /++ 2 $(H2 Scriptlike $(SCRIPTLIKE_VERSION)) 3 4 Wrappers for $(MODULE_STD_FILE) that add support for Scriptlike's 5 $(API_PATH_EXTR Path), command echoing and dry-run features. 6 7 Copyright: Copyright (C) 2014-2017 Nick Sabalausky 8 License: zlib/libpng 9 Authors: Nick Sabalausky 10 +/ 11 module scriptlike.file.wrappers; 12 13 import std.algorithm; 14 import std.conv; 15 import std.datetime; 16 import std..string; 17 import std.traits; 18 import std.typecons; 19 20 static import std.file; 21 public import std.file : FileException, SpanMode, 22 attrIsDir, attrIsFile, attrIsSymlink; 23 static import std.path; 24 25 import scriptlike.core; 26 import scriptlike.path.extras; 27 28 /// Like $(FULL_STD_FILE read), but supports Path and command echoing. 29 void[] read(in Path name, size_t upTo = size_t.max) 30 { 31 return read(name.raw, upTo); 32 } 33 34 ///ditto 35 void[] read(in string name, size_t upTo = size_t.max) 36 { 37 yapFunc(name); 38 return std.file.read(name, upTo); 39 } 40 41 /// Alias of read, included to provide naming symmetry with writeFile, which 42 /// helps avoid naming conflicts with 43 /// $(D_INLINECODE $(LINK2 http://dlang.org/phobos/std_stdio.html#.write, std.stdio.write)). 44 alias readFile = read; 45 46 version(unittest_scriptlike_d) 47 unittest 48 { 49 string file; 50 51 testFileOperation!("read", "string")(() { 52 mixin(useTmpName!"file"); 53 std.file.write(file, "abc123"); 54 55 assert(cast(string) read(file) == "abc123"); 56 }); 57 58 testFileOperation!("read", "Path")(() { 59 mixin(useTmpName!"file"); 60 std.file.write(file, "abc123"); 61 62 assert(cast(string) read(Path(file)) == "abc123"); 63 }); 64 } 65 66 /// Like $(FULL_STD_FILE readText), but supports Path and command echoing. 67 S readText(S = string)(in Path name) 68 { 69 return readText(name.raw); 70 } 71 72 ///ditto 73 S readText(S = string)(in string name) 74 { 75 yapFunc(name); 76 return std.file.readText(name); 77 } 78 79 version(unittest_scriptlike_d) 80 unittest 81 { 82 string file; 83 84 testFileOperation!("readText", "string")(() { 85 mixin(useTmpName!"file"); 86 std.file.write(file, "abc123"); 87 88 assert(cast(string) readText(file) == "abc123"); 89 }); 90 91 testFileOperation!("readText", "Path")(() { 92 mixin(useTmpName!"file"); 93 std.file.write(file, "abc123"); 94 95 assert(cast(string) readText(Path(file)) == "abc123"); 96 }); 97 } 98 99 /// Like $(FULL_STD_FILE write), but supports Path, command echoing and dryrun. 100 /// 101 /// To avoid naming conflicts with 102 /// $(D_INLINECODE $(LINK2 http://dlang.org/phobos/std_stdio.html#.write, std.stdio.write)), 103 /// you may wish to use the writeFile alias instead. A readFile is also provided 104 /// for symmetry with writeFile. 105 void write(in Path name, const void[] buffer) 106 { 107 write(name.raw, buffer); 108 } 109 110 ///ditto 111 void write(in string name, const void[] buffer) 112 { 113 yapFunc(name.escapeShellArg()); 114 115 if(!scriptlikeDryRun) 116 std.file.write(name, buffer); 117 } 118 119 /// Alias of write to help avoid naming conflicts with 120 /// $(D_INLINECODE $(LINK2 http://dlang.org/phobos/std_stdio.html#.write, std.stdio.write)). 121 /// A readFile is also provided for symmetry with writeFile. 122 alias writeFile = write; 123 124 version(unittest_scriptlike_d) 125 unittest 126 { 127 string file; 128 void checkPre() 129 { 130 assert(!std.file.exists(file)); 131 } 132 133 void checkPost() 134 { 135 assert(std.file.exists(file)); 136 assert(std.file.isFile(file)); 137 assert(cast(string) std.file.read(file) == "abc123"); 138 } 139 140 // Create 141 testFileOperation!("write", "Create: string")(() { 142 mixin(useTmpName!"file"); 143 144 checkPre(); 145 write(file, "abc123"); 146 mixin(checkResult); 147 }); 148 149 testFileOperation!("write", "Create: Path")(() { 150 mixin(useTmpName!"file"); 151 152 checkPre(); 153 write(Path(file), "abc123"); 154 mixin(checkResult); 155 }); 156 157 // Overwrite 158 testFileOperation!("write", "Overwrite: string")(() { 159 mixin(useTmpName!"file"); 160 161 checkPre(); 162 write(file, "hello"); 163 write(file, "abc123"); 164 mixin(checkResult); 165 }); 166 167 testFileOperation!("write", "Overwrite: Path")(() { 168 mixin(useTmpName!"file"); 169 170 checkPre(); 171 write(Path(file), "hello"); 172 write(Path(file), "abc123"); 173 mixin(checkResult); 174 }); 175 } 176 177 /// Like $(FULL_STD_FILE append), but supports Path, command echoing and dryrun. 178 void append(in Path name, in void[] buffer) 179 { 180 append(name.raw, buffer); 181 } 182 183 ///ditto 184 void append(in string name, in void[] buffer) 185 { 186 yapFunc(name.escapeShellArg()); 187 188 if(!scriptlikeDryRun) 189 std.file.append(name, buffer); 190 } 191 192 version(unittest_scriptlike_d) 193 unittest 194 { 195 string file; 196 void checkPre() 197 { 198 assert(std.file.exists(file)); 199 assert(std.file.isFile(file)); 200 assert(cast(string) std.file.read(file) == "abc123"); 201 } 202 203 void checkPost() 204 { 205 assert(std.file.exists(file)); 206 assert(std.file.isFile(file)); 207 assert(cast(string) std.file.read(file) == "abc123hello"); 208 } 209 210 testFileOperation!("append", "string")(() { 211 mixin(useTmpName!"file"); 212 std.file.write(file, "abc123"); 213 214 checkPre(); 215 append(file, "hello"); 216 mixin(checkResult); 217 }); 218 219 testFileOperation!("append", "Path")(() { 220 mixin(useTmpName!"file"); 221 std.file.write(file, "abc123"); 222 223 checkPre(); 224 append(Path(file), "hello"); 225 mixin(checkResult); 226 }); 227 } 228 229 /// Like $(FULL_STD_FILE rename), but supports Path, command echoing and dryrun. 230 void rename(in Path from, in Path to) 231 { 232 rename(from.raw, to.raw); 233 } 234 235 ///ditto 236 void rename(in string from, in Path to) 237 { 238 rename(from, to.raw); 239 } 240 241 ///ditto 242 void rename(in Path from, in string to) 243 { 244 rename(from.raw, to); 245 } 246 247 ///ditto 248 void rename(in string from, in string to) 249 { 250 yapFunc(from.escapeShellArg(), " -> ", to.escapeShellArg()); 251 252 if(!scriptlikeDryRun) 253 std.file.rename(from, to); 254 } 255 256 version(unittest_scriptlike_d) 257 unittest 258 { 259 string file1; 260 string file2; 261 void checkPre() 262 { 263 assert(!std.file.exists(file2)); 264 assert(std.file.exists(file1)); 265 assert(std.file.isFile(file1)); 266 assert(cast(string) std.file.read(file1) == "abc"); 267 } 268 269 void checkPost() 270 { 271 assert(!std.file.exists(file1)); 272 assert(std.file.exists(file2)); 273 assert(std.file.isFile(file2)); 274 assert(cast(string) std.file.read(file2) == "abc"); 275 } 276 277 testFileOperation!("rename", "string,string")(() { 278 mixin(useTmpName!"file1"); 279 mixin(useTmpName!"file2"); 280 std.file.write(file1, "abc"); 281 282 checkPre(); 283 rename(file1, file2); 284 mixin(checkResult); 285 }); 286 287 testFileOperation!("rename", "string,Path")(() { 288 mixin(useTmpName!"file1"); 289 mixin(useTmpName!"file2"); 290 std.file.write(file1, "abc"); 291 292 checkPre(); 293 rename(file1, Path(file2)); 294 mixin(checkResult); 295 }); 296 297 testFileOperation!("rename", "Path,string")(() { 298 mixin(useTmpName!"file1"); 299 mixin(useTmpName!"file2"); 300 std.file.write(file1, "abc"); 301 302 checkPre(); 303 rename(Path(file1), file2); 304 mixin(checkResult); 305 }); 306 307 testFileOperation!("rename", "Path,Path")(() { 308 mixin(useTmpName!"file1"); 309 mixin(useTmpName!"file2"); 310 std.file.write(file1, "abc"); 311 312 checkPre(); 313 rename(Path(file1), Path(file2)); 314 mixin(checkResult); 315 }); 316 } 317 318 /// Like $(FULL_STD_FILE remove), but supports Path, command echoing and dryrun. 319 void remove(in Path name) 320 { 321 remove(name.raw); 322 } 323 324 ///ditto 325 void remove(in string name) 326 { 327 yapFunc(name.escapeShellArg()); 328 329 if(!scriptlikeDryRun) 330 std.file.remove(name); 331 } 332 333 version(unittest_scriptlike_d) 334 unittest 335 { 336 string file; 337 void checkPre() 338 { 339 assert(std.file.exists(file)); 340 assert(std.file.isFile(file)); 341 assert(cast(string) std.file.read(file) == "abc"); 342 } 343 344 void checkPost() 345 { 346 assert(!std.file.exists(file)); 347 } 348 349 testFileOperation!("remove", "string")(() { 350 mixin(useTmpName!"file"); 351 std.file.write(file, "abc"); 352 353 checkPre(); 354 remove(file); 355 mixin(checkResult); 356 }); 357 358 testFileOperation!("remove", "Path")(() { 359 mixin(useTmpName!"file"); 360 std.file.write(file, "abc"); 361 362 checkPre(); 363 remove(Path(file)); 364 mixin(checkResult); 365 }); 366 } 367 368 /// Like $(FULL_STD_FILE getSize), but supports Path and command echoing. 369 ulong getSize(in Path name) 370 { 371 return getSize(name.raw); 372 } 373 374 ///ditto 375 ulong getSize(in string name) 376 { 377 yapFunc(name); 378 return std.file.getSize(name); 379 } 380 381 version(unittest_scriptlike_d) 382 unittest 383 { 384 string file; 385 386 testFileOperation!("getSize", "string")(() { 387 mixin(useTmpName!"file"); 388 std.file.write(file, "abc123"); 389 390 assert(getSize(file) == 6); 391 }); 392 393 testFileOperation!("getSize", "Path")(() { 394 mixin(useTmpName!"file"); 395 std.file.write(file, "abc123"); 396 397 assert(getSize(Path(file)) == 6); 398 }); 399 } 400 401 /// Like $(FULL_STD_FILE getTimes), but supports Path and command echoing. 402 void getTimes(in Path name, 403 out SysTime accessTime, 404 out SysTime modificationTime) 405 { 406 getTimes(name.raw, accessTime, modificationTime); 407 } 408 409 ///ditto 410 void getTimes(in string name, 411 out SysTime accessTime, 412 out SysTime modificationTime) 413 { 414 yapFunc(name); 415 std.file.getTimes(name, accessTime, modificationTime); 416 } 417 418 version(unittest_scriptlike_d) 419 unittest 420 { 421 string file; 422 423 testFileOperation!("getTimes", "string")(() { 424 mixin(useTmpName!"file"); 425 std.file.write(file, "abc123"); 426 427 SysTime a, b; 428 getTimes(file, a, b); 429 }); 430 431 testFileOperation!("getTimes", "Path")(() { 432 mixin(useTmpName!"file"); 433 std.file.write(file, "abc123"); 434 435 SysTime a, b; 436 getTimes(Path(file), a, b); 437 }); 438 } 439 440 version(docs_scriptlike_d) 441 { 442 /// Windows-only. Like $(FULL_STD_FILE getTimesWin), but supports Path and command echoing. 443 void getTimesWin(in Path name, 444 out SysTime fileCreationTime, 445 out SysTime fileAccessTime, 446 out SysTime fileModificationTime); 447 448 ///ditto 449 void getTimesWin(in string name, 450 out SysTime fileCreationTime, 451 out SysTime fileAccessTime, 452 out SysTime fileModificationTime); 453 } 454 else version(Windows) 455 { 456 void getTimesWin(in Path name, 457 out SysTime fileCreationTime, 458 out SysTime fileAccessTime, 459 out SysTime fileModificationTime) 460 { 461 getTimesWin(name.raw, fileCreationTime, fileAccessTime, fileModificationTime); 462 } 463 464 void getTimesWin(in string name, 465 out SysTime fileCreationTime, 466 out SysTime fileAccessTime, 467 out SysTime fileModificationTime) 468 { 469 yapFunc(name); 470 std.file.getTimesWin(name, fileCreationTime, fileAccessTime, fileModificationTime); 471 } 472 473 version(unittest_scriptlike_d) 474 unittest 475 { 476 string file; 477 478 testFileOperation!("getTimesWin", "string")(() { 479 mixin(useTmpName!"file"); 480 std.file.write(file, "abc123"); 481 482 SysTime a, b, c; 483 getTimesWin(file, a, b, c); 484 }); 485 486 testFileOperation!("getTimesWin", "Path")(() { 487 mixin(useTmpName!"file"); 488 std.file.write(file, "abc123"); 489 490 SysTime a, b, c; 491 getTimesWin(Path(file), a, b, c); 492 }); 493 } 494 } 495 496 /// Like $(FULL_STD_FILE setTimes), but supports Path, command echoing and dryrun. 497 void setTimes(in Path name, 498 SysTime accessTime, 499 SysTime modificationTime) 500 { 501 setTimes(name.raw, accessTime, modificationTime); 502 } 503 504 ///ditto 505 void setTimes(in string name, 506 SysTime accessTime, 507 SysTime modificationTime) 508 { 509 yapFunc(name.escapeShellArg(), 510 "Accessed ", accessTime, "; Modified ", modificationTime); 511 512 if(!scriptlikeDryRun) 513 std.file.setTimes(name, accessTime, modificationTime); 514 } 515 516 version(unittest_scriptlike_d) 517 unittest 518 { 519 string file; 520 SysTime actualAccessTime, actualModTime; 521 SysTime expectedAccessTime = SysTime(234567890); 522 SysTime expectedModTime = SysTime(123456789); 523 524 void checkPre() 525 { 526 std.file.getTimes(file, actualAccessTime, actualModTime); 527 assert(actualAccessTime != expectedAccessTime); 528 assert(actualModTime != expectedModTime); 529 } 530 531 void checkPost() 532 { 533 std.file.getTimes(file, actualAccessTime, actualModTime); 534 assert(actualAccessTime == expectedAccessTime); 535 assert(actualModTime == expectedModTime); 536 } 537 538 /+ 539 testFileOperation!("setTimes", "string")(() { 540 mixin(useTmpName!"file"); 541 std.file.write(file, "abc"); 542 543 checkPre(); 544 setTimes(file, expectedAccessTime, expectedModTime); 545 mixin(checkResult); 546 }); 547 548 testFileOperation!("setTimes", "Path")(() { 549 mixin(useTmpName!"file"); 550 std.file.write(file, "abc"); 551 552 checkPre(); 553 setTimes(Path(file), expectedAccessTime, expectedModTime); 554 mixin(checkResult); 555 }); 556 +/ 557 } 558 559 /// Like $(FULL_STD_FILE timeLastModified), but supports Path and command echoing. 560 SysTime timeLastModified(in Path name) 561 { 562 return timeLastModified(name.raw); 563 } 564 565 ///ditto 566 SysTime timeLastModified(in string name) 567 { 568 yapFunc(name); 569 return std.file.timeLastModified(name); 570 } 571 572 ///ditto 573 SysTime timeLastModified(in Path name, SysTime returnIfMissing) 574 { 575 return timeLastModified(name.raw, returnIfMissing); 576 } 577 578 ///ditto 579 SysTime timeLastModified(in string name, SysTime returnIfMissing) 580 { 581 yapFunc(name); 582 return std.file.timeLastModified(name, returnIfMissing); 583 } 584 585 version(unittest_scriptlike_d) 586 unittest 587 { 588 string file; 589 590 testFileOperation!("timeLastModified", "string")(() { 591 mixin(useTmpName!"file"); 592 std.file.write(file, "abc123"); 593 594 timeLastModified(file); 595 }); 596 597 testFileOperation!("timeLastModified", "Path")(() { 598 mixin(useTmpName!"file"); 599 std.file.write(file, "abc123"); 600 601 timeLastModified(Path(file)); 602 }); 603 604 testFileOperation!("timeLastModified", "string,SysTime - exists")(() { 605 mixin(useTmpName!"file"); 606 std.file.write(file, "abc123"); 607 608 auto ifMissing = SysTime(123); 609 timeLastModified(file, ifMissing); 610 }); 611 612 testFileOperation!("timeLastModified", "Path,SysTime - exists")(() { 613 mixin(useTmpName!"file"); 614 std.file.write(file, "abc123"); 615 616 auto ifMissing = SysTime(123); 617 timeLastModified(Path(file), ifMissing); 618 }); 619 620 testFileOperation!("timeLastModified", "string,SysTime - missing")(() { 621 mixin(useTmpName!"file"); 622 623 auto ifMissing = SysTime(123); 624 assert(timeLastModified(file, ifMissing) == SysTime(123)); 625 }); 626 627 testFileOperation!("timeLastModified", "Path,SysTime - missing")(() { 628 mixin(useTmpName!"file"); 629 630 auto ifMissing = SysTime(123); 631 assert(timeLastModified(Path(file), ifMissing) == SysTime(123)); 632 }); 633 } 634 635 /// Like $(FULL_STD_FILE exists), but supports Path and command echoing. 636 bool exists(in Path name) @trusted 637 { 638 return exists(name.raw); 639 } 640 641 ///ditto 642 bool exists(in string name) @trusted 643 { 644 yapFunc(name); 645 return std.file.exists(name); 646 } 647 648 version(unittest_scriptlike_d) 649 unittest 650 { 651 string file; 652 653 testFileOperation!("exists", "string")(() { 654 mixin(useTmpName!"file"); 655 656 assert(!exists(file)); 657 std.file.write(file, "abc"); 658 assert(exists(file)); 659 }); 660 661 testFileOperation!("exists", "Path")(() { 662 mixin(useTmpName!"file"); 663 664 assert(!exists(Path(file))); 665 std.file.write(file, "abc"); 666 assert(exists(Path(file))); 667 }); 668 } 669 670 /// Like $(FULL_STD_FILE getAttributes), but supports Path and command echoing. 671 uint getAttributes(in Path name) 672 { 673 return getAttributes(name.raw); 674 } 675 676 ///ditto 677 uint getAttributes(in string name) 678 { 679 yapFunc(name); 680 return std.file.getAttributes(name); 681 } 682 683 version(unittest_scriptlike_d) 684 unittest 685 { 686 string file; 687 688 testFileOperation!("getAttributes", "string")(() { 689 mixin(useTmpName!"file"); 690 std.file.write(file, "abc123"); 691 692 getAttributes(file); 693 }); 694 695 testFileOperation!("getAttributes", "Path")(() { 696 mixin(useTmpName!"file"); 697 std.file.write(file, "abc123"); 698 699 getAttributes(Path(file)); 700 }); 701 } 702 703 /// Like $(FULL_STD_FILE getLinkAttributes), but supports Path and command echoing. 704 uint getLinkAttributes(in Path name) 705 { 706 return getLinkAttributes(name.raw); 707 } 708 709 ///ditto 710 uint getLinkAttributes(in string name) 711 { 712 yapFunc(name); 713 return std.file.getLinkAttributes(name); 714 } 715 716 version(unittest_scriptlike_d) 717 unittest 718 { 719 string file; 720 721 testFileOperation!("getLinkAttributes", "string")(() { 722 mixin(useTmpName!"file"); 723 std.file.write(file, "abc123"); 724 725 getLinkAttributes(file); 726 }); 727 728 testFileOperation!("getLinkAttributes", "Path")(() { 729 mixin(useTmpName!"file"); 730 std.file.write(file, "abc123"); 731 732 getLinkAttributes(Path(file)); 733 }); 734 } 735 736 /// Like $(FULL_STD_FILE isDir), but supports Path and command echoing. 737 @property bool isDir(in Path name) 738 { 739 return isDir(name.raw); 740 } 741 742 ///ditto 743 @property bool isDir(in string name) 744 { 745 yapFunc(name); 746 return std.file.isDir(name); 747 } 748 749 version(unittest_scriptlike_d) 750 unittest 751 { 752 string file, dir; 753 754 testFileOperation!("isDir", "string")(() { 755 mixin(useTmpName!"file"); 756 mixin(useTmpName!"dir"); 757 std.file.write(file, "abc123"); 758 std.file.mkdir(dir); 759 760 assert( !isDir(file) ); 761 assert( isDir(dir) ); 762 }); 763 764 testFileOperation!("isDir", "Path")(() { 765 mixin(useTmpName!"file"); 766 mixin(useTmpName!"dir"); 767 std.file.write(file, "abc123"); 768 std.file.mkdir(dir); 769 770 assert( !isDir(Path(file)) ); 771 assert( isDir(Path(dir)) ); 772 }); 773 } 774 775 /// Like $(FULL_STD_FILE isFile), but supports Path and command echoing. 776 @property bool isFile(in Path name) 777 { 778 return isFile(name.raw); 779 } 780 781 ///ditto 782 @property bool isFile(in string name) 783 { 784 yapFunc(name); 785 return std.file.isFile(name); 786 } 787 788 version(unittest_scriptlike_d) 789 unittest 790 { 791 string file, dir; 792 793 testFileOperation!("isFile", "string")(() { 794 mixin(useTmpName!"file"); 795 mixin(useTmpName!"dir"); 796 std.file.write(file, "abc123"); 797 std.file.mkdir(dir); 798 799 assert( isFile(file) ); 800 assert( !isFile(dir) ); 801 }); 802 803 testFileOperation!("isFile", "Path")(() { 804 mixin(useTmpName!"file"); 805 mixin(useTmpName!"dir"); 806 std.file.write(file, "abc123"); 807 std.file.mkdir(dir); 808 809 assert( isFile(Path(file)) ); 810 assert( !isFile(Path(dir)) ); 811 }); 812 } 813 814 /// Like $(FULL_STD_FILE isSymlink), but supports Path and command echoing. 815 @property bool isSymlink(in Path name) 816 { 817 return isSymlink(name.raw); 818 } 819 820 ///ditto 821 @property bool isSymlink(in string name) 822 { 823 yapFunc(name); 824 return std.file.isSymlink(name); 825 } 826 827 version(unittest_scriptlike_d) 828 unittest 829 { 830 string file, dir, fileLink, dirLink; 831 832 testFileOperation!("isSymlink", "string")(() { 833 mixin(useTmpName!"file"); 834 mixin(useTmpName!"dir"); 835 mixin(useTmpName!"fileLink"); 836 mixin(useTmpName!"dirLink"); 837 std.file.write(file, "abc123"); 838 std.file.mkdir(dir); 839 version(Posix) 840 { 841 std.file.symlink(file, fileLink); 842 std.file.symlink(dir, dirLink); 843 } 844 845 assert( !isSymlink(file) ); 846 assert( !isSymlink(dir) ); 847 version(Posix) 848 { 849 assert( isSymlink(fileLink) ); 850 assert( isSymlink(dirLink) ); 851 } 852 }); 853 854 testFileOperation!("isSymlink", "Path")(() { 855 mixin(useTmpName!"file"); 856 mixin(useTmpName!"dir"); 857 mixin(useTmpName!"fileLink"); 858 mixin(useTmpName!"dirLink"); 859 std.file.write(file, "abc123"); 860 std.file.mkdir(dir); 861 version(Posix) 862 { 863 std.file.symlink(file, fileLink); 864 std.file.symlink(dir, dirLink); 865 } 866 867 assert( !isSymlink(Path(file)) ); 868 assert( !isSymlink(Path(dir)) ); 869 version(Posix) 870 { 871 assert( isSymlink(Path(fileLink)) ); 872 assert( isSymlink(Path(dirLink)) ); 873 } 874 }); 875 } 876 877 /// Like $(FULL_STD_FILE getcwd), but returns a Path. 878 Path getcwd() 879 { 880 return Path( std.file.getcwd() ); 881 } 882 883 /// Like $(FULL_STD_FILE chdir), but supports Path and command echoing. 884 void chdir(in Path pathname) 885 { 886 chdir(pathname.raw); 887 } 888 889 /// Like $(FULL_STD_FILE chdir), but supports Path and command echoing. 890 void chdir(in string pathname) 891 { 892 yapFunc(pathname.escapeShellArg()); 893 std.file.chdir(pathname); 894 } 895 896 version(unittest_scriptlike_d) 897 unittest 898 { 899 string dir; 900 901 testFileOperation!("chdir", "string")(() { 902 mixin(useTmpName!"dir"); 903 std.file.mkdir(dir); 904 auto origDir = std.file.getcwd(); 905 scope(exit) std.file.chdir(origDir); 906 907 chdir(dir); 908 assert(std.file.getcwd() == dir); 909 }); 910 911 testFileOperation!("chdir", "Path")(() { 912 mixin(useTmpName!"dir"); 913 std.file.mkdir(dir); 914 auto origDir = std.file.getcwd(); 915 scope(exit) std.file.chdir(origDir); 916 917 chdir(Path(dir)); 918 assert(std.file.getcwd() == dir); 919 }); 920 } 921 922 /// Like $(FULL_STD_FILE mkdir), but supports Path, command echoing and dryrun. 923 void mkdir(in Path pathname) 924 { 925 mkdir(pathname.raw); 926 } 927 928 ///ditto 929 void mkdir(in string pathname) 930 { 931 yapFunc(pathname.escapeShellArg()); 932 933 if(!scriptlikeDryRun) 934 std.file.mkdir(pathname); 935 } 936 937 version(unittest_scriptlike_d) 938 unittest 939 { 940 string dir; 941 void checkPre() 942 { 943 assert(!std.file.exists(dir)); 944 } 945 946 void checkPost() 947 { 948 assert(std.file.exists(dir)); 949 assert(std.file.isDir(dir)); 950 } 951 952 testFileOperation!("mkdir", "string")(() { 953 mixin(useTmpName!"dir"); 954 955 checkPre(); 956 mkdir(dir); 957 mixin(checkResult); 958 }); 959 960 testFileOperation!("mkdir", "Path")(() { 961 mixin(useTmpName!"dir"); 962 963 checkPre(); 964 mkdir(Path(dir)); 965 mixin(checkResult); 966 }); 967 } 968 969 /// Like $(FULL_STD_FILE mkdirRecurse), but supports Path, command echoing and dryrun. 970 void mkdirRecurse(in Path pathname) 971 { 972 mkdirRecurse(pathname.raw); 973 } 974 975 ///ditto 976 void mkdirRecurse(in string pathname) 977 { 978 yapFunc(pathname.escapeShellArg()); 979 980 if(!scriptlikeDryRun) 981 std.file.mkdirRecurse(pathname); 982 } 983 984 version(unittest_scriptlike_d) 985 unittest 986 { 987 string dir; 988 void checkPre() 989 { 990 assert(!std.file.exists(dir)); 991 } 992 993 void checkPost() 994 { 995 assert(std.file.exists(dir)); 996 assert(std.file.isDir(dir)); 997 } 998 999 testFileOperation!("mkdirRecurse", "string")(() { 1000 mixin(useTmpName!("dir", "subdir")); 1001 1002 checkPre(); 1003 mkdirRecurse(dir); 1004 mixin(checkResult); 1005 }); 1006 1007 testFileOperation!("mkdirRecurse", "Path")(() { 1008 mixin(useTmpName!("dir", "subdir")); 1009 1010 checkPre(); 1011 mkdirRecurse(Path(dir)); 1012 mixin(checkResult); 1013 }); 1014 } 1015 1016 /// Like $(FULL_STD_FILE rmdir), but supports Path, command echoing and dryrun. 1017 void rmdir(in Path pathname) 1018 { 1019 rmdir(pathname.raw); 1020 } 1021 1022 ///ditto 1023 void rmdir(in string pathname) 1024 { 1025 yapFunc(pathname.escapeShellArg()); 1026 1027 if(!scriptlikeDryRun) 1028 std.file.rmdir(pathname); 1029 } 1030 1031 version(unittest_scriptlike_d) 1032 unittest 1033 { 1034 string dir; 1035 void checkPre() 1036 { 1037 assert(std.file.exists(dir)); 1038 assert(std.file.isDir(dir)); 1039 } 1040 1041 void checkPost() 1042 { 1043 assert(!std.file.exists(dir)); 1044 } 1045 1046 testFileOperation!("rmdir", "string")(() { 1047 mixin(useTmpName!"dir"); 1048 std.file.mkdir(dir); 1049 1050 checkPre(); 1051 rmdir(dir); 1052 mixin(checkResult); 1053 }); 1054 1055 testFileOperation!("rmdir", "Path")(() { 1056 mixin(useTmpName!"dir"); 1057 std.file.mkdir(dir); 1058 1059 checkPre(); 1060 rmdir(Path(dir)); 1061 mixin(checkResult); 1062 }); 1063 } 1064 1065 version(docs_scriptlike_d) 1066 { 1067 /// Posix-only. Like $(FULL_STD_FILE symlink), but supports Path and command echoing. 1068 void symlink(Path original, Path link); 1069 1070 ///ditto 1071 void symlink(string original, Path link); 1072 1073 ///ditto 1074 void symlink(Path original, string link); 1075 1076 ///ditto 1077 void symlink(string original, string link); 1078 1079 /// Posix-only. Like $(FULL_STD_FILE readLink), but supports Path and command echoing. 1080 Path readLink(Path link); 1081 1082 ///ditto 1083 string readLink(string link); 1084 } 1085 else version(Posix) 1086 { 1087 void symlink(Path original, Path link) 1088 { 1089 symlink(original.raw, link.raw); 1090 } 1091 1092 void symlink(string original, Path link) 1093 { 1094 symlink(original, link.raw); 1095 } 1096 1097 void symlink(Path original, string link) 1098 { 1099 symlink(original.raw, link); 1100 } 1101 1102 void symlink(string original, string link) 1103 { 1104 yapFunc("[original] ", original.escapeShellArg(), " : [symlink] ", link.escapeShellArg()); 1105 1106 if(!scriptlikeDryRun) 1107 std.file.symlink(original, link); 1108 } 1109 1110 version(unittest_scriptlike_d) 1111 unittest 1112 { 1113 string file, link; 1114 void checkPre() 1115 { 1116 assert(std.file.exists(file)); 1117 assert(std.file.isFile(file)); 1118 assert(cast(string) std.file.read(file) == "abc123"); 1119 1120 assert(!std.file.exists(link)); 1121 } 1122 1123 void checkPost() 1124 { 1125 assert(std.file.exists(file)); 1126 assert(std.file.isFile(file)); 1127 assert(cast(string) std.file.read(file) == "abc123"); 1128 1129 assert(std.file.exists(link)); 1130 assert(std.file.isSymlink(link)); 1131 assert(std.file.readLink(link) == file); 1132 assert(cast(string) std.file.read(link) == "abc123"); 1133 } 1134 1135 testFileOperation!("symlink", "string,string")(() { 1136 mixin(useTmpName!"file"); 1137 mixin(useTmpName!"link"); 1138 std.file.write(file, "abc123"); 1139 1140 checkPre(); 1141 symlink(file, link); 1142 mixin(checkResult); 1143 }); 1144 1145 testFileOperation!("symlink", "string,Path")(() { 1146 mixin(useTmpName!"file"); 1147 mixin(useTmpName!"link"); 1148 std.file.write(file, "abc123"); 1149 1150 checkPre(); 1151 symlink(file, Path(link)); 1152 mixin(checkResult); 1153 }); 1154 1155 testFileOperation!("symlink", "Path,string")(() { 1156 mixin(useTmpName!"file"); 1157 mixin(useTmpName!"link"); 1158 std.file.write(file, "abc123"); 1159 1160 checkPre(); 1161 symlink(Path(file), link); 1162 mixin(checkResult); 1163 }); 1164 1165 testFileOperation!("symlink", "Path,Path")(() { 1166 mixin(useTmpName!"file"); 1167 mixin(useTmpName!"link"); 1168 std.file.write(file, "abc123"); 1169 1170 checkPre(); 1171 symlink(Path(file), Path(link)); 1172 mixin(checkResult); 1173 }); 1174 } 1175 1176 Path readLink(Path link) 1177 { 1178 return Path( readLink(link.raw) ); 1179 } 1180 1181 string readLink(string link) 1182 { 1183 yapFunc(link); 1184 return std.file.readLink(link); 1185 } 1186 1187 version(unittest_scriptlike_d) 1188 unittest 1189 { 1190 string file, link; 1191 1192 testFileOperation!("readLink", "string")(() { 1193 mixin(useTmpName!"file"); 1194 mixin(useTmpName!"link"); 1195 std.file.write(file, "abc123"); 1196 std.file.symlink(file, link); 1197 1198 assert(readLink(link) == file); 1199 }); 1200 1201 testFileOperation!("readLink", "Path")(() { 1202 mixin(useTmpName!"file"); 1203 mixin(useTmpName!"link"); 1204 std.file.write(file, "abc123"); 1205 std.file.symlink(file, link); 1206 1207 assert(readLink(Path(link)) == Path(file)); 1208 }); 1209 } 1210 } 1211 1212 /// Like $(FULL_STD_FILE copy), but supports Path, command echoing and dryrun. 1213 void copy(in Path from, in Path to) 1214 { 1215 copy(from.raw, to.raw); 1216 } 1217 1218 ///ditto 1219 void copy(in string from, in Path to) 1220 { 1221 copy(from, to.raw); 1222 } 1223 1224 ///ditto 1225 void copy(in Path from, in string to) 1226 { 1227 copy(from.raw, to); 1228 } 1229 1230 ///ditto 1231 void copy(in string from, in string to) 1232 { 1233 yapFunc(from.escapeShellArg(), " -> ", to.escapeShellArg()); 1234 1235 if(!scriptlikeDryRun) 1236 std.file.copy(from, to); 1237 } 1238 1239 version(unittest_scriptlike_d) 1240 unittest 1241 { 1242 string file1; 1243 string file2; 1244 void checkPre() 1245 { 1246 assert(std.file.exists(file1)); 1247 assert(std.file.isFile(file1)); 1248 assert(cast(string) std.file.read(file1) == "abc"); 1249 1250 assert(!std.file.exists(file2)); 1251 } 1252 1253 void checkPost() 1254 { 1255 assert(std.file.exists(file1)); 1256 assert(std.file.isFile(file1)); 1257 assert(cast(string) std.file.read(file1) == "abc"); 1258 1259 assert(std.file.exists(file2)); 1260 assert(std.file.isFile(file2)); 1261 assert(cast(string) std.file.read(file2) == "abc"); 1262 } 1263 1264 testFileOperation!("copy", "string,string")(() { 1265 mixin(useTmpName!"file1"); 1266 mixin(useTmpName!"file2"); 1267 std.file.write(file1, "abc"); 1268 1269 checkPre(); 1270 copy(file1, file2); 1271 mixin(checkResult); 1272 }); 1273 1274 testFileOperation!("copy", "string,Path")(() { 1275 mixin(useTmpName!"file1"); 1276 mixin(useTmpName!"file2"); 1277 std.file.write(file1, "abc"); 1278 1279 checkPre(); 1280 copy(file1, Path(file2)); 1281 mixin(checkResult); 1282 }); 1283 1284 testFileOperation!("copy", "Path,string")(() { 1285 mixin(useTmpName!"file1"); 1286 mixin(useTmpName!"file2"); 1287 std.file.write(file1, "abc"); 1288 1289 checkPre(); 1290 copy(Path(file1), file2); 1291 mixin(checkResult); 1292 }); 1293 1294 testFileOperation!("copy", "Path,Path")(() { 1295 mixin(useTmpName!"file1"); 1296 mixin(useTmpName!"file2"); 1297 std.file.write(file1, "abc"); 1298 1299 checkPre(); 1300 copy(Path(file1), Path(file2)); 1301 mixin(checkResult); 1302 }); 1303 } 1304 1305 /// Like $(FULL_STD_FILE rmdirRecurse), but supports Path, command echoing and dryrun. 1306 void rmdirRecurse(in Path pathname) 1307 { 1308 rmdirRecurse(pathname.raw); 1309 } 1310 1311 ///ditto 1312 void rmdirRecurse(in string pathname) 1313 { 1314 yapFunc(pathname.escapeShellArg()); 1315 1316 if(!scriptlikeDryRun) 1317 std.file.rmdirRecurse(pathname); 1318 } 1319 1320 version(unittest_scriptlike_d) 1321 unittest 1322 { 1323 string dir; 1324 void checkPre() 1325 { 1326 assert(std.file.exists(dir)); 1327 assert(std.file.isDir(dir)); 1328 } 1329 1330 void checkPost() 1331 { 1332 assert(!std.file.exists( std.path.dirName(dir) )); 1333 } 1334 1335 testFileOperation!("rmdirRecurse", "string")(() { 1336 mixin(useTmpName!("dir", "subdir")); 1337 std.file.mkdirRecurse(dir); 1338 1339 checkPre(); 1340 rmdirRecurse( std.path.dirName(dir) ); 1341 mixin(checkResult); 1342 }); 1343 1344 testFileOperation!("rmdirRecurse", "Path")(() { 1345 mixin(useTmpName!("dir", "subdir")); 1346 std.file.mkdirRecurse(dir); 1347 1348 checkPre(); 1349 rmdirRecurse(Path( std.path.dirName(dir) )); 1350 mixin(checkResult); 1351 }); 1352 } 1353 1354 /// Like $(FULL_STD_FILE dirEntries), but supports Path and command echoing. 1355 auto dirEntries(string path, SpanMode mode, bool followSymlink = true) 1356 { 1357 yapFunc(path); 1358 return std.file.dirEntries(path, mode, followSymlink); 1359 } 1360 1361 ///ditto 1362 auto dirEntries(Path path, SpanMode mode, bool followSymlink = true) 1363 { 1364 return dirEntries(path.raw, mode, followSymlink); 1365 } 1366 1367 ///ditto 1368 auto dirEntries(string path, string pattern, SpanMode mode, 1369 bool followSymlink = true) 1370 { 1371 yapFunc(path); 1372 return std.file.dirEntries(path, pattern, mode, followSymlink); 1373 } 1374 1375 ///ditto 1376 auto dirEntries(Path path, string pattern, SpanMode mode, 1377 bool followSymlink = true) 1378 { 1379 return dirEntries(path.raw, pattern, mode, followSymlink); 1380 } 1381 1382 version(unittest_scriptlike_d) 1383 unittest 1384 { 1385 string dir; 1386 1387 testFileOperation!("dirEntries", "string")(() { 1388 mixin(useTmpName!("dir", "subdir")); 1389 std.file.mkdirRecurse(dir); 1390 1391 auto range = dirEntries(std.path.dirName(dir), SpanMode.shallow); 1392 assert(range.front.name == dir); 1393 range.popFront(); 1394 assert(range.empty); 1395 }); 1396 1397 testFileOperation!("dirEntries", "Path")(() { 1398 mixin(useTmpName!("dir", "subdir")); 1399 std.file.mkdirRecurse(dir); 1400 1401 auto range = dirEntries(Path(std.path.dirName(dir)), SpanMode.shallow); 1402 assert(range.front.name == dir); 1403 range.popFront(); 1404 assert(range.empty); 1405 }); 1406 1407 testFileOperation!("dirEntries", "string,pattern")(() { 1408 mixin(useTmpName!("dir", "subdir")); 1409 std.file.mkdirRecurse(dir); 1410 1411 auto range = dirEntries(std.path.dirName(dir), "*", SpanMode.shallow); 1412 assert(range.front.name == dir); 1413 range.popFront(); 1414 assert(range.empty); 1415 }); 1416 1417 testFileOperation!("dirEntries", "Path,pattern")(() { 1418 mixin(useTmpName!("dir", "subdir")); 1419 std.file.mkdirRecurse(dir); 1420 1421 auto range = dirEntries(Path(std.path.dirName(dir)), "*", SpanMode.shallow); 1422 assert(range.front.name == dir); 1423 range.popFront(); 1424 assert(range.empty); 1425 }); 1426 } 1427 1428 /// Like $(FULL_STD_FILE slurp), but supports Path and command echoing. 1429 auto slurp(Types...)(Path filename, in string format) 1430 { 1431 return slurp!Types(filename.raw, format); 1432 } 1433 1434 ///ditto 1435 auto slurp(Types...)(string filename, in string format) 1436 { 1437 yapFunc(filename); 1438 return std.file.slurp!Types(filename, format); 1439 } 1440 1441 version(unittest_scriptlike_d) 1442 unittest 1443 { 1444 string file; 1445 1446 testFileOperation!("slurp", "string")(() { 1447 mixin(useTmpName!"file"); 1448 std.file.write(file, "abc, 123"); 1449 1450 auto result = slurp!(string, int)(file, "%s, %s"); 1451 auto expected = [Tuple!(string, int)("abc", 123)]; 1452 assert(result == expected); 1453 }); 1454 1455 testFileOperation!("slurp", "Path")(() { 1456 mixin(useTmpName!"file"); 1457 std.file.write(file, "abc, 123"); 1458 1459 auto result = slurp!(string, int)(Path(file), "%s, %s"); 1460 auto expected = [Tuple!(string, int)("abc", 123)]; 1461 assert(result == expected); 1462 }); 1463 } 1464 1465 /// Like $(FULL_STD_FILE thisExePath), but supports Path and command echoing. 1466 @trusted Path thisExePath() 1467 { 1468 auto path = Path( std.file.thisExePath() ); 1469 yapFunc(path); 1470 return path; 1471 } 1472 1473 version(unittest_scriptlike_d) 1474 unittest 1475 { 1476 testFileOperation!("thisExePath", "Path")(() { 1477 thisExePath(); 1478 }); 1479 } 1480 1481 /// Like $(FULL_STD_FILE tempDir), but supports Path and command echoing. 1482 @trusted Path tempDir() 1483 { 1484 auto path = Path( std.file.tempDir() ); 1485 yapFunc(path); 1486 return path; 1487 } 1488 1489 version(unittest_scriptlike_d) 1490 unittest 1491 { 1492 testFileOperation!("tempDir", "Path")(() { 1493 assert( tempDir() == Path(std.file.tempDir()) ); 1494 }); 1495 }