1 module seed; 2 3 // -- IMPORTS 4 5 import core.stdc.stdlib : exit; 6 import std.ascii : isDigit, isLower, isUpper; 7 import std.conv : to; 8 import std.file : dirEntries, exists, mkdirRecurse, read, readText, remove, rmdir, thisExePath, write, SpanMode; 9 import std.path : dirName; 10 import std.stdio : writeln; 11 import std.string : capitalize, endsWith, indexOf, join, lastIndexOf, replace, split, startsWith, strip, stripRight, toLower, toUpper; 12 import std.uni : isAlpha; 13 14 // -- TYPES 15 16 enum VERBOSITY 17 { 18 Error, 19 Warning, 20 Activity, 21 Action, 22 Operation, 23 Information, 24 Debug 25 } 26 27 // -- VARIABLES 28 29 VERBOSITY 30 Verbosity = VERBOSITY.Debug; 31 32 // -- FUNCTIONS 33 34 void SetVerbosity( 35 VERBOSITY verbosity 36 ) 37 { 38 Verbosity = verbosity; 39 } 40 41 // ~~ 42 43 bool HasVerbosity( 44 VERBOSITY verbosity 45 ) 46 { 47 return Verbosity >= verbosity; 48 } 49 50 // ~~ 51 52 void PrintWarning( 53 string message 54 ) 55 { 56 writeln( "*** WARNING : ", message ); 57 } 58 59 // ~~ 60 61 void PrintError( 62 string message 63 ) 64 { 65 writeln( "*** ERROR : ", message ); 66 } 67 68 // ~~ 69 70 void Abort( 71 string message 72 ) 73 { 74 PrintError( message ); 75 76 exit( -1 ); 77 } 78 79 // ~~ 80 81 void Abort( 82 string message, 83 Exception exception 84 ) 85 { 86 PrintError( message ); 87 PrintError( exception.msg ); 88 89 exit( -1 ); 90 } 91 92 // ~~ 93 94 bool IsLinux( 95 ) 96 { 97 version ( linux ) 98 { 99 return true; 100 } 101 else 102 { 103 return false; 104 } 105 } 106 107 // ~~ 108 109 bool IsMacOs( 110 ) 111 { 112 version ( OSX ) 113 { 114 return true; 115 } 116 else 117 { 118 return false; 119 } 120 } 121 122 // ~~ 123 124 bool IsWindows( 125 ) 126 { 127 version ( Windows ) 128 { 129 return true; 130 } 131 else 132 { 133 return false; 134 } 135 } 136 137 // ~~ 138 139 bool IsAlphabeticalCharacter( 140 char character 141 ) 142 { 143 return 144 ( character >= 'a' && character <= 'z' ) 145 || ( character >= 'A' && character <= 'Z' ); 146 } 147 148 // ~~ 149 150 bool IsIdentifierCharacter( 151 char character 152 ) 153 { 154 return 155 ( character >= 'a' && character <= 'z' ) 156 || ( character >= 'A' && character <= 'Z' ) 157 || ( character >= '0' && character <= '9' ) 158 || character == '_'; 159 } 160 161 // ~~ 162 163 bool IsDecimalCharacter( 164 char character 165 ) 166 { 167 return ( character >= '0' && character <= '9' ); 168 } 169 170 // ~~ 171 172 bool IsDecimalCharacter( 173 dchar character 174 ) 175 { 176 return ( character >= '0' && character <= '9' ); 177 } 178 179 // ~~ 180 181 bool IsNumberCharacter( 182 char character 183 ) 184 { 185 return 186 ( character >= '0' && character <= '9' ) 187 || character == '.' 188 || character == '-' 189 || character == 'e' 190 || character == 'E'; 191 } 192 193 // ~~ 194 195 bool IsSpaceCharacter( 196 dchar character 197 ) 198 { 199 return 200 character == dchar( ' ' ) 201 || character == dchar( '\t' ) 202 || character == dchar( 0xA0 ); 203 } 204 205 // ~~ 206 207 bool IsDigitCharacter( 208 dchar character 209 ) 210 { 211 return 212 character >= '0' 213 && character <= '9'; 214 } 215 216 // ~~ 217 218 bool IsVowelCharacter( 219 char character 220 ) 221 { 222 return "aeiouy".indexOf( character ) >= 0; 223 } 224 225 // ~~ 226 227 bool IsConsonantCharacter( 228 char character 229 ) 230 { 231 return "bcdfghjklmnpqrstvwx".indexOf( character ) >= 0; 232 } 233 234 // ~~ 235 236 bool StartsByVowel( 237 string text 238 ) 239 { 240 return 241 text != "" 242 && IsVowelCharacter( text[ 0 ] ); 243 } 244 245 // ~~ 246 247 bool StartsByConsonant( 248 string text 249 ) 250 { 251 return 252 text != "" 253 && IsConsonantCharacter( text[ 0 ] ); 254 } 255 256 // ~~ 257 258 bool EndsByVowel( 259 string text 260 ) 261 { 262 return 263 text != "" 264 && IsVowelCharacter( text[ $ - 1 ] ); 265 } 266 267 // ~~ 268 269 bool EndsByConsonant( 270 string text 271 ) 272 { 273 return 274 text != "" 275 && IsConsonantCharacter( text[ $ - 1 ] ); 276 } 277 278 // ~~ 279 280 string GetBooleanText( 281 bool boolean 282 ) 283 { 284 if ( boolean ) 285 { 286 return "true"; 287 } 288 else 289 { 290 return "false"; 291 } 292 } 293 294 // ~~ 295 296 bool IsNatural( 297 string text 298 ) 299 { 300 if ( text.length > 0 ) 301 { 302 foreach ( character; text ) 303 { 304 if ( character < '0' 305 || character > '9' ) 306 { 307 return false; 308 } 309 } 310 311 return true; 312 } 313 else 314 { 315 return false; 316 } 317 } 318 319 // ~~ 320 321 bool IsInteger( 322 string text 323 ) 324 { 325 if ( text.length > 0 326 && text[ 0 ] == '-' ) 327 { 328 text = text[ 1 .. $ ]; 329 } 330 331 return IsNatural( text ); 332 } 333 334 // ~~ 335 336 ulong GetNatural( 337 string text 338 ) 339 { 340 try 341 { 342 return text.to!ulong(); 343 } 344 catch ( Exception exception ) 345 { 346 Abort( "Invalid natural : " ~ text, exception ); 347 } 348 349 return 0; 350 } 351 352 // ~~ 353 354 long GetInteger( 355 string text 356 ) 357 { 358 try 359 { 360 return text.to!long(); 361 } 362 catch ( Exception exception ) 363 { 364 Abort( "Invalid integer : " ~ text, exception ); 365 } 366 367 return 0; 368 } 369 370 // ~~ 371 372 double GetReal( 373 long integer 374 ) 375 { 376 return integer.to!double(); 377 } 378 379 // ~~ 380 381 double GetReal( 382 string text 383 ) 384 { 385 try 386 { 387 return text.to!double(); 388 } 389 catch ( Exception exception ) 390 { 391 Abort( "Invalid real : " ~ text, exception ); 392 } 393 394 return 0.0; 395 } 396 397 // ~~ 398 399 bool ContainsText( 400 string text, 401 string searched_text 402 ) 403 { 404 return text.indexOf( searched_text ) >= 0; 405 } 406 407 // ~~ 408 409 bool HasPrefix( 410 string text, 411 string prefix 412 ) 413 { 414 return text.startsWith( prefix ); 415 } 416 417 // ~~ 418 419 bool HasSuffix( 420 string text, 421 string suffix 422 ) 423 { 424 return text.endsWith( suffix ); 425 } 426 427 // ~~ 428 429 string GetPrefix( 430 string text, 431 string separator 432 ) 433 { 434 return text.split( separator )[ 0 ]; 435 } 436 437 // ~~ 438 439 string GetSuffix( 440 string text, 441 string separator 442 ) 443 { 444 return text.split( separator )[ $ - 1 ]; 445 } 446 447 // ~~ 448 449 string AddPrefix( 450 string text, 451 string prefix 452 ) 453 { 454 return prefix ~ text; 455 } 456 457 // ~~ 458 459 string AddSuffix( 460 string text, 461 string suffix 462 ) 463 { 464 return text ~ suffix; 465 } 466 467 // ~~ 468 469 string RemovePrefix( 470 string text, 471 string prefix 472 ) 473 { 474 if ( text.startsWith( prefix ) ) 475 { 476 return text[ prefix.length .. $ ]; 477 } 478 else 479 { 480 return text; 481 } 482 } 483 484 // ~~ 485 486 string RemoveSuffix( 487 string text, 488 string suffix 489 ) 490 { 491 if ( text.endsWith( suffix ) ) 492 { 493 return text[ 0 .. $ - suffix.length ]; 494 } 495 else 496 { 497 return text; 498 } 499 } 500 501 // ~~ 502 503 string ReplacePrefix( 504 string text, 505 string old_prefix, 506 string new_prefix 507 ) 508 { 509 if ( text.startsWith( old_prefix ) ) 510 { 511 return new_prefix ~ text[ old_prefix.length .. $ ]; 512 } 513 else 514 { 515 return text; 516 } 517 } 518 519 // ~~ 520 521 string ReplaceSuffix( 522 string text, 523 string old_suffix, 524 string new_suffix 525 ) 526 { 527 if ( text.endsWith( old_suffix ) ) 528 { 529 return text[ 0 .. $ - old_suffix.length ] ~ new_suffix; 530 } 531 else 532 { 533 return text; 534 } 535 } 536 537 // ~~ 538 539 string ReplaceText( 540 string text, 541 string old_text, 542 string new_text 543 ) 544 { 545 return text.replace( old_text, new_text ); 546 } 547 548 // ~~ 549 550 string GetStrippedText( 551 string text 552 ) 553 { 554 dstring 555 unicode_text; 556 557 unicode_text = text.to!dstring(); 558 559 while ( unicode_text.length > 0 560 && IsSpaceCharacter( unicode_text[ 0 ] ) ) 561 { 562 unicode_text = unicode_text[ 1 .. $ ]; 563 } 564 565 while ( unicode_text.length > 0 566 && IsSpaceCharacter( unicode_text[ $ - 1 ] ) ) 567 { 568 unicode_text = unicode_text[ 0 .. $ - 1 ]; 569 } 570 571 return unicode_text.to!string(); 572 } 573 574 // ~~ 575 576 string GetLeftStrippedText( 577 string text 578 ) 579 { 580 dstring 581 unicode_text; 582 583 unicode_text = text.to!dstring(); 584 585 while ( unicode_text.length > 0 586 && IsSpaceCharacter( unicode_text[ 0 ] ) ) 587 { 588 unicode_text = unicode_text[ 1 .. $ ]; 589 } 590 591 return unicode_text.to!string(); 592 } 593 594 // ~~ 595 596 string GetRightStrippedText( 597 string text 598 ) 599 { 600 dstring 601 unicode_text; 602 603 unicode_text = text.to!dstring(); 604 605 while ( unicode_text.length > 0 606 && IsSpaceCharacter( unicode_text[ $ - 1 ] ) ) 607 { 608 unicode_text = unicode_text[ 0 .. $ - 1 ]; 609 } 610 611 return unicode_text.to!string(); 612 } 613 614 // ~~ 615 616 dstring GetUnaccentedCharacter( 617 dchar character, 618 string language_code = "", 619 bool next_character_is_lower_case = false 620 ) 621 { 622 switch ( character ) 623 { 624 case 'á', 'à', 'â' : 625 { 626 return "a"; 627 } 628 case 'ä' : 629 { 630 if ( language_code == "de" ) 631 { 632 return "ae"; 633 } 634 else 635 { 636 return "a"; 637 } 638 } 639 case 'é', 'è', 'ê', 'ë' : 640 { 641 return "e"; 642 } 643 case 'í', 'ì', 'î', 'ï' : 644 { 645 return "i"; 646 } 647 case 'ó', 'ò', 'ô' : 648 { 649 return "o"; 650 } 651 case 'ö' : 652 { 653 if ( language_code == "de" ) 654 { 655 return "oe"; 656 } 657 else 658 { 659 return "o"; 660 } 661 } 662 case 'œ' : 663 { 664 return "oe"; 665 } 666 case 'ú', 'ù', 'û' : 667 { 668 return "u"; 669 } 670 case 'ü' : 671 { 672 if ( language_code == "de" ) 673 { 674 return "ue"; 675 } 676 else 677 { 678 return "u"; 679 } 680 } 681 case 'ç' : 682 { 683 return "c"; 684 } 685 case 'ñ' : 686 { 687 return "n"; 688 } 689 case 'ß' : 690 { 691 return "ss"; 692 } 693 case 'Á', 'À', 'Â' : 694 { 695 return "A"; 696 } 697 case 'Ä' : 698 { 699 if ( language_code == "de" ) 700 { 701 if ( next_character_is_lower_case ) 702 { 703 return "Ae"; 704 } 705 else 706 { 707 return "AE"; 708 } 709 } 710 else 711 { 712 return "A"; 713 } 714 } 715 case 'É', 'È', 'Ê', 'Ë' : 716 { 717 return "E"; 718 } 719 case 'Í', 'Ì', 'Î' : 720 { 721 return "I"; 722 } 723 case 'Ï' : 724 { 725 return "I"; 726 } 727 case 'Ó', 'Ò', 'Ô' : 728 { 729 return "O"; 730 } 731 case 'Ö' : 732 { 733 if ( language_code == "de" ) 734 { 735 if ( next_character_is_lower_case ) 736 { 737 return "Oe"; 738 } 739 else 740 { 741 return "OE"; 742 } 743 } 744 else 745 { 746 return "O"; 747 } 748 } 749 case 'Œ' : 750 { 751 return "Oe"; 752 } 753 case 'Ú', 'Ù', 'Û' : 754 { 755 return "U"; 756 } 757 case 'Ü' : 758 { 759 if ( language_code == "de" ) 760 { 761 if ( next_character_is_lower_case ) 762 { 763 return "Ue"; 764 } 765 else 766 { 767 return "UE"; 768 } 769 } 770 else 771 { 772 return "U"; 773 } 774 } 775 case 'Ç' : 776 { 777 return "C"; 778 } 779 case 'Ñ' : 780 { 781 return "N"; 782 } 783 case 'ẞ' : 784 { 785 if ( next_character_is_lower_case ) 786 { 787 return "Ss"; 788 } 789 else 790 { 791 return "SS"; 792 } 793 } 794 default : 795 { 796 return character.to!dstring(); 797 } 798 } 799 } 800 801 // ~~ 802 803 string GetUnaccentedText( 804 string text, 805 string language_code = "" 806 ) 807 { 808 dstring 809 unaccented_text, 810 unicode_text; 811 812 unicode_text = text.to!dstring(); 813 814 foreach ( character; unicode_text ) 815 { 816 unaccented_text ~= GetUnaccentedCharacter( character, language_code ); 817 } 818 819 return unaccented_text.to!string(); 820 } 821 822 // ~~ 823 824 string GetMinorCaseText( 825 string text 826 ) 827 { 828 dstring 829 unicode_text; 830 831 if ( text == "" ) 832 { 833 return ""; 834 } 835 else 836 { 837 unicode_text = text.to!dstring(); 838 839 return ( unicode_text[ 0 .. 1 ].toLower() ~ unicode_text[ 1 .. $ ] ).to!string(); 840 } 841 } 842 843 // ~~ 844 845 string GetMajorCaseText( 846 string text 847 ) 848 { 849 dstring 850 unicode_text; 851 852 if ( text == "" ) 853 { 854 return ""; 855 } 856 else 857 { 858 unicode_text = text.to!dstring(); 859 860 return ( unicode_text[ 0 .. 1 ].capitalize() ~ unicode_text[ 1 .. $ ] ).to!string(); 861 } 862 } 863 864 // ~~ 865 866 string GetLowerCaseText( 867 string text 868 ) 869 { 870 return text.toLower(); 871 } 872 873 // ~~ 874 875 string GetUpperCaseText( 876 string text 877 ) 878 { 879 return text.toUpper(); 880 } 881 882 // ~~ 883 884 string GetSpacedText( 885 string text 886 ) 887 { 888 foreach ( character; [ '\t', '_', '-', ',', ';', ':', '.', '!', '?' ] ) 889 { 890 text = text.replace( character, ' ' ); 891 } 892 893 while ( text.indexOf( " " ) >= 0 ) 894 { 895 text = text.replace( " ", " " ); 896 } 897 898 return text; 899 } 900 901 // ~~ 902 903 string GetPascalCaseText( 904 string text 905 ) 906 { 907 string[] 908 word_array; 909 910 word_array = text.GetSpacedText().strip().split( ' ' ); 911 912 foreach ( ref word; word_array ) 913 { 914 word = word.GetMajorCaseText(); 915 } 916 917 return word_array.join( "" ); 918 } 919 920 // ~~ 921 922 string GetCamelCaseText( 923 string text 924 ) 925 { 926 return text.GetPascalCaseText().GetMinorCaseText(); 927 } 928 929 // ~~ 930 931 string GetSnakeCaseText( 932 string text 933 ) 934 { 935 dchar 936 character, 937 next_character, 938 prior_character; 939 long 940 character_index; 941 dstring 942 snake_case_text, 943 unicode_text; 944 945 unicode_text = text.GetSpacedText().strip().to!dstring(); 946 947 snake_case_text = ""; 948 prior_character = 0; 949 950 for ( character_index = 0; 951 character_index < unicode_text.length; 952 ++character_index ) 953 { 954 character = unicode_text[ character_index ]; 955 956 if ( character_index + 1 < unicode_text.length ) 957 { 958 next_character = unicode_text[ character_index + 1 ]; 959 } 960 else 961 { 962 next_character = 0; 963 } 964 965 if ( ( prior_character.isLower() 966 && ( character.isUpper() 967 || character.isDigit() ) ) 968 || ( prior_character.isDigit() 969 && ( character.isLower() 970 || character.isUpper() ) ) 971 || ( prior_character.isUpper() 972 && character.isUpper() 973 && next_character.isLower() ) ) 974 { 975 snake_case_text ~= '_'; 976 } 977 978 if ( character == ' ' 979 && !snake_case_text.endsWith( '_' ) ) 980 { 981 character = '_'; 982 } 983 984 snake_case_text ~= character; 985 prior_character = character; 986 } 987 988 return snake_case_text.to!string().toLower(); 989 } 990 991 // ~~ 992 993 string GetKebabCaseText( 994 string text 995 ) 996 { 997 return GetSnakeCaseText( text ).replace( '_', '-' ); 998 } 999 1000 // ~~ 1001 1002 string GetSlugCaseText( 1003 string text, 1004 string language_code = "" 1005 ) 1006 { 1007 dstring 1008 slug_case_text, 1009 unicode_text; 1010 1011 unicode_text = text.GetUnaccentedText().GetSpacedText().strip().to!dstring(); 1012 1013 foreach ( character; unicode_text ) 1014 { 1015 if ( character.isAlpha() ) 1016 { 1017 slug_case_text ~= character.toLower(); 1018 } 1019 else if ( character >= '0' 1020 && character <= '9' ) 1021 { 1022 if ( slug_case_text != "" 1023 && !slug_case_text.endsWith( '-' ) 1024 && !IsDecimalCharacter( slug_case_text[ $ - 1 ] ) ) 1025 { 1026 slug_case_text ~= '-'; 1027 } 1028 1029 slug_case_text ~= character; 1030 } 1031 else 1032 { 1033 if ( !slug_case_text.endsWith( '-' ) ) 1034 { 1035 slug_case_text ~= '-'; 1036 } 1037 } 1038 } 1039 1040 while ( slug_case_text.endsWith( '-' ) ) 1041 { 1042 slug_case_text = slug_case_text[ 0 .. $ - 1 ]; 1043 } 1044 1045 return slug_case_text.to!string(); 1046 } 1047 1048 // ~~ 1049 1050 string GetSearchCaseText( 1051 string text, 1052 string language_code = "" 1053 ) 1054 { 1055 return GetSlugCaseText( text, language_code ).replace( '-', ' ' ); 1056 } 1057 1058 // ~~ 1059 1060 string GetFileCaseText( 1061 string text 1062 ) 1063 { 1064 return GetSlugCaseText( text ).replace( '-', '_' ); 1065 } 1066 1067 // ~~ 1068 1069 string GetBasilText( 1070 string text 1071 ) 1072 { 1073 return 1074 text 1075 .replace( "\\", "\\\\" ) 1076 .replace( "~", "\\~" ) 1077 .replace( "^", "\\^" ) 1078 .replace( "{", "\\{" ) 1079 .replace( "}", "\\}" ) 1080 .replace( "\n", "\\n" ) 1081 .replace( "\r", "\\r" ) 1082 .replace( "\t", "\\t" ) 1083 .ReplacePrefix( "#", "\\#" ) 1084 .ReplacePrefix( "%", "\\%" ) 1085 .ReplacePrefix( " ", "^" ) 1086 .ReplaceSuffix( " ", "^" ); 1087 } 1088 1089 // ~~ 1090 1091 string GetCsvText( 1092 string text 1093 ) 1094 { 1095 if ( text.indexOf( '"' ) >= 0 1096 || text.indexOf( ',' ) >= 0 1097 || text.indexOf( '\r' ) >= 0 1098 || text.indexOf( '\n' ) >= 0 ) 1099 { 1100 return "\"" ~ text.replace( "\"", "\"\"" ) ~ "\""; 1101 } 1102 else 1103 { 1104 return text; 1105 } 1106 } 1107 1108 // ~~ 1109 1110 string GetJsonText( 1111 string text 1112 ) 1113 { 1114 return 1115 "\"" 1116 ~ text 1117 .replace( "\\", "\\\\" ) 1118 .replace( "\n", "\\n" ) 1119 .replace( "\r", "\\r" ) 1120 .replace( "\t", "\\t" ) 1121 .replace( "\"", "\\\"" ) 1122 ~ "\""; 1123 } 1124 1125 // ~~ 1126 1127 string GetSqlText( 1128 string text 1129 ) 1130 { 1131 return 1132 "\"" 1133 ~ text 1134 .replace( "\\", "\\\\" ) 1135 .replace( "\n", "\\n" ) 1136 .replace( "\r", "\\r" ) 1137 .replace( "\t", "\\t" ) 1138 .replace( "\"", "\\\"" ) 1139 .replace( "'", "\\'" ) 1140 ~ "\""; 1141 } 1142 1143 // ~~ 1144 1145 string GetExecutablePath( 1146 string file_name 1147 ) 1148 { 1149 return dirName( thisExePath() ) ~ "/" ~ file_name; 1150 } 1151 1152 1153 1154 // ~~ 1155 1156 string GetLogicalPath( 1157 string path 1158 ) 1159 { 1160 return path.replace( '\\', '/' ); 1161 } 1162 1163 // ~~ 1164 1165 string GetFolderPath( 1166 string file_path 1167 ) 1168 { 1169 long 1170 slash_character_index; 1171 1172 slash_character_index = file_path.GetLogicalPath().lastIndexOf( '/' ); 1173 1174 if ( slash_character_index >= 0 ) 1175 { 1176 return file_path[ 0 .. slash_character_index + 1 ]; 1177 } 1178 else 1179 { 1180 return ""; 1181 } 1182 } 1183 1184 // ~~ 1185 1186 string GetFileName( 1187 string file_path 1188 ) 1189 { 1190 long 1191 slash_character_index; 1192 1193 slash_character_index = file_path.GetLogicalPath().lastIndexOf( '/' ); 1194 1195 if ( slash_character_index >= 0 ) 1196 { 1197 return file_path[ slash_character_index + 1 .. $ ]; 1198 } 1199 else 1200 { 1201 return file_path; 1202 } 1203 } 1204 1205 // ~~ 1206 1207 string GetFileLabel( 1208 string file_path 1209 ) 1210 { 1211 long 1212 dot_character_index; 1213 string 1214 file_name; 1215 1216 file_name = file_path.GetFileName(); 1217 dot_character_index = file_name.lastIndexOf( '.' ); 1218 1219 if ( dot_character_index >= 0 ) 1220 { 1221 return file_name[ 0 .. dot_character_index ]; 1222 } 1223 else 1224 { 1225 return file_name; 1226 } 1227 } 1228 1229 // ~~ 1230 1231 string GetFileExtension( 1232 string file_path 1233 ) 1234 { 1235 long 1236 dot_character_index; 1237 string 1238 file_name; 1239 1240 file_name = file_path.GetFileName(); 1241 dot_character_index = file_name.lastIndexOf( '.' ); 1242 1243 if ( dot_character_index >= 0 ) 1244 { 1245 return file_name[ dot_character_index .. $ ]; 1246 } 1247 else 1248 { 1249 return ""; 1250 } 1251 } 1252 1253 // ~~ 1254 1255 bool IsEmptyFolder( 1256 string folder_path 1257 ) 1258 { 1259 bool 1260 it_is_empty_folder; 1261 1262 try 1263 { 1264 it_is_empty_folder = true; 1265 1266 foreach ( folder_entry; dirEntries( folder_path, SpanMode.shallow ) ) 1267 { 1268 it_is_empty_folder = false; 1269 1270 break; 1271 } 1272 } 1273 catch ( Exception exception ) 1274 { 1275 Abort( "Can't read folder : " ~ folder_path, exception ); 1276 } 1277 1278 return it_is_empty_folder; 1279 } 1280 1281 // ~~ 1282 1283 void CreateFolder( 1284 string folder_path 1285 ) 1286 { 1287 if ( folder_path != "" 1288 && folder_path != "/" 1289 && !folder_path.exists() ) 1290 { 1291 if ( HasVerbosity( VERBOSITY.Operation ) ) 1292 { 1293 writeln( "Creating folder : ", folder_path ); 1294 } 1295 1296 try 1297 { 1298 folder_path.mkdirRecurse(); 1299 } 1300 catch ( Exception exception ) 1301 { 1302 Abort( "Can't create folder : " ~ folder_path, exception ); 1303 } 1304 } 1305 } 1306 1307 // ~~ 1308 1309 void RemoveFolder( 1310 string folder_path 1311 ) 1312 { 1313 writeln( "Removing folder : ", folder_path ); 1314 1315 try 1316 { 1317 folder_path.rmdir(); 1318 } 1319 catch ( Exception exception ) 1320 { 1321 Abort( "Can't create folder : " ~ folder_path, exception ); 1322 } 1323 } 1324 1325 // ~~ 1326 1327 void RemoveFile( 1328 string file_path 1329 ) 1330 { 1331 writeln( "Removing file : ", file_path ); 1332 1333 try 1334 { 1335 file_path.remove(); 1336 } 1337 catch ( Exception exception ) 1338 { 1339 Abort( "Can't remove file : " ~ file_path, exception ); 1340 } 1341 } 1342 1343 // ~~ 1344 1345 void WriteByteArray( 1346 string file_path, 1347 ubyte[] file_byte_array, 1348 bool folder_is_created = true 1349 ) 1350 { 1351 if ( folder_is_created ) 1352 { 1353 CreateFolder( file_path.dirName() ); 1354 } 1355 1356 if ( HasVerbosity( VERBOSITY.Operation ) ) 1357 { 1358 writeln( "Writing file : ", file_path ); 1359 } 1360 1361 try 1362 { 1363 file_path.write( file_byte_array ); 1364 } 1365 catch ( Exception exception ) 1366 { 1367 Abort( "Can't write file : " ~ file_path, exception ); 1368 } 1369 } 1370 1371 // ~~ 1372 1373 ubyte[] ReadByteArray( 1374 string file_path 1375 ) 1376 { 1377 ubyte[] 1378 file_byte_array; 1379 1380 if ( HasVerbosity( VERBOSITY.Operation ) ) 1381 { 1382 writeln( "Reading file : ", file_path ); 1383 } 1384 1385 try 1386 { 1387 file_byte_array = cast( ubyte[] )file_path.read(); 1388 } 1389 catch ( Exception exception ) 1390 { 1391 Abort( "Can't read file : " ~ file_path, exception ); 1392 } 1393 1394 return file_byte_array; 1395 } 1396 1397 // ~~ 1398 1399 void WriteText( 1400 string file_path, 1401 string file_text, 1402 bool folder_is_created = true 1403 ) 1404 { 1405 if ( folder_is_created ) 1406 { 1407 CreateFolder( file_path.dirName() ); 1408 } 1409 1410 if ( HasVerbosity( VERBOSITY.Operation ) ) 1411 { 1412 writeln( "Writing file : ", file_path ); 1413 } 1414 1415 file_text = file_text.stripRight(); 1416 1417 if ( file_text != "" 1418 && !file_text.endsWith( '\n' ) ) 1419 { 1420 file_text ~= '\n'; 1421 } 1422 1423 try 1424 { 1425 if ( !file_path.exists() 1426 || file_path.readText() != file_text ) 1427 { 1428 file_path.write( file_text ); 1429 } 1430 } 1431 catch ( Exception exception ) 1432 { 1433 Abort( "Can't write file : " ~ file_path, exception ); 1434 } 1435 } 1436 1437 // ~~ 1438 1439 string ReadText( 1440 string file_path 1441 ) 1442 { 1443 string 1444 file_text; 1445 1446 if ( HasVerbosity( VERBOSITY.Operation ) ) 1447 { 1448 writeln( "Reading file : ", file_path ); 1449 } 1450 1451 try 1452 { 1453 file_text = file_path.readText(); 1454 } 1455 catch ( Exception exception ) 1456 { 1457 Abort( "Can't read file : " ~ file_path, exception ); 1458 } 1459 1460 return file_text; 1461 } 1462